aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2021-08-20 21:52:09 +0100
committerGitHub <noreply@github.com>2021-08-20 17:52:09 -0300
commitbdc1f91a5b459a25cb74de9895d0136cf29d220d (patch)
tree61b3d5fdf638cc8c4cf99bed04d7600c732ce92b /Ryujinx.Graphics.Gpu/Image/TextureCache.cs
parente0af248e6f96efe7009915935407fc809eb774a9 (diff)
Remove pool cache entries for incompatible overlapping textures (#2568)
This greatly reduces memory usage in games that aggressively reuse memory without removing dead textures from the pool, such as the Xenoblade games, UE3 games, and to a lesser extent, UE4/unity games. This change stops memory usage from ballooning in xenoblade and some other games. It will also reduce texture view/dependency complexity in some games - for example in MK8D it will reduce the number of surface copies between lighting cubemaps generated for actors. There shouldn't be any performance impact from doing this, though the deletion and creation of textures could be improved by improving the OpenGL texture storage cache, which is very simple and limited right now. This will be improved in future. Another potential error has been fixed with the texture cache, which could prevent data loss when data is interchangably written to textures from both the GPU and CPU. It was possible that the dirty flag for a texture would be consumed without the data being synchronized on next use, due to the old overlap check. This check no longer consumes the dirty flag. Please test a bunch of games to make sure they still work, and there are no performance regressions.
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Image/TextureCache.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureCache.cs50
1 files changed, 35 insertions, 15 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 58cd3a2f..37682b65 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -623,29 +623,49 @@ namespace Ryujinx.Graphics.Gpu.Image
hasLayerViews |= overlap.Info.GetSlices() < texture.Info.GetSlices();
hasMipViews |= overlap.Info.Levels < texture.Info.Levels;
}
- else if (overlapInCache || !setData)
+ else
{
- if (info.GobBlocksInZ > 1 && info.GobBlocksInZ == overlap.Info.GobBlocksInZ)
+ bool removeOverlap;
+ bool modified = overlap.CheckModified(false);
+
+ if (overlapInCache || !setData)
{
- // Allow overlapping slices of 3D textures. Could be improved in future by making sure the textures don't overlap.
- continue;
- }
+ if (info.GobBlocksInZ > 1 && info.GobBlocksInZ == overlap.Info.GobBlocksInZ)
+ {
+ // Allow overlapping slices of 3D textures. Could be improved in future by making sure the textures don't overlap.
+ continue;
+ }
+
+ // The overlap texture is going to contain garbage data after we draw, or is generally incompatible.
+ // If the texture cannot be entirely contained in the new address space, and one of its view children is compatible with us,
+ // it must be flushed before removal, so that the data is not lost.
+
+ // If the texture was modified since its last use, then that data is probably meant to go into this texture.
+ // If the data has been modified by the CPU, then it also shouldn't be flushed.
- // The overlap texture is going to contain garbage data after we draw, or is generally incompatible.
- // If the texture cannot be entirely contained in the new address space, and one of its view children is compatible with us,
- // it must be flushed before removal, so that the data is not lost.
+ bool viewCompatibleChild = overlap.HasViewCompatibleChild(texture);
- // If the texture was modified since its last use, then that data is probably meant to go into this texture.
- // If the data has been modified by the CPU, then it also shouldn't be flushed.
- bool modified = overlap.ConsumeModified();
+ bool flush = overlapInCache && !modified && !texture.Range.Contains(overlap.Range) && viewCompatibleChild;
- bool flush = overlapInCache && !modified && !texture.Range.Contains(overlap.Range) && overlap.HasViewCompatibleChild(texture);
+ setData |= modified || flush;
- setData |= modified || flush;
+ if (overlapInCache)
+ {
+ _cache.Remove(overlap, flush);
+ }
+
+ removeOverlap = modified && !viewCompatibleChild;
+ }
+ else
+ {
+ // If an incompatible overlapping texture has been modified, then it's data is likely destined for this texture,
+ // and the overlapped texture will contain garbage. In this case, it should be removed to save memory.
+ removeOverlap = modified;
+ }
- if (overlapInCache)
+ if (removeOverlap && overlap.Info.Target != Target.TextureBuffer)
{
- _cache.Remove(overlap, flush);
+ overlap.RemoveFromPools(false);
}
}
}