Add stencil buffer usage with object layer information

#3080 #967
This commit is contained in:
Wojtek Figat
2025-10-07 18:07:23 +02:00
parent 823ed247d2
commit 361fc3ecfb
36 changed files with 291 additions and 65 deletions

View File

@@ -11,6 +11,7 @@
#include "GPUSamplerDX11.h"
#include "GPUVertexLayoutDX11.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Math/Rectangle.h"
#include "Engine/Profiler/RenderStats.h"
@@ -216,7 +217,10 @@ void GPUContextDX11::ClearDepth(GPUTextureView* depthBuffer, float depthValue, u
if (depthBufferDX11)
{
ASSERT(depthBufferDX11->DSV());
_context->ClearDepthStencilView(depthBufferDX11->DSV(), D3D11_CLEAR_DEPTH, depthValue, stencilValue);
UINT clearFlags = D3D11_CLEAR_DEPTH;
if (PixelFormatExtensions::HasStencil(depthBufferDX11->GetFormat()))
clearFlags |= D3D11_CLEAR_STENCIL;
_context->ClearDepthStencilView(depthBufferDX11->DSV(), clearFlags, depthValue, stencilValue);
}
}

View File

@@ -150,6 +150,7 @@ void GPUTextureDX11::OnReleaseGPU()
_handleArray.Release();
_handleVolume.Release();
_handleReadOnlyDepth.Release();
_handleStencil.Release();
DX_SAFE_RELEASE_CHECK(_resource, 0);
// Base
@@ -547,6 +548,41 @@ void GPUTextureDX11::initHandles()
}
_handleReadOnlyDepth.Init(this, rtView, srView, dsView, nullptr, format, msaa);
}
// Stencil view
if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format))
{
PixelFormat stencilFormat;
switch (_dxgiFormatDSV)
{
case PixelFormat::D24_UNorm_S8_UInt:
srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
stencilFormat = PixelFormat::X24_Typeless_G8_UInt;
break;
case PixelFormat::D32_Float_S8X24_UInt:
srDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
stencilFormat = PixelFormat::X32_Typeless_G8X24_UInt;
break;
}
if (isCubeMap)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srDesc.TextureCube.MostDetailedMip = 0;
srDesc.TextureCube.MipLevels = mipLevels;
}
else if (isMsaa)
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
}
else
{
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = mipLevels;
}
VALIDATE_DIRECTX_CALL(device->CreateShaderResourceView(_resource, &srDesc, &srView));
_handleStencil.Init(this, nullptr, srView, nullptr, nullptr, stencilFormat, msaa);
}
}
bool GPUTextureDX11::GetData(int32 arrayIndex, int32 mipMapIndex, TextureMipData& data, uint32 mipRowPitch)

View File

@@ -158,6 +158,7 @@ private:
GPUTextureViewDX11 _handleArray;
GPUTextureViewDX11 _handleVolume;
GPUTextureViewDX11 _handleReadOnlyDepth;
GPUTextureViewDX11 _handleStencil;
Array<GPUTextureViewDX11> _handlesPerSlice; // [slice]
Array<Array<GPUTextureViewDX11>> _handlesPerMip; // [slice][mip]
@@ -225,6 +226,11 @@ public:
ASSERT(_desc.Flags & GPUTextureFlags::ReadOnlyDepthView);
return (GPUTextureView*)&_handleReadOnlyDepth;
}
GPUTextureView* ViewStencil() const override
{
ASSERT(_desc.Flags & GPUTextureFlags::DepthStencil);
return (GPUTextureView*)&_handleStencil;
}
void* GetNativePtr() const override
{
return static_cast<void*>(_resource);

View File

@@ -36,6 +36,7 @@
#include "CommandSignatureDX12.h"
#include "Engine/Profiler/RenderStats.h"
#include "Engine/Graphics/GPUResourceAccess.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Threading/Threading.h"
@@ -823,7 +824,10 @@ void GPUContextDX12::ClearDepth(GPUTextureView* depthBuffer, float depthValue, u
SetResourceState(depthBufferDX12->GetResourceOwner(), D3D12_RESOURCE_STATE_DEPTH_WRITE, depthBufferDX12->SubresourceIndex);
flushRBs();
_commandList->ClearDepthStencilView(depthBufferDX12->DSV(), D3D12_CLEAR_FLAG_DEPTH, depthValue, stencilValue, 0, nullptr);
D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH;
if (PixelFormatExtensions::HasStencil(depthBufferDX12->GetFormat()))
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
_commandList->ClearDepthStencilView(depthBufferDX12->DSV(), clearFlags, depthValue, stencilValue, 0, nullptr);
}
}

