diff options
Diffstat (limited to 'src')
61 files changed, 908 insertions, 186 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index a0ae07752..d25a1a645 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -42,6 +42,7 @@ add_library(audio_core STATIC voice_context.h $<$<BOOL:${ENABLE_CUBEB}>:cubeb_sink.cpp cubeb_sink.h> + $<$<BOOL:${ENABLE_SDL2}>:sdl2_sink.cpp sdl2_sink.h> ) create_target_directory_groups(audio_core) @@ -71,3 +72,7 @@ if(ENABLE_CUBEB) target_link_libraries(audio_core PRIVATE cubeb) target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1) endif() +if(ENABLE_SDL2) + target_link_libraries(audio_core PRIVATE SDL2) + target_compile_definitions(audio_core PRIVATE HAVE_SDL2) +endif() diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp new file mode 100644 index 000000000..62d3716a6 --- /dev/null +++ b/src/audio_core/sdl2_sink.cpp @@ -0,0 +1,163 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <atomic> +#include <cstring> +#include "audio_core/sdl2_sink.h" +#include "audio_core/stream.h" +#include "audio_core/time_stretch.h" +#include "common/assert.h" +#include "common/logging/log.h" +//#include "common/settings.h" + +// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307 +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#endif +#include <SDL.h> +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace AudioCore { + +class SDLSinkStream final : public SinkStream { +public: + SDLSinkStream(u32 sample_rate, u32 num_channels_, const std::string& output_device) + : num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, num_channels} { + + SDL_AudioSpec spec; + spec.freq = sample_rate; + spec.channels = static_cast<u8>(num_channels); + spec.format = AUDIO_S16SYS; + spec.samples = 4096; + spec.callback = nullptr; + + SDL_AudioSpec obtained; + if (output_device.empty()) { + dev = SDL_OpenAudioDevice(nullptr, 0, &spec, &obtained, 0); + } else { + dev = SDL_OpenAudioDevice(output_device.c_str(), 0, &spec, &obtained, 0); + } + + if (dev == 0) { + LOG_CRITICAL(Audio_Sink, "Error opening sdl audio device: {}", SDL_GetError()); + return; + } + + SDL_PauseAudioDevice(dev, 0); + } + + ~SDLSinkStream() override { + if (dev == 0) { + return; + } + + SDL_CloseAudioDevice(dev); + } + + void EnqueueSamples(u32 source_num_channels, const std::vector<s16>& samples) override { + if (source_num_channels > num_channels) { + // Downsample 6 channels to 2 + ASSERT_MSG(source_num_channels == 6, "Channel count must be 6"); + + std::vector<s16> buf; + buf.reserve(samples.size() * num_channels / source_num_channels); + for (std::size_t i = 0; i < samples.size(); i += source_num_channels) { + // Downmixing implementation taken from the ATSC standard + const s16 left{samples[i + 0]}; + const s16 right{samples[i + 1]}; + const s16 center{samples[i + 2]}; + const s16 surround_left{samples[i + 4]}; + const s16 surround_right{samples[i + 5]}; + // Not used in the ATSC reference implementation + [[maybe_unused]] const s16 low_frequency_effects{samples[i + 3]}; + + constexpr s32 clev{707}; // center mixing level coefficient + constexpr s32 slev{707}; // surround mixing level coefficient + + buf.push_back(static_cast<s16>(left + (clev * center / 1000) + + (slev * surround_left / 1000))); + buf.push_back(static_cast<s16>(right + (clev * center / 1000) + + (slev * surround_right / 1000))); + } + int ret = SDL_QueueAudio(dev, static_cast<const void*>(buf.data()), + static_cast<u32>(buf.size() * sizeof(s16))); + if (ret < 0) + LOG_WARNING(Audio_Sink, "Could not queue audio buffer: {}", SDL_GetError()); + return; + } + + int ret = SDL_QueueAudio(dev, static_cast<const void*>(samples.data()), + static_cast<u32>(samples.size() * sizeof(s16))); + if (ret < 0) + LOG_WARNING(Audio_Sink, "Could not queue audio buffer: {}", SDL_GetError()); + } + + std::size_t SamplesInQueue(u32 channel_count) const override { + if (dev == 0) + return 0; + + return SDL_GetQueuedAudioSize(dev) / (channel_count * sizeof(s16)); + } + + void Flush() override { + should_flush = true; + } + + u32 GetNumChannels() const { + return num_channels; + } + +private: + SDL_AudioDeviceID dev = 0; + u32 num_channels{}; + std::atomic<bool> should_flush{}; + TimeStretcher time_stretch; +}; + +SDLSink::SDLSink(std::string_view target_device_name) { + if (!SDL_WasInit(SDL_INIT_AUDIO)) { + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError()); + return; + } + } + + if (target_device_name != auto_device_name && !target_device_name.empty()) { + output_device = target_device_name; + } else { + output_device.clear(); + } +} + +SDLSink::~SDLSink() = default; + +SinkStream& SDLSink::AcquireSinkStream(u32 sample_rate, u32 num_channels, const std::string&) { + sink_streams.push_back( + std::make_unique<SDLSinkStream>(sample_rate, num_channels, output_device)); + return *sink_streams.back(); +} + +std::vector<std::string> ListSDLSinkDevices() { + std::vector<std::string> device_list; + + if (!SDL_WasInit(SDL_INIT_AUDIO)) { + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError()); + return {}; + } + } + + const int device_count = SDL_GetNumAudioDevices(0); + for (int i = 0; i < device_count; ++i) { + device_list.emplace_back(SDL_GetAudioDeviceName(i, 0)); + } + + return device_list; +} + +} // namespace AudioCore diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h new file mode 100644 index 000000000..8ec1526d8 --- /dev/null +++ b/src/audio_core/sdl2_sink.h @@ -0,0 +1,29 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <vector> + +#include "audio_core/sink.h" + +namespace AudioCore { + +class SDLSink final : public Sink { +public: + explicit SDLSink(std::string_view device_id); + ~SDLSink() override; + + SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels, + const std::string& name) override; + +private: + std::string output_device; + std::vector<SinkStreamPtr> sink_streams; +}; + +std::vector<std::string> ListSDLSinkDevices(); + +} // namespace AudioCore diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp index a848eb1c9..de10aecd2 100644 --- a/src/audio_core/sink_details.cpp +++ b/src/audio_core/sink_details.cpp @@ -11,6 +11,9 @@ #ifdef HAVE_CUBEB #include "audio_core/cubeb_sink.h" #endif +#ifdef HAVE_SDL2 +#include "audio_core/sdl2_sink.h" +#endif #include "common/logging/log.h" namespace AudioCore { @@ -36,6 +39,13 @@ constexpr SinkDetails sink_details[] = { }, &ListCubebSinkDevices}, #endif +#ifdef HAVE_SDL2 + SinkDetails{"sdl2", + [](std::string_view device_id) -> std::unique_ptr<Sink> { + return std::make_unique<SDLSink>(device_id); + }, + &ListSDLSinkDevices}, +#endif SinkDetails{"null", [](std::string_view device_id) -> std::unique_ptr<Sink> { return std::make_unique<NullSink>(device_id); diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp index f2b4939df..c1362631e 100644 --- a/src/common/detached_tasks.cpp +++ b/src/common/detached_tasks.cpp @@ -21,6 +21,8 @@ void DetachedTasks::WaitForAllTasks() { } DetachedTasks::~DetachedTasks() { + WaitForAllTasks(); + std::unique_lock lock{mutex}; ASSERT(count == 0); instance = nullptr; diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp index 710e88b39..077f34995 100644 --- a/src/common/fs/file.cpp +++ b/src/common/fs/file.cpp @@ -172,7 +172,7 @@ std::string ReadStringFromFile(const std::filesystem::path& path, FileType type) size_t WriteStringToFile(const std::filesystem::path& path, FileType type, std::string_view string) { - if (!IsFile(path)) { + if (Exists(path) && !IsFile(path)) { return 0; } @@ -183,7 +183,7 @@ size_t WriteStringToFile(const std::filesystem::path& path, FileType type, size_t AppendStringToFile(const std::filesystem::path& path, FileType type, std::string_view string) { - if (!IsFile(path)) { + if (Exists(path) && !IsFile(path)) { return 0; } diff --git a/src/common/fs/file.h b/src/common/fs/file.h index 0f10b6003..588fe619d 100644 --- a/src/common/fs/file.h +++ b/src/common/fs/file.h @@ -49,7 +49,7 @@ void OpenFileStream(FileStream& file_stream, const Path& path, std::ios_base::op /** * Reads an entire file at path and returns a string of the contents read from the file. - * If the filesystem object at path is not a file, this function returns an empty string. + * If the filesystem object at path is not a regular file, this function returns an empty string. * * @param path Filesystem path * @param type File type @@ -72,7 +72,8 @@ template <typename Path> /** * Writes a string to a file at path and returns the number of characters successfully written. * If a file already exists at path, its contents will be erased. - * If the filesystem object at path is not a file, this function returns 0. + * If a file does not exist at path, it creates and opens a new empty file for writing. + * If the filesystem object at path exists and is not a regular file, this function returns 0. * * @param path Filesystem path * @param type File type @@ -95,7 +96,8 @@ template <typename Path> /** * Appends a string to a file at path and returns the number of characters successfully written. - * If the filesystem object at path is not a file, this function returns 0. + * If a file does not exist at path, it creates and opens a new empty file for appending. + * If the filesystem object at path exists and is not a regular file, this function returns 0. * * @param path Filesystem path * @param type File type @@ -394,11 +396,11 @@ public: [[nodiscard]] size_t WriteString(std::span<const char> string) const; /** - * Flushes any unwritten buffered data into the file. + * Attempts to flush any unwritten buffered data into the file and flush the file into the disk. * * @returns True if the flush was successful, false otherwise. */ - [[nodiscard]] bool Flush() const; + bool Flush() const; /** * Resizes the file to a given size. diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index d3159e908..9089cad67 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -135,8 +135,9 @@ std::shared_ptr<IOFile> FileOpen(const fs::path& path, FileAccessMode mode, File return nullptr; } - if (!IsFile(path)) { - LOG_ERROR(Common_Filesystem, "Filesystem object at path={} is not a file", + if (Exists(path) && !IsFile(path)) { + LOG_ERROR(Common_Filesystem, + "Filesystem object at path={} exists and is not a regular file", PathToUTF8String(path)); return nullptr; } diff --git a/src/common/fs/fs.h b/src/common/fs/fs.h index f6f256349..183126de3 100644 --- a/src/common/fs/fs.h +++ b/src/common/fs/fs.h @@ -48,18 +48,18 @@ template <typename Path> * * Failures occur when: * - Input path is not valid - * - Filesystem object at path is not a file + * - Filesystem object at path is not a regular file * - Filesystem at path is read only * * @param path Filesystem path * * @returns True if file removal succeeds or file does not exist, false otherwise. */ -[[nodiscard]] bool RemoveFile(const std::filesystem::path& path); +bool RemoveFile(const std::filesystem::path& path); #ifdef _WIN32 template <typename Path> -[[nodiscard]] bool RemoveFile(const Path& path) { +bool RemoveFile(const Path& path) { if constexpr (IsChar<typename Path::value_type>) { return RemoveFile(ToU8String(path)); } else { @@ -74,7 +74,7 @@ template <typename Path> * Failures occur when: * - One or both input path(s) is not valid * - Filesystem object at old_path does not exist - * - Filesystem object at old_path is not a file + * - Filesystem object at old_path is not a regular file * - Filesystem object at new_path exists * - Filesystem at either path is read only * @@ -110,8 +110,8 @@ template <typename Path1, typename Path2> * * Failures occur when: * - Input path is not valid - * - Filesystem object at path is not a file - * - The file is not opened + * - Filesystem object at path exists and is not a regular file + * - The file is not open * * @param path Filesystem path * @param mode File access mode @@ -251,11 +251,11 @@ template <typename Path> * * @returns True if directory removal succeeds or directory does not exist, false otherwise. */ -[[nodiscard]] bool RemoveDir(const std::filesystem::path& path); +bool RemoveDir(const std::filesystem::path& path); #ifdef _WIN32 template <typename Path> -[[nodiscard]] bool RemoveDir(const Path& path) { +bool RemoveDir(const Path& path) { if constexpr (IsChar<typename Path::value_type>) { return RemoveDir(ToU8String(path)); } else { @@ -276,11 +276,11 @@ template <typename Path> * * @returns True if the directory and all of its contents are removed successfully, false otherwise. */ -[[nodiscard]] bool RemoveDirRecursively(const std::filesystem::path& path); +bool RemoveDirRecursively(const std::filesystem::path& path); #ifdef _WIN32 template <typename Path> -[[nodiscard]] bool RemoveDirRecursively(const Path& path) { +bool RemoveDirRecursively(const Path& path) { if constexpr (IsChar<typename Path::value_type>) { return RemoveDirRecursively(ToU8String(path)); } else { @@ -301,11 +301,11 @@ template <typename Path> * * @returns True if all of the directory's contents are removed successfully, false otherwise. */ -[[nodiscard]] bool RemoveDirContentsRecursively(const std::filesystem::path& path); +bool RemoveDirContentsRecursively(const std::filesystem::path& path); #ifdef _WIN32 template <typename Path> -[[nodiscard]] bool RemoveDirContentsRecursively(const Path& path) { +bool RemoveDirContentsRecursively(const Path& path) { if constexpr (IsChar<typename Path::value_type>) { return RemoveDirContentsRecursively(ToU8String(path)); } else { @@ -435,11 +435,13 @@ template <typename Path> #endif /** - * Returns whether a filesystem object at path is a file. + * Returns whether a filesystem object at path is a regular file. + * A regular file is a file that stores text or binary data. + * It is not a directory, symlink, FIFO, socket, block device, or character device. * * @param path Filesystem path * - * @returns True if a filesystem object at path is a file, false otherwise. + * @returns True if a filesystem object at path is a regular file, false otherwise. */ [[nodiscard]] bool IsFile(const std::filesystem::path& path); diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 8bd70abc7..2a5a7596c 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -34,7 +34,7 @@ constexpr size_t HugePageSize = 0x200000; // Manually imported for MinGW compatibility #ifndef MEM_RESERVE_PLACEHOLDER -#define MEM_RESERVE_PLACEHOLDER 0x0004000 +#define MEM_RESERVE_PLACEHOLDER 0x00040000 #endif #ifndef MEM_REPLACE_PLACEHOLDER #define MEM_REPLACE_PLACEHOLDER 0x00004000 diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index d5cff400f..47ce06478 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -159,7 +159,7 @@ FileBackend::FileBackend(const std::filesystem::path& filename) { // Existence checks are done within the functions themselves. // We don't particularly care if these succeed or not. - void(FS::RemoveFile(old_filename)); + FS::RemoveFile(old_filename); void(FS::RenameFile(filename, old_filename)); file = @@ -186,7 +186,7 @@ void FileBackend::Write(const Entry& entry) { bytes_written += file->WriteString(FormatLogMessage(entry).append(1, '\n')); if (entry.log_level >= Level::Error) { - void(file->Flush()); + file->Flush(); } } diff --git a/src/common/settings.cpp b/src/common/settings.cpp index ab5cbe67b..e1bb4b7ff 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -123,6 +123,7 @@ void RestoreGlobalState(bool is_powered_on) { values.cpu_accuracy.SetGlobal(true); values.cpuopt_unsafe_unfuse_fma.SetGlobal(true); values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true); + values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true); values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true); values.cpuopt_unsafe_fastmem_check.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index a1c0bf3ad..82ec18e27 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -129,6 +129,7 @@ struct Values { Setting<bool> cpuopt_unsafe_unfuse_fma; Setting<bool> cpuopt_unsafe_reduce_fp_error; + Setting<bool> cpuopt_unsafe_ignore_standard_fpcr; Setting<bool> cpuopt_unsafe_inaccurate_nan; Setting<bool> cpuopt_unsafe_fastmem_check; @@ -149,6 +150,7 @@ struct Values { Setting<bool> use_nvdec_emulation; Setting<bool> accelerate_astc; Setting<bool> use_vsync; + Setting<bool> disable_fps_limit; Setting<bool> use_assembly_shaders; Setting<bool> use_asynchronous_shaders; Setting<bool> use_fast_gpu_time; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index efb851f5a..83b5b7676 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -139,6 +139,7 @@ add_library(core STATIC frontend/input.h hardware_interrupt_manager.cpp hardware_interrupt_manager.h + hle/api_version.h hle/ipc.h hle/ipc_helpers.h hle/kernel/board/nintendo/nx/k_system_control.cpp @@ -550,6 +551,8 @@ add_library(core STATIC hle/service/spl/module.h hle/service/spl/spl.cpp hle/service/spl/spl.h + hle/service/spl/spl_results.h + hle/service/spl/spl_types.h hle/service/ssl/ssl.cpp hle/service/ssl/ssl.h hle/service/time/clock_types.h diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index c8f6dc765..f871f7bf4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -186,6 +186,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; } + if (Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue()) { + config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; + } if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; } diff --git a/src/core/core.cpp b/src/core/core.cpp index c5004b7b4..e6f1aa0e7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <array> +#include <atomic> #include <memory> #include <utility> @@ -377,7 +378,7 @@ struct System::Impl { std::unique_ptr<Core::DeviceMemory> device_memory; Core::Memory::Memory memory; CpuManager cpu_manager; - bool is_powered_on = false; + std::atomic_bool is_powered_on{}; bool exit_lock = false; Reporter reporter; @@ -463,7 +464,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st } bool System::IsPoweredOn() const { - return impl->is_powered_on; + return impl->is_powered_on.load(std::memory_order::relaxed); } void System::PrepareReschedule() { diff --git a/src/core/file_sys/system_archive/system_version.cpp b/src/core/file_sys/system_archive/system_version.cpp index 54704105b..9b76d007e 100644 --- a/src/core/file_sys/system_archive/system_version.cpp +++ b/src/core/file_sys/system_archive/system_version.cpp @@ -4,47 +4,29 @@ #include "core/file_sys/system_archive/system_version.h" #include "core/file_sys/vfs_vector.h" +#include "core/hle/api_version.h" namespace FileSys::SystemArchive { -namespace SystemVersionData { - -// This section should reflect the best system version to describe yuzu's HLE api. -// TODO(DarkLordZach): Update when HLE gets better. - -constexpr u8 VERSION_MAJOR = 11; -constexpr u8 VERSION_MINOR = 0; -constexpr u8 VERSION_MICRO = 1; - -constexpr u8 REVISION_MAJOR = 1; -constexpr u8 REVISION_MINOR = 0; - -constexpr char PLATFORM_STRING[] = "NX"; -constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf"; -constexpr char DISPLAY_VERSION[] = "11.0.1"; -constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0"; - -} // namespace SystemVersionData - std::string GetLongDisplayVersion() { - return SystemVersionData::DISPLAY_TITLE; + return HLE::ApiVersion::DISPLAY_TITLE; } VirtualDir SystemVersion() { VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file"); - file->WriteObject(SystemVersionData::VERSION_MAJOR, 0); - file->WriteObject(SystemVersionData::VERSION_MINOR, 1); - file->WriteObject(SystemVersionData::VERSION_MICRO, 2); - file->WriteObject(SystemVersionData::REVISION_MAJOR, 4); - file->WriteObject(SystemVersionData::REVISION_MINOR, 5); - file->WriteArray(SystemVersionData::PLATFORM_STRING, - std::min<u64>(sizeof(SystemVersionData::PLATFORM_STRING), 0x20ULL), 0x8); - file->WriteArray(SystemVersionData::VERSION_HASH, - std::min<u64>(sizeof(SystemVersionData::VERSION_HASH), 0x40ULL), 0x28); - file->WriteArray(SystemVersionData::DISPLAY_VERSION, - std::min<u64>(sizeof(SystemVersionData::DISPLAY_VERSION), 0x18ULL), 0x68); - file->WriteArray(SystemVersionData::DISPLAY_TITLE, - std::min<u64>(sizeof(SystemVersionData::DISPLAY_TITLE), 0x80ULL), 0x80); + file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0); + file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1); + file->WriteObject(HLE::ApiVersion::HOS_VERSION_MICRO, 2); + file->WriteObject(HLE::ApiVersion::SDK_REVISION_MAJOR, 4); + file->WriteObject(HLE::ApiVersion::SDK_REVISION_MINOR, 5); + file->WriteArray(HLE::ApiVersion::PLATFORM_STRING, + std::min<u64>(sizeof(HLE::ApiVersion::PLATFORM_STRING), 0x20ULL), 0x8); + file->WriteArray(HLE::ApiVersion::VERSION_HASH, + std::min<u64>(sizeof(HLE::ApiVersion::VERSION_HASH), 0x40ULL), 0x28); + file->WriteArray(HLE::ApiVersion::DISPLAY_VERSION, + std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_VERSION), 0x18ULL), 0x68); + file->WriteArray(HLE::ApiVersion::DISPLAY_TITLE, + std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_TITLE), 0x80ULL), 0x80); return std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{file}, std::vector<VirtualDir>{}, "data"); } diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index d0b8fd046..3dad54f49 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -24,17 +24,12 @@ constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(Mode mode) { case Mode::Read: return FS::FileAccessMode::Read; case Mode::Write: - return FS::FileAccessMode::Write; case Mode::ReadWrite: - return FS::FileAccessMode::ReadWrite; case Mode::Append: - return FS::FileAccessMode::Append; case Mode::ReadAppend: - return FS::FileAccessMode::ReadAppend; case Mode::WriteAppend: - return FS::FileAccessMode::Append; case Mode::All: - return FS::FileAccessMode::ReadAppend; + return FS::FileAccessMode::ReadWrite; default: return {}; } diff --git a/src/core/hle/api_version.h b/src/core/hle/api_version.h new file mode 100644 index 000000000..811732179 --- /dev/null +++ b/src/core/hle/api_version.h @@ -0,0 +1,38 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/common_types.h" + +// This file contains yuzu's HLE API version constants. + +namespace HLE::ApiVersion { + +// Horizon OS version constants. + +constexpr u8 HOS_VERSION_MAJOR = 11; +constexpr u8 HOS_VERSION_MINOR = 0; +constexpr u8 HOS_VERSION_MICRO = 1; + +// NintendoSDK version constants. + +constexpr u8 SDK_REVISION_MAJOR = 1; +constexpr u8 SDK_REVISION_MINOR = 0; + +constexpr char PLATFORM_STRING[] = "NX"; +constexpr char VERSION_HASH[] = "69103fcb2004dace877094c2f8c29e6113be5dbf"; +constexpr char DISPLAY_VERSION[] = "11.0.1"; +constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.1-1.0"; + +// Atmosphere version constants. + +constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 0; +constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 19; +constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 4; + +constexpr u32 GetTargetFirmware() { + return u32{HOS_VERSION_MAJOR} << 24 | u32{HOS_VERSION_MINOR} << 16 | + u32{HOS_VERSION_MICRO} << 8 | 0U; +} + +} // namespace HLE::ApiVersion diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index da88f35bc..0c4bba66b 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp @@ -79,6 +79,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) { R_UNLESS(current_values[index] <= value, ResultInvalidState); limit_values[index] = value; + peak_values[index] = current_values[index]; return ResultSuccess; } diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp index a2844ea8c..dc15cf58b 100644 --- a/src/core/hle/service/bcat/backend/boxcat.cpp +++ b/src/core/hle/service/bcat/backend/boxcat.cpp @@ -313,7 +313,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { - void(Common::FS::RemoveFile(zip_path)); + Common::FS::RemoveFile(zip_path); } HandleDownloadDisplayResult(applet_manager, res); @@ -445,7 +445,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { - void(Common::FS::RemoveFile(bin_file_path)); + Common::FS::RemoveFile(bin_file_path); } HandleDownloadDisplayResult(applet_manager, res); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 7acad3798..1eb02aee2 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -314,6 +314,8 @@ void Controller_NPad::OnInit() { void Controller_NPad::OnLoadInputDevices() { const auto& players = Settings::values.players.GetValue(); + + std::lock_guard lock{mutex}; for (std::size_t i = 0; i < players.size(); ++i) { std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, @@ -348,6 +350,8 @@ void Controller_NPad::OnRelease() { } void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { + std::lock_guard lock{mutex}; + const auto controller_idx = NPadIdToIndex(npad_id); const auto controller_type = connected_controllers[controller_idx].type; if (!connected_controllers[controller_idx].is_connected) { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index c050c9a44..1409d82a2 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -6,6 +6,8 @@ #include <array> #include <atomic> +#include <mutex> + #include "common/bit_field.h" #include "common/common_types.h" #include "common/quaternion.h" @@ -563,6 +565,8 @@ private: using MotionArray = std::array< std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>, 10>; + + std::mutex mutex; ButtonArray buttons; StickArray sticks; VibrationArray vibrations; diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index d1dbc659b..1d810562f 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -307,6 +307,9 @@ void NVFlinger::Compose() { } s64 NVFlinger::GetNextTicks() const { + if (Settings::values.disable_fps_limit.GetValue()) { + return 0; + } constexpr s64 max_hertz = 120LL; return (1000000000 * (1LL << swap_interval)) / max_hertz; } diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp index 1beca417c..9c7f89475 100644 --- a/src/core/hle/service/spl/csrng.cpp +++ b/src/core/hle/service/spl/csrng.cpp @@ -9,7 +9,7 @@ namespace Service::SPL { CSRNG::CSRNG(Core::System& system_, std::shared_ptr<Module> module_) : Interface(system_, std::move(module_), "csrng") { static const FunctionInfo functions[] = { - {0, &CSRNG::GetRandomBytes, "GetRandomBytes"}, + {0, &CSRNG::GenerateRandomBytes, "GenerateRandomBytes"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index 0b5e2b7c3..ebb179aa8 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp @@ -10,6 +10,7 @@ #include <vector> #include "common/logging/log.h" #include "common/settings.h" +#include "core/hle/api_version.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/spl/csrng.h" #include "core/hle/service/spl/module.h" @@ -24,7 +25,46 @@ Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> modu Module::Interface::~Interface() = default; -void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { +void Module::Interface::GetConfig(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto config_item = rp.PopEnum<ConfigItem>(); + + // This should call svcCallSecureMonitor with the appropriate args. + // Since we do not have it implemented yet, we will use this for now. + const auto smc_result = GetConfigImpl(config_item); + const auto result_code = smc_result.Code(); + + if (smc_result.Failed()) { + LOG_ERROR(Service_SPL, "called, config_item={}, result_code={}", config_item, + result_code.raw); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result_code); + } + + LOG_DEBUG(Service_SPL, "called, config_item={}, result_code={}, smc_result={}", config_item, + result_code.raw, *smc_result); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(result_code); + rb.Push(*smc_result); +} + +void Module::Interface::ModularExponentiate(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("ModularExponentiate is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::SetConfig(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("SetConfig is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::GenerateRandomBytes(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SPL, "called"); const std::size_t size = ctx.GetWriteBufferSize(); @@ -39,6 +79,88 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Module::Interface::IsDevelopment(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("IsDevelopment is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::SetBootReason(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("SetBootReason is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +void Module::Interface::GetBootReason(Kernel::HLERequestContext& ctx) { + UNIMPLEMENTED_MSG("GetBootReason is not implemented!"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSecureMonitorNotImplemented); +} + +ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const { + switch (config_item) { + case ConfigItem::DisableProgramVerification: + case ConfigItem::DramId: + case ConfigItem::SecurityEngineInterruptNumber: + case ConfigItem::FuseVersion: + case ConfigItem::HardwareType: + case ConfigItem::HardwareState: + case ConfigItem::IsRecoveryBoot: + case ConfigItem::DeviceId: + case ConfigItem::BootReason: + case ConfigItem::MemoryMode: + case ConfigItem::IsDevelopmentFunctionEnabled: + case ConfigItem::KernelConfiguration: + case ConfigItem::IsChargerHiZModeEnabled: + case ConfigItem::QuestState: + case ConfigItem::RegulatorType: + case ConfigItem::DeviceUniqueKeyGeneration: + case ConfigItem::Package2Hash: + return ResultSecureMonitorNotImplemented; + case ConfigItem::ExosphereApiVersion: + // Get information about the current exosphere version. + return MakeResult((u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MAJOR} << 56) | + (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MINOR} << 48) | + (u64{HLE::ApiVersion::ATMOSPHERE_RELEASE_VERSION_MICRO} << 40) | + (static_cast<u64>(HLE::ApiVersion::GetTargetFirmware()))); + case ConfigItem::ExosphereNeedsReboot: + // We are executing, so we aren't in the process of rebooting. + return MakeResult(u64{0}); + case ConfigItem::ExosphereNeedsShutdown: + // We are executing, so we aren't in the process of shutting down. + return MakeResult(u64{0}); + case ConfigItem::ExosphereGitCommitHash: + // Get information about the current exosphere git commit hash. + return MakeResult(u64{0}); + case ConfigItem::ExosphereHasRcmBugPatch: + // Get information about whether this unit has the RCM bug patched. + return MakeResult(u64{0}); + case ConfigItem::ExosphereBlankProdInfo: + // Get whether this unit should simulate a "blanked" PRODINFO. + return MakeResult(u64{0}); + case ConfigItem::ExosphereAllowCalWrites: + // Get whether this unit should allow writing to the calibration partition. + return MakeResult(u64{0}); + case ConfigItem::ExosphereEmummcType: + // Get what kind of emummc this unit has active. + return MakeResult(u64{0}); + case ConfigItem::ExospherePayloadAddress: + // Gets the physical address of the reboot payload buffer, if one exists. + return ResultSecureMonitorNotInitialized; + case ConfigItem::ExosphereLogConfiguration: + // Get the log configuration. + return MakeResult(u64{0}); + case ConfigItem::ExosphereForceEnableUsb30: + // Get whether usb 3.0 should be force-enabled. + return MakeResult(u64{0}); + default: + return ResultSecureMonitorInvalidArgument; + } +} + void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { auto module = std::make_shared<Module>(); std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager); diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h index 71855c1bf..61630df80 100644 --- a/src/core/hle/service/spl/module.h +++ b/src/core/hle/service/spl/module.h @@ -6,6 +6,8 @@ #include <random> #include "core/hle/service/service.h" +#include "core/hle/service/spl/spl_results.h" +#include "core/hle/service/spl/spl_types.h" namespace Core { class System; @@ -21,12 +23,21 @@ public: const char* name); ~Interface() override; - void GetRandomBytes(Kernel::HLERequestContext& ctx); + // General + void GetConfig(Kernel::HLERequestContext& ctx); + void ModularExponentiate(Kernel::HLERequestContext& ctx); + void SetConfig(Kernel::HLERequestContext& ctx); + void GenerateRandomBytes(Kernel::HLERequestContext& ctx); + void IsDevelopment(Kernel::HLERequestContext& ctx); + void SetBootReason(Kernel::HLERequestContext& ctx); + void GetBootReason(Kernel::HLERequestContext& ctx); protected: std::shared_ptr<Module> module; private: + ResultVal<u64> GetConfigImpl(ConfigItem config_item) const; + std::mt19937 rng; }; }; diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp index fff3f3c42..20384042f 100644 --- a/src/core/hle/service/spl/spl.cpp +++ b/src/core/hle/service/spl/spl.cpp @@ -10,13 +10,13 @@ SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_) : Interface(system_, std::move(module_), "spl:") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetConfig"}, - {1, nullptr, "ModularExponentiate"}, - {5, nullptr, "SetConfig"}, - {7, &SPL::GetRandomBytes, "GetRandomBytes"}, - {11, nullptr, "IsDevelopment"}, - {24, nullptr, "SetBootReason"}, - {25, nullptr, "GetBootReason"}, + {0, &SPL::GetConfig, "GetConfig"}, + {1, &SPL::ModularExponentiate, "ModularExponentiate"}, + {5, &SPL::SetConfig, "SetConfig"}, + {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"}, + {11, &SPL::IsDevelopment, "IsDevelopment"}, + {24, &SPL::SetBootReason, "SetBootReason"}, + {25, &SPL::GetBootReason, "GetBootReason"}, }; // clang-format on @@ -27,22 +27,22 @@ SPL_MIG::SPL_MIG(Core::System& system_, std::shared_ptr<Module> module_) : Interface(system_, std::move(module_), "spl:mig") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetConfig"}, - {1, nullptr, "ModularExponentiate"}, + {0, &SPL::GetConfig, "GetConfig"}, + {1, &SPL::ModularExponentiate, "ModularExponentiate"}, {2, nullptr, "GenerateAesKek"}, {3, nullptr, "LoadAesKey"}, {4, nullptr, "GenerateAesKey"}, - {5, nullptr, "SetConfig"}, - {7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, - {11, nullptr, "IsDevelopment"}, + {5, &SPL::SetConfig, "SetConfig"}, + {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"}, + {11, &SPL::IsDevelopment, "IsDevelopment"}, {14, nullptr, "DecryptAesKey"}, {15, nullptr, "CryptAesCtr"}, {16, nullptr, "ComputeCmac"}, {21, nullptr, "AllocateAesKeyslot"}, {22, nullptr, "DeallocateAesKeySlot"}, {23, nullptr, "GetAesKeyslotAvailableEvent"}, - {24, nullptr, "SetBootReason"}, - {25, nullptr, "GetBootReason"}, + {24, &SPL::SetBootReason, "SetBootReason"}, + {25, &SPL::GetBootReason, "GetBootReason"}, }; // clang-format on @@ -53,16 +53,16 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_) : Interface(system_, std::move(module_), "spl:fs") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetConfig"}, - {1, nullptr, "ModularExponentiate"}, + {0, &SPL::GetConfig, "GetConfig"}, + {1, &SPL::ModularExponentiate, "ModularExponentiate"}, {2, nullptr, "GenerateAesKek"}, {3, nullptr, "LoadAesKey"}, {4, nullptr, "GenerateAesKey"}, - {5, nullptr, "SetConfig"}, - {7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, + {5, &SPL::SetConfig, "SetConfig"}, + {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"}, {9, nullptr, "ImportLotusKey"}, {10, nullptr, "DecryptLotusMessage"}, - {11, nullptr, "IsDevelopment"}, + {11, &SPL::IsDevelopment, "IsDevelopment"}, {12, nullptr, "GenerateSpecificAesKey"}, {14, nullptr, "DecryptAesKey"}, {15, nullptr, "CryptAesCtr"}, @@ -71,8 +71,8 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_) {21, nullptr, "AllocateAesKeyslot"}, {22, nullptr, "DeallocateAesKeySlot"}, {23, nullptr, "GetAesKeyslotAvailableEvent"}, - {24, nullptr, "SetBootReason"}, - {25, nullptr, "GetBootReason"}, + {24, &SPL::SetBootReason, "SetBootReason"}, + {25, &SPL::GetBootReason, "GetBootReason"}, {31, nullptr, "GetPackage2Hash"}, }; // clang-format on @@ -84,14 +84,14 @@ SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_) : Interface(system_, std::move(module_), "spl:ssl") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetConfig"}, - {1, nullptr, "ModularExponentiate"}, + {0, &SPL::GetConfig, "GetConfig"}, + {1, &SPL::ModularExponentiate, "ModularExponentiate"}, {2, nullptr, "GenerateAesKek"}, {3, nullptr, "LoadAesKey"}, {4, nullptr, "GenerateAesKey"}, - {5, nullptr, "SetConfig"}, - {7, &SPL::GetRandomBytes, "GetRandomBytes"}, - {11, nullptr, "IsDevelopment"}, + {5, &SPL::SetConfig, "SetConfig"}, + {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"}, + {11, &SPL::IsDevelopment, "IsDevelopment"}, {13, nullptr, "DecryptDeviceUniqueData"}, {14, nullptr, "DecryptAesKey"}, {15, nullptr, "CryptAesCtr"}, @@ -99,8 +99,8 @@ SPL_SSL::SPL_SSL(Core::System& system_, std::shared_ptr<Module> module_) {21, nullptr, "AllocateAesKeyslot"}, {22, nullptr, "DeallocateAesKeySlot"}, {23, nullptr, "GetAesKeyslotAvailableEvent"}, - {24, nullptr, "SetBootReason"}, - {25, nullptr, "GetBootReason"}, + {24, &SPL::SetBootReason, "SetBootReason"}, + {25, &SPL::GetBootReason, "GetBootReason"}, {26, nullptr, "DecryptAndStoreSslClientCertKey"}, {27, nullptr, "ModularExponentiateWithSslClientCertKey"}, }; @@ -113,14 +113,14 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_) : Interface(system_, std::move(module_), "spl:es") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetConfig"}, - {1, nullptr, "ModularExponentiate"}, + {0, &SPL::GetConfig, "GetConfig"}, + {1, &SPL::ModularExponentiate, "ModularExponentiate"}, {2, nullptr, "GenerateAesKek"}, {3, nullptr, "LoadAesKey"}, {4, nullptr, "GenerateAesKey"}, - {5, nullptr, "SetConfig"}, - {7, &SPL::GetRandomBytes, "GenerateRandomBytes"}, - {11, nullptr, "IsDevelopment"}, + {5, &SPL::SetConfig, "SetConfig"}, + {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"}, + {11, &SPL::IsDevelopment, "IsDevelopment"}, {13, nullptr, "DecryptDeviceUniqueData"}, {14, nullptr, "DecryptAesKey"}, {15, nullptr, "CryptAesCtr"}, @@ -131,8 +131,8 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_) {21, nullptr, "AllocateAesKeyslot"}, {22, nullptr, "DeallocateAesKeySlot"}, {23, nullptr, "GetAesKeyslotAvailableEvent"}, - {24, nullptr, "SetBootReason"}, - {25, nullptr, "GetBootReason"}, + {24, &SPL::SetBootReason, "SetBootReason"}, + {25, &SPL::GetBootReason, "GetBootReason"}, {28, nullptr, "DecryptAndStoreDrmDeviceCertKey"}, {29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"}, {31, nullptr, "PrepareEsArchiveKey"}, @@ -147,14 +147,14 @@ SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_) : Interface(system_, std::move(module_), "spl:manu") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetConfig"}, - {1, nullptr, "ModularExponentiate"}, + {0, &SPL::GetConfig, "GetConfig"}, + {1, &SPL::ModularExponentiate, "ModularExponentiate"}, {2, nullptr, "GenerateAesKek"}, {3, nullptr, "LoadAesKey"}, {4, nullptr, "GenerateAesKey"}, - {5, nullptr, "SetConfig"}, - {7, &SPL::GetRandomBytes, "GetRandomBytes"}, - {11, nullptr, "IsDevelopment"}, + {5, &SPL::SetConfig, "SetConfig"}, + {7, &SPL::GenerateRandomBytes, "GenerateRandomBytes"}, + {11, &SPL::IsDevelopment, "IsDevelopment"}, {13, nullptr, "DecryptDeviceUniqueData"}, {14, nullptr, "DecryptAesKey"}, {15, nullptr, "CryptAesCtr"}, @@ -162,8 +162,8 @@ SPL_MANU::SPL_MANU(Core::System& system_, std::shared_ptr<Module> module_) {21, nullptr, "AllocateAesKeyslot"}, {22, nullptr, "DeallocateAesKeySlot"}, {23, nullptr, "GetAesKeyslotAvailableEvent"}, - {24, nullptr, "SetBootReason"}, - {25, nullptr, "GetBootReason"}, + {24, &SPL::SetBootReason, "SetBootReason"}, + {25, &SPL::GetBootReason, "GetBootReason"}, {30, nullptr, "ReencryptDeviceUniqueData"}, }; // clang-format on diff --git a/src/core/hle/service/spl/spl_results.h b/src/core/hle/service/spl/spl_results.h new file mode 100644 index 000000000..878fa91b7 --- /dev/null +++ b/src/core/hle/service/spl/spl_results.h @@ -0,0 +1,29 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/result.h" + +namespace Service::SPL { + +// Description 0 - 99 +constexpr ResultCode ResultSecureMonitorError{ErrorModule::SPL, 0}; +constexpr ResultCode ResultSecureMonitorNotImplemented{ErrorModule::SPL, 1}; +constexpr ResultCode ResultSecureMonitorInvalidArgument{ErrorModule::SPL, 2}; +constexpr ResultCode ResultSecureMonitorBusy{ErrorModule::SPL, 3}; +constexpr ResultCode ResultSecureMonitorNoAsyncOperation{ErrorModule::SPL, 4}; +constexpr ResultCode ResultSecureMonitorInvalidAsyncOperation{ErrorModule::SPL, 5}; +constexpr ResultCode ResultSecureMonitorNotPermitted{ErrorModule::SPL, 6}; +constexpr ResultCode ResultSecureMonitorNotInitialized{ErrorModule::SPL, 7}; + +constexpr ResultCode ResultInvalidSize{ErrorModule::SPL, 100}; +constexpr ResultCode ResultUnknownSecureMonitorError{ErrorModule::SPL, 101}; +constexpr ResultCode ResultDecryptionFailed{ErrorModule::SPL, 102}; + +constexpr ResultCode ResultOutOfKeySlots{ErrorModule::SPL, 104}; +constexpr ResultCode ResultInvalidKeySlot{ErrorModule::SPL, 105}; +constexpr ResultCode ResultBootReasonAlreadySet{ErrorModule::SPL, 106}; +constexpr ResultCode ResultBootReasonNotSet{ErrorModule::SPL, 107}; +constexpr ResultCode ResultInvalidArgument{ErrorModule::SPL, 108}; + +} // namespace Service::SPL diff --git a/src/core/hle/service/spl/spl_types.h b/src/core/hle/service/spl/spl_types.h new file mode 100644 index 000000000..23c39f7ed --- /dev/null +++ b/src/core/hle/service/spl/spl_types.h @@ -0,0 +1,230 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <span> + +#include "common/bit_field.h" +#include "common/common_types.h" + +namespace Service::SPL { + +constexpr size_t AES_128_KEY_SIZE = 0x10; + +namespace Smc { + +enum class FunctionId : u32 { + SetConfig = 0xC3000401, + GetConfig = 0xC3000002, + GetResult = 0xC3000003, + GetResultData = 0xC3000404, + ModularExponentiate = 0xC3000E05, + GenerateRandomBytes = 0xC3000006, + GenerateAesKek = 0xC3000007, + LoadAesKey = 0xC3000008, + ComputeAes = 0xC3000009, + GenerateSpecificAesKey = 0xC300000A, + ComputeCmac = 0xC300040B, + ReencryptDeviceUniqueData = 0xC300D60C, + DecryptDeviceUniqueData = 0xC300100D, + + ModularExponentiateWithStorageKey = 0xC300060F, + PrepareEsDeviceUniqueKey = 0xC3000610, + LoadPreparedAesKey = 0xC3000011, + PrepareCommonEsTitleKey = 0xC3000012, + + // Deprecated functions. + LoadEsDeviceKey = 0xC300100C, + DecryptAndStoreGcKey = 0xC300100E, + + // Atmosphere functions. + AtmosphereIramCopy = 0xF0000201, + AtmosphereReadWriteRegister = 0xF0000002, + + AtmosphereGetEmummcConfig = 0xF0000404, +}; + +enum class CipherMode { + CbcEncrypt = 0, + CbcDecrypt = 1, + Ctr = 2, +}; + +enum class DeviceUniqueDataMode { + DecryptDeviceUniqueData = 0, + DecryptAndStoreGcKey = 1, + DecryptAndStoreEsDeviceKey = 2, + DecryptAndStoreSslKey = 3, + DecryptAndStoreDrmDeviceCertKey = 4, +}; + +enum class ModularExponentiateWithStorageKeyMode { + Gc = 0, + Ssl = 1, + DrmDeviceCert = 2, +}; + +enum class EsCommonKeyType { + TitleKey = 0, + ArchiveKey = 1, +}; + +struct AsyncOperationKey { + u64 value; +}; + +} // namespace Smc + +enum class HardwareType { + Icosa = 0, + Copper = 1, + Hoag = 2, + Iowa = 3, + Calcio = 4, + Aula = 5, +}; + +enum class SocType { + Erista = 0, + Mariko = 1, +}; + +enum class HardwareState { + Development = 0, + Production = 1, +}; + +enum class MemoryArrangement { + Standard = 0, + StandardForAppletDev = 1, + StandardForSystemDev = 2, + Expanded = 3, + ExpandedForAppletDev = 4, + + // Note: Dynamic is not official. + // Atmosphere uses it to maintain compatibility with firmwares prior to 6.0.0, + // which removed the explicit retrieval of memory arrangement from PM. + Dynamic = 5, + Count, +}; + +enum class BootReason { + Unknown = 0, + AcOk = 1, + OnKey = 2, + RtcAlarm1 = 3, + RtcAlarm2 = 4, +}; + +struct BootReasonValue { + union { + u32 value{}; + + BitField<0, 8, u32> power_intr; + BitField<8, 8, u32> rtc_intr; + BitField<16, 8, u32> nv_erc; + BitField<24, 8, u32> boot_reason; + }; +}; +static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!"); + +struct AesKey { + std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{}; + + std::span<u8> AsBytes() { + return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE}; + } + + std::span<const u8> AsBytes() const { + return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE}; + } +}; +static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "AesKey definition!"); + +struct IvCtr { + std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{}; + + std::span<u8> AsBytes() { + return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE}; + } + + std::span<const u8> AsBytes() const { + return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE}; + } +}; +static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "IvCtr definition!"); + +struct Cmac { + std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{}; + + std::span<u8> AsBytes() { + return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE}; + } + + std::span<const u8> AsBytes() const { + return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE}; + } +}; +static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "Cmac definition!"); + +struct AccessKey { + std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{}; + + std::span<u8> AsBytes() { + return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE}; + } + + std::span<const u8> AsBytes() const { + return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE}; + } +}; +static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "AccessKey definition!"); + +struct KeySource { + std::array<u64, AES_128_KEY_SIZE / sizeof(u64)> data64{}; + + std::span<u8> AsBytes() { + return std::span{reinterpret_cast<u8*>(data64.data()), AES_128_KEY_SIZE}; + } + + std::span<const u8> AsBytes() const { + return std::span{reinterpret_cast<const u8*>(data64.data()), AES_128_KEY_SIZE}; + } +}; +static_assert(sizeof(AesKey) == AES_128_KEY_SIZE, "KeySource definition!"); + +enum class ConfigItem : u32 { + // Standard config items. + DisableProgramVerification = 1, + DramId = 2, + SecurityEngineInterruptNumber = 3, + FuseVersion = 4, + HardwareType = 5, + HardwareState = 6, + IsRecoveryBoot = 7, + DeviceId = 8, + BootReason = 9, + MemoryMode = 10, + IsDevelopmentFunctionEnabled = 11, + KernelConfiguration = 12, + IsChargerHiZModeEnabled = 13, + QuestState = 14, + RegulatorType = 15, + DeviceUniqueKeyGeneration = 16, + Package2Hash = 17, + + // Extension config items for exosphere. + ExosphereApiVersion = 65000, + ExosphereNeedsReboot = 65001, + ExosphereNeedsShutdown = 65002, + ExosphereGitCommitHash = 65003, + ExosphereHasRcmBugPatch = 65004, + ExosphereBlankProdInfo = 65005, + ExosphereAllowCalWrites = 65006, + ExosphereEmummcType = 65007, + ExospherePayloadAddress = 65008, + ExosphereLogConfiguration = 65009, + ExosphereForceEnableUsb30 = 65010, +}; + +} // namespace Service::SPL diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp index bf4402308..c634b6abd 100644 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ b/src/core/hle/service/time/time_zone_content_manager.cpp @@ -125,7 +125,7 @@ ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& locati return ERROR_TIME_NOT_FOUND; } - vfs_file = zoneinfo_dir->GetFile(location_name); + vfs_file = zoneinfo_dir->GetFileRelative(location_name); if (!vfs_file) { LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", time_zone_binary_titleid, location_name); diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp index a335e6da1..3b052ffb2 100644 --- a/src/input_common/mouse/mouse_input.cpp +++ b/src/input_common/mouse/mouse_input.cpp @@ -2,25 +2,23 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include <stop_token> +#include <thread> + #include "common/settings.h" #include "input_common/mouse/mouse_input.h" namespace MouseInput { Mouse::Mouse() { - update_thread = std::thread(&Mouse::UpdateThread, this); + update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); } -Mouse::~Mouse() { - update_thread_running = false; - if (update_thread.joinable()) { - update_thread.join(); - } -} +Mouse::~Mouse() = default; -void Mouse::UpdateThread() { +void Mouse::UpdateThread(std::stop_token stop_token) { constexpr int update_time = 10; - while (update_thread_running) { + while (!stop_token.stop_requested()) { for (MouseInfo& info : mouse_info) { const Common::Vec3f angular_direction{ -info.tilt_direction.y, diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h index 5a971ad67..c8bae99c1 100644 --- a/src/input_common/mouse/mouse_input.h +++ b/src/input_common/mouse/mouse_input.h @@ -6,6 +6,7 @@ #include <array> #include <mutex> +#include <stop_token> #include <thread> #include "common/common_types.h" @@ -85,7 +86,7 @@ public: [[nodiscard]] const MouseData& GetMouseState(std::size_t button) const; private: - void UpdateThread(); + void UpdateThread(std::stop_token stop_token); void UpdateYuzuSettings(); void StopPanning(); @@ -105,12 +106,11 @@ private: u16 buttons{}; u16 toggle_buttons{}; u16 lock_buttons{}; - std::thread update_thread; + std::jthread update_thread; MouseButton last_button{MouseButton::Undefined}; std::array<MouseInfo, 7> mouse_info; Common::SPSCQueue<MouseStatus> mouse_queue; bool configuring{false}; - bool update_thread_running{true}; int mouse_panning_timout{}; }; } // namespace MouseInput diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index f968b5b16..07939432f 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -4,10 +4,10 @@ #pragma once -#include <atomic> #include <functional> #include <optional> #include <span> +#include <stop_token> #include "common/common_types.h" #include "video_core/engines/fermi_2d.h" #include "video_core/gpu.h" @@ -123,7 +123,7 @@ public: virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {} /// Initialize disk cached resources for the game being emulated - virtual void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading, + virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading, const DiskResourceLoadCallback& callback) {} /// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver. diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index f87bb269b..eb8bdaa85 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -351,7 +351,7 @@ void RasterizerOpenGL::SetupShaders(bool is_indexed) { } } -void RasterizerOpenGL::LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading, +void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_loading, const VideoCore::DiskResourceLoadCallback& callback) { shader_cache.LoadDiskCache(title_id, stop_loading, callback); } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 76298517f..9995a563b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -94,7 +94,7 @@ public: const Tegra::Engines::Fermi2D::Config& copy_config) override; bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) override; - void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading, + void LoadDiskResources(u64 title_id, std::stop_token stop_loading, const VideoCore::DiskResourceLoadCallback& callback) override; /// Returns true when there are commands queued to the OpenGL server. diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 5cf7cd151..5a01c59ec 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -331,7 +331,7 @@ ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer_, ShaderCacheOpenGL::~ShaderCacheOpenGL() = default; -void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading, +void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, std::stop_token stop_loading, const VideoCore::DiskResourceLoadCallback& callback) { disk_cache.BindTitleID(title_id); const std::optional transferable = disk_cache.LoadTransferable(); @@ -372,7 +372,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop const auto scope = context->Acquire(); for (std::size_t i = begin; i < end; ++i) { - if (stop_loading) { + if (stop_loading.stop_requested()) { return; } const auto& entry = (*transferable)[i]; @@ -435,7 +435,7 @@ void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop precompiled_cache_altered = true; return; } - if (stop_loading) { + if (stop_loading.stop_requested()) { return; } diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 2aed0697e..b30308b6f 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -127,7 +127,7 @@ public: ~ShaderCacheOpenGL() override; /// Loads disk cache for the current game - void LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading, + void LoadDiskCache(u64 title_id, std::stop_token stop_loading, const VideoCore::DiskResourceLoadCallback& callback); /// Gets the current specified shader stage program diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index db78ce3d9..6852c11b0 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp @@ -2,8 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <atomic> -#include <chrono> +#include <thread> #include "common/settings.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" @@ -12,8 +11,6 @@ namespace Vulkan { -using namespace std::chrono_literals; - MasterSemaphore::MasterSemaphore(const Device& device) { static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR, @@ -34,9 +31,9 @@ MasterSemaphore::MasterSemaphore(const Device& device) { // Validation layers have a bug where they fail to track resource usage when using timeline // semaphores and synchronizing with GetSemaphoreCounterValueKHR. To workaround this issue, have // a separate thread waiting for each timeline semaphore value. - debug_thread = std::thread([this] { + debug_thread = std::jthread([this](std::stop_token stop_token) { u64 counter = 0; - while (!shutdown) { + while (!stop_token.stop_requested()) { if (semaphore.Wait(counter, 10'000'000)) { ++counter; } @@ -44,13 +41,6 @@ MasterSemaphore::MasterSemaphore(const Device& device) { }); } -MasterSemaphore::~MasterSemaphore() { - shutdown = true; - - // This thread might not be started - if (debug_thread.joinable()) { - debug_thread.join(); - } -} +MasterSemaphore::~MasterSemaphore() = default; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 4b6d64daa..ee3cd35d0 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -65,11 +65,10 @@ public: } private: - vk::Semaphore semaphore; ///< Timeline semaphore. - std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. - std::atomic<u64> current_tick{1}; ///< Current logical tick. - std::atomic<bool> shutdown{false}; ///< True when the object is being destroyed. - std::thread debug_thread; ///< Debug thread to workaround validation layer bugs. + vk::Semaphore semaphore; ///< Timeline semaphore. + std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. + std::atomic<u64> current_tick{1}; ///< Current logical tick. + std::jthread debug_thread; ///< Debug thread to workaround validation layer bugs. }; } // namespace Vulkan diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 9680167ee..4efe042b6 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -1098,7 +1098,15 @@ std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const return std::nullopt; } const ImageInfo& existing = image.info; - if (False(options & RelaxedOptions::Format)) { + if (True(options & RelaxedOptions::Format)) { + // Format checking is relaxed, but we still have to check for matching bytes per block. + // This avoids creating a view for blits on UE4 titles where formats with different bytes + // per block are aliased. + if (BytesPerBlock(existing.format) != BytesPerBlock(candidate.format)) { + return std::nullopt; + } + } else { + // Format comaptibility is not relaxed, ensure we are creating a view on a compatible format if (!IsViewCompatible(existing.format, candidate.format, broken_views, native_bgr)) { return std::nullopt; } diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp index f0ee76519..758c038ba 100644 --- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp +++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp @@ -50,7 +50,7 @@ NsightAftermathTracker::NsightAftermathTracker() { } dump_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir) / "gpucrash"; - void(Common::FS::RemoveDirRecursively(dump_dir)); + Common::FS::RemoveDirRecursively(dump_dir); if (!Common::FS::CreateDir(dump_dir)) { LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory"); return; diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp index 5c64c9bf7..0f60765bb 100644 --- a/src/video_core/vulkan_common/vulkan_debug_callback.cpp +++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp @@ -12,6 +12,14 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* data, [[maybe_unused]] void* user_data) { + // Skip logging known false-positive validation errors + switch (static_cast<u32>(data->messageIdNumber)) { + case 0x682a878au: // VUID-vkCmdBindVertexBuffers2EXT-pBuffers-parameter + case 0x99fb7dfdu: // UNASSIGNED-RequiredParameter (vkCmdBindVertexBuffers2EXT pBuffers[0]) + return VK_FALSE; + default: + break; + } const std::string_view message{data->pMessage}; if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { LOG_CRITICAL(Render_Vulkan, "{}", message); diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 67183e64c..e04f7dfc6 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -100,8 +100,9 @@ struct Client::Impl { request.body = data; httplib::Response response; + httplib::Error error; - if (!cli->send(request, response)) { + if (!cli->send(request, response, error)) { LOG_ERROR(WebService, "{} to {} returned null", method, host + path); return WebResult{WebResult::Code::LibError, "Null response", ""}; } diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 86495803e..7524e3c40 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -51,11 +51,11 @@ void EmuThread::run() { Common::SetCurrentThreadName(name.c_str()); auto& system = Core::System::GetInstance(); + auto& gpu = system.GPU(); + auto stop_token = stop_source.get_token(); system.RegisterHostThread(); - auto& gpu = system.GPU(); - // Main process has been loaded. Make the context current to this thread and begin GPU and CPU // execution. gpu.Start(); @@ -65,7 +65,7 @@ void EmuThread::run() { emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); system.Renderer().ReadRasterizer()->LoadDiskResources( - system.CurrentProcess()->GetTitleID(), stop_run, + system.CurrentProcess()->GetTitleID(), stop_token, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { emit LoadProgress(stage, value, total); }); @@ -78,7 +78,7 @@ void EmuThread::run() { // so that the DebugModeLeft signal can be emitted before the // next execution step bool was_active = false; - while (!stop_run) { + while (!stop_token.stop_requested()) { if (running) { if (was_active) { emit DebugModeLeft(); @@ -100,7 +100,7 @@ void EmuThread::run() { } running_guard = false; - if (!stop_run) { + if (!stop_token.stop_requested()) { was_active = true; emit DebugModeEntered(); } @@ -108,7 +108,7 @@ void EmuThread::run() { UNIMPLEMENTED(); } else { std::unique_lock lock{running_mutex}; - running_cv.wait(lock, [this] { return IsRunning() || exec_step || stop_run; }); + running_cv.wait(lock, stop_token, [this] { return IsRunning() || exec_step; }); } } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index acfe2bc8c..402dd2ee1 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -89,16 +89,16 @@ public: * Requests for the emulation thread to stop running */ void RequestStop() { - stop_run = true; + stop_source.request_stop(); SetRunning(false); } private: bool exec_step = false; bool running = false; - std::atomic_bool stop_run{false}; + std::stop_source stop_source; std::mutex running_mutex; - std::condition_variable running_cv; + std::condition_variable_any running_cv; Common::Event running_wait{}; std::atomic_bool running_guard{false}; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 57843ac5a..62bafc453 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -221,7 +221,7 @@ const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default // This must be in alphabetical order according to action name as it must have the same order as // UISetting::values.shortcuts, which is alphabetically ordered. // clang-format off -const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{ +const std::array<UISettings::Shortcut, 18> Config::default_hotkeys{{ {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}}, {QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::ApplicationShortcut}}, {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}}, @@ -236,6 +236,7 @@ const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{ {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}}, {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}}, {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}}, + {QStringLiteral("Toggle Framerate Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}}, @@ -756,6 +757,8 @@ void Config::ReadCpuValues() { QStringLiteral("cpuopt_unsafe_unfuse_fma"), true); ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error, QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true); + ReadSettingGlobal(Settings::values.cpuopt_unsafe_ignore_standard_fpcr, + QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"), true); ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan, QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true); ReadSettingGlobal(Settings::values.cpuopt_unsafe_fastmem_check, @@ -811,6 +814,8 @@ void Config::ReadRendererValues() { true); ReadSettingGlobal(Settings::values.accelerate_astc, QStringLiteral("accelerate_astc"), true); ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true); + ReadSettingGlobal(Settings::values.disable_fps_limit, QStringLiteral("disable_fps_limit"), + false); ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"), false); ReadSettingGlobal(Settings::values.use_asynchronous_shaders, @@ -1340,6 +1345,8 @@ void Config::SaveCpuValues() { Settings::values.cpuopt_unsafe_unfuse_fma, true); WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), Settings::values.cpuopt_unsafe_reduce_fp_error, true); + WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_ignore_standard_fpcr"), + Settings::values.cpuopt_unsafe_ignore_standard_fpcr, true); WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"), Settings::values.cpuopt_unsafe_inaccurate_nan, true); WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_fastmem_check"), @@ -1396,6 +1403,8 @@ void Config::SaveRendererValues() { true); WriteSettingGlobal(QStringLiteral("accelerate_astc"), Settings::values.accelerate_astc, true); WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true); + WriteSettingGlobal(QStringLiteral("disable_fps_limit"), Settings::values.disable_fps_limit, + false); WriteSettingGlobal(QStringLiteral("use_assembly_shaders"), Settings::values.use_assembly_shaders, false); WriteSettingGlobal(QStringLiteral("use_asynchronous_shaders"), diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index ce3355588..3c1de0ac9 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -42,7 +42,7 @@ public: default_mouse_buttons; static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; - static const std::array<UISettings::Shortcut, 17> default_hotkeys; + static const std::array<UISettings::Shortcut, 18> default_hotkeys; private: void Initialize(const std::string& config_name); diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index 22219cbad..13db2ba98 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp @@ -34,12 +34,15 @@ void ConfigureCpu::SetConfiguration() { ui->accuracy->setEnabled(runtime_lock); ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock); ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock); + ui->cpuopt_unsafe_ignore_standard_fpcr->setEnabled(runtime_lock); ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock); ui->cpuopt_unsafe_fastmem_check->setEnabled(runtime_lock); ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()); ui->cpuopt_unsafe_reduce_fp_error->setChecked( Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()); + ui->cpuopt_unsafe_ignore_standard_fpcr->setChecked( + Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue()); ui->cpuopt_unsafe_inaccurate_nan->setChecked( Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()); ui->cpuopt_unsafe_fastmem_check->setChecked( @@ -84,6 +87,9 @@ void ConfigureCpu::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_reduce_fp_error, ui->cpuopt_unsafe_reduce_fp_error, cpuopt_unsafe_reduce_fp_error); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_ignore_standard_fpcr, + ui->cpuopt_unsafe_ignore_standard_fpcr, + cpuopt_unsafe_ignore_standard_fpcr); ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_inaccurate_nan, ui->cpuopt_unsafe_inaccurate_nan, cpuopt_unsafe_inaccurate_nan); @@ -137,6 +143,9 @@ void ConfigureCpu::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_reduce_fp_error, Settings::values.cpuopt_unsafe_reduce_fp_error, cpuopt_unsafe_reduce_fp_error); + ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_ignore_standard_fpcr, + Settings::values.cpuopt_unsafe_ignore_standard_fpcr, + cpuopt_unsafe_ignore_standard_fpcr); ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_inaccurate_nan, Settings::values.cpuopt_unsafe_inaccurate_nan, cpuopt_unsafe_inaccurate_nan); diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 57ff2772a..b2b5f1671 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -40,6 +40,7 @@ private: ConfigurationShared::CheckState cpuopt_unsafe_unfuse_fma; ConfigurationShared::CheckState cpuopt_unsafe_reduce_fp_error; + ConfigurationShared::CheckState cpuopt_unsafe_ignore_standard_fpcr; ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan; ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check; }; diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui index 31ef9e3f5..0e296d4e5 100644 --- a/src/yuzu/configuration/configure_cpu.ui +++ b/src/yuzu/configuration/configure_cpu.ui @@ -112,6 +112,18 @@ </widget> </item> <item> + <widget class="QCheckBox" name="cpuopt_unsafe_ignore_standard_fpcr"> + <property name="toolTip"> + <string> + <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> + </string> + </property> + <property name="text"> + <string>Faster ASIMD instructions (32 bits only)</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan"> <property name="toolTip"> <string> diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index a9e611125..8d13c9857 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -28,6 +28,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); + ui->disable_fps_limit->setChecked(Settings::values.disable_fps_limit.GetValue()); ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue()); ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue()); @@ -58,6 +59,8 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, ui->anisotropic_filtering_combobox); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.disable_fps_limit, + ui->disable_fps_limit, disable_fps_limit); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders, ui->use_assembly_shaders, use_assembly_shaders); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, @@ -100,6 +103,7 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { if (Settings::IsConfiguringGlobal()) { ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); + ui->disable_fps_limit->setEnabled(Settings::values.disable_fps_limit.UsingGlobal()); ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal()); ui->use_asynchronous_shaders->setEnabled( Settings::values.use_asynchronous_shaders.UsingGlobal()); @@ -112,6 +116,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { } ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync); + ConfigurationShared::SetColoredTristate(ui->disable_fps_limit, + Settings::values.disable_fps_limit, disable_fps_limit); ConfigurationShared::SetColoredTristate( ui->use_assembly_shaders, Settings::values.use_assembly_shaders, use_assembly_shaders); ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 9148aacf2..6ac5f20ec 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -35,6 +35,7 @@ private: std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; ConfigurationShared::CheckState use_vsync; + ConfigurationShared::CheckState disable_fps_limit; ConfigurationShared::CheckState use_assembly_shaders; ConfigurationShared::CheckState use_asynchronous_shaders; ConfigurationShared::CheckState use_fast_gpu_time; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index ad0840355..18c43629e 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -77,6 +77,24 @@ </widget> </item> <item> + <widget class="QCheckBox" name="disable_fps_limit"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string> + <html><head/><body> + <p>Presents guest frames as they become available, disabling the FPS limit in most titles.</p> + <p>NOTE: Will cause instabilities.</p> + </body></html> + </string> + </property> + <property name="text"> + <string>Disable framerate limit (experimental)</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="use_assembly_shaders"> <property name="toolTip"> <string>Enabling this reduces shader stutter. Enables OpenGL assembly shaders on supported Nvidia devices (NV_gpu_program5 is required). This feature is experimental.</string> diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index a1d434aca..8c00eec59 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -47,6 +47,8 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, const std::str ui->setupUi(this); setFocusPolicy(Qt::ClickFocus); setWindowTitle(tr("Properties")); + // remove Help question mark button from the title bar + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); ui->addonsTab->SetTitleId(title_id); diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui index adf6d0b39..7da14146b 100644 --- a/src/yuzu/configuration/configure_per_game.ui +++ b/src/yuzu/configuration/configure_per_game.ui @@ -6,10 +6,15 @@ <rect> <x>0</x> <y>0</y> - <width>800</width> + <width>900</width> <height>600</height> </rect> </property> + <property name="minimumSize"> + <size> + <width>900</width> + </size> + </property> <property name="windowTitle"> <string>Dialog</string> </property> diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 9b709d405..ebb0f411c 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -79,8 +79,8 @@ void ConfigurePerGameAddons::ApplyConfiguration() { std::sort(disabled_addons.begin(), disabled_addons.end()); std::sort(current.begin(), current.end()); if (disabled_addons != current) { - void(Common::FS::RemoveFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / - "game_list" / fmt::format("{:016X}.pv.txt", title_id))); + Common::FS::RemoveFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / + "game_list" / fmt::format("{:016X}.pv.txt", title_id)); } Settings::values.disabled_addons[title_id] = disabled_addons; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index be8933c5c..75ab5ef44 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -194,10 +194,10 @@ static void RemoveCachedContents() { const auto offline_legal_information = cache_dir / "offline_web_applet_legal_information"; const auto offline_system_data = cache_dir / "offline_web_applet_system_data"; - void(Common::FS::RemoveDirRecursively(offline_fonts)); - void(Common::FS::RemoveDirRecursively(offline_manual)); - void(Common::FS::RemoveDirRecursively(offline_legal_information)); - void(Common::FS::RemoveDirRecursively(offline_system_data)); + Common::FS::RemoveDirRecursively(offline_fonts); + Common::FS::RemoveDirRecursively(offline_manual); + Common::FS::RemoveDirRecursively(offline_legal_information); + Common::FS::RemoveDirRecursively(offline_system_data); } GMainWindow::GMainWindow() @@ -1025,7 +1025,11 @@ void GMainWindow::InitializeHotkeys() { connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this), &QShortcut::activated, this, [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); - + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Framerate Limit"), this), + &QShortcut::activated, this, [] { + Settings::values.disable_fps_limit.SetValue( + !Settings::values.disable_fps_limit.GetValue()); + }); connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this), &QShortcut::activated, this, [&] { Settings::values.mouse_panning = !Settings::values.mouse_panning; @@ -1739,8 +1743,8 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT RemoveAddOnContent(program_id, entry_type); break; } - void(Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / - "game_list")); + Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / + "game_list"); game_list->PopulateAsync(UISettings::values.game_dirs); } @@ -2209,8 +2213,8 @@ void GMainWindow::OnMenuInstallToNAND() { : tr("%n file(s) failed to install\n", "", failed_files.size())); QMessageBox::information(this, tr("Install Results"), install_results); - void(Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / - "game_list")); + Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / + "game_list"); game_list->PopulateAsync(UISettings::values.game_dirs); ui.action_Install_File_NAND->setEnabled(true); } @@ -2842,7 +2846,7 @@ void GMainWindow::MigrateConfigFiles() { LOG_INFO(Frontend, "Migrating config file from {} to {}", origin, destination); if (!Common::FS::RenameFile(origin, destination)) { // Delete the old config file if one already exists in the new location. - void(Common::FS::RemoveFile(origin)); + Common::FS::RemoveFile(origin); } } } @@ -3036,9 +3040,9 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { const auto keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); - void(Common::FS::RemoveFile(keys_dir / "prod.keys_autogenerated")); - void(Common::FS::RemoveFile(keys_dir / "console.keys_autogenerated")); - void(Common::FS::RemoveFile(keys_dir / "title.keys_autogenerated")); + Common::FS::RemoveFile(keys_dir / "prod.keys_autogenerated"); + Common::FS::RemoveFile(keys_dir / "console.keys_autogenerated"); + Common::FS::RemoveFile(keys_dir / "title.keys_autogenerated"); } Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 621b31571..60bf66ec0 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -443,6 +443,8 @@ void Config::ReadValues() { sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", true)); Settings::values.use_vsync.SetValue( static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1))); + Settings::values.disable_fps_limit.SetValue( + sdl2_config->GetBoolean("Renderer", "disable_fps_limit", false)); Settings::values.use_assembly_shaders.SetValue( sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", true)); Settings::values.use_asynchronous_shaders.SetValue( diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index f0a0ec398..cc9850aad 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -264,7 +264,10 @@ swap_screen = [Audio] # Which audio output engine to use. -# auto (default): Auto-select, null: No audio output, cubeb: Cubeb audio engine (if available) +# auto (default): Auto-select +# cubeb: Cubeb audio engine (if available) +# sdl2: SDL2 audio engine (if available) +# null: No audio output output_engine = # Whether or not to enable the audio-stretching post-processing effect. @@ -363,6 +366,9 @@ use_debug_asserts = use_auto_stub = # Enables/Disables the macro JIT compiler disable_macro_jit=false +# Presents guest frames as they become available. Experimental. +# false: Disabled (default), true: Enabled +disable_fps_limit=false [WebService] # Whether or not to enable telemetry diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 584967f5c..50e388312 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -219,7 +219,7 @@ int main(int argc, char** argv) { system.GPU().Start(); system.Renderer().ReadRasterizer()->LoadDiskResources( - system.CurrentProcess()->GetTitleID(), false, + system.CurrentProcess()->GetTitleID(), std::stop_token{}, [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); void(system.Run()); |