Compare commits
7 Commits
qcom-weird
...
reorder-me
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59734dcc04 | ||
|
|
e22756160c | ||
|
|
a33956f738 | ||
|
|
4642e82ca7 | ||
|
|
97054357d2 | ||
|
|
941caf31ce | ||
|
|
c72144abad |
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
@@ -27,7 +27,7 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON)
|
||||
|
||||
# Xbyak (also used by Dynarmic, so needs to be added first)
|
||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||
if (PLATFORM_SUN OR PLATFORM_OPENBSD)
|
||||
if (PLATFORM_SUN OR PLATFORM_OPENBSD OR PLATFORM_NETBSD OR PLATFORM_DRAGONFLY)
|
||||
AddJsonPackage(xbyak_sun)
|
||||
else()
|
||||
AddJsonPackage(xbyak)
|
||||
|
||||
@@ -22,33 +22,21 @@ void AssertFailSoftImpl();
|
||||
#define YUZU_NO_INLINE __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
#define ASSERT(_a_) \
|
||||
([&]() YUZU_NO_INLINE { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
LOG_CRITICAL(Debug, "Assert"); \
|
||||
AssertFailSoftImpl(); \
|
||||
} \
|
||||
}())
|
||||
|
||||
#define ASSERT_MSG(_a_, ...) \
|
||||
([&]() YUZU_NO_INLINE { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
LOG_CRITICAL(Debug, "Assert\n" __VA_ARGS__); \
|
||||
AssertFailSoftImpl(); \
|
||||
LOG_CRITICAL(Debug, __FILE__ ": assert\n" __VA_ARGS__); \
|
||||
AssertFailSoftImpl(); \
|
||||
} \
|
||||
}())
|
||||
|
||||
#define UNREACHABLE() \
|
||||
do { \
|
||||
LOG_CRITICAL(Debug, "Unreachable"); \
|
||||
AssertFatalImpl(); \
|
||||
} while (0)
|
||||
#define ASSERT(_a_) ASSERT_MSG(_a_, "{}", #_a_)
|
||||
|
||||
#define UNREACHABLE_MSG(...) \
|
||||
do { \
|
||||
LOG_CRITICAL(Debug, "Unreachable\n" __VA_ARGS__); \
|
||||
AssertFatalImpl(); \
|
||||
LOG_CRITICAL(Debug, __FILE__ ": unreachable\n" __VA_ARGS__); \
|
||||
AssertFatalImpl(); \
|
||||
} while (0)
|
||||
#define UNREACHABLE() UNREACHABLE_MSG("")
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
|
||||
@@ -68,20 +56,12 @@ void AssertFailSoftImpl();
|
||||
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
|
||||
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
|
||||
|
||||
// If the assert is ignored, execute _b_
|
||||
#define ASSERT_OR_EXECUTE(_a_, _b_) \
|
||||
do { \
|
||||
ASSERT(_a_); \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
_b_ \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// If the assert is ignored, execute _b_
|
||||
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
|
||||
do { \
|
||||
ASSERT_MSG(_a_, __VA_ARGS__); \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
_b_ \
|
||||
} \
|
||||
if (!(_a_)) { _b_ } \
|
||||
} while (0)
|
||||
|
||||
// If the assert is ignored, execute _b_
|
||||
#define ASSERT_OR_EXECUTE(_a_, _b_) ASSERT_OR_EXECUTE_MSG(_a_, _b_, "{}", #_a_)
|
||||
|
||||
@@ -50,8 +50,7 @@ constexpr const char* TrimSourcePath(std::string_view source) {
|
||||
}
|
||||
|
||||
/// @brief Interface for logging backends.
|
||||
class Backend {
|
||||
public:
|
||||
struct Backend {
|
||||
virtual ~Backend() = default;
|
||||
virtual void Write(const Entry& entry) = 0;
|
||||
virtual void EnableForStacktrace() = 0;
|
||||
@@ -59,8 +58,7 @@ public:
|
||||
};
|
||||
|
||||
/// @brief Backend that writes to stderr and with color
|
||||
class ColorConsoleBackend final : public Backend {
|
||||
public:
|
||||
struct ColorConsoleBackend final : public Backend {
|
||||
explicit ColorConsoleBackend() = default;
|
||||
~ColorConsoleBackend() override = default;
|
||||
|
||||
@@ -86,16 +84,15 @@ private:
|
||||
};
|
||||
|
||||
/// @brief Backend that writes to a file passed into the constructor
|
||||
class FileBackend final : public Backend {
|
||||
public:
|
||||
struct FileBackend final : public Backend {
|
||||
explicit FileBackend(const std::filesystem::path& filename) {
|
||||
auto old_filename = filename;
|
||||
old_filename += ".old.txt";
|
||||
|
||||
// Existence checks are done within the functions themselves.
|
||||
// We don't particularly care if these succeed or not.
|
||||
static_cast<void>(FS::RemoveFile(old_filename));
|
||||
static_cast<void>(FS::RenameFile(filename, old_filename));
|
||||
void(FS::RemoveFile(old_filename));
|
||||
void(FS::RenameFile(filename, old_filename));
|
||||
|
||||
file = std::make_unique<FS::IOFile>(filename, FS::FileAccessMode::Write, FS::FileType::TextFile);
|
||||
}
|
||||
@@ -165,51 +162,34 @@ private:
|
||||
bool enabled = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Backend that writes to Visual Studio's output window
|
||||
*/
|
||||
class DebuggerBackend final : public Backend {
|
||||
public:
|
||||
explicit DebuggerBackend() = default;
|
||||
|
||||
~DebuggerBackend() override = default;
|
||||
|
||||
void Write(const Entry& entry) override {
|
||||
#ifdef _WIN32
|
||||
/// @brief Backend that writes to Visual Studio's output window
|
||||
struct DebuggerBackend final : public Backend {
|
||||
explicit DebuggerBackend() = default;
|
||||
~DebuggerBackend() override = default;
|
||||
void Write(const Entry& entry) override {
|
||||
::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void Flush() override {}
|
||||
|
||||
void EnableForStacktrace() override {}
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
/**
|
||||
* Backend that writes to the Android logcat
|
||||
*/
|
||||
class LogcatBackend : public Backend {
|
||||
public:
|
||||
/// @brief Backend that writes to the Android logcat
|
||||
struct LogcatBackend : public Backend {
|
||||
explicit LogcatBackend() = default;
|
||||
|
||||
~LogcatBackend() override = default;
|
||||
|
||||
void Write(const Entry& entry) override {
|
||||
PrintMessageToLogcat(entry);
|
||||
}
|
||||
|
||||
void Flush() override {}
|
||||
|
||||
void EnableForStacktrace() override {}
|
||||
};
|
||||
#endif
|
||||
|
||||
bool initialization_in_progress_suppress_logging = true;
|
||||
|
||||
/**
|
||||
* Static state as a singleton.
|
||||
*/
|
||||
/// @brief Static state as a singleton.
|
||||
class Impl {
|
||||
public:
|
||||
static Impl& Instance() {
|
||||
@@ -228,8 +208,7 @@ public:
|
||||
void(CreateDir(log_dir));
|
||||
Filter filter;
|
||||
filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
||||
instance = std::unique_ptr<Impl, decltype(&Deleter)>(new Impl(log_dir / LOG_FILE, filter),
|
||||
Deleter);
|
||||
instance = std::unique_ptr<Impl, decltype(&Deleter)>(new Impl(log_dir / LOG_FILE, filter), Deleter);
|
||||
initialization_in_progress_suppress_logging = false;
|
||||
}
|
||||
|
||||
@@ -276,13 +255,14 @@ private:
|
||||
Common::SetCurrentThreadName("Logger");
|
||||
Entry entry;
|
||||
const auto write_logs = [this, &entry]() {
|
||||
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
|
||||
ForEachBackend([&entry](Backend& backend) {
|
||||
backend.Write(entry);
|
||||
});
|
||||
};
|
||||
while (!stop_token.stop_requested()) {
|
||||
do {
|
||||
message_queue.PopWait(entry, stop_token);
|
||||
if (entry.filename != nullptr)
|
||||
write_logs();
|
||||
}
|
||||
write_logs();
|
||||
} while (!stop_token.stop_requested());
|
||||
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
|
||||
// case where a system is repeatedly spamming logs even on close.
|
||||
int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100;
|
||||
@@ -315,9 +295,11 @@ private:
|
||||
}
|
||||
|
||||
void ForEachBackend(auto lambda) {
|
||||
lambda(static_cast<Backend&>(debugger_backend));
|
||||
lambda(static_cast<Backend&>(color_console_backend));
|
||||
lambda(static_cast<Backend&>(file_backend));
|
||||
#ifdef _WIN32
|
||||
lambda(static_cast<Backend&>(debugger_backend));
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
lambda(static_cast<Backend&>(lc_backend));
|
||||
#endif
|
||||
@@ -330,9 +312,11 @@ private:
|
||||
static inline std::unique_ptr<Impl, decltype(&Deleter)> instance{nullptr, Deleter};
|
||||
|
||||
Filter filter;
|
||||
DebuggerBackend debugger_backend{};
|
||||
ColorConsoleBackend color_console_backend{};
|
||||
FileBackend file_backend;
|
||||
#ifdef _WIN32
|
||||
DebuggerBackend debugger_backend{};
|
||||
#endif
|
||||
#ifdef ANDROID
|
||||
LogcatBackend lc_backend{};
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -25,15 +28,21 @@ static s64 WindowsQueryPerformanceCounter() {
|
||||
}
|
||||
|
||||
static s64 GetSystemTimeNS() {
|
||||
// GetSystemTimePreciseAsFileTime returns the file time in 100ns units.
|
||||
static constexpr s64 Multiplier = 100;
|
||||
// Convert Windows epoch to Unix epoch.
|
||||
static constexpr s64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL;
|
||||
|
||||
FILETIME filetime;
|
||||
GetSystemTimePreciseAsFileTime(&filetime);
|
||||
return Multiplier * ((static_cast<s64>(filetime.dwHighDateTime) << 32) +
|
||||
static_cast<s64>(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch);
|
||||
static auto pf = (decltype(&GetSystemTimePreciseAsFileTime))(void*)GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")), "GetSystemTimePreciseAsFileTime"); // Windows 8+
|
||||
if (pf) {
|
||||
// GetSystemTimePreciseAsFileTime returns the file time in 100ns units.
|
||||
constexpr s64 Multiplier = 100;
|
||||
// Convert Windows epoch to Unix epoch.
|
||||
constexpr s64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL;
|
||||
FILETIME filetime;
|
||||
pf(&filetime);
|
||||
return Multiplier * ((s64(filetime.dwHighDateTime) << 32) + s64(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch);
|
||||
} else {
|
||||
// Only Windows XP and below error out here
|
||||
LARGE_INTEGER ticks;
|
||||
QueryPerformanceCounter(&ticks);
|
||||
return ticks.QuadPart;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -81,10 +81,9 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
||||
|
||||
// Sets the debugger-visible name of the current thread.
|
||||
void SetCurrentThreadName(const char* name) {
|
||||
if (auto pf = (decltype(&SetThreadDescription))(void*)GetProcAddress(GetModuleHandle(TEXT("KernelBase.dll")), "SetThreadDescription"); pf)
|
||||
static auto pf = (decltype(&SetThreadDescription))(void*)GetProcAddress(GetModuleHandle(TEXT("KernelBase.dll")), "SetThreadDescription");
|
||||
if (pf)
|
||||
pf(GetCurrentThread(), UTF8ToUTF16W(name).data()); // Windows 10+
|
||||
else
|
||||
; // No-op
|
||||
}
|
||||
|
||||
#else // !MSVC_VER, so must be POSIX threads
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -62,14 +65,15 @@ TimerResolution GetTimerResolution() {
|
||||
|
||||
void SetHighQoS() {
|
||||
// https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
|
||||
PROCESS_POWER_THROTTLING_STATE PowerThrottling{
|
||||
.Version{PROCESS_POWER_THROTTLING_CURRENT_VERSION},
|
||||
.ControlMask{PROCESS_POWER_THROTTLING_EXECUTION_SPEED |
|
||||
PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION},
|
||||
.StateMask{},
|
||||
};
|
||||
SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &PowerThrottling,
|
||||
sizeof(PROCESS_POWER_THROTTLING_STATE));
|
||||
static auto pf = (decltype(&SetProcessInformation))(void*)GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")), "SetProcessInformation");
|
||||
if (pf) {
|
||||
PROCESS_POWER_THROTTLING_STATE PowerThrottling{
|
||||
.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION,
|
||||
.ControlMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION,
|
||||
.StateMask = 0,
|
||||
};
|
||||
pf(GetCurrentProcess(), ProcessPowerThrottling, &PowerThrottling, sizeof(PROCESS_POWER_THROTTLING_STATE)); // Windows 7+
|
||||
}
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
@@ -211,7 +211,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* pa
|
||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||
|
||||
// Code cache size
|
||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__)
|
||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
config.code_cache_size = std::uint32_t(128_MiB);
|
||||
#else
|
||||
config.code_cache_size = std::uint32_t(512_MiB);
|
||||
@@ -295,7 +295,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* pa
|
||||
// Curated optimizations
|
||||
case Settings::CpuAccuracy::Auto:
|
||||
config.unsafe_optimizations = true;
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__)
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
config.fastmem_pointer = std::nullopt;
|
||||
config.fastmem_exclusive_access = false;
|
||||
#endif
|
||||
|
||||
@@ -270,7 +270,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||
|
||||
// Code cache size
|
||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__)
|
||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
config.code_cache_size = std::uint32_t(128_MiB);
|
||||
#else
|
||||
config.code_cache_size = std::uint32_t(512_MiB);
|
||||
|
||||
@@ -339,14 +339,10 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
|
||||
};
|
||||
m_system_settings.eula_versions[0] = eula_version;
|
||||
m_system_settings.eula_version_count = 1;
|
||||
|
||||
m_save_thread =
|
||||
std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); });
|
||||
}
|
||||
|
||||
ISystemSettingsServer::~ISystemSettingsServer() {
|
||||
SetSaveNeeded();
|
||||
m_save_thread.request_stop();
|
||||
}
|
||||
|
||||
bool ISystemSettingsServer::LoadSettingsFile(std::filesystem::path& path, auto&& default_func) {
|
||||
@@ -1393,20 +1389,9 @@ void ISystemSettingsServer::StoreSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
void ISystemSettingsServer::StoreSettingsThreadFunc(std::stop_token stop_token) {
|
||||
Common::SetCurrentThreadName("SettingsStore");
|
||||
|
||||
while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) {
|
||||
std::scoped_lock l{m_save_needed_mutex};
|
||||
if (!std::exchange(m_save_needed, false))
|
||||
continue;
|
||||
StoreSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void ISystemSettingsServer::SetSaveNeeded() {
|
||||
std::scoped_lock l{m_save_needed_mutex};
|
||||
m_save_needed = true;
|
||||
StoreSettings();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetSettingsItemValueImpl(std::span<u8> out_value, u64& out_size,
|
||||
|
||||
@@ -167,7 +167,6 @@ private:
|
||||
bool StoreSettingsFile(std::filesystem::path& path, auto& settings);
|
||||
void SetupSettings();
|
||||
void StoreSettings();
|
||||
void StoreSettingsThreadFunc(std::stop_token stop_token);
|
||||
void SetSaveNeeded();
|
||||
|
||||
Core::System& m_system;
|
||||
@@ -176,7 +175,6 @@ private:
|
||||
DeviceSettings m_device_settings{};
|
||||
ApplnSettings m_appln_settings{};
|
||||
std::mutex m_save_needed_mutex;
|
||||
std::jthread m_save_thread;
|
||||
bool m_save_needed{false};
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,12 @@ endif()
|
||||
# Dynarmic project options
|
||||
option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON)
|
||||
|
||||
option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${PLATFORM_OPENBSD})
|
||||
if (PLATFORM_OPENBSD OR PLATFORM_DRAGONFLY OR PLATFORM_NETBSD)
|
||||
set(REQUIRE_WX ON)
|
||||
else()
|
||||
set(REQUIRE_WX OFF)
|
||||
endif()
|
||||
option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${REQUIRE_WX})
|
||||
|
||||
option(DYNARMIC_IGNORE_ASSERTS "Ignore asserts" OFF)
|
||||
option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF)
|
||||
|
||||
@@ -87,9 +87,11 @@ A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig conf, A32::Jit* jit_in
|
||||
code.PreludeComplete();
|
||||
ClearFastDispatchTable();
|
||||
|
||||
exception_handler.SetFastmemCallback([this](u64 rip_) {
|
||||
return FastmemCallback(rip_);
|
||||
});
|
||||
if (conf.fastmem_pointer.has_value()) {
|
||||
exception_handler.SetFastmemCallback([this](u64 rip_) {
|
||||
return FastmemCallback(rip_);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
A32EmitX64::~A32EmitX64() = default;
|
||||
|
||||
@@ -61,9 +61,11 @@ A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_in
|
||||
code.PreludeComplete();
|
||||
ClearFastDispatchTable();
|
||||
|
||||
exception_handler.SetFastmemCallback([this](u64 rip_) {
|
||||
return FastmemCallback(rip_);
|
||||
});
|
||||
if (conf.fastmem_pointer.has_value()) {
|
||||
exception_handler.SetFastmemCallback([this](u64 rip_) {
|
||||
return FastmemCallback(rip_);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
A64EmitX64::~A64EmitX64() = default;
|
||||
|
||||
@@ -87,18 +87,24 @@ public:
|
||||
// Waste a page to store the size
|
||||
size += DYNARMIC_PAGE_SIZE;
|
||||
|
||||
# if defined(MAP_ANONYMOUS)
|
||||
int mode = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
# elif defined(MAP_ANON)
|
||||
int mode = MAP_PRIVATE | MAP_ANON;
|
||||
# else
|
||||
# error "not supported"
|
||||
# endif
|
||||
# ifdef MAP_JIT
|
||||
int mode = MAP_PRIVATE;
|
||||
#if defined(MAP_ANONYMOUS)
|
||||
mode |= MAP_ANONYMOUS;
|
||||
#elif defined(MAP_ANON)
|
||||
mode |= MAP_ANON;
|
||||
#else
|
||||
# error "not supported"
|
||||
#endif
|
||||
#ifdef MAP_JIT
|
||||
mode |= MAP_JIT;
|
||||
# endif
|
||||
|
||||
void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, mode, -1, 0);
|
||||
#endif
|
||||
int prot = PROT_READ | PROT_WRITE;
|
||||
#ifdef PROT_MPROTECT
|
||||
// https://man.netbsd.org/mprotect.2 specifies that an mprotect() that is LESS
|
||||
// restrictive than the original mapping MUST fail
|
||||
prot |= PROT_MPROTECT(PROT_READ) | PROT_MPROTECT(PROT_WRITE) | PROT_MPROTECT(PROT_EXEC);
|
||||
#endif
|
||||
void* p = mmap(nullptr, size, prot, mode, -1, 0);
|
||||
if (p == MAP_FAILED) {
|
||||
using Xbyak::Error;
|
||||
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <optional>
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
#include "dynarmic/backend/x64/abi.h"
|
||||
@@ -42,43 +42,46 @@ void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct SpinLockImpl {
|
||||
void Initialize();
|
||||
|
||||
void Initialize() noexcept;
|
||||
static void GlobalInitialize() noexcept;
|
||||
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode);
|
||||
|
||||
void (*lock)(volatile int*);
|
||||
void (*unlock)(volatile int*);
|
||||
void (*lock)(volatile int*) = nullptr;
|
||||
void (*unlock)(volatile int*) = nullptr;
|
||||
};
|
||||
|
||||
std::once_flag flag;
|
||||
SpinLockImpl impl;
|
||||
|
||||
void SpinLockImpl::Initialize() {
|
||||
const Xbyak::Reg64 ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1);
|
||||
/// @brief Bear in mind that initializing the variable as-is on ctor time will trigger bugs
|
||||
/// because some OSes do not prepare mprotect() properly at static ctor time
|
||||
/// We can't really do anything about it, so just live with this fact
|
||||
std::optional<SpinLockImpl> impl;
|
||||
|
||||
void SpinLockImpl::Initialize() noexcept {
|
||||
Xbyak::Reg64 const ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1);
|
||||
code.align();
|
||||
lock = code.getCurr<void (*)(volatile int*)>();
|
||||
EmitSpinLockLock(code, ABI_PARAM1, code.eax);
|
||||
code.ret();
|
||||
|
||||
code.align();
|
||||
unlock = code.getCurr<void (*)(volatile int*)>();
|
||||
EmitSpinLockUnlock(code, ABI_PARAM1, code.eax);
|
||||
code.ret();
|
||||
}
|
||||
|
||||
void SpinLockImpl::GlobalInitialize() noexcept {
|
||||
impl.emplace();
|
||||
impl->Initialize();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SpinLock::Lock() noexcept {
|
||||
std::call_once(flag, &SpinLockImpl::Initialize, impl);
|
||||
impl.lock(&storage);
|
||||
std::call_once(flag, &SpinLockImpl::GlobalInitialize);
|
||||
impl->lock(&storage);
|
||||
}
|
||||
|
||||
void SpinLock::Unlock() noexcept {
|
||||
std::call_once(flag, &SpinLockImpl::Initialize, impl);
|
||||
impl.unlock(&storage);
|
||||
std::call_once(flag, &SpinLockImpl::GlobalInitialize);
|
||||
impl->unlock(&storage);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic
|
||||
|
||||
@@ -274,18 +274,10 @@ void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target)
|
||||
const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
|
||||
const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id);
|
||||
const auto target_file = shader_cache_folder_path / target_file_name;
|
||||
|
||||
if (!Common::FS::Exists(target_file)) {
|
||||
QtCommon::Frontend::Warning(tr("Error Removing Transferable Shader Cache"),
|
||||
tr("A shader cache for this title does not exist."));
|
||||
return;
|
||||
}
|
||||
if (Common::FS::RemoveFile(target_file)) {
|
||||
QtCommon::Frontend::Information(tr("Successfully Removed"),
|
||||
tr("Successfully removed the transferable shader cache."));
|
||||
if (!Common::FS::Exists(target_file) || Common::FS::RemoveFile(target_file)) {
|
||||
QtCommon::Frontend::Information(tr("Successfully Removed"), tr("Successfully removed the shader cache."));
|
||||
} else {
|
||||
QtCommon::Frontend::Warning(tr("Error Removing Transferable Shader Cache"),
|
||||
tr("Failed to remove the transferable shader cache."));
|
||||
QtCommon::Frontend::Warning(tr("Error Removing Shader Cache"), tr("Failed to remove the shader cache."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,10 +44,20 @@ std::bitset<32> PersistentCallerSavedRegs() {
|
||||
return PERSISTENT_REGISTERS & Common::X64::ABI_ALL_CALLER_SAVED;
|
||||
}
|
||||
|
||||
/// @brief Must enforce W^X constraints, as we yet don't havea global "NO_EXECUTE" support flag
|
||||
/// the speed loss is minimal, and in fact may be negligible, however for your peace of mind
|
||||
/// I simply included known OSes whom had W^X issues
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||
static const auto default_cg_mode = Xbyak::DontSetProtectRWE;
|
||||
#else
|
||||
static const auto default_cg_mode = nullptr; //Allow RWE
|
||||
#endif
|
||||
|
||||
class MacroJITx64Impl final : public Xbyak::CodeGenerator, public CachedMacro {
|
||||
public:
|
||||
explicit MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_)
|
||||
: CodeGenerator{MAX_CODE_SIZE}, code{code_}, maxwell3d{maxwell3d_} {
|
||||
: Xbyak::CodeGenerator(MAX_CODE_SIZE, default_cg_mode)
|
||||
, code{code_}, maxwell3d{maxwell3d_} {
|
||||
Compile();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "yuzu/configuration/configure_per_game.h"
|
||||
#include "yuzu/configuration/configure_per_game_addons.h"
|
||||
#include "yuzu/configuration/configure_system.h"
|
||||
#include "yuzu/configuration/configure_network.h"
|
||||
#include "qt_common/config/uisettings.h"
|
||||
#include "yuzu/util/util.h"
|
||||
#include "yuzu/vk_device_info.h"
|
||||
@@ -69,6 +70,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
|
||||
input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
|
||||
linux_tab = std::make_unique<ConfigureLinuxTab>(system_, tab_group, *builder, this);
|
||||
system_tab = std::make_unique<ConfigureSystem>(system_, tab_group, *builder, this);
|
||||
network_tab = std::make_unique<ConfigureNetwork>(system_, this);
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
@@ -80,6 +82,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
|
||||
ui->tabWidget->addTab(graphics_extensions_tab.get(), tr("GPU Extensions"));
|
||||
ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));
|
||||
ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles"));
|
||||
ui->tabWidget->addTab(network_tab.get(), tr("Network"));
|
||||
|
||||
// Only show Linux tab on Unix
|
||||
linux_tab->setVisible(false);
|
||||
@@ -113,6 +116,7 @@ void ConfigurePerGame::ApplyConfiguration() {
|
||||
}
|
||||
addons_tab->ApplyConfiguration();
|
||||
input_tab->ApplyConfiguration();
|
||||
network_tab->ApplyConfiguration();
|
||||
|
||||
if (Settings::IsDockedMode() && Settings::values.players.GetValue()[0].controller_type ==
|
||||
Settings::ControllerType::Handheld) {
|
||||
|
||||
@@ -38,6 +38,7 @@ class ConfigureGraphicsExtensions;
|
||||
class ConfigureInputPerGame;
|
||||
class ConfigureLinuxTab;
|
||||
class ConfigureSystem;
|
||||
class ConfigureNetwork;
|
||||
|
||||
class QGraphicsScene;
|
||||
class QStandardItem;
|
||||
@@ -93,4 +94,5 @@ private:
|
||||
std::unique_ptr<ConfigureInputPerGame> input_tab;
|
||||
std::unique_ptr<ConfigureLinuxTab> linux_tab;
|
||||
std::unique_ptr<ConfigureSystem> system_tab;
|
||||
std::unique_ptr<ConfigureNetwork> network_tab;
|
||||
};
|
||||
|
||||
@@ -545,44 +545,40 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
// TODO(crueter): Refactor this and make it less bad
|
||||
QAction* favorite = context_menu.addAction(tr("Favorite"));
|
||||
context_menu.addSeparator();
|
||||
QAction* start_game = context_menu.addAction(tr("Start Game"));
|
||||
QAction* start_game_global =
|
||||
context_menu.addAction(tr("Start Game without Custom Configuration"));
|
||||
QAction* start_game = context_menu.addAction(tr("Start"));
|
||||
QAction* start_game_global = context_menu.addAction(tr("Start with Global Settings"));
|
||||
context_menu.addSeparator();
|
||||
QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
|
||||
QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location"));
|
||||
QAction* open_transferable_shader_cache =
|
||||
context_menu.addAction(tr("Open Transferable Pipeline Cache"));
|
||||
QAction* ryujinx = context_menu.addAction(tr("Link to Ryujinx"));
|
||||
QAction* properties = context_menu.addAction(tr("Configure Game"));
|
||||
context_menu.addSeparator();
|
||||
QMenu* remove_menu = context_menu.addMenu(tr("Remove"));
|
||||
QAction* remove_update = remove_menu->addAction(tr("Remove Installed Update"));
|
||||
QAction* remove_dlc = remove_menu->addAction(tr("Remove All Installed DLC"));
|
||||
QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration"));
|
||||
QAction* remove_cache_storage = remove_menu->addAction(tr("Remove Cache Storage"));
|
||||
QAction* remove_gl_shader_cache = remove_menu->addAction(tr("Remove OpenGL Pipeline Cache"));
|
||||
QAction* remove_vk_shader_cache = remove_menu->addAction(tr("Remove Vulkan Pipeline Cache"));
|
||||
remove_menu->addSeparator();
|
||||
QAction* remove_shader_cache = remove_menu->addAction(tr("Remove All Pipeline Caches"));
|
||||
QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents"));
|
||||
QMenu* play_time_menu = context_menu.addMenu(tr("Manage Play Time"));
|
||||
QAction* set_play_time = play_time_menu->addAction(tr("Edit Play Time Data"));
|
||||
QAction* remove_play_time_data = play_time_menu->addAction(tr("Remove Play Time Data"));
|
||||
QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS"));
|
||||
QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS"));
|
||||
QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC"));
|
||||
QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
|
||||
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
|
||||
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
|
||||
QMenu* shader_cache_menu = context_menu.addMenu(tr("Shader Cache"));
|
||||
QAction* open_transferable_shader_cache = shader_cache_menu->addAction(tr("Open Pipeline Cache"));
|
||||
QAction* remove_shader_cache = shader_cache_menu->addAction(tr("Remove All Pipeline Caches"));
|
||||
QAction* remove_gl_shader_cache = shader_cache_menu->addAction(tr("Remove OpenGL Pipeline Cache"));
|
||||
QAction* remove_vk_shader_cache = shader_cache_menu->addAction(tr("Remove Vulkan Pipeline Cache"));
|
||||
QMenu* storage_menu = context_menu.addMenu(tr("Storage"));
|
||||
QAction* remove_all_content = storage_menu->addAction(tr("Remove All Installed Contents"));
|
||||
QAction* remove_cache_storage = storage_menu->addAction(tr("Remove Cache Storage"));
|
||||
QAction* remove_update = storage_menu->addAction(tr("Remove Installed Update"));
|
||||
QAction* remove_dlc = storage_menu->addAction(tr("Remove All Installed DLC"));
|
||||
QAction* remove_custom_config = storage_menu->addAction(tr("Remove Custom Settings"));
|
||||
QAction* dump_romfs = storage_menu->addAction(tr("Dump RomFS"));
|
||||
QAction* dump_romfs_sdmc = storage_menu->addAction(tr("Dump RomFS to SDMC"));
|
||||
QAction* ryujinx = context_menu.addAction(tr("Link to Ryujinx"));
|
||||
QMenu* play_time_menu = context_menu.addMenu(tr("Play Time"));
|
||||
QAction* set_play_time = play_time_menu->addAction(tr("Edit"));
|
||||
QAction* remove_play_time_data = play_time_menu->addAction(tr("Clear"));
|
||||
// TODO: Implement shortcut creation for macOS
|
||||
#if !defined(__APPLE__)
|
||||
QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut"));
|
||||
QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop"));
|
||||
QAction* create_applications_menu_shortcut =
|
||||
shortcut_menu->addAction(tr("Add to Applications Menu"));
|
||||
QAction* create_applications_menu_shortcut = shortcut_menu->addAction(tr("Add to Applications Menu"));
|
||||
#endif
|
||||
context_menu.addSeparator();
|
||||
QAction* properties = context_menu.addAction(tr("Configure Game"));
|
||||
QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
|
||||
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID"));
|
||||
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("View on GameDB"));
|
||||
|
||||
favorite->setVisible(program_id != 0);
|
||||
favorite->setCheckable(true);
|
||||
@@ -603,10 +599,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
|
||||
});
|
||||
connect(start_game, &QAction::triggered,
|
||||
[this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Normal); });
|
||||
connect(start_game_global, &QAction::triggered,
|
||||
[this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Global); });
|
||||
connect(start_game, &QAction::triggered, [this, path]() {
|
||||
emit BootGame(QString::fromStdString(path), StartGameType::Normal);
|
||||
});
|
||||
connect(start_game_global, &QAction::triggered, [this, path]() {
|
||||
emit BootGame(QString::fromStdString(path), StartGameType::Global);
|
||||
});
|
||||
connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
|
||||
});
|
||||
@@ -633,10 +631,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() {
|
||||
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CustomConfiguration, path);
|
||||
});
|
||||
connect(set_play_time, &QAction::triggered,
|
||||
[this, program_id]() { emit SetPlayTimeRequested(program_id); });
|
||||
connect(remove_play_time_data, &QAction::triggered,
|
||||
[this, program_id]() { emit RemovePlayTimeRequested(program_id); });
|
||||
connect(set_play_time, &QAction::triggered, [this, program_id]() {
|
||||
emit SetPlayTimeRequested(program_id);
|
||||
});
|
||||
connect(remove_play_time_data, &QAction::triggered, [this, program_id]() {
|
||||
emit RemovePlayTimeRequested(program_id);
|
||||
});
|
||||
connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] {
|
||||
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CacheStorage, path);
|
||||
});
|
||||
|
||||
@@ -2536,11 +2536,11 @@ void MainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRe
|
||||
const QString question = [target] {
|
||||
switch (target) {
|
||||
case QtCommon::Game::GameListRemoveTarget::GlShaderCache:
|
||||
return tr("Delete OpenGL Transferable Shader Cache?");
|
||||
return tr("Delete OpenGL Shader Cache?");
|
||||
case QtCommon::Game::GameListRemoveTarget::VkShaderCache:
|
||||
return tr("Delete Vulkan Transferable Shader Cache?");
|
||||
return tr("Delete Vulkan Shader Cache?");
|
||||
case QtCommon::Game::GameListRemoveTarget::AllShaderCache:
|
||||
return tr("Delete All Transferable Shader Caches?");
|
||||
return tr("Delete All Shader Caches?");
|
||||
case QtCommon::Game::GameListRemoveTarget::CustomConfiguration:
|
||||
return tr("Remove Custom Game Configuration?");
|
||||
case QtCommon::Game::GameListRemoveTarget::CacheStorage:
|
||||
|
||||
Reference in New Issue
Block a user