diff --git a/src/SharpEmu.Libs/Gpu/Rendering/DepthTargetResolver.cs b/src/SharpEmu.Libs/Gpu/Rendering/DepthTargetResolver.cs index 0c8808e..83733fe 100644 --- a/src/SharpEmu.Libs/Gpu/Rendering/DepthTargetResolver.cs +++ b/src/SharpEmu.Libs/Gpu/Rendering/DepthTargetResolver.cs @@ -63,6 +63,19 @@ public readonly record struct DepthStencilState( public bool IsReadOnly(Format format) => AttachmentWriteAspects(format) == ImageAspectFlags.None; + // The layout for an attachment the draw does not also sample: writable in every aspect the + // format has, so draws that toggle depth or stencil writes keep one layout (and one rendering + // scope). Only a sampled attachment needs the read-only layouts of AttachmentLayout. + public static ImageLayout WritableAttachmentLayout(Format format) + { + var available = ViewFormatRules.DepthAspects(format); + var hasDepth = (available & ImageAspectFlags.DepthBit) != 0; + var hasStencil = (available & ImageAspectFlags.StencilBit) != 0; + return hasDepth && hasStencil ? ImageLayout.DepthStencilAttachmentOptimal + : hasStencil ? ImageLayout.StencilAttachmentOptimal + : ImageLayout.DepthAttachmentOptimal; + } + public ImageLayout AttachmentLayout(Format format) { var available = ViewFormatRules.DepthAspects(format); diff --git a/src/SharpEmu.Libs/Gpu/Rendering/IRenderHost.cs b/src/SharpEmu.Libs/Gpu/Rendering/IRenderHost.cs index b8017b2..c83fdc1 100644 --- a/src/SharpEmu.Libs/Gpu/Rendering/IRenderHost.cs +++ b/src/SharpEmu.Libs/Gpu/Rendering/IRenderHost.cs @@ -137,6 +137,9 @@ public interface IRenderHost void EndRendering(); + // Whether a texture bound for the draw being prepared reads the depth attachment's subresources. + bool SamplesDepthAttachment(in DepthAttachmentState depth) => true; + // The next draw stores to buffers or storage images; called before its BeginRendering. void PrepareMemoryWritingDraw() { } diff --git a/src/SharpEmu.Libs/Gpu/Rendering/RenderExecutor.Targets.cs b/src/SharpEmu.Libs/Gpu/Rendering/RenderExecutor.Targets.cs index c8029b8..09230df 100644 --- a/src/SharpEmu.Libs/Gpu/Rendering/RenderExecutor.Targets.cs +++ b/src/SharpEmu.Libs/Gpu/Rendering/RenderExecutor.Targets.cs @@ -251,7 +251,9 @@ public sealed partial class RenderExecutor } var loadState = depth.LoadState; - var layout = loadState.AttachmentLayout(target.Format); + var layout = _host.SamplesDepthAttachment(in depth) + ? loadState.AttachmentLayout(target.Format) + : DepthStencilState.WritableAttachmentLayout(target.Format); _host.TransitionDepthAttachment(in depth, layout, loadState.AttachmentWriteAspects(target.Format)); var view = target.Request.View; rendering.Width = Math.Min(rendering.Width, target.Width); diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs index 143755c..9bdeb10 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Descriptors.cs @@ -400,6 +400,28 @@ internal static unsafe partial class VulkanVideoPresenter BindBuffers(stage); ObtainDeviceAddressRanges(stage); BindImages(stage); + _preparedTextures.Add(stage.Textures); + } + + // Textures bound for the draw being prepared; cleared when its preparation closes. + private readonly List _preparedTextures = new(); + + bool IRenderHost.SamplesDepthAttachment(in DepthAttachmentState depth) + { + var image = _imageCache.GetImage(depth.Image); + var attachmentView = depth.Target.Target.Request.View; + foreach (var textures in _preparedTextures) + { + foreach (var texture in textures) + { + if (!texture.IsHostMovie && ReferenceEquals(texture.CachedImage, image) && ViewsOverlap(texture.Request.View, attachmentView)) + { + return true; + } + } + } + + return false; } private BufferView NullStorageBuffer() => new(_bufferCache.GetBuffer(GuestBufferCache.NullBufferId).Handle, 0, NullStorageBufferBytes); diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs index a6ea683..f2c9ce8 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Rendering.cs @@ -66,6 +66,7 @@ internal static unsafe partial class VulkanVideoPresenter } owner._preparation = null; + owner._preparedTextures.Clear(); streamRetention.Dispose(); if (StencilStorageImages is { } stencilImages) {