Compare commits

..

1 Commits

23 changed files with 356 additions and 266 deletions

View File

@@ -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 OR PLATFORM_NETBSD OR PLATFORM_DRAGONFLY)
if (PLATFORM_SUN OR PLATFORM_OPENBSD)
AddJsonPackage(xbyak_sun)
else()
AddJsonPackage(xbyak)

View File

@@ -22,21 +22,33 @@ 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, __FILE__ ": assert\n" __VA_ARGS__); \
AssertFailSoftImpl(); \
LOG_CRITICAL(Debug, "Assert\n" __VA_ARGS__); \
AssertFailSoftImpl(); \
} \
}())
#define ASSERT(_a_) ASSERT_MSG(_a_, "{}", #_a_)
#define UNREACHABLE() \
do { \
LOG_CRITICAL(Debug, "Unreachable"); \
AssertFatalImpl(); \
} while (0)
#define UNREACHABLE_MSG(...) \
do { \
LOG_CRITICAL(Debug, __FILE__ ": unreachable\n" __VA_ARGS__); \
AssertFatalImpl(); \
LOG_CRITICAL(Debug, "Unreachable\n" __VA_ARGS__); \
AssertFatalImpl(); \
} while (0)
#define UNREACHABLE() UNREACHABLE_MSG("")
#ifdef _DEBUG
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
@@ -57,11 +69,19 @@ void AssertFailSoftImpl();
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
// If the assert is ignored, execute _b_
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
#define ASSERT_OR_EXECUTE(_a_, _b_) \
do { \
ASSERT_MSG(_a_, __VA_ARGS__); \
if (!(_a_)) { _b_ } \
ASSERT(_a_); \
if (!(_a_)) [[unlikely]] { \
_b_ \
} \
} while (0)
// If the assert is ignored, execute _b_
#define ASSERT_OR_EXECUTE(_a_, _b_) ASSERT_OR_EXECUTE_MSG(_a_, _b_, "{}", #_a_)
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
do { \
ASSERT_MSG(_a_, __VA_ARGS__); \
if (!(_a_)) [[unlikely]] { \
_b_ \
} \
} while (0)

View File

@@ -50,7 +50,8 @@ constexpr const char* TrimSourcePath(std::string_view source) {
}
/// @brief Interface for logging backends.
struct Backend {
class Backend {
public:
virtual ~Backend() = default;
virtual void Write(const Entry& entry) = 0;
virtual void EnableForStacktrace() = 0;
@@ -58,7 +59,8 @@ struct Backend {
};
/// @brief Backend that writes to stderr and with color
struct ColorConsoleBackend final : public Backend {
class ColorConsoleBackend final : public Backend {
public:
explicit ColorConsoleBackend() = default;
~ColorConsoleBackend() override = default;
@@ -84,15 +86,16 @@ private:
};
/// @brief Backend that writes to a file passed into the constructor
struct FileBackend final : public Backend {
class FileBackend final : public Backend {
public:
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.
void(FS::RemoveFile(old_filename));
void(FS::RenameFile(filename, old_filename));
static_cast<void>(FS::RemoveFile(old_filename));
static_cast<void>(FS::RenameFile(filename, old_filename));
file = std::make_unique<FS::IOFile>(filename, FS::FileAccessMode::Write, FS::FileType::TextFile);
}
@@ -162,34 +165,51 @@ private:
bool enabled = true;
};
#ifdef _WIN32
/// @brief Backend that writes to Visual Studio's output window
struct DebuggerBackend final : public Backend {
/**
* 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
::OutputDebugStringW(UTF8ToUTF16W(FormatLogMessage(entry).append(1, '\n')).c_str());
#endif
}
void Flush() override {}
void EnableForStacktrace() override {}
};
#endif
#ifdef ANDROID
/// @brief Backend that writes to the Android logcat
struct LogcatBackend : public Backend {
/**
* Backend that writes to the Android logcat
*/
class LogcatBackend : public Backend {
public:
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;
/// @brief Static state as a singleton.
/**
* Static state as a singleton.
*/
class Impl {
public:
static Impl& Instance() {
@@ -208,7 +228,8 @@ 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;
}
@@ -255,14 +276,13 @@ 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); });
};
do {
while (!stop_token.stop_requested()) {
message_queue.PopWait(entry, stop_token);
write_logs();
} while (!stop_token.stop_requested());
if (entry.filename != nullptr)
write_logs();
}
// 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;
@@ -295,11 +315,9 @@ 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
@@ -312,11 +330,9 @@ 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

View File

@@ -1,6 +1,3 @@
// 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
@@ -28,21 +25,15 @@ static s64 WindowsQueryPerformanceCounter() {
}
static s64 GetSystemTimeNS() {
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;
}
// 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);
}
#endif

View File

@@ -81,9 +81,10 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
// Sets the debugger-visible name of the current thread.
void SetCurrentThreadName(const char* name) {
static auto pf = (decltype(&SetThreadDescription))(void*)GetProcAddress(GetModuleHandle(TEXT("KernelBase.dll")), "SetThreadDescription");
if (pf)
if (auto pf = (decltype(&SetThreadDescription))(void*)GetProcAddress(GetModuleHandle(TEXT("KernelBase.dll")), "SetThreadDescription"); pf)
pf(GetCurrentThread(), UTF8ToUTF16W(name).data()); // Windows 10+
else
; // No-op
}
#else // !MSVC_VER, so must be POSIX threads

View File

@@ -1,6 +1,3 @@
// 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
@@ -65,15 +62,14 @@ TimerResolution GetTimerResolution() {
void SetHighQoS() {
// https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
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+
}
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));
}
} // Anonymous namespace

View File

@@ -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__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#if defined(ARCHITECTURE_arm64) || defined(__sun__)
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__) || defined(__NetBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__)
config.fastmem_pointer = std::nullopt;
config.fastmem_exclusive_access = false;
#endif

View File

@@ -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__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#if defined(ARCHITECTURE_arm64) || defined(__sun__)
config.code_cache_size = std::uint32_t(128_MiB);
#else
config.code_cache_size = std::uint32_t(512_MiB);

View File

@@ -339,10 +339,14 @@ 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) {
@@ -1389,9 +1393,20 @@ 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};
StoreSettings();
m_save_needed = true;
}
Result ISystemSettingsServer::GetSettingsItemValueImpl(std::span<u8> out_value, u64& out_size,

View File

@@ -167,6 +167,7 @@ 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;
@@ -175,6 +176,7 @@ 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};
};

View File

@@ -18,12 +18,7 @@ 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)
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_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${PLATFORM_OPENBSD})
option(DYNARMIC_IGNORE_ASSERTS "Ignore asserts" OFF)
option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF)

View File

@@ -87,11 +87,9 @@ A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig conf, A32::Jit* jit_in
code.PreludeComplete();
ClearFastDispatchTable();
if (conf.fastmem_pointer.has_value()) {
exception_handler.SetFastmemCallback([this](u64 rip_) {
return FastmemCallback(rip_);
});
}
exception_handler.SetFastmemCallback([this](u64 rip_) {
return FastmemCallback(rip_);
});
}
A32EmitX64::~A32EmitX64() = default;

View File

@@ -61,11 +61,9 @@ A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_in
code.PreludeComplete();
ClearFastDispatchTable();
if (conf.fastmem_pointer.has_value()) {
exception_handler.SetFastmemCallback([this](u64 rip_) {
return FastmemCallback(rip_);
});
}
exception_handler.SetFastmemCallback([this](u64 rip_) {
return FastmemCallback(rip_);
});
}
A64EmitX64::~A64EmitX64() = default;

View File

