0
0
Fork 0

Implement safe depth-stencil blit using stencil export extension (#4356)

* Implement safe depth-stencil blit using stencil export extension

* Delete depth-stencil blit with buffer path
This commit is contained in:
gdkchan 2023-02-06 00:19:31 -03:00 committed by GitHub
parent 43081c16c4
commit 7528f94536
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 330 additions and 213 deletions

View file

@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_device = device; _device = device;
_attachments = new[] { view }; _attachments = new[] { view };
_validColorAttachments = 1u; _validColorAttachments = isDepthStencil ? 0u : 1u;
Width = width; Width = width;
Height = height; Height = height;
@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Vulkan
AttachmentSamples = new[] { samples }; AttachmentSamples = new[] { samples };
AttachmentFormats = new[] { format }; AttachmentFormats = new[] { format };
AttachmentIndices = new[] { 0 }; AttachmentIndices = isDepthStencil ? Array.Empty<int>() : new[] { 0 };
AttachmentsCount = 1; AttachmentsCount = 1;

View file

@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
public readonly bool SupportsGeometryShaderPassthrough; public readonly bool SupportsGeometryShaderPassthrough;
public readonly bool SupportsSubgroupSizeControl; public readonly bool SupportsSubgroupSizeControl;
public readonly bool SupportsShaderInt8; public readonly bool SupportsShaderInt8;
public readonly bool SupportsShaderStencilExport;
public readonly bool SupportsConditionalRendering; public readonly bool SupportsConditionalRendering;
public readonly bool SupportsExtendedDynamicState; public readonly bool SupportsExtendedDynamicState;
public readonly bool SupportsMultiView; public readonly bool SupportsMultiView;
@ -48,6 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
bool supportsGeometryShaderPassthrough, bool supportsGeometryShaderPassthrough,
bool supportsSubgroupSizeControl, bool supportsSubgroupSizeControl,
bool supportsShaderInt8, bool supportsShaderInt8,
bool supportsShaderStencilExport,
bool supportsConditionalRendering, bool supportsConditionalRendering,
bool supportsExtendedDynamicState, bool supportsExtendedDynamicState,
bool supportsMultiView, bool supportsMultiView,
@ -71,6 +73,7 @@ namespace Ryujinx.Graphics.Vulkan
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough; SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
SupportsSubgroupSizeControl = supportsSubgroupSizeControl; SupportsSubgroupSizeControl = supportsSubgroupSizeControl;
SupportsShaderInt8 = supportsShaderInt8; SupportsShaderInt8 = supportsShaderInt8;
SupportsShaderStencilExport = supportsShaderStencilExport;
SupportsConditionalRendering = supportsConditionalRendering; SupportsConditionalRendering = supportsConditionalRendering;
SupportsExtendedDynamicState = supportsExtendedDynamicState; SupportsExtendedDynamicState = supportsExtendedDynamicState;
SupportsMultiView = supportsMultiView; SupportsMultiView = supportsMultiView;

View file

@ -33,6 +33,8 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IProgram _programConvertIndirectData; private readonly IProgram _programConvertIndirectData;
private readonly IProgram _programColorCopyToNonMs; private readonly IProgram _programColorCopyToNonMs;
private readonly IProgram _programColorDrawToMs; private readonly IProgram _programColorDrawToMs;
private readonly IProgram _programDepthBlit;
private readonly IProgram _programStencilBlit;
public HelperShader(VulkanRenderer gd, Device device) public HelperShader(VulkanRenderer gd, Device device)
{ {
@ -42,13 +44,13 @@ namespace Ryujinx.Graphics.Vulkan
_samplerLinear = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); _samplerLinear = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
_samplerNearest = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest)); _samplerNearest = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
var colorBlitVertexBindings = new ShaderBindings( var blitVertexBindings = new ShaderBindings(
new[] { 1 }, new[] { 1 },
Array.Empty<int>(), Array.Empty<int>(),
Array.Empty<int>(), Array.Empty<int>(),
Array.Empty<int>()); Array.Empty<int>());
var colorBlitFragmentBindings = new ShaderBindings( var blitFragmentBindings = new ShaderBindings(
Array.Empty<int>(), Array.Empty<int>(),
Array.Empty<int>(), Array.Empty<int>(),
new[] { 0 }, new[] { 0 },
@ -56,14 +58,14 @@ namespace Ryujinx.Graphics.Vulkan
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[] _programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
{ {
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, colorBlitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
}); });
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[] _programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
{ {
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, colorBlitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
}); });
var colorClearFragmentBindings = new ShaderBindings( var colorClearFragmentBindings = new ShaderBindings(
@ -74,19 +76,19 @@ namespace Ryujinx.Graphics.Vulkan
_programColorClearF = gd.CreateProgramWithMinimalLayout(new[] _programColorClearF = gd.CreateProgramWithMinimalLayout(new[]
{ {
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.ColorClearFFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorClearFFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
}); });
_programColorClearSI = gd.CreateProgramWithMinimalLayout(new[] _programColorClearSI = gd.CreateProgramWithMinimalLayout(new[]
{ {
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.ColorClearSIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorClearSIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
}); });
_programColorClearUI = gd.CreateProgramWithMinimalLayout(new[] _programColorClearUI = gd.CreateProgramWithMinimalLayout(new[]
{ {
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.ColorClearUIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ColorClearUIFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
}); });
@ -151,6 +153,21 @@ namespace Ryujinx.Graphics.Vulkan
{ {
new ShaderSource(ShaderBinaries.ConvertIndirectDataShaderSource, convertIndirectDataBindings, ShaderStage.Compute, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.ConvertIndirectDataShaderSource, convertIndirectDataBindings, ShaderStage.Compute, TargetLanguage.Spirv),
}); });
_programDepthBlit = gd.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.DepthBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
if (gd.Capabilities.SupportsShaderStencilExport)
{
_programStencilBlit = gd.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.StencilBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
}
} }
public void Blit( public void Blit(
@ -162,6 +179,7 @@ namespace Ryujinx.Graphics.Vulkan
VkFormat dstFormat, VkFormat dstFormat,
Extents2D srcRegion, Extents2D srcRegion,
Extents2D dstRegion, Extents2D dstRegion,
bool isDepthOrStencil,
bool linearFilter, bool linearFilter,
bool clearAlpha = false) bool clearAlpha = false)
{ {
@ -169,10 +187,17 @@ namespace Ryujinx.Graphics.Vulkan
using var cbs = gd.CommandBufferPool.Rent(); using var cbs = gd.CommandBufferPool.Rent();
Blit(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion, linearFilter, clearAlpha); if (isDepthOrStencil)
{
BlitDepthStencil(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion);
}
else
{
BlitColor(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion, linearFilter, clearAlpha);
}
} }
public void Blit( public void BlitColor(
VulkanRenderer gd, VulkanRenderer gd,
CommandBufferScoped cbs, CommandBufferScoped cbs,
TextureView src, TextureView src,
@ -255,6 +280,173 @@ namespace Ryujinx.Graphics.Vulkan
gd.BufferManager.Delete(bufferHandle); gd.BufferManager.Delete(bufferHandle);
} }
private void BlitDepthStencil(
VulkanRenderer gd,
CommandBufferScoped cbs,
TextureView src,
Auto<DisposableImageView> dst,
int dstWidth,
int dstHeight,
VkFormat dstFormat,
Extents2D srcRegion,
Extents2D dstRegion)
{
_pipeline.SetCommandBuffer(cbs);
const int RegionBufferSize = 16;
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
region[0] = (float)srcRegion.X1 / src.Width;
region[1] = (float)srcRegion.X2 / src.Width;
region[2] = (float)srcRegion.Y1 / src.Height;
region[3] = (float)srcRegion.Y2 / src.Height;
if (dstRegion.X1 > dstRegion.X2)
{
(region[0], region[1]) = (region[1], region[0]);
}
if (dstRegion.Y1 > dstRegion.Y2)
{
(region[2], region[3]) = (region[3], region[2]);
}
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize, false);
gd.BufferManager.SetData<float>(bufferHandle, 0, region);
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
var rect = new Rectangle<float>(
MathF.Min(dstRegion.X1, dstRegion.X2),
MathF.Min(dstRegion.Y1, dstRegion.Y2),
MathF.Abs(dstRegion.X2 - dstRegion.X1),
MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
viewports[0] = new GAL.Viewport(
rect,
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, true, dstFormat);
_pipeline.SetScissors(scissors);
_pipeline.SetViewports(viewports, false);
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
var aspectFlags = src.Info.Format.ConvertAspectFlags();
if (aspectFlags.HasFlag(ImageAspectFlags.DepthBit))
{
var depthTexture = CreateDepthOrStencilView(src, DepthStencilMode.Depth);
BlitDepthStencilDraw(depthTexture, isDepth: true);
if (depthTexture != src)
{
depthTexture.Release();
}
}
if (aspectFlags.HasFlag(ImageAspectFlags.StencilBit) && _programStencilBlit != null)
{
var stencilTexture = CreateDepthOrStencilView(src, DepthStencilMode.Stencil);
BlitDepthStencilDraw(stencilTexture, isDepth: false);
if (stencilTexture != src)
{
stencilTexture.Release();
}
}
_pipeline.Finish(gd, cbs);
gd.BufferManager.Delete(bufferHandle);
}
private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode)
{
if (depthStencilTexture.Info.DepthStencilMode == depthStencilMode)
{
return depthStencilTexture;
}
return (TextureView)depthStencilTexture.CreateView(new TextureCreateInfo(
depthStencilTexture.Info.Width,
depthStencilTexture.Info.Height,
depthStencilTexture.Info.Depth,
depthStencilTexture.Info.Levels,
depthStencilTexture.Info.Samples,
depthStencilTexture.Info.BlockWidth,
depthStencilTexture.Info.BlockHeight,
depthStencilTexture.Info.BytesPerPixel,
depthStencilTexture.Info.Format,
depthStencilMode,
depthStencilTexture.Info.Target,
SwizzleComponent.Red,
SwizzleComponent.Green,
SwizzleComponent.Blue,
SwizzleComponent.Alpha), 0, 0);
}
private void BlitDepthStencilDraw(TextureView src, bool isDepth)
{
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, _samplerNearest);
if (isDepth)
{
_pipeline.SetProgram(_programDepthBlit);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, GAL.CompareOp.Always));
}
else
{
_pipeline.SetProgram(_programStencilBlit);
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
}
_pipeline.Draw(4, 1, 0, 0);
if (isDepth)
{
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, GAL.CompareOp.Always));
}
else
{
_pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
}
}
private static StencilTestDescriptor CreateStencilTestDescriptor(bool enabled)
{
return new StencilTestDescriptor(
enabled,
GAL.CompareOp.Always,
GAL.StencilOp.Replace,
GAL.StencilOp.Replace,
GAL.StencilOp.Replace,
0,
0xff,
0xff,
GAL.CompareOp.Always,
GAL.StencilOp.Replace,
GAL.StencilOp.Replace,
GAL.StencilOp.Replace,
0,
0xff,
0xff);
}
public void Clear( public void Clear(
VulkanRenderer gd, VulkanRenderer gd,
Auto<DisposableImageView> dst, Auto<DisposableImageView> dst,
@ -993,6 +1185,8 @@ namespace Ryujinx.Graphics.Vulkan
_programConvertIndirectData.Dispose(); _programConvertIndirectData.Dispose();
_programColorCopyToNonMs.Dispose(); _programColorCopyToNonMs.Dispose();
_programColorDrawToMs.Dispose(); _programColorDrawToMs.Dispose();
_programDepthBlit.Dispose();
_programStencilBlit?.Dispose();
_samplerNearest.Dispose(); _samplerNearest.Dispose();
_samplerLinear.Dispose(); _samplerLinear.Dispose();
_pipeline.Dispose(); _pipeline.Dispose();

View file

@ -0,0 +1,10 @@
#version 450 core
layout (binding = 0, set = 2) uniform sampler2D texDepth;
layout (location = 0) in vec2 tex_coord;
void main()
{
gl_FragDepth = texture(texDepth, tex_coord).r;
}

View file

@ -1459,5 +1459,95 @@ namespace Ryujinx.Graphics.Vulkan.Shaders
0x3B, 0x01, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xE3, 0x00, 0x00, 0x00, 0x3B, 0x01, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xE3, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0xE5, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xE5, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
}; };
public static readonly byte[] DepthBlitFragmentShaderSource = new byte[]
{
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x17, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x46, 0x72, 0x61, 0x67, 0x44,
0x65, 0x70, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x74, 0x65, 0x78, 0x44, 0x65, 0x70, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x19, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00,
0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
public static readonly byte[] StencilBlitFragmentShaderSource = new byte[]
{
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x95, 0x13, 0x00, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x53, 0x50, 0x56, 0x5F, 0x45, 0x58, 0x54, 0x5F,
0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x5F, 0x65,
0x78, 0x70, 0x6F, 0x72, 0x74, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00,
0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x07, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0xA3, 0x13, 0x00, 0x00,
0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00,
0x47, 0x4C, 0x5F, 0x41, 0x52, 0x42, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x73, 0x74,
0x65, 0x6E, 0x63, 0x69, 0x6C, 0x5F, 0x65, 0x78, 0x70, 0x6F, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x46, 0x72, 0x61, 0x67, 0x53,
0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x52, 0x65, 0x66, 0x41, 0x52, 0x42, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x53, 0x74, 0x65, 0x6E, 0x63,
0x69, 0x6C, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x5F,
0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x96, 0x13, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,
0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
} }
} }

