aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL/Image
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-04-17 05:13:53 -0300
committerGitHub <noreply@github.com>2023-04-17 08:13:53 +0000
commitd9b63353b019e1f1775370154f4f045ff14184ce (patch)
treeef4909c3da741eb9c498fcd57891c857a5cabe5a /Ryujinx.Graphics.OpenGL/Image
parenteabd0ec93f903fb39605a29b35db4c6290bc9c88 (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.cs103
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs5
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureView.cs78
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);