@@ -87,24 +87,18 @@ public:
// Waste a page to store the size
size += DYNARMIC_PAGE_SIZE;
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
# 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
mode |= MAP_JIT;
#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);
# endif
void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, mode, -1, 0);
if (p == MAP_FAILED) {
using Xbyak::Error;
XBYAK_THROW(Xbyak::ERR_CANT_ALLOC);

View File

@@ -911,15 +911,15 @@ static Xbyak::Reg8 DoCarry(RegAlloc& reg_alloc, Argument& carry_in, IR::Inst* ca
// AL contains flags (after LAHF + SETO sequence)
static Xbyak::Reg64 DoNZCV(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* nzcv_out) {
if (!nzcv_out) {
return Xbyak::Reg64{-1};
if (nzcv_out) {
const Xbyak::Reg64 nzcv = reg_alloc.ScratchGpr(HostLoc::RAX);
code.xor_(nzcv.cvt32(), nzcv.cvt32());
return nzcv;
}
const Xbyak::Reg64 nzcv = reg_alloc.ScratchGpr(HostLoc::RAX);
code.xor_(nzcv.cvt32(), nzcv.cvt32());
return nzcv;
return Xbyak::Reg64{-1};
}
static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bitsize) {
static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, size_t bitsize) {
const auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp);
const auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp);
const auto nzcv_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetNZCVFromOp);
@@ -930,19 +930,13 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
// Consider using LEA.
if (!carry_inst && !overflow_inst && !nzcv_inst && carry_in.IsImmediate() && !carry_in.GetImmediateU1()) {
if (args[1].IsImmediate() && args[1].FitsInImmediateS32()) {
const Xbyak::Reg op1 = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize);
const Xbyak::Reg result = ctx.reg_alloc.ScratchGpr().changeBit(bitsize);
code.lea(result, code.ptr[op1 + args[1].GetImmediateS32()]);
const Xbyak::Reg result = ctx.reg_alloc.UseScratchGpr(args[0]).changeBit(bitsize);
code.lea(result, code.ptr[result + args[1].GetImmediateS32()]);
ctx.reg_alloc.DefineValue(inst, result);
} else {
const Xbyak::Reg op1 = ctx.reg_alloc.UseGpr(args[0]).changeBit(bitsize);
const Xbyak::Reg result = ctx.reg_alloc.UseScratchGpr(args[0]).changeBit(bitsize);
const Xbyak::Reg op2 = ctx.reg_alloc.UseGpr(args[1]).changeBit(bitsize);
const Xbyak::Reg result = ctx.reg_alloc.ScratchGpr().changeBit(bitsize);
code.lea(result, code.ptr[op1 + op2]);
code.lea(result, code.ptr[result + op2]);
ctx.reg_alloc.DefineValue(inst, result);
}
return;
@@ -957,8 +951,14 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int bit
const u32 op_arg = args[1].GetImmediateU32();
if (carry_in.IsImmediate()) {
if (carry_in.GetImmediateU1()) {
code.stc();
code.adc(result, op_arg);
// In range for a valid LEA materialisation
auto const in_range = s32(op_arg) >= -0x7ffffffe && s32(op_arg) <= 0x7ffffffe;
if (in_range && (carry_inst || nzcv_inst || overflow_inst)) {
code.stc();
code.adc(result, op_arg);
} else {
code.lea(result, code.ptr[result + op_arg + 1]);
}
} else {
code.add(result, op_arg);
}

View File

@@ -7,7 +7,7 @@
*/
#include <mutex>
#include <optional>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/abi.h"
@@ -42,46 +42,43 @@ void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg
}
namespace {
struct SpinLockImpl {
void Initialize() noexcept;
static void GlobalInitialize() noexcept;
void Initialize();
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode);
void (*lock)(volatile int*) = nullptr;
void (*unlock)(volatile int*) = nullptr;
void (*lock)(volatile int*);
void (*unlock)(volatile int*);
};
std::once_flag flag;
/// @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;
SpinLockImpl impl;
void SpinLockImpl::Initialize() {
const Xbyak::Reg64 ABI_PARAM1 = Backend::X64::HostLocToReg64(Backend::X64::ABI_PARAM1);
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::GlobalInitialize);
impl->lock(&storage);
std::call_once(flag, &SpinLockImpl::Initialize, impl);
impl.lock(&storage);
}
void SpinLock::Unlock() noexcept {
std::call_once(flag, &SpinLockImpl::GlobalInitialize);
impl->unlock(&storage);
std::call_once(flag, &SpinLockImpl::Initialize, impl);
impl.unlock(&storage);
}
} // namespace Dynarmic

View File

