Skip to content

Commit

Permalink
AttachmentCleanerWebGPU: some improvements + refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Aug 3, 2024
1 parent e7d5ff5 commit 9ab35cf
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 55 deletions.
23 changes: 14 additions & 9 deletions Graphics/GraphicsEngineWebGPU/include/AttachmentCleanerWebGPU.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

namespace Diligent
{

class AttachmentCleanerWebGPU
{
public:
Expand Down Expand Up @@ -91,10 +92,9 @@ class AttachmentCleanerWebGPU
COLOR_MASK ColorMask = COLOR_MASK_ALL;
Int32 RTIndex = 0; // -1 for depth
WGPUDepthStencilState DepthState = {};
mutable size_t PSOHash = 0;
};

using ClearPSOCache = std::unordered_map<ClearPSOHashKey, WebGPURenderPipelineWrapper, ClearPSOHashKey::Hasher>;
mutable size_t Hash = 0;
};

WebGPURenderPipelineWrapper CreatePSO(const ClearPSOHashKey& Key);

Expand All @@ -120,13 +120,18 @@ class AttachmentCleanerWebGPU
WebGPUBindGroupWrapper wgpuBindGroup;
} m_PipelineResourceLayout;

ClearPSOCache m_PSOCache;
WebGPUShaderModuleWrapper m_wgpuVSModule;

using FSModuleCacheType = std::unordered_map<Int32, WebGPUShaderModuleWrapper>;
FSModuleCacheType m_wgpuFSModules;

using PSOCacheType = std::unordered_map<ClearPSOHashKey, WebGPURenderPipelineWrapper, ClearPSOHashKey::Hasher>;
PSOCacheType m_PSOCache;

