Make PBO cache actually work, also some style changes, use int instead of long for sizes

This commit is contained in:
gdkchan 2018-12-09 19:57:52 -03:00
parent 7c39c731e2
commit b7c54a13d4
9 changed files with 128 additions and 98 deletions

View file

@ -7,9 +7,9 @@ namespace Ryujinx.Graphics.Gal
void LockCache();
void UnlockCache();
void Create(long key, IntPtr hostAddress, long size);
void Create(long key, byte[] data);
void Create(long key, IntPtr hostAddress, int size);
void Create(long key, byte[] buffer);
bool IsCached(long Key, long Size);
bool IsCached(long Key, int Size);
}
}

View file

@ -24,13 +24,13 @@ namespace Ryujinx.Graphics.Gal
GalVertexAttrib[] attributes,
GalVertexAttribArray[] arrays);
bool IsVboCached(long key, long size);
bool IsIboCached(long key, long size, out long vertexCount);
void CreateVbo(long Key, int DataSize, IntPtr HostAddress);
void CreateVbo(long Key, byte[] Data);
bool IsVboCached(long key, int size);
bool IsIboCached(long key, int size, out long vertexCount);
void CreateVbo(long key, IntPtr hostAddress, int size);
void CreateIbo(long key, IntPtr hostAddress, int size, long vertexCount);
void CreateVbo(long key, byte[] buffer);
void CreateIbo(long key, byte[] buffer, long vertexCount);
void SetIndexArray(int Size, GalIndexFormat Format);

View file

