summaryrefslogtreecommitdiff
path: root/src/common/host_memory.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-06-08 02:14:12 -0300
committerGravatar Markus Wick2021-06-11 17:27:17 +0200
commitf332d4a9b548e9c7e18c245fd3b90ffc5a94b943 (patch)
tree00e81d38600eed41b55983b40de7e57270168d5d /src/common/host_memory.cpp
parentGPUTHread: Remove async reads from Normal Accuracy. (diff)
downloadyuzu-f332d4a9b548e9c7e18c245fd3b90ffc5a94b943.tar.gz
yuzu-f332d4a9b548e9c7e18c245fd3b90ffc5a94b943.tar.xz
yuzu-f332d4a9b548e9c7e18c245fd3b90ffc5a94b943.zip
common/host_shader: Load Windows 10 functions dynamically
Workaround old headers and libraries shipped on MinGW.
Diffstat (limited to 'src/common/host_memory.cpp')
-rw-r--r--src/common/host_memory.cpp117
1 files changed, 88 insertions, 29 deletions
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index c6d65aab9..9ae384f01 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -1,18 +1,10 @@
1#ifdef _WIN32 1#ifdef _WIN32
2 2
3#ifdef _WIN32_WINNT
4#undef _WIN32_WINNT
5#endif
6#define _WIN32_WINNT 0x0A00 // Windows 10
7
8#include <windows.h>
9
10#include <boost/icl/separate_interval_set.hpp>
11
12#include <iterator> 3#include <iterator>
13#include <unordered_map> 4#include <unordered_map>
14 5#include <boost/icl/separate_interval_set.hpp>
15#pragma comment(lib, "mincore.lib") 6#include <windows.h>
7#include "common/dynamic_library.h"
16 8
17#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv 9#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
18 10
@@ -40,38 +32,99 @@ constexpr size_t HugePageSize = 0x200000;
40 32
41#ifdef _WIN32 33#ifdef _WIN32
42 34
35// Manually imported for MinGW compatibility
36#ifndef MEM_RESERVE_PLACEHOLDER
37#define MEM_RESERVE_PLACEHOLDER 0x0004000
38#endif
39#ifndef MEM_REPLACE_PLACEHOLDER
40#define MEM_REPLACE_PLACEHOLDER 0x00004000
41#endif
42#ifndef MEM_COALESCE_PLACEHOLDERS
43#define MEM_COALESCE_PLACEHOLDERS 0x00000001
44#endif
45#ifndef MEM_PRESERVE_PLACEHOLDER
46#define MEM_PRESERVE_PLACEHOLDER 0x00000002
47#endif
48
49using PFN_CreateFileMapping2 = _Ret_maybenull_ HANDLE(WINAPI*)(
50 _In_ HANDLE File, _In_opt_ SECURITY_ATTRIBUTES* SecurityAttributes, _In_ ULONG DesiredAccess,
51 _In_ ULONG PageProtection, _In_ ULONG AllocationAttributes, _In_ ULONG64 MaximumSize,
52 _In_opt_ PCWSTR Name,
53 _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
54 _In_ ULONG ParameterCount);
55
56using PFN_VirtualAlloc2 = _Ret_maybenull_ PVOID(WINAPI*)(
57 _In_opt_ HANDLE Process, _In_opt_ PVOID BaseAddress, _In_ SIZE_T Size,
58 _In_ ULONG AllocationType, _In_ ULONG PageProtection,
59 _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
60 _In_ ULONG ParameterCount);
61
62using PFN_MapViewOfFile3 = _Ret_maybenull_ PVOID(WINAPI*)(
63 _In_ HANDLE FileMapping, _In_opt_ HANDLE Process, _In_opt_ PVOID BaseAddress,
64 _In_ ULONG64 Offset, _In_ SIZE_T ViewSize, _In_ ULONG AllocationType, _In_ ULONG PageProtection,
65 _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
66 _In_ ULONG ParameterCount);
67
68using PFN_UnmapViewOfFile2 = BOOL(WINAPI*)(_In_ HANDLE Process, _In_ PVOID BaseAddress,
69 _In_ ULONG UnmapFlags);
70
71template <typename T>
72static void GetFuncAddress(Common::DynamicLibrary& dll, const char* name, T& pfn) {
73 if (!dll.GetSymbol(name, &pfn)) {
74 LOG_CRITICAL(HW_Memory, "Failed to load {}", name);
75 throw std::bad_alloc{};
76 }
77}
78
43class HostMemory::Impl { 79class HostMemory::Impl {
44public: 80public:
45 explicit Impl(size_t backing_size_, size_t virtual_size_) 81 explicit Impl(size_t backing_size_, size_t virtual_size_)
46 : backing_size{backing_size_}, virtual_size{virtual_size_}, process{GetCurrentProcess()} { 82 : backing_size{backing_size_}, virtual_size{virtual_size_}, process{GetCurrentProcess()},
83 kernelbase_dll("Kernelbase") {
84 if (!kernelbase_dll.IsOpen()) {
85 LOG_CRITICAL(HW_Memory, "Failed to load Kernelbase.dll");
86 throw std::bad_alloc{};
87 }
88 GetFuncAddress(kernelbase_dll, "CreateFileMapping2", pfn_CreateFileMapping2);
89 GetFuncAddress(kernelbase_dll, "VirtualAlloc2", pfn_VirtualAlloc2);
90 GetFuncAddress(kernelbase_dll, "MapViewOfFile3", pfn_MapViewOfFile3);
91 GetFuncAddress(kernelbase_dll, "UnmapViewOfFile2", pfn_UnmapViewOfFile2);
92
47 // Allocate backing file map 93 // Allocate backing file map
48 backing_handle = 94 backing_handle =
49 CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ, 95 pfn_CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
50 PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0); 96 PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
51 if (!backing_handle) { 97 if (!backing_handle) {
98 LOG_CRITICAL(HW_Memory, "Failed to allocate {} MiB of backing memory",
99 backing_size >> 20);
52 throw std::bad_alloc{}; 100 throw std::bad_alloc{};
53 } 101 }
54 // Allocate a virtual memory for the backing file map as placeholder 102 // Allocate a virtual memory for the backing file map as placeholder
55 backing_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, backing_size, 103 backing_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, backing_size,
56 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, 104 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
57 PAGE_NOACCESS, nullptr, 0)); 105 PAGE_NOACCESS, nullptr, 0));
58 if (!backing_base) { 106 if (!backing_base) {
59 Release(); 107 Release();
108 LOG_CRITICAL(HW_Memory, "Failed to reserve {} MiB of virtual memory",
109 backing_size >> 20);
60 throw std::bad_alloc{}; 110 throw std::bad_alloc{};
61 } 111 }
62 // Map backing placeholder 112 // Map backing placeholder
63 void* const ret = MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size, 113 void* const ret = pfn_MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size,
64 MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0); 114 MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
65 if (ret != backing_base) { 115 if (ret != backing_base) {
66 Release(); 116 Release();
117 LOG_CRITICAL(HW_Memory, "Failed to map {} MiB of virtual memory", backing_size >> 20);
67 throw std::bad_alloc{}; 118 throw std::bad_alloc{};
68 } 119 }
69 // Allocate virtual address placeholder 120 // Allocate virtual address placeholder
70 virtual_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, virtual_size, 121 virtual_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, virtual_size,
71 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, 122 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
72 PAGE_NOACCESS, nullptr, 0)); 123 PAGE_NOACCESS, nullptr, 0));
73 if (!virtual_base) { 124 if (!virtual_base) {
74 Release(); 125 Release();
126 LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory",
127 virtual_size >> 30);
75 throw std::bad_alloc{}; 128 throw std::bad_alloc{};
76 } 129 }
77 } 130 }
@@ -136,8 +189,8 @@ private:
136 void Release() { 189 void Release() {
137 if (!placeholders.empty()) { 190 if (!placeholders.empty()) {
138 for (const auto& placeholder : placeholders) { 191 for (const auto& placeholder : placeholders) {
139 if (!UnmapViewOfFile2(process, virtual_base + placeholder.lower(), 192 if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder.lower(),
140 MEM_PRESERVE_PLACEHOLDER)) { 193 MEM_PRESERVE_PLACEHOLDER)) {
141 LOG_CRITICAL(HW_Memory, "Failed to unmap virtual memory placeholder"); 194 LOG_CRITICAL(HW_Memory, "Failed to unmap virtual memory placeholder");
142 } 195 }
143 } 196 }
@@ -149,7 +202,7 @@ private:
149 } 202 }
150 } 203 }
151 if (backing_base) { 204 if (backing_base) {
152 if (!UnmapViewOfFile2(process, backing_base, MEM_PRESERVE_PLACEHOLDER)) { 205 if (!pfn_UnmapViewOfFile2(process, backing_base, MEM_PRESERVE_PLACEHOLDER)) {
153 LOG_CRITICAL(HW_Memory, "Failed to unmap backing memory placeholder"); 206 LOG_CRITICAL(HW_Memory, "Failed to unmap backing memory placeholder");
154 } 207 }
155 if (!VirtualFreeEx(process, backing_base, 0, MEM_RELEASE)) { 208 if (!VirtualFreeEx(process, backing_base, 0, MEM_RELEASE)) {
@@ -184,8 +237,8 @@ private:
184 const bool split_left = unmap_begin > placeholder_begin; 237 const bool split_left = unmap_begin > placeholder_begin;
185 const bool split_right = unmap_end < placeholder_end; 238 const bool split_right = unmap_end < placeholder_end;
186 239
187 if (!UnmapViewOfFile2(process, virtual_base + placeholder_begin, 240 if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder_begin,
188 MEM_PRESERVE_PLACEHOLDER)) { 241 MEM_PRESERVE_PLACEHOLDER)) {
189 LOG_CRITICAL(HW_Memory, "Failed to unmap placeholder"); 242 LOG_CRITICAL(HW_Memory, "Failed to unmap placeholder");
190 } 243 }
191 // If we have to remap memory regions due to partial unmaps, we are in a data race as 244 // If we have to remap memory regions due to partial unmaps, we are in a data race as
@@ -235,8 +288,8 @@ private:
235 } 288 }
236 289
237 void MapView(size_t virtual_offset, size_t host_offset, size_t length) { 290 void MapView(size_t virtual_offset, size_t host_offset, size_t length) {
238 if (!MapViewOfFile3(backing_handle, process, virtual_base + virtual_offset, host_offset, 291 if (!pfn_MapViewOfFile3(backing_handle, process, virtual_base + virtual_offset, host_offset,
239 length, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) { 292 length, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) {
240 LOG_CRITICAL(HW_Memory, "Failed to map placeholder"); 293 LOG_CRITICAL(HW_Memory, "Failed to map placeholder");
241 } 294 }
242 } 295 }
@@ -279,6 +332,12 @@ private:
279 HANDLE process{}; ///< Current process handle 332 HANDLE process{}; ///< Current process handle
280 HANDLE backing_handle{}; ///< File based backing memory 333 HANDLE backing_handle{}; ///< File based backing memory
281 334
335 DynamicLibrary kernelbase_dll;
336 PFN_CreateFileMapping2 pfn_CreateFileMapping2{};
337 PFN_VirtualAlloc2 pfn_VirtualAlloc2{};
338 PFN_MapViewOfFile3 pfn_MapViewOfFile3{};
339 PFN_UnmapViewOfFile2 pfn_UnmapViewOfFile2{};
340
282 std::mutex placeholder_mutex; ///< Mutex for placeholders 341 std::mutex placeholder_mutex; ///< Mutex for placeholders
283 boost::icl::separate_interval_set<size_t> placeholders; ///< Mapped placeholders 342 boost::icl::separate_interval_set<size_t> placeholders; ///< Mapped placeholders
284 std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset 343 std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset