diff --git a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
index febabdad8..726b97ea1 100644
--- a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
@@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Gpu.Image
oldestTexture.SynchronizeMemory();
- if (oldestTexture.IsModified && !oldestTexture.ConsumeModified())
+ if (oldestTexture.IsModified && !oldestTexture.CheckModified(true))
{
// The texture must be flushed if it falls out of the auto delete cache.
// Flushes out of the auto delete cache do not trigger write tracking,
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index e156ff5ed..0a083ebc3 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!isView)
{
// Don't update this texture the next time we synchronize.
- ConsumeModified();
+ CheckModified(true);
if (ScaleMode == TextureScaleMode.Scaled)
{
@@ -599,12 +599,13 @@ namespace Ryujinx.Graphics.Gpu.Image
///
/// Checks if the memory for this texture was modified, and returns true if it was.
- /// The modified flags are consumed as a result.
+ /// The modified flags are optionally consumed as a result.
///
+ /// True to consume the dirty flags and reprotect, false to leave them as is
/// True if the texture was modified, false otherwise.
- public bool ConsumeModified()
+ public bool CheckModified(bool consume)
{
- return Group.ConsumeDirty(this);
+ return Group.CheckDirty(this, consume);
}
///
@@ -634,7 +635,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
else
{
- Group.ConsumeDirty(this);
+ Group.CheckDirty(this, true);
SynchronizeFull();
}
}
@@ -698,7 +699,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
BlacklistScale();
- Group.ConsumeDirty(this);
+ Group.CheckDirty(this, true);
IsModified = false;
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 58cd3a2f7..37682b655 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.
+
+ bool viewCompatibleChild = overlap.HasViewCompatibleChild(texture);
+
+ bool flush = overlapInCache && !modified && !texture.Range.Contains(overlap.Range) && viewCompatibleChild;
+
+ 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;
}
- // 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.
- bool modified = overlap.ConsumeModified();
-
- bool flush = overlapInCache && !modified && !texture.Range.Contains(overlap.Range) && overlap.HasViewCompatibleChild(texture);
-
- setData |= modified || flush;
-
- if (overlapInCache)
+ if (removeOverlap && overlap.Info.Target != Target.TextureBuffer)
{
- _cache.Remove(overlap, flush);
+ overlap.RemoveFromPools(false);
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index c4be1ceca..1fe0bbf7a 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -83,11 +83,13 @@ namespace Ryujinx.Graphics.Gpu.Image
}
///
- /// Consume the dirty flags for a given texture. The state is shared between views of the same layers and levels.
+ /// Check and optionally consume the dirty flags for a given texture.
+ /// The state is shared between views of the same layers and levels.
///
/// The texture being used
+ /// True to consume the dirty flags and reprotect, false to leave them as is
/// True if a flag was dirty, false otherwise
- public bool ConsumeDirty(Texture texture)
+ public bool CheckDirty(Texture texture, bool consume)
{
bool dirty = false;
@@ -101,7 +103,11 @@ namespace Ryujinx.Graphics.Gpu.Image
{
if (handle.Dirty)
{
- handle.Reprotect();
+ if (consume)
+ {
+ handle.Reprotect();
+ }
+
dirty = true;
}
}