From eafe47fee003c421e122089027a405dab41df81f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 8 Jun 2018 21:15:56 -0300 Subject: [PATCH] Texture/Vertex/Index data cache (#132) * Initial implementation of the texture cache * Cache vertex and index data aswell, some cleanup * Improve handling of the cache by storing cached ranges on a list for each page * Delete old data from the caches automatically, ensure that the cache is cleaned when the mapping/size changes, and some general cleanup --- Memory/AMemory.cs | 63 ++++++++++++++++++++++++++++++++++-- Memory/AMemoryWin32.cs | 73 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 Memory/AMemoryWin32.cs diff --git a/Memory/AMemory.cs b/Memory/AMemory.cs index e7d4656..7e9a358 100644 --- a/Memory/AMemory.cs +++ b/Memory/AMemory.cs @@ -54,7 +54,14 @@ namespace ChocolArm64.Memory ExAddrs = new HashSet(); - Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize + AMemoryMgr.PageSize); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Ram = AMemoryWin32.Allocate((IntPtr)AMemoryMgr.RamSize + AMemoryMgr.PageSize); + } + else + { + Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize + AMemoryMgr.PageSize); + } RamPtr = (byte*)Ram; } @@ -141,6 +148,51 @@ namespace ChocolArm64.Memory } } + public long GetHostPageSize() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return AMemoryMgr.PageSize; + } + + IntPtr MemAddress = new IntPtr(RamPtr); + IntPtr MemSize = new IntPtr(AMemoryMgr.RamSize); + + long PageSize = AMemoryWin32.IsRegionModified(MemAddress, MemSize, Reset: false); + + if (PageSize < 1) + { + throw new InvalidOperationException(); + } + + return PageSize; + } + + public bool IsRegionModified(long Position, long Size) + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return true; + } + + long EndPos = Position + Size; + + if ((ulong)EndPos < (ulong)Position) + { + return false; + } + + if ((ulong)EndPos > AMemoryMgr.RamSize) + { + return false; + } + + IntPtr MemAddress = new IntPtr(RamPtr + Position); + IntPtr MemSize = new IntPtr(Size); + + return AMemoryWin32.IsRegionModified(MemAddress, MemSize, Reset: true) != 0; + } + public sbyte ReadSByte(long Position) { return (sbyte)ReadByte(Position); @@ -640,7 +692,14 @@ namespace ChocolArm64.Memory { if (Ram != IntPtr.Zero) { - Marshal.FreeHGlobal(Ram); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + AMemoryWin32.Free(Ram); + } + else + { + Marshal.FreeHGlobal(Ram); + } Ram = IntPtr.Zero; } diff --git a/Memory/AMemoryWin32.cs b/Memory/AMemoryWin32.cs new file mode 100644 index 0000000..d097dc8 --- /dev/null +++ b/Memory/AMemoryWin32.cs @@ -0,0 +1,73 @@ +using System; +using System.Runtime.InteropServices; + +namespace ChocolArm64.Memory +{ + static class AMemoryWin32 + { + private const int MEM_COMMIT = 0x00001000; + private const int MEM_RESERVE = 0x00002000; + private const int MEM_WRITE_WATCH = 0x00200000; + + private const int PAGE_READWRITE = 0x04; + + private const int MEM_RELEASE = 0x8000; + + private const int WRITE_WATCH_FLAG_RESET = 1; + + [DllImport("kernel32.dll")] + private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, int flAllocationType, int flProtect); + + [DllImport("kernel32.dll")] + private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, int dwFreeType); + + [DllImport("kernel32.dll")] + private unsafe static extern int GetWriteWatch( + int dwFlags, + IntPtr lpBaseAddress, + IntPtr dwRegionSize, + IntPtr[] lpAddresses, + long* lpdwCount, + long* lpdwGranularity); + + public static IntPtr Allocate(IntPtr Size) + { + const int Flags = MEM_COMMIT | MEM_RESERVE | MEM_WRITE_WATCH; + + IntPtr Address = VirtualAlloc(IntPtr.Zero, Size, Flags, PAGE_READWRITE); + + if (Address == IntPtr.Zero) + { + throw new InvalidOperationException(); + } + + return Address; + } + + public static void Free(IntPtr Address) + { + VirtualFree(Address, IntPtr.Zero, MEM_RELEASE); + } + + public unsafe static long IsRegionModified(IntPtr Address, IntPtr Size, bool Reset) + { + IntPtr[] Addresses = new IntPtr[1]; + + long Count = Addresses.Length; + + long Granularity; + + int Flags = Reset ? WRITE_WATCH_FLAG_RESET : 0; + + GetWriteWatch( + Flags, + Address, + Size, + Addresses, + &Count, + &Granularity); + + return Count != 0 ? Granularity : 0; + } + } +} \ No newline at end of file