mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-03-14 20:00:17 +00:00
Avoid lookup of invalid textures if pool did not change
This commit is contained in:
parent
c881cd2d14
commit
3d3dd8e821
2 changed files with 237 additions and 0 deletions
226
Ryujinx.Common/Collections/BitMap.cs
Normal file
226
Ryujinx.Common/Collections/BitMap.cs
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
namespace Ryujinx.Common.Collections
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a collection that can store 1 bit values.
|
||||||
|
/// </summary>
|
||||||
|
public struct BitMap
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Size in bits of the integer used internally for the groups of bits.
|
||||||
|
/// </summary>
|
||||||
|
public const int IntSize = 64;
|
||||||
|
|
||||||
|
private const int IntShift = 6;
|
||||||
|
private const int IntMask = IntSize - 1;
|
||||||
|
|
||||||
|
private readonly long[] _masks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value of a bit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit">Bit to access</param>
|
||||||
|
/// <returns>Bit value</returns>
|
||||||
|
public bool this[int bit]
|
||||||
|
{
|
||||||
|
get => IsSet(bit);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
Set(bit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Clear(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new bitmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">Total number of bits</param>
|
||||||
|
public BitMap(int count)
|
||||||
|
{
|
||||||
|
_masks = new long[(count + IntMask) / IntSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if any bit is set.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if any bit is set, false otherwise</returns>
|
||||||
|
public bool AnySet()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _masks.Length; i++)
|
||||||
|
{
|
||||||
|
if (_masks[i] != 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a specific bit is set.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit">Bit to be checked</param>
|
||||||
|
/// <returns>True if set, false otherwise</returns>
|
||||||
|
public bool IsSet(int bit)
|
||||||
|
{
|
||||||
|
int wordIndex = bit >> IntShift;
|
||||||
|
int wordBit = bit & IntMask;
|
||||||
|
|
||||||
|
long wordMask = 1L << wordBit;
|
||||||
|
|
||||||
|
return (_masks[wordIndex] & wordMask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if any bit inside a given range of bits is set.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">Start bit of the range</param>
|
||||||
|
/// <param name="end">End bit of the range (inclusive)</param>
|
||||||
|
/// <returns>True if any bit is set, false otherwise</returns>
|
||||||
|
public bool IsSet(int start, int end)
|
||||||
|
{
|
||||||
|
if (start == end)
|
||||||
|
{
|
||||||
|
return IsSet(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
int startIndex = start >> IntShift;
|
||||||
|
int startBit = start & IntMask;
|
||||||
|
long startMask = -1L << startBit;
|
||||||
|
|
||||||
|
int endIndex = end >> IntShift;
|
||||||
|
int endBit = end & IntMask;
|
||||||
|
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
|
||||||
|
|
||||||
|
if (startIndex == endIndex)
|
||||||
|
{
|
||||||
|
return (_masks[startIndex] & startMask & endMask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_masks[startIndex] & startMask) != 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = startIndex + 1; i < endIndex; i++)
|
||||||
|
{
|
||||||
|
if (_masks[i] != 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_masks[endIndex] & endMask) != 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the value of a bit to 1.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit">Bit to be set</param>
|
||||||
|
/// <returns>True if the bit was 0 and then changed to 1, false if it was already 1</returns>
|
||||||
|
public bool Set(int bit)
|
||||||
|
{
|
||||||
|
int wordIndex = bit >> IntShift;
|
||||||
|
int wordBit = bit & IntMask;
|
||||||
|
|
||||||
|
long wordMask = 1L << wordBit;
|
||||||
|
|
||||||
|
if ((_masks[wordIndex] & wordMask) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_masks[wordIndex] |= wordMask;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a given range of bits to 1.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">Start bit of the range</param>
|
||||||
|
/// <param name="end">End bit of the range (inclusive)</param>
|
||||||
|
public void SetRange(int start, int end)
|
||||||
|
{
|
||||||
|
if (start == end)
|
||||||
|
{
|
||||||
|
Set(start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startIndex = start >> IntShift;
|
||||||
|
int startBit = start & IntMask;
|
||||||
|
long startMask = -1L << startBit;
|
||||||
|
|
||||||
|
int endIndex = end >> IntShift;
|
||||||
|
int endBit = end & IntMask;
|
||||||
|
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
|
||||||
|
|
||||||
|
if (startIndex == endIndex)
|
||||||
|
{
|
||||||
|
_masks[startIndex] |= startMask & endMask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_masks[startIndex] |= startMask;
|
||||||
|
|
||||||
|
for (int i = startIndex + 1; i < endIndex; i++)
|
||||||
|
{
|
||||||
|
_masks[i] |= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_masks[endIndex] |= endMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a given bit to 0.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit">Bit to be cleared</param>
|
||||||
|
public void Clear(int bit)
|
||||||
|
{
|
||||||
|
int wordIndex = bit >> IntShift;
|
||||||
|
int wordBit = bit & IntMask;
|
||||||
|
|
||||||
|
long wordMask = 1L << wordBit;
|
||||||
|
|
||||||
|
_masks[wordIndex] &= ~wordMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets all bits to 0.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _masks.Length; i++)
|
||||||
|
{
|
||||||
|
_masks[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets one or more groups of bits to 0.
|
||||||
|
/// See <see cref="IntSize"/> for how many bits are inside each group.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start">Start index of the group</param>
|
||||||
|
/// <param name="end">End index of the group (inclusive)</param>
|
||||||
|
public void ClearInt(int start, int end)
|
||||||
|
{
|
||||||
|
for (int i = start; i <= end; i++)
|
||||||
|
{
|
||||||
|
_masks[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Ryujinx.Common.Collections;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
|
@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
class TexturePool : Pool<Texture, TextureDescriptor>
|
class TexturePool : Pool<Texture, TextureDescriptor>
|
||||||
{
|
{
|
||||||
private readonly GpuChannel _channel;
|
private readonly GpuChannel _channel;
|
||||||
|
private readonly BitMap _invalidMap;
|
||||||
private readonly ConcurrentQueue<Texture> _dereferenceQueue = new ConcurrentQueue<Texture>();
|
private readonly ConcurrentQueue<Texture> _dereferenceQueue = new ConcurrentQueue<Texture>();
|
||||||
private TextureDescriptor _defaultDescriptor;
|
private TextureDescriptor _defaultDescriptor;
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
|
public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
|
||||||
{
|
{
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
|
_invalidMap = new BitMap(maximumId + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -47,6 +50,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
{
|
||||||
|
if (_invalidMap.IsSet(id))
|
||||||
|
{
|
||||||
|
return ref descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
||||||
|
|
||||||
ProcessDereferenceQueue();
|
ProcessDereferenceQueue();
|
||||||
|
@ -56,6 +64,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// If this happens, then the texture address is invalid, we can't add it to the cache.
|
// If this happens, then the texture address is invalid, we can't add it to the cache.
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
{
|
||||||
|
_invalidMap.Set(id);
|
||||||
return ref descriptor;
|
return ref descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +225,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
Items[id] = null;
|
Items[id] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_invalidMap.Clear(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue