From d9b63353b019e1f1775370154f4f045ff14184ce Mon Sep 17 00:00:00 2001 From: gdkchan <gab.dark.100@gmail.com> Date: Mon, 17 Apr 2023 05:13:53 -0300 Subject: Support copy between multisample and non-multisample depth textures (#4676) * Support copy between multisample and non-multisample depth textures * PR feedback --- Ryujinx.Graphics.OpenGL/Image/TextureView.cs | 78 ++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 4 deletions(-) (limited to 'Ryujinx.Graphics.OpenGL/Image/TextureView.cs') diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs index ddc5f9a3..804b3b03 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs @@ -117,12 +117,20 @@ namespace Ryujinx.Graphics.OpenGL.Image { TextureView destinationView = (TextureView)destination; - if (!destinationView.Target.IsMultisample() && Target.IsMultisample()) + bool srcIsMultisample = Target.IsMultisample(); + bool dstIsMultisample = destinationView.Target.IsMultisample(); + + if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil()) + { + int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); + CopyWithBlitForDepthMS(destinationView, 0, firstLayer, layers); + } + else if (!dstIsMultisample && srcIsMultisample) { int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, 0, firstLayer, layers); } - else if (destinationView.Target.IsMultisample() && !Target.IsMultisample()) + else if (dstIsMultisample && !srcIsMultisample) { int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer); _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, 0, firstLayer, layers); @@ -143,11 +151,18 @@ namespace Ryujinx.Graphics.OpenGL.Image { TextureView destinationView = (TextureView)destination; - if (!destinationView.Target.IsMultisample() && Target.IsMultisample()) + bool srcIsMultisample = Target.IsMultisample(); + bool dstIsMultisample = destinationView.Target.IsMultisample(); + + if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil()) + { + CopyWithBlitForDepthMS(destinationView, srcLayer, dstLayer, 1); + } + else if (!dstIsMultisample && srcIsMultisample) { _renderer.TextureCopyMS.CopyMSToNonMS(this, destinationView, srcLayer, dstLayer, 1); } - else if (destinationView.Target.IsMultisample() && !Target.IsMultisample()) + else if (dstIsMultisample && !srcIsMultisample) { _renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, srcLayer, dstLayer, 1); } @@ -161,6 +176,61 @@ namespace Ryujinx.Graphics.OpenGL.Image } } + private void CopyWithBlitForDepthMS(TextureView destinationView, int srcLayer, int dstLayer, int layers) + { + // This is currently used for multisample <-> non-multisample copies. + // We can't do that with compute because it's not possible to write depth textures on compute. + // It can be done with draws, but we don't have support for saving and restoring the OpenGL state + // for a draw with different state right now. + // This approach uses blit, which causes a resolution loss since some samples will be lost + // in the process. + + Extents2D srcRegion = new Extents2D(0, 0, Width, Height); + Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height); + + if (destinationView.Target.IsMultisample()) + { + TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast( + Info.Target, + Info.BlockWidth, + Info.BlockHeight, + Info.BytesPerPixel, + Format, + destinationView.Width, + destinationView.Height, + Info.Depth, + 1, + 1); + + _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, dstRegion, false); + _renderer.TextureCopy.Copy(intermmediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1); + } + else + { + Target target = Target switch + { + Target.Texture2DMultisample => Target.Texture2D, + Target.Texture2DMultisampleArray => Target.Texture2DArray, + _ => Target + }; + + TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast( + target, + Info.BlockWidth, + Info.BlockHeight, + Info.BytesPerPixel, + Format, + Width, + Height, + Info.Depth, + 1, + 1); + + _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, false); + _renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1); + } + } + public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter) { _renderer.TextureCopy.Copy(this, (TextureView)destination, srcRegion, dstRegion, linearFilter); -- cgit v1.2.3-70-g09d2