summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt20
-rw-r--r--src/common/fs/file.cpp10
-rw-r--r--src/common/fs/file.h3
-rw-r--r--src/common/fs/fs.cpp18
-rw-r--r--src/common/fs/path_util.h2
-rw-r--r--src/common/host_memory.cpp538
-rw-r--r--src/common/host_memory.h70
-rw-r--r--src/common/logging/backend.cpp147
-rw-r--r--src/common/logging/backend.h43
-rw-r--r--src/common/logging/filter.cpp132
-rw-r--r--src/common/logging/filter.h12
-rw-r--r--src/common/logging/log.h120
-rw-r--r--src/common/logging/text_formatter.cpp2
-rw-r--r--src/common/logging/types.h142
-rw-r--r--src/common/page_table.h2
-rw-r--r--src/common/settings.cpp10
-rw-r--r--src/common/settings.h6
17 files changed, 975 insertions, 302 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 7a4d9e354..7534eb8f1 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -21,14 +21,14 @@ find_package(Git QUIET)
21 21
22add_custom_command(OUTPUT scm_rev.cpp 22add_custom_command(OUTPUT scm_rev.cpp
23 COMMAND ${CMAKE_COMMAND} 23 COMMAND ${CMAKE_COMMAND}
24 -DSRC_DIR="${CMAKE_SOURCE_DIR}" 24 -DSRC_DIR=${CMAKE_SOURCE_DIR}
25 -DBUILD_REPOSITORY="${BUILD_REPOSITORY}" 25 -DBUILD_REPOSITORY=${BUILD_REPOSITORY}
26 -DTITLE_BAR_FORMAT_IDLE="${TITLE_BAR_FORMAT_IDLE}" 26 -DTITLE_BAR_FORMAT_IDLE=${TITLE_BAR_FORMAT_IDLE}
27 -DTITLE_BAR_FORMAT_RUNNING="${TITLE_BAR_FORMAT_RUNNING}" 27 -DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING}
28 -DBUILD_TAG="${BUILD_TAG}" 28 -DBUILD_TAG=${BUILD_TAG}
29 -DBUILD_ID="${DISPLAY_VERSION}" 29 -DBUILD_ID=${DISPLAY_VERSION}
30 -DGIT_EXECUTABLE="${GIT_EXECUTABLE}" 30 -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
31 -P "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake" 31 -P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
32 DEPENDS 32 DEPENDS
33 # WARNING! It was too much work to try and make a common location for this list, 33 # WARNING! It was too much work to try and make a common location for this list,
34 # so if you need to change it, please update CMakeModules/GenerateSCMRev.cmake as well 34 # so if you need to change it, please update CMakeModules/GenerateSCMRev.cmake as well
@@ -92,6 +92,7 @@ add_custom_command(OUTPUT scm_rev.cpp
92 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h" 92 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
93 # technically we should regenerate if the git version changed, but its not worth the effort imo 93 # technically we should regenerate if the git version changed, but its not worth the effort imo
94 "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake" 94 "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
95 VERBATIM
95) 96)
96 97
97add_library(common STATIC 98add_library(common STATIC
@@ -130,6 +131,8 @@ add_library(common STATIC
130 hash.h 131 hash.h
131 hex_util.cpp 132 hex_util.cpp
132 hex_util.h 133 hex_util.h
134 host_memory.cpp
135 host_memory.h
133 intrusive_red_black_tree.h 136 intrusive_red_black_tree.h
134 logging/backend.cpp 137 logging/backend.cpp
135 logging/backend.h 138 logging/backend.h
@@ -138,6 +141,7 @@ add_library(common STATIC
138 logging/log.h 141 logging/log.h
139 logging/text_formatter.cpp 142 logging/text_formatter.cpp
140 logging/text_formatter.h 143 logging/text_formatter.h
144 logging/types.h
141 lz4_compression.cpp 145 lz4_compression.cpp
142 lz4_compression.h 146 lz4_compression.h
143 math_util.h 147 math_util.h
diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp
index 9f3de1cb0..710e88b39 100644
--- a/src/common/fs/file.cpp
+++ b/src/common/fs/file.cpp
@@ -183,10 +183,6 @@ size_t WriteStringToFile(const std::filesystem::path& path, FileType type,
183 183
184size_t AppendStringToFile(const std::filesystem::path& path, FileType type, 184size_t AppendStringToFile(const std::filesystem::path& path, FileType type,
185 std::string_view string) { 185 std::string_view string) {
186 if (!Exists(path)) {
187 return WriteStringToFile(path, type, string);
188 }
189
190 if (!IsFile(path)) { 186 if (!IsFile(path)) {
191 return 0; 187 return 0;
192 } 188 }
@@ -309,7 +305,11 @@ bool IOFile::Flush() const {
309 305
310 errno = 0; 306 errno = 0;
311 307
312 const auto flush_result = std::fflush(file) == 0; 308#ifdef _WIN32
309 const auto flush_result = std::fflush(file) == 0 && _commit(fileno(file)) == 0;
310#else
311 const auto flush_result = std::fflush(file) == 0 && fsync(fileno(file)) == 0;
312#endif
313 313
314 if (!flush_result) { 314 if (!flush_result) {
315 const auto ec = std::error_code{errno, std::generic_category()}; 315 const auto ec = std::error_code{errno, std::generic_category()};
diff --git a/src/common/fs/file.h b/src/common/fs/file.h
index 50e270c5b..0f10b6003 100644
--- a/src/common/fs/file.h
+++ b/src/common/fs/file.h
@@ -71,7 +71,7 @@ template <typename Path>
71 71
72/** 72/**
73 * Writes a string to a file at path and returns the number of characters successfully written. 73 * Writes a string to a file at path and returns the number of characters successfully written.
74 * If an file already exists at path, its contents will be erased. 74 * If a file already exists at path, its contents will be erased.
75 * If the filesystem object at path is not a file, this function returns 0. 75 * If the filesystem object at path is not a file, this function returns 0.
76 * 76 *
77 * @param path Filesystem path 77 * @param path Filesystem path
@@ -95,7 +95,6 @@ template <typename Path>
95 95
96/** 96/**
97 * Appends a string to a file at path and returns the number of characters successfully written. 97 * Appends a string to a file at path and returns the number of characters successfully written.
98 * If a file does not exist at path, WriteStringToFile is called instead.
99 * If the filesystem object at path is not a file, this function returns 0. 98 * If the filesystem object at path is not a file, this function returns 0.
100 * 99 *
101 * @param path Filesystem path 100 * @param path Filesystem path
diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp
index d492480d9..d3159e908 100644
--- a/src/common/fs/fs.cpp
+++ b/src/common/fs/fs.cpp
@@ -321,7 +321,8 @@ bool RemoveDirContentsRecursively(const fs::path& path) {
321 321
322 std::error_code ec; 322 std::error_code ec;
323 323
324 for (const auto& entry : fs::recursive_directory_iterator(path, ec)) { 324 // TODO (Morph): Replace this with recursive_directory_iterator once it's fixed in MSVC.
325 for (const auto& entry : fs::directory_iterator(path, ec)) {
325 if (ec) { 326 if (ec) {
326 LOG_ERROR(Common_Filesystem, 327 LOG_ERROR(Common_Filesystem,
327 "Failed to completely enumerate the directory at path={}, ec_message={}", 328 "Failed to completely enumerate the directory at path={}, ec_message={}",
@@ -337,6 +338,12 @@ bool RemoveDirContentsRecursively(const fs::path& path) {
337 PathToUTF8String(entry.path()), ec.message()); 338 PathToUTF8String(entry.path()), ec.message());
338 break; 339 break;
339 } 340 }
341
342 // TODO (Morph): Remove this when MSVC fixes recursive_directory_iterator.
343 // recursive_directory_iterator throws an exception despite passing in a std::error_code.
344 if (entry.status().type() == fs::file_type::directory) {
345 return RemoveDirContentsRecursively(entry.path());
346 }
340 } 347 }
341 348
342 if (ec) { 349 if (ec) {
@@ -475,7 +482,8 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
475 482
476 std::error_code ec; 483 std::error_code ec;
477 484
478 for (const auto& entry : fs::recursive_directory_iterator(path, ec)) { 485 // TODO (Morph): Replace this with recursive_directory_iterator once it's fixed in MSVC.
486 for (const auto& entry : fs::directory_iterator(path, ec)) {
479 if (ec) { 487 if (ec) {
480 break; 488 break;
481 } 489 }
@@ -495,6 +503,12 @@ void IterateDirEntriesRecursively(const std::filesystem::path& path,
495 break; 503 break;
496 } 504 }
497 } 505 }
506
507 // TODO (Morph): Remove this when MSVC fixes recursive_directory_iterator.
508 // recursive_directory_iterator throws an exception despite passing in a std::error_code.
509 if (entry.status().type() == fs::file_type::directory) {
510 IterateDirEntriesRecursively(entry.path(), callback, filter);
511 }
498 } 512 }
499 513
500 if (callback_error || ec) { 514 if (callback_error || ec) {
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 14e8c35d7..f956ac9a2 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -209,7 +209,7 @@ void SetYuzuPath(YuzuPath yuzu_path, const std::filesystem::path& new_path);
209 209
210#ifdef _WIN32 210#ifdef _WIN32
211template <typename Path> 211template <typename Path>
212[[nodiscard]] void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) { 212void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
213 if constexpr (IsChar<typename Path::value_type>) { 213 if constexpr (IsChar<typename Path::value_type>) {
214 SetYuzuPath(yuzu_path, ToU8String(new_path)); 214 SetYuzuPath(yuzu_path, ToU8String(new_path));
215 } else { 215 } else {
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
new file mode 100644
index 000000000..8bd70abc7
--- /dev/null
+++ b/src/common/host_memory.cpp
@@ -0,0 +1,538 @@
1#ifdef _WIN32
2
3#include <iterator>
4#include <unordered_map>
5#include <boost/icl/separate_interval_set.hpp>
6#include <windows.h>
7#include "common/dynamic_library.h"
8
9#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
10
11#ifndef _GNU_SOURCE
12#define _GNU_SOURCE
13#endif
14#include <fcntl.h>
15#include <sys/mman.h>
16#include <unistd.h>
17
18#endif // ^^^ Linux ^^^
19
20#include <mutex>
21
22#include "common/alignment.h"
23#include "common/assert.h"
24#include "common/host_memory.h"
25#include "common/logging/log.h"
26#include "common/scope_exit.h"
27
28namespace Common {
29
30constexpr size_t PageAlignment = 0x1000;
31constexpr size_t HugePageSize = 0x200000;
32
33#ifdef _WIN32
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
79class HostMemory::Impl {
80public:
81 explicit Impl(size_t backing_size_, size_t virtual_size_)
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
93 // Allocate backing file map
94 backing_handle =
95 pfn_CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
96 PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
97 if (!backing_handle) {
98 LOG_CRITICAL(HW_Memory, "Failed to allocate {} MiB of backing memory",
99 backing_size >> 20);
100 throw std::bad_alloc{};
101 }
102 // Allocate a virtual memory for the backing file map as placeholder
103 backing_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, backing_size,
104 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
105 PAGE_NOACCESS, nullptr, 0));
106 if (!backing_base) {
107 Release();
108 LOG_CRITICAL(HW_Memory, "Failed to reserve {} MiB of virtual memory",
109 backing_size >> 20);
110 throw std::bad_alloc{};
111 }
112 // Map backing placeholder
113 void* const ret = pfn_MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size,
114 MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
115 if (ret != backing_base) {
116 Release();
117 LOG_CRITICAL(HW_Memory, "Failed to map {} MiB of virtual memory", backing_size >> 20);
118 throw std::bad_alloc{};
119 }
120 // Allocate virtual address placeholder
121 virtual_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, virtual_size,
122 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
123 PAGE_NOACCESS, nullptr, 0));
124 if (!virtual_base) {
125 Release();
126 LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory",
127 virtual_size >> 30);
128 throw std::bad_alloc{};
129 }
130 }
131
132 ~Impl() {
133 Release();
134 }
135
136 void Map(size_t virtual_offset, size_t host_offset, size_t length) {
137 std::unique_lock lock{placeholder_mutex};
138 if (!IsNiechePlaceholder(virtual_offset, length)) {
139 Split(virtual_offset, length);
140 }
141 ASSERT(placeholders.find({virtual_offset, virtual_offset + length}) == placeholders.end());
142 TrackPlaceholder(virtual_offset, host_offset, length);
143
144 MapView(virtual_offset, host_offset, length);
145 }
146
147 void Unmap(size_t virtual_offset, size_t length) {
148 std::lock_guard lock{placeholder_mutex};
149
150 // Unmap until there are no more placeholders
151 while (UnmapOnePlaceholder(virtual_offset, length)) {
152 }
153 }
154
155 void Protect(size_t virtual_offset, size_t length, bool read, bool write) {
156 DWORD new_flags{};
157 if (read && write) {
158 new_flags = PAGE_READWRITE;
159 } else if (read && !write) {
160 new_flags = PAGE_READONLY;
161 } else if (!read && !write) {
162 new_flags = PAGE_NOACCESS;
163 } else {
164 UNIMPLEMENTED_MSG("Protection flag combination read={} write={}", read, write);
165 }
166 const size_t virtual_end = virtual_offset + length;
167
168 std::lock_guard lock{placeholder_mutex};
169 auto [it, end] = placeholders.equal_range({virtual_offset, virtual_end});
170 while (it != end) {
171 const size_t offset = std::max(it->lower(), virtual_offset);
172 const size_t protect_length = std::min(it->upper(), virtual_end) - offset;
173 DWORD old_flags{};
174 if (!VirtualProtect(virtual_base + offset, protect_length, new_flags, &old_flags)) {
175 LOG_CRITICAL(HW_Memory, "Failed to change virtual memory protect rules");
176 }
177 ++it;
178 }
179 }
180
181 const size_t backing_size; ///< Size of the backing memory in bytes
182 const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
183
184 u8* backing_base{};
185 u8* virtual_base{};
186
187private:
188 /// Release all resources in the object
189 void Release() {
190 if (!placeholders.empty()) {
191 for (const auto& placeholder : placeholders) {
192 if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder.lower(),
193 MEM_PRESERVE_PLACEHOLDER)) {
194 LOG_CRITICAL(HW_Memory, "Failed to unmap virtual memory placeholder");
195 }
196 }
197 Coalesce(0, virtual_size);
198 }
199 if (virtual_base) {
200 if (!VirtualFree(virtual_base, 0, MEM_RELEASE)) {
201 LOG_CRITICAL(HW_Memory, "Failed to free virtual memory");
202 }
203 }
204 if (backing_base) {
205 if (!pfn_UnmapViewOfFile2(process, backing_base, MEM_PRESERVE_PLACEHOLDER)) {
206 LOG_CRITICAL(HW_Memory, "Failed to unmap backing memory placeholder");
207 }
208 if (!VirtualFreeEx(process, backing_base, 0, MEM_RELEASE)) {
209 LOG_CRITICAL(HW_Memory, "Failed to free backing memory");
210 }
211 }
212 if (!CloseHandle(backing_handle)) {
213 LOG_CRITICAL(HW_Memory, "Failed to free backing memory file handle");
214 }
215 }
216
217 /// Unmap one placeholder in the given range (partial unmaps are supported)
218 /// Return true when there are no more placeholders to unmap
219 bool UnmapOnePlaceholder(size_t virtual_offset, size_t length) {
220 const auto it = placeholders.find({virtual_offset, virtual_offset + length});
221 const auto begin = placeholders.begin();
222 const auto end = placeholders.end();
223 if (it == end) {
224 return false;
225 }
226 const size_t placeholder_begin = it->lower();
227 const size_t placeholder_end = it->upper();
228 const size_t unmap_begin = std::max(virtual_offset, placeholder_begin);
229 const size_t unmap_end = std::min(virtual_offset + length, placeholder_end);
230 ASSERT(unmap_begin >= placeholder_begin && unmap_begin < placeholder_end);
231 ASSERT(unmap_end <= placeholder_end && unmap_end > placeholder_begin);
232
233 const auto host_pointer_it = placeholder_host_pointers.find(placeholder_begin);
234 ASSERT(host_pointer_it != placeholder_host_pointers.end());
235 const size_t host_offset = host_pointer_it->second;
236
237 const bool split_left = unmap_begin > placeholder_begin;
238 const bool split_right = unmap_end < placeholder_end;
239
240 if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder_begin,
241 MEM_PRESERVE_PLACEHOLDER)) {
242 LOG_CRITICAL(HW_Memory, "Failed to unmap placeholder");
243 }
244 // If we have to remap memory regions due to partial unmaps, we are in a data race as
245 // Windows doesn't support remapping memory without unmapping first. Avoid adding any extra
246 // logic within the panic region described below.
247
248 // Panic region, we are in a data race right now
249 if (split_left || split_right) {
250 Split(unmap_begin, unmap_end - unmap_begin);
251 }
252 if (split_left) {
253 MapView(placeholder_begin, host_offset, unmap_begin - placeholder_begin);
254 }
255 if (split_right) {
256 MapView(unmap_end, host_offset + unmap_end - placeholder_begin,
257 placeholder_end - unmap_end);
258 }
259 // End panic region
260
261 size_t coalesce_begin = unmap_begin;
262 if (!split_left) {
263 // Try to coalesce pages to the left
264 coalesce_begin = it == begin ? 0 : std::prev(it)->upper();
265 if (coalesce_begin != placeholder_begin) {
266 Coalesce(coalesce_begin, unmap_end - coalesce_begin);
267 }
268 }
269 if (!split_right) {
270 // Try to coalesce pages to the right
271 const auto next = std::next(it);
272 const size_t next_begin = next == end ? virtual_size : next->lower();
273 if (placeholder_end != next_begin) {
274 // We can coalesce to the right
275 Coalesce(coalesce_begin, next_begin - coalesce_begin);
276 }
277 }
278 // Remove and reinsert placeholder trackers
279 UntrackPlaceholder(it);
280 if (split_left) {
281 TrackPlaceholder(placeholder_begin, host_offset, unmap_begin - placeholder_begin);
282 }
283 if (split_right) {
284 TrackPlaceholder(unmap_end, host_offset + unmap_end - placeholder_begin,
285 placeholder_end - unmap_end);
286 }
287 return true;
288 }
289
290 void MapView(size_t virtual_offset, size_t host_offset, size_t length) {
291 if (!pfn_MapViewOfFile3(backing_handle, process, virtual_base + virtual_offset, host_offset,
292 length, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) {
293 LOG_CRITICAL(HW_Memory, "Failed to map placeholder");
294 }
295 }
296
297 void Split(size_t virtual_offset, size_t length) {
298 if (!VirtualFreeEx(process, reinterpret_cast<LPVOID>(virtual_base + virtual_offset), length,
299 MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)) {
300 LOG_CRITICAL(HW_Memory, "Failed to split placeholder");
301 }
302 }
303
304 void Coalesce(size_t virtual_offset, size_t length) {
305 if (!VirtualFreeEx(process, reinterpret_cast<LPVOID>(virtual_base + virtual_offset), length,
306 MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) {
307 LOG_CRITICAL(HW_Memory, "Failed to coalesce placeholders");
308 }
309 }
310
311 void TrackPlaceholder(size_t virtual_offset, size_t host_offset, size_t length) {
312 placeholders.insert({virtual_offset, virtual_offset + length});
313 placeholder_host_pointers.emplace(virtual_offset, host_offset);
314 }
315
316 void UntrackPlaceholder(boost::icl::separate_interval_set<size_t>::iterator it) {
317 placeholders.erase(it);
318 placeholder_host_pointers.erase(it->lower());
319 }
320
321 /// Return true when a given memory region is a "nieche" and the placeholders don't have to be
322 /// splitted.
323 bool IsNiechePlaceholder(size_t virtual_offset, size_t length) const {
324 const auto it = placeholders.upper_bound({virtual_offset, virtual_offset + length});
325 if (it != placeholders.end() && it->lower() == virtual_offset + length) {
326 const bool is_root = it == placeholders.begin() && virtual_offset == 0;
327 return is_root || std::prev(it)->upper() == virtual_offset;
328 }
329 return false;
330 }
331
332 HANDLE process{}; ///< Current process handle
333 HANDLE backing_handle{}; ///< File based backing memory
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
341 std::mutex placeholder_mutex; ///< Mutex for placeholders
342 boost::icl::separate_interval_set<size_t> placeholders; ///< Mapped placeholders
343 std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
344};
345
346#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
347
348class HostMemory::Impl {
349public:
350 explicit Impl(size_t backing_size_, size_t virtual_size_)
351 : backing_size{backing_size_}, virtual_size{virtual_size_} {
352 bool good = false;
353 SCOPE_EXIT({
354 if (!good) {
355 Release();
356 }
357 });
358
359 // Backing memory initialization
360 fd = memfd_create("HostMemory", 0);
361 if (fd == -1) {
362 LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno));
363 throw std::bad_alloc{};
364 }
365
366 // Defined to extend the file with zeros
367 int ret = ftruncate(fd, backing_size);
368 if (ret != 0) {
369 LOG_CRITICAL(HW_Memory, "ftruncate failed with {}, are you out-of-memory?",
370 strerror(errno));
371 throw std::bad_alloc{};
372 }
373
374 backing_base = static_cast<u8*>(
375 mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
376 if (backing_base == MAP_FAILED) {
377 LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
378 throw std::bad_alloc{};
379 }
380
381 // Virtual memory initialization
382 virtual_base = static_cast<u8*>(
383 mmap(nullptr, virtual_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
384 if (virtual_base == MAP_FAILED) {
385 LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
386 throw std::bad_alloc{};
387 }
388
389 good = true;
390 }
391
392 ~Impl() {
393 Release();
394 }
395
396 void Map(size_t virtual_offset, size_t host_offset, size_t length) {
397
398 void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE,
399 MAP_SHARED | MAP_FIXED, fd, host_offset);
400 ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
401 }
402
403 void Unmap(size_t virtual_offset, size_t length) {
404 // The method name is wrong. We're still talking about the virtual range.
405 // We don't want to unmap, we want to reserve this memory.
406
407 void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE,
408 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
409 ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
410 }
411
412 void Protect(size_t virtual_offset, size_t length, bool read, bool write) {
413 int flags = 0;
414 if (read) {
415 flags |= PROT_READ;
416 }
417 if (write) {
418 flags |= PROT_WRITE;
419 }
420 int ret = mprotect(virtual_base + virtual_offset, length, flags);
421 ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
422 }
423
424 const size_t backing_size; ///< Size of the backing memory in bytes
425 const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
426
427 u8* backing_base{reinterpret_cast<u8*>(MAP_FAILED)};
428 u8* virtual_base{reinterpret_cast<u8*>(MAP_FAILED)};
429
430private:
431 /// Release all resources in the object
432 void Release() {
433 if (virtual_base != MAP_FAILED) {
434 int ret = munmap(virtual_base, virtual_size);
435 ASSERT_MSG(ret == 0, "munmap failed: {}", strerror(errno));
436 }
437
438 if (backing_base != MAP_FAILED) {
439 int ret = munmap(backing_base, backing_size);
440 ASSERT_MSG(ret == 0, "munmap failed: {}", strerror(errno));
441 }
442
443 if (fd != -1) {
444 int ret = close(fd);
445 ASSERT_MSG(ret == 0, "close failed: {}", strerror(errno));
446 }
447 }
448
449 int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
450};
451
452#else // ^^^ Linux ^^^ vvv Generic vvv
453
454class HostMemory::Impl {
455public:
456 explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) {
457 // This is just a place holder.
458 // Please implement fastmem in a propper way on your platform.
459 throw std::bad_alloc{};
460 }
461
462 void Map(size_t virtual_offset, size_t host_offset, size_t length) {}
463
464 void Unmap(size_t virtual_offset, size_t length) {}
465
466 void Protect(size_t virtual_offset, size_t length, bool read, bool write) {}
467
468 u8* backing_base{nullptr};
469 u8* virtual_base{nullptr};
470};
471
472#endif // ^^^ Generic ^^^
473
474HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
475 : backing_size(backing_size_), virtual_size(virtual_size_) {
476 try {
477 // Try to allocate a fastmem arena.
478 // The implementation will fail with std::bad_alloc on errors.
479 impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment),
480 AlignUp(virtual_size, PageAlignment) +
481 3 * HugePageSize);
482 backing_base = impl->backing_base;
483 virtual_base = impl->virtual_base;
484
485 if (virtual_base) {
486 virtual_base += 2 * HugePageSize - 1;
487 virtual_base -= reinterpret_cast<size_t>(virtual_base) & (HugePageSize - 1);
488 virtual_base_offset = virtual_base - impl->virtual_base;
489 }
490
491 } catch (const std::bad_alloc&) {
492 LOG_CRITICAL(HW_Memory,
493 "Fastmem unavailable, falling back to VirtualBuffer for memory allocation");
494 fallback_buffer = std::make_unique<Common::VirtualBuffer<u8>>(backing_size);
495 backing_base = fallback_buffer->data();
496 virtual_base = nullptr;
497 }
498}
499
500HostMemory::~HostMemory() = default;
501
502HostMemory::HostMemory(HostMemory&&) noexcept = default;
503
504HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
505
506void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length) {
507 ASSERT(virtual_offset % PageAlignment == 0);
508 ASSERT(host_offset % PageAlignment == 0);
509 ASSERT(length % PageAlignment == 0);
510 ASSERT(virtual_offset + length <= virtual_size);
511 ASSERT(host_offset + length <= backing_size);
512 if (length == 0 || !virtual_base || !impl) {
513 return;
514 }
515 impl->Map(virtual_offset + virtual_base_offset, host_offset, length);
516}
517
518void HostMemory::Unmap(size_t virtual_offset, size_t length) {
519 ASSERT(virtual_offset % PageAlignment == 0);
520 ASSERT(length % PageAlignment == 0);
521 ASSERT(virtual_offset + length <= virtual_size);
522 if (length == 0 || !virtual_base || !impl) {
523 return;
524 }
525 impl->Unmap(virtual_offset + virtual_base_offset, length);
526}
527
528void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write) {
529 ASSERT(virtual_offset % PageAlignment == 0);
530 ASSERT(length % PageAlignment == 0);
531 ASSERT(virtual_offset + length <= virtual_size);
532 if (length == 0 || !virtual_base || !impl) {
533 return;
534 }
535 impl->Protect(virtual_offset + virtual_base_offset, length, read, write);
536}
537
538} // namespace Common
diff --git a/src/common/host_memory.h b/src/common/host_memory.h
new file mode 100644
index 000000000..9b8326d0f
--- /dev/null
+++ b/src/common/host_memory.h
@@ -0,0 +1,70 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include "common/common_types.h"
9#include "common/virtual_buffer.h"
10
11namespace Common {
12
13/**
14 * A low level linear memory buffer, which supports multiple mappings
15 * Its purpose is to rebuild a given sparse memory layout, including mirrors.
16 */
17class HostMemory {
18public:
19 explicit HostMemory(size_t backing_size_, size_t virtual_size_);
20 ~HostMemory();
21
22 /**
23 * Copy constructors. They shall return a copy of the buffer without the mappings.
24 * TODO: Implement them with COW if needed.
25 */
26 HostMemory(const HostMemory& other) = delete;
27 HostMemory& operator=(const HostMemory& other) = delete;
28
29 /**
30 * Move constructors. They will move the buffer and the mappings to the new object.
31 */
32 HostMemory(HostMemory&& other) noexcept;
33 HostMemory& operator=(HostMemory&& other) noexcept;
34
35 void Map(size_t virtual_offset, size_t host_offset, size_t length);
36
37 void Unmap(size_t virtual_offset, size_t length);
38
39 void Protect(size_t virtual_offset, size_t length, bool read, bool write);
40
41 [[nodiscard]] u8* BackingBasePointer() noexcept {
42 return backing_base;
43 }
44 [[nodiscard]] const u8* BackingBasePointer() const noexcept {
45 return backing_base;
46 }
47
48 [[nodiscard]] u8* VirtualBasePointer() noexcept {
49 return virtual_base;
50 }
51 [[nodiscard]] const u8* VirtualBasePointer() const noexcept {
52 return virtual_base;
53 }
54
55private:
56 size_t backing_size{};
57 size_t virtual_size{};
58
59 // Low level handler for the platform dependent memory routines
60 class Impl;
61 std::unique_ptr<Impl> impl;
62 u8* backing_base{};
63 u8* virtual_base{};
64 size_t virtual_base_offset{};
65
66 // Fallback if fastmem is not supported on this platform
67 std::unique_ptr<Common::VirtualBuffer<u8>> fallback_buffer;
68};
69
70} // namespace Common
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 6aa8ac960..d5cff400f 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -17,6 +17,7 @@
17#endif 17#endif
18 18
19#include "common/assert.h" 19#include "common/assert.h"
20#include "common/fs/file.h"
20#include "common/fs/fs.h" 21#include "common/fs/fs.h"
21#include "common/logging/backend.h" 22#include "common/logging/backend.h"
22#include "common/logging/log.h" 23#include "common/logging/log.h"
@@ -140,10 +141,14 @@ private:
140 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()}; 141 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
141}; 142};
142 143
144ConsoleBackend::~ConsoleBackend() = default;
145
143void ConsoleBackend::Write(const Entry& entry) { 146void ConsoleBackend::Write(const Entry& entry) {
144 PrintMessage(entry); 147 PrintMessage(entry);
145} 148}
146 149
150ColorConsoleBackend::~ColorConsoleBackend() = default;
151
147void ColorConsoleBackend::Write(const Entry& entry) { 152void ColorConsoleBackend::Write(const Entry& entry) {
148 PrintColoredMessage(entry); 153 PrintColoredMessage(entry);
149} 154}
@@ -157,16 +162,19 @@ FileBackend::FileBackend(const std::filesystem::path& filename) {
157 void(FS::RemoveFile(old_filename)); 162 void(FS::RemoveFile(old_filename));
158 void(FS::RenameFile(filename, old_filename)); 163 void(FS::RenameFile(filename, old_filename));
159 164
160 file = FS::IOFile(filename, FS::FileAccessMode::Write, FS::FileType::TextFile); 165 file =
166 std::make_unique<FS::IOFile>(filename, FS::FileAccessMode::Write, FS::FileType::TextFile);
161} 167}
162 168
169FileBackend::~FileBackend() = default;
170
163void FileBackend::Write(const Entry& entry) { 171void FileBackend::Write(const Entry& entry) {
164 // prevent logs from going over the maximum size (in case its spamming and the user doesn't 172 // prevent logs from going over the maximum size (in case its spamming and the user doesn't
165 // know) 173 // know)
166 constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024; 174 constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024;
167 constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024; 175 constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024;
168 176
169 if (!file.IsOpen()) { 177 if (!file->IsOpen()) {
170 return; 178 return;
171 } 179 }
172 180
@@ -176,147 +184,20 @@ void FileBackend::Write(const Entry& entry) {
176 return; 184 return;
177 } 185 }
178 186
179 bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n')); 187 bytes_written += file->WriteString(FormatLogMessage(entry).append(1, '\n'));
180 if (entry.log_level >= Level::Error) { 188 if (entry.log_level >= Level::Error) {
181 void(file.Flush()); 189 void(file->Flush());
182 } 190 }
183} 191}
184 192
193DebuggerBackend::~DebuggerBackend() = default;
194
185void DebuggerBackend::Write(const Entry& entry) { 195void DebuggerBackend::Write(const Entry& entry) {
186#ifdef _WIN32 196#ifdef _WIN32
187 ::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str()); 197 ::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
188#endif 198#endif
189} 199}
190 200
191/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
192#define ALL_LOG_CLASSES() \
193 CLS(Log) \
194 CLS(Common) \
195 SUB(Common, Filesystem) \
196 SUB(Common, Memory) \
197 CLS(Core) \
198 SUB(Core, ARM) \
199 SUB(Core, Timing) \
200 CLS(Config) \
201 CLS(Debug) \
202 SUB(Debug, Emulated) \
203 SUB(Debug, GPU) \
204 SUB(Debug, Breakpoint) \
205 SUB(Debug, GDBStub) \
206 CLS(Kernel) \
207 SUB(Kernel, SVC) \
208 CLS(Service) \
209 SUB(Service, ACC) \
210 SUB(Service, Audio) \
211 SUB(Service, AM) \
212 SUB(Service, AOC) \
213 SUB(Service, APM) \
214 SUB(Service, ARP) \
215 SUB(Service, BCAT) \
216 SUB(Service, BPC) \
217 SUB(Service, BGTC) \
218 SUB(Service, BTDRV) \
219 SUB(Service, BTM) \
220 SUB(Service, Capture) \
221 SUB(Service, ERPT) \
222 SUB(Service, ETicket) \
223 SUB(Service, EUPLD) \
224 SUB(Service, Fatal) \
225 SUB(Service, FGM) \
226 SUB(Service, Friend) \
227 SUB(Service, FS) \
228 SUB(Service, GRC) \
229 SUB(Service, HID) \
230 SUB(Service, IRS) \
231 SUB(Service, LBL) \
232 SUB(Service, LDN) \
233 SUB(Service, LDR) \
234 SUB(Service, LM) \
235 SUB(Service, Migration) \
236 SUB(Service, Mii) \
237 SUB(Service, MM) \
238 SUB(Service, NCM) \
239 SUB(Service, NFC) \
240 SUB(Service, NFP) \
241 SUB(Service, NIFM) \
242 SUB(Service, NIM) \
243 SUB(Service, NPNS) \
244 SUB(Service, NS) \
245 SUB(Service, NVDRV) \
246 SUB(Service, OLSC) \
247 SUB(Service, PCIE) \
248 SUB(Service, PCTL) \
249 SUB(Service, PCV) \
250 SUB(Service, PM) \
251 SUB(Service, PREPO) \
252 SUB(Service, PSC) \
253 SUB(Service, PSM) \
254 SUB(Service, SET) \
255 SUB(Service, SM) \
256 SUB(Service, SPL) \
257 SUB(Service, SSL) \
258 SUB(Service, TCAP) \
259 SUB(Service, Time) \
260 SUB(Service, USB) \
261 SUB(Service, VI) \
262 SUB(Service, WLAN) \
263 CLS(HW) \
264 SUB(HW, Memory) \
265 SUB(HW, LCD) \
266 SUB(HW, GPU) \
267 SUB(HW, AES) \
268 CLS(IPC) \
269 CLS(Frontend) \
270 CLS(Render) \
271 SUB(Render, Software) \
272 SUB(Render, OpenGL) \
273 SUB(Render, Vulkan) \
274 CLS(Audio) \
275 SUB(Audio, DSP) \
276 SUB(Audio, Sink) \
277 CLS(Input) \
278 CLS(Network) \
279 CLS(Loader) \
280 CLS(CheatEngine) \
281 CLS(Crypto) \
282 CLS(WebService)
283
284// GetClassName is a macro defined by Windows.h, grrr...
285const char* GetLogClassName(Class log_class) {
286 switch (log_class) {
287#define CLS(x) \
288 case Class::x: \
289 return #x;
290#define SUB(x, y) \
291 case Class::x##_##y: \
292 return #x "." #y;
293 ALL_LOG_CLASSES()
294#undef CLS
295#undef SUB
296 case Class::Count:
297 break;
298 }
299 return "Invalid";
300}
301
302const char* GetLevelName(Level log_level) {
303#define LVL(x) \
304 case Level::x: \
305 return #x
306 switch (log_level) {
307 LVL(Trace);
308 LVL(Debug);
309 LVL(Info);
310 LVL(Warning);
311 LVL(Error);
312 LVL(Critical);
313 case Level::Count:
314 break;
315 }
316#undef LVL
317 return "Invalid";
318}
319
320void SetGlobalFilter(const Filter& filter) { 201void SetGlobalFilter(const Filter& filter) {
321 Impl::Instance().SetGlobalFilter(filter); 202 Impl::Instance().SetGlobalFilter(filter);
322} 203}
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index eb629a33f..4b9a910c1 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -1,43 +1,32 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4
4#pragma once 5#pragma once
5 6
6#include <chrono>
7#include <filesystem> 7#include <filesystem>
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include <string_view> 10#include <string_view>
11#include "common/fs/file.h"
12#include "common/logging/filter.h" 11#include "common/logging/filter.h"
13#include "common/logging/log.h" 12#include "common/logging/log.h"
14 13
14namespace Common::FS {
15class IOFile;
16}
17
15namespace Common::Log { 18namespace Common::Log {
16 19
17class Filter; 20class Filter;
18 21
19/** 22/**
20 * A log entry. Log entries are store in a structured format to permit more varied output
21 * formatting on different frontends, as well as facilitating filtering and aggregation.
22 */
23struct Entry {
24 std::chrono::microseconds timestamp;
25 Class log_class{};
26 Level log_level{};
27 const char* filename = nullptr;
28 unsigned int line_num = 0;
29 std::string function;
30 std::string message;
31 bool final_entry = false;
32};
33
34/**
35 * Interface for logging backends. As loggers can be created and removed at runtime, this can be 23 * Interface for logging backends. As loggers can be created and removed at runtime, this can be
36 * used by a frontend for adding a custom logging backend as needed 24 * used by a frontend for adding a custom logging backend as needed
37 */ 25 */
38class Backend { 26class Backend {
39public: 27public:
40 virtual ~Backend() = default; 28 virtual ~Backend() = default;
29
41 virtual void SetFilter(const Filter& new_filter) { 30 virtual void SetFilter(const Filter& new_filter) {
42 filter = new_filter; 31 filter = new_filter;
43 } 32 }
@@ -53,6 +42,8 @@ private:
53 */ 42 */
54class ConsoleBackend : public Backend { 43class ConsoleBackend : public Backend {
55public: 44public:
45 ~ConsoleBackend() override;
46
56 static const char* Name() { 47 static const char* Name() {
57 return "console"; 48 return "console";
58 } 49 }
@@ -67,6 +58,8 @@ public:
67 */ 58 */
68class ColorConsoleBackend : public Backend { 59class ColorConsoleBackend : public Backend {
69public: 60public:
61 ~ColorConsoleBackend() override;
62
70 static const char* Name() { 63 static const char* Name() {
71 return "color_console"; 64 return "color_console";
72 } 65 }
@@ -83,6 +76,7 @@ public:
83class FileBackend : public Backend { 76class FileBackend : public Backend {
84public: 77public:
85 explicit FileBackend(const std::filesystem::path& filename); 78 explicit FileBackend(const std::filesystem::path& filename);
79 ~FileBackend() override;
86 80
87 static const char* Name() { 81 static const char* Name() {
88 return "file"; 82 return "file";
@@ -95,7 +89,7 @@ public:
95 void Write(const Entry& entry) override; 89 void Write(const Entry& entry) override;
96 90
97private: 91private:
98 FS::IOFile file; 92 std::unique_ptr<FS::IOFile> file;
99 std::size_t bytes_written = 0; 93 std::size_t bytes_written = 0;
100}; 94};
101 95
@@ -104,6 +98,8 @@ private:
104 */ 98 */
105class DebuggerBackend : public Backend { 99class DebuggerBackend : public Backend {
106public: 100public:
101 ~DebuggerBackend() override;
102
107 static const char* Name() { 103 static const char* Name() {
108 return "debugger"; 104 return "debugger";
109 } 105 }
@@ -120,17 +116,6 @@ void RemoveBackend(std::string_view backend_name);
120Backend* GetBackend(std::string_view backend_name); 116Backend* GetBackend(std::string_view backend_name);
121 117
122/** 118/**
123 * Returns the name of the passed log class as a C-string. Subclasses are separated by periods
124 * instead of underscores as in the enumeration.
125 */
126const char* GetLogClassName(Class log_class);
127
128/**
129 * Returns the name of the passed log level as a C-string.
130 */
131const char* GetLevelName(Level log_level);
132
133/**
134 * The global filter will prevent any messages from even being processed if they are filtered. Each 119 * The global filter will prevent any messages from even being processed if they are filtered. Each
135 * backend can have a filter, but if the level is lower than the global filter, the backend will 120 * backend can have a filter, but if the level is lower than the global filter, the backend will
136 * never get the message 121 * never get the message
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 20a2dd106..4f2cc29e1 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include "common/logging/backend.h"
7#include "common/logging/filter.h" 6#include "common/logging/filter.h"
8#include "common/string_util.h" 7#include "common/string_util.h"
9 8
@@ -22,7 +21,7 @@ Level GetLevelByName(const It begin, const It end) {
22 21
23template <typename It> 22template <typename It>
24Class GetClassByName(const It begin, const It end) { 23Class GetClassByName(const It begin, const It end) {
25 for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) { 24 for (u8 i = 0; i < static_cast<u8>(Class::Count); ++i) {
26 const char* level_name = GetLogClassName(static_cast<Class>(i)); 25 const char* level_name = GetLogClassName(static_cast<Class>(i));
27 if (Common::ComparePartialString(begin, end, level_name)) { 26 if (Common::ComparePartialString(begin, end, level_name)) {
28 return static_cast<Class>(i); 27 return static_cast<Class>(i);
@@ -62,6 +61,135 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
62} 61}
63} // Anonymous namespace 62} // Anonymous namespace
64 63
64/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
65#define ALL_LOG_CLASSES() \
66 CLS(Log) \
67 CLS(Common) \
68 SUB(Common, Filesystem) \
69 SUB(Common, Memory) \
70 CLS(Core) \
71 SUB(Core, ARM) \
72 SUB(Core, Timing) \
73 CLS(Config) \
74 CLS(Debug) \
75 SUB(Debug, Emulated) \
76 SUB(Debug, GPU) \
77 SUB(Debug, Breakpoint) \
78 SUB(Debug, GDBStub) \
79 CLS(Kernel) \
80 SUB(Kernel, SVC) \
81 CLS(Service) \
82 SUB(Service, ACC) \
83 SUB(Service, Audio) \
84 SUB(Service, AM) \
85 SUB(Service, AOC) \
86 SUB(Service, APM) \
87 SUB(Service, ARP) \
88 SUB(Service, BCAT) \
89 SUB(Service, BPC) \
90 SUB(Service, BGTC) \
91 SUB(Service, BTDRV) \
92 SUB(Service, BTM) \
93 SUB(Service, Capture) \
94 SUB(Service, ERPT) \
95 SUB(Service, ETicket) \
96 SUB(Service, EUPLD) \
97 SUB(Service, Fatal) \
98 SUB(Service, FGM) \
99 SUB(Service, Friend) \
100 SUB(Service, FS) \
101 SUB(Service, GRC) \
102 SUB(Service, HID) \
103 SUB(Service, IRS) \
104 SUB(Service, LBL) \
105 SUB(Service, LDN) \
106 SUB(Service, LDR) \
107 SUB(Service, LM) \
108 SUB(Service, Migration) \
109 SUB(Service, Mii) \
110 SUB(Service, MM) \
111 SUB(Service, NCM) \
112 SUB(Service, NFC) \
113 SUB(Service, NFP) \
114 SUB(Service, NIFM) \
115 SUB(Service, NIM) \
116 SUB(Service, NPNS) \
117 SUB(Service, NS) \
118 SUB(Service, NVDRV) \
119 SUB(Service, OLSC) \
120 SUB(Service, PCIE) \
121 SUB(Service, PCTL) \
122 SUB(Service, PCV) \
123 SUB(Service, PM) \
124 SUB(Service, PREPO) \
125 SUB(Service, PSC) \
126 SUB(Service, PSM) \
127 SUB(Service, SET) \
128 SUB(Service, SM) \
129 SUB(Service, SPL) \
130 SUB(Service, SSL) \
131 SUB(Service, TCAP) \
132 SUB(Service, Time) \
133 SUB(Service, USB) \
134 SUB(Service, VI) \
135 SUB(Service, WLAN) \
136 CLS(HW) \
137 SUB(HW, Memory) \
138 SUB(HW, LCD) \
139 SUB(HW, GPU) \
140 SUB(HW, AES) \
141 CLS(IPC) \
142 CLS(Frontend) \
143 CLS(Render) \
144 SUB(Render, Software) \
145 SUB(Render, OpenGL) \
146 SUB(Render, Vulkan) \
147 CLS(Audio) \
148 SUB(Audio, DSP) \
149 SUB(Audio, Sink) \
150 CLS(Input) \
151 CLS(Network) \
152 CLS(Loader) \
153 CLS(CheatEngine) \
154 CLS(Crypto) \
155 CLS(WebService)
156
157// GetClassName is a macro defined by Windows.h, grrr...
158const char* GetLogClassName(Class log_class) {
159 switch (log_class) {
160#define CLS(x) \
161 case Class::x: \
162 return #x;
163#define SUB(x, y) \
164 case Class::x##_##y: \
165 return #x "." #y;
166 ALL_LOG_CLASSES()
167#undef CLS
168#undef SUB
169 case Class::Count:
170 break;
171 }
172 return "Invalid";
173}
174
175const char* GetLevelName(Level log_level) {
176#define LVL(x) \
177 case Level::x: \
178 return #x
179 switch (log_level) {
180 LVL(Trace);
181 LVL(Debug);
182 LVL(Info);
183 LVL(Warning);
184 LVL(Error);
185 LVL(Critical);
186 case Level::Count:
187 break;
188 }
189#undef LVL
190 return "Invalid";
191}
192
65Filter::Filter(Level default_level) { 193Filter::Filter(Level default_level) {
66 ResetAll(default_level); 194 ResetAll(default_level);
67} 195}
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index f5673a9f6..1a3074e04 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <chrono>
8#include <cstddef> 9#include <cstddef>
9#include <string_view> 10#include <string_view>
10#include "common/logging/log.h" 11#include "common/logging/log.h"
@@ -12,6 +13,17 @@
12namespace Common::Log { 13namespace Common::Log {
13 14
14/** 15/**
16 * Returns the name of the passed log class as a C-string. Subclasses are separated by periods
17 * instead of underscores as in the enumeration.
18 */
19const char* GetLogClassName(Class log_class);
20
21/**
22 * Returns the name of the passed log level as a C-string.
23 */
24const char* GetLevelName(Level log_level);
25
26/**
15 * Implements a log message filter which allows different log classes to have different minimum 27 * Implements a log message filter which allows different log classes to have different minimum
16 * severity levels. The filter can be changed at runtime and can be parsed from a string to allow 28 * severity levels. The filter can be changed at runtime and can be parsed from a string to allow
17 * editing via the interface or loading from a configuration file. 29 * editing via the interface or loading from a configuration file.
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 1f0f8db52..8d43eddc7 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <fmt/format.h> 7#include <fmt/format.h>
8#include "common/common_types.h" 8#include "common/logging/types.h"
9 9
10namespace Common::Log { 10namespace Common::Log {
11 11
@@ -18,124 +18,6 @@ constexpr const char* TrimSourcePath(std::string_view source) {
18 return source.data() + idx; 18 return source.data() + idx;
19} 19}
20 20
21/// Specifies the severity or level of detail of the log message.
22enum class Level : u8 {
23 Trace, ///< Extremely detailed and repetitive debugging information that is likely to
24 ///< pollute logs.
25 Debug, ///< Less detailed debugging information.
26 Info, ///< Status information from important points during execution.
27 Warning, ///< Minor or potential problems found during execution of a task.
28 Error, ///< Major problems found during execution of a task that prevent it from being
29 ///< completed.
30 Critical, ///< Major problems during execution that threaten the stability of the entire
31 ///< application.
32
33 Count ///< Total number of logging levels
34};
35
36typedef u8 ClassType;
37
38/**
39 * Specifies the sub-system that generated the log message.
40 *
41 * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in
42 * backend.cpp.
43 */
44enum class Class : ClassType {
45 Log, ///< Messages about the log system itself
46 Common, ///< Library routines
47 Common_Filesystem, ///< Filesystem interface library
48 Common_Memory, ///< Memory mapping and management functions
49 Core, ///< LLE emulation core
50 Core_ARM, ///< ARM CPU core
51 Core_Timing, ///< CoreTiming functions
52 Config, ///< Emulator configuration (including commandline)
53 Debug, ///< Debugging tools
54 Debug_Emulated, ///< Debug messages from the emulated programs
55 Debug_GPU, ///< GPU debugging tools
56 Debug_Breakpoint, ///< Logging breakpoints and watchpoints
57 Debug_GDBStub, ///< GDB Stub
58 Kernel, ///< The HLE implementation of the CTR kernel
59 Kernel_SVC, ///< Kernel system calls
60 Service, ///< HLE implementation of system services. Each major service
61 ///< should have its own subclass.
62 Service_ACC, ///< The ACC (Accounts) service
63 Service_AM, ///< The AM (Applet manager) service
64 Service_AOC, ///< The AOC (AddOn Content) service
65 Service_APM, ///< The APM (Performance) service
66 Service_ARP, ///< The ARP service
67 Service_Audio, ///< The Audio (Audio control) service
68 Service_BCAT, ///< The BCAT service
69 Service_BGTC, ///< The BGTC (Background Task Controller) service
70 Service_BPC, ///< The BPC service
71 Service_BTDRV, ///< The Bluetooth driver service
72 Service_BTM, ///< The BTM service
73 Service_Capture, ///< The capture service
74 Service_ERPT, ///< The error reporting service
75 Service_ETicket, ///< The ETicket service
76 Service_EUPLD, ///< The error upload service
77 Service_Fatal, ///< The Fatal service
78 Service_FGM, ///< The FGM service
79 Service_Friend, ///< The friend service
80 Service_FS, ///< The FS (Filesystem) service
81 Service_GRC, ///< The game recording service
82 Service_HID, ///< The HID (Human interface device) service
83 Service_IRS, ///< The IRS service
84 Service_LBL, ///< The LBL (LCD backlight) service
85 Service_LDN, ///< The LDN (Local domain network) service
86 Service_LDR, ///< The loader service
87 Service_LM, ///< The LM (Logger) service
88 Service_Migration, ///< The migration service
89 Service_Mii, ///< The Mii service
90 Service_MM, ///< The MM (Multimedia) service
91 Service_NCM, ///< The NCM service
92 Service_NFC, ///< The NFC (Near-field communication) service
93 Service_NFP, ///< The NFP service
94 Service_NIFM, ///< The NIFM (Network interface) service
95 Service_NIM, ///< The NIM service
96 Service_NPNS, ///< The NPNS service
97 Service_NS, ///< The NS services
98 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
99 Service_OLSC, ///< The OLSC service
100 Service_PCIE, ///< The PCIe service
101 Service_PCTL, ///< The PCTL (Parental control) service
102 Service_PCV, ///< The PCV service
103 Service_PM, ///< The PM service
104 Service_PREPO, ///< The PREPO (Play report) service
105 Service_PSC, ///< The PSC service
106 Service_PSM, ///< The PSM service
107 Service_SET, ///< The SET (Settings) service
108 Service_SM, ///< The SM (Service manager) service
109 Service_SPL, ///< The SPL service
110 Service_SSL, ///< The SSL service
111 Service_TCAP, ///< The TCAP service.
112 Service_Time, ///< The time service
113 Service_USB, ///< The USB (Universal Serial Bus) service
114 Service_VI, ///< The VI (Video interface) service
115 Service_WLAN, ///< The WLAN (Wireless local area network) service
116 HW, ///< Low-level hardware emulation
117 HW_Memory, ///< Memory-map and address translation
118 HW_LCD, ///< LCD register emulation
119 HW_GPU, ///< GPU control emulation
120 HW_AES, ///< AES engine emulation
121 IPC, ///< IPC interface
122 Frontend, ///< Emulator UI
123 Render, ///< Emulator video output and hardware acceleration
124 Render_Software, ///< Software renderer backend
125 Render_OpenGL, ///< OpenGL backend
126 Render_Vulkan, ///< Vulkan backend
127 Audio, ///< Audio emulation
128 Audio_DSP, ///< The HLE implementation of the DSP
129 Audio_Sink, ///< Emulator audio output backend
130 Loader, ///< ROM loader
131 CheatEngine, ///< Memory manipulation and engine VM functions
132 Crypto, ///< Cryptographic engine/functions
133 Input, ///< Input emulation
134 Network, ///< Network emulation
135 WebService, ///< Interface to yuzu Web Services
136 Count ///< Total number of logging classes
137};
138
139/// Logs a message to the global logger, using fmt 21/// Logs a message to the global logger, using fmt
140void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, 22void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
141 unsigned int line_num, const char* function, const char* format, 23 unsigned int line_num, const char* function, const char* format,
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
index 80ee2cca1..cfc0d5846 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -11,7 +11,7 @@
11 11
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/common_funcs.h" 13#include "common/common_funcs.h"
14#include "common/logging/backend.h" 14#include "common/logging/filter.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/logging/text_formatter.h" 16#include "common/logging/text_formatter.h"
17#include "common/string_util.h" 17#include "common/string_util.h"
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
new file mode 100644
index 000000000..ee9a1ed84
--- /dev/null
+++ b/src/common/logging/types.h
@@ -0,0 +1,142 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <chrono>
6
7#include "common/common_types.h"
8
9namespace Common::Log {
10
11/// Specifies the severity or level of detail of the log message.
12enum class Level : u8 {
13 Trace, ///< Extremely detailed and repetitive debugging information that is likely to
14 ///< pollute logs.
15 Debug, ///< Less detailed debugging information.
16 Info, ///< Status information from important points during execution.
17 Warning, ///< Minor or potential problems found during execution of a task.
18 Error, ///< Major problems found during execution of a task that prevent it from being
19 ///< completed.
20 Critical, ///< Major problems during execution that threaten the stability of the entire
21 ///< application.
22
23 Count ///< Total number of logging levels
24};
25
26/**
27 * Specifies the sub-system that generated the log message.
28 *
29 * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in
30 * filter.cpp.
31 */
32enum class Class : u8 {
33 Log, ///< Messages about the log system itself
34 Common, ///< Library routines
35 Common_Filesystem, ///< Filesystem interface library
36 Common_Memory, ///< Memory mapping and management functions
37 Core, ///< LLE emulation core
38 Core_ARM, ///< ARM CPU core
39 Core_Timing, ///< CoreTiming functions
40 Config, ///< Emulator configuration (including commandline)
41 Debug, ///< Debugging tools
42 Debug_Emulated, ///< Debug messages from the emulated programs
43 Debug_GPU, ///< GPU debugging tools
44 Debug_Breakpoint, ///< Logging breakpoints and watchpoints
45 Debug_GDBStub, ///< GDB Stub
46 Kernel, ///< The HLE implementation of the CTR kernel
47 Kernel_SVC, ///< Kernel system calls
48 Service, ///< HLE implementation of system services. Each major service
49 ///< should have its own subclass.
50 Service_ACC, ///< The ACC (Accounts) service
51 Service_AM, ///< The AM (Applet manager) service
52 Service_AOC, ///< The AOC (AddOn Content) service
53 Service_APM, ///< The APM (Performance) service
54 Service_ARP, ///< The ARP service
55 Service_Audio, ///< The Audio (Audio control) service
56 Service_BCAT, ///< The BCAT service
57 Service_BGTC, ///< The BGTC (Background Task Controller) service
58 Service_BPC, ///< The BPC service
59 Service_BTDRV, ///< The Bluetooth driver service
60 Service_BTM, ///< The BTM service
61 Service_Capture, ///< The capture service
62 Service_ERPT, ///< The error reporting service
63 Service_ETicket, ///< The ETicket service
64 Service_EUPLD, ///< The error upload service
65 Service_Fatal, ///< The Fatal service
66 Service_FGM, ///< The FGM service
67 Service_Friend, ///< The friend service
68 Service_FS, ///< The FS (Filesystem) service
69 Service_GRC, ///< The game recording service
70 Service_HID, ///< The HID (Human interface device) service
71 Service_IRS, ///< The IRS service
72 Service_LBL, ///< The LBL (LCD backlight) service
73 Service_LDN, ///< The LDN (Local domain network) service
74 Service_LDR, ///< The loader service
75 Service_LM, ///< The LM (Logger) service
76 Service_Migration, ///< The migration service
77 Service_Mii, ///< The Mii service
78 Service_MM, ///< The MM (Multimedia) service
79 Service_NCM, ///< The NCM service
80 Service_NFC, ///< The NFC (Near-field communication) service
81 Service_NFP, ///< The NFP service
82 Service_NIFM, ///< The NIFM (Network interface) service
83 Service_NIM, ///< The NIM service
84 Service_NPNS, ///< The NPNS service
85 Service_NS, ///< The NS services
86 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
87 Service_OLSC, ///< The OLSC service
88 Service_PCIE, ///< The PCIe service
89 Service_PCTL, ///< The PCTL (Parental control) service
90 Service_PCV, ///< The PCV service
91 Service_PM, ///< The PM service
92 Service_PREPO, ///< The PREPO (Play report) service
93 Service_PSC, ///< The PSC service
94 Service_PSM, ///< The PSM service
95 Service_SET, ///< The SET (Settings) service
96 Service_SM, ///< The SM (Service manager) service
97 Service_SPL, ///< The SPL service
98 Service_SSL, ///< The SSL service
99 Service_TCAP, ///< The TCAP service.
100 Service_Time, ///< The time service
101 Service_USB, ///< The USB (Universal Serial Bus) service
102 Service_VI, ///< The VI (Video interface) service
103 Service_WLAN, ///< The WLAN (Wireless local area network) service
104 HW, ///< Low-level hardware emulation
105 HW_Memory, ///< Memory-map and address translation
106 HW_LCD, ///< LCD register emulation
107 HW_GPU, ///< GPU control emulation
108 HW_AES, ///< AES engine emulation
109 IPC, ///< IPC interface
110 Frontend, ///< Emulator UI
111 Render, ///< Emulator video output and hardware acceleration
112 Render_Software, ///< Software renderer backend
113 Render_OpenGL, ///< OpenGL backend
114 Render_Vulkan, ///< Vulkan backend
115 Audio, ///< Audio emulation
116 Audio_DSP, ///< The HLE implementation of the DSP
117 Audio_Sink, ///< Emulator audio output backend
118 Loader, ///< ROM loader
119 CheatEngine, ///< Memory manipulation and engine VM functions
120 Crypto, ///< Cryptographic engine/functions
121 Input, ///< Input emulation
122 Network, ///< Network emulation
123 WebService, ///< Interface to yuzu Web Services
124 Count ///< Total number of logging classes
125};
126
127/**
128 * A log entry. Log entries are store in a structured format to permit more varied output
129 * formatting on different frontends, as well as facilitating filtering and aggregation.
130 */
131struct Entry {
132 std::chrono::microseconds timestamp;
133 Class log_class{};
134 Level log_level{};
135 const char* filename = nullptr;
136 unsigned int line_num = 0;
137 std::string function;
138 std::string message;
139 bool final_entry = false;
140};
141
142} // namespace Common::Log
diff --git a/src/common/page_table.h b/src/common/page_table.h
index e92b66b2b..8267e8b4d 100644
--- a/src/common/page_table.h
+++ b/src/common/page_table.h
@@ -111,6 +111,8 @@ struct PageTable {
111 VirtualBuffer<u64> backing_addr; 111 VirtualBuffer<u64> backing_addr;
112 112
113 size_t current_address_space_width_in_bits; 113 size_t current_address_space_width_in_bits;
114
115 u8* fastmem_arena;
114}; 116};
115 117
116} // namespace Common 118} // namespace Common
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index bcb4e4be1..9ec71eced 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -55,6 +55,7 @@ void LogSettings() {
55 log_setting("Renderer_UseAsynchronousGpuEmulation", 55 log_setting("Renderer_UseAsynchronousGpuEmulation",
56 values.use_asynchronous_gpu_emulation.GetValue()); 56 values.use_asynchronous_gpu_emulation.GetValue());
57 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue()); 57 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue());
58 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
58 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 59 log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
59 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); 60 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue());
60 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 61 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
@@ -90,6 +91,13 @@ bool IsGPULevelHigh() {
90 values.gpu_accuracy.GetValue() == GPUAccuracy::High; 91 values.gpu_accuracy.GetValue() == GPUAccuracy::High;
91} 92}
92 93
94bool IsFastmemEnabled() {
95 if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) {
96 return values.cpuopt_fastmem;
97 }
98 return true;
99}
100
93float Volume() { 101float Volume() {
94 if (values.audio_muted) { 102 if (values.audio_muted) {
95 return 0.0f; 103 return 0.0f;
@@ -115,6 +123,7 @@ void RestoreGlobalState(bool is_powered_on) {
115 values.cpuopt_unsafe_unfuse_fma.SetGlobal(true); 123 values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
116 values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true); 124 values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
117 values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true); 125 values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
126 values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
118 127
119 // Renderer 128 // Renderer
120 values.renderer_backend.SetGlobal(true); 129 values.renderer_backend.SetGlobal(true);
@@ -127,6 +136,7 @@ void RestoreGlobalState(bool is_powered_on) {
127 values.gpu_accuracy.SetGlobal(true); 136 values.gpu_accuracy.SetGlobal(true);
128 values.use_asynchronous_gpu_emulation.SetGlobal(true); 137 values.use_asynchronous_gpu_emulation.SetGlobal(true);
129 values.use_nvdec_emulation.SetGlobal(true); 138 values.use_nvdec_emulation.SetGlobal(true);
139 values.accelerate_astc.SetGlobal(true);
130 values.use_vsync.SetGlobal(true); 140 values.use_vsync.SetGlobal(true);
131 values.use_assembly_shaders.SetGlobal(true); 141 values.use_assembly_shaders.SetGlobal(true);
132 values.use_asynchronous_shaders.SetGlobal(true); 142 values.use_asynchronous_shaders.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 48085b9a9..6198f2d9f 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -125,10 +125,12 @@ struct Values {
125 bool cpuopt_const_prop; 125 bool cpuopt_const_prop;
126 bool cpuopt_misc_ir; 126 bool cpuopt_misc_ir;
127 bool cpuopt_reduce_misalign_checks; 127 bool cpuopt_reduce_misalign_checks;
128 bool cpuopt_fastmem;
128 129
129 Setting<bool> cpuopt_unsafe_unfuse_fma; 130 Setting<bool> cpuopt_unsafe_unfuse_fma;
130 Setting<bool> cpuopt_unsafe_reduce_fp_error; 131 Setting<bool> cpuopt_unsafe_reduce_fp_error;
131 Setting<bool> cpuopt_unsafe_inaccurate_nan; 132 Setting<bool> cpuopt_unsafe_inaccurate_nan;
133 Setting<bool> cpuopt_unsafe_fastmem_check;
132 134
133 // Renderer 135 // Renderer
134 Setting<RendererBackend> renderer_backend; 136 Setting<RendererBackend> renderer_backend;
@@ -145,6 +147,7 @@ struct Values {
145 Setting<GPUAccuracy> gpu_accuracy; 147 Setting<GPUAccuracy> gpu_accuracy;
146 Setting<bool> use_asynchronous_gpu_emulation; 148 Setting<bool> use_asynchronous_gpu_emulation;
147 Setting<bool> use_nvdec_emulation; 149 Setting<bool> use_nvdec_emulation;
150 Setting<bool> accelerate_astc;
148 Setting<bool> use_vsync; 151 Setting<bool> use_vsync;
149 Setting<bool> use_assembly_shaders; 152 Setting<bool> use_assembly_shaders;
150 Setting<bool> use_asynchronous_shaders; 153 Setting<bool> use_asynchronous_shaders;
@@ -216,6 +219,7 @@ struct Values {
216 std::string program_args; 219 std::string program_args;
217 bool dump_exefs; 220 bool dump_exefs;
218 bool dump_nso; 221 bool dump_nso;
222 bool enable_fs_access_log;
219 bool reporting_services; 223 bool reporting_services;
220 bool quest_flag; 224 bool quest_flag;
221 bool disable_macro_jit; 225 bool disable_macro_jit;
@@ -249,6 +253,8 @@ void SetConfiguringGlobal(bool is_global);
249bool IsGPULevelExtreme(); 253bool IsGPULevelExtreme();
250bool IsGPULevelHigh(); 254bool IsGPULevelHigh();
251 255
256bool IsFastmemEnabled();
257
252float Volume(); 258float Volume();
253 259
254std::string GetTimeZoneString(); 260std::string GetTimeZoneString();