Skip to content

Commit 24c300b

Browse files
Hydrogent: use manual depth testing in OIT layers pass on WebGPU
1 parent 5a95c7a commit 24c300b

File tree

5 files changed

+66
-18
lines changed

5 files changed

+66
-18
lines changed

Hydrogent/interface/Tasks/HnBeginOITPassTask.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
#pragma once
2828

29+
#include <array>
30+
2931
#include "HnTask.hpp"
3032
#include "../interface/HnRenderPassState.hpp"
3133

@@ -80,7 +82,9 @@ class HnBeginOITPassTask final : public HnTask
8082
HnRenderPassState m_RenderPassState;
8183

8284
RefCntAutoPtr<IShaderResourceBinding> m_ClearLayersSRB;
83-
RefCntAutoPtr<IShaderResourceBinding> m_RWLayersSRB;
85+
86+
// Two SRBs for ping-ponging between depth buffers.
87+
std::array<RefCntAutoPtr<IShaderResourceBinding>, 2> m_RWLayersSRBs;
8488

8589
Uint32 m_BoundOITResourcesVersion = ~0u;
8690
};

Hydrogent/src/Tasks/HnBeginOITPassTask.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,13 @@ void HnBeginOITPassTask::Prepare(pxr::HdTaskContext* TaskCtx,
8383
{
8484
FrameTargets->OIT = {};
8585
m_ClearLayersSRB.Release();
86-
m_RWLayersSRB.Release();
86+
m_RWLayersSRBs = {};
8787
}
8888
}
8989

9090
HnRenderDelegate* RenderDelegate = static_cast<HnRenderDelegate*>(RenderIndex->GetRenderDelegate());
91+
IRenderDevice* pDevice = RenderDelegate->GetDevice();
92+
const bool IsWebGPUDevice = pDevice->GetDeviceInfo().IsWebGPUDevice();
9193

9294
const USD_Renderer& Renderer = *RenderDelegate->GetUSDRenderer();
9395
VERIFY_EXPR(Renderer.GetSettings().OITLayerCount > 0);
@@ -103,7 +105,9 @@ void HnBeginOITPassTask::Prepare(pxr::HdTaskContext* TaskCtx,
103105
bool UseReverseDepth = false;
104106
GetTaskContextData(TaskCtx, HnRenderResourceTokens->useReverseDepth, UseReverseDepth);
105107

106-
const TEXTURE_FORMAT DepthFormat = FrameTargets->DepthDSV->GetTexture()->GetDesc().Format;
108+
const TEXTURE_FORMAT DepthFormat = !IsWebGPUDevice ?
109+
FrameTargets->DepthDSV->GetDesc().Format :
110+
TEX_FORMAT_UNKNOWN;
107111
if (m_RenderPassState.GetDepthStencilFormat() != DepthFormat ||
108112
m_RenderPassState.GetUseReverseDepth() != UseReverseDepth)
109113
{
@@ -122,7 +126,10 @@ void HnBeginOITPassTask::Prepare(pxr::HdTaskContext* TaskCtx,
122126
0, // Unused
123127
1, // Total tail transmittance
124128
};
125-
m_RenderPassState.Begin(_countof(OITRTVs), OITRTVs, FrameTargets->DepthDSV, &TailClearValue, 0, 0x01u);
129+
// WebGPU does not support the earlydepthstencil attribute, so we have to
130+
// perform depth testing manually in the shader.
131+
ITextureView* pDepthDSV = !IsWebGPUDevice ? FrameTargets->DepthDSV : nullptr;
132+
m_RenderPassState.Begin(_countof(OITRTVs), OITRTVs, pDepthDSV, &TailClearValue, 0, 0x01u);
126133

127134
const HnCamera* pCamera = nullptr;
128135
if (GetTaskContextData(TaskCtx, HnRenderResourceTokens->camera, pCamera))
@@ -177,13 +184,16 @@ void HnBeginOITPassTask::Execute(pxr::HdTaskContext* TaskCtx)
177184
}
178185

179186
HnRenderDelegate* RenderDelegate = static_cast<HnRenderDelegate*>(m_RenderIndex->GetRenderDelegate());
187+
IRenderDevice* pDevice = RenderDelegate->GetDevice();
188+
const bool IsWebGPUDevice = pDevice->GetDeviceInfo().IsWebGPUDevice();
180189
IDeviceContext* pCtx = RenderDelegate->GetDeviceContext();
181190

182-
HnRenderParam* RenderParam = static_cast<HnRenderParam*>(RenderDelegate->GetRenderParam());
183-
if (m_BoundOITResourcesVersion != RenderParam->GetAttribVersion(HnRenderParam::GlobalAttrib::OITResources))
191+
const HnRenderParam* RenderParam = static_cast<HnRenderParam*>(RenderDelegate->GetRenderParam());
192+
const Uint32 OITResourcesVersion = RenderParam->GetAttribVersion(HnRenderParam::GlobalAttrib::OITResources);
193+
if (m_BoundOITResourcesVersion != OITResourcesVersion)
184194
{
185195
BindOITResources(RenderDelegate);
186-
m_BoundOITResourcesVersion = RenderParam->GetAttribVersion(HnRenderParam::GlobalAttrib::OITResources);
196+
m_BoundOITResourcesVersion = OITResourcesVersion;
187197
}
188198

189199
ScopedDebugGroup DebugGroup{pCtx, "Begin OIT pass"};
@@ -193,16 +203,28 @@ void HnBeginOITPassTask::Execute(pxr::HdTaskContext* TaskCtx)
193203
{
194204
Renderer.CreateClearOITLayersSRB(RenderDelegate->GetFrameAttribsCB(), m_FrameTargets->OIT.Layers, &m_ClearLayersSRB);
195205
}
196-
if (!m_RWLayersSRB)
206+
207+
// For WebGPU, we need to ping-pong between two SRBs using odd/even frame depth buffers.
208+
// Other APIs can use a single SRB since they support early depth testing.
209+
RefCntAutoPtr<IShaderResourceBinding>& RWLayersSRB = m_RWLayersSRBs[IsWebGPUDevice ? (RenderParam->GetFrameNumber() & 0x01) : 0];
210+
if (!RWLayersSRB)
197211
{
198-
Renderer.CreateRWOITLayersSRB(m_FrameTargets->OIT.Layers, &m_RWLayersSRB);
212+
ITextureView* pDepthSRV = nullptr;
213+
if (IsWebGPUDevice)
214+
{
215+
// WebGPU does not support the earlydepthstencil attribute, so we have to
216+
// perform depth testing manually in the shader.
217+
pDepthSRV = m_FrameTargets->DepthDSV->GetTexture()->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE);
218+
DEV_CHECK_ERR(pDepthSRV != nullptr, "Depth buffer shader resource view is null");
219+
}
220+
Renderer.CreateRWOITLayersSRB(m_FrameTargets->OIT.Layers, pDepthSRV, &RWLayersSRB);
199221
}
200222
const TextureDesc& OITTailDesc = m_FrameTargets->OIT.Tail->GetDesc();
201223
Renderer.ClearOITLayers(pCtx, m_ClearLayersSRB, OITTailDesc.Width, OITTailDesc.Height);
202224

203225
IShaderResourceBinding* pFrameAttribsSRB = RenderDelegate->GetFrameAttribsSRB(HnRenderDelegate::FrameAttribsSRBType::Opaque);
204226
m_RenderPassState.SetFrameAttribsSRB(pFrameAttribsSRB);
205-
m_RenderPassState.SetRWOITLayersSRB(m_RWLayersSRB);
227+
m_RenderPassState.SetRWOITLayersSRB(RWLayersSRB);
206228
m_RenderPassState.Commit(pCtx);
207229
}
208230

PBR/interface/PBR_Renderer.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ class PBR_Renderer
796796
static OITResources CreateOITResources(IRenderDevice* pDevice, Uint32 Width, Uint32 Height, Uint32 LayerCount);
797797
OITResources CreateOITResources(Uint32 Width, Uint32 Height) const;
798798
void CreateClearOITLayersSRB(IBuffer* pFrameAttribs, IBuffer* OITLayers, IShaderResourceBinding** ppSRB) const;
799-
void CreateRWOITLayersSRB(IBuffer* OITLayers, IShaderResourceBinding** ppSRB) const;
799+
void CreateRWOITLayersSRB(IBuffer* OITLayers, ITextureView* pDepthSRV, IShaderResourceBinding** ppSRB) const;
800800
void ClearOITLayers(IDeviceContext* pCtx, IShaderResourceBinding* pSRB, Uint32 Width, Uint32 Height) const;
801801
void CreateApplyOITAttenuationPSO(TEXTURE_FORMAT ColorFormat, TEXTURE_FORMAT DepthFormat, IPipelineState** ppPSO) const;
802802
void CreateApplyOITAttenuationSRB(IBuffer* pFrameAttribs,

PBR/src/PBR_Renderer.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,11 @@ void PBR_Renderer::CreateSignature()
12541254
.SetBindingIndex(static_cast<Uint8>(m_ResourceSignatures.size()))
12551255
.SetUseCombinedTextureSamplers(true)
12561256
.AddResource(SHADER_TYPE_PIXEL, "g_rwOITLayers", SHADER_RESOURCE_TYPE_BUFFER_UAV, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE);
1257+
if (m_Device.GetDeviceInfo().IsWebGPUDevice())
1258+
{
1259+
constexpr WebGPUResourceAttribs WGPUDepthMap{WEB_GPU_BINDING_TYPE_UNFILTERABLE_FLOAT_TEXTURE, RESOURCE_DIM_TEX_2D};
1260+
OITLayersSignDesc.AddResource(SHADER_TYPE_PIXEL, "g_DepthBuffer", SHADER_RESOURCE_TYPE_TEXTURE_SRV, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, PIPELINE_RESOURCE_FLAG_NONE, WGPUDepthMap);
1261+
}
12571262
m_RWOITLayersSignature = m_Device.CreatePipelineResourceSignature(OITLayersSignDesc);
12581263
VERIFY_EXPR(m_RWOITLayersSignature);
12591264
}
@@ -1975,6 +1980,9 @@ void PBR_Renderer::CreatePSO(PsoHashMapType& PsoHashMap,
19751980
{
19761981
SrcFile = "UpdateOITLayers.psh";
19771982
Name = "OIT Layers PS";
1983+
// WebGPU does not support the earlydepthstencil attribute, so we have to
1984+
// perform depth testing manually in the shader.
1985+
Macros.Add("USE_MANUAL_DEPTH_TEST", m_Device.GetDeviceInfo().IsWebGPUDevice());
19781986
}
19791987
else
19801988
{
@@ -2294,7 +2302,7 @@ void PBR_Renderer::CreateClearOITLayersSRB(IBuffer* pFrameAttribs, IBuffer* OITL
22942302
ShaderResourceVariableX{*ppSRB, SHADER_TYPE_COMPUTE, "g_rwOITLayers"}.Set(OITLayers->GetDefaultView(BUFFER_VIEW_UNORDERED_ACCESS));
22952303
}
22962304

2297-
void PBR_Renderer::CreateRWOITLayersSRB(IBuffer* OITLayers, IShaderResourceBinding** ppSRB) const
2305+
void PBR_Renderer::CreateRWOITLayersSRB(IBuffer* OITLayers, ITextureView* pDepthSRV, IShaderResourceBinding** ppSRB) const
22982306
{
22992307
if (!m_RWOITLayersSignature)
23002308
{
@@ -2305,6 +2313,17 @@ void PBR_Renderer::CreateRWOITLayersSRB(IBuffer* OITLayers, IShaderResourceBindi
23052313
m_RWOITLayersSignature->CreateShaderResourceBinding(ppSRB, true);
23062314
VERIFY_EXPR(*ppSRB);
23072315
ShaderResourceVariableX{*ppSRB, SHADER_TYPE_PIXEL, "g_rwOITLayers"}.Set(OITLayers->GetDefaultView(BUFFER_VIEW_UNORDERED_ACCESS));
2316+
if (m_Device.GetDeviceInfo().IsWebGPUDevice())
2317+
{
2318+
if (pDepthSRV != nullptr)
2319+
{
2320+
ShaderResourceVariableX{*ppSRB, SHADER_TYPE_PIXEL, "g_DepthBuffer"}.Set(pDepthSRV);
2321+
}
2322+
else
2323+
{
2324+
DEV_ERROR("Depth buffer SRV is required on WebGPU to perform manual depth test");
2325+
}
2326+
}
23082327
}
23092328

23102329
void PBR_Renderer::CreateApplyOITAttenuationSRB(IBuffer* pFrameAttribs,

Shaders/PBR/private/OIT/UpdateOITLayers.psh

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,19 @@ PSOutput main(in VSOutput VSOut,
5252
in bool IsFrontFace : SV_IsFrontFace)
5353
{
5454
float D = VSOut.ClipPos.z;
55-
if (g_Frame.Camera.fNearPlaneDepth > g_Frame.Camera.fFarPlaneDepth)
56-
{
57-
D = 1.0 - D;
58-
}
5955
#if USE_MANUAL_DEPTH_TEST
60-
if (D >= g_DepthBuffer.Load(int3(VSOut.ClipPos.xy, 0)))
6156
{
62-
discard;
57+
float S = g_Frame.Camera.fNearPlaneDepth < g_Frame.Camera.fFarPlaneDepth ? +1.0 : -1.0;
58+
if (D * S >= g_DepthBuffer.Load(int3(VSOut.ClipPos.xy, 0)) * S)
59+
{
60+
discard;
61+
}
6362
}
6463
#endif
64+
if (g_Frame.Camera.fNearPlaneDepth > g_Frame.Camera.fFarPlaneDepth)
65+
{
66+
D = 1.0 - D;
67+
}
6568

6669
float4 BaseColor = GetBaseColor(VSOut, g_Material, g_Frame.Renderer.MipBias, PRIMITIVE.FallbackColor);
6770

0 commit comments

Comments
 (0)