From 0540b8e1ade4a169d67cfa4ef1c1553a743ebe1c Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 28 Jun 2022 17:37:52 +1000 Subject: [PATCH] GS: Switch to placeholders for VM repeat mapping in Qt This is not reliant on having larger gaps in the virtual address space, and should never fail. --- pcsx2/GS/GS.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index aa785b1b2a..e2ec76f6b8 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -960,6 +960,79 @@ void vmfree(void* ptr, size_t size) VirtualFree(ptr, 0, MEM_RELEASE); } +#ifdef PCSX2_CORE +// Safe, placeholder-based mapping for Win10+ and Qt. + +static HANDLE s_fh = NULL; + +void* fifo_alloc(size_t size, size_t repeat) +{ + pxAssertRel(!s_fh, "Has no file mapping"); + + s_fh = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, size, nullptr); + if (s_fh == NULL) + { + Console.Error("Failed to create file mapping of size %zu. WIN API ERROR:%u", size, GetLastError()); + return nullptr; + } + + // Reserve the whole area with repeats. + u8* base = static_cast(VirtualAlloc2( + GetCurrentProcess(), nullptr, repeat * size, + MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, + nullptr, 0)); + if (base) + { + bool okay = true; + for (size_t i = 0; i < repeat; i++) + { + // Everything except the last needs the placeholders split to map over them. Then map the same file over the region. + u8* addr = base + i * size; + if ((i != (repeat - 1) && !VirtualFreeEx(GetCurrentProcess(), addr, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)) || + !MapViewOfFile3(s_fh, GetCurrentProcess(), addr, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) + { + Console.Error("Failed to map repeat %zu of size %zu.", i, size); + okay = false; + + for (size_t j = 0; j < i; j++) + UnmapViewOfFile2(GetCurrentProcess(), addr, MEM_PRESERVE_PLACEHOLDER); + } + } + + if (okay) + { + DbgCon.WriteLn("fifo_alloc(): Mapped %zu repeats of %zu bytes at %p.", repeat, size, base); + return base; + } + + VirtualFreeEx(GetCurrentProcess(), base, 0, MEM_RELEASE); + } + + Console.Error("Failed to reserve VA space of size %zu. WIN API ERROR:%u", size, GetLastError()); + CloseHandle(s_fh); + s_fh = NULL; + return nullptr; +} + +void fifo_free(void* ptr, size_t size, size_t repeat) +{ + pxAssertRel(s_fh, "Has a file mapping"); + + for (size_t i = 0; i < repeat; i++) + { + u8* addr = (u8*)ptr + i * size; + UnmapViewOfFile2(GetCurrentProcess(), addr, MEM_PRESERVE_PLACEHOLDER); + } + + VirtualFreeEx(GetCurrentProcess(), ptr, 0, MEM_RELEASE); + s_fh = NULL; +} + +#else + +// "Best effort" mapping for