Compare commits
7 Commits
qcom-weird
...
mutliplaye
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
795a52c75a | ||
|
|
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
|
||||
|
||||
@@ -170,14 +170,10 @@ struct Values {
|
||||
// multiplayer settings
|
||||
Setting<std::string> multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_games_owned{linkage, false, "filter_games_owned",
|
||||
Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty",
|
||||
Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full",
|
||||
Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_games_owned{linkage, true, "filter_games_owned", Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_public_rooms{linkage, true, "filter_games_public_room", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
|
||||
Setting<u16, true> multiplayer_port{linkage, 24872, 0,
|
||||
Setting<u16, true> multiplayer_port{linkage, 24872, 0,
|
||||
UINT16_MAX, "port", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_room_nickname{
|
||||
linkage, {}, "room_nickname", Category::Multiplayer};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -62,14 +62,12 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
|
||||
ui->room_list->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
ui->nickname->setValidator(validation.GetNickname());
|
||||
ui->nickname->setText(
|
||||
QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
|
||||
ui->nickname->setText(QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
|
||||
|
||||
// Try find the best nickname by default
|
||||
if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("Eden")) {
|
||||
if (!Settings::values.eden_username.GetValue().empty()) {
|
||||
ui->nickname->setText(
|
||||
QString::fromStdString(Settings::values.eden_username.GetValue()));
|
||||
if (auto const username = Settings::values.eden_username.GetValue(); !username.empty()) {
|
||||
ui->nickname->setText(QString::fromStdString(username));
|
||||
} else if (!GetProfileUsername().empty()) {
|
||||
ui->nickname->setText(QString::fromStdString(GetProfileUsername()));
|
||||
} else {
|
||||
@@ -81,21 +79,17 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
|
||||
connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby);
|
||||
connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
|
||||
connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned);
|
||||
connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty);
|
||||
connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull);
|
||||
connect(ui->public_rooms, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterPublic);
|
||||
connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom);
|
||||
connect(ui->room_list, &QTreeView::clicked, this, &Lobby::OnExpandRoom);
|
||||
|
||||
// Actions
|
||||
connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this,
|
||||
&Lobby::OnRefreshLobby);
|
||||
connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this, &Lobby::OnRefreshLobby);
|
||||
|
||||
// Load persistent filters after events are connected to make sure they apply
|
||||
ui->search->setText(
|
||||
QString::fromStdString(UISettings::values.multiplayer_filter_text.GetValue()));
|
||||
ui->search->setText(QString::fromStdString(UISettings::values.multiplayer_filter_text.GetValue()));
|
||||
ui->games_owned->setChecked(UISettings::values.multiplayer_filter_games_owned.GetValue());
|
||||
ui->hide_empty->setChecked(UISettings::values.multiplayer_filter_hide_empty.GetValue());
|
||||
ui->hide_full->setChecked(UISettings::values.multiplayer_filter_hide_full.GetValue());
|
||||
ui->public_rooms->setChecked(UISettings::values.multiplayer_filter_public_rooms.GetValue());
|
||||
}
|
||||
|
||||
Lobby::~Lobby() = default;
|
||||
@@ -215,12 +209,9 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
|
||||
UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString();
|
||||
UISettings::values.multiplayer_filter_text = ui->search->text().toStdString();
|
||||
UISettings::values.multiplayer_filter_games_owned = ui->games_owned->isChecked();
|
||||
UISettings::values.multiplayer_filter_hide_empty = ui->hide_empty->isChecked();
|
||||
UISettings::values.multiplayer_filter_hide_full = ui->hide_full->isChecked();
|
||||
UISettings::values.multiplayer_ip =
|
||||
proxy->data(connection_index, LobbyItemHost::HostIPRole).value<QString>().toStdString();
|
||||
UISettings::values.multiplayer_port =
|
||||
proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
|
||||
UISettings::values.multiplayer_filter_public_rooms = ui->public_rooms->isChecked();
|
||||
UISettings::values.multiplayer_ip = proxy->data(connection_index, LobbyItemHost::HostIPRole).value<QString>().toStdString();
|
||||
UISettings::values.multiplayer_port = proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
|
||||
emit SaveConfig();
|
||||
}
|
||||
|
||||
@@ -228,8 +219,8 @@ void Lobby::ResetModel() {
|
||||
model->clear();
|
||||
model->insertColumns(0, Column::TOTAL);
|
||||
model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole);
|
||||
model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Room Name"), Qt::DisplayRole);
|
||||
model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Preferred Game"), Qt::DisplayRole);
|
||||
model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Name"), Qt::DisplayRole);
|
||||
model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Game"), Qt::DisplayRole);
|
||||
model->setHeaderData(Column::HOST, Qt::Horizontal, tr("Host"), Qt::DisplayRole);
|
||||
}
|
||||
|
||||
@@ -345,26 +336,12 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
|
||||
return true;
|
||||
}
|
||||
|
||||
// filter by empty rooms
|
||||
if (filter_empty) {
|
||||
QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
|
||||
int player_count =
|
||||
sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size();
|
||||
if (player_count == 0) {
|
||||
// filter by non-password protected
|
||||
if (filter_public) {
|
||||
QModelIndex password_index = sourceModel()->index(sourceRow, Column::ROOM_NAME);
|
||||
bool has_password = sourceModel()->data(password_index, LobbyItemName::PasswordRole).toBool();
|
||||
if (has_password)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// filter by filled rooms
|
||||
if (filter_full) {
|
||||
QModelIndex member_list = sourceModel()->index(sourceRow, Column::MEMBER, sourceParent);
|
||||
int player_count =
|
||||
sourceModel()->data(member_list, LobbyItemMemberList::MemberListRole).toList().size();
|
||||
int max_players =
|
||||
sourceModel()->data(member_list, LobbyItemMemberList::MaxPlayerRole).toInt();
|
||||
if (player_count >= max_players) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// filter by search parameters
|
||||
@@ -372,18 +349,9 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
|
||||
QModelIndex game_name = sourceModel()->index(sourceRow, Column::GAME_NAME, sourceParent);
|
||||
QModelIndex room_name = sourceModel()->index(sourceRow, Column::ROOM_NAME, sourceParent);
|
||||
QModelIndex host_name = sourceModel()->index(sourceRow, Column::HOST, sourceParent);
|
||||
bool preferred_game_match = sourceModel()
|
||||
->data(game_name, LobbyItemGame::GameNameRole)
|
||||
.toString()
|
||||
.contains(filter_search, filterCaseSensitivity());
|
||||
bool room_name_match = sourceModel()
|
||||
->data(room_name, LobbyItemName::NameRole)
|
||||
.toString()
|
||||
.contains(filter_search, filterCaseSensitivity());
|
||||
bool username_match = sourceModel()
|
||||
->data(host_name, LobbyItemHost::HostUsernameRole)
|
||||
.toString()
|
||||
.contains(filter_search, filterCaseSensitivity());
|
||||
bool preferred_game_match = sourceModel()->data(game_name, LobbyItemGame::GameNameRole).toString().contains(filter_search, filterCaseSensitivity());
|
||||
bool room_name_match = sourceModel()->data(room_name, LobbyItemName::NameRole).toString().contains(filter_search, filterCaseSensitivity());
|
||||
bool username_match = sourceModel()->data(host_name, LobbyItemHost::HostUsernameRole).toString().contains(filter_search, filterCaseSensitivity());
|
||||
if (!preferred_game_match && !room_name_match && !username_match) {
|
||||
return false;
|
||||
}
|
||||
@@ -425,13 +393,8 @@ void LobbyFilterProxyModel::SetFilterOwned(bool filter) {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void LobbyFilterProxyModel::SetFilterEmpty(bool filter) {
|
||||
filter_empty = filter;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void LobbyFilterProxyModel::SetFilterFull(bool filter) {
|
||||
filter_full = filter;
|
||||
void LobbyFilterProxyModel::SetFilterPublic(bool filter) {
|
||||
filter_public = filter;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
|
||||
@@ -126,14 +126,13 @@ public:
|
||||
|
||||
public slots:
|
||||
void SetFilterOwned(bool);
|
||||
void SetFilterEmpty(bool);
|
||||
void SetFilterFull(bool);
|
||||
void SetFilterPublic(bool);
|
||||
void SetFilterSearch(const QString&);
|
||||
|
||||
private:
|
||||
QStandardItemModel* game_list;
|
||||
bool filter_owned = false;
|
||||
bool filter_empty = false;
|
||||
bool filter_full = false;
|
||||
bool filter_public = false;
|
||||
QString filter_search;
|
||||
};
|
||||
|
||||
@@ -78,16 +78,9 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="hide_empty">
|
||||
<widget class="QCheckBox" name="public_rooms">
|
||||
<property name="text">
|
||||
<string>Hide Empty Rooms</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="hide_full">
|
||||
<property name="text">
|
||||
<string>Hide Full Rooms</string>
|
||||
<string>Public Rooms</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
Reference in New Issue
Block a user