aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Texture
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2021-03-02 22:30:54 +0000
committerGitHub <noreply@github.com>2021-03-02 19:30:54 -0300
commitb530f0e1104723b894695b2860cf0f568f24cc9a (patch)
tree04f6b7d76d334ddc5c0378f6aa00b98739bc793e /Ryujinx.Graphics.Texture
parent7a90abc03555f41ba7589bc8e1f714839f9e2fed (diff)
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.
Diffstat (limited to 'Ryujinx.Graphics.Texture')
-rw-r--r--Ryujinx.Graphics.Texture/SizeCalculator.cs29
-rw-r--r--Ryujinx.Graphics.Texture/SizeInfo.cs43
2 files changed, 60 insertions, 12 deletions
diff --git a/Ryujinx.Graphics.Texture/SizeCalculator.cs b/Ryujinx.Graphics.Texture/SizeCalculator.cs
index 2dc60869..7eee13c0 100644
--- a/Ryujinx.Graphics.Texture/SizeCalculator.cs
+++ b/Ryujinx.Graphics.Texture/SizeCalculator.cs
@@ -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 * sliceSizes[level];
- layerSize += totalBlocksOfGobsInZ * totalBlocksOfGobsInY * robSize;
+ 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(
diff --git a/Ryujinx.Graphics.Texture/SizeInfo.cs b/Ryujinx.Graphics.Texture/SizeInfo.cs
index 55b22e3a..f518ee4b 100644
--- a/Ryujinx.Graphics.Texture/SizeInfo.cs
+++ b/Ryujinx.Graphics.Texture/SizeInfo.cs
@@ -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;
}