@ -5,13 +5,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
class OGLConstBuffer : IGalConstBuffer
{
private const long MaxConstBufferCacheSize = 64 * 1024 * 1024;
private OGLResourceCache<long, OGLStreamBuffer> Cache;
private OGLResourceCache<int, OGLStreamBuffer> Cache;
public OGLConstBuffer()
{
Cache = new OGLResourceCache<long, OGLStreamBuffer>(DeleteBuffer, MaxConstBufferCacheSize);
Cache = new OGLResourceCache<int, OGLStreamBuffer>(DeleteBuffer, OGLResourceLimits.ConstBufferLimit);
}
private static void DeleteBuffer(OGLStreamBuffer Buffer)
@ -29,19 +27,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Cache.Unlock();
}
public bool IsCached(long key, long size)
public bool IsCached(long key, int size)
{
return Cache.TryGetSize(key, out long cbSize) && cbSize >= size;
return Cache.TryGetSize(key, out int cbSize) && cbSize >= size;
}
public void Create(long key, IntPtr hostAddress, long size)
public void Create(long key, IntPtr hostAddress, int size)
{
GetBuffer(key, size).SetData(size, hostAddress);
GetBuffer(key, size).SetData(hostAddress, size);
}
public void Create(long key, byte[] data)
public void Create(long key, byte[] buffer)
{
GetBuffer(key, data.Length).SetData(data);
GetBuffer(key, buffer.Length).SetData(buffer);
}
public bool TryGetUbo(long key, out int uboHandle)
@ -58,7 +56,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return false;
}
private OGLStreamBuffer GetBuffer(long Key, long Size)
private OGLStreamBuffer GetBuffer(long Key, int Size)
{
if (!Cache.TryReuseValue(Key, Size, out OGLStreamBuffer Buffer))
{

View file

@ -75,9 +75,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev }
};
private const long MaxVertexBufferCacheSize = 128 * 1024 * 1024;
private const long MaxIndexBufferCacheSize = 64 * 1024 * 1024;
private int[] VertexBuffers;
private struct CachedVao
@ -99,7 +96,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private OGLResourceCache<int, CachedVao> VaoCache;
private OGLResourceCache<long, OGLStreamBuffer> VboCache;
private OGLResourceCache<int, OGLStreamBuffer> VboCache;
private class CachedIbo
{
@ -113,7 +110,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
private OGLResourceCache<long, CachedIbo> IboCache;
private OGLResourceCache<int, CachedIbo> IboCache;
private struct IbInfo
{
@ -129,11 +126,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
VertexBuffers = new int[32];
VaoCache = new OGLResourceCache<int, CachedVao>(DeleteVao, 64 * 1024);
VaoCache = new OGLResourceCache<int, CachedVao>(DeleteVao, OGLResourceLimits.VertexArrayLimit);
VboCache = new OGLResourceCache<long, OGLStreamBuffer>(DeleteBuffer, MaxVertexBufferCacheSize);
VboCache = new OGLResourceCache<int, OGLStreamBuffer>(DeleteBuffer, OGLResourceLimits.VertexBufferLimit);
IboCache = new OGLResourceCache<long, CachedIbo>(DeleteIbo, MaxIndexBufferCacheSize);
IboCache = new OGLResourceCache<int, CachedIbo>(DeleteIbo, OGLResourceLimits.IndexBufferLimit);
IndexBuffer = new IbInfo();
}
@ -169,13 +166,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void ClearBuffers(
GalClearBufferFlags Flags,
int Attachment,
float Red,
float Green,
float Blue,
float Alpha,
float Depth,
int Stencil)
int Attachment,
float Red,
float Green,
float Blue,
float Alpha,
float Depth,
int Stencil)
{
GL.ColorMask(
Attachment,
@ -200,14 +197,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
public bool IsVboCached(long key, long size)
public bool IsVboCached(long key, int size)
{
return VboCache.TryGetSize(key, out long vbSize) && vbSize >= size;
return VboCache.TryGetSize(key, out int vbSize) && vbSize >= size;
}
public bool IsIboCached(long key, long size, out long vertexCount)
public bool IsIboCached(long key, int size, out long vertexCount)
{
if (IboCache.TryGetSizeAndValue(key, out long ibSize, out CachedIbo ibo) && ibSize >= size)
if (IboCache.TryGetSizeAndValue(key, out int ibSize, out CachedIbo ibo) && ibSize >= size)
{
vertexCount = ibo.VertexCount;
@ -523,19 +520,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
throw new NotImplementedException("Unsupported size \"" + Attrib.Size + "\" on type \"" + Attrib.Type + "\"!");
}
public void CreateVbo(long Key, int DataSize, IntPtr HostAddress)
public void CreateVbo(long key, IntPtr hostAddress, int size)
{
GetVbo(Key, DataSize).SetData(DataSize, HostAddress);
}
public void CreateVbo(long Key, byte[] Data)
{
GetVbo(Key, Data.Length).SetData(Data);
GetVbo(key, size).SetData(hostAddress, size);
}
public void CreateIbo(long key, IntPtr hostAddress, int size, long vertexCount)
{
GetIbo(key, size, vertexCount).SetData(size, hostAddress);
GetIbo(key, size, vertexCount).SetData(hostAddress, size);
}
public void CreateVbo(long key, byte[] buffer)
{
GetVbo(key, buffer.Length).SetData(buffer);
}
public void CreateIbo(long key, byte[] buffer, long vertexCount)
@ -620,7 +617,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return false;
}
private OGLStreamBuffer GetVbo(long Key, long Size)
private OGLStreamBuffer GetVbo(long Key, int Size)
{
if (!VboCache.TryReuseValue(Key, Size, out OGLStreamBuffer Buffer))
{
@ -632,7 +629,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return Buffer;
}
private OGLStreamBuffer GetIbo(long Key, long Size, long VertexCount)
private OGLStreamBuffer GetIbo(long Key, int Size, long VertexCount)
{
if (!IboCache.TryReuseValue(Key, Size, out CachedIbo Ibo))
{

View file

@ -7,9 +7,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
class OGLResourceCache<TPoolKey, TValue>
{
private const int MinTimeDelta = 5 * 60000;
private const int MinTimeDeltaPool = 2500;
private const int MaxRemovalsPerRun = 10;
private const int DefaultMinTimeForPoolTransfer = 2500;
private class CacheBucket
{
public long Key { get; private set; }
@ -21,18 +22,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private Queue<Action> _deleteDeps;
public long DataSize { get; private set; }
public int Size { get; private set; }
public long Timestamp { get; private set; }
public bool Orphan { get; private set; }
public CacheBucket(long key, TPoolKey poolKey, TValue value, long dataSize)
public CacheBucket(long key, TPoolKey poolKey, TValue value, int size)
{
Key = key;
PoolKey = poolKey;
Value = value;
DataSize = dataSize;
Key = key;
PoolKey = poolKey;
Value = value;
Size = size;
_deleteDeps = new Queue<Action>();
}
@ -82,14 +83,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private bool _locked;
private long _maxSize;
private long _totalSize;
private int _maxSize;
private int _totalSize;
private int _minTimeForPoolTransfer;
public OGLResourceCache(Action<TValue> DeleteValueCallback, long MaxSize)
public OGLResourceCache(
Action<TValue> deleteValueCallback,
int maxSize,
int minTimeForPoolTransfer = DefaultMinTimeForPoolTransfer)
{
_maxSize = MaxSize;
_maxSize = maxSize;
_deleteValueCallback = DeleteValueCallback ?? throw new ArgumentNullException(nameof(DeleteValueCallback));
_deleteValueCallback = deleteValueCallback ?? throw new ArgumentNullException(nameof(deleteValueCallback));
_cache = new Dictionary<long, CacheBucket>();
@ -120,7 +125,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
ClearCacheIfNeeded();
}
public void AddOrUpdate(long key, TPoolKey poolKey, TValue value, long size)
public void AddOrUpdate(long key, TPoolKey poolKey, TValue value, int size)
{
if (!_locked)
{
@ -181,15 +186,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public bool TryReuseValue(long key, TPoolKey poolKey, out TValue value)
{
if (_cache.TryGetValue(key, out CacheBucket bucket) && bucket.PoolKey.Equals(poolKey))
{
//Value on key is already compatible, we don't need to do anything.
value = bucket.Value;
return true;
}
if (_pool.TryGetValue(poolKey, out LinkedList<CacheBucket> queue))
{
LinkedListNode<CacheBucket> node = queue.First;
CacheBucket bucket = node.Value;
bucket = node.Value;
Remove(bucket);
AddOrUpdate(key, poolKey, bucket.Value, bucket.DataSize);
AddOrUpdate(key, poolKey, bucket.Value, bucket.Size);
value = bucket.Value;
@ -201,11 +214,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return false;
}
public bool TryGetSize(long key, out long size)
public bool TryGetSize(long key, out int size)
{
if (_cache.TryGetValue(key, out CacheBucket bucket))
{
size = bucket.DataSize;
size = bucket.Size;
return true;
}
@ -215,11 +228,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return false;
}
public bool TryGetSizeAndValue(long key, out long size, out TValue value)
public bool TryGetSizeAndValue(long key, out int size, out TValue value)
{
if (_cache.TryGetValue(key, out CacheBucket bucket))
{
size = bucket.DataSize;
size = bucket.Size;
value = bucket.Value;
return true;
@ -267,7 +280,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
long timeDelta = timestamp - bucket.Timestamp;
if (timeDelta <= MinTimeDeltaPool)
if (timeDelta <= _minTimeForPoolTransfer)
{
break;
}
@ -319,7 +332,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
bucket.DeleteAllDependencies();
_totalSize -= bucket.DataSize;
_totalSize -= bucket.Size;
}
private void RemoveFromSortedCache(LinkedListNode<CacheBucket> node)

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.Gal.OpenGL
{
static class OGLResourceLimits
{
private const int KB = 1024;
private const int MB = 1024 * KB;
public const int ConstBufferLimit = 64 * MB;
public const int VertexArrayLimit = 16384;
public const int VertexBufferLimit = 128 * MB;
public const int IndexBufferLimit = 64 * MB;
public const int TextureLimit = 768 * MB;
public const int PixelBufferLimit = 64 * MB;
}
}

View file

@ -11,30 +11,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
protected BufferTarget Target { get; private set; }
public OGLStreamBuffer(BufferTarget Target, long Size)
public OGLStreamBuffer(BufferTarget target, int size)
{
this.Target = Target;
this.Size = Size;
Target = target;
Size = size;
Handle = GL.GenBuffer();
GL.BindBuffer(Target, Handle);
GL.BindBuffer(target, Handle);
GL.BufferData(Target, (IntPtr)Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
GL.BufferData(target, new IntPtr(size), IntPtr.Zero, BufferUsageHint.StreamDraw);
}
public void SetData(long Size, IntPtr HostAddress)
public void SetData(IntPtr hostAddress, int size)
{
GL.BindBuffer(Target, Handle);
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Size, HostAddress);
GL.BufferSubData(Target, IntPtr.Zero, new IntPtr(size), hostAddress);
}
public void SetData(byte[] Data)
public void SetData(byte[] buffer)
{
GL.BindBuffer(Target, Handle);
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Data.Length, Data);
GL.BufferSubData(Target, IntPtr.Zero, new IntPtr(buffer.Length), buffer);
}
public void Dispose()
@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
protected virtual void Dispose(bool disposing)
{
if (Disposing && Handle != 0)
if (disposing && Handle != 0)
{
GL.DeleteBuffer(Handle);

View file

@ -6,8 +6,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
class OGLTexture : IGalTexture
{
private const long MaxTextureCacheSize = 768 * 1024 * 1024;
private struct ImageKey
{
public int Width { get; private set; }
@ -48,9 +46,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public OGLTexture()
{
TextureCache = new OGLResourceCache<ImageKey, ImageHandler>(DeleteTexture, MaxTextureCacheSize);
TextureCache = new OGLResourceCache<ImageKey, ImageHandler>(DeleteTexture, OGLResourceLimits.TextureLimit);
PboCache = new OGLResourceCache<int, int>(GL.DeleteBuffer, 256);
PboCache = new OGLResourceCache<int, int>(GL.DeleteBuffer, OGLResourceLimits.PixelBufferLimit, 0);
}
public void LockCache()
@ -90,7 +88,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
CachedImage = new ImageHandler(GL.GenTexture(), Image);
TextureCache.AddOrUpdate(Key, imageKey, CachedImage, (uint)Size);
TextureCache.AddOrUpdate(Key, imageKey, CachedImage, Size);
}
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
@ -128,9 +126,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
const int Level = 0; //TODO: Support mipmap textures.
const int Border = 0;
ImageKey imgKey = new ImageKey(Image);
ImageKey imageKey = new ImageKey(Image);
TextureCache.AddOrUpdate(Key, imgKey, new ImageHandler(Handle, Image), (uint)Data.Length);
TextureCache.AddOrUpdate(Key, imageKey, new ImageHandler(Handle, Image), Data.Length);
if (ImageUtils.IsCompressed(Image.Format) && !IsAstc(Image.Format))
{
@ -195,9 +193,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return;
}
if (NewImage.Format == OldImage.Format &&
NewImage.Width == OldImage.Width &&
NewImage.Height == OldImage.Height)
if (NewImage.Width == OldImage.Width &&
NewImage.Height == OldImage.Height &&
NewImage.Format == OldImage.Format)
{
return;
}
@ -208,16 +206,22 @@ namespace Ryujinx.Graphics.Gal.OpenGL
if (!PboCache.TryReuseValue(0, BufferSize, out int Handle))
{
PboCache.AddOrUpdate(0, BufferSize, Handle = GL.GenBuffer(), BufferSize);
Handle = GL.GenBuffer();
GL.BindBuffer(BufferTarget.PixelPackBuffer, Handle);
GL.BufferData(BufferTarget.PixelPackBuffer, BufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
PboCache.AddOrUpdate(0, BufferSize, Handle, BufferSize);
}
else
{
GL.BindBuffer(BufferTarget.PixelPackBuffer, Handle);
}
GL.BindBuffer(BufferTarget.PixelPackBuffer, Handle);
GL.BufferData(BufferTarget.PixelPackBuffer, BufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
if (!TryGetImageHandler(Key, out ImageHandler CachedImage))
{
throw new InvalidOperationException();
throw new ArgumentException(nameof(Key));
}
(_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);

View file

@ -989,13 +989,13 @@ namespace Ryujinx.Graphics.Graphics3d
VbSize = MaxVbSize;
}
bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, VbSize);
bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, (int)VbSize);
if (Gpu.ResourceManager.MemoryRegionModified(Vmm, VboKey, VbSize, NvGpuBufferType.Vertex) || !VboCached)
{
if (Vmm.TryGetHostAddress(VbPosition, VbSize, out IntPtr VbPtr))
{
Gpu.Renderer.Rasterizer.CreateVbo(VboKey, (int)VbSize, VbPtr);
Gpu.Renderer.Rasterizer.CreateVbo(VboKey, VbPtr, (int)VbSize);
}
else
{