diff options
author | gdkchan <gab.dark.100@gmail.com> | 2023-04-17 05:13:53 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-17 08:13:53 +0000 |
commit | d9b63353b019e1f1775370154f4f045ff14184ce (patch) | |
tree | ef4909c3da741eb9c498fcd57891c857a5cabe5a /Ryujinx.Graphics.OpenGL/Image | |
parent | eabd0ec93f903fb39605a29b35db4c6290bc9c88 (diff) |
Support copy between multisample and non-multisample depth textures (#4676)1.1.721
* Support copy between multisample and non-multisample depth textures
* PR feedback
Diffstat (limited to 'Ryujinx.Graphics.OpenGL/Image')
-rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs | 103 | ||||
-rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs | 5 | ||||
-rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/TextureView.cs | 78 |
3 files changed, 182 insertions, 4 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs b/Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs new file mode 100644 index 00000000..4f167e89 --- /dev/null +++ b/Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs @@ -0,0 +1,103 @@ +using Ryujinx.Graphics.GAL; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.OpenGL.Image +{ + class IntermediatePool : IDisposable + { + private readonly OpenGLRenderer _renderer; + private readonly List<TextureView> _entries; + + public IntermediatePool(OpenGLRenderer renderer) + { + _renderer = renderer; + _entries = new List<TextureView>(); + } + + public TextureView GetOrCreateWithAtLeast( + Target target, + int blockWidth, + int blockHeight, + int bytesPerPixel, + Format format, + int width, + int height, + int depth, + int levels, + int samples) + { + TextureView entry; + + for (int i = 0; i < _entries.Count; i++) + { + entry = _entries[i]; + + if (entry.Target == target && entry.Format == format && entry.Info.Samples == samples) + { + if (entry.Width < width || + entry.Height < height || + entry.Info.Depth < depth || + entry.Info.Levels < levels) + { + width = Math.Max(width, entry.Width); + height = Math.Max(height, entry.Height); + depth = Math.Max(depth, entry.Info.Depth); + levels = Math.Max(levels, entry.Info.Levels); + + entry.Dispose(); + entry = CreateNew(target, blockWidth, blockHeight, bytesPerPixel, format, width, height, depth, levels, samples); + _entries[i] = entry; + } + + return entry; + } + } + + entry = CreateNew(target, blockWidth, blockHeight, bytesPerPixel, format, width, height, depth, levels, samples); + _entries.Add(entry); + + return entry; + } + + private TextureView CreateNew( + Target target, + int blockWidth, + int blockHeight, + int bytesPerPixel, + Format format, + int width, + int height, + int depth, + int levels, + int samples) + { + return (TextureView)_renderer.CreateTexture(new TextureCreateInfo( + width, + height, + depth, + levels, + samples, + blockWidth, + blockHeight, + bytesPerPixel, + format, + DepthStencilMode.Depth, + target, + SwizzleComponent.Red, + SwizzleComponent.Green, + SwizzleComponent.Blue, + SwizzleComponent.Alpha), 1f); + } + + public void Dispose() + { + foreach (TextureView entry in _entries) + { + entry.Dispose(); + } + + _entries.Clear(); + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs b/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs index 75c4d870..a4b08787 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs @@ -15,9 +15,12 @@ namespace Ryujinx.Graphics.OpenGL.Image private int _copyPboHandle; private int _copyPboSize; + public IntermediatePool IntermediatePool { get; } + public TextureCopy(OpenGLRenderer renderer) { _renderer = renderer; + IntermediatePool = new IntermediatePool(renderer); } public void Copy( @@ -514,6 +517,8 @@ namespace Ryujinx.Graphics.OpenGL.Image _copyPboHandle = 0; } + + IntermediatePool.Dispose(); } } } 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); |