Compare commits

..

1 Commits

Author SHA1 Message Date
lizzie
fb7169156c [cmake] fix & allow FFmpeg cross compilations 2025-11-29 07:51:29 +00:00
22 changed files with 280 additions and 247 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

@@ -13,63 +13,98 @@ set(FFmpeg_HWACCEL_FLAGS)
set(FFmpeg_HWACCEL_INCLUDE_DIRS)
set(FFmpeg_HWACCEL_LDFLAGS)
if (UNIX AND NOT ANDROID)
find_package(PkgConfig REQUIRED)
if (NOT ANDROID)
pkg_check_modules(LIBVA libva)
pkg_check_modules(CUDA cuda)
pkg_check_modules(FFNVCODEC ffnvcodec)
pkg_check_modules(VDPAU vdpau)
if (NOT YUZU_USE_BUNDLED_FFMPEG)
set(FFmpeg_CROSS_COMPILE_FLAGS "")
if (ANDROID)
# TODO: Maybe use CMAKE_SYSROOT? and probably provide a toolchain file for android
# I mean isn't that the "proper" way anyways?
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME)
set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
set(SYSROOT "${TOOLCHAIN}/sysroot")
set(FFmpeg_CPU "armv8-a")
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--enable-cross-compile
--arch=arm64
#--cpu=${FFmpeg_CPU}
--cross-prefix="${TOOLCHAIN}/bin/aarch64-linux-android-"
--sysroot="${SYSROOT}"
--target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib"
)
set(FFmpeg_IS_CROSS_COMPILING TRUE)
# User attempts to do a FFmpeg cross compilation because...
# Here we just quickly test against host/system processors not matching
# TODO: Test for versions not matching as well?
elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR
AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME))
string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME)
# TODO: Can we really do better? Auto-detection? Something clever?
if (NOT DEFINED FFmpeg_CROSS_PREFIX)
message(ERROR "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-")
endif()
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--enable-cross-compile
--arch="${CMAKE_SYSTEM_PROCESSOR}"
--target-os="${FFmpeg_SYSTEM_NAME}"
--sysroot="${CMAKE_SYSROOT}"
--cross-prefix="${FFmpeg_CROSS_PREFIX}"
)
set(FFmpeg_IS_CROSS_COMPILING TRUE)
endif()
endif()
if (NOT APPLE)
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
if(PLATFORM_SUN)
find_library(LIBDRM_LIB libdrm PATHS /usr/lib/64 /usr/lib/amd64 /usr/lib)
if(LIBDRM_LIB)
if (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBVA libva)
pkg_check_modules(CUDA cuda)
pkg_check_modules(FFNVCODEC ffnvcodec)
pkg_check_modules(VDPAU vdpau)
find_package(X11)
if(X11_FOUND)
if (NOT APPLE)
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
if(PLATFORM_SUN)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
X11
"${LIBDRM_LIB}")
message(STATUS "Found libdrm at: ${LIBDRM_LIB}")
"${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
else()
message(WARNING "libdrm not found, disabling libdrm support")
list(APPEND FFmpeg_HWACCEL_FLAGS
--disable-libdrm)
pkg_check_modules(LIBDRM libdrm REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
${LIBDRM_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${LIBDRM_INCLUDE_DIRS})
endif()
else()
pkg_check_modules(LIBDRM libdrm REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
${LIBDRM_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${LIBDRM_INCLUDE_DIRS})
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-libdrm)
endif()
endif()
if(LIBVA_FOUND)
find_package(X11 REQUIRED)
pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
${X11_LIBRARIES}
${LIBVA-DRM_LIBRARIES}
${LIBVA-X11_LIBRARIES}
${LIBVA_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-hwaccel=h264_vaapi
--enable-hwaccel=vp8_vaapi
--enable-hwaccel=vp9_vaapi)
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${X11_INCLUDE_DIRS}
${LIBVA-DRM_INCLUDE_DIRS}
${LIBVA-X11_INCLUDE_DIRS}
${LIBVA_INCLUDE_DIRS}
)
message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found")
if(LIBVA_FOUND)
pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
${X11_LIBRARIES}
${LIBVA-DRM_LIBRARIES}
${LIBVA-X11_LIBRARIES}
${LIBVA_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-hwaccel=h264_vaapi
--enable-hwaccel=vp8_vaapi
--enable-hwaccel=vp9_vaapi)
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${X11_INCLUDE_DIRS}
${LIBVA-DRM_INCLUDE_DIRS}
${LIBVA-X11_INCLUDE_DIRS}
${LIBVA_INCLUDE_DIRS}
)
message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found")
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
message(WARNING "ffmpeg: libva-dev not found, disabling Video Acceleration API (VA-API)...")
endif()
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
message(WARNING "ffmpeg: libva-dev not found, disabling Video Acceleration API (VA-API)...")
message(WARNING "ffmpeg: X11 libraries not found, disabling VA-API...")
endif()
if (FFNVCODEC_FOUND)
@@ -193,24 +228,6 @@ else()
find_program(BASH_PROGRAM bash REQUIRED)
set(FFmpeg_CROSS_COMPILE_FLAGS "")
if (ANDROID)
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME)
set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
set(SYSROOT "${TOOLCHAIN}/sysroot")
set(FFmpeg_CPU "armv8-a")
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--arch=arm64
#--cpu=${FFmpeg_CPU}
--enable-cross-compile
--cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
--sysroot=${SYSROOT}
--target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib"
)
endif()
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
# `--disable-vdpau` is needed to avoid linking issues
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
@@ -236,6 +253,7 @@ else()
--enable-pic
--cc="${FFmpeg_CC}"
--cxx="${FFmpeg_CXX}"
${FFmpeg_CROSS_COMPILE_FLAG}
${FFmpeg_HWACCEL_FLAGS}
${FFmpeg_CROSS_COMPILE_FLAGS}
WORKING_DIRECTORY

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

