forked from suyu/suyu
common/host_shader: Load Windows 10 functions dynamically
Workaround old headers and libraries shipped on MinGW.
This commit is contained in:
parent
588ab44470
commit
f332d4a9b5
1 changed files with 88 additions and 29 deletions
|
@ -1,18 +1,10 @@
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#ifdef _WIN32_WINNT
|
|
||||||
#undef _WIN32_WINNT
|
|
||||||
#endif
|
|
||||||
#define _WIN32_WINNT 0x0A00 // Windows 10
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <boost/icl/separate_interval_set.hpp>
|
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <boost/icl/separate_interval_set.hpp>
|
||||||
#pragma comment(lib, "mincore.lib")
|
#include <windows.h>
|
||||||
|
#include "common/dynamic_library.h"
|
||||||
|
|
||||||
#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
|
#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
|
||||||
|
|
||||||
|
@ -40,38 +32,99 @@ constexpr size_t HugePageSize = 0x200000;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
// Manually imported for MinGW compatibility
|
||||||
|
#ifndef MEM_RESERVE_PLACEHOLDER
|
||||||
|
#define MEM_RESERVE_PLACEHOLDER 0x0004000
|
||||||
|
#endif
|
||||||
|
#ifndef MEM_REPLACE_PLACEHOLDER
|
||||||
|
#define MEM_REPLACE_PLACEHOLDER 0x00004000
|
||||||
|
#endif
|
||||||
|
#ifndef MEM_COALESCE_PLACEHOLDERS
|
||||||
|
#define MEM_COALESCE_PLACEHOLDERS 0x00000001
|
||||||
|
#endif
|
||||||
|
#ifndef MEM_PRESERVE_PLACEHOLDER
|
||||||
|
#define MEM_PRESERVE_PLACEHOLDER 0x00000002
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using PFN_CreateFileMapping2 = _Ret_maybenull_ HANDLE(WINAPI*)(
|
||||||
|
_In_ HANDLE File, _In_opt_ SECURITY_ATTRIBUTES* SecurityAttributes, _In_ ULONG DesiredAccess,
|
||||||
|
_In_ ULONG PageProtection, _In_ ULONG AllocationAttributes, _In_ ULONG64 MaximumSize,
|
||||||
|
_In_opt_ PCWSTR Name,
|
||||||
|
_Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
|
||||||
|
_In_ ULONG ParameterCount);
|
||||||
|
|
||||||
|
using PFN_VirtualAlloc2 = _Ret_maybenull_ PVOID(WINAPI*)(
|
||||||
|
_In_opt_ HANDLE Process, _In_opt_ PVOID BaseAddress, _In_ SIZE_T Size,
|
||||||
|
_In_ ULONG AllocationType, _In_ ULONG PageProtection,
|
||||||
|
_Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
|
||||||
|
_In_ ULONG ParameterCount);
|
||||||
|
|
||||||
|
using PFN_MapViewOfFile3 = _Ret_maybenull_ PVOID(WINAPI*)(
|
||||||
|
_In_ HANDLE FileMapping, _In_opt_ HANDLE Process, _In_opt_ PVOID BaseAddress,
|
||||||
|
_In_ ULONG64 Offset, _In_ SIZE_T ViewSize, _In_ ULONG AllocationType, _In_ ULONG PageProtection,
|
||||||
|
_Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
|
||||||
|
_In_ ULONG ParameterCount);
|
||||||
|
|
||||||
|
using PFN_UnmapViewOfFile2 = BOOL(WINAPI*)(_In_ HANDLE Process, _In_ PVOID BaseAddress,
|
||||||
|
_In_ ULONG UnmapFlags);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void GetFuncAddress(Common::DynamicLibrary& dll, const char* name, T& pfn) {
|
||||||
|
if (!dll.GetSymbol(name, &pfn)) {
|
||||||
|
LOG_CRITICAL(HW_Memory, "Failed to load {}", name);
|
||||||
|
throw std::bad_alloc{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class HostMemory::Impl {
|
class HostMemory::Impl {
|
||||||
public:
|
public:
|
||||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||||
: backing_size{backing_size_}, virtual_size{virtual_size_}, process{GetCurrentProcess()} {
|
: backing_size{backing_size_}, virtual_size{virtual_size_}, process{GetCurrentProcess()},
|
||||||
|
kernelbase_dll("Kernelbase") {
|
||||||
|
if (!kernelbase_dll.IsOpen()) {
|
||||||
|
LOG_CRITICAL(HW_Memory, "Failed to load Kernelbase.dll");
|
||||||
|
throw std::bad_alloc{};
|
||||||
|
}
|
||||||
|
GetFuncAddress(kernelbase_dll, "CreateFileMapping2", pfn_CreateFileMapping2);
|
||||||
|
GetFuncAddress(kernelbase_dll, "VirtualAlloc2", pfn_VirtualAlloc2);
|
||||||
|
GetFuncAddress(kernelbase_dll, "MapViewOfFile3", pfn_MapViewOfFile3);
|
||||||
|
GetFuncAddress(kernelbase_dll, "UnmapViewOfFile2", pfn_UnmapViewOfFile2);
|
||||||
|
|
||||||
// Allocate backing file map
|
// Allocate backing file map
|
||||||
backing_handle =
|
backing_handle =
|
||||||
CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
|
pfn_CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
|
||||||
PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
|
PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
|
||||||
if (!backing_handle) {
|
if (!backing_handle) {
|
||||||
|
LOG_CRITICAL(HW_Memory, "Failed to allocate {} MiB of backing memory",
|
||||||
|
backing_size >> 20);
|
||||||
throw std::bad_alloc{};
|
throw std::bad_alloc{};
|
||||||
}
|
}
|
||||||
// Allocate a virtual memory for the backing file map as placeholder
|
// Allocate a virtual memory for the backing file map as placeholder
|
||||||
backing_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, backing_size,
|
backing_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, backing_size,
|
||||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||||
PAGE_NOACCESS, nullptr, 0));
|
PAGE_NOACCESS, nullptr, 0));
|
||||||
if (!backing_base) {
|
if (!backing_base) {
|
||||||
Release();
|
Release();
|
||||||
|
LOG_CRITICAL(HW_Memory, "Failed to reserve {} MiB of virtual memory",
|
||||||
|
backing_size >> 20);
|
||||||
throw std::bad_alloc{};
|
throw std::bad_alloc{};
|
||||||
}
|
}
|
||||||
// Map backing placeholder
|
// Map backing placeholder
|
||||||
void* const ret = MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size,
|
void* const ret = pfn_MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size,
|
||||||
MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
|
MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
|
||||||
if (ret != backing_base) {
|
if (ret != backing_base) {
|
||||||
Release();
|
Release();
|
||||||
|
LOG_CRITICAL(HW_Memory, "Failed to map {} MiB of virtual memory", backing_size >> 20);
|
||||||
throw std::bad_alloc{};
|
throw std::bad_alloc{};
|
||||||
}
|
}
|
||||||
// Allocate virtual address placeholder
|
// Allocate virtual address placeholder
|
||||||
virtual_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, virtual_size,
|
virtual_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, virtual_size,
|
||||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||||
PAGE_NOACCESS, nullptr, 0));
|
PAGE_NOACCESS, nullptr, 0));
|
||||||
if (!virtual_base) {
|
if (!virtual_base) {
|
||||||
Release();
|
Release();
|
||||||
|
LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory",
|
||||||
|
virtual_size >> 30);
|
||||||
throw std::bad_alloc{};
|
throw std::bad_alloc{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,8 +189,8 @@ private:
|
||||||
void Release() {
|
void Release() {
|
||||||
if (!placeholders.empty()) {
|
if (!placeholders.empty()) {
|
||||||
for (const auto& placeholder : placeholders) {
|
for (const auto& placeholder : placeholders) {
|
||||||
if (!UnmapViewOfFile2(process, virtual_base + placeholder.lower(),
|
if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder.lower(),
|
||||||
MEM_PRESERVE_PLACEHOLDER)) {
|
MEM_PRESERVE_PLACEHOLDER)) {
|
||||||
LOG_CRITICAL(HW_Memory, "Failed to unmap virtual memory placeholder");
|
LOG_CRITICAL(HW_Memory, "Failed to unmap virtual memory placeholder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +202,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (backing_base) {
|
if (backing_base) {
|
||||||
if (!UnmapViewOfFile2(process, backing_base, MEM_PRESERVE_PLACEHOLDER)) {
|
if (!pfn_UnmapViewOfFile2(process, backing_base, MEM_PRESERVE_PLACEHOLDER)) {
|
||||||
LOG_CRITICAL(HW_Memory, "Failed to unmap backing memory placeholder");
|
LOG_CRITICAL(HW_Memory, "Failed to unmap backing memory placeholder");
|
||||||
}
|
}
|
||||||
if (!VirtualFreeEx(process, backing_base, 0, MEM_RELEASE)) {
|
if (!VirtualFreeEx(process, backing_base, 0, MEM_RELEASE)) {
|
||||||
|
@ -184,8 +237,8 @@ private:
|
||||||
const bool split_left = unmap_begin > placeholder_begin;
|
const bool split_left = unmap_begin > placeholder_begin;
|
||||||
const bool split_right = unmap_end < placeholder_end;
|
const bool split_right = unmap_end < placeholder_end;
|
||||||
|
|
||||||
if (!UnmapViewOfFile2(process, virtual_base + placeholder_begin,
|
if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder_begin,
|
||||||
MEM_PRESERVE_PLACEHOLDER)) {
|
MEM_PRESERVE_PLACEHOLDER)) {
|
||||||
LOG_CRITICAL(HW_Memory, "Failed to unmap placeholder");
|
LOG_CRITICAL(HW_Memory, "Failed to unmap placeholder");
|
||||||
}
|
}
|
||||||
// If we have to remap memory regions due to partial unmaps, we are in a data race as
|
// If we have to remap memory regions due to partial unmaps, we are in a data race as
|
||||||
|
@ -235,8 +288,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView(size_t virtual_offset, size_t host_offset, size_t length) {
|
void MapView(size_t virtual_offset, size_t host_offset, size_t length) {
|
||||||
if (!MapViewOfFile3(backing_handle, process, virtual_base + virtual_offset, host_offset,
|
if (!pfn_MapViewOfFile3(backing_handle, process, virtual_base + virtual_offset, host_offset,
|
||||||
length, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) {
|
length, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) {
|
||||||
LOG_CRITICAL(HW_Memory, "Failed to map placeholder");
|
LOG_CRITICAL(HW_Memory, "Failed to map placeholder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,6 +332,12 @@ private:
|
||||||
HANDLE process{}; ///< Current process handle
|
HANDLE process{}; ///< Current process handle
|
||||||
HANDLE backing_handle{}; ///< File based backing memory
|
HANDLE backing_handle{}; ///< File based backing memory
|
||||||
|
|
||||||
|
DynamicLibrary kernelbase_dll;
|
||||||
|
PFN_CreateFileMapping2 pfn_CreateFileMapping2{};
|
||||||
|
PFN_VirtualAlloc2 pfn_VirtualAlloc2{};
|
||||||
|
PFN_MapViewOfFile3 pfn_MapViewOfFile3{};
|
||||||
|
PFN_UnmapViewOfFile2 pfn_UnmapViewOfFile2{};
|
||||||
|
|
||||||
std::mutex placeholder_mutex; ///< Mutex for placeholders
|
std::mutex placeholder_mutex; ///< Mutex for placeholders
|
||||||
boost::icl::separate_interval_set<size_t> placeholders; ///< Mapped placeholders
|
boost::icl::separate_interval_set<size_t> placeholders; ///< Mapped placeholders
|
||||||
std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
|
std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
|
||||||
|
|
Loading…
Reference in a new issue