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
@ -13,4 +13,12 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
CubemapArray,
|
CubemapArray,
|
||||||
TextureBuffer
|
TextureBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TargetExtensions
|
||||||
|
{
|
||||||
|
public static bool IsMultisample(this Target target)
|
||||||
|
{
|
||||||
|
return target == Target.Texture2DMultisample || target == Target.Texture2DMultisampleArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1136,33 +1136,23 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="range">Texture view physical memory ranges</param>
|
/// <param name="range">Texture view physical memory ranges</param>
|
||||||
/// <param name="layerSize">Layer size on the given texture</param>
|
/// <param name="layerSize">Layer size on the given texture</param>
|
||||||
/// <param name="caps">Host GPU capabilities</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="firstLayer">Texture view initial layer on this texture</param>
|
||||||
/// <param name="firstLevel">Texture view first mipmap level 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>
|
/// <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;
|
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
||||||
|
|
||||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps));
|
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps));
|
||||||
if (result != TextureViewCompatibility.Incompatible)
|
if (result != TextureViewCompatibility.Incompatible)
|
||||||
{
|
|
||||||
bool msTargetCompatible = false;
|
|
||||||
|
|
||||||
if (allowMs)
|
|
||||||
{
|
|
||||||
msTargetCompatible = Info.Target == Target.Texture2DMultisample && info.Target == Target.Texture2D;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!msTargetCompatible)
|
|
||||||
{
|
{
|
||||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
|
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
|
||||||
|
|
||||||
if (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY)
|
bool bothMs = Info.Target.IsMultisample() && info.Target.IsMultisample();
|
||||||
|
if (bothMs && (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)
|
if (result == TextureViewCompatibility.Full && Info.FormatInfo.Format != info.FormatInfo.Format && !_context.Capabilities.SupportsMismatchingViewFormat)
|
||||||
{
|
{
|
||||||
|
@ -547,7 +547,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
range.Value,
|
range.Value,
|
||||||
sizeInfo.LayerSize,
|
sizeInfo.LayerSize,
|
||||||
_context.Capabilities,
|
_context.Capabilities,
|
||||||
flags.HasFlag(TextureSearchFlags.ForCopy),
|
|
||||||
out int firstLayer,
|
out int firstLayer,
|
||||||
out int firstLevel);
|
out int firstLevel);
|
||||||
|
|
||||||
@ -662,7 +661,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
overlap.Range,
|
overlap.Range,
|
||||||
overlap.LayerSize,
|
overlap.LayerSize,
|
||||||
_context.Capabilities,
|
_context.Capabilities,
|
||||||
false,
|
|
||||||
out int firstLayer,
|
out int firstLayer,
|
||||||
out int firstLevel);
|
out int firstLevel);
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
@ -657,6 +656,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
case Target.Texture2DMultisample:
|
case Target.Texture2DMultisample:
|
||||||
case Target.Texture2DMultisampleArray:
|
case Target.Texture2DMultisampleArray:
|
||||||
|
if (rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray)
|
||||||
|
{
|
||||||
|
return TextureViewCompatibility.CopyOnly;
|
||||||
|
}
|
||||||
|
|
||||||
result = rhs.Target == Target.Texture2DMultisample ||
|
result = rhs.Target == Target.Texture2DMultisample ||
|
||||||
rhs.Target == Target.Texture2DMultisampleArray;
|
rhs.Target == Target.Texture2DMultisampleArray;
|
||||||
break;
|
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;
|
private readonly Renderer _renderer;
|
||||||
|
|
||||||
|
public IntermmediatePool IntermmediatePool { get; }
|
||||||
|
|
||||||
private int _srcFramebuffer;
|
private int _srcFramebuffer;
|
||||||
private int _dstFramebuffer;
|
private int _dstFramebuffer;
|
||||||
|
|
||||||
@ -18,6 +20,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
public TextureCopy(Renderer renderer)
|
public TextureCopy(Renderer renderer)
|
||||||
{
|
{
|
||||||
_renderer = renderer;
|
_renderer = renderer;
|
||||||
|
IntermmediatePool = new IntermmediatePool(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Copy(
|
public void Copy(
|
||||||
@ -25,7 +28,30 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
TextureView dst,
|
TextureView dst,
|
||||||
Extents2D srcRegion,
|
Extents2D srcRegion,
|
||||||
Extents2D dstRegion,
|
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;
|
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.ReadFramebuffer, GetSrcFramebufferLazy());
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
|
||||||
|
|
||||||
int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
|
if (srcLevel != 0)
|
||||||
int layers = Math.Min(src.Info.GetLayers(), dst.Info.GetLayers());
|
{
|
||||||
|
srcRegion = srcRegion.Reduce(srcLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstLevel != 0)
|
||||||
|
{
|
||||||
|
dstRegion = dstRegion.Reduce(dstLevel);
|
||||||
|
}
|
||||||
|
|
||||||
for (int level = 0; level < levels; level++)
|
for (int level = 0; level < levels; level++)
|
||||||
{
|
{
|
||||||
for (int layer = 0; layer < layers; layer++)
|
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.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level, srcLayer + layer);
|
||||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level, layer);
|
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level, dstLayer + layer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level);
|
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level);
|
||||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level);
|
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearBufferMask mask = GetMask(src.Format);
|
ClearBufferMask mask = GetMask(src.Format);
|
||||||
@ -484,6 +517,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
|
|
||||||
_copyPboHandle = 0;
|
_copyPboHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntermmediatePool.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,15 +115,78 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
{
|
{
|
||||||
TextureView destinationView = (TextureView)destination;
|
TextureView destinationView = (TextureView)destination;
|
||||||
|
|
||||||
|
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);
|
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
|
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
|
||||||
{
|
{
|
||||||
TextureView destinationView = (TextureView)destination;
|
TextureView destinationView = (TextureView)destination;
|
||||||
|
|
||||||
|
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);
|
_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)
|
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user