More flexible memory manager (#307)

* Keep track mapped buffers with fixed offsets

* Started rewriting the memory manager

* Initial support for MapPhysicalMemory and UnmapPhysicalMemory, other tweaks

* MapPhysicalMemory/UnmapPhysicalMemory support, other tweaks

* Rebased

* Optimize the map/unmap physical memory svcs

* Integrate shared font support

* Fix address space reserve alignment

* Some fixes related to gpu memory mapping

* Some cleanup

* Only try uploading const buffers that are really used

* Check if memory region is contiguous

* Rebased

* Add missing count increment on IsRegionModified

* Check for reads/writes outside of the address space, optimize translation with a tail call
This commit is contained in:
gdkchan 2018-08-15 15:59:51 -03:00 committed by GitHub
parent 76d95dee05
commit c393cdf8e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 3289 additions and 1852 deletions

View file

@ -0,0 +1,112 @@
using System.Collections.Generic;
namespace Ryujinx.HLE.Memory
{
class ArenaAllocator
{
private class Region
{
public long Position { get; set; }
public long Size { get; set; }
public Region(long Position, long Size)
{
this.Position = Position;
this.Size = Size;
}
}
private LinkedList<Region> FreeRegions;
public long TotalAvailableSize { get; private set; }
public long TotalUsedSize { get; private set; }
public ArenaAllocator(long ArenaSize)
{
TotalAvailableSize = ArenaSize;
FreeRegions = new LinkedList<Region>();
FreeRegions.AddFirst(new Region(0, ArenaSize));
}
public bool TryAllocate(long Size, out long Position)
{
LinkedListNode<Region> Node = FreeRegions.First;
while (Node != null)
{
Region Rg = Node.Value;
if ((ulong)Rg.Size >= (ulong)Size)
{
Position = Rg.Position;
Rg.Position += Size;
Rg.Size -= Size;
TotalUsedSize += Size;
return true;
}
Node = Node.Next;
}
Position = 0;
return false;
}
public void Free(long Position, long Size)
{
long End = Position + Size;
Region NewRg = new Region(Position, Size);
LinkedListNode<Region> Node = FreeRegions.First;
LinkedListNode<Region> PrevSz = Node;
while (Node != null)
{
LinkedListNode<Region> NextNode = Node.Next;
Region Rg = Node.Value;
long RgEnd = Rg.Position + Rg.Size;
if (Rg.Position == End)
{
NewRg.Size += Rg.Size;
FreeRegions.Remove(Node);
}
else if (RgEnd == Position)
{
NewRg.Position = Rg.Position;
NewRg.Size += Rg.Size;
FreeRegions.Remove(Node);
}
else if ((ulong)Rg.Size < (ulong)NewRg.Size &&
(ulong)Rg.Size > (ulong)PrevSz.Value.Size)
{
PrevSz = Node;
}
Node = NextNode;
}
if ((ulong)PrevSz.Value.Size < (ulong)Size)
{
FreeRegions.AddAfter(PrevSz, NewRg);
}
else
{
FreeRegions.AddFirst(NewRg);
}
TotalUsedSize -= Size;
}
}
}

View file

@ -0,0 +1,130 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.Memory
{
class DeviceMemory : IDisposable
{
public const long RamSize = 4L * 1024 * 1024 * 1024;
public ArenaAllocator Allocator { get; private set; }
public IntPtr RamPointer { get; private set; }
private unsafe byte* RamPtr;
public unsafe DeviceMemory()
{
Allocator = new ArenaAllocator(RamSize);
RamPointer = Marshal.AllocHGlobal(new IntPtr(RamSize));
RamPtr = (byte*)RamPointer;
}
public sbyte ReadSByte(long Position)
{
return (sbyte)ReadByte(Position);
}
public short ReadInt16(long Position)
{
return (short)ReadUInt16(Position);
}
public int ReadInt32(long Position)
{
return (int)ReadUInt32(Position);
}
public long ReadInt64(long Position)
{
return (long)ReadUInt64(Position);
}
public unsafe byte ReadByte(long Position)
{
return *((byte*)(RamPtr + Position));
}
public unsafe ushort ReadUInt16(long Position)
{
return *((ushort*)(RamPtr + Position));
}
public unsafe uint ReadUInt32(long Position)
{
return *((uint*)(RamPtr + Position));
}
public unsafe ulong ReadUInt64(long Position)
{
return *((ulong*)(RamPtr + Position));
}
public void WriteSByte(long Position, sbyte Value)
{
WriteByte(Position, (byte)Value);
}
public void WriteInt16(long Position, short Value)
{
WriteUInt16(Position, (ushort)Value);
}
public void WriteInt32(long Position, int Value)
{
WriteUInt32(Position, (uint)Value);
}
public void WriteInt64(long Position, long Value)
{
WriteUInt64(Position, (ulong)Value);
}
public unsafe void WriteByte(long Position, byte Value)
{
*((byte*)(RamPtr + Position)) = Value;
}
public unsafe void WriteUInt16(long Position, ushort Value)
{
*((ushort*)(RamPtr + Position)) = Value;
}
public unsafe void WriteUInt32(long Position, uint Value)
{
*((uint*)(RamPtr + Position)) = Value;
}
public unsafe void WriteUInt64(long Position, ulong Value)
{
*((ulong*)(RamPtr + Position)) = Value;
}
public void FillWithZeros(long Position, int Size)
{
int Size8 = Size & ~(8 - 1);
for (int Offs = 0; Offs < Size8; Offs += 8)
{
WriteInt64(Position + Offs, 0);
}
for (int Offs = Size8; Offs < (Size - Size8); Offs++)
{
WriteByte(Position + Offs, 0);
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool Disposing)
{
Marshal.FreeHGlobal(RamPointer);
}
}
}