Copy dependency for multisample and non-multisample textures (#3382)
* Use copy dependency for textures that differs in multisample but are otherwise compatible * Remove allowMs flag as it's no longer required for correctness, it's just an optimization now * Dispose intermmediate pool
This commit is contained in:
parent
2073ba2919
commit
a3e7bb8eb4
7 changed files with 225 additions and 29 deletions
|
@ -13,4 +13,12 @@ namespace Ryujinx.Graphics.GAL
|
|||
CubemapArray,
|
||||
TextureBuffer
|
||||
}
|
||||
|
||||
public static class TargetExtensions
|
||||
{
|
||||
public static bool IsMultisample(this Target target)
|
||||
{
|
||||
return target == Target.Texture2DMultisample || target == Target.Texture2DMultisampleArray;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1136,32 +1136,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// <param name="range">Texture view physical memory ranges</param>
|
||||
/// <param name="layerSize">Layer size on the given texture</param>
|
||||
/// <param name="caps">Host GPU capabilities</param>
|
||||
/// <param name="allowMs">Indicates that multisample textures are allowed to match non-multisample requested textures</param>
|
||||
/// <param name="firstLayer">Texture view initial layer on this texture</param>
|
||||
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
|
||||
/// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns>
|
||||
public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, bool allowMs, out int firstLayer, out int firstLevel)
|
||||
public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, out int firstLayer, out int firstLevel)
|
||||
{
|
||||
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
||||
|
||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps));
|
||||
if (result != TextureViewCompatibility.Incompatible)
|
||||
{
|
||||
bool msTargetCompatible = false;
|
||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
|
||||
|
||||
if (allowMs)
|
||||
bool bothMs = Info.Target.IsMultisample() && info.Target.IsMultisample();
|
||||
if (bothMs && (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY))
|
||||
{
|
||||
msTargetCompatible = Info.Target == Target.Texture2DMultisample && info.Target == Target.Texture2D;
|
||||
}
|
||||
|
||||
if (!msTargetCompatible)
|
||||
{
|
||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
|
||||
|
||||
if (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY)
|
||||
{
|
||||
result = TextureViewCompatibility.Incompatible;
|
||||
}
|
||||
result = TextureViewCompatibility.Incompatible;
|
||||
}
|
||||
|
||||
if (result == TextureViewCompatibility.Full && Info.FormatInfo.Format != info.FormatInfo.Format && !_context.Capabilities.SupportsMismatchingViewFormat)
|
||||
|
|
|
@ -547,7 +547,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
range.Value,
|
||||
sizeInfo.LayerSize,
|
||||
_context.Capabilities,
|
||||
flags.HasFlag(TextureSearchFlags.ForCopy),
|
||||
out int firstLayer,
|
||||
out int firstLevel);
|
||||
|
||||
|
@ -662,7 +661,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
overlap.Range,
|
||||
overlap.LayerSize,
|
||||
_context.Capabilities,
|
||||
false,
|
||||
out int firstLayer,
|
||||
out int firstLevel);
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ using Ryujinx.Common;
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
|
@ -657,6 +656,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
case Target.Texture2DMultisample:
|
||||
case Target.Texture2DMultisampleArray:
|
||||
if (rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray)
|
||||
{
|
||||
return TextureViewCompatibility.CopyOnly;
|
||||
}
|
||||
|
||||
result = rhs.Target == Target.Texture2DMultisample ||
|
||||
rhs.Target == Target.Texture2DMultisampleArray;
|
||||
break;
|
||||
|
|
98
Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs
Normal file
98
Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs
Normal file
|
@ -0,0 +1,98 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Image
|
||||
{
|
||||
class IntermmediatePool : IDisposable
|
||||
{
|
||||
private readonly Renderer _renderer;
|
||||
private readonly List<TextureView> _entries;
|
||||
|
||||
public IntermmediatePool(Renderer 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)
|
||||
{
|
||||
TextureView entry;
|
||||
|
||||
for (int i = 0; i < _entries.Count; i++)
|
||||
{
|
||||
entry = _entries[i];
|
||||
|
||||
if (entry.Target == target && entry.Format == format)
|
||||
{
|
||||
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);
|
||||
_entries[i] = entry;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
entry = CreateNew(target, blockWidth, blockHeight, bytesPerPixel, format, width, height, depth, levels);
|
||||
_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)
|
||||
{
|
||||
return (TextureView)_renderer.CreateTexture(new TextureCreateInfo(
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
levels,
|
||||
1,
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
{
|
||||
private readonly Renderer _renderer;
|
||||
|
||||
public IntermmediatePool IntermmediatePool { get; }
|
||||
|
||||
private int _srcFramebuffer;
|
||||
private int _dstFramebuffer;
|
||||
|
||||
|
@ -18,6 +20,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
public TextureCopy(Renderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
IntermmediatePool = new IntermmediatePool(renderer);
|
||||
}
|
||||
|
||||
public void Copy(
|
||||
|
@ -25,7 +28,30 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
TextureView dst,
|
||||
Extents2D srcRegion,
|
||||
Extents2D dstRegion,
|
||||
bool linearFilter)
|
||||
bool linearFilter,
|
||||
int srcLayer = 0,
|
||||
int dstLayer = 0,
|
||||
int srcLevel = 0,
|
||||
int dstLevel = 0)
|
||||
{
|
||||
int levels = Math.Min(src.Info.Levels - srcLevel, dst.Info.Levels - dstLevel);
|
||||
int layers = Math.Min(src.Info.GetLayers() - srcLayer, dst.Info.GetLayers() - dstLayer);
|
||||
|
||||
Copy(src, dst, srcRegion, dstRegion, linearFilter, srcLayer, dstLayer, srcLevel, dstLevel, layers, levels);
|
||||
}
|
||||
|
||||
public void Copy(
|
||||
TextureView src,
|
||||
TextureView dst,
|
||||
Extents2D srcRegion,
|
||||
Extents2D dstRegion,
|
||||
bool linearFilter,
|
||||
int srcLayer,
|
||||
int dstLayer,
|
||||
int srcLevel,
|
||||
int dstLevel,
|
||||
int layers,
|
||||
int levels)
|
||||
{
|
||||
TextureView srcConverted = src.Format.IsBgr() != dst.Format.IsBgr() ? BgraSwap(src) : src;
|
||||
|
||||
|
@ -34,22 +60,29 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
|
||||
|
||||
int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
|
||||
int layers = Math.Min(src.Info.GetLayers(), dst.Info.GetLayers());
|
||||
if (srcLevel != 0)
|
||||
{
|
||||
srcRegion = srcRegion.Reduce(srcLevel);
|
||||
}
|
||||
|
||||
if (dstLevel != 0)
|
||||
{
|
||||
dstRegion = dstRegion.Reduce(dstLevel);
|
||||
}
|
||||
|
||||
for (int level = 0; level < levels; level++)
|
||||
{
|
||||
for (int layer = 0; layer < layers; layer++)
|
||||
{
|
||||
if (layers > 1)
|
||||
if ((srcLayer | dstLayer) != 0 || layers > 1)
|
||||
{
|
||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level, layer);
|
||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level, layer);
|
||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level, srcLayer + layer);
|
||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level, dstLayer + layer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level);
|
||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level);
|
||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level);
|
||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level);
|
||||
}
|
||||
|
||||
ClearBufferMask mask = GetMask(src.Format);
|
||||
|
@ -484,6 +517,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
|
||||
_copyPboHandle = 0;
|
||||
}
|
||||
|
||||
IntermmediatePool.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,14 +115,77 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||
{
|
||||
TextureView destinationView = (TextureView)destination;
|
||||
|
||||
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
|
||||
if (destinationView.Target.IsMultisample() || Target.IsMultisample())
|
||||
{
|
||||
Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
|
||||
Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
|
||||
|
||||
TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
|
||||
GetIntermmediateTarget(Target),
|
||||
Info.BlockWidth,
|
||||
Info.BlockHeight,
|
||||
Info.BytesPerPixel,
|
||||
Format,
|
||||
Width,
|
||||
Height,
|
||||
Info.Depth,
|
||||
Info.Levels);
|
||||
|
||||
GL.Disable(EnableCap.FramebufferSrgb);
|
||||
|
||||
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true);
|
||||
_renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, firstLayer, 0, firstLevel);
|
||||
|
||||
GL.Enable(EnableCap.FramebufferSrgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
|
||||
{
|
||||
TextureView destinationView = (TextureView)destination;
|
||||
TextureView destinationView = (TextureView)destination;
|
||||
|
||||
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
|
||||
if (destinationView.Target.IsMultisample() || Target.IsMultisample())
|
||||
{
|
||||
Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
|
||||
Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
|
||||
|
||||
TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
|
||||
GetIntermmediateTarget(Target),
|
||||
Info.BlockWidth,
|
||||
Info.BlockHeight,
|
||||
Info.BytesPerPixel,
|
||||
Format,
|
||||
Math.Max(1, Width >> srcLevel),
|
||||
Math.Max(1, Height >> srcLevel),
|
||||
1,
|
||||
1);
|
||||
|
||||
GL.Disable(EnableCap.FramebufferSrgb);
|
||||
|
||||
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true, srcLayer, 0, srcLevel, 0, 1, 1);
|
||||
_renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, dstLayer, 0, dstLevel, 1, 1);
|
||||
|
||||
GL.Enable(EnableCap.FramebufferSrgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static Target GetIntermmediateTarget(Target srcTarget)
|
||||
{
|
||||
return srcTarget switch
|
||||
{
|
||||
Target.Texture2D => Target.Texture2DMultisample,
|
||||
Target.Texture2DArray => Target.Texture2DMultisampleArray,
|
||||
Target.Texture2DMultisampleArray => Target.Texture2DArray,
|
||||
_ => Target.Texture2D
|
||||
};
|
||||
}
|
||||
|
||||
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
|
||||
|
|
Reference in a new issue