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

@ -9,6 +9,19 @@ namespace Ryujinx.Graphics.Texture
{
private const int StrideAlignment = 32;
private static int Calculate3DOffsetCount(int levels, int depth)
{
int offsetCount = depth;
while (--levels > 0)
{
depth = Math.Max(1, depth >> 1);
offsetCount += depth;
}
return offsetCount;
}
public static SizeInfo GetBlockLinearTextureSize(
int width,
int height,
@ -27,8 +40,9 @@ namespace Ryujinx.Graphics.Texture
int layerSize = 0;
int[] allOffsets = new int[levels * layers * depth];
int[] allOffsets = new int[is3D ? Calculate3DOffsetCount(levels, depth) : levels * layers * depth];
int[] mipOffsets = new int[levels];
int[] sliceSizes = new int[levels];
int mipGobBlocksInY = gobBlocksInY;
int mipGobBlocksInZ = gobBlocksInZ;
@ -36,6 +50,8 @@ namespace Ryujinx.Graphics.Texture
int gobWidth = (GobStride / bytesPerPixel) * gobBlocksInTileX;
int gobHeight = gobBlocksInY * GobHeight;
int depthLevelOffset = 0;
for (int level = 0; level < levels; level++)
{
int w = Math.Max(1, width >> level);
@ -86,13 +102,16 @@ namespace Ryujinx.Graphics.Texture
int zLow = z & mask;
int zHigh = z & ~mask;
allOffsets[z * levels + level] = baseOffset + zLow * gobSize + zHigh * sliceSize;
allOffsets[z + depthLevelOffset] = baseOffset + zLow * gobSize + zHigh * sliceSize;
}
}
mipOffsets[level] = layerSize;
sliceSizes[level] = totalBlocksOfGobsInY * robSize;
layerSize += totalBlocksOfGobsInZ * totalBlocksOfGobsInY * robSize;
layerSize += totalBlocksOfGobsInZ * sliceSizes[level];
depthLevelOffset += d;
}
if (layers > 1)
@ -133,7 +152,7 @@ namespace Ryujinx.Graphics.Texture
}
}
return new SizeInfo(mipOffsets, allOffsets, levels, layerSize, totalSize);
return new SizeInfo(mipOffsets, allOffsets, sliceSizes, depth, levels, layerSize, totalSize, is3D);
}
public static SizeInfo GetLinearTextureSize(int stride, int height, int blockHeight)
@ -142,7 +161,7 @@ namespace Ryujinx.Graphics.Texture
// so we only need to handle a single case (2D textures without mipmaps).
int totalSize = stride * BitUtils.DivRoundUp(height, blockHeight);
return new SizeInfo(new int[] { 0 }, new int[] { 0 }, 1, totalSize, totalSize);
return new SizeInfo(totalSize);
}
private static int AlignLayerSize(

View file

@ -5,34 +5,46 @@ namespace Ryujinx.Graphics.Texture
public struct SizeInfo
{
private readonly int[] _mipOffsets;
private readonly int[] _allOffsets;
private readonly int _levels;
private readonly int _depth;
private readonly bool _is3D;
public readonly int[] AllOffsets;
public readonly int[] SliceSizes;
public int LayerSize { get; }
public int TotalSize { get; }
public SizeInfo(int size)
{
_mipOffsets = new int[] { 0 };
_allOffsets = new int[] { 0 };
AllOffsets = new int[] { 0 };
SliceSizes = new int[] { size };
_depth = 1;
_levels = 1;
LayerSize = size;
TotalSize = size;
_is3D = false;
}
internal SizeInfo(
int[] mipOffsets,
int[] allOffsets,
int[] sliceSizes,
int depth,
int levels,
int layerSize,
int totalSize)
int totalSize,
bool is3D)
{
_mipOffsets = mipOffsets;
_allOffsets = allOffsets;
AllOffsets = allOffsets;
SliceSizes = sliceSizes;
_depth = depth;
_levels = levels;
LayerSize = layerSize;
TotalSize = totalSize;
_is3D = is3D;
}
public int GetMipOffset(int level)
@ -47,7 +59,7 @@ namespace Ryujinx.Graphics.Texture
public bool FindView(int offset, out int firstLayer, out int firstLevel)
{
int index = Array.BinarySearch(_allOffsets, offset);
int index = Array.BinarySearch(AllOffsets, offset);
if (index < 0)
{
@ -57,8 +69,25 @@ namespace Ryujinx.Graphics.Texture
return false;
}
firstLayer = index / _levels;
firstLevel = index - (firstLayer * _levels);
if (_is3D)
{
firstLayer = index;
firstLevel = 0;
int levelDepth = _depth;
while (firstLayer >= levelDepth)
{
firstLayer -= levelDepth;
firstLevel++;
levelDepth = Math.Max(levelDepth >> 1, 1);
}
}
else
{
firstLayer = index / _levels;
firstLevel = index - (firstLayer * _levels);
}
return true;
}