Texture Cache: "Texture Groups" and "Texture Dependencies" (#2001)

* Initial implementation (3d tex mips broken)

This works rather well for most games, just need to fix 3d texture mips.

* Cleanup

* Address feedback

* Copy Dependencies and various other fixes

* Fix layer/level offset for copy from view<->view.

* Remove dirty flag from dependency

The dirty flag behaviour is not needed - DeferredCopy is all we need.

* Fix tracking mip slices.

* Propagate granularity (fix astral chain)

* Address Feedback pt 1

* Save slice sizes as part of SizeInfo

* Fix nits

* Fix disposing multiple dependencies causing a crash

This list is obviously modified when removing dependencies, so create a copy of it.
This commit is contained in:
riperiperi 2021-03-02 22:30:54 +00:00 committed by GitHub
parent 7a90abc035
commit b530f0e110
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1915 additions and 220 deletions

View file

@ -18,6 +18,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
throw new NotSupportedException();
}
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{
throw new NotSupportedException();
}
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
{
throw new NotSupportedException();
@ -38,6 +43,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
Buffer.SetData(_buffer, _bufferOffset, data.Slice(0, Math.Min(data.Length, _bufferSize)));
}
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
{
throw new NotSupportedException();
}
public void SetStorage(BufferRange buffer)
{
if (buffer.Handle == _buffer &&

View file

@ -115,18 +115,44 @@ namespace Ryujinx.Graphics.OpenGL.Image
TextureCreateInfo srcInfo = src.Info;
TextureCreateInfo dstInfo = dst.Info;
int srcDepth = srcInfo.GetDepthOrLayers();
int srcLevels = srcInfo.Levels;
int dstDepth = dstInfo.GetDepthOrLayers();
int dstLevels = dstInfo.Levels;
if (dstInfo.Target == Target.Texture3D)
{
dstDepth = Math.Max(1, dstDepth >> dstLevel);
}
int depth = Math.Min(srcDepth, dstDepth);
int levels = Math.Min(srcLevels, dstLevels);
CopyUnscaled(src, dst, srcLayer, dstLayer, srcLevel, dstLevel, depth, levels);
}
public void CopyUnscaled(
ITextureInfo src,
ITextureInfo dst,
int srcLayer,
int dstLayer,
int srcLevel,
int dstLevel,
int depth,
int levels)
{
TextureCreateInfo srcInfo = src.Info;
TextureCreateInfo dstInfo = dst.Info;
int srcHandle = src.Handle;
int dstHandle = dst.Handle;
int srcWidth = srcInfo.Width;
int srcHeight = srcInfo.Height;
int srcDepth = srcInfo.GetDepthOrLayers();
int srcLevels = srcInfo.Levels;
int dstWidth = dstInfo.Width;
int dstHeight = dstInfo.Height;
int dstDepth = dstInfo.GetDepthOrLayers();
int dstLevels = dstInfo.Levels;
srcWidth = Math.Max(1, srcWidth >> srcLevel);
srcHeight = Math.Max(1, srcHeight >> srcLevel);
@ -134,11 +160,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
dstWidth = Math.Max(1, dstWidth >> dstLevel);
dstHeight = Math.Max(1, dstHeight >> dstLevel);
if (dstInfo.Target == Target.Texture3D)
{
dstDepth = Math.Max(1, dstDepth >> dstLevel);
}
int blockWidth = 1;
int blockHeight = 1;
bool sizeInBlocks = false;
@ -166,8 +187,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
int width = Math.Min(srcWidth, dstWidth);
int height = Math.Min(srcHeight, dstHeight);
int depth = Math.Min(srcDepth, dstDepth);
int levels = Math.Min(srcLevels, dstLevels);
for (int level = 0; level < levels; level++)
{

View file

@ -10,8 +10,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
private readonly TextureStorage _parent;
private TextureView _emulatedViewParent;
private TextureView _incompatibleFormatView;
public int FirstLayer { get; private set; }
@ -96,37 +94,10 @@ namespace Ryujinx.Graphics.OpenGL.Image
public ITexture CreateView(TextureCreateInfo info, int firstLayer, int firstLevel)
{
if (Info.IsCompressed == info.IsCompressed)
{
firstLayer += FirstLayer;
firstLevel += FirstLevel;
firstLayer += FirstLayer;
firstLevel += FirstLevel;
return _parent.CreateView(info, firstLayer, firstLevel);
}
else
{
// TODO: Most graphics APIs doesn't support creating a texture view from a compressed format
// with a non-compressed format (or vice-versa), however NVN seems to support it.
// So we emulate that here with a texture copy (see the first CopyTo overload).
// However right now it only does a single copy right after the view is created,
// so it doesn't work for all cases.
TextureView emulatedView = (TextureView)_renderer.CreateTexture(info, ScaleFactor);
_renderer.TextureCopy.CopyUnscaled(
this,
emulatedView,
0,
firstLayer,
0,
firstLevel);
emulatedView._emulatedViewParent = this;
emulatedView.FirstLayer = firstLayer;
emulatedView.FirstLevel = firstLevel;
return emulatedView;
}
return _parent.CreateView(info, firstLayer, firstLevel);
}
public int GetIncompatibleFormatViewHandle()
@ -163,17 +134,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
TextureView destinationView = (TextureView)destination;
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
}
if (destinationView._emulatedViewParent != null)
{
_renderer.TextureCopy.CopyUnscaled(
this,
destinationView._emulatedViewParent,
0,
destinationView.FirstLayer,
0,
destinationView.FirstLevel);
}
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{
TextureView destinationView = (TextureView)destination;
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
@ -308,6 +275,20 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
public void SetData(ReadOnlySpan<byte> data, int layer, int level)
{
unsafe
{
fixed (byte* ptr = data)
{
int width = Math.Max(Info.Width >> level, 1);
int height = Math.Max(Info.Height >> level, 1);
ReadFrom2D((IntPtr)ptr, layer, level, width, height);
}
}
}
public void ReadFromPbo(int offset, int size)
{
ReadFrom(IntPtr.Zero + offset, size);