aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Vulkan/HelperShader.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/HelperShader.cs')
-rw-r--r--Ryujinx.Graphics.Vulkan/HelperShader.cs216
1 files changed, 205 insertions, 11 deletions
diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs
index 223bcc71..658516e6 100644
--- a/Ryujinx.Graphics.Vulkan/HelperShader.cs
+++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs
@@ -33,6 +33,8 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IProgram _programConvertIndirectData;
private readonly IProgram _programColorCopyToNonMs;
private readonly IProgram _programColorDrawToMs;
+ private readonly IProgram _programDepthBlit;
+ private readonly IProgram _programStencilBlit;
public HelperShader(VulkanRenderer gd, Device device)
{
@@ -42,13 +44,13 @@ namespace Ryujinx.Graphics.Vulkan
_samplerLinear = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
_samplerNearest = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
- var colorBlitVertexBindings = new ShaderBindings(
+ var blitVertexBindings = new ShaderBindings(
new[] { 1 },
Array.Empty<int>(),
Array.Empty<int>(),
Array.Empty<int>());
- var colorBlitFragmentBindings = new ShaderBindings(
+ var blitFragmentBindings = new ShaderBindings(
Array.Empty<int>(),
Array.Empty<int>(),
new[] { 0 },
@@ -56,14 +58,14 @@ namespace Ryujinx.Graphics.Vulkan
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
{
- new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
- new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, colorBlitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
{
- new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
- new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, colorBlitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
var colorClearFragmentBindings = new ShaderBindings(
@@ -74,19 +76,19 @@ namespace Ryujinx.Graphics.Vulkan
_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),
});
_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),
});
_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),
});
@@ -151,6 +153,21 @@ namespace Ryujinx.Graphics.Vulkan
{
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(
@@ -162,6 +179,7 @@ namespace Ryujinx.Graphics.Vulkan
VkFormat dstFormat,
Extents2D srcRegion,
Extents2D dstRegion,
+ bool isDepthOrStencil,
bool linearFilter,
bool clearAlpha = false)
{
@@ -169,10 +187,17 @@ namespace Ryujinx.Graphics.Vulkan
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,
CommandBufferScoped cbs,
TextureView src,
@@ -255,6 +280,173 @@ namespace Ryujinx.Graphics.Vulkan
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(
VulkanRenderer gd,
Auto<DisposableImageView> dst,
@@ -993,6 +1185,8 @@ namespace Ryujinx.Graphics.Vulkan
_programConvertIndirectData.Dispose();
_programColorCopyToNonMs.Dispose();
_programColorDrawToMs.Dispose();
+ _programDepthBlit.Dispose();
+ _programStencilBlit?.Dispose();
_samplerNearest.Dispose();
_samplerLinear.Dispose();
_pipeline.Dispose();