View File

@@ -227,6 +227,8 @@ void GPUTextureDX12::OnReleaseGPU()
_handlesPerSlice.Resize(0, false);
_handleArray.Release();
_handleVolume.Release();
_handleReadOnlyDepth.Release();
_handleStencil.Release();
_srv.Release();
_uav.Release();
releaseResource();
@@ -721,6 +723,45 @@ void GPUTextureDX12::initHandles()
_handleReadOnlyDepth.SetSRV(srDesc);
}
}
// Stencil view
if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format))
{
PixelFormat stencilFormat;
switch (_dxgiFormatDSV)
{
case PixelFormat::D24_UNorm_S8_UInt:
srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
stencilFormat = PixelFormat::X24_Typeless_G8_UInt;
break;
case PixelFormat::D32_Float_S8X24_UInt:
srDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
stencilFormat = PixelFormat::X32_Typeless_G8X24_UInt;
break;
}
if (isCubeMap)
{
srDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
srDesc.TextureCube.MostDetailedMip = 0;
srDesc.TextureCube.MipLevels = mipLevels;
srDesc.TextureCube.ResourceMinLODClamp = 0;
}
else if (isMsaa)
{
srDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
}
else
{
srDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = mipLevels;
srDesc.Texture2D.ResourceMinLODClamp = 0;
srDesc.Texture2D.PlaneSlice = 1;
}
_handleStencil.Init(this, _device, this, stencilFormat, msaa);
_handleStencil.ReadOnlyDepthView = true;
_handleStencil.SetSRV(srDesc);
}
}
#endif

View File

