diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 0a083ebc3..c9c3c59ac 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -9,6 +9,7 @@ using Ryujinx.Memory.Range;
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
namespace Ryujinx.Graphics.Gpu.Image
{
@@ -1295,6 +1296,37 @@ namespace Ryujinx.Graphics.Gpu.Image
return false;
}
+ ///
+ /// Determine if any of this texture's data overlaps with another.
+ ///
+ /// The texture to check against
+ /// True if any slice of the textures overlap, false otherwise
+ public bool DataOverlaps(Texture texture)
+ {
+ if (texture._sizeInfo.AllOffsets.Length == 1 && _sizeInfo.AllOffsets.Length == 1)
+ {
+ return Range.OverlapsWith(texture.Range);
+ }
+
+ MultiRange otherRange = texture.Range;
+
+ IEnumerable regions = _sizeInfo.AllRegions().Select((region) => Range.GetSlice((ulong)region.Offset, (ulong)region.Size));
+ IEnumerable otherRegions = texture._sizeInfo.AllRegions().Select((region) => otherRange.GetSlice((ulong)region.Offset, (ulong)region.Size));
+
+ foreach (MultiRange region in regions)
+ {
+ foreach (MultiRange otherRegion in otherRegions)
+ {
+ if (region.OverlapsWith(otherRegion))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
///
/// Increments the texture reference count.
///
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 37682b655..44c974e8f 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -636,6 +636,13 @@ namespace Ryujinx.Graphics.Gpu.Image
continue;
}
+ if (!texture.DataOverlaps(overlap))
+ {
+ // Allow textures to overlap if their data does not actually overlap.
+ // This typically happens when mip level subranges of a layered texture are used. (each texture fills the gaps of the others)
+ 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.
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index bcce443cb..5b5c5ab01 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -85,8 +85,9 @@ namespace Ryujinx.Graphics.Gpu.Image
TextureDescriptor descriptor = GetDescriptor(id);
- int width = descriptor.UnpackWidth();
- int height = descriptor.UnpackHeight();
+ int baseLevel = descriptor.UnpackBaseLevel();
+ int width = Math.Max(1, descriptor.UnpackWidth() >> baseLevel);
+ int height = Math.Max(1, descriptor.UnpackHeight() >> baseLevel);
if (texture.Info.Width != width || texture.Info.Height != height)
{
diff --git a/Ryujinx.Graphics.Texture/Region.cs b/Ryujinx.Graphics.Texture/Region.cs
new file mode 100644
index 000000000..a60951e32
--- /dev/null
+++ b/Ryujinx.Graphics.Texture/Region.cs
@@ -0,0 +1,14 @@
+namespace Ryujinx.Graphics.Texture
+{
+ public struct Region
+ {
+ public int Offset { get; }
+ public int Size { get; }
+
+ public Region(int offset, int size)
+ {
+ Offset = offset;
+ Size = size;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Texture/SizeInfo.cs b/Ryujinx.Graphics.Texture/SizeInfo.cs
index f518ee4b1..880d677b9 100644
--- a/Ryujinx.Graphics.Texture/SizeInfo.cs
+++ b/Ryujinx.Graphics.Texture/SizeInfo.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace Ryujinx.Graphics.Texture
{
@@ -91,5 +92,23 @@ namespace Ryujinx.Graphics.Texture
return true;
}
+
+ public IEnumerable AllRegions()
+ {
+ if (_is3D)
+ {
+ for (int i = 0; i < _mipOffsets.Length; i++)
+ {
+ yield return new Region(_mipOffsets[i], SliceSizes[i]);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < AllOffsets.Length; i++)
+ {
+ yield return new Region(AllOffsets[i], SliceSizes[i % _levels]);
+ }
+ }
+ }
}
}
\ No newline at end of file