aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Memory
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-06-08 21:15:56 -0300
committerGitHub <noreply@github.com>2018-06-08 21:15:56 -0300
commit231fae1a4c97d7588655e9775f37c1dc9bd55fb0 (patch)
tree1c0e7b298ec33d5bf5b6a5693dd69a8c7e0bd23b /ChocolArm64/Memory
parent6fe51f970501fe732276c17ed0dacb564b92a73d (diff)
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
Diffstat (limited to 'ChocolArm64/Memory')
-rw-r--r--ChocolArm64/Memory/AMemory.cs63
-rw-r--r--ChocolArm64/Memory/AMemoryWin32.cs73
2 files changed, 134 insertions, 2 deletions
diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs
index e7d46565..7e9a358a 100644
--- a/ChocolArm64/Memory/AMemory.cs
+++ b/ChocolArm64/Memory/AMemory.cs
@@ -54,7 +54,14 @@ namespace ChocolArm64.Memory
ExAddrs = new HashSet<long>();
- 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/ChocolArm64/Memory/AMemoryWin32.cs b/ChocolArm64/Memory/AMemoryWin32.cs
new file mode 100644
index 00000000..d097dc87
--- /dev/null
+++ b/ChocolArm64/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