@@ -91,7 +91,7 @@ public:
// [IShaderResourceDX12]
bool IsDepthStencilResource() const override
{
return _dsv.IsValid();
return ReadOnlyDepthView || _dsv.IsValid();
}
D3D12_CPU_DESCRIPTOR_HANDLE SRV() const override
{
@@ -117,6 +117,7 @@ private:
GPUTextureViewDX12 _handleArray;
GPUTextureViewDX12 _handleVolume;
GPUTextureViewDX12 _handleReadOnlyDepth;
GPUTextureViewDX12 _handleStencil;
Array<GPUTextureViewDX12> _handlesPerSlice; // [slice]
Array<Array<GPUTextureViewDX12>> _handlesPerMip; // [slice][mip]
@@ -165,6 +166,11 @@ public:
ASSERT(_desc.Flags & GPUTextureFlags::ReadOnlyDepthView);
return (GPUTextureView*)&_handleReadOnlyDepth;
}
GPUTextureView* ViewStencil() const override
{
ASSERT(_desc.Flags & GPUTextureFlags::DepthStencil);
return (GPUTextureView*)&_handleStencil;
}
void* GetNativePtr() const override
{
return (void*)_resource;

View File

@@ -33,6 +33,10 @@ public:
{
return nullptr;
}
GPUTextureView* ViewStencil() const override
{
return nullptr;
}
void* GetNativePtr() const override
{
return nullptr;

View File

@@ -11,7 +11,7 @@
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Scripting/Enums.h"
void GPUTextureViewVulkan::Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels, int32 firstMipIndex, int32 arraySize, int32 firstArraySlice, bool readOnlyDepth)
void GPUTextureViewVulkan::Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels, int32 firstMipIndex, int32 arraySize, int32 firstArraySlice, bool readOnlyDepth, bool stencilView)
{
ASSERT(View == VK_NULL_HANDLE);
@@ -57,7 +57,13 @@ void GPUTextureViewVulkan::Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* ow
SubresourceIndex = RenderTools::CalcSubresourceIndex(firstMipIndex, firstArraySlice, totalMipLevels);
}
if (PixelFormatExtensions::IsDepthStencil(format))
if (stencilView)
{
range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
LayoutRTV = readOnlyDepth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
LayoutSRV = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
else if (PixelFormatExtensions::IsDepthStencil(format))
{
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
#if 0
@@ -157,13 +163,23 @@ void GPUTextureViewVulkan::DescriptorAsImage(GPUContextVulkan* context, VkImageV
imageView = View;
layout = LayoutSRV;
const VkImageAspectFlags aspectMask = Info.subresourceRange.aspectMask;
if (aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
if (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
{
// Transition depth-only when binding depth buffer with stencil
// Transition depth-only when binding depth buffer with stencil (or stencil-only without depth)
if (ViewSRV == VK_NULL_HANDLE)
{
VkImageViewCreateInfo createInfo = Info;
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)
{
// Stencil
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
createInfo.components.g = VK_COMPONENT_SWIZZLE_R; // Map .g component in shader to .r of stencil plane
}
else
{
// Depth
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
VALIDATE_VULKAN_RESULT(vkCreateImageView(Device->Device, &createInfo, nullptr, &ViewSRV));
}
imageView = ViewSRV;
@@ -434,6 +450,26 @@ void GPUTextureVulkan::initHandles()
{
_handleReadOnlyDepth.Init(_device, this, _image, mipLevels, format, msaa, extent, VK_IMAGE_VIEW_TYPE_2D, mipLevels, 0, 1, 0, true);
}
// Stencil view
if (IsDepthStencil() && IsShaderResource() && PixelFormatExtensions::HasStencil(format))
{
PixelFormat stencilFormat;
switch (format)
{
case PixelFormat::D24_UNorm_S8_UInt:
case PixelFormat::R24_UNorm_X8_Typeless:
case PixelFormat::R24G8_Typeless:
stencilFormat = PixelFormat::X24_Typeless_G8_UInt;
break;
case PixelFormat::D32_Float_S8X24_UInt:
case PixelFormat::R32_Float_X8X24_Typeless:
case PixelFormat::R32G8X24_Typeless:
stencilFormat = PixelFormat::X32_Typeless_G8X24_UInt;
break;
}
_handleStencil.Init(_device, this, _image, mipLevels, stencilFormat, msaa, extent, VK_IMAGE_VIEW_TYPE_2D, mipLevels, 0, 1, 0, true, true);
}
}
void GPUTextureVulkan::OnResidentMipsChanged()
@@ -457,6 +493,7 @@ void GPUTextureVulkan::OnReleaseGPU()
_handleVolume.Release();
_handleUAV.Release();
_handleReadOnlyDepth.Release();
_handleStencil.Release();
for (int32 i = 0; i < _handlesPerMip.Count(); i++)
{
for (int32 j = 0; j < _handlesPerMip[i].Count(); j++)

View File

@@ -45,7 +45,7 @@ public:
#endif
public:
void Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels = 1, int32 firstMipIndex = 0, int32 arraySize = 1, int32 firstArraySlice = 0, bool readOnlyDepth = false);
void Init(GPUDeviceVulkan* device, ResourceOwnerVulkan* owner, VkImage image, int32 totalMipLevels, PixelFormat format, MSAALevel msaa, VkExtent3D extent, VkImageViewType viewType, int32 mipLevels = 1, int32 firstMipIndex = 0, int32 arraySize = 1, int32 firstArraySlice = 0, bool readOnlyDepth = false, bool stencilView = false);
VkImageView GetFramebufferView();
@@ -79,6 +79,7 @@ private:
GPUTextureViewVulkan _handleVolume;
GPUTextureViewVulkan _handleUAV;
GPUTextureViewVulkan _handleReadOnlyDepth;
GPUTextureViewVulkan _handleStencil;
Array<GPUTextureViewVulkan> _handlesPerSlice; // [slice]
Array<Array<GPUTextureViewVulkan>> _handlesPerMip; // [slice][mip]
@@ -140,6 +141,11 @@ public:
ASSERT(_desc.Flags & GPUTextureFlags::ReadOnlyDepthView);
return (GPUTextureView*)&_handleReadOnlyDepth;
}
GPUTextureView* ViewStencil() const override
{
ASSERT(_desc.Flags & GPUTextureFlags::DepthStencil);
return (GPUTextureView*)&_handleStencil;
}
void* GetNativePtr() const override
{
return (void*)_image;