WGPUDepthStencilState m_wgpuDisableDepth = {};
WGPUDepthStencilState m_wgpuWriteDepth = {};
WGPUDepthStencilState m_wgpuWriteStencil = {};
WGPUDepthStencilState m_wgpuWriteDepthStencil = {};
bool m_IsInitializedResources = false;
WGPUDepthStencilState m_wgpuDisableDepth = {};
WGPUDepthStencilState m_wgpuWriteDepth = {};
WGPUDepthStencilState m_wgpuWriteStencil = {};
WGPUDepthStencilState m_wgpuWriteDepthStencil = {};
};

} // namespace Diligent
91 changes: 45 additions & 46 deletions Graphics/GraphicsEngineWebGPU/src/AttachmentCleanerWebGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ namespace
constexpr char VSSource[] = R"(
struct ClearConstants
{
Color: vec4f,
Depth: f32,
Color: vec4f,
Depth: f32,
Padding0: f32,
Padding1: f32,
Padding2: f32,
Expand Down Expand Up @@ -163,7 +164,7 @@ size_t AttachmentCleanerWebGPU::RenderPassInfo::GetHash() const

bool AttachmentCleanerWebGPU::ClearPSOHashKey::operator==(const ClearPSOHashKey& rhs) const
{
if (PSOHash != rhs.PSOHash)
if (Hash != rhs.Hash)
return false;
// clang-format off
return RPInfo == rhs.RPInfo &&
Expand All @@ -175,15 +176,18 @@ bool AttachmentCleanerWebGPU::ClearPSOHashKey::operator==(const ClearPSOHashKey&

size_t AttachmentCleanerWebGPU::ClearPSOHashKey::Hasher::operator()(const ClearPSOHashKey& Key) const
{
if (Key.PSOHash == 0)
Key.PSOHash = ComputeHash(Key.RPInfo.GetHash(), static_cast<Int32>(Key.ColorMask), Key.RTIndex, ComputeHashRaw(&Key.DepthState, sizeof(WGPUDepthStencilState)));
if (Key.Hash == 0)
Key.Hash = ComputeHash(Key.RPInfo.GetHash(), static_cast<Int32>(Key.ColorMask), Key.RTIndex, ComputeHashRaw(&Key.DepthState, sizeof(WGPUDepthStencilState)));

return Key.PSOHash;
return Key.Hash;
}

AttachmentCleanerWebGPU::AttachmentCleanerWebGPU(RenderDeviceWebGPUImpl& DeviceWebGPU) :
m_DeviceWebGPU{DeviceWebGPU}
{
InitializePipelineStates();
InitializeConstantBuffer();
InitializePipelineResourceLayout();
}

void AttachmentCleanerWebGPU::ClearColor(WGPURenderPassEncoder wgpuCmdEncoder,
Expand All @@ -194,13 +198,6 @@ void AttachmentCleanerWebGPU::ClearColor(WGPURenderPassEncoder wgpuCmdEncoder
const float Color[])
{
VERIFY_EXPR(m_DeviceWebGPU.GetNumImmediateContexts() == 1);
if (!m_IsInitializedResources)
{
InitializePipelineStates();
InitializeConstantBuffer();
InitializePipelineResourceLayout();
m_IsInitializedResources = true;
}

ClearPSOHashKey Key;
Key.RPInfo = RPInfo;
Expand All @@ -220,13 +217,6 @@ void AttachmentCleanerWebGPU::ClearDepthStencil(WGPURenderPassEncoder wgpuCm
Uint8 Stencil)
{
VERIFY_EXPR(m_DeviceWebGPU.GetNumImmediateContexts() == 1);
if (!m_IsInitializedResources)
{
InitializePipelineStates();
InitializeConstantBuffer();
InitializePipelineResourceLayout();
m_IsInitializedResources = true;
}

ClearPSOHashKey Key{};
Key.RPInfo = RPInfo;
Expand Down Expand Up @@ -255,7 +245,7 @@ WebGPURenderPipelineWrapper AttachmentCleanerWebGPU::CreatePSO(const ClearPSOHas

try
{
WebGPUShaderModuleWrapper wgpuVSShaderModule{};
if (!m_wgpuVSModule)
{
WGPUShaderModuleWGSLDescriptor wgpuShaderCodeDesc{};
wgpuShaderCodeDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
Expand All @@ -264,12 +254,16 @@ WebGPURenderPipelineWrapper AttachmentCleanerWebGPU::CreatePSO(const ClearPSOHas
WGPUShaderModuleDescriptor wgpuShaderModuleDesc{};
wgpuShaderModuleDesc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&wgpuShaderCodeDesc);

wgpuVSShaderModule.Reset(wgpuDeviceCreateShaderModule(m_DeviceWebGPU.GetWebGPUDevice(), &wgpuShaderModuleDesc));
if (!wgpuVSShaderModule)
LOG_ERROR_AND_THROW("Failed to create shader module");
m_wgpuVSModule.Reset(wgpuDeviceCreateShaderModule(m_DeviceWebGPU.GetWebGPUDevice(), &wgpuShaderModuleDesc));
if (!m_wgpuVSModule)
{
LOG_ERROR_MESSAGE("Attachment cleaner: failed to create vertex shader module");
return {};
}
}

WebGPUShaderModuleWrapper wgpuPSShaderModule{};
WebGPUShaderModuleWrapper& wgpuPSModule = m_wgpuFSModules[Key.RTIndex];
if (!wgpuPSModule)
{
std::string PSSource;

Expand All @@ -290,12 +284,15 @@ WebGPURenderPipelineWrapper AttachmentCleanerWebGPU::CreatePSO(const ClearPSOHas
WGPUShaderModuleDescriptor wgpuShaderModuleDesc{};
wgpuShaderModuleDesc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&wgpuShaderCodeDesc);

wgpuPSShaderModule.Reset(wgpuDeviceCreateShaderModule(m_DeviceWebGPU.GetWebGPUDevice(), &wgpuShaderModuleDesc));
if (!wgpuPSShaderModule)
LOG_ERROR_AND_THROW("Failed to create shader module");
wgpuPSModule.Reset(wgpuDeviceCreateShaderModule(m_DeviceWebGPU.GetWebGPUDevice(), &wgpuShaderModuleDesc));
if (!wgpuPSModule)
{
LOG_ERROR_MESSAGE("Attachment cleaner: failed to create fragment shader module");
return {};
}
}

const auto& RPInfo = Key.RPInfo;
const RenderPassInfo& RPInfo = Key.RPInfo;

WGPUColorTargetState wgpuColorTargetState[MAX_RENDER_TARGETS]{};
for (Uint32 RTIndex = 0; RTIndex < RPInfo.NumRenderTargets; ++RTIndex)
Expand All @@ -308,16 +305,16 @@ WebGPURenderPipelineWrapper AttachmentCleanerWebGPU::CreatePSO(const ClearPSOHas
wgpuDepthStencilState.format = TextureFormatToWGPUFormat(RPInfo.DSVFormat);

WGPUFragmentState wgpuFragmentState{};
wgpuFragmentState.module = wgpuPSShaderModule.Get();
wgpuFragmentState.module = wgpuPSModule;
wgpuFragmentState.entryPoint = "PSMain";
wgpuFragmentState.targetCount = RPInfo.NumRenderTargets;
wgpuFragmentState.targets = wgpuColorTargetState;

WGPURenderPipelineDescriptor wgpuRenderPipelineDesc{};
wgpuRenderPipelineDesc.label = "AttachmentCleanerPSO";
wgpuRenderPipelineDesc.layout = m_PipelineResourceLayout.wgpuPipelineLayout.Get();
wgpuRenderPipelineDesc.layout = m_PipelineResourceLayout.wgpuPipelineLayout;
wgpuRenderPipelineDesc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
wgpuRenderPipelineDesc.vertex.module = wgpuVSShaderModule.Get();
wgpuRenderPipelineDesc.vertex.module = m_wgpuVSModule;
wgpuRenderPipelineDesc.vertex.entryPoint = "VSMain";
wgpuRenderPipelineDesc.fragment = RPInfo.NumRenderTargets > 0 ? &wgpuFragmentState : nullptr;
wgpuRenderPipelineDesc.depthStencil = RPInfo.DSVFormat != TEX_FORMAT_UNKNOWN ? &wgpuDepthStencilState : nullptr;
Expand All @@ -327,7 +324,10 @@ WebGPURenderPipelineWrapper AttachmentCleanerWebGPU::CreatePSO(const ClearPSOHas
wgpuPipeline.Reset(wgpuDeviceCreateRenderPipeline(m_DeviceWebGPU.GetWebGPUDevice(), &wgpuRenderPipelineDesc));

if (!wgpuPipeline)
LOG_ERROR_AND_THROW("Failed to create clear attachment render pipeline");
{
LOG_ERROR_MESSAGE("Attachment cleaner: failed to create render pipeline");
return {};
}
}
catch (...)
{
Expand All @@ -338,12 +338,11 @@ WebGPURenderPipelineWrapper AttachmentCleanerWebGPU::CreatePSO(const ClearPSOHas

void AttachmentCleanerWebGPU::ClearAttachment(WGPURenderPassEncoder wgpuCmdEncoder, DeviceContextWebGPUImpl* pDeviceContext, const ClearPSOHashKey& Key, std::array<float, 8>& ClearData)
{
auto Iter = m_PSOCache.find(Key);
if (Iter == m_PSOCache.end())
Iter = m_PSOCache.emplace(Key, CreatePSO(Key)).first;
WebGPURenderPipelineWrapper& wgpuPipelineState = m_PSOCache[Key];
if (!wgpuPipelineState)
wgpuPipelineState = CreatePSO(Key);

WGPURenderPipeline wgpuPipelineState = Iter->second.Get();
if (wgpuPipelineState == nullptr)
if (!wgpuPipelineState)
{
UNEXPECTED("Clear attachment PSO is null");
return;
Expand All @@ -354,11 +353,11 @@ void AttachmentCleanerWebGPU::ClearAttachment(WGPURenderPassEncoder wgpuCmdEncod
memcpy(pMappedData, ClearData.data(), sizeof(ClearData));
pDeviceContext->UnmapBuffer(m_pBuffer, MAP_WRITE);

const auto* pBufferImpl = ClassPtrCast<BufferWebGPUImpl>(m_pBuffer.RawPtr());
Uint32 DynamicOffsets[] = {static_cast<Uint32>(pBufferImpl->GetDynamicOffset(pDeviceContext->GetContextId(), nullptr))};
const BufferWebGPUImpl* pBufferImpl = m_pBuffer.RawPtr<BufferWebGPUImpl>();
const Uint32 DynamicOffsets[] = {static_cast<Uint32>(pBufferImpl->GetDynamicOffset(pDeviceContext->GetContextId(), nullptr))};

wgpuRenderPassEncoderSetPipeline(wgpuCmdEncoder, wgpuPipelineState);
wgpuRenderPassEncoderSetBindGroup(wgpuCmdEncoder, 0, m_PipelineResourceLayout.wgpuBindGroup.Get(), _countof(DynamicOffsets), DynamicOffsets);
wgpuRenderPassEncoderSetBindGroup(wgpuCmdEncoder, 0, m_PipelineResourceLayout.wgpuBindGroup, _countof(DynamicOffsets), DynamicOffsets);
wgpuRenderPassEncoderDraw(wgpuCmdEncoder, 3, 1, 0, 0);
}

Expand Down Expand Up @@ -420,17 +419,17 @@ void AttachmentCleanerWebGPU::InitializePipelineResourceLayout()

m_PipelineResourceLayout.wgpuBindGroupLayout.Reset(wgpuDeviceCreateBindGroupLayout(wgpuDevice, &wgpuBindGroupLayoutDesc));
if (!m_PipelineResourceLayout.wgpuBindGroupLayout)
LOG_ERROR_AND_THROW("Failed to create clear attachment bind group layout");
LOG_ERROR_AND_THROW("Attachment cleaner: failed to create bind group layout");

WGPUPipelineLayoutDescriptor wgpuPipelineLayoutDesc{};
wgpuPipelineLayoutDesc.label = "AttachmentCleanerLayout";
wgpuPipelineLayoutDesc.bindGroupLayouts = &m_PipelineResourceLayout.wgpuBindGroupLayout.Get();
wgpuPipelineLayoutDesc.bindGroupLayoutCount = 1;
m_PipelineResourceLayout.wgpuPipelineLayout.Reset(wgpuDeviceCreatePipelineLayout(wgpuDevice, &wgpuPipelineLayoutDesc));
if (!m_PipelineResourceLayout.wgpuPipelineLayout)
LOG_ERROR_AND_THROW("Failed to create clear attachment pipeline layout");
LOG_ERROR_AND_THROW("Attachment cleaner: failed to create pipeline layout");

const auto* pBufferImpl = ClassPtrCast<BufferWebGPUImpl>(m_pBuffer.RawPtr());
const BufferWebGPUImpl* pBufferImpl = ClassPtrCast<BufferWebGPUImpl>(m_pBuffer.RawPtr());

WGPUBindGroupEntry wgpuBindGroupEntry[1]{};
wgpuBindGroupEntry[0].binding = 0;
Expand All @@ -439,12 +438,12 @@ void AttachmentCleanerWebGPU::InitializePipelineResourceLayout()
wgpuBindGroupEntry[0].size = m_pBuffer->GetDesc().Size;

WGPUBindGroupDescriptor wgpuBindGroupDesc{};
wgpuBindGroupDesc.layout = m_PipelineResourceLayout.wgpuBindGroupLayout.Get();
wgpuBindGroupDesc.layout = m_PipelineResourceLayout.wgpuBindGroupLayout;
wgpuBindGroupDesc.entries = wgpuBindGroupEntry;
wgpuBindGroupDesc.entryCount = _countof(wgpuBindGroupEntry);
m_PipelineResourceLayout.wgpuBindGroup.Reset(wgpuDeviceCreateBindGroup(wgpuDevice, &wgpuBindGroupDesc));
if (!m_PipelineResourceLayout.wgpuBindGroup)
LOG_ERROR_AND_THROW("Failed to create clear attachment bind group");
LOG_ERROR_AND_THROW("Attachment cleaner: failed to create bind group");
}

} // namespace Diligent

0 comments on commit 9ab35cf

Please sign in to comment.