@@ -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

@@ -274,10 +274,18 @@ 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) || Common::FS::RemoveFile(target_file)) {
QtCommon::Frontend::Information(tr("Successfully Removed"), tr("Successfully removed the shader cache."));
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."));
} else {
QtCommon::Frontend::Warning(tr("Error Removing Shader Cache"), tr("Failed to remove the shader cache."));
QtCommon::Frontend::Warning(tr("Error Removing Transferable Shader Cache"),
tr("Failed to remove the transferable shader cache."));
}
}

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

@@ -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

@@ -545,40 +545,44 @@ 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"));
QAction* start_game_global = context_menu.addAction(tr("Start with Global Settings"));
QAction* start_game = context_menu.addAction(tr("Start Game"));
QAction* start_game_global =
context_menu.addAction(tr("Start Game without Custom Configuration"));
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* properties = context_menu.addAction(tr("Configure Game"));
context_menu.addSeparator();
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* open_transferable_shader_cache =
context_menu.addAction(tr("Open Transferable Pipeline Cache"));
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"));
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"));
// 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* 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"));
QAction* properties = context_menu.addAction(tr("Configure Game"));
favorite->setVisible(program_id != 0);
favorite->setCheckable(true);
@@ -599,12 +603,10 @@ 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);
});
@@ -631,12 +633,10 @@ 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);
});

View File

@@ -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 Shader Cache?");
return tr("Delete OpenGL Transferable Shader Cache?");
case QtCommon::Game::GameListRemoveTarget::VkShaderCache:
return tr("Delete Vulkan Shader Cache?");
return tr("Delete Vulkan Transferable Shader Cache?");
case QtCommon::Game::GameListRemoveTarget::AllShaderCache:
return tr("Delete All Shader Caches?");
return tr("Delete All Transferable Shader Caches?");
case QtCommon::Game::GameListRemoveTarget::CustomConfiguration:
return tr("Remove Custom Game Configuration?");
case QtCommon::Game::GameListRemoveTarget::CacheStorage: