Fix depth stencil view format when binding to shader to use depth-only aspect but still render to both

This commit is contained in:
Wojtek Figat
2026-02-26 11:07:19 +01:00
parent 153b16ebd7
commit d2a8ac54cf
5 changed files with 108 additions and 12 deletions

View File

@@ -686,27 +686,26 @@ void GPUContextWebGPU::ManualClear(const PendingClear& clear)
{
renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
depthStencilAttachment = WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_INIT;
depthStencilAttachment.view = clear.View->View;
depthStencilAttachment.view = clear.View->ViewRender;
depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
depthStencilAttachment.depthClearValue = clear.Depth;
depthStencilAttachment.stencilClearValue = clear.Stencil;
if (clear.View->HasStencil)
{
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Store;
}
}
else
{
renderPassDesc.colorAttachmentCount = 1;
renderPassDesc.colorAttachments = &colorAttachment;
colorAttachment = WGPU_RENDER_PASS_COLOR_ATTACHMENT_INIT;
colorAttachment.view = clear.View->View;
colorAttachment.view = clear.View->ViewRender;
colorAttachment.depthSlice = clear.View->DepthSlice;
colorAttachment.loadOp = WGPULoadOp_Clear;
colorAttachment.storeOp = WGPUStoreOp_Store;
if (clear.View->HasStencil)
{
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Store;
depthStencilAttachment.stencilClearValue = clear.Stencil;
}
colorAttachment.clearValue = { clear.RGBA[0], clear.RGBA[1], clear.RGBA[2], clear.RGBA[3] };
}
auto renderPass = wgpuCommandEncoderBeginRenderPass(Encoder, &renderPassDesc);
@@ -805,11 +804,11 @@ void GPUContextWebGPU::FlushRenderPass()
auto& colorAttachment = colorAttachments[i];
colorAttachment = WGPU_RENDER_PASS_COLOR_ATTACHMENT_INIT;
auto renderTarget = _renderTargets[i];
colorAttachment.view = renderTarget->View;
colorAttachment.view = renderTarget->ViewRender;
colorAttachment.depthSlice = renderTarget->DepthSlice;
colorAttachment.loadOp = WGPULoadOp_Load;
colorAttachment.storeOp = WGPUStoreOp_Store;
if (FindClear(_depthStencil, clear))
if (FindClear(renderTarget, clear))
{
colorAttachment.loadOp = WGPULoadOp_Clear;
colorAttachment.clearValue = { clear.RGBA[0], clear.RGBA[1], clear.RGBA[2], clear.RGBA[3] };
@@ -820,7 +819,7 @@ void GPUContextWebGPU::FlushRenderPass()
if (_depthStencil)
{
renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
depthStencilAttachment.view = _depthStencil->View;
depthStencilAttachment.view = _depthStencil->ViewRender;
depthStencilAttachment.depthLoadOp = WGPULoadOp_Load;
depthStencilAttachment.depthStoreOp = _depthStencil->ReadOnly ? WGPUStoreOp_Discard : WGPUStoreOp_Store;
depthStencilAttachment.depthReadOnly = _depthStencil->ReadOnly;

View File

@@ -7,6 +7,31 @@
#include "Engine/Core/Log.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
bool HasStencil(WGPUTextureFormat format)
{
switch (format)
{
case WGPUTextureFormat_Depth24PlusStencil8:
case WGPUTextureFormat_Depth32FloatStencil8:
return true;
default:
return false;
}
}
WGPUTextureFormat DropStencil(WGPUTextureFormat format)
{
switch (format)
{
case WGPUTextureFormat_Depth24PlusStencil8:
return WGPUTextureFormat_Depth24Plus;
case WGPUTextureFormat_Depth32FloatStencil8:
return WGPUTextureFormat_Depth32Float;
default:
return format;
}
}
void GPUTextureViewWebGPU::Create(WGPUTexture texture, WGPUTextureViewDescriptor const* desc)
{
if (View)
@@ -17,13 +42,31 @@ void GPUTextureViewWebGPU::Create(WGPUTexture texture, WGPUTextureViewDescriptor
{
#if GPU_ENABLE_RESOURCE_NAMING
LOG(Error, "Failed to create a view for texture '{}'", GetParent() ? GetParent()->GetName() : StringView::Empty);
#else
LOG(Error, "Failed to create a view for texture");
#endif
}
ViewRender = View;
// Depth-stencil textures expose depth-only when binding to shaders (unless via custom _handleStencil view) so make separate ViewRender for rendering with all components
if (desc && desc->aspect == WGPUTextureAspect_All && ::HasStencil(desc->format))
{
auto depthOnlyDesc = *desc;
depthOnlyDesc.aspect = WGPUTextureAspect_DepthOnly;
depthOnlyDesc.format = DropStencil(depthOnlyDesc.format);
View = wgpuTextureCreateView(texture, &depthOnlyDesc);
}
Format = desc ? desc->format : wgpuTextureGetFormat(texture);
}
void GPUTextureViewWebGPU::Release()
{
if (View != ViewRender)
{
wgpuTextureViewRelease(ViewRender);
ViewRender = nullptr;
}
if (View)
{
wgpuTextureViewRelease(View);
@@ -64,7 +107,7 @@ bool GPUTextureWebGPU::OnInit()
textureDesc.dimension = WGPUTextureDimension_3D;
break;
case TextureDimensions::CubeTexture:
_viewDimension = IsArray() ? WGPUTextureViewDimension_CubeArray : WGPUTextureViewDimension_Cube;
_viewDimension = _desc.ArraySize > 6 ? WGPUTextureViewDimension_CubeArray : WGPUTextureViewDimension_Cube;
textureDesc.dimension = WGPUTextureDimension_2D;
textureDesc.size.depthOrArrayLayers *= 6; // Each cubemap uses 6 array slices
break;

View File

@@ -31,6 +31,8 @@ public:
WGPUTexture Texture = nullptr;
// Handle to the WebGPU texture view object.
WGPUTextureView View = nullptr;
// Handle to the WebGPU texture view object for render passes (contains all views).
WGPUTextureView ViewRender = nullptr;
bool HasStencil = false;
bool ReadOnly = false;
uint32 DepthSlice = WGPU_DEPTH_SLICE_UNDEFINED;

View File

@@ -238,4 +238,55 @@ PixelFormat RenderToolsWebGPU::ToPixelFormat(WGPUTextureFormat format)
}
}
PixelFormat RenderToolsWebGPU::ToPixelFormat(WGPUVertexFormat format)
{
switch (format)
{
// @formatter:off
case WGPUVertexFormat_Uint8: return PixelFormat::R8_UInt;
case WGPUVertexFormat_Uint8x2: return PixelFormat::R8G8_UInt;
case WGPUVertexFormat_Uint8x4: return PixelFormat::R8G8B8A8_UInt;
case WGPUVertexFormat_Sint8: return PixelFormat::R8_SInt;
case WGPUVertexFormat_Sint8x2: return PixelFormat::R8G8_SInt;
case WGPUVertexFormat_Sint8x4: return PixelFormat::R8G8B8A8_SInt;
case WGPUVertexFormat_Unorm8: return PixelFormat::R8_UNorm;
case WGPUVertexFormat_Unorm8x2: return PixelFormat::R8G8_UNorm;
case WGPUVertexFormat_Unorm8x4: return PixelFormat::R8G8B8A8_UNorm;
case WGPUVertexFormat_Snorm8: return PixelFormat::R8_SNorm;
case WGPUVertexFormat_Snorm8x2: return PixelFormat::R8G8_SNorm;
case WGPUVertexFormat_Snorm8x4: return PixelFormat::R8G8B8A8_SNorm;
case WGPUVertexFormat_Uint16: return PixelFormat::R16_UInt;
case WGPUVertexFormat_Uint16x2: return PixelFormat::R16G16_UInt;
case WGPUVertexFormat_Uint16x4: return PixelFormat::R16G16B16A16_UInt;
case WGPUVertexFormat_Sint16: return PixelFormat::R16_SInt;
case WGPUVertexFormat_Sint16x2: return PixelFormat::R16G16_SInt;
case WGPUVertexFormat_Sint16x4: return PixelFormat::R16G16B16A16_SInt;
case WGPUVertexFormat_Unorm16: return PixelFormat::R16_UNorm;
case WGPUVertexFormat_Unorm16x2: return PixelFormat::R16G16_UNorm;
case WGPUVertexFormat_Unorm16x4: return PixelFormat::R16G16B16A16_UNorm;
case WGPUVertexFormat_Snorm16: return PixelFormat::R16_SNorm;
case WGPUVertexFormat_Snorm16x2: return PixelFormat::R16G16_SNorm;
case WGPUVertexFormat_Snorm16x4: return PixelFormat::R16G16B16A16_SNorm;
case WGPUVertexFormat_Float16: return PixelFormat::R16_Float;
case WGPUVertexFormat_Float16x2: return PixelFormat::R16G16_Float;
case WGPUVertexFormat_Float16x4: return PixelFormat::R16G16B16A16_Float;
case WGPUVertexFormat_Float32: return PixelFormat::R32_Float;
case WGPUVertexFormat_Float32x2: return PixelFormat::R32G32_Float;
case WGPUVertexFormat_Float32x3: return PixelFormat::R32G32B32_Float;
case WGPUVertexFormat_Float32x4: return PixelFormat::R32G32B32A32_Float;
case WGPUVertexFormat_Uint32: return PixelFormat::R32_UInt;
case WGPUVertexFormat_Uint32x2: return PixelFormat::R32G32_UInt;
case WGPUVertexFormat_Uint32x3: return PixelFormat::R32G32B32_UInt;
case WGPUVertexFormat_Uint32x4: return PixelFormat::R32G32B32A32_UInt;
case WGPUVertexFormat_Sint32: return PixelFormat::R32_SInt;
case WGPUVertexFormat_Sint32x2: return PixelFormat::R32G32_SInt;
case WGPUVertexFormat_Sint32x3: return PixelFormat::R32G32B32_SInt;
case WGPUVertexFormat_Sint32x4: return PixelFormat::R32G32B32A32_SInt;
case WGPUVertexFormat_Unorm10_10_10_2: return PixelFormat::R10G10B10A2_UNorm;
case WGPUVertexFormat_Unorm8x4BGRA: return PixelFormat::B8G8R8A8_UNorm;
default: return PixelFormat::Unknown;
// @formatter:on
}
}
#endif

View File

@@ -69,6 +69,7 @@ public:
static WGPUVertexFormat ToVertexFormat(PixelFormat format);
static WGPUTextureFormat ToTextureFormat(PixelFormat format);
static PixelFormat ToPixelFormat(WGPUTextureFormat format);
static PixelFormat ToPixelFormat(WGPUVertexFormat format);
};
#endif