aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Image
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Image')
-rw-r--r--Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Image/Pool.cs18
-rw-r--r--Ryujinx.Graphics.Gpu/Image/Texture.cs218
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureManager.cs141
4 files changed, 207 insertions, 172 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs
index 634f9448..febabdad 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)
+ if (oldestTexture.IsModified && !oldestTexture.ConsumeModified())
{
// 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/Pool.cs b/Ryujinx.Graphics.Gpu/Image/Pool.cs
index 0abf6824..ff7a783b 100644
--- a/Ryujinx.Graphics.Gpu/Image/Pool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Pool.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common;
+using Ryujinx.Cpu.Tracking;
using Ryujinx.Graphics.Gpu.Memory;
using System;
@@ -34,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public ulong Size { get; }
- private readonly (ulong, ulong)[] _modifiedRanges;
+ private readonly CpuMultiRegionHandle _memoryTracking;
public Pool(GpuContext context, ulong address, int maximumId)
{
@@ -50,11 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Image
Address = address;
Size = size;
- ulong endAddress = BitUtils.AlignUp(Address + Size, PhysicalMemory.PageSize);
-
- ulong pagesCount = (endAddress - BitUtils.AlignDown(Address, PhysicalMemory.PageSize)) / PhysicalMemory.PageSize;
-
- _modifiedRanges = new (ulong, ulong)[pagesCount];
+ _memoryTracking = context.PhysicalMemory.BeginGranularTracking(address, size);
}
/// <summary>
@@ -71,12 +68,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public void SynchronizeMemory()
{
- int count = Context.PhysicalMemory.QueryModified(Address, Size, ResourceName.TexturePool, _modifiedRanges);
-
- for (int index = 0; index < count; index++)
+ _memoryTracking.QueryModified((ulong mAddress, ulong mSize) =>
{
- (ulong mAddress, ulong mSize) = _modifiedRanges[index];
-
if (mAddress < Address)
{
mAddress = Address;
@@ -90,7 +83,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
InvalidateRangeImpl(mAddress, mSize);
- }
+ });
}
private void InvalidateRangeInternal(ulong offset, int size)
@@ -152,6 +145,7 @@ namespace Ryujinx.Graphics.Gpu.Image
Items = null;
}
+ _memoryTracking.Dispose();
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index b1698363..e3c3a30a 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -1,9 +1,10 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
+using Ryujinx.Cpu.Tracking;
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
using Ryujinx.Graphics.Texture.Astc;
+using Ryujinx.Memory.Range;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -40,12 +41,10 @@ namespace Ryujinx.Graphics.Gpu.Image
public TextureScaleMode ScaleMode { get; private set; }
/// <summary>
- /// Set when a texture has been modified since it was last flushed.
+ /// Set when a texture has been modified by the Host GPU since it was last flushed.
/// </summary>
public bool IsModified { get; internal set; }
- private bool _everModified;
-
private int _depth;
private int _layers;
private int _firstLayer;
@@ -56,6 +55,8 @@ namespace Ryujinx.Graphics.Gpu.Image
private ITexture _arrayViewTexture;
private Target _arrayViewTarget;
+ private ITexture _flushHostTexture;
+
private Texture _viewStorage;
private List<Texture> _views;
@@ -71,11 +72,6 @@ namespace Ryujinx.Graphics.Gpu.Image
public LinkedListNode<Texture> CacheNode { get; set; }
/// <summary>
- /// Event to fire when texture data is modified by the GPU.
- /// </summary>
- public event Action<Texture> Modified;
-
- /// <summary>
/// Event to fire when texture data is disposed.
/// </summary>
public event Action<Texture> Disposed;
@@ -95,12 +91,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public ulong Size => (ulong)_sizeInfo.TotalSize;
- private (ulong, ulong)[] _modifiedRanges;
+ private CpuRegionHandle _memoryTracking;
private int _referenceCount;
- private int _sequenceNumber;
-
/// <summary>
/// Constructs a new instance of the cached GPU texture.
/// </summary>
@@ -159,8 +153,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_context = context;
_sizeInfo = sizeInfo;
- _modifiedRanges = new (ulong, ulong)[(sizeInfo.TotalSize / PhysicalMemory.PageSize) + 1];
-
SetInfo(info);
_viewStorage = this;
@@ -176,6 +168,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="withData">True if the texture is to be initialized with data</param>
public void InitializeData(bool isView, bool withData = false)
{
+ _memoryTracking = _context.PhysicalMemory.BeginTracking(Address, Size);
+
if (withData)
{
Debug.Assert(!isView);
@@ -246,6 +240,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="texture">The child texture</param>
private void AddView(Texture texture)
{
+ DisableMemoryTracking();
+
_views.Add(texture);
texture._viewStorage = this;
@@ -314,6 +310,16 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Disables memory tracking on this texture. Currently used for view containers, as we assume their views are covering all memory regions.
+ /// Textures with disabled memory tracking also cannot flush in most circumstances.
+ /// </summary>
+ public void DisableMemoryTracking()
+ {
+ _memoryTracking?.Dispose();
+ _memoryTracking = null;
+ }
+
+ /// <summary>
/// Recreates the texture storage (or view, in the case of child textures) of this texture.
/// This allows recreating the texture with a new size.
/// A copy is automatically performed from the old to the new texture.
@@ -327,7 +333,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
RecreateStorageOrView(
BitUtils.DivRoundUp(width * Info.FormatInfo.BlockWidth, blockWidth),
- BitUtils.DivRoundUp(height * Info.FormatInfo.BlockHeight, blockHeight),
+ BitUtils.DivRoundUp(height * Info.FormatInfo.BlockHeight, blockHeight),
depthOrLayers);
}
@@ -453,6 +459,33 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Copy the host texture to a scaled one. If a texture is not provided, create it with the given scale.
+ /// </summary>
+ /// <param name="scale">Scale factor</param>
+ /// <param name="storage">Texture to use instead of creating one</param>
+ /// <returns>A host texture containing a scaled version of this texture</returns>
+ private ITexture GetScaledHostTexture(float scale, ITexture storage = null)
+ {
+ if (storage == null)
+ {
+ TextureCreateInfo createInfo = TextureManager.GetCreateInfo(Info, _context.Capabilities);
+
+ storage = _context.Renderer.CreateTexture(createInfo, scale);
+ }
+
+ if (Info.Target == Target.Texture2DArray)
+ {
+ CopyArrayScaled(storage);
+ }
+ else
+ {
+ HostTexture.CopyTo(storage, new Extents2D(0, 0, HostTexture.Width, HostTexture.Height), new Extents2D(0, 0, storage.Width, storage.Height), true);
+ }
+
+ return storage;
+ }
+
+ /// <summary>
/// Sets the Scale Factor on this texture, and immediately recreates it at the correct size.
/// When a texture is resized, a scaled copy is performed from the old texture to the new one, to ensure no data is lost.
/// If scale is equivalent, this only propagates the blacklisted/scaled mode.
@@ -474,20 +507,10 @@ namespace Ryujinx.Graphics.Gpu.Image
if (ScaleFactor != scale)
{
Logger.Debug?.Print(LogClass.Gpu, $"Rescaling {Info.Width}x{Info.Height} {Info.FormatInfo.Format.ToString()} to ({ScaleFactor} to {scale}). ");
- TextureCreateInfo createInfo = TextureManager.GetCreateInfo(Info, _context.Capabilities);
ScaleFactor = scale;
- ITexture newStorage = _context.Renderer.CreateTexture(createInfo, ScaleFactor);
-
- if (Info.Target == Target.Texture2DArray)
- {
- CopyArrayScaled(newStorage);
- }
- else
- {
- HostTexture.CopyTo(newStorage, new Extents2D(0, 0, HostTexture.Width, HostTexture.Height), new Extents2D(0, 0, newStorage.Width, newStorage.Height), true);
- }
+ ITexture newStorage = GetScaledHostTexture(ScaleFactor);
Logger.Debug?.Print(LogClass.Gpu, $" Copy performed: {HostTexture.Width}x{HostTexture.Height} to {newStorage.Width}x{newStorage.Height}");
@@ -525,10 +548,17 @@ 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.
/// </summary>
+ /// <remarks>
+ /// If there is no memory tracking for this texture, it will always report as modified.
+ /// </remarks>
/// <returns>True if the texture was modified, false otherwise.</returns>
public bool ConsumeModified()
{
- return _context.PhysicalMemory.QueryModified(Address, Size, ResourceName.Texture, _modifiedRanges) > 0;
+ bool wasDirty = _memoryTracking?.Dirty ?? true;
+
+ _memoryTracking?.Reprotect();
+
+ return wasDirty;
}
/// <summary>
@@ -540,20 +570,14 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public void SynchronizeMemory()
{
- // Texture buffers are not handled here, instead they are invalidated (if modified)
- // when the texture is bound. This is handled by the buffer manager.
- if ((_sequenceNumber == _context.SequenceNumber && _hasData) || Info.Target == Target.TextureBuffer)
+ if (Info.Target == Target.TextureBuffer)
{
return;
}
- _sequenceNumber = _context.SequenceNumber;
-
- int modifiedCount = _context.PhysicalMemory.QueryModified(Address, Size, ResourceName.Texture, _modifiedRanges);
-
if (_hasData)
{
- if (modifiedCount == 0)
+ if (_memoryTracking?.Dirty != true)
{
return;
}
@@ -561,51 +585,27 @@ namespace Ryujinx.Graphics.Gpu.Image
BlacklistScale();
}
- ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Address, (int)Size);
-
- // If the texture was ever modified by the host GPU, we do partial invalidation
- // of the texture by getting GPU data and merging in the pages of memory
- // that were modified.
- // Note that if ASTC is not supported by the GPU we can't read it back since
- // it will use a different format. Since applications shouldn't be writing
- // ASTC textures from the GPU anyway, ignoring it should be safe.
- if (_everModified && !Info.FormatInfo.Format.IsAstc())
- {
- Span<byte> gpuData = GetTextureDataFromGpu(true);
-
- ulong endAddress = Address + Size;
+ _memoryTracking?.Reprotect();
- for (int i = 0; i < modifiedCount; i++)
- {
- (ulong modifiedAddress, ulong modifiedSize) = _modifiedRanges[i];
-
- ulong endModifiedAddress = modifiedAddress + modifiedSize;
+ ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Address, (int)Size);
- if (modifiedAddress < Address)
- {
- modifiedAddress = Address;
- }
+ IsModified = false;
- if (endModifiedAddress > endAddress)
- {
- endModifiedAddress = endAddress;
- }
+ data = ConvertToHostCompatibleFormat(data);
- modifiedSize = endModifiedAddress - modifiedAddress;
+ HostTexture.SetData(data);
- int offset = (int)(modifiedAddress - Address);
- int length = (int)modifiedSize;
+ _hasData = true;
+ }
- data.Slice(offset, length).CopyTo(gpuData.Slice(offset, length));
- }
+ public void SetData(ReadOnlySpan<byte> data)
+ {
+ BlacklistScale();
- data = gpuData;
- }
+ _memoryTracking?.Reprotect();
IsModified = false;
- data = ConvertToHostCompatibleFormat(data);
-
HostTexture.SetData(data);
_hasData = true;
@@ -699,6 +699,39 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
+
+ /// <summary>
+ /// Flushes the texture data, to be called from an external thread.
+ /// The host backend must ensure that we have shared access to the resource from this thread.
+ /// This is used when flushing from memory access handlers.
+ /// </summary>
+ public void ExternalFlush(ulong address, ulong size)
+ {
+ if (!IsModified || _memoryTracking == null)
+ {
+ return;
+ }
+
+ _context.Renderer.BackgroundContextAction(() =>
+ {
+ IsModified = false;
+ if (Info.FormatInfo.Format.IsAstc())
+ {
+ // ASTC textures are not in their original format, so cannot be flushed.
+ return;
+ }
+
+ ITexture texture = HostTexture;
+ if (ScaleFactor != 1f)
+ {
+ // If needed, create a texture to flush back to host at 1x scale.
+ texture = _flushHostTexture = GetScaledHostTexture(1f, _flushHostTexture);
+ }
+
+ _context.PhysicalMemory.WriteUntracked(Address, GetTextureDataFromGpu(false, texture));
+ });
+ }
+
/// <summary>
/// Gets data from the host GPU.
/// </summary>
@@ -707,25 +740,32 @@ namespace Ryujinx.Graphics.Gpu.Image
/// This is not cheap, avoid doing that unless strictly needed.
/// </remarks>
/// <returns>Host texture data</returns>
- private Span<byte> GetTextureDataFromGpu(bool blacklist)
+ private Span<byte> GetTextureDataFromGpu(bool blacklist, ITexture texture = null)
{
Span<byte> data;
- if (blacklist)
- {
- BlacklistScale();
- data = HostTexture.GetData();
- }
- else if (ScaleFactor != 1f)
+ if (texture != null)
{
- float scale = ScaleFactor;
- SetScale(1f);
- data = HostTexture.GetData();
- SetScale(scale);
+ data = texture.GetData();
}
else
{
- data = HostTexture.GetData();
+ if (blacklist)
+ {
+ BlacklistScale();
+ data = HostTexture.GetData();
+ }
+ else if (ScaleFactor != 1f)
+ {
+ float scale = ScaleFactor;
+ SetScale(1f);
+ data = HostTexture.GetData();
+ SetScale(scale);
+ }
+ else
+ {
+ data = HostTexture.GetData();
+ }
}
if (Info.IsLinear)
@@ -967,6 +1007,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="firstLevel">The first level of the view</param>
public void ReplaceView(Texture parent, TextureInfo info, ITexture hostTexture, int firstLayer, int firstLevel)
{
+ parent._viewStorage.SynchronizeMemory();
ReplaceStorage(hostTexture);
_firstLayer = parent._firstLayer + firstLayer;
@@ -994,14 +1035,13 @@ namespace Ryujinx.Graphics.Gpu.Image
public void SignalModified()
{
IsModified = true;
- _everModified = true;
-
- Modified?.Invoke(this);
if (_viewStorage != this)
{
_viewStorage.SignalModified();
}
+
+ _memoryTracking?.RegisterAction(ExternalFlush);
}
/// <summary>
@@ -1109,6 +1149,9 @@ namespace Ryujinx.Graphics.Gpu.Image
_arrayViewTexture?.Release();
_arrayViewTexture = null;
+
+ _flushHostTexture?.Release();
+ _flushHostTexture = null;
}
/// <summary>
@@ -1118,6 +1161,10 @@ namespace Ryujinx.Graphics.Gpu.Image
public void Unmapped()
{
IsModified = false; // We shouldn't flush this texture, as its memory is no longer mapped.
+
+ CpuRegionHandle tracking = _memoryTracking;
+ tracking?.Reprotect();
+ tracking?.RegisterAction(null);
}
/// <summary>
@@ -1128,6 +1175,7 @@ namespace Ryujinx.Graphics.Gpu.Image
DisposeTextures();
Disposed?.Invoke(this);
+ _memoryTracking?.Dispose();
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index dd499b78..27292f56 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -4,8 +4,8 @@ using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Graphics.Texture;
+using Ryujinx.Memory.Range;
using System;
-using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Image
{
@@ -51,9 +51,6 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly AutoDeleteCache _cache;
- private readonly HashSet<Texture> _modified;
- private readonly HashSet<Texture> _modifiedLinear;
-
/// <summary>
/// The scaling factor applied to all currently bound render targets.
/// </summary>
@@ -82,9 +79,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_overlapInfo = new OverlapInfo[OverlapsBufferInitialCapacity];
_cache = new AutoDeleteCache();
-
- _modified = new HashSet<Texture>(new ReferenceEqualityComparer<Texture>());
- _modifiedLinear = new HashSet<Texture>(new ReferenceEqualityComparer<Texture>());
}
/// <summary>
@@ -735,8 +729,9 @@ namespace Ryujinx.Graphics.Gpu.Image
for (int index = 0; index < overlapsCount; index++)
{
Texture overlap = _textureOverlaps[index];
+ TextureViewCompatibility overlapCompatibility = overlap.IsViewCompatible(info, size, out int firstLayer, out int firstLevel);
- if (overlap.IsViewCompatible(info, size, out int firstLayer, out int firstLevel) == TextureViewCompatibility.Full)
+ if (overlapCompatibility == TextureViewCompatibility.Full)
{
if (!isSamplerTexture)
{
@@ -745,7 +740,7 @@ namespace Ryujinx.Graphics.Gpu.Image
texture = overlap.CreateView(info, sizeInfo, firstLayer, firstLevel);
- if (IsTextureModified(overlap))
+ if (overlap.IsModified)
{
texture.SignalModified();
}
@@ -759,6 +754,11 @@ namespace Ryujinx.Graphics.Gpu.Image
}
break;
+ }
+ else if (overlapCompatibility == TextureViewCompatibility.CopyOnly)
+ {
+ // TODO: Copy rules for targets created after the container texture. See below.
+ overlap.DisableMemoryTracking();
}
}
@@ -849,7 +849,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Inherit modification from overlapping texture, do that before replacing
// the view since the replacement operation removes it from the list.
- if (IsTextureModified(overlap))
+ if (overlap.IsModified)
{
texture.SignalModified();
}
@@ -859,8 +859,13 @@ namespace Ryujinx.Graphics.Gpu.Image
// If the texture is a 3D texture, we need to additionally copy any slice
// of the 3D texture to the newly created 3D texture.
- if (info.Target == Target.Texture3D)
+ if (info.Target == Target.Texture3D && viewCompatible > 0)
{
+ // TODO: This copy can currently only happen when the 3D texture is created.
+ // If a game clears and redraws the slices, we won't be able to copy the new data to the 3D texture.
+ // Disable tracking to try keep at least the original data in there for as long as possible.
+ texture.DisableMemoryTracking();
+
for (int index = 0; index < viewCompatible; index++)
{
Texture overlap = _textureOverlaps[index];
@@ -872,7 +877,7 @@ namespace Ryujinx.Graphics.Gpu.Image
overlap.HostTexture.CopyTo(texture.HostTexture, oInfo.FirstLayer, oInfo.FirstLevel);
- if (IsTextureModified(overlap))
+ if (overlap.IsModified)
{
texture.SignalModified();
}
@@ -886,8 +891,6 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!isSamplerTexture)
{
_cache.Add(texture);
- texture.Modified += CacheTextureModified;
- texture.Disposed += CacheTextureDisposed;
}
lock (_textures)
@@ -901,42 +904,65 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
- /// Checks if a texture was modified by the host GPU.
+ /// Tries to find an existing texture matching the given buffer copy destination. If none is found, returns null.
/// </summary>
- /// <param name="texture">Texture to be checked</param>
- /// <returns>True if the texture was modified by the host GPU, false otherwise</returns>
- public bool IsTextureModified(Texture texture)
+ /// <param name="tex">The texture information</param>
+ /// <param name="cbp">The copy buffer parameters</param>
+ /// <param name="swizzle">The copy buffer swizzle</param>
+ /// <param name="linear">True if the texture has a linear layout, false otherwise</param>
+ /// <returns>A matching texture, or null if there is no match</returns>
+ public Texture FindTexture(CopyBufferTexture tex, CopyBufferParams cbp, CopyBufferSwizzle swizzle, bool linear)
{
- return _modified.Contains(texture);
- }
+ ulong address = _context.MemoryManager.Translate(cbp.DstAddress.Pack());
- /// <summary>
- /// Signaled when a cache texture is modified, and adds it to a set to be enumerated when flushing textures.
- /// </summary>
- /// <param name="texture">The texture that was modified.</param>
- private void CacheTextureModified(Texture texture)
- {
- texture.IsModified = true;
- _modified.Add(texture);
-
- if (texture.Info.IsLinear)
+ if (address == MemoryManager.BadAddress)
{
- _modifiedLinear.Add(texture);
+ return null;
}
- }
- /// <summary>
- /// Signaled when a cache texture is disposed, so it can be removed from the set of modified textures if present.
- /// </summary>
- /// <param name="texture">The texture that was diosposed.</param>
- private void CacheTextureDisposed(Texture texture)
- {
- _modified.Remove(texture);
+ int bpp = swizzle.UnpackDstComponentsCount() * swizzle.UnpackComponentSize();
- if (texture.Info.IsLinear)
+ int addressMatches = _textures.FindOverlaps(address, ref _textureOverlaps);
+
+ for (int i = 0; i < addressMatches; i++)
{
- _modifiedLinear.Remove(texture);
+ Texture texture = _textureOverlaps[i];
+ FormatInfo format = texture.Info.FormatInfo;
+
+ if (texture.Info.DepthOrLayers > 1)
+ {
+ continue;
+ }
+
+ bool match;
+
+ if (linear)
+ {
+ // Size is not available for linear textures. Use the stride and end of the copy region instead.
+
+ match = texture.Info.IsLinear && texture.Info.Stride == cbp.DstStride && tex.RegionY + cbp.YCount <= texture.Info.Height;
+ }
+ else
+ {
+ // Bpp may be a mismatch between the target texture and the param.
+ // Due to the way linear strided and block layouts work, widths can be multiplied by Bpp for comparison.
+ // Note: tex.Width is the aligned texture size. Prefer param.XCount, as the destination should be a texture with that exact size.
+
+ bool sizeMatch = cbp.XCount * bpp == texture.Info.Width * format.BytesPerPixel && tex.Height == texture.Info.Height;
+ bool formatMatch = !texture.Info.IsLinear &&
+ texture.Info.GobBlocksInY == tex.MemoryLayout.UnpackGobBlocksInY() &&
+ texture.Info.GobBlocksInZ == tex.MemoryLayout.UnpackGobBlocksInZ();
+
+ match = sizeMatch && formatMatch;
+ }
+
+ if (match)
+ {
+ return texture;
+ }
}
+
+ return null;
}
/// <summary>
@@ -1085,38 +1111,6 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
- /// Flushes all the textures in the cache that have been modified since the last call.
- /// </summary>
- public void Flush()
- {
- foreach (Texture texture in _modifiedLinear)
- {
- if (texture.IsModified)
- {
- texture.Flush();
- }
- }
-
- _modifiedLinear.Clear();
- }
-
- /// <summary>
- /// Flushes the textures in the cache inside a given range that have been modified since the last call.
- /// </summary>
- /// <param name="address">The range start address</param>
- /// <param name="size">The range size</param>
- public void Flush(ulong address, ulong size)
- {
- foreach (Texture texture in _modified)
- {
- if (texture.OverlapsWith(address, size) && texture.IsModified)
- {
- texture.Flush();
- }
- }
- }
-
- /// <summary>
/// Removes a texture from the cache.
/// </summary>
/// <remarks>
@@ -1142,7 +1136,6 @@ namespace Ryujinx.Graphics.Gpu.Image
{
foreach (Texture texture in _textures)
{
- _modified.Remove(texture);
texture.Dispose();
}
}