diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index 0a083ebc..c9c3c59a 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 37682b65..44c974e8 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 bcce443c..5b5c5ab0 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 00000000..a60951e3 --- /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 f518ee4b..880d677b 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