From 3157596b5dd092eeb3f6b2bc35bab4b3d1afeb71 Mon Sep 17 00:00:00 2001 From: Misaki Date: Wed, 1 Apr 2026 15:28:25 +0900 Subject: [PATCH] Fix D3D12 depth format and stencil barrier issues in Render Graph --- .../D3D12CommandBuffer.cs | 6 ++++++ .../D3D12ResourceAllocator.cs | 19 ++++++++++++++----- .../Utilities/D3D12Utility.cs | 17 +++++++++++++++++ src/Runtime/Ghost.Graphics.RHI/Common.cs | 9 ++++++++- .../RenderGraphModule/RenderGraphBuilder.cs | 2 +- .../RenderGraphModule/RenderGraphExecutor.cs | 8 +++++--- .../RenderGraphNativePassBuilder.cs | 12 ++++++++++++ .../RenderGraphModule/RenderGraphTypes.cs | 2 ++ 8 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs b/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs index 04b93ed..60dd476 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs @@ -537,6 +537,12 @@ internal unsafe class D3D12CommandBuffer : D3D12Object D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE }; + if (!depthDesc.HasStencil) + { + stencilLoadAccessType = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS; + stencilStoreAccessType = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; + } + var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC { cpuDescriptor = cpuHandle, diff --git a/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs b/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs index be6a02f..bdec38b 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/D3D12ResourceAllocator.cs @@ -39,7 +39,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator } } - private static D3D12_SHADER_RESOURCE_VIEW_DESC CreateTextureSrvDesc(ID3D12Resource* pResource, uint mipLevels, uint arraySize, bool isCubeMap) + private static D3D12_SHADER_RESOURCE_VIEW_DESC CreateTextureSrvDesc(ID3D12Resource* pResource, uint mipLevels, uint arraySize, bool isCubeMap, TextureFormat originalFormat) { var resourceDesc = pResource->GetDesc(); var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC @@ -48,6 +48,15 @@ internal sealed unsafe partial class D3D12ResourceAllocator Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING }; + if (originalFormat == TextureFormat.D32_Float) + { + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + } + else if (originalFormat == TextureFormat.D24_UNorm_S8_UInt) + { + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + } + switch (resourceDesc.Dimension) { case D3D12_RESOURCE_DIMENSION_TEXTURE1D: @@ -251,7 +260,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator return rtvDesc; } - private static D3D12_DEPTH_STENCIL_VIEW_DESC CreateDsvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, D3D12_DSV_FLAGS flags = D3D12_DSV_FLAG_NONE) + private static D3D12_DEPTH_STENCIL_VIEW_DESC CreateDsvDesc(ID3D12Resource* pResource, uint mipSlice = 0, uint firstArraySlice = 0, D3D12_DSV_FLAGS flags = D3D12_DSV_FLAG_NONE, TextureFormat originalFormat = TextureFormat.Unknown) { var resourceDesc = pResource->GetDesc(); var dsvDesc = new D3D12_DEPTH_STENCIL_VIEW_DESC @@ -276,7 +285,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator break; } - dsvDesc.Format = resourceDesc.Format; + dsvDesc.Format = originalFormat == TextureFormat.Unknown ? resourceDesc.Format : originalFormat.ToDXGIFormat(); var isArray = dsvDesc.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2DARRAY || @@ -644,7 +653,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv); var isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray; - var srvDesc = CreateTextureSrvDesc(pResource, resourceDesc.MipLevels, resourceDesc.DepthOrArraySize, isCubeMap); + var srvDesc = CreateTextureSrvDesc(pResource, resourceDesc.MipLevels, resourceDesc.DepthOrArraySize, isCubeMap, desc.Format); _device.NativeObject.Get()->CreateShaderResourceView(pResource, &srvDesc, cpuHandle); _descriptorAllocator.CopyToShaderVisible(resourceDescriptor.srv); @@ -663,7 +672,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator { resourceDescriptor.dsv = _descriptorAllocator.AllocateDSV(); var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.dsv); - var dsvDesc = CreateDsvDesc(pResource); + var dsvDesc = CreateDsvDesc(pResource, 0, 0, D3D12_DSV_FLAG_NONE, desc.Format); _device.NativeObject.Get()->CreateDepthStencilView(pResource, &dsvDesc, cpuHandle); } diff --git a/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs b/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs index b1bc629..4352b58 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs @@ -140,6 +140,8 @@ internal static unsafe class D3D12Utility TextureFormat.R32G32B32A32_Float => DXGI_FORMAT_R32G32B32A32_FLOAT, TextureFormat.D24_UNorm_S8_UInt => DXGI_FORMAT_D24_UNORM_S8_UINT, TextureFormat.D32_Float => DXGI_FORMAT_D32_FLOAT, + TextureFormat.R32_Typeless => DXGI_FORMAT_R32_TYPELESS, + TextureFormat.R24G8_Typeless => DXGI_FORMAT_R24G8_TYPELESS, _ => throw new NotSupportedException($"Texture format {format} is not supported."), }; } @@ -154,6 +156,8 @@ internal static unsafe class D3D12Utility DXGI_FORMAT_R32G32B32A32_FLOAT => TextureFormat.R32G32B32A32_Float, DXGI_FORMAT_D24_UNORM_S8_UINT => TextureFormat.D24_UNorm_S8_UInt, DXGI_FORMAT_D32_FLOAT => TextureFormat.D32_Float, + DXGI_FORMAT_R32_TYPELESS => TextureFormat.R32_Typeless, + DXGI_FORMAT_R24G8_TYPELESS => TextureFormat.R24G8_Typeless, _ => throw new NotSupportedException($"DXGI format {format} is not supported.") }; } @@ -385,6 +389,19 @@ internal static unsafe class D3D12Utility public static D3D12_RESOURCE_DESC ToD3D12ResourceDesc(this in TextureDesc desc) { var dxgiFormat = desc.Format.ToDXGIFormat(); + + if (desc.Usage.HasFlag(TextureUsage.DepthStencil) && desc.Usage.HasFlag(TextureUsage.ShaderResource)) + { + if (dxgiFormat == DXGI_FORMAT_D32_FLOAT) + { + dxgiFormat = DXGI_FORMAT_R32_TYPELESS; + } + else if (dxgiFormat == DXGI_FORMAT_D24_UNORM_S8_UINT) + { + dxgiFormat = DXGI_FORMAT_R24G8_TYPELESS; + } + } + var maxDimension = Math.Max(desc.Width, Math.Max(desc.Height, desc.Slice)); var mipLevels = desc.MipLevels == 0 ? (ushort)(1 + Math.Floor(Math.Log2(maxDimension))) diff --git a/src/Runtime/Ghost.Graphics.RHI/Common.cs b/src/Runtime/Ghost.Graphics.RHI/Common.cs index 3d2535a..85947d3 100644 --- a/src/Runtime/Ghost.Graphics.RHI/Common.cs +++ b/src/Runtime/Ghost.Graphics.RHI/Common.cs @@ -454,6 +454,10 @@ public struct PassDepthStencilDesc get; set; } + public bool HasStencil + { + get; set; + } } @@ -1287,7 +1291,10 @@ public enum TextureFormat R16G16B16A16_Float, R32G32B32A32_Float, D24_UNorm_S8_UInt, - D32_Float + D32_Float, + + R32_Typeless, + R24G8_Typeless, } [Flags] diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs index 66a0ab2..2ff75b3 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs @@ -294,7 +294,7 @@ internal class RenderGraphBuilder : IRasterRenderGraphBuilder, IComputeRenderGra } } - public void SetDepthAttachment(Identifier texture, AccessFlags flags = AccessFlags.ReadWrite) + public void SetDepthAttachment(Identifier texture, AccessFlags flags = AccessFlags.WriteAll) { ThrowIfDisposed(); diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs index 9c935fd..83dc19e 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs @@ -144,11 +144,13 @@ internal sealed class RenderGraphExecutor ? nativePass.depthAttachment.storeOp : AttachmentStoreOp.DontCare, StencilLoadOp = nativePass.hasDepthAttachment - ? nativePass.depthAttachment.loadOp + ? nativePass.depthAttachment.stencilLoadOp : AttachmentLoadOp.DontCare, StencilStoreOp = nativePass.hasDepthAttachment - ? nativePass.depthAttachment.storeOp - : AttachmentStoreOp.DontCare + ? nativePass.depthAttachment.stencilStoreOp + : AttachmentStoreOp.DontCare, + HasStencil = nativePass.hasDepthAttachment && + (_resources.GetResource(nativePass.depthAttachment.texture).rgTextureDesc.format == TextureFormat.D24_UNorm_S8_UInt) }; commandBuffer.BeginRenderPass(new Span(pPassRTDescs, nativePass.colorAttachmentCount), depthDesc); diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs index 9427a49..0181bc4 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs @@ -365,6 +365,18 @@ internal sealed class RenderGraphNativePassBuilder attachment.storeOp = AttachmentStoreOp.Store; } + var hasStencil = resource.rgTextureDesc.format == TextureFormat.D24_UNorm_S8_UInt; + if (hasStencil) + { + attachment.stencilLoadOp = attachment.loadOp; + attachment.stencilStoreOp = attachment.storeOp; + } + else + { + attachment.stencilLoadOp = AttachmentLoadOp.DontCare; + attachment.stencilStoreOp = AttachmentStoreOp.DontCare; + } + } } } diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphTypes.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphTypes.cs index c8e8a33..ecf3c26 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphTypes.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphTypes.cs @@ -384,6 +384,8 @@ internal struct DepthStencilInfo public AccessFlags access; public AttachmentLoadOp loadOp; public AttachmentStoreOp storeOp; + public AttachmentLoadOp stencilLoadOp; + public AttachmentStoreOp stencilStoreOp; public float clearDepth; public byte clearStencil; } \ No newline at end of file