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.cs267
1 files changed, 220 insertions, 47 deletions
diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs
index 8eb3088e..c57edaf7 100644
--- a/Ryujinx.Graphics.Vulkan/HelperShader.cs
+++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs
@@ -39,8 +39,12 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IProgram _programColorDrawToMs;
private readonly IProgram _programDepthBlit;
private readonly IProgram _programDepthBlitMs;
+ private readonly IProgram _programDepthDrawToMs;
+ private readonly IProgram _programDepthDrawToNonMs;
private readonly IProgram _programStencilBlit;
private readonly IProgram _programStencilBlitMs;
+ private readonly IProgram _programStencilDrawToMs;
+ private readonly IProgram _programStencilDrawToNonMs;
public HelperShader(VulkanRenderer gd, Device device)
{
@@ -188,6 +192,18 @@ namespace Ryujinx.Graphics.Vulkan
new ShaderSource(ShaderBinaries.DepthBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
+ _programDepthDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, colorDrawToMsVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.DepthDrawToMsFragmentShaderSource, colorDrawToMsFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ });
+
+ _programDepthDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, colorDrawToMsVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.DepthDrawToNonMsFragmentShaderSource, colorDrawToMsFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ });
+
if (gd.Capabilities.SupportsShaderStencilExport)
{
_programStencilBlit = gd.CreateProgramWithMinimalLayout(new[]
@@ -201,6 +217,18 @@ namespace Ryujinx.Graphics.Vulkan
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.StencilBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
});
+
+ _programStencilDrawToMs = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, colorDrawToMsVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.StencilDrawToMsFragmentShaderSource, colorDrawToMsFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ });
+
+ _programStencilDrawToNonMs = gd.CreateProgramWithMinimalLayout(new[]
+ {
+ new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, colorDrawToMsVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
+ new ShaderSource(ShaderBinaries.StencilDrawToNonMsFragmentShaderSource, colorDrawToMsFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
+ });
}
}
@@ -1043,6 +1071,8 @@ namespace Ryujinx.Graphics.Vulkan
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
int samples = src.Info.Samples;
+ bool isDepthOrStencil = src.Info.Format.IsDepthOrStencil();
+ var aspectFlags = src.Info.Format.ConvertAspectFlags();
// X and Y are the expected texture samples.
// Z and W are the actual texture samples used.
@@ -1061,42 +1091,94 @@ namespace Ryujinx.Graphics.Vulkan
TextureStorage.DefaultAccessMask,
AccessFlags.ShaderReadBit,
PipelineStageFlags.AllCommandsBit,
- PipelineStageFlags.ComputeShaderBit,
- ImageAspectFlags.ColorBit,
+ isDepthOrStencil ? PipelineStageFlags.FragmentShaderBit : PipelineStageFlags.ComputeShaderBit,
+ aspectFlags,
src.FirstLayer + srcLayer,
src.FirstLevel,
depth,
1);
_pipeline.SetCommandBuffer(cbs);
+ _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
- _pipeline.SetProgram(_programColorCopyToNonMs);
+ if (isDepthOrStencil)
+ {
+ // We can't use compute for this case because compute can't modify depth textures.
- var format = GetFormat(src.Info.BytesPerPixel);
+ Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
- int dispatchX = (dst.Info.Width + 31) / 32;
- int dispatchY = (dst.Info.Height + 31) / 32;
+ var rect = new Rectangle<float>(0, 0, dst.Width, dst.Height);
- _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
+ viewports[0] = new GAL.Viewport(
+ rect,
+ ViewportSwizzle.PositiveX,
+ ViewportSwizzle.PositiveY,
+ ViewportSwizzle.PositiveZ,
+ ViewportSwizzle.PositiveW,
+ 0f,
+ 1f);
- for (int z = 0; z < depth; z++)
- {
- var srcView = Create2DLayerView(src, srcLayer + z, 0, format);
- var dstView = Create2DLayerView(dst, dstLayer + z, 0);
+ Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
- _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null);
- _pipeline.SetImage(0, dstView, format);
+ scissors[0] = new Rectangle<int>(0, 0, dst.Width, dst.Height);
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
+ _pipeline.SetScissors(scissors);
+ _pipeline.SetViewports(viewports, false);
+ _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
- if (srcView != src)
+ for (int z = 0; z < depth; z++)
{
- srcView.Release();
+ var srcView = Create2DLayerView(src, srcLayer + z, 0);
+ var dstView = Create2DLayerView(dst, dstLayer + z, 0);
+
+ _pipeline.SetRenderTarget(
+ ((TextureView)dstView).GetImageViewForAttachment(),
+ (uint)dst.Width,
+ (uint)dst.Height,
+ true,
+ dst.VkFormat);
+
+ CopyMSDraw(srcView, aspectFlags, fromMS: true);
+
+ if (srcView != src)
+ {
+ srcView.Release();
+ }
+
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
}
+ }
+ else
+ {
+ var format = GetFormat(src.Info.BytesPerPixel);
+
+ int dispatchX = (dst.Info.Width + 31) / 32;
+ int dispatchY = (dst.Info.Height + 31) / 32;
- if (dstView != dst)
+ _pipeline.SetProgram(_programColorCopyToNonMs);
+
+ for (int z = 0; z < depth; z++)
{
- dstView.Release();
+ var srcView = Create2DLayerView(src, srcLayer + z, 0, format);
+ var dstView = Create2DLayerView(dst, dstLayer + z, 0);
+
+ _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null);
+ _pipeline.SetImage(0, dstView, format);
+
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
+
+ if (srcView != src)
+ {
+ srcView.Release();
+ }
+
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
}
}
@@ -1108,11 +1190,11 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api,
cbs.CommandBuffer,
dst.GetImage().Get(cbs).Value,
- AccessFlags.ShaderWriteBit,
+ isDepthOrStencil ? AccessFlags.DepthStencilAttachmentWriteBit : AccessFlags.ShaderWriteBit,
TextureStorage.DefaultAccessMask,
- PipelineStageFlags.ComputeShaderBit,
+ isDepthOrStencil ? PipelineStageFlags.LateFragmentTestsBit : PipelineStageFlags.ComputeShaderBit,
PipelineStageFlags.AllCommandsBit,
- ImageAspectFlags.ColorBit,
+ aspectFlags,
dst.FirstLayer + dstLayer,
dst.FirstLevel,
depth,
@@ -1126,6 +1208,8 @@ namespace Ryujinx.Graphics.Vulkan
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
int samples = dst.Info.Samples;
+ bool isDepthOrStencil = src.Info.Format.IsDepthOrStencil();
+ var aspectFlags = src.Info.Format.ConvertAspectFlags();
// X and Y are the expected texture samples.
// Z and W are the actual texture samples used.
@@ -1145,7 +1229,7 @@ namespace Ryujinx.Graphics.Vulkan
AccessFlags.ShaderReadBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.FragmentShaderBit,
- ImageAspectFlags.ColorBit,
+ aspectFlags,
src.FirstLayer + srcLayer,
src.FirstLevel,
depth,
@@ -1153,8 +1237,6 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetCommandBuffer(cbs);
- _pipeline.SetProgram(_programColorDrawToMs);
-
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
var rect = new Rectangle<float>(0, 0, dst.Width, dst.Height);
@@ -1179,33 +1261,66 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
- var format = GetFormat(src.Info.BytesPerPixel);
- var vkFormat = FormatTable.GetFormat(format);
-
- for (int z = 0; z < depth; z++)
+ if (isDepthOrStencil)
{
- var srcView = Create2DLayerView(src, srcLayer + z, 0, format);
- var dstView = Create2DLayerView(dst, dstLayer + z, 0);
+ for (int z = 0; z < depth; z++)
+ {
+ var srcView = Create2DLayerView(src, srcLayer + z, 0);
+ var dstView = Create2DLayerView(dst, dstLayer + z, 0);
- _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, srcView, null);
- _pipeline.SetRenderTarget(
- ((TextureView)dstView).GetView(format).GetImageViewForAttachment(),
- (uint)dst.Width,
- (uint)dst.Height,
- (uint)samples,
- false,
- vkFormat);
+ _pipeline.SetRenderTarget(
+ ((TextureView)dstView).GetImageViewForAttachment(),
+ (uint)dst.Width,
+ (uint)dst.Height,
+ (uint)samples,
+ true,
+ dst.VkFormat);
- _pipeline.Draw(4, 1, 0, 0);
+ CopyMSDraw(srcView, aspectFlags, fromMS: false);
- if (srcView != src)
- {
- srcView.Release();
+ if (srcView != src)
+ {
+ srcView.Release();
+ }
+
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
}
+ }
+ else
+ {
+ _pipeline.SetProgram(_programColorDrawToMs);
+
+ var format = GetFormat(src.Info.BytesPerPixel);
+ var vkFormat = FormatTable.GetFormat(format);
- if (dstView != dst)
+ for (int z = 0; z < depth; z++)
{
- dstView.Release();
+ var srcView = Create2DLayerView(src, srcLayer + z, 0, format);
+ var dstView = Create2DLayerView(dst, dstLayer + z, 0);
+
+ _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, srcView, null);
+ _pipeline.SetRenderTarget(
+ ((TextureView)dstView).GetView(format).GetImageViewForAttachment(),
+ (uint)dst.Width,
+ (uint)dst.Height,
+ (uint)samples,
+ false,
+ vkFormat);
+
+ _pipeline.Draw(4, 1, 0, 0);
+
+ if (srcView != src)
+ {
+ srcView.Release();
+ }
+
+ if (dstView != dst)
+ {
+ dstView.Release();
+ }
}
}
@@ -1217,17 +1332,71 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api,
cbs.CommandBuffer,
dst.GetImage().Get(cbs).Value,
- AccessFlags.ColorAttachmentWriteBit,
+ isDepthOrStencil ? AccessFlags.DepthStencilAttachmentWriteBit : AccessFlags.ColorAttachmentWriteBit,
TextureStorage.DefaultAccessMask,
- PipelineStageFlags.FragmentShaderBit,
+ isDepthOrStencil ? PipelineStageFlags.LateFragmentTestsBit : PipelineStageFlags.ColorAttachmentOutputBit,
PipelineStageFlags.AllCommandsBit,
- ImageAspectFlags.ColorBit,
+ aspectFlags,
dst.FirstLayer + dstLayer,
dst.FirstLevel,
depth,
1);
}
+ private void CopyMSDraw(TextureView src, ImageAspectFlags aspectFlags, bool fromMS)
+ {
+ if (aspectFlags.HasFlag(ImageAspectFlags.DepthBit))
+ {
+ var depthTexture = CreateDepthOrStencilView(src, DepthStencilMode.Depth);
+
+ CopyMSAspectDraw(depthTexture, fromMS, isDepth: true);
+
+ if (depthTexture != src)
+ {
+ depthTexture.Release();
+ }
+ }
+
+ if (aspectFlags.HasFlag(ImageAspectFlags.StencilBit) && _programStencilDrawToMs != null)
+ {
+ var stencilTexture = CreateDepthOrStencilView(src, DepthStencilMode.Stencil);
+
+ CopyMSAspectDraw(stencilTexture, fromMS, isDepth: false);
+
+ if (stencilTexture != src)
+ {
+ stencilTexture.Release();
+ }
+ }
+ }
+
+ private void CopyMSAspectDraw(TextureView src, bool fromMS, bool isDepth)
+ {
+ _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, _samplerNearest);
+
+ if (isDepth)
+ {
+ _pipeline.SetProgram(fromMS ? _programDepthDrawToNonMs : _programDepthDrawToMs);
+ _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, GAL.CompareOp.Always));
+ }
+ else
+ {
+ _pipeline.SetProgram(fromMS ? _programStencilDrawToNonMs : _programStencilDrawToMs);
+ _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 (int, int) GetSampleCountXYLog2(int samples)
{
int samplesInXLog2 = 0;
@@ -1494,8 +1663,12 @@ namespace Ryujinx.Graphics.Vulkan
_programColorDrawToMs.Dispose();
_programDepthBlit.Dispose();
_programDepthBlitMs.Dispose();
+ _programDepthDrawToMs.Dispose();
+ _programDepthDrawToNonMs.Dispose();
_programStencilBlit?.Dispose();
_programStencilBlitMs?.Dispose();
+ _programStencilDrawToMs?.Dispose();
+ _programStencilDrawToNonMs?.Dispose();
_samplerNearest.Dispose();
_samplerLinear.Dispose();
_pipeline.Dispose();