Improve handling for unmapped GPU resources (#2083)

* Improve handling for unmapped GPU resources

- Fixed a memory tracking bug that would set protection on empty PTEs
- When a texture's memory is (partially) unmapped, all pool references are forcibly removed and the texture must be rediscovered to draw with it. This will also force the texture discovery to always compare the texture's range for a match.
- RegionHandles now know if they are unmapped, and automatically unset their dirty flag when unmapped.
- Partial texture sync now loads only the region of texture that has been modified. Unmapped memory tracking handles cause dirty flags for a texture group handle to be ignored.

This greatly improves the emulator's stability for newer UE4 games.

* Address feedback, fix MultiRange slice

Fixed an issue where the size of the multi-range slice would be miscalculated.

* Update Ryujinx.Memory/Range/MultiRange.cs (feedback)

Co-authored-by: Mary <thog@protonmail.com>

Co-authored-by: Mary <thog@protonmail.com>
This commit is contained in:
riperiperi 2021-03-06 14:43:55 +00:00 committed by GitHub
parent bab6eedccf
commit 8d36681bf1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 229 additions and 15 deletions

View file

@ -2,6 +2,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Texture;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Image
@ -12,6 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Image
class TexturePool : Pool<Texture, TextureDescriptor>
{
private int _sequenceNumber;
private readonly ConcurrentQueue<Texture> _dereferenceQueue = new ConcurrentQueue<Texture>();
/// <summary>
/// Intrusive linked list node used on the texture pool cache.
@ -53,6 +55,8 @@ namespace Ryujinx.Graphics.Gpu.Image
TextureInfo info = GetInfo(descriptor, out int layerSize);
ProcessDereferenceQueue();
texture = Context.Methods.TextureManager.FindOrCreateTexture(TextureSearchFlags.ForSampler, info, layerSize);
// If this happens, then the texture address is invalid, we can't add it to the cache.
@ -61,7 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Image
return null;
}
texture.IncrementReferenceCount();
texture.IncrementReferenceCount(this, id);
Items[id] = texture;
@ -92,6 +96,39 @@ namespace Ryujinx.Graphics.Gpu.Image
return texture;
}
/// <summary>
/// Forcibly remove a texture from this pool's items.
/// If deferred, the dereference will be queued to occur on the render thread.
/// </summary>
/// <param name="texture">The texture being removed</param>
/// <param name="id">The ID of the texture in this pool</param>
/// <param name="deferred">If true, queue the dereference to happen on the render thread, otherwise dereference immediately</param>
public void ForceRemove(Texture texture, int id, bool deferred)
{
Items[id] = null;
if (deferred)
{
_dereferenceQueue.Enqueue(texture);
}
else
{
texture.DecrementReferenceCount();
}
}
/// <summary>
/// Process the dereference queue, decrementing the reference count for each texture in it.
/// This is used to ensure that texture disposal happens on the render thread.
/// </summary>
private void ProcessDereferenceQueue()
{
while (_dereferenceQueue.TryDequeue(out Texture toRemove))
{
toRemove.DecrementReferenceCount();
}
}
/// <summary>
/// Implementation of the texture pool range invalidation.
/// </summary>
@ -99,6 +136,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="size">Size of the range being invalidated</param>
protected override void InvalidateRangeImpl(ulong address, ulong size)
{
ProcessDereferenceQueue();
ulong endAddress = address + size;
for (; address < endAddress; address += DescriptorSize)
@ -118,7 +157,7 @@ namespace Ryujinx.Graphics.Gpu.Image
continue;
}
texture.DecrementReferenceCount();
texture.DecrementReferenceCount(this, id);
Items[id] = null;
}
@ -342,7 +381,14 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="item">The texture to be deleted</param>
protected override void Delete(Texture item)
{
item?.DecrementReferenceCount();
item?.DecrementReferenceCount(this);
}
public override void Dispose()
{
ProcessDereferenceQueue();
base.Dispose();
}
}
}