Skip to content

Commit 9306540

Browse files
committed
fix: Vulkan: honor stage-declared read-only depth access on worker command lists
1 parent d4d5e75 commit 9306540

4 files changed

Lines changed: 54 additions & 5 deletions

File tree

sources/engine/Stride.Graphics/CommandList.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ public partial class CommandList : GraphicsResourceBase
5252
/// </summary>
5353
public int ViewportCount => boundViewportCount;
5454

55+
/// <summary>
56+
/// Gets how draws access the currently bound Depth-Stencil Buffer.
57+
/// Part of the binding: reset to <see cref="DepthStencilAccess.Write"/> by any
58+
/// <c>SetRenderTargets</c> call.
59+
/// Stopgap until render pass objects declare this per pass.
60+
/// </summary>
61+
internal DepthStencilAccess DepthStencilAccess { get; set; }
62+
5563

5664
/// <summary>
5765
/// Binds a single viewport to the rasterizer stage of the pipeline.
@@ -238,6 +246,7 @@ public void ResetTargets()
238246
ResetTargetsImpl();
239247

240248
depthStencilBuffer = null;
249+
DepthStencilAccess = DepthStencilAccess.Write;
241250
renderTargets.AsSpan().Clear();
242251
}
243252

@@ -260,6 +269,7 @@ public void ResetTargets()
260269
public void SetRenderTargetAndViewport(Texture depthStencilView, Texture renderTargetView)
261270
{
262271
depthStencilBuffer = depthStencilView;
272+
DepthStencilAccess = DepthStencilAccess.Write;
263273

264274
renderTargets[0] = renderTargetView; // TODO: Should we clear the other entries?
265275
renderTargetCount = renderTargetView is not null ? 1 : 0;
@@ -286,6 +296,7 @@ public void SetRenderTargetAndViewport(Texture depthStencilView, Texture renderT
286296
public void SetRenderTargetsAndViewport(ReadOnlySpan<Texture> renderTargetViews)
287297
{
288298
depthStencilBuffer = null;
299+
DepthStencilAccess = DepthStencilAccess.Write;
289300

290301
renderTargetCount = renderTargetViews.Length;
291302
renderTargetViews.CopyTo(renderTargets);
@@ -315,6 +326,7 @@ public void SetRenderTargetsAndViewport(ReadOnlySpan<Texture> renderTargetViews)
315326
public void SetRenderTargetsAndViewport(Texture depthStencilView, params ReadOnlySpan<Texture> renderTargetViews)
316327
{
317328
depthStencilBuffer = depthStencilView;
329+
DepthStencilAccess = DepthStencilAccess.Write;
318330

319331
renderTargetCount = renderTargetViews.Length;
320332
renderTargetViews.CopyTo(renderTargets); // TODO: Should we clear the other entries?
@@ -340,6 +352,7 @@ public void SetRenderTargetsAndViewport(Texture depthStencilView, params ReadOnl
340352
public void SetRenderTarget(Texture depthStencilView, Texture renderTargetView)
341353
{
342354
depthStencilBuffer = depthStencilView;
355+
DepthStencilAccess = DepthStencilAccess.Write;
343356

344357
renderTargetCount = renderTargetView is not null ? 1 : 0;
345358
renderTargets[0] = renderTargetView; // TODO: Should we clear the other entries?
@@ -367,6 +380,7 @@ public void SetRenderTargets(ReadOnlySpan<Texture> renderTargetViews)
367380
ArgumentOutOfRangeException.ThrowIfGreaterThan(renderTargetViews.Length, MaxRenderTargetCount);
368381

369382
depthStencilBuffer = null;
383+
DepthStencilAccess = DepthStencilAccess.Write;
370384

371385
renderTargetCount = renderTargetViews.Length;
372386
renderTargetViews.CopyTo(renderTargets); // TODO: Should we clear the other entries?
@@ -397,6 +411,7 @@ public void SetRenderTargets(Texture depthStencilView, params ReadOnlySpan<Textu
397411
ArgumentOutOfRangeException.ThrowIfGreaterThan(renderTargetViews.Length, MaxRenderTargetCount);
398412

399413
depthStencilBuffer = depthStencilView;
414+
DepthStencilAccess = DepthStencilAccess.Write;
400415

401416
renderTargetCount = renderTargetViews.Length;
402417
renderTargetViews.CopyTo(renderTargets); // TODO: Should we clear the other entries?
@@ -482,6 +497,8 @@ public void ClearState()
482497
{
483498
ClearStateImpl();
484499

500+
DepthStencilAccess = DepthStencilAccess.Write;
501+
485502
// Setup empty viewports
486503
Array.Clear(viewports);
487504

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
4+
namespace Stride.Graphics;
5+
6+
/// <summary>
7+
/// Defines how draws access the bound Depth-Stencil Buffer.
8+
/// </summary>
9+
internal enum DepthStencilAccess
10+
{
11+
/// <summary>
12+
/// Depth and stencil writes are allowed.
13+
/// </summary>
14+
Write,
15+
16+
/// <summary>
17+
/// Read-only: the buffer can be depth-tested and sampled at the same time.
18+
/// Depth and stencil writes are dropped.
19+
/// </summary>
20+
Read,
21+
}

sources/engine/Stride.Graphics/Vulkan/CommandList.Vulkan.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ private unsafe void PrepareDraw()
281281
// A read-only depth view drops depth and stencil writes instead of being invalid
282282
// usage, matching D3D12's read-only depth-stencil view behavior
283283
var depthStencilState = activePipeline.Description.DepthStencilState;
284-
bool depthWritesAllowed = depthStencilBuffer?.IsDepthStencilReadOnly != true;
284+
bool depthWritesAllowed = !(depthStencilBuffer != null && (depthStencilBuffer.IsDepthStencilReadOnly || DepthStencilAccess == DepthStencilAccess.Read));
285285
GraphicsDevice.NativeDeviceApi.vkCmdSetDepthWriteEnable(currentCommandList.NativeCommandBuffer, depthStencilState.DepthBufferWriteEnable && depthWritesAllowed);
286286
GraphicsDevice.NativeDeviceApi.vkCmdSetStencilWriteMask(currentCommandList.NativeCommandBuffer, VkStencilFaceFlags.FrontAndBack, depthWritesAllowed ? depthStencilState.StencilWriteMask : 0u);
287287
}
@@ -384,7 +384,8 @@ private unsafe void BindDescriptorSets()
384384
// Sampling the depth buffer while it is bound as a read-only attachment:
385385
// the image rides in DepthStencilReadOnlyOptimal, including on worker
386386
// command lists that did not record the transition themselves.
387-
bool sampledBoundReadOnlyDepth = depthStencilBuffer?.IsDepthStencilReadOnly == true
387+
bool sampledBoundReadOnlyDepth = depthStencilBuffer != null
388+
&& (depthStencilBuffer.IsDepthStencilReadOnly || DepthStencilAccess == DepthStencilAccess.Read)
388389
&& parent == (depthStencilBuffer.ParentTexture ?? depthStencilBuffer);
389390
var imageLayout = perCb == BarrierLayout.DepthStencilRead || (perCb == null && sampledBoundReadOnlyDepth)
390391
? VkImageLayout.DepthStencilReadOnlyOptimal
@@ -1654,9 +1655,10 @@ private unsafe void EnsureRenderPass()
16541655
if (activePipeline == null || activePipeline.NativePipeline == VkPipeline.Null)
16551656
return;
16561657

1657-
// The depth attachment layout follows the bound view: a read-only depth view keeps the
1658-
// image in DepthStencilReadOnlyOptimal so it can be sampled at the same time
1659-
bool depthReadOnly = depthStencilBuffer?.IsDepthStencilReadOnly == true;
1658+
// The depth attachment layout follows the bound view and the declared stage access:
1659+
// a read-only depth keeps the image in DepthStencilReadOnlyOptimal so it can be
1660+
// sampled at the same time
1661+
bool depthReadOnly = depthStencilBuffer != null && (depthStencilBuffer.IsDepthStencilReadOnly || DepthStencilAccess == DepthStencilAccess.Read);
16601662

16611663
// The render pass instance stays active across pipeline changes as long as the
16621664
// attachments and the depth layout stay the same

sources/engine/Stride.Rendering/Rendering/RenderSystem.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,14 @@ public void Draw(RenderDrawContext renderDrawContext, RenderView renderView, Ren
447447
: BarrierLayout.DepthStencilWrite);
448448
}
449449

450+
// Let command lists know the depth buffer stays readable during this stage, so the
451+
// depth attachment layout and descriptors can declare it (e.g. sampling the depth
452+
// while it stays bound)
453+
var depthStencilAccess = stageDepthAccess == RenderStageDepthAccess.Read
454+
? DepthStencilAccess.Read
455+
: DepthStencilAccess.Write;
456+
commandList.DepthStencilAccess = depthStencilAccess;
457+
450458
// Collect one command list per batch and the main one up to this point
451459
if (commandLists == null || (commandLists.Length < batchCount + 1))
452460
{
@@ -465,6 +473,7 @@ public void Draw(RenderDrawContext renderDrawContext, RenderView renderView, Ren
465473
threadContext.CommandList.SetRenderTargets(depthStencilBuffer, renderTargetsToSet);
466474
threadContext.CommandList.SetViewport(viewport);
467475
threadContext.CommandList.SetScissorRectangle(scissor);
476+
threadContext.CommandList.DepthStencilAccess = depthStencilAccess;
468477

469478
var currentStart = batchSize * batchIndex;
470479
int currentEnd;

0 commit comments

Comments
 (0)