@@ -44,20 +44,10 @@ 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_)
: Xbyak::CodeGenerator(MAX_CODE_SIZE, default_cg_mode)
, code{code_}, maxwell3d{maxwell3d_} {
: CodeGenerator{MAX_CODE_SIZE}, code{code_}, maxwell3d{maxwell3d_} {
Compile();
}

View File

@@ -55,7 +55,7 @@ using VideoCommon::FileEnvironment;
using VideoCommon::GenericEnvironment;
using VideoCommon::GraphicsEnvironment;
constexpr u32 CACHE_VERSION = 14;
constexpr u32 CACHE_VERSION = 13;
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
template <typename Container>

View File

@@ -41,7 +41,6 @@
#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"
@@ -70,7 +69,6 @@ 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);
@@ -82,7 +80,6 @@ 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);
@@ -116,7 +113,6 @@ 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) {

View File

@@ -38,7 +38,6 @@ class ConfigureGraphicsExtensions;
class ConfigureInputPerGame;
class ConfigureLinuxTab;
class ConfigureSystem;
class ConfigureNetwork;
class QGraphicsScene;
class QStandardItem;
@@ -94,5 +93,4 @@ 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;
};

View File

@@ -160,20 +160,20 @@
<property name="title">
<string>Am&amp;iibo</string>
</property>
<addaction name="action_Launch_Cabinet_Nickname_Owner"/>
<addaction name="action_Launch_Cabinet_Eraser"/>
<addaction name="action_Launch_Cabinet_Restorer"/>
<addaction name="action_Launch_Cabinet_Formatter"/>
<addaction name="action_Load_Cabinet_Nickname_Owner"/>
<addaction name="action_Load_Cabinet_Eraser"/>
<addaction name="action_Load_Cabinet_Restorer"/>
<addaction name="action_Load_Cabinet_Formatter"/>
</widget>
<widget class="QMenu" name="menu_Applets">
<property name="title">
<string>Launch &amp;Applet</string>
<string>&amp;Applets</string>
</property>
<addaction name="action_Launch_QLaunch"/>
<addaction name="action_Launch_MiiEdit"/>
<addaction name="action_Launch_Controller"/>
<addaction name="action_Launch_Setup"/>
<addaction name="action_Launch_PhotoViewer"/>
<addaction name="action_Load_Home_Menu"/>
<addaction name="action_Load_Album"/>
<addaction name="action_Load_Mii_Edit"/>
<addaction name="action_Open_Controller_Menu"/>
<addaction name="action_Open_Setup"/>
</widget>
<widget class="QMenu" name="menuTAS">
<property name="title">
@@ -420,34 +420,34 @@
<string>&amp;Capture Screenshot</string>
</property>
</action>
<action name="action_Launch_PhotoViewer">
<action name="action_Load_Album">
<property name="text">
<string>&amp;Album</string>
<string>Open &amp;Album</string>
</property>
</action>
<action name="action_Launch_Cabinet_Nickname_Owner">
<action name="action_Load_Cabinet_Nickname_Owner">
<property name="text">
<string>&amp;Set Nickname and Owner</string>
</property>
</action>
<action name="action_Launch_Cabinet_Eraser">
<action name="action_Load_Cabinet_Eraser">
<property name="text">
<string>&amp;Delete Game Data</string>
</property>
</action>
<action name="action_Launch_Cabinet_Restorer">
<action name="action_Load_Cabinet_Restorer">
<property name="text">
<string>&amp;Restore Amiibo</string>
</property>
</action>
<action name="action_Launch_Cabinet_Formatter">
<action name="action_Load_Cabinet_Formatter">
<property name="text">
<string>&amp;Format Amiibo</string>
</property>
</action>
<action name="action_Launch_MiiEdit">
<action name="action_Load_Mii_Edit">
<property name="text">
<string>&amp;Mii Editor</string>
<string>Open &amp;Mii Editor</string>
</property>
</action>
<action name="action_Configure_Tas">
@@ -493,7 +493,7 @@
<string>R&amp;ecord</string>
</property>
</action>
<action name="action_Launch_Controller">
<action name="action_Open_Controller_Menu">
<property name="text">
<string>Open &amp;Controller Menu</string>
</property>
@@ -503,14 +503,14 @@
<string>Install Decryption &amp;Keys</string>
</property>
</action>
<action name="action_Launch_QLaunch">
<action name="action_Load_Home_Menu">
<property name="text">
<string>&amp;Home Menu</string>
<string>Open &amp;Home Menu</string>
</property>
</action>
<action name="action_Launch_Setup">
<action name="action_Open_Setup">
<property name="text">
<string>&amp;Setup</string>
<string>Open &amp;Setup</string>
</property>
<property name="menuRole">
<enum>QAction::MenuRole::TextHeuristicRole</enum>