View file

@ -0,0 +1,12 @@
#version 450 core
#extension GL_ARB_shader_stencil_export : require
layout (binding = 0, set = 2) uniform isampler2D texStencil;
layout (location = 0) in vec2 tex_coord;
void main()
{
gl_FragStencilRefARB = texture(texStencil, tex_coord).r;
}

View file

@ -364,19 +364,14 @@ namespace Ryujinx.Graphics.Vulkan
return; return;
} }
else if (srcFormat == GAL.Format.D32FloatS8Uint && srcFormat == dstFormat && SupportsBlitFromD32FS8ToD32FAndS8()) }
{
BlitDepthStencilWithBuffer(_gd, cbs, src, dst, srcRegion, dstRegion);
return; bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
}
}
if (VulkanConfiguration.UseSlowSafeBlitOnAmd && if (VulkanConfiguration.UseSlowSafeBlitOnAmd &&
(_gd.Vendor == Vendor.Amd || _gd.IsMoltenVk) && (_gd.Vendor == Vendor.Amd || _gd.IsMoltenVk) &&
src.Info.Target == Target.Texture2D && src.Info.Target == Target.Texture2D &&
dst.Info.Target == Target.Texture2D && dst.Info.Target == Target.Texture2D)
!dst.Info.Format.IsDepthOrStencil())
{ {
_gd.HelperShader.Blit( _gd.HelperShader.Blit(
_gd, _gd,
@ -387,6 +382,7 @@ namespace Ryujinx.Graphics.Vulkan
dst.VkFormat, dst.VkFormat,
srcRegion, srcRegion,
dstRegion, dstRegion,
isDepthOrStencil,
linearFilter); linearFilter);
return; return;
@ -395,7 +391,7 @@ namespace Ryujinx.Graphics.Vulkan
Auto<DisposableImage> srcImage; Auto<DisposableImage> srcImage;
Auto<DisposableImage> dstImage; Auto<DisposableImage> dstImage;
if (dst.Info.Format.IsDepthOrStencil()) if (isDepthOrStencil)
{ {
srcImage = src.Storage.CreateAliasedColorForDepthStorageUnsafe(srcFormat).GetImage(); srcImage = src.Storage.CreateAliasedColorForDepthStorageUnsafe(srcFormat).GetImage();
dstImage = dst.Storage.CreateAliasedColorForDepthStorageUnsafe(dstFormat).GetImage(); dstImage = dst.Storage.CreateAliasedColorForDepthStorageUnsafe(dstFormat).GetImage();
@ -426,189 +422,6 @@ namespace Ryujinx.Graphics.Vulkan
ImageAspectFlags.ColorBit); ImageAspectFlags.ColorBit);
} }
private static void BlitDepthStencilWithBuffer(
VulkanRenderer gd,
CommandBufferScoped cbs,
TextureView src,
TextureView dst,
Extents2D srcRegion,
Extents2D dstRegion)
{
int drBaseX = Math.Min(dstRegion.X1, dstRegion.X2);
int drBaseY = Math.Min(dstRegion.Y1, dstRegion.Y2);
int drWidth = Math.Abs(dstRegion.X2 - dstRegion.X1);
int drHeight = Math.Abs(dstRegion.Y2 - dstRegion.Y1);
var drOriginZero = new Extents2D(
dstRegion.X1 - drBaseX,
dstRegion.Y1 - drBaseY,
dstRegion.X2 - drBaseX,
dstRegion.Y2 - drBaseY);
var d32SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.D32Float, 4);
var d32DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.D32Float, 4, drWidth, drHeight);
var s8SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.S8Uint, 1);
var s8DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.S8Uint, 1, drWidth, drHeight);
using var d32SrcStorage = gd.CreateTextureStorage(d32SrcStorageInfo, src.Storage.ScaleFactor);
using var d32DstStorage = gd.CreateTextureStorage(d32DstStorageInfo, dst.Storage.ScaleFactor);
using var s8SrcStorage = gd.CreateTextureStorage(s8SrcStorageInfo, src.Storage.ScaleFactor);
using var s8DstStorage = gd.CreateTextureStorage(s8DstStorageInfo, dst.Storage.ScaleFactor);
void SlowBlit(TextureStorage srcTemp, TextureStorage dstTemp, ImageAspectFlags aspectFlags)
{
int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
int srcSize = 0;
int dstSize = 0;
for (int l = 0; l < levels; l++)
{
srcSize += srcTemp.Info.GetMipSize2D(l);
dstSize += dstTemp.Info.GetMipSize2D(l);
}
using var srcTempBuffer = gd.BufferManager.Create(gd, srcSize, deviceLocal: true);
using var dstTempBuffer = gd.BufferManager.Create(gd, dstSize, deviceLocal: true);
src.Storage.CopyFromOrToBuffer(
cbs.CommandBuffer,
srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
src.GetImage().Get(cbs).Value,
srcSize,
to: true,
0,
0,
src.FirstLayer,
src.FirstLevel,
1,
levels,
true,
aspectFlags,
false);
BufferHolder.InsertBufferBarrier(
gd,
cbs.CommandBuffer,
srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
0,
srcSize);
srcTemp.CopyFromOrToBuffer(
cbs.CommandBuffer,
srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
srcTemp.GetImage().Get(cbs).Value,
srcSize,
to: false,
0,
0,
0,
0,
1,
levels,
true,
aspectFlags,
false);
InsertImageBarrier(
gd.Api,
cbs.CommandBuffer,
srcTemp.GetImage().Get(cbs).Value,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
aspectFlags,
0,
0,
1,
levels);
TextureCopy.Blit(
gd.Api,
cbs.CommandBuffer,
srcTemp.GetImage().Get(cbs).Value,
dstTemp.GetImage().Get(cbs).Value,
srcTemp.Info,
dstTemp.Info,
srcRegion,
drOriginZero,
0,
0,
0,
0,
1,
levels,
false,
aspectFlags,
aspectFlags);
InsertImageBarrier(
gd.Api,
cbs.CommandBuffer,
dstTemp.GetImage().Get(cbs).Value,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
aspectFlags,
0,
0,
1,
levels);
dstTemp.CopyFromOrToBuffer(
cbs.CommandBuffer,
dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
dstTemp.GetImage().Get(cbs).Value,
dstSize,
to: true,
0,
0,
0,
0,
1,
levels,
true,
aspectFlags,
false);
BufferHolder.InsertBufferBarrier(
gd,
cbs.CommandBuffer,
dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
AccessFlags.TransferWriteBit,
AccessFlags.TransferReadBit,
PipelineStageFlags.TransferBit,
PipelineStageFlags.TransferBit,
0,
dstSize);
dst.Storage.CopyFromOrToBuffer(
cbs.CommandBuffer,
dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
dst.GetImage().Get(cbs).Value,
dstSize,
to: false,
drBaseX,
drBaseY,
dst.FirstLayer,
dst.FirstLevel,
1,
levels,
true,
aspectFlags,
false);
}
SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.DepthBit);
SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.StencilBit);
}
public static unsafe void InsertImageBarrier( public static unsafe void InsertImageBarrier(
Vk api, Vk api,
CommandBuffer commandBuffer, CommandBuffer commandBuffer,
@ -649,13 +462,6 @@ namespace Ryujinx.Graphics.Vulkan
memoryBarrier); memoryBarrier);
} }
private bool SupportsBlitFromD32FS8ToD32FAndS8()
{
var formatFeatureFlags = FormatFeatureFlags.BlitSrcBit | FormatFeatureFlags.BlitDstBit;
return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
_gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
}
public TextureView GetView(GAL.Format format) public TextureView GetView(GAL.Format format)
{ {
if (format == Info.Format) if (format == Info.Format)

View file

@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.Vulkan
"VK_EXT_fragment_shader_interlock", "VK_EXT_fragment_shader_interlock",
"VK_EXT_index_type_uint8", "VK_EXT_index_type_uint8",
"VK_EXT_robustness2", "VK_EXT_robustness2",
"VK_EXT_shader_stencil_export",
"VK_KHR_shader_float16_int8", "VK_KHR_shader_float16_int8",
"VK_EXT_shader_subgroup_ballot", "VK_EXT_shader_subgroup_ballot",
"VK_EXT_subgroup_size_control", "VK_EXT_subgroup_size_control",

View file

@ -263,6 +263,7 @@ namespace Ryujinx.Graphics.Vulkan
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"), supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
supportedExtensions.Contains("VK_EXT_subgroup_size_control"), supportedExtensions.Contains("VK_EXT_subgroup_size_control"),
featuresShaderInt8.ShaderInt8, featuresShaderInt8.ShaderInt8,
supportedExtensions.Contains("VK_EXT_shader_stencil_export"),
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName), supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName), supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName),
features2.Features.MultiViewport, features2.Features.MultiViewport,

View file

@ -335,7 +335,7 @@ namespace Ryujinx.Graphics.Vulkan
int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY; int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY; int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;
_gd.HelperShader.Blit( _gd.HelperShader.BlitColor(
_gd, _gd,
cbs, cbs,
view, view,