diff options
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/HelperShader.cs')
-rw-r--r-- | Ryujinx.Graphics.Vulkan/HelperShader.cs | 283 |
1 files changed, 219 insertions, 64 deletions
diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs index 658516e6..b8c21fe8 100644 --- a/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Vulkan private readonly ISampler _samplerLinear; private readonly ISampler _samplerNearest; private readonly IProgram _programColorBlit; + private readonly IProgram _programColorBlitMs; private readonly IProgram _programColorBlitClearAlpha; private readonly IProgram _programColorClearF; private readonly IProgram _programColorClearSI; @@ -34,7 +35,9 @@ namespace Ryujinx.Graphics.Vulkan private readonly IProgram _programColorCopyToNonMs; private readonly IProgram _programColorDrawToMs; private readonly IProgram _programDepthBlit; + private readonly IProgram _programDepthBlitMs; private readonly IProgram _programStencilBlit; + private readonly IProgram _programStencilBlitMs; public HelperShader(VulkanRenderer gd, Device device) { @@ -62,6 +65,12 @@ namespace Ryujinx.Graphics.Vulkan new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); + _programColorBlitMs = gd.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + }); + _programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[] { new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), @@ -160,6 +169,12 @@ namespace Ryujinx.Graphics.Vulkan new ShaderSource(ShaderBinaries.DepthBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); + _programDepthBlitMs = gd.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.DepthBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + }); + if (gd.Capabilities.SupportsShaderStencilExport) { _programStencilBlit = gd.CreateProgramWithMinimalLayout(new[] @@ -167,18 +182,23 @@ namespace Ryujinx.Graphics.Vulkan new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), new ShaderSource(ShaderBinaries.StencilBlitFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); + + _programStencilBlitMs = gd.CreateProgramWithMinimalLayout(new[] + { + new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, blitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.StencilBlitMsFragmentShaderSource, blitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + }); } } public void Blit( VulkanRenderer gd, TextureView src, - Auto<DisposableImageView> dst, - int dstWidth, - int dstHeight, - VkFormat dstFormat, + TextureView dst, Extents2D srcRegion, Extents2D dstRegion, + int layers, + int levels, bool isDepthOrStencil, bool linearFilter, bool clearAlpha = false) @@ -187,13 +207,137 @@ namespace Ryujinx.Graphics.Vulkan using var cbs = gd.CommandBufferPool.Rent(); - if (isDepthOrStencil) + var dstFormat = dst.VkFormat; + var dstSamples = dst.Info.Samples; + + for (int l = 0; l < levels; l++) { - BlitDepthStencil(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion); + int srcWidth = Math.Max(1, src.Width >> l); + int srcHeight = Math.Max(1, src.Height >> l); + + int dstWidth = Math.Max(1, dst.Width >> l); + int dstHeight = Math.Max(1, dst.Height >> l); + + var mipSrcRegion = new Extents2D( + srcRegion.X1 >> l, + srcRegion.Y1 >> l, + srcRegion.X2 >> l, + srcRegion.Y2 >> l); + + var mipDstRegion = new Extents2D( + dstRegion.X1 >> l, + dstRegion.Y1 >> l, + dstRegion.X2 >> l, + dstRegion.Y2 >> l); + + for (int z = 0; z < layers; z++) + { + var srcView = Create2DLayerView(src, z, l); + var dstView = Create2DLayerView(dst, z, l); + + if (isDepthOrStencil) + { + BlitDepthStencil( + gd, + cbs, + srcView, + dst.GetImageViewForAttachment(), + dstWidth, + dstHeight, + dstSamples, + dstFormat, + mipSrcRegion, + mipDstRegion); + } + else + { + BlitColor( + gd, + cbs, + srcView, + dst.GetImageViewForAttachment(), + dstWidth, + dstHeight, + dstSamples, + dstFormat, + false, + mipSrcRegion, + mipDstRegion, + linearFilter, + clearAlpha); + } + + if (srcView != src) + { + srcView.Release(); + } + + if (dstView != dst) + { + dstView.Release(); + } + } } - else + } + + public void CopyColor( + VulkanRenderer gd, + CommandBufferScoped cbs, + TextureView src, + TextureView dst, + int srcLayer, + int dstLayer, + int srcLevel, + int dstLevel, + int depth, + int levels) + { + for (int l = 0; l < levels; l++) { - BlitColor(gd, cbs, src, dst, dstWidth, dstHeight, dstFormat, srcRegion, dstRegion, linearFilter, clearAlpha); + int mipSrcLevel = srcLevel + l; + int mipDstLevel = dstLevel + l; + + int srcWidth = Math.Max(1, src.Width >> mipSrcLevel); + int srcHeight = Math.Max(1, src.Height >> mipSrcLevel); + + int dstWidth = Math.Max(1, dst.Width >> mipDstLevel); + int dstHeight = Math.Max(1, dst.Height >> mipDstLevel); + + var extents = new Extents2D( + 0, + 0, + Math.Min(srcWidth, dstWidth), + Math.Min(srcHeight, dstHeight)); + + for (int z = 0; z < depth; z++) + { + var srcView = Create2DLayerView(src, srcLayer + z, mipSrcLevel); + var dstView = Create2DLayerView(dst, dstLayer + z, mipDstLevel); + + BlitColor( + gd, + cbs, + srcView, + dstView.GetImageViewForAttachment(), + dstView.Width, + dstView.Height, + dstView.Info.Samples, + dstView.VkFormat, + dstView.Info.Format.IsDepthOrStencil(), + extents, + extents, + false); + + if (srcView != src) + { + srcView.Release(); + } + + if (dstView != dst) + { + dstView.Release(); + } + } } } @@ -204,7 +348,9 @@ namespace Ryujinx.Graphics.Vulkan Auto<DisposableImageView> dst, int dstWidth, int dstHeight, + int dstSamples, VkFormat dstFormat, + bool dstIsDepthOrStencil, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter, @@ -262,8 +408,25 @@ namespace Ryujinx.Graphics.Vulkan scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight); - _pipeline.SetProgram(clearAlpha ? _programColorBlitClearAlpha : _programColorBlit); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat); + if (dstIsDepthOrStencil) + { + _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit); + _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, GAL.CompareOp.Always)); + } + else if (src.Info.Target.IsMultisample()) + { + _pipeline.SetProgram(_programColorBlitMs); + } + else if (clearAlpha) + { + _pipeline.SetProgram(_programColorBlitClearAlpha); + } + else + { + _pipeline.SetProgram(_programColorBlit); + } + + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, dstIsDepthOrStencil, dstFormat); _pipeline.SetRenderTargetColorMasks(new uint[] { 0xf }); _pipeline.SetScissors(scissors); @@ -275,6 +438,12 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetViewports(viewports, false); _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip); _pipeline.Draw(4, 1, 0, 0); + + if (dstIsDepthOrStencil) + { + _pipeline.SetDepthTest(new DepthTestDescriptor(false, false, GAL.CompareOp.Always)); + } + _pipeline.Finish(gd, cbs); gd.BufferManager.Delete(bufferHandle); @@ -287,6 +456,7 @@ namespace Ryujinx.Graphics.Vulkan Auto<DisposableImageView> dst, int dstWidth, int dstHeight, + int dstSamples, VkFormat dstFormat, Extents2D srcRegion, Extents2D dstRegion) @@ -339,7 +509,7 @@ namespace Ryujinx.Graphics.Vulkan scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, true, dstFormat); + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, true, dstFormat); _pipeline.SetScissors(scissors); _pipeline.SetViewports(viewports, false); _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip); @@ -406,12 +576,12 @@ namespace Ryujinx.Graphics.Vulkan if (isDepth) { - _pipeline.SetProgram(_programDepthBlit); + _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit); _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, GAL.CompareOp.Always)); } else { - _pipeline.SetProgram(_programStencilBlit); + _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit); _pipeline.SetStencilTest(CreateStencilTestDescriptor(true)); } @@ -795,33 +965,25 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); - if (src.Info.Target == Target.Texture2DMultisampleArray || - dst.Info.Target == Target.Texture2DMultisampleArray) + for (int z = 0; z < depth; z++) { - for (int z = 0; z < depth; z++) - { - var srcView = Create2DLayerView(src, srcLayer + z, format); - var dstView = Create2DLayerView(dst, dstLayer + z); + 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.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null); + _pipeline.SetImage(0, dstView, format); - _pipeline.DispatchCompute(dispatchX, dispatchY, 1); + _pipeline.DispatchCompute(dispatchX, dispatchY, 1); + if (srcView != src) + { srcView.Release(); - dstView.Release(); } - } - else - { - var srcView = Create2DLayerView(src, srcLayer, format); - - _pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null); - _pipeline.SetImage(0, dst, format); - _pipeline.DispatchCompute(dispatchX, dispatchY, 1); - - srcView.Release(); + if (dstView != dst) + { + dstView.Release(); + } } gd.BufferManager.Delete(bufferHandle); @@ -906,36 +1068,14 @@ namespace Ryujinx.Graphics.Vulkan var format = GetFormat(src.Info.BytesPerPixel); var vkFormat = FormatTable.GetFormat(format); - if (src.Info.Target == Target.Texture2DMultisampleArray || - dst.Info.Target == Target.Texture2DMultisampleArray) - { - for (int z = 0; z < depth; z++) - { - var srcView = Create2DLayerView(src, srcLayer + z, format); - var dstView = Create2DLayerView(dst, dstLayer + z); - - _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); - - srcView.Release(); - dstView.Release(); - } - } - else + for (int z = 0; z < depth; z++) { - var srcView = Create2DLayerView(src, srcLayer, format); + var srcView = Create2DLayerView(src, srcLayer + z, 0, format); + var dstView = Create2DLayerView(dst, dstLayer + z, 0); _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, srcView, null); _pipeline.SetRenderTarget( - dst.GetView(format).GetImageViewForAttachment(), + ((TextureView)dstView).GetView(format).GetImageViewForAttachment(), (uint)dst.Width, (uint)dst.Height, (uint)samples, @@ -944,7 +1084,15 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.Draw(4, 1, 0, 0); - srcView.Release(); + if (srcView != src) + { + srcView.Release(); + } + + if (dstView != dst) + { + dstView.Release(); + } } gd.BufferManager.Delete(bufferHandle); @@ -1001,14 +1149,18 @@ namespace Ryujinx.Graphics.Vulkan return (samplesInXLog2, samplesInYLog2); } - private static ITexture Create2DLayerView(TextureView from, int layer, GAL.Format? format = null) + private static TextureView Create2DLayerView(TextureView from, int layer, int level, GAL.Format? format = null) { + if (from.Info.Target == Target.Texture2D && level == 0 && (format == null || format.Value == from.Info.Format)) + { + return from; + } + var target = from.Info.Target switch { Target.Texture1DArray => Target.Texture1D, - Target.Texture2DArray => Target.Texture2D, Target.Texture2DMultisampleArray => Target.Texture2DMultisample, - _ => from.Info.Target + _ => Target.Texture2D }; var info = new TextureCreateInfo( @@ -1028,7 +1180,7 @@ namespace Ryujinx.Graphics.Vulkan from.Info.SwizzleB, from.Info.SwizzleA); - return from.CreateView(info, layer, 0); + return from.CreateViewImpl(info, layer, level); } private static GAL.Format GetFormat(int bytesPerPixel) @@ -1177,6 +1329,7 @@ namespace Ryujinx.Graphics.Vulkan { _programColorBlitClearAlpha.Dispose(); _programColorBlit.Dispose(); + _programColorBlitMs.Dispose(); _programColorClearF.Dispose(); _programColorClearSI.Dispose(); _programColorClearUI.Dispose(); @@ -1186,7 +1339,9 @@ namespace Ryujinx.Graphics.Vulkan _programColorCopyToNonMs.Dispose(); _programColorDrawToMs.Dispose(); _programDepthBlit.Dispose(); + _programDepthBlitMs.Dispose(); _programStencilBlit?.Dispose(); + _programStencilBlitMs?.Dispose(); _samplerNearest.Dispose(); _samplerLinear.Dispose(); _pipeline.Dispose(); |