View File

@@ -705,13 +705,13 @@ MainWindow::MainWindow(bool has_broken_vulkan)
}
if (should_launch_setup) {
LaunchFirmwareApplet(Service::AM::AppletProgramId::Starter, std::nullopt);
OnInitialSetup();
} else {
if (!game_path.isEmpty()) {
BootGame(game_path, ApplicationAppletParameters());
} else {
if (should_launch_qlaunch) {
LaunchFirmwareApplet(Service::AM::AppletProgramId::QLaunch, std::nullopt);
OnHomeMenu();
}
}
}
@@ -1661,35 +1661,19 @@ void MainWindow::ConnectMenuEvents() {
connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &MainWindow::OnSaveConfig);
// Tools
connect_menu(ui->action_Launch_PhotoViewer, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::PhotoViewer, std::nullopt);
});
connect_menu(ui->action_Launch_MiiEdit, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::MiiEdit, std::nullopt);
});
connect_menu(ui->action_Launch_Controller, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::Controller, std::nullopt);
});
connect_menu(ui->action_Launch_QLaunch, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::QLaunch, std::nullopt);
});
connect_menu(ui->action_Launch_Setup, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::Starter, std::nullopt);
});
// Tools (cabinet)
connect_menu(ui->action_Launch_Cabinet_Nickname_Owner, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::Cabinet, {Service::NFP::CabinetMode::StartNicknameAndOwnerSettings});
});
connect_menu(ui->action_Launch_Cabinet_Eraser, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::Cabinet, {Service::NFP::CabinetMode::StartGameDataEraser});
});
connect_menu(ui->action_Launch_Cabinet_Restorer, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::Cabinet, {Service::NFP::CabinetMode::StartRestorer});
});
connect_menu(ui->action_Launch_Cabinet_Formatter, [this]{
LaunchFirmwareApplet(Service::AM::AppletProgramId::Cabinet, {Service::NFP::CabinetMode::StartFormatter});
});
connect_menu(ui->action_Load_Album, &MainWindow::OnAlbum);
connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
connect_menu(ui->action_Load_Cabinet_Eraser,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartGameDataEraser); });
connect_menu(ui->action_Load_Cabinet_Restorer,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartRestorer); });
connect_menu(ui->action_Load_Cabinet_Formatter,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartFormatter); });
connect_menu(ui->action_Load_Mii_Edit, &MainWindow::OnMiiEdit);
connect_menu(ui->action_Open_Controller_Menu, &MainWindow::OnOpenControllerMenu);
connect_menu(ui->action_Load_Home_Menu, &MainWindow::OnHomeMenu);
connect_menu(ui->action_Open_Setup, &MainWindow::OnInitialSetup);
connect_menu(ui->action_Desktop, &MainWindow::OnCreateHomeMenuDesktopShortcut);
connect_menu(ui->action_Application_Menu,
&MainWindow::OnCreateHomeMenuApplicationMenuShortcut);
@@ -1730,16 +1714,14 @@ void MainWindow::UpdateMenuState() {
ui->action_Pause,
};
const std::array applet_actions{
ui->action_Launch_PhotoViewer,
ui->action_Launch_Cabinet_Nickname_Owner,
ui->action_Launch_Cabinet_Eraser,
ui->action_Launch_Cabinet_Restorer,
ui->action_Launch_Cabinet_Formatter,
ui->action_Launch_MiiEdit,
ui->action_Launch_QLaunch,
ui->action_Launch_Controller
};
const std::array applet_actions{ui->action_Load_Album,
ui->action_Load_Cabinet_Nickname_Owner,
ui->action_Load_Cabinet_Eraser,
ui->action_Load_Cabinet_Restorer,
ui->action_Load_Cabinet_Formatter,
ui->action_Load_Mii_Edit,
ui->action_Load_Home_Menu,
ui->action_Open_Controller_Menu};
for (QAction* action : running_actions) {
action->setEnabled(emulation_running);
@@ -3978,61 +3960,157 @@ void MainWindow::OnGameListRefresh()
SetFirmwareVersion();
}
void MainWindow::OnAlbum() {
constexpr u64 AlbumId = static_cast<u64>(Service::AM::AppletProgramId::PhotoViewer);
auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install firmware to use the Album applet."));
return;
}
void MainWindow::LaunchFirmwareApplet(Service::AM::AppletProgramId program_id, std::optional<Service::NFP::CabinetMode> cabinet_mode) {
auto album_nca = bis_system->GetEntry(AlbumId, FileSys::ContentRecordType::Program);
if (!album_nca) {
QMessageBox::warning(this, tr("Album Applet"),
tr("Album applet is not available. Please reinstall firmware."));
return;
}
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer);
const auto filename = QString::fromStdString(album_nca->GetFullPath());
UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
BootGame(filename, LibraryAppletParameters(AlbumId, Service::AM::AppletId::PhotoViewer));
}
void MainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
constexpr u64 CabinetId = static_cast<u64>(Service::AM::AppletProgramId::Cabinet);
auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install firmware to use the Cabinet applet."));
return;
}
auto cabinet_nca = bis_system->GetEntry(CabinetId, FileSys::ContentRecordType::Program);
if (!cabinet_nca) {
QMessageBox::warning(this, tr("Cabinet Applet"),
tr("Cabinet applet is not available. Please reinstall firmware."));
return;
}
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet);
QtCommon::system->GetFrontendAppletHolder().SetCabinetMode(mode);
const auto filename = QString::fromStdString(cabinet_nca->GetFullPath());
UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
BootGame(filename, LibraryAppletParameters(CabinetId, Service::AM::AppletId::Cabinet));
}
void MainWindow::OnMiiEdit() {
constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install firmware to use the Mii editor."));
return;
}
auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program);
if (!mii_applet_nca) {
QMessageBox::warning(this, tr("Mii Edit Applet"),
tr("Mii editor is not available. Please reinstall firmware."));
return;
}
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit);
const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath()));
UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
BootGame(filename, LibraryAppletParameters(MiiEditId, Service::AM::AppletId::MiiEdit));
}
void MainWindow::OnOpenControllerMenu() {
constexpr u64 ControllerAppletId = static_cast<u64>(Service::AM::AppletProgramId::Controller);
auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install firmware to use the Controller Menu."));
return;
}
auto controller_applet_nca =
bis_system->GetEntry(ControllerAppletId, FileSys::ContentRecordType::Program);
if (!controller_applet_nca) {
QMessageBox::warning(this, tr("Controller Applet"),
tr("Controller Menu is not available. Please reinstall firmware."));
return;
}
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller);
const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath()));
UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
BootGame(filename,
LibraryAppletParameters(ControllerAppletId, Service::AM::AppletId::Controller));
}
void MainWindow::OnHomeMenu() {
auto result = FirmwareManager::VerifyFirmware(*QtCommon::system.get());
using namespace QtCommon::StringLookup;
switch (result) {
case FirmwareManager::ErrorFirmwareMissing:
QMessageBox::warning(this, tr("No firmware available"), Lookup(FwCheckErrorFirmwareMissing));
QMessageBox::warning(this, tr("No firmware available"),
Lookup(FwCheckErrorFirmwareMissing));
return;
case FirmwareManager::ErrorFirmwareCorrupted:
QMessageBox::warning(this, tr("Firmware Corrupted"), Lookup(FwCheckErrorFirmwareCorrupted));
QMessageBox::warning(this, tr("Firmware Corrupted"),
Lookup(FwCheckErrorFirmwareCorrupted));
return;
default:
break;
}
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::QLaunch);
auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents();
if (auto applet_nca = bis_system->GetEntry(u64(program_id), FileSys::ContentRecordType::Program); applet_nca) {
if (auto const applet_id = [program_id] {
using namespace Service::AM;
switch (program_id) {
case AppletProgramId::OverlayDisplay: return AppletId::OverlayDisplay;
case AppletProgramId::QLaunch: return AppletId::QLaunch;
case AppletProgramId::Starter: return AppletId::Starter;
case AppletProgramId::Auth: return AppletId::Auth;
case AppletProgramId::Cabinet: return AppletId::Cabinet;
case AppletProgramId::Controller: return AppletId::Controller;
case AppletProgramId::DataErase: return AppletId::DataErase;
case AppletProgramId::Error: return AppletId::Error;
case AppletProgramId::NetConnect: return AppletId::NetConnect;
case AppletProgramId::ProfileSelect: return AppletId::ProfileSelect;
case AppletProgramId::SoftwareKeyboard: return AppletId::SoftwareKeyboard;
case AppletProgramId::MiiEdit: return AppletId::MiiEdit;
case AppletProgramId::Web: return AppletId::Web;
case AppletProgramId::Shop: return AppletId::Shop;
case AppletProgramId::PhotoViewer: return AppletId::PhotoViewer;
case AppletProgramId::Settings: return AppletId::Settings;
case AppletProgramId::OfflineWeb: return AppletId::OfflineWeb;
case AppletProgramId::LoginShare: return AppletId::LoginShare;
case AppletProgramId::WebAuth: return AppletId::WebAuth;
case AppletProgramId::MyPage: return AppletId::MyPage;
default: return AppletId::None;
auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
if (!qlaunch_applet_nca) {
QMessageBox::warning(this, tr("Home Menu Applet"),
tr("Home Menu is not available. Please reinstall firmware."));
return;
}
}(); applet_id != Service::AM::AppletId::None) {
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(applet_id);
if (cabinet_mode)
QtCommon::system->GetFrontendAppletHolder().SetCabinetMode(*cabinet_mode);
// ?
auto const filename = QString::fromStdString((applet_nca->GetFullPath()));
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch);
const auto filename = QString::fromStdString((qlaunch_applet_nca->GetFullPath()));
UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
BootGame(filename, LibraryAppletParameters(u64(program_id), applet_id));
} else {
QMessageBox::warning(this, tr("Unknown applet"), tr("Applet doesn't map to a known value."));
}
} else {
QMessageBox::warning(this, tr("Record not found"), tr("Applet not found. Please reinstall firmware."));
BootGame(filename, LibraryAppletParameters(QLaunchId, Service::AM::AppletId::QLaunch));
}
void MainWindow::OnInitialSetup() {
constexpr u64 Starter = static_cast<u64>(Service::AM::AppletProgramId::Starter);
auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install firmware to use Starter."));
return;
}
auto qlaunch_nca = bis_system->GetEntry(Starter, FileSys::ContentRecordType::Program);
if (!qlaunch_nca) {
QMessageBox::warning(this, tr("Starter Applet"),
tr("Starter is not available. Please reinstall firmware."));
return;
}
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Starter);
const auto filename = QString::fromStdString((qlaunch_nca->GetFullPath()));
UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
BootGame(filename, LibraryAppletParameters(Starter, Service::AM::AppletId::Starter));
}
void MainWindow::OnCreateHomeMenuDesktopShortcut() {

View File

@@ -101,7 +101,6 @@ class InputSubsystem;
namespace Service::AM {
struct FrontendAppletParameters;
enum class AppletId : u32;
enum class AppletProgramId : u64;
} // namespace Service::AM
namespace Service::AM::Frontend {
@@ -400,7 +399,12 @@ private slots:
void ResetWindowSize720();
void ResetWindowSize900();
void ResetWindowSize1080();
void LaunchFirmwareApplet(Service::AM::AppletProgramId program_id, std::optional<Service::NFP::CabinetMode> mode);
void OnAlbum();
void OnCabinet(Service::NFP::CabinetMode mode);
void OnMiiEdit();
void OnOpenControllerMenu();
void OnHomeMenu();
void OnInitialSetup();
void OnCreateHomeMenuDesktopShortcut();
void OnCreateHomeMenuApplicationMenuShortcut();
void OnCaptureScreenshot();
@@ -424,6 +428,7 @@ private:
bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id,
u64* selected_title_id, u8* selected_content_record_type);
ContentManager::InstallResult InstallNCA(const QString& filename);
void MigrateConfigFiles();
void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {},
std::string_view gpu_vendor = {});
void UpdateDockedButton();