diff options
128 files changed, 1172 insertions, 563 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index a6c43f401..561eaafb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,7 +222,7 @@ find_package(ZLIB 1.2 REQUIRED) find_package(zstd 1.5 REQUIRED) if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS) - find_package(Vulkan 1.3.238 REQUIRED) + find_package(Vulkan 1.3.246 REQUIRED) endif() if (ENABLE_LIBUSB) diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers -Subproject 00671c64ba5c488ade22ad572a0ef81d5e64c80 +Subproject 63af1cf1ee906ba4dcd5a324bdd0201d4f4bfd1 diff --git a/externals/dynarmic b/externals/dynarmic -Subproject 165621a872ffb802c7a26ef5900e1e62681f1a8 +Subproject c08c5a9362bb224dc343c2f616c24df027dfdf1 diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index 5a327a606..b5c0ef0e6 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp @@ -93,7 +93,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { stream->AppendBuffer(new_buffer, samples); } else { std::vector<s16> samples(buffer.size / sizeof(s16)); - system.Memory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size); + system.ApplicationMemory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size); stream->AppendBuffer(new_buffer, samples); } } @@ -102,7 +102,7 @@ void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const { if (type == Sink::StreamType::In) { auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))}; - system.Memory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); + system.ApplicationMemory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); } } @@ -121,8 +121,7 @@ u64 DeviceSession::GetPlayedSampleCount() const { } std::optional<std::chrono::nanoseconds> DeviceSession::ThreadFunc() { - // Add 5ms of samples at a 48K sample rate. - played_sample_count += 48'000 * INCREMENT_TIME / 1s; + played_sample_count = stream->GetExpectedPlayedSampleCount(); if (type == Sink::StreamType::Out) { system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioOutManager, true); } else { diff --git a/src/audio_core/renderer/adsp/adsp.cpp b/src/audio_core/renderer/adsp/adsp.cpp index a28395663..74772fc50 100644 --- a/src/audio_core/renderer/adsp/adsp.cpp +++ b/src/audio_core/renderer/adsp/adsp.cpp @@ -13,7 +13,7 @@ namespace AudioCore::AudioRenderer::ADSP { ADSP::ADSP(Core::System& system_, Sink::Sink& sink_) - : system{system_}, memory{system.Memory()}, sink{sink_} {} + : system{system_}, memory{system.ApplicationMemory()}, sink{sink_} {} ADSP::~ADSP() { ClearCommandBuffers(); diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp index 42b4b167a..503f40349 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.cpp +++ b/src/audio_core/renderer/adsp/audio_renderer.cpp @@ -189,6 +189,8 @@ void AudioRenderer::ThreadFunc() { max_time = std::min(command_buffer.time_limit, max_time); command_list_processor.SetProcessTimeMax(max_time); + streams[index]->WaitFreeSpace(); + // Process the command list { MICROPROFILE_SCOPE(Audio_Renderer); diff --git a/src/audio_core/renderer/adsp/audio_renderer.h b/src/audio_core/renderer/adsp/audio_renderer.h index 151f38c1b..85ce6a269 100644 --- a/src/audio_core/renderer/adsp/audio_renderer.h +++ b/src/audio_core/renderer/adsp/audio_renderer.h @@ -10,6 +10,7 @@ #include "audio_core/renderer/adsp/command_buffer.h" #include "audio_core/renderer/adsp/command_list_processor.h" #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "common/reader_writer_queue.h" #include "common/thread.h" diff --git a/src/audio_core/renderer/adsp/command_list_processor.cpp b/src/audio_core/renderer/adsp/command_list_processor.cpp index e3bf2d7ec..7a300d216 100644 --- a/src/audio_core/renderer/adsp/command_list_processor.cpp +++ b/src/audio_core/renderer/adsp/command_list_processor.cpp @@ -17,7 +17,7 @@ namespace AudioCore::AudioRenderer::ADSP { void CommandListProcessor::Initialize(Core::System& system_, CpuAddr buffer, u64 size, Sink::SinkStream* stream_) { system = &system_; - memory = &system->Memory(); + memory = &system->ApplicationMemory(); stream = stream_; header = reinterpret_cast<CommandListHeader*>(buffer); commands = reinterpret_cast<u8*>(buffer + sizeof(CommandListHeader)); diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp index 28f063641..ad869facb 100644 --- a/src/audio_core/renderer/system.cpp +++ b/src/audio_core/renderer/system.cpp @@ -127,8 +127,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params, render_device = params.rendering_device; execution_mode = params.execution_mode; - core.Memory().ZeroBlock(*core.ApplicationProcess(), transfer_memory->GetSourceAddress(), - transfer_memory_size); + core.ApplicationMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size); // Note: We're not actually using the transfer memory because it's a pain to code for. // Allocate the memory normally instead and hope the game doesn't try to read anything back diff --git a/src/audio_core/renderer/system_manager.cpp b/src/audio_core/renderer/system_manager.cpp index ce631f810..07d8ed093 100644 --- a/src/audio_core/renderer/system_manager.cpp +++ b/src/audio_core/renderer/system_manager.cpp @@ -15,14 +15,9 @@ MICROPROFILE_DEFINE(Audio_RenderSystemManager, "Audio", "Render System Manager", MP_RGB(60, 19, 97)); namespace AudioCore::AudioRenderer { -constexpr std::chrono::nanoseconds RENDER_TIME{5'000'000UL}; SystemManager::SystemManager(Core::System& core_) - : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()}, - thread_event{Core::Timing::CreateEvent( - "AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) { - return ThreadFunc2(time); - })} {} + : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()} {} SystemManager::~SystemManager() { Stop(); @@ -33,8 +28,6 @@ bool SystemManager::InitializeUnsafe() { if (adsp.Start()) { active = true; thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); }); - core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), RENDER_TIME, - thread_event); } } @@ -45,7 +38,6 @@ void SystemManager::Stop() { if (!active) { return; } - core.CoreTiming().UnscheduleEvent(thread_event, {}); active = false; update.store(true); update.notify_all(); @@ -111,16 +103,7 @@ void SystemManager::ThreadFunc() { adsp.Signal(); adsp.Wait(); - - update.wait(false); - update.store(false); } } -std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) { - update.store(true); - update.notify_all(); - return std::nullopt; -} - } // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/system_manager.h b/src/audio_core/renderer/system_manager.h index 415ddb74f..1f0bbd8b4 100644 --- a/src/audio_core/renderer/system_manager.h +++ b/src/audio_core/renderer/system_manager.h @@ -68,11 +68,6 @@ private: */ void ThreadFunc(); - /** - * Signalling core timing thread to run ThreadFunc. - */ - std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time); - enum class StreamState { Filling, Steady, @@ -95,8 +90,6 @@ private: ADSP::ADSP& adsp; /// AudioRenderer mailbox for communication ADSP::AudioRenderer_Mailbox* mailbox{}; - /// Core timing event to signal main thread - std::shared_ptr<Core::Timing::EventType> thread_event; /// Atomic for main thread to wait on std::atomic<bool> update{}; }; diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp index 9133f5388..9a0801888 100644 --- a/src/audio_core/sink/cubeb_sink.cpp +++ b/src/audio_core/sink/cubeb_sink.cpp @@ -101,8 +101,6 @@ public: ~CubebSinkStream() override { LOG_DEBUG(Service_Audio, "Destructing cubeb stream {}", name); - Unstall(); - if (!ctx) { return; } @@ -143,8 +141,6 @@ public: * Stop the sink stream. */ void Stop() override { - Unstall(); - if (!ctx || paused) { return; } diff --git a/src/audio_core/sink/sdl2_sink.cpp b/src/audio_core/sink/sdl2_sink.cpp index c138dc628..ee1a0652f 100644 --- a/src/audio_core/sink/sdl2_sink.cpp +++ b/src/audio_core/sink/sdl2_sink.cpp @@ -88,7 +88,6 @@ public: * Finalize the sink stream. */ void Finalize() override { - Unstall(); if (device == 0) { return; } @@ -116,7 +115,6 @@ public: * Stop the sink stream. */ void Stop() override { - Unstall(); if (device == 0 || paused) { return; } diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 39a21b0f0..f99dbd8ec 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -14,6 +14,8 @@ #include "common/fixed_point.h" #include "common/settings.h" #include "core/core.h" +#include "core/core_timing.h" +#include "core/core_timing_util.h" namespace AudioCore::Sink { @@ -149,10 +151,6 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n return; } - if (queued_buffers > max_queue_size) { - Stall(); - } - while (frames_written < num_frames) { // If the playing buffer has been consumed or has no frames, we need a new one if (playing_buffer.consumed || playing_buffer.frames == 0) { @@ -187,10 +185,6 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n } std::memcpy(&last_frame[0], &input_buffer[(frames_written - 1) * frame_size], frame_size_bytes); - - if (queued_buffers <= max_queue_size) { - Unstall(); - } } void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::size_t num_frames) { @@ -198,10 +192,15 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz const std::size_t frame_size = num_channels; const std::size_t frame_size_bytes = frame_size * sizeof(s16); size_t frames_written{0}; + size_t actual_frames_written{0}; // If we're paused or going to shut down, we don't want to consume buffers as coretiming is // paused and we'll desync, so just play silence. if (system.IsPaused() || system.IsShuttingDown()) { + if (system.IsShuttingDown()) { + release_cv.notify_one(); + } + static constexpr std::array<s16, 6> silence{}; for (size_t i = frames_written; i < num_frames; i++) { std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes); @@ -209,20 +208,6 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz return; } - // Due to many frames being queued up with nvdec (5 frames or so?), a lot of buffers also get - // queued up (30+) but not all at once, which causes constant stalling here, so just let the - // video play out without attempting to stall. - // Can hopefully remove this later with a more complete NVDEC implementation. - const auto nvdec_active{system.AudioCore().IsNVDECActive()}; - - // Core timing cannot be paused in single-core mode, so Stall ends up being called over and over - // and never recovers to a normal state, so just skip attempting to sync things on single-core. - if (system.IsMulticore() && !nvdec_active && queued_buffers > max_queue_size) { - Stall(); - } else if (system.IsMulticore() && queued_buffers <= max_queue_size) { - Unstall(); - } - while (frames_written < num_frames) { // If the playing buffer has been consumed or has no frames, we need a new one if (playing_buffer.consumed || playing_buffer.frames == 0) { @@ -237,6 +222,10 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz } // Successfully dequeued a new buffer. queued_buffers--; + + { std::unique_lock lk{release_mutex}; } + + release_cv.notify_one(); } // Get the minimum frames available between the currently playing buffer, and the @@ -248,6 +237,7 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz frames_available * frame_size); frames_written += frames_available; + actual_frames_written += frames_available; playing_buffer.frames_played += frames_available; // If that's all the frames in the current buffer, add its samples and mark it as @@ -260,26 +250,29 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size], frame_size_bytes); - if (system.IsMulticore() && queued_buffers <= max_queue_size) { - Unstall(); + { + std::scoped_lock lk{sample_count_lock}; + last_sample_count_update_time = + Core::Timing::CyclesToUs(system.CoreTiming().GetClockTicks()); + min_played_sample_count = max_played_sample_count; + max_played_sample_count += actual_frames_written; } } -void SinkStream::Stall() { - std::scoped_lock lk{stall_guard}; - if (stalled_lock) { - return; - } - stalled_lock = system.StallApplication(); +u64 SinkStream::GetExpectedPlayedSampleCount() { + std::scoped_lock lk{sample_count_lock}; + auto cur_time{Core::Timing::CyclesToUs(system.CoreTiming().GetClockTicks())}; + auto time_delta{cur_time - last_sample_count_update_time}; + auto exp_played_sample_count{min_played_sample_count + + (TargetSampleRate * time_delta) / std::chrono::seconds{1}}; + + return std::min<u64>(exp_played_sample_count, max_played_sample_count); } -void SinkStream::Unstall() { - std::scoped_lock lk{stall_guard}; - if (!stalled_lock) { - return; - } - system.UnstallApplication(); - stalled_lock.unlock(); +void SinkStream::WaitFreeSpace() { + std::unique_lock lk{release_mutex}; + release_cv.wait( + lk, [this]() { return queued_buffers < max_queue_size || system.IsShuttingDown(); }); } } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 5fea72ab7..23e289c7b 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h @@ -5,6 +5,7 @@ #include <array> #include <atomic> +#include <chrono> #include <memory> #include <mutex> #include <span> @@ -14,6 +15,7 @@ #include "common/common_types.h" #include "common/reader_writer_queue.h" #include "common/ring_buffer.h" +#include "common/thread.h" namespace Core { class System; @@ -53,9 +55,7 @@ struct SinkBuffer { class SinkStream { public: explicit SinkStream(Core::System& system_, StreamType type_) : system{system_}, type{type_} {} - virtual ~SinkStream() { - Unstall(); - } + virtual ~SinkStream() {} /** * Finalize the sink stream. @@ -201,14 +201,16 @@ public: void ProcessAudioOutAndRender(std::span<s16> output_buffer, std::size_t num_frames); /** - * Stall core processes if the audio thread falls too far behind. + * Get the total number of samples expected to have been played by this stream. + * + * @return The number of samples. */ - void Stall(); + u64 GetExpectedPlayedSampleCount(); /** - * Unstall core processes. + * Waits for free space in the sample ring buffer */ - void Unstall(); + void WaitFreeSpace(); protected: /// Core system @@ -237,12 +239,21 @@ private: std::atomic<u32> queued_buffers{}; /// The ring size for audio out buffers (usually 4, rarely 2 or 8) u32 max_queue_size{}; + /// Locks access to sample count tracking info + std::mutex sample_count_lock; + /// Minimum number of total samples that have been played since the last callback + u64 min_played_sample_count{}; + /// Maximum number of total samples that can be played since the last callback + u64 max_played_sample_count{}; + /// The time the two above tracking variables were last written to + std::chrono::microseconds last_sample_count_update_time{}; /// Set by the audio render/in/out system which uses this stream f32 system_volume{1.0f}; /// Set via IAudioDevice service calls f32 device_volume{1.0f}; - std::mutex stall_guard; - std::unique_lock<std::mutex> stalled_lock; + /// Signalled when ring buffer entries are consumed + std::condition_variable release_cv; + std::mutex release_mutex; }; using SinkStreamPtr = std::unique_ptr<SinkStream>; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c1d2b24a1..13ed68b3f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -160,6 +160,8 @@ if(ARCHITECTURE_x86_64) PRIVATE x64/cpu_detect.cpp x64/cpu_detect.h + x64/cpu_wait.cpp + x64/cpu_wait.h x64/native_clock.cpp x64/native_clock.h x64/xbyak_abi.h diff --git a/src/common/container_hash.h b/src/common/container_hash.h index cfc5dfea8..a5e357745 100644 --- a/src/common/container_hash.h +++ b/src/common/container_hash.h @@ -3,6 +3,7 @@ // SPDX-License-Identifier: BSL-1.0 #include <array> +#include <climits> #include <cstdint> #include <limits> #include <type_traits> diff --git a/src/common/range_map.h b/src/common/range_map.h index 79c7ef547..ab73993e3 100644 --- a/src/common/range_map.h +++ b/src/common/range_map.h @@ -38,12 +38,12 @@ public: Map(address, address_end, null_value); } - [[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const { + [[nodiscard]] size_t GetContinuousSizeFrom(KeyTBase address) const { const KeyT new_address = static_cast<KeyT>(address); if (new_address < 0) { return 0; } - return ContinousSizeInternal(new_address); + return ContinuousSizeInternal(new_address); } [[nodiscard]] ValueT GetValueAt(KeyT address) const { @@ -59,7 +59,7 @@ private: using IteratorType = typename MapType::iterator; using ConstIteratorType = typename MapType::const_iterator; - size_t ContinousSizeInternal(KeyT address) const { + size_t ContinuousSizeInternal(KeyT address) const { const auto it = GetFirstElementBeforeOrOn(address); if (it == container.end() || it->second == null_value) { return 0; diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp index d26394359..91352912d 100644 --- a/src/common/telemetry.cpp +++ b/src/common/telemetry.cpp @@ -97,6 +97,7 @@ void AppendCPUInfo(FieldCollection& fc) { add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq); add_field("CPU_Extension_x64_POPCNT", caps.popcnt); add_field("CPU_Extension_x64_SHA", caps.sha); + add_field("CPU_Extension_x64_WAITPKG", caps.waitpkg); #else fc.AddField(FieldType::UserSystem, "CPU_Model", "Other"); #endif diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index e54383a4a..72ed6e96c 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp @@ -144,6 +144,7 @@ static CPUCaps Detect() { caps.bmi2 = Common::Bit<8>(cpu_id[1]); caps.sha = Common::Bit<29>(cpu_id[1]); + caps.waitpkg = Common::Bit<5>(cpu_id[2]); caps.gfni = Common::Bit<8>(cpu_id[2]); __cpuidex(cpu_id, 0x00000007, 0x00000001); diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index ca8db19d6..8253944d6 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h @@ -67,6 +67,7 @@ struct CPUCaps { bool pclmulqdq : 1; bool popcnt : 1; bool sha : 1; + bool waitpkg : 1; }; /** diff --git a/src/common/x64/cpu_wait.cpp b/src/common/x64/cpu_wait.cpp new file mode 100644 index 000000000..cfeef6a3d --- /dev/null +++ b/src/common/x64/cpu_wait.cpp @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <thread> + +#ifdef _MSC_VER +#include <intrin.h> +#endif + +#include "common/x64/cpu_detect.h" +#include "common/x64/cpu_wait.h" + +namespace Common::X64 { + +#ifdef _MSC_VER +__forceinline static u64 FencedRDTSC() { + _mm_lfence(); + _ReadWriteBarrier(); + const u64 result = __rdtsc(); + _mm_lfence(); + _ReadWriteBarrier(); + return result; +} + +__forceinline static void TPAUSE() { + // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. + // For reference: + // At 1 GHz, 100K cycles is 100us + // At 2 GHz, 100K cycles is 50us + // At 4 GHz, 100K cycles is 25us + static constexpr auto PauseCycles = 100'000; + _tpause(0, FencedRDTSC() + PauseCycles); +} +#else +static u64 FencedRDTSC() { + u64 eax; + u64 edx; + asm volatile("lfence\n\t" + "rdtsc\n\t" + "lfence\n\t" + : "=a"(eax), "=d"(edx)); + return (edx << 32) | eax; +} + +static void TPAUSE() { + // 100,000 cycles is a reasonable amount of time to wait to save on CPU resources. + // For reference: + // At 1 GHz, 100K cycles is 100us + // At 2 GHz, 100K cycles is 50us + // At 4 GHz, 100K cycles is 25us + static constexpr auto PauseCycles = 100'000; + const auto tsc = FencedRDTSC() + PauseCycles; + const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF); + const auto edx = static_cast<u32>(tsc >> 32); + asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax)); +} +#endif + +void MicroSleep() { + static const bool has_waitpkg = GetCPUCaps().waitpkg; + + if (has_waitpkg) { + TPAUSE(); + } else { + std::this_thread::yield(); + } +} + +} // namespace Common::X64 diff --git a/src/common/x64/cpu_wait.h b/src/common/x64/cpu_wait.h new file mode 100644 index 000000000..99d3757a7 --- /dev/null +++ b/src/common/x64/cpu_wait.h @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Common::X64 { + +void MicroSleep(); + +} // namespace Common::X64 diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 76c66e7ee..277b00662 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -27,16 +27,13 @@ __forceinline static u64 FencedRDTSC() { } #else static u64 FencedRDTSC() { - u64 result; + u64 eax; + u64 edx; asm volatile("lfence\n\t" "rdtsc\n\t" - "shl $32, %%rdx\n\t" - "or %%rdx, %0\n\t" - "lfence" - : "=a"(result) - : - : "rdx", "memory", "cc"); - return result; + "lfence\n\t" + : "=a"(eax), "=d"(edx)); + return (edx << 32) | eax; } #endif diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index be3f55cd2..d30914b7a 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -44,7 +44,7 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt std::map<std::string, Symbols::Symbols> symbols; for (const auto& module : modules) { symbols.insert_or_assign( - module.second, Symbols::GetSymbols(module.first, system.Memory(), + module.second, Symbols::GetSymbols(module.first, system.ApplicationMemory(), system.ApplicationProcess()->Is64BitProcess())); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index aa92d3fc3..dfdcbe35a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -5,7 +5,6 @@ #include <memory> #include <dynarmic/interface/A32/a32.h> #include <dynarmic/interface/A32/config.h> -#include <dynarmic/interface/A32/context.h> #include "common/assert.h" #include "common/literals.h" #include "common/logging/log.h" @@ -28,8 +27,8 @@ using namespace Common::Literals; class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { public: explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) - : parent{parent_}, - memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()}, + : parent{parent_}, memory(parent.system.ApplicationMemory()), + debugger_enabled{parent.system.DebuggerEnabled()}, check_memory_access{debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} @@ -410,21 +409,19 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { } void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { - Dynarmic::A32::Context context; - jit.load()->SaveContext(context); - ctx.cpu_registers = context.Regs(); - ctx.extension_registers = context.ExtRegs(); - ctx.cpsr = context.Cpsr(); - ctx.fpscr = context.Fpscr(); + Dynarmic::A32::Jit* j = jit.load(); + ctx.cpu_registers = j->Regs(); + ctx.extension_registers = j->ExtRegs(); + ctx.cpsr = j->Cpsr(); + ctx.fpscr = j->Fpscr(); } void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { - Dynarmic::A32::Context context; - context.Regs() = ctx.cpu_registers; - context.ExtRegs() = ctx.extension_registers; - context.SetCpsr(ctx.cpsr); - context.SetFpscr(ctx.fpscr); - jit.load()->LoadContext(context); + Dynarmic::A32::Jit* j = jit.load(); + j->Regs() = ctx.cpu_registers; + j->ExtRegs() = ctx.extension_registers; + j->SetCpsr(ctx.cpsr); + j->SetFpscr(ctx.fpscr); } void ARM_Dynarmic_32::SignalInterrupt() { @@ -468,7 +465,7 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc) { std::vector<BacktraceEntry> out; - auto& memory = system.Memory(); + auto& memory = system.ApplicationMemory(); out.push_back({"", 0, pc, 0, ""}); diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 67073c84d..bbbcb4f9d 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -28,8 +28,8 @@ using namespace Common::Literals; class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { public: explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) - : parent{parent_}, - memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()}, + : parent{parent_}, memory(parent.system.ApplicationMemory()), + debugger_enabled{parent.system.DebuggerEnabled()}, check_memory_access{debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} @@ -529,7 +529,7 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc) { std::vector<BacktraceEntry> out; - auto& memory = system.Memory(); + auto& memory = system.ApplicationMemory(); out.push_back({"", 0, pc, 0, ""}); diff --git a/src/core/core.cpp b/src/core/core.cpp index f6273ac39..caa6a77be 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -293,6 +293,7 @@ struct System::Impl { ASSERT(Kernel::KProcess::Initialize(main_process, system, "main", Kernel::KProcess::ProcessType::Userland, resource_limit) .IsSuccess()); + kernel.MakeApplicationProcess(main_process); const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); if (load_result != Loader::ResultStatus::Success) { LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); @@ -302,7 +303,6 @@ struct System::Impl { static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); } AddGlueRegistrationForProcess(*app_loader, *main_process); - kernel.MakeApplicationProcess(main_process); kernel.InitializeCores(); // Initialize cheat engine @@ -681,11 +681,11 @@ const ExclusiveMonitor& System::Monitor() const { return impl->kernel.GetExclusiveMonitor(); } -Memory::Memory& System::Memory() { +Memory::Memory& System::ApplicationMemory() { return impl->memory; } -const Core::Memory::Memory& System::Memory() const { +const Core::Memory::Memory& System::ApplicationMemory() const { return impl->memory; } diff --git a/src/core/core.h b/src/core/core.h index 7032240be..4a5aba032 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -256,10 +256,10 @@ public: [[nodiscard]] const ExclusiveMonitor& Monitor() const; /// Gets a mutable reference to the system memory instance. - [[nodiscard]] Core::Memory::Memory& Memory(); + [[nodiscard]] Core::Memory::Memory& ApplicationMemory(); /// Gets a constant reference to the system memory instance. - [[nodiscard]] const Core::Memory::Memory& Memory() const; + [[nodiscard]] const Core::Memory::Memory& ApplicationMemory() const; /// Gets a mutable reference to the GPU interface [[nodiscard]] Tegra::GPU& GPU(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index cd4df4522..4f2692b05 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -10,6 +10,10 @@ #include "common/windows/timer_resolution.h" #endif +#ifdef ARCHITECTURE_x86_64 +#include "common/x64/cpu_wait.h" +#endif + #include "common/microprofile.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -269,7 +273,11 @@ void CoreTiming::ThreadLoop() { if (wait_time >= timer_resolution_ns) { Common::Windows::SleepForOneTick(); } else { +#ifdef ARCHITECTURE_x86_64 + Common::X64::MicroSleep(); +#else std::this_thread::yield(); +#endif } } diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 5cfb66b93..e2a13bbd2 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -261,9 +261,9 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))}; const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; - if (system.Memory().IsValidVirtualAddressRange(addr, size)) { + if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { std::vector<u8> mem(size); - system.Memory().ReadBlock(addr, mem.data(), size); + system.ApplicationMemory().ReadBlock(addr, mem.data(), size); SendReply(Common::HexToString(mem)); } else { @@ -281,8 +281,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction const auto mem_substr{std::string_view(command).substr(mem_sep)}; const auto mem{Common::HexStringToVector(mem_substr, false)}; - if (system.Memory().IsValidVirtualAddressRange(addr, size)) { - system.Memory().WriteBlock(addr, mem.data(), size); + if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { + system.ApplicationMemory().WriteBlock(addr, mem.data(), size); system.InvalidateCpuInstructionCacheRange(addr, size); SendReply(GDB_STUB_REPLY_OK); } else { @@ -325,7 +325,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; - if (!system.Memory().IsValidVirtualAddressRange(addr, size)) { + if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { SendReply(GDB_STUB_REPLY_ERR); return; } @@ -334,22 +334,22 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { switch (type) { case BreakpointType::Software: - replaced_instructions[addr] = system.Memory().Read32(addr); - system.Memory().Write32(addr, arch->BreakpointInstruction()); + replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); + system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); success = true; break; case BreakpointType::WriteWatch: - success = system.ApplicationProcess()->InsertWatchpoint(system, addr, size, + success = system.ApplicationProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); break; case BreakpointType::ReadWatch: - success = system.ApplicationProcess()->InsertWatchpoint(system, addr, size, + success = system.ApplicationProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); break; case BreakpointType::AccessWatch: success = system.ApplicationProcess()->InsertWatchpoint( - system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite); + addr, size, Kernel::DebugWatchpointType::ReadOrWrite); break; case BreakpointType::Hardware: default: @@ -372,7 +372,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; - if (!system.Memory().IsValidVirtualAddressRange(addr, size)) { + if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { SendReply(GDB_STUB_REPLY_ERR); return; } @@ -383,7 +383,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { case BreakpointType::Software: { const auto orig_insn{replaced_instructions.find(addr)}; if (orig_insn != replaced_instructions.end()) { - system.Memory().Write32(addr, orig_insn->second); + system.ApplicationMemory().Write32(addr, orig_insn->second); system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); replaced_instructions.erase(addr); success = true; @@ -391,16 +391,16 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { break; } case BreakpointType::WriteWatch: - success = system.ApplicationProcess()->RemoveWatchpoint(system, addr, size, + success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); break; case BreakpointType::ReadWatch: - success = system.ApplicationProcess()->RemoveWatchpoint(system, addr, size, + success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); break; case BreakpointType::AccessWatch: success = system.ApplicationProcess()->RemoveWatchpoint( - system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite); + addr, size, Kernel::DebugWatchpointType::ReadOrWrite); break; case BreakpointType::Hardware: default: @@ -483,9 +483,9 @@ static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& static std::optional<std::string> GetThreadName(Core::System& system, const Kernel::KThread* thread) { if (system.ApplicationProcess()->Is64BitProcess()) { - return GetNameFromThreadType64(system.Memory(), thread); + return GetNameFromThreadType64(system.ApplicationMemory(), thread); } else { - return GetNameFromThreadType32(system.Memory(), thread); + return GetNameFromThreadType32(system.ApplicationMemory(), thread); } } diff --git a/src/core/frontend/applets/applet.h b/src/core/frontend/applets/applet.h new file mode 100644 index 000000000..77fffe306 --- /dev/null +++ b/src/core/frontend/applets/applet.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Core::Frontend { + +class Applet { +public: + virtual ~Applet() = default; + virtual void Close() const = 0; +}; + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp index 26c7fefe3..2d501eeae 100644 --- a/src/core/frontend/applets/cabinet.cpp +++ b/src/core/frontend/applets/cabinet.cpp @@ -10,6 +10,8 @@ namespace Core::Frontend { CabinetApplet::~CabinetApplet() = default; +void DefaultCabinetApplet::Close() const {} + void DefaultCabinetApplet::ShowCabinetApplet( const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h index c28a235c1..74dc5a4f6 100644 --- a/src/core/frontend/applets/cabinet.h +++ b/src/core/frontend/applets/cabinet.h @@ -4,6 +4,7 @@ #pragma once #include <functional> +#include "core/frontend/applets/applet.h" #include "core/hle/service/nfp/nfp_types.h" namespace Service::NFP { @@ -20,7 +21,7 @@ struct CabinetParameters { using CabinetCallback = std::function<void(bool, const std::string&)>; -class CabinetApplet { +class CabinetApplet : public Applet { public: virtual ~CabinetApplet(); virtual void ShowCabinetApplet(const CabinetCallback& callback, @@ -30,6 +31,7 @@ public: class DefaultCabinetApplet final : public CabinetApplet { public: + void Close() const override; void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; }; diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 52919484e..3300d4f79 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -16,6 +16,8 @@ DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_ DefaultControllerApplet::~DefaultControllerApplet() = default; +void DefaultControllerApplet::Close() const {} + void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callback, const ControllerParameters& parameters) const { LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); @@ -69,7 +71,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac } } - callback(); + callback(true); } } // namespace Core::Frontend diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index adb2feefd..19a2db6bf 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h @@ -7,6 +7,7 @@ #include <vector> #include "common/common_types.h" +#include "core/frontend/applets/applet.h" namespace Core::HID { class HIDCore; @@ -34,9 +35,9 @@ struct ControllerParameters { bool allow_gamecube_controller{}; }; -class ControllerApplet { +class ControllerApplet : public Applet { public: - using ReconfigureCallback = std::function<void()>; + using ReconfigureCallback = std::function<void(bool)>; virtual ~ControllerApplet(); @@ -49,6 +50,7 @@ public: explicit DefaultControllerApplet(HID::HIDCore& hid_core_); ~DefaultControllerApplet() override; + void Close() const override; void ReconfigureControllers(ReconfigureCallback callback, const ControllerParameters& parameters) const override; diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp index 69c2b2b4d..2e6f7a3d9 100644 --- a/src/core/frontend/applets/error.cpp +++ b/src/core/frontend/applets/error.cpp @@ -8,6 +8,8 @@ namespace Core::Frontend { ErrorApplet::~ErrorApplet() = default; +void DefaultErrorApplet::Close() const {} + void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const { LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", error.module.Value(), error.description.Value(), error.raw); diff --git a/src/core/frontend/applets/error.h b/src/core/frontend/applets/error.h index 884f2f653..3a12196ce 100644 --- a/src/core/frontend/applets/error.h +++ b/src/core/frontend/applets/error.h @@ -6,11 +6,12 @@ #include <chrono> #include <functional> +#include "core/frontend/applets/applet.h" #include "core/hle/result.h" namespace Core::Frontend { -class ErrorApplet { +class ErrorApplet : public Applet { public: using FinishedCallback = std::function<void()>; @@ -28,6 +29,7 @@ public: class DefaultErrorApplet final : public ErrorApplet { public: + void Close() const override; void ShowError(Result error, FinishedCallback finished) const override; void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, FinishedCallback finished) const override; diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp index 29a00fb6f..b4b213a31 100644 --- a/src/core/frontend/applets/general_frontend.cpp +++ b/src/core/frontend/applets/general_frontend.cpp @@ -10,6 +10,8 @@ ParentalControlsApplet::~ParentalControlsApplet() = default; DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default; +void DefaultParentalControlsApplet::Close() const {} + void DefaultParentalControlsApplet::VerifyPIN(std::function<void(bool)> finished, bool suspend_future_verification_temporarily) { LOG_INFO(Service_AM, @@ -39,6 +41,8 @@ PhotoViewerApplet::~PhotoViewerApplet() = default; DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default; +void DefaultPhotoViewerApplet::Close() const {} + void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const { LOG_INFO(Service_AM, diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h index cbec8b4ad..319838ac7 100644 --- a/src/core/frontend/applets/general_frontend.h +++ b/src/core/frontend/applets/general_frontend.h @@ -6,9 +6,11 @@ #include <functional> #include "common/common_types.h" +#include "core/frontend/applets/applet.h" + namespace Core::Frontend { -class ParentalControlsApplet { +class ParentalControlsApplet : public Applet { public: virtual ~ParentalControlsApplet(); @@ -33,6 +35,7 @@ class DefaultParentalControlsApplet final : public ParentalControlsApplet { public: ~DefaultParentalControlsApplet() override; + void Close() const override; void VerifyPIN(std::function<void(bool)> finished, bool suspend_future_verification_temporarily) override; void VerifyPINForSettings(std::function<void(bool)> finished) override; @@ -40,7 +43,7 @@ public: void ChangePIN(std::function<void()> finished) override; }; -class PhotoViewerApplet { +class PhotoViewerApplet : public Applet { public: virtual ~PhotoViewerApplet(); @@ -52,6 +55,7 @@ class DefaultPhotoViewerApplet final : public PhotoViewerApplet { public: ~DefaultPhotoViewerApplet() override; + void Close() const override; void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const override; void ShowAllPhotos(std::function<void()> finished) const override; }; diff --git a/src/core/frontend/applets/mii_edit.cpp b/src/core/frontend/applets/mii_edit.cpp index bc8c57067..2988c3e72 100644 --- a/src/core/frontend/applets/mii_edit.cpp +++ b/src/core/frontend/applets/mii_edit.cpp @@ -8,6 +8,8 @@ namespace Core::Frontend { MiiEditApplet::~MiiEditApplet() = default; +void DefaultMiiEditApplet::Close() const {} + void DefaultMiiEditApplet::ShowMiiEdit(const MiiEditCallback& callback) const { LOG_WARNING(Service_AM, "(STUBBED) called"); diff --git a/src/core/frontend/applets/mii_edit.h b/src/core/frontend/applets/mii_edit.h index d828f06ec..9d86ee658 100644 --- a/src/core/frontend/applets/mii_edit.h +++ b/src/core/frontend/applets/mii_edit.h @@ -5,9 +5,11 @@ #include <functional> +#include "core/frontend/applets/applet.h" + namespace Core::Frontend { -class MiiEditApplet { +class MiiEditApplet : public Applet { public: using MiiEditCallback = std::function<void()>; @@ -18,6 +20,7 @@ public: class DefaultMiiEditApplet final : public MiiEditApplet { public: + void Close() const override; void ShowMiiEdit(const MiiEditCallback& callback) const override; }; diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp index da4cfbf87..c18f17a36 100644 --- a/src/core/frontend/applets/profile_select.cpp +++ b/src/core/frontend/applets/profile_select.cpp @@ -9,7 +9,10 @@ namespace Core::Frontend { ProfileSelectApplet::~ProfileSelectApplet() = default; -void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback) const { +void DefaultProfileSelectApplet::Close() const {} + +void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback, + const ProfileSelectParameters& parameters) const { Service::Account::ProfileManager manager; callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{})); LOG_INFO(Service_ACC, "called, selecting current user instead of prompting..."); diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h index 138429533..92e2737ea 100644 --- a/src/core/frontend/applets/profile_select.h +++ b/src/core/frontend/applets/profile_select.h @@ -5,22 +5,35 @@ #include <functional> #include <optional> + #include "common/uuid.h" +#include "core/frontend/applets/applet.h" +#include "core/hle/service/am/applets/applet_profile_select.h" namespace Core::Frontend { -class ProfileSelectApplet { +struct ProfileSelectParameters { + Service::AM::Applets::UiMode mode; + std::array<Common::UUID, 8> invalid_uid_list; + Service::AM::Applets::UiSettingsDisplayOptions display_options; + Service::AM::Applets::UserSelectionPurpose purpose; +}; + +class ProfileSelectApplet : public Applet { public: using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>; virtual ~ProfileSelectApplet(); - virtual void SelectProfile(SelectProfileCallback callback) const = 0; + virtual void SelectProfile(SelectProfileCallback callback, + const ProfileSelectParameters& parameters) const = 0; }; class DefaultProfileSelectApplet final : public ProfileSelectApplet { public: - void SelectProfile(SelectProfileCallback callback) const override; + void Close() const override; + void SelectProfile(SelectProfileCallback callback, + const ProfileSelectParameters& parameters) const override; }; } // namespace Core::Frontend diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp index a3720f4d7..7655d215b 100644 --- a/src/core/frontend/applets/software_keyboard.cpp +++ b/src/core/frontend/applets/software_keyboard.cpp @@ -13,6 +13,8 @@ SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default; +void DefaultSoftwareKeyboardApplet::Close() const {} + void DefaultSoftwareKeyboardApplet::InitializeKeyboard( bool is_inline, KeyboardInitializeParameters initialize_parameters, SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) { diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h index 8aef103d3..8ed96da24 100644 --- a/src/core/frontend/applets/software_keyboard.h +++ b/src/core/frontend/applets/software_keyboard.h @@ -7,6 +7,7 @@ #include "common/common_types.h" +#include "core/frontend/applets/applet.h" #include "core/hle/service/am/applets/applet_software_keyboard_types.h" namespace Core::Frontend { @@ -52,7 +53,7 @@ struct InlineTextParameters { s32 cursor_position; }; -class SoftwareKeyboardApplet { +class SoftwareKeyboardApplet : public Applet { public: using SubmitInlineCallback = std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>; @@ -84,6 +85,8 @@ class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { public: ~DefaultSoftwareKeyboardApplet() override; + void Close() const override; + void InitializeKeyboard(bool is_inline, KeyboardInitializeParameters initialize_parameters, SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) override; diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp index b09cb7102..6e703ef06 100644 --- a/src/core/frontend/applets/web_browser.cpp +++ b/src/core/frontend/applets/web_browser.cpp @@ -10,6 +10,8 @@ WebBrowserApplet::~WebBrowserApplet() = default; DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; +void DefaultWebBrowserApplet::Close() const {} + void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback, OpenWebPageCallback callback) const { diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h index 4f72284ad..178bbdd3f 100644 --- a/src/core/frontend/applets/web_browser.h +++ b/src/core/frontend/applets/web_browser.h @@ -5,11 +5,12 @@ #include <functional> +#include "core/frontend/applets/applet.h" #include "core/hle/service/am/applets/applet_web_browser_types.h" namespace Core::Frontend { -class WebBrowserApplet { +class WebBrowserApplet : public Applet { public: using ExtractROMFSCallback = std::function<void()>; using OpenWebPageCallback = @@ -29,6 +30,8 @@ class DefaultWebBrowserApplet final : public WebBrowserApplet { public: ~DefaultWebBrowserApplet() override; + void Close() const override; + void OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback, OpenWebPageCallback callback) const override; diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 274928dcf..78d43d729 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -21,8 +21,8 @@ KAddressArbiter::~KAddressArbiter() = default; namespace { -bool ReadFromUser(Core::System& system, s32* out, KProcessAddress address) { - *out = system.Memory().Read32(GetInteger(address)); +bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) { + *out = GetCurrentMemory(kernel).Read32(GetInteger(address)); return true; } @@ -35,24 +35,30 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address // TODO(bunnei): We should call CanAccessAtomic(..) here. - // Load the value from the address. - const s32 current_value = - static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); + s32 current_value{}; + + while (true) { + // Load the value from the address. + current_value = + static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); - // Compare it to the desired one. - if (current_value < value) { - // If less than, we want to try to decrement. - const s32 decrement_value = current_value - 1; + // Compare it to the desired one. + if (current_value < value) { + // If less than, we want to try to decrement. + const s32 decrement_value = current_value - 1; + + // Decrement and try to store. + if (monitor.ExclusiveWrite32(current_core, GetInteger(address), + static_cast<u32>(decrement_value))) { + break; + } - // Decrement and try to store. - if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), - static_cast<u32>(decrement_value))) { // If we failed to store, try again. - DecrementIfLessThan(system, out, address, value); + } else { + // Otherwise, clear our exclusive hold and finish + monitor.ClearExclusive(current_core); + break; } - } else { - // Otherwise, clear our exclusive hold and finish - monitor.ClearExclusive(current_core); } // We're done. @@ -70,23 +76,29 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 // TODO(bunnei): We should call CanAccessAtomic(..) here. - // Load the value from the address. - const s32 current_value = - static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); + s32 current_value{}; - // Compare it to the desired one. - if (current_value == value) { - // If equal, we want to try to write the new value. + // Load the value from the address. + while (true) { + current_value = + static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); + + // Compare it to the desired one. + if (current_value == value) { + // If equal, we want to try to write the new value. + + // Try to store. + if (monitor.ExclusiveWrite32(current_core, GetInteger(address), + static_cast<u32>(new_value))) { + break; + } - // Try to store. - if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), - static_cast<u32>(new_value))) { // If we failed to store, try again. - UpdateIfEqual(system, out, address, value, new_value); + } else { + // Otherwise, clear our exclusive hold and finish. + monitor.ClearExclusive(current_core); + break; } - } else { - // Otherwise, clear our exclusive hold and finish. - monitor.ClearExclusive(current_core); } // We're done. @@ -209,7 +221,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32 if (value != new_value) { succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value); } else { - succeeded = ReadFromUser(m_system, std::addressof(user_value), addr); + succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); } R_UNLESS(succeeded, ResultInvalidCurrentMemory); @@ -252,7 +264,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement, if (decrement) { succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value); } else { - succeeded = ReadFromUser(m_system, std::addressof(user_value), addr); + succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); } if (!succeeded) { @@ -303,7 +315,7 @@ Result KAddressArbiter::WaitIfEqual(uint64_t addr, s32 value, s64 timeout) { // Read the value from userspace. s32 user_value{}; - if (!ReadFromUser(m_system, std::addressof(user_value), addr)) { + if (!ReadFromUser(m_kernel, std::addressof(user_value), addr)) { slp.CancelSleep(); R_THROW(ResultInvalidCurrentMemory); } diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index c6634313f..efbac0e6a 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -18,13 +18,13 @@ namespace Kernel { namespace { -bool ReadFromUser(Core::System& system, u32* out, KProcessAddress address) { - *out = system.Memory().Read32(GetInteger(address)); +bool ReadFromUser(KernelCore& kernel, u32* out, KProcessAddress address) { + *out = GetCurrentMemory(kernel).Read32(GetInteger(address)); return true; } -bool WriteToUser(Core::System& system, KProcessAddress address, const u32* p) { - system.Memory().Write32(GetInteger(address), *p); +bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) { + GetCurrentMemory(kernel).Write32(GetInteger(address), *p); return true; } @@ -33,21 +33,26 @@ bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u auto& monitor = system.Monitor(); const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); - // Load the value from the address. - const auto expected = monitor.ExclusiveRead32(current_core, GetInteger(address)); + u32 expected{}; - // Orr in the new mask. - u32 value = expected | new_orr_mask; + while (true) { + // Load the value from the address. + expected = monitor.ExclusiveRead32(current_core, GetInteger(address)); - // If the value is zero, use the if_zero value, otherwise use the newly orr'd value. - if (!expected) { - value = if_zero; - } + // Orr in the new mask. + u32 value = expected | new_orr_mask; + + // If the value is zero, use the if_zero value, otherwise use the newly orr'd value. + if (!expected) { + value = if_zero; + } + + // Try to store. + if (monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) { + break; + } - // Try to store. - if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) { // If we failed to store, try again. - return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask); } // We're done. @@ -128,7 +133,7 @@ Result KConditionVariable::SignalToAddress(KProcessAddress addr) { // Write the value to userspace. Result result{ResultSuccess}; - if (WriteToUser(m_system, addr, std::addressof(next_value))) [[likely]] { + if (WriteToUser(m_kernel, addr, std::addressof(next_value))) [[likely]] { result = ResultSuccess; } else { result = ResultInvalidCurrentMemory; @@ -157,7 +162,7 @@ Result KConditionVariable::WaitForAddress(Handle handle, KProcessAddress addr, u // Read the tag from userspace. u32 test_tag{}; - R_UNLESS(ReadFromUser(m_system, std::addressof(test_tag), addr), + R_UNLESS(ReadFromUser(m_kernel, std::addressof(test_tag), addr), ResultInvalidCurrentMemory); // If the tag isn't the handle (with wait mask), we're done. @@ -257,7 +262,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { // If we have no waiters, clear the has waiter flag. if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) { const u32 has_waiter_flag{}; - WriteToUser(m_system, cv_key, std::addressof(has_waiter_flag)); + WriteToUser(m_kernel, cv_key, std::addressof(has_waiter_flag)); } } } @@ -301,12 +306,12 @@ Result KConditionVariable::Wait(KProcessAddress addr, u64 key, u32 value, s64 ti // Write to the cv key. { const u32 has_waiter_flag = 1; - WriteToUser(m_system, key, std::addressof(has_waiter_flag)); + WriteToUser(m_kernel, key, std::addressof(has_waiter_flag)); std::atomic_thread_fence(std::memory_order_seq_cst); } // Write the value to userspace. - if (!WriteToUser(m_system, addr, std::addressof(next_value))) { + if (!WriteToUser(m_kernel, addr, std::addressof(next_value))) { slp.CancelSleep(); R_THROW(ResultInvalidCurrentMemory); } diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index cb39387ea..02b5cada4 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -108,7 +108,8 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_addr, size_t code_size, KSystemResource* system_resource, - KResourceLimit* resource_limit) { + KResourceLimit* resource_limit, + Core::Memory::Memory& memory) { const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) { return KAddressSpaceInfo::GetAddressSpaceStart(m_address_space_width, type); @@ -117,6 +118,9 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type return KAddressSpaceInfo::GetAddressSpaceSize(m_address_space_width, type); }; + // Set the tracking memory + m_memory = std::addressof(memory); + // Set our width and heap/alias sizes m_address_space_width = GetAddressSpaceWidthFromType(as_type); const KProcessAddress start = 0; @@ -334,10 +338,10 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type void KPageTable::Finalize() { // Finalize memory blocks. - m_memory_block_manager.Finalize( - m_memory_block_slab_manager, [&](KProcessAddress addr, u64 size) { - m_system.Memory().UnmapRegion(*m_page_table_impl, addr, size); - }); + m_memory_block_manager.Finalize(m_memory_block_slab_manager, + [&](KProcessAddress addr, u64 size) { + m_memory->UnmapRegion(*m_page_table_impl, addr, size); + }); // Release any insecure mapped memory. if (m_mapped_insecure_memory) { @@ -1010,23 +1014,22 @@ Result KPageTable::SetupForIpcServer(KProcessAddress* out_addr, size_t size, clear_size = 0; } - std::memset(m_system.Memory().GetPointer<void>(GetInteger(start_partial_virt)), - fill_val, partial_offset); + std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt)), fill_val, + partial_offset); std::memcpy( - m_system.Memory().GetPointer<void>(GetInteger(start_partial_virt) + partial_offset), - m_system.Memory().GetPointer<void>( - GetInteger( - GetHeapVirtualAddress(m_system.Kernel().MemoryLayout(), cur_block_addr)) + - partial_offset), + m_memory->GetPointer<void>(GetInteger(start_partial_virt) + partial_offset), + m_memory->GetPointer<void>(GetInteger(GetHeapVirtualAddress( + m_system.Kernel().MemoryLayout(), cur_block_addr)) + + partial_offset), copy_size); if (clear_size > 0) { - std::memset(m_system.Memory().GetPointer<void>(GetInteger(start_partial_virt) + - partial_offset + copy_size), + std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt) + + partial_offset + copy_size), fill_val, clear_size); } } else { - std::memset(m_system.Memory().GetPointer<void>(GetInteger(start_partial_virt)), - fill_val, PageSize); + std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt)), fill_val, + PageSize); } // Map the page. @@ -1099,15 +1102,14 @@ Result KPageTable::SetupForIpcServer(KProcessAddress* out_addr, size_t size, GetHeapVirtualAddress(m_system.Kernel().MemoryLayout(), end_partial_page); if (send) { const size_t copy_size = src_end - mapping_src_end; - std::memcpy(m_system.Memory().GetPointer<void>(GetInteger(end_partial_virt)), - m_system.Memory().GetPointer<void>(GetInteger(GetHeapVirtualAddress( + std::memcpy(m_memory->GetPointer<void>(GetInteger(end_partial_virt)), + m_memory->GetPointer<void>(GetInteger(GetHeapVirtualAddress( m_system.Kernel().MemoryLayout(), cur_block_addr))), copy_size); - std::memset( - m_system.Memory().GetPointer<void>(GetInteger(end_partial_virt) + copy_size), - fill_val, PageSize - copy_size); + std::memset(m_memory->GetPointer<void>(GetInteger(end_partial_virt) + copy_size), + fill_val, PageSize - copy_size); } else { - std::memset(m_system.Memory().GetPointer<void>(GetInteger(end_partial_virt)), fill_val, + std::memset(m_memory->GetPointer<void>(GetInteger(end_partial_virt)), fill_val, PageSize); } @@ -2800,7 +2802,7 @@ Result KPageTable::SetHeapSize(u64* out, size_t size) { // Clear all the newly allocated pages. for (size_t cur_page = 0; cur_page < num_pages; ++cur_page) { - std::memset(m_system.Memory().GetPointer(m_current_heap_end + (cur_page * PageSize)), 0, + std::memset(m_memory->GetPointer(m_current_heap_end + (cur_page * PageSize)), 0, PageSize); } @@ -3006,7 +3008,7 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, const KPageGr const size_t size{node.GetNumPages() * PageSize}; // Map the pages. - m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress()); + m_memory->MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress()); addr += size; } @@ -3039,14 +3041,14 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); this->AddRegionToPages(addr, num_pages, pages_to_close); - m_system.Memory().UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize); + m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize); break; } case OperationType::MapFirst: case OperationType::Map: { ASSERT(map_addr); ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize)); - m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr); + m_memory->MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr); // Open references to pages, if we should. if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) { diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 1917b2a98..022d15f35 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -66,7 +66,8 @@ public: Result InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_addr, size_t code_size, - KSystemResource* system_resource, KResourceLimit* resource_limit); + KSystemResource* system_resource, KResourceLimit* resource_limit, + Core::Memory::Memory& memory); void Finalize(); @@ -546,6 +547,7 @@ private: Core::System& m_system; KernelCore& m_kernel; + Core::Memory::Memory* m_memory{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 53f8139f3..efe86ad27 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -367,8 +367,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: // Initialize process address space if (const Result result{m_page_table.InitializeForProcess( metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application, - 0x8000000, code_size, std::addressof(m_kernel.GetAppSystemResource()), - m_resource_limit)}; + 0x8000000, code_size, std::addressof(m_kernel.GetAppSystemResource()), m_resource_limit, + m_kernel.System().ApplicationMemory())}; result.IsError()) { R_RETURN(result); } @@ -592,8 +592,7 @@ Result KProcess::DeleteThreadLocalRegion(KProcessAddress addr) { R_SUCCEED(); } -bool KProcess::InsertWatchpoint(Core::System& system, KProcessAddress addr, u64 size, - DebugWatchpointType type) { +bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) { const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) { return wp.type == DebugWatchpointType::None; })}; @@ -609,14 +608,13 @@ bool KProcess::InsertWatchpoint(Core::System& system, KProcessAddress addr, u64 for (KProcessAddress page = Common::AlignDown(GetInteger(addr), PageSize); page < addr + size; page += PageSize) { m_debug_page_refcounts[page]++; - system.Memory().MarkRegionDebug(page, PageSize, true); + this->GetMemory().MarkRegionDebug(page, PageSize, true); } return true; } -bool KProcess::RemoveWatchpoint(Core::System& system, KProcessAddress addr, u64 size, - DebugWatchpointType type) { +bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) { const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) { return wp.start_address == addr && wp.end_address == addr + size && wp.type == type; })}; @@ -633,7 +631,7 @@ bool KProcess::RemoveWatchpoint(Core::System& system, KProcessAddress addr, u64 page += PageSize) { m_debug_page_refcounts[page]--; if (!m_debug_page_refcounts[page]) { - system.Memory().MarkRegionDebug(page, PageSize, false); + this->GetMemory().MarkRegionDebug(page, PageSize, false); } } @@ -646,8 +644,7 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { m_page_table.SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); }; - m_kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), - code_set.memory.size()); + this->GetMemory().WriteBlock(base_addr, code_set.memory.data(), code_set.memory.size()); ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute); ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read); @@ -706,4 +703,9 @@ Result KProcess::AllocateMainThreadStack(std::size_t stack_size) { R_SUCCEED(); } +Core::Memory::Memory& KProcess::GetMemory() const { + // TODO: per-process memory + return m_kernel.System().ApplicationMemory(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 04b6bbb86..925981d06 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -22,8 +22,12 @@ #include "core/hle/result.h" namespace Core { +namespace Memory { +class Memory; +}; + class System; -} +} // namespace Core namespace FileSys { class ProgramMetadata; @@ -135,6 +139,9 @@ public: return m_handle_table; } + /// Gets a reference to process's memory. + Core::Memory::Memory& GetMemory() const; + Result SignalToAddress(KProcessAddress address) { return m_condition_var.SignalToAddress(address); } @@ -397,12 +404,10 @@ public: // Debug watchpoint management // Attempts to insert a watchpoint into a free slot. Returns false if none are available. - bool InsertWatchpoint(Core::System& system, KProcessAddress addr, u64 size, - DebugWatchpointType type); + bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); // Attempts to remove the watchpoint specified by the given parameters. - bool RemoveWatchpoint(Core::System& system, KProcessAddress addr, u64 size, - DebugWatchpointType type); + bool RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const { return m_watchpoints; diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 2288ee435..c66aff501 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -222,7 +222,7 @@ Result KServerSession::SendReply(bool is_hle) { // HLE servers write directly to a pointer to the thread command buffer. Therefore // the reply has already been written in this case. } else { - Core::Memory::Memory& memory{m_kernel.System().Memory()}; + Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; KThread* server_thread{GetCurrentThreadPointer(m_kernel)}; UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); @@ -319,7 +319,7 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext // bool recv_list_broken = false; // Receive the message. - Core::Memory::Memory& memory{m_kernel.System().Memory()}; + Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; if (out_context != nullptr) { // HLE request. u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))}; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 9d101c640..70480b725 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -546,7 +546,7 @@ u16 KThread::GetUserDisableCount() const { return {}; } - auto& memory = m_kernel.System().Memory(); + auto& memory = this->GetOwnerProcess()->GetMemory(); return memory.Read16(m_tls_address + offsetof(ThreadLocalRegion, disable_count)); } @@ -556,7 +556,7 @@ void KThread::SetInterruptFlag() { return; } - auto& memory = m_kernel.System().Memory(); + auto& memory = this->GetOwnerProcess()->GetMemory(); memory.Write16(m_tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 1); } @@ -566,7 +566,7 @@ void KThread::ClearInterruptFlag() { return; } - auto& memory = m_kernel.System().Memory(); + auto& memory = this->GetOwnerProcess()->GetMemory(); memory.Write16(m_tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 0); } @@ -1422,6 +1422,11 @@ s32 GetCurrentCoreId(KernelCore& kernel) { return GetCurrentThread(kernel).GetCurrentCore(); } +Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) { + // TODO: per-process memory + return kernel.System().ApplicationMemory(); +} + KScopedDisableDispatch::~KScopedDisableDispatch() { // If we are shutting down the kernel, none of this is relevant anymore. if (m_kernel.IsShuttingDown()) { diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 0fa9672bf..9c1a41128 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -34,6 +34,9 @@ class Fiber; } namespace Core { +namespace Memory { +class Memory; +} class ARM_Interface; class System; } // namespace Core @@ -113,6 +116,7 @@ KThread& GetCurrentThread(KernelCore& kernel); KProcess* GetCurrentProcessPointer(KernelCore& kernel); KProcess& GetCurrentProcess(KernelCore& kernel); s32 GetCurrentCoreId(KernelCore& kernel); +Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel); class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, public boost::intrusive::list_base_hook<>, diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 29809b2c5..4f3366c9d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -102,7 +102,7 @@ struct KernelCore::Impl { void InitializeCores() { for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { cores[core_id]->Initialize((*application_process).Is64BitProcess()); - system.Memory().SetCurrentPageTable(*application_process, core_id); + system.ApplicationMemory().SetCurrentPageTable(*application_process, core_id); } } @@ -206,7 +206,7 @@ struct KernelCore::Impl { void InitializePhysicalCores() { exclusive_monitor = - Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); + Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES); for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { const s32 core{static_cast<s32>(i)}; diff --git a/src/core/hle/kernel/svc/svc_cache.cpp b/src/core/hle/kernel/svc/svc_cache.cpp index 1779832d3..082942dab 100644 --- a/src/core/hle/kernel/svc/svc_cache.cpp +++ b/src/core/hle/kernel/svc/svc_cache.cpp @@ -46,7 +46,7 @@ Result FlushProcessDataCache(Core::System& system, Handle process_handle, u64 ad R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); // Perform the operation. - R_RETURN(system.Memory().FlushDataCache(*process, address, size)); + R_RETURN(GetCurrentMemory(system.Kernel()).FlushDataCache(address, size)); } void FlushEntireDataCache64(Core::System& system) { diff --git a/src/core/hle/kernel/svc/svc_debug_string.cpp b/src/core/hle/kernel/svc/svc_debug_string.cpp index 8771d2b01..4c14ce668 100644 --- a/src/core/hle/kernel/svc/svc_debug_string.cpp +++ b/src/core/hle/kernel/svc/svc_debug_string.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/core.h" +#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/svc.h" #include "core/memory.h" @@ -12,7 +13,7 @@ Result OutputDebugString(Core::System& system, u64 address, u64 len) { R_SUCCEED_IF(len == 0); std::string str(len, '\0'); - system.Memory().ReadBlock(address, str.data(), str.size()); + GetCurrentMemory(system.Kernel()).ReadBlock(address, str.data(), str.size()); LOG_DEBUG(Debug_Emulated, "{}", str); R_SUCCEED(); diff --git a/src/core/hle/kernel/svc/svc_exception.cpp b/src/core/hle/kernel/svc/svc_exception.cpp index 4ab5f471f..580cf2f75 100644 --- a/src/core/hle/kernel/svc/svc_exception.cpp +++ b/src/core/hle/kernel/svc/svc_exception.cpp @@ -25,7 +25,7 @@ void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) { return; } - auto& memory = system.Memory(); + auto& memory = GetCurrentMemory(system.Kernel()); // This typically is an error code so we're going to assume this is the case if (sz == sizeof(u32)) { diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp index 2a8c09a79..ea03068aa 100644 --- a/src/core/hle/kernel/svc/svc_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_ipc.cpp @@ -41,12 +41,12 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); - R_UNLESS(system.Memory().IsValidVirtualAddressRange( + R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange( handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)), ResultInvalidPointer); std::vector<Handle> handles(num_handles); - system.Memory().ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles); + GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles); // Convert handle list to object table. std::vector<KSynchronizationObject*> objs(num_handles); diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp index c6eb70422..abba757c7 100644 --- a/src/core/hle/kernel/svc/svc_port.cpp +++ b/src/core/hle/kernel/svc/svc_port.cpp @@ -14,7 +14,8 @@ namespace Kernel::Svc { Result ConnectToNamedPort(Core::System& system, Handle* out, u64 user_name) { // Copy the provided name from user memory to kernel memory. - auto string_name = system.Memory().ReadCString(user_name, KObjectName::NameLengthMax); + auto string_name = + GetCurrentMemory(system.Kernel()).ReadCString(user_name, KObjectName::NameLengthMax); std::array<char, KObjectName::NameLengthMax> name{}; std::strncpy(name.data(), string_name.c_str(), KObjectName::NameLengthMax - 1); @@ -62,7 +63,8 @@ Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, int32_t max_sessions) { // Copy the provided name from user memory to kernel memory. - auto string_name = system.Memory().ReadCString(user_name, KObjectName::NameLengthMax); + auto string_name = + GetCurrentMemory(system.Kernel()).ReadCString(user_name, KObjectName::NameLengthMax); // Copy the provided name from user memory to kernel memory. std::array<char, KObjectName::NameLengthMax> name{}; diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp index 3c3579947..619ed16a3 100644 --- a/src/core/hle/kernel/svc/svc_process.cpp +++ b/src/core/hle/kernel/svc/svc_process.cpp @@ -73,7 +73,7 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc R_THROW(ResultInvalidCurrentMemory); } - auto& memory = system.Memory(); + auto& memory = GetCurrentMemory(kernel); const auto& process_list = kernel.GetProcessList(); const auto num_processes = process_list.size(); const auto copy_amount = diff --git a/src/core/hle/kernel/svc/svc_query_memory.cpp b/src/core/hle/kernel/svc/svc_query_memory.cpp index 5db5611f0..4d9fcd25f 100644 --- a/src/core/hle/kernel/svc/svc_query_memory.cpp +++ b/src/core/hle/kernel/svc/svc_query_memory.cpp @@ -30,10 +30,10 @@ Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageIn R_THROW(ResultInvalidHandle); } - auto& memory{system.Memory()}; + auto& current_memory{GetCurrentMemory(system.Kernel())}; const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()}; - memory.WriteBlock(out_memory_info, std::addressof(memory_info), sizeof(memory_info)); + current_memory.WriteBlock(out_memory_info, std::addressof(memory_info), sizeof(memory_info)); //! This is supposed to be part of the QueryInfo call. *out_page_info = {}; diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index e490a13ae..04d65f0bd 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp @@ -90,7 +90,8 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha std::vector<Handle> handles(num_handles); if (num_handles > 0) { - system.Memory().ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle)); + GetCurrentMemory(system.Kernel()) + .ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle)); } R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns)); diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 0be4858a2..37b54079c 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp @@ -178,7 +178,7 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha R_TRY(thread->GetThreadContext3(context)); // Copy the thread context to user space. - system.Memory().WriteBlock(out_context, context.data(), context.size()); + GetCurrentMemory(kernel).WriteBlock(out_context, context.data(), context.size()); R_SUCCEED(); } @@ -242,7 +242,7 @@ Result GetThreadList(Core::System& system, s32* out_num_threads, u64 out_thread_ R_THROW(ResultInvalidCurrentMemory); } - auto& memory = system.Memory(); + auto& memory = GetCurrentMemory(system.Kernel()); const auto& thread_list = current_process->GetThreadList(); const auto num_threads = thread_list.size(); const auto copy_amount = std::min(static_cast<std::size_t>(out_thread_ids_size), num_threads); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index deeca925d..a17c46121 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -945,7 +945,7 @@ public: {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, {10, &ILibraryAppletAccessor::Start, "Start"}, - {20, nullptr, "RequestExit"}, + {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"}, {25, nullptr, "Terminate"}, {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, @@ -1010,6 +1010,15 @@ private: rb.Push(ResultSuccess); } + void RequestExit(HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + ASSERT(applet != nullptr); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(applet->RequestExit()); + } + void PushInData(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -1265,7 +1274,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) } std::vector<u8> memory(transfer_mem->GetSize()); - system.Memory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); + system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), + memory.size()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); @@ -1298,7 +1308,8 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { } std::vector<u8> memory(transfer_mem->GetSize()); - system.Memory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); + system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), + memory.size()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 162687b29..93c9f2a55 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -174,4 +174,9 @@ void Cabinet::Cancel() { broker.SignalStateChanged(); } +Result Cabinet::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h index 84197a807..edd295a27 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -89,6 +89,7 @@ public: void Execute() override; void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); void Cancel(); + Result RequestExit() override; private: const Core::Frontend::CabinetApplet& frontend; diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 58484519b..9840d2547 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -224,7 +224,8 @@ void Controller::Execute() { parameters.allow_dual_joycons, parameters.allow_left_joycon, parameters.allow_right_joycon); - frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters); + frontend.ReconfigureControllers( + [this](bool is_success) { ConfigurationComplete(is_success); }, parameters); break; } case ControllerSupportMode::ShowControllerStrapGuide: @@ -232,16 +233,16 @@ void Controller::Execute() { case ControllerSupportMode::ShowControllerKeyRemappingForSystem: UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", controller_private_arg.mode); - ConfigurationComplete(); + ConfigurationComplete(true); break; default: { - ConfigurationComplete(); + ConfigurationComplete(true); break; } } } -void Controller::ConfigurationComplete() { +void Controller::ConfigurationComplete(bool is_success) { ControllerSupportResultInfo result_info{}; // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. @@ -250,7 +251,8 @@ void Controller::ConfigurationComplete() { result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId()); - result_info.result = 0; + result_info.result = + is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel; LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}", result_info.player_count, result_info.selected_id, result_info.result); @@ -262,4 +264,9 @@ void Controller::ConfigurationComplete() { broker.SignalStateChanged(); } +Result Controller::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h index 1f9adec65..f6c64f633 100644 --- a/src/core/hle/service/am/applets/applet_controller.h +++ b/src/core/hle/service/am/applets/applet_controller.h @@ -48,6 +48,11 @@ enum class ControllerSupportCaller : u8 { MaxControllerSupportCaller, }; +enum class ControllerSupportResult : u32 { + Success = 0, + Cancel = 2, +}; + struct ControllerSupportArgPrivate { u32 arg_private_size{}; u32 arg_size{}; @@ -112,7 +117,7 @@ struct ControllerSupportResultInfo { s8 player_count{}; INSERT_PADDING_BYTES(3); u32 selected_id{}; - u32 result{}; + ControllerSupportResult result{}; }; static_assert(sizeof(ControllerSupportResultInfo) == 0xC, "ControllerSupportResultInfo has incorrect size."); @@ -129,8 +134,9 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; - void ConfigurationComplete(); + void ConfigurationComplete(bool is_success); private: const Core::Frontend::ControllerApplet& frontend; diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index b013896b4..b46ea840c 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -209,4 +209,9 @@ void Error::DisplayCompleted() { broker.SignalStateChanged(); } +Result Error::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_error.h b/src/core/hle/service/am/applets/applet_error.h index d78d6f1d1..d822a32bb 100644 --- a/src/core/hle/service/am/applets/applet_error.h +++ b/src/core/hle/service/am/applets/applet_error.h @@ -34,6 +34,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; void DisplayCompleted(); diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index 1eefa85e3..8b352020e 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -150,6 +150,11 @@ void Auth::AuthFinished(bool is_successful) { broker.SignalStateChanged(); } +Result Auth::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, const Core::Frontend::PhotoViewerApplet& frontend_) : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} @@ -202,6 +207,11 @@ void PhotoViewer::ViewFinished() { broker.SignalStateChanged(); } +Result PhotoViewer::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) : Applet{system_, applet_mode_}, id{id_}, system{system_} {} @@ -250,4 +260,9 @@ void StubApplet::Execute() { broker.SignalStateChanged(); } +Result StubApplet::RequestExit() { + // Nothing to do. + R_SUCCEED(); +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_general_backend.h b/src/core/hle/service/am/applets/applet_general_backend.h index a9f2535a2..34ecaebb9 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.h +++ b/src/core/hle/service/am/applets/applet_general_backend.h @@ -28,6 +28,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; void AuthFinished(bool is_successful = true); @@ -59,6 +60,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; void ViewFinished(); @@ -80,6 +82,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; private: AppletId id; diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp index ae80ef506..d1f652c09 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp @@ -135,4 +135,9 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, broker.SignalStateChanged(); } +Result MiiEdit::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_mii_edit.h b/src/core/hle/service/am/applets/applet_mii_edit.h index d18dd3cf5..3f46fae1b 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.h +++ b/src/core/hle/service/am/applets/applet_mii_edit.h @@ -25,6 +25,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; void MiiEditOutput(MiiEditResult result, s32 index); diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp index 1d69f5447..89cb323e9 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ b/src/core/hle/service/am/applets/applet_profile_select.cpp @@ -25,13 +25,29 @@ void ProfileSelect::Initialize() { final_data.clear(); Applet::Initialize(); + profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; const auto user_config_storage = broker.PopNormalDataToApplet(); ASSERT(user_config_storage != nullptr); const auto& user_config = user_config_storage->GetData(); - ASSERT(user_config.size() >= sizeof(UserSelectionConfig)); - std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig)); + LOG_INFO(Service_AM, "Initializing Profile Select Applet with version={}", + profile_select_version); + + switch (profile_select_version) { + case ProfileSelectAppletVersion::Version1: + ASSERT(user_config.size() == sizeof(UiSettingsV1)); + std::memcpy(&config_old, user_config.data(), sizeof(UiSettingsV1)); + break; + case ProfileSelectAppletVersion::Version2: + case ProfileSelectAppletVersion::Version3: + ASSERT(user_config.size() == sizeof(UiSettings)); + std::memcpy(&config, user_config.data(), sizeof(UiSettings)); + break; + default: + UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); + break; + } } bool ProfileSelect::TransactionComplete() const { @@ -52,11 +68,37 @@ void ProfileSelect::Execute() { return; } - frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); }); + Core::Frontend::ProfileSelectParameters parameters{}; + + switch (profile_select_version) { + case ProfileSelectAppletVersion::Version1: + parameters = { + .mode = config_old.mode, + .invalid_uid_list = config_old.invalid_uid_list, + .display_options = config_old.display_options, + .purpose = UserSelectionPurpose::General, + }; + break; + case ProfileSelectAppletVersion::Version2: + case ProfileSelectAppletVersion::Version3: + parameters = { + .mode = config.mode, + .invalid_uid_list = config.invalid_uid_list, + .display_options = config.display_options, + .purpose = config.purpose, + }; + break; + default: + UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); + break; + } + + frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); }, + parameters); } void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { - UserSelectionOutput output{}; + UiReturnArg output{}; if (uuid.has_value() && uuid->IsValid()) { output.result = 0; @@ -67,10 +109,15 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { output.uuid_selected = Common::InvalidUUID; } - final_data = std::vector<u8>(sizeof(UserSelectionOutput)); + final_data = std::vector<u8>(sizeof(UiReturnArg)); std::memcpy(final_data.data(), &output, final_data.size()); broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); broker.SignalStateChanged(); } +Result ProfileSelect::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h index b77f1d205..369f9250f 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ b/src/core/hle/service/am/applets/applet_profile_select.h @@ -16,19 +16,100 @@ class System; namespace Service::AM::Applets { -struct UserSelectionConfig { - // TODO(DarkLordZach): RE this structure - // It seems to be flags and the like that determine the UI of the applet on the switch... from - // my research this is safe to ignore for now. - INSERT_PADDING_BYTES(0xA0); +enum class ProfileSelectAppletVersion : u32 { + Version1 = 0x1, // 1.0.0+ + Version2 = 0x10000, // 2.0.0+ + Version3 = 0x20000, // 6.0.0+ }; -static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size."); -struct UserSelectionOutput { +// This is nn::account::UiMode +enum class UiMode { + UserSelector, + UserCreator, + EnsureNetworkServiceAccountAvailable, + UserIconEditor, + UserNicknameEditor, + UserCreatorForStarter, + NintendoAccountAuthorizationRequestContext, + IntroduceExternalNetworkServiceAccount, + IntroduceExternalNetworkServiceAccountForRegistration, + NintendoAccountNnidLinker, + LicenseRequirementsForNetworkService, + LicenseRequirementsForNetworkServiceWithUserContextImpl, + UserCreatorForImmediateNaLoginTest, + UserQualificationPromoter, +}; + +// This is nn::account::UserSelectionPurpose +enum class UserSelectionPurpose { + General, + GameCardRegistration, + EShopLaunch, + EShopItemShow, + PicturePost, + NintendoAccountLinkage, + SettingsUpdate, + SaveDataDeletion, + UserMigration, + SaveDataTransfer, +}; + +// This is nn::account::NintendoAccountStartupDialogType +enum class NintendoAccountStartupDialogType { + LoginAndCreate, + Login, + Create, +}; + +// This is nn::account::UserSelectionSettingsForSystemService +struct UserSelectionSettingsForSystemService { + UserSelectionPurpose purpose; + bool enable_user_creation; + INSERT_PADDING_BYTES(0x3); +}; +static_assert(sizeof(UserSelectionSettingsForSystemService) == 0x8, + "UserSelectionSettingsForSystemService has incorrect size."); + +struct UiSettingsDisplayOptions { + bool is_network_service_account_required; + bool is_skip_enabled; + bool is_system_or_launcher; + bool is_registration_permitted; + bool show_skip_button; + bool aditional_select; + bool show_user_selector; + bool is_unqualified_user_selectable; +}; +static_assert(sizeof(UiSettingsDisplayOptions) == 0x8, + "UiSettingsDisplayOptions has incorrect size."); + +struct UiSettingsV1 { + UiMode mode; + INSERT_PADDING_BYTES(0x4); + std::array<Common::UUID, 8> invalid_uid_list; + u64 application_id; + UiSettingsDisplayOptions display_options; +}; +static_assert(sizeof(UiSettingsV1) == 0x98, "UiSettings has incorrect size."); + +// This is nn::account::UiSettings +struct UiSettings { + UiMode mode; + INSERT_PADDING_BYTES(0x4); + std::array<Common::UUID, 8> invalid_uid_list; + u64 application_id; + UiSettingsDisplayOptions display_options; + UserSelectionPurpose purpose; + INSERT_PADDING_BYTES(0x4); +}; +static_assert(sizeof(UiSettings) == 0xA0, "UiSettings has incorrect size."); + +// This is nn::account::UiReturnArg +struct UiReturnArg { u64 result; Common::UUID uuid_selected; }; -static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size."); +static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); class ProfileSelect final : public Applet { public: @@ -42,13 +123,17 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; void SelectionComplete(std::optional<Common::UUID> uuid); private: const Core::Frontend::ProfileSelectApplet& frontend; - UserSelectionConfig config; + UiSettings config; + UiSettingsV1 config_old; + ProfileSelectAppletVersion profile_select_version; + bool complete = false; Result status = ResultSuccess; std::vector<u8> final_data; diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp index c18236045..4145bb84f 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp +++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp @@ -770,6 +770,11 @@ void SoftwareKeyboard::ExitKeyboard() { broker.SignalStateChanged(); } +Result SoftwareKeyboard::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + // Inline Software Keyboard Requests void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) { diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.h b/src/core/hle/service/am/applets/applet_software_keyboard.h index b01b31c98..2e919811b 100644 --- a/src/core/hle/service/am/applets/applet_software_keyboard.h +++ b/src/core/hle/service/am/applets/applet_software_keyboard.h @@ -31,6 +31,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; /** * Submits the input text to the application. diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index f061bae80..2accf7898 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -363,6 +363,11 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) broker.SignalStateChanged(); } +Result WebBrowser::RequestExit() { + frontend.Close(); + R_SUCCEED(); +} + bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const { return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end(); } diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/applets/applet_web_browser.h index fd727fac8..99fe18659 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.h +++ b/src/core/hle/service/am/applets/applet_web_browser.h @@ -35,6 +35,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; + Result RequestExit() override; void ExtractOfflineRomFS(); diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index a22eb62a8..12f374199 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -142,6 +142,7 @@ public: virtual Result GetStatus() const = 0; virtual void ExecuteInteractive() = 0; virtual void Execute() = 0; + virtual Result RequestExit() = 0; AppletDataBroker& GetBroker() { return broker; diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index 37f2e4405..bcb272eaf 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -60,7 +60,8 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti // Update seven six axis transfer memory seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); - system.Memory().WriteBlock(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); + system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo, + sizeof(seven_sixaxis_lifo)); } void Controller_ConsoleSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index ba6f04d8d..b070327ec 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -819,12 +819,12 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode return communication_mode; } -Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, - NpadJoyDeviceType npad_device_type, - NpadJoyAssignmentMode assignment_mode) { +bool Controller_NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, + NpadJoyDeviceType npad_device_type, + NpadJoyAssignmentMode assignment_mode) { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return InvalidNpadId; + return false; } auto& controller = GetControllerFromNpadIdType(npad_id); @@ -833,7 +833,7 @@ Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, } if (!controller.device->IsConnected()) { - return ResultSuccess; + return false; } if (assignment_mode == NpadJoyAssignmentMode::Dual) { @@ -842,52 +842,52 @@ Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, controller.is_dual_left_connected = true; controller.is_dual_right_connected = false; UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); - return ResultSuccess; + return false; } if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { DisconnectNpad(npad_id); controller.is_dual_left_connected = false; controller.is_dual_right_connected = true; UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); - return ResultSuccess; + return false; } - return ResultSuccess; + return false; } // This is for NpadJoyAssignmentMode::Single // Only JoyconDual get affected by this function if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { - return ResultSuccess; + return false; } if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { DisconnectNpad(npad_id); UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); - return ResultSuccess; + return false; } if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { DisconnectNpad(npad_id); UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); - return ResultSuccess; + return false; } // We have two controllers connected to the same npad_id we need to split them - const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId(); - auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); + new_npad_id = hid_core.GetFirstDisconnectedNpadId(); + auto& controller_2 = GetControllerFromNpadIdType(new_npad_id); DisconnectNpad(npad_id); if (npad_device_type == NpadJoyDeviceType::Left) { UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); controller_2.is_dual_left_connected = false; controller_2.is_dual_right_connected = true; - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); } else { UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); controller_2.is_dual_left_connected = true; controller_2.is_dual_right_connected = false; - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); + UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); } - return ResultSuccess; + return true; } bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, @@ -1388,7 +1388,8 @@ Result Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, return NpadIsDualJoycon; } - // Disconnect the joycon at the second id and connect the dual joycon at the first index. + // Disconnect the joycons and connect them as dual joycon at the first index. + DisconnectNpad(npad_id_1); DisconnectNpad(npad_id_2); controller_1.is_dual_left_connected = true; controller_1.is_dual_right_connected = true; diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index a5998c453..9cfe298f1 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -102,8 +102,8 @@ public: void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); NpadCommunicationMode GetNpadCommunicationMode() const; - Result SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, - NpadJoyAssignmentMode assignment_mode); + bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, + NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, const Core::HID::VibrationValue& vibration_value); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 4529ad643..87e7b864a 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -302,7 +302,7 @@ Hid::Hid(Core::System& system_) {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"}, {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, - {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, + {133, &Hid::SetNpadJoyAssignmentModeSingleWithDestination, "SetNpadJoyAssignmentModeSingleWithDestination"}, {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"}, {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"}, {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"}, @@ -1180,8 +1180,10 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; + Core::HID::NpadIdType new_npad_id{}; auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, + controller.SetNpadMode(new_npad_id, parameters.npad_id, + Controller_NPad::NpadJoyDeviceType::Left, Controller_NPad::NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, @@ -1203,8 +1205,9 @@ void Hid::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; + Core::HID::NpadIdType new_npad_id{}; auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, + controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, Controller_NPad::NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", @@ -1226,8 +1229,10 @@ void Hid::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; + Core::HID::NpadIdType new_npad_id{}; auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual); + controller.SetNpadMode(new_npad_id, parameters.npad_id, {}, + Controller_NPad::NpadJoyAssignmentMode::Dual); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1369,6 +1374,34 @@ void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { rb.Push(result); } +void Hid::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + Core::HID::NpadIdType npad_id; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + Controller_NPad::NpadJoyDeviceType npad_joy_device_type; + }; + static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + Core::HID::NpadIdType new_npad_id{}; + auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); + const auto is_reassigned = + controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, + Controller_NPad::NpadJoyAssignmentMode::Single); + + LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", + parameters.npad_id, parameters.applet_resource_user_id, + parameters.npad_joy_device_type); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(is_reassigned); + rb.PushEnum(new_npad_id); +} + void Hid::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index c69e5f3fb..f247b83c2 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -151,6 +151,7 @@ private: void SwapNpadAssignment(HLERequestContext& ctx); void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx); void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx); + void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx); void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx); void SetNpadCaptureButtonAssignment(HLERequestContext& ctx); void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx); diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp index 65a2dd521..378108012 100644 --- a/src/core/hle/service/hid/hidbus/ringcon.cpp +++ b/src/core/hle/service/hid/hidbus/ringcon.cpp @@ -64,8 +64,8 @@ void RingController::OnUpdate() { curr_entry.polling_data.out_size = sizeof(ringcon_value); std::memcpy(curr_entry.polling_data.data.data(), &ringcon_value, sizeof(ringcon_value)); - system.Memory().WriteBlock(transfer_memory, &enable_sixaxis_data, - sizeof(enable_sixaxis_data)); + system.ApplicationMemory().WriteBlock(transfer_memory, &enable_sixaxis_data, + sizeof(enable_sixaxis_data)); break; } default: diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp index ca5d067e8..803a6277c 100644 --- a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp +++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp @@ -58,16 +58,16 @@ void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType if (camera_data.format != current_config.origin_format) { LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format, current_config.origin_format); - system.Memory().ZeroBlock(*system.ApplicationProcess(), transfer_memory, - GetDataSize(current_config.trimming_format)); + system.ApplicationMemory().ZeroBlock(transfer_memory, + GetDataSize(current_config.trimming_format)); return; } if (current_config.origin_format > current_config.trimming_format) { LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}", current_config.origin_format, current_config.trimming_format); - system.Memory().ZeroBlock(*system.ApplicationProcess(), transfer_memory, - GetDataSize(current_config.trimming_format)); + system.ApplicationMemory().ZeroBlock(transfer_memory, + GetDataSize(current_config.trimming_format)); return; } @@ -84,8 +84,8 @@ void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType "Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})", current_config.trimming_start_x, current_config.trimming_start_y, trimming_width, trimming_height, origin_width, origin_height); - system.Memory().ZeroBlock(*system.ApplicationProcess(), transfer_memory, - GetDataSize(current_config.trimming_format)); + system.ApplicationMemory().ZeroBlock(transfer_memory, + GetDataSize(current_config.trimming_format)); return; } @@ -99,8 +99,8 @@ void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType } } - system.Memory().WriteBlock(transfer_memory, window_data.data(), - GetDataSize(current_config.trimming_format)); + system.ApplicationMemory().WriteBlock(transfer_memory, window_data.data(), + GetDataSize(current_config.trimming_format)); if (!IsProcessorActive()) { StartProcessor(); @@ -148,7 +148,7 @@ Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState( std::vector<u8>& data) const { const auto size = GetDataSize(current_config.trimming_format); data.resize(size); - system.Memory().ReadBlock(transfer_memory, data.data(), size); + system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size); return processor_state; } diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index cca697c64..2290df705 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -303,8 +303,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti } // Copy the translated command buffer back into the thread's command buffer area. - memory.WriteBlock(owner_process, requesting_thread.GetTlsAddress(), cmd_buf.data(), - write_size * sizeof(u32)); + memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32)); return ResultSuccess; } diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 607f27b21..be996870f 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp @@ -24,8 +24,8 @@ class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { public: explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, CodeRange user_ro) - : ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, context{ - system_.Memory()} { + : ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, + context{system_.ApplicationMemory()} { // clang-format off static const FunctionInfo functions[] = { {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 437dc2ea5..c42489ff9 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -225,7 +225,7 @@ public: // Read NRR data from memory std::vector<u8> nrr_data(nrr_size); - system.Memory().ReadBlock(nrr_address, nrr_data.data(), nrr_size); + system.ApplicationMemory().ReadBlock(nrr_address, nrr_data.data(), nrr_size); NRRHeader header; std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); @@ -314,7 +314,7 @@ public: const auto is_region_available = [&](VAddr addr) { const auto end_addr = addr + size; while (addr < end_addr) { - if (system.Memory().IsValidVirtualAddress(addr)) { + if (system.ApplicationMemory().IsValidVirtualAddress(addr)) { return false; } @@ -427,8 +427,8 @@ public: const VAddr bss_end_addr{ Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)}; - const auto CopyCode = [this, process](VAddr src_addr, VAddr dst_addr, u64 size) { - system.Memory().CopyBlock(*process, dst_addr, src_addr, size); + const auto CopyCode = [this](VAddr src_addr, VAddr dst_addr, u64 size) { + system.ApplicationMemory().CopyBlock(dst_addr, src_addr, size); }; CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start, nro_header.segment_headers[TEXT_INDEX].memory_size); @@ -506,7 +506,7 @@ public: // Read NRO data from memory std::vector<u8> nro_data(nro_size); - system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size); + system.ApplicationMemory().ReadBlock(nro_address, nro_data.data(), nro_size); SHA256Hash hash{}; mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0); diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index bba862fb2..a3622e792 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp @@ -70,6 +70,10 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { return true; } +bool IsAmiiboValid(const NTAG215File& ntag_file) { + return IsAmiiboValid(EncodedDataToNfcData(ntag_file)); +} + NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { NTAG215File encoded_data{}; diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfp/amiibo_crypto.h index c9fd67a39..f6208ee6b 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.h +++ b/src/core/hle/service/nfp/amiibo_crypto.h @@ -60,6 +60,9 @@ static_assert(sizeof(DerivedKeys) == 0x30, "DerivedKeys is an invalid size"); /// Validates that the amiibo file is not corrupted bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file); +/// Validates that the amiibo file is not corrupted +bool IsAmiiboValid(const NTAG215File& ntag_file); + /// Converts from encrypted file format to encoded file format NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data); diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 5990e1473..607e70968 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -121,7 +121,16 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) { // TODO: Filter by allowed_protocols here - memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); + memcpy(&tag_data, data.data(), sizeof(EncryptedNTAG215File)); + is_plain_amiibo = AmiiboCrypto::IsAmiiboValid(tag_data); + + if (is_plain_amiibo) { + encrypted_tag_data = AmiiboCrypto::EncodedDataToNfcData(tag_data); + LOG_INFO(Service_NFP, "Using plain amiibo"); + } else { + tag_data = {}; + memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); + } device_state = DeviceState::TagFound; deactivate_event->GetReadableEvent().Clear(); @@ -232,13 +241,17 @@ Result NfpDevice::Flush() { tag_data.write_counter++; - if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) { - LOG_ERROR(Service_NFP, "Failed to encode data"); - return WriteAmiiboFailed; - } + std::vector<u8> data(sizeof(EncryptedNTAG215File)); + if (is_plain_amiibo) { + memcpy(data.data(), &tag_data, sizeof(tag_data)); + } else { + if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) { + LOG_ERROR(Service_NFP, "Failed to encode data"); + return WriteAmiiboFailed; + } - std::vector<u8> data(sizeof(encrypted_tag_data)); - memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); + memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); + } if (!npad_device->WriteNfc(data)) { LOG_ERROR(Service_NFP, "Error writing to file"); @@ -256,6 +269,13 @@ Result NfpDevice::Mount(MountTarget mount_target_) { return WrongDeviceState; } + // The loaded amiibo is not encrypted + if (is_plain_amiibo) { + device_state = DeviceState::TagMounted; + mount_target = mount_target_; + return ResultSuccess; + } + if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { LOG_ERROR(Service_NFP, "Not an amiibo"); return NotAnAmiibo; diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 27122e86e..7f963730d 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -95,6 +95,7 @@ private: bool is_initalized{}; bool is_data_moddified{}; bool is_app_area_open{}; + bool is_plain_amiibo{}; TagProtocol allowed_protocols{}; s64 current_posix_time{}; MountTarget mount_target{MountTarget::None}; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index b3599a513..70c878552 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -309,7 +309,8 @@ struct EncryptedNTAG215File { u32 CFG1; // Defines number of verification attempts NTAG215Password password; // Password data }; -static_assert(sizeof(EncryptedNTAG215File) == 0x21C, "EncryptedNTAG215File is an invalid size"); +static_assert(sizeof(EncryptedNTAG215File) == sizeof(NTAG215File), + "EncryptedNTAG215File is an invalid size"); static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>, "EncryptedNTAG215File must be trivially copyable."); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index d2308fffc..453a965dc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -304,8 +304,8 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::vector<u8> Tegra::CommandList entries(params.num_entries); if (kickoff) { - system.Memory().ReadBlock(params.address, entries.command_lists.data(), - params.num_entries * sizeof(Tegra::CommandListHeader)); + system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(), + params.num_entries * sizeof(Tegra::CommandListHeader)); } else { std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], params.num_entries * sizeof(Tegra::CommandListHeader)); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 7bcef105b..1ab51f10b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -105,8 +105,8 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, const auto object = nvmap.GetHandle(cmd_buffer.memory_id); ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); - system.Memory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), - cmdlist.size() * sizeof(u32)); + system.ApplicationMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), + cmdlist.size() * sizeof(u32)); gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); } std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 95e070825..432310632 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -832,11 +832,6 @@ std::string Memory::ReadCString(Common::ProcessAddress vaddr, std::size_t max_le return impl->ReadCString(vaddr, max_length); } -void Memory::ReadBlock(const Kernel::KProcess& process, const Common::ProcessAddress src_addr, - void* dest_buffer, const std::size_t size) { - impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size); -} - void Memory::ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer, const std::size_t size) { impl->ReadBlock(src_addr, dest_buffer, size); @@ -847,11 +842,6 @@ void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_b impl->ReadBlockUnsafe(src_addr, dest_buffer, size); } -void Memory::WriteBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - const void* src_buffer, std::size_t size) { - impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size); -} - void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, const std::size_t size) { impl->WriteBlock(dest_addr, src_buffer, size); @@ -862,29 +852,25 @@ void Memory::WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void impl->WriteBlockUnsafe(dest_addr, src_buffer, size); } -void Memory::CopyBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - Common::ProcessAddress src_addr, const std::size_t size) { - impl->CopyBlock(process, dest_addr, src_addr, size); +void Memory::CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr, + const std::size_t size) { + impl->CopyBlock(*system.ApplicationProcess(), dest_addr, src_addr, size); } -void Memory::ZeroBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - const std::size_t size) { - impl->ZeroBlock(process, dest_addr, size); +void Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size) { + impl->ZeroBlock(*system.ApplicationProcess(), dest_addr, size); } -Result Memory::InvalidateDataCache(const Kernel::KProcess& process, - Common::ProcessAddress dest_addr, const std::size_t size) { - return impl->InvalidateDataCache(process, dest_addr, size); +Result Memory::InvalidateDataCache(Common::ProcessAddress dest_addr, const std::size_t size) { + return impl->InvalidateDataCache(*system.ApplicationProcess(), dest_addr, size); } -Result Memory::StoreDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - const std::size_t size) { - return impl->StoreDataCache(process, dest_addr, size); +Result Memory::StoreDataCache(Common::ProcessAddress dest_addr, const std::size_t size) { + return impl->StoreDataCache(*system.ApplicationProcess(), dest_addr, size); } -Result Memory::FlushDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - const std::size_t size) { - return impl->FlushDataCache(process, dest_addr, size); +Result Memory::FlushDataCache(Common::ProcessAddress dest_addr, const std::size_t size) { + return impl->FlushDataCache(*system.ApplicationProcess(), dest_addr, size); } void Memory::RasterizerMarkRegionCached(Common::ProcessAddress vaddr, u64 size, bool cached) { diff --git a/src/core/memory.h b/src/core/memory.h index ed4e87739..72a0be813 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -305,26 +305,6 @@ public: std::string ReadCString(Common::ProcessAddress vaddr, std::size_t max_length); /** - * Reads a contiguous block of bytes from a specified process' address space. - * - * @param process The process to read the data from. - * @param src_addr The virtual address to begin reading from. - * @param dest_buffer The buffer to place the read bytes into. - * @param size The amount of data to read, in bytes. - * - * @note If a size of 0 is specified, then this function reads nothing and - * no attempts to access memory are made at all. - * - * @pre dest_buffer must be at least size bytes in length, otherwise a - * buffer overrun will occur. - * - * @post The range [dest_buffer, size) contains the read bytes from the - * process' address space. - */ - void ReadBlock(const Kernel::KProcess& process, Common::ProcessAddress src_addr, - void* dest_buffer, std::size_t size); - - /** * Reads a contiguous block of bytes from the current process' address space. * * @param src_addr The virtual address to begin reading from. @@ -362,29 +342,6 @@ public: void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); /** - * Writes a range of bytes into a given process' address space at the specified - * virtual address. - * - * @param process The process to write data into the address space of. - * @param dest_addr The destination virtual address to begin writing the data at. - * @param src_buffer The data to write into the process' address space. - * @param size The size of the data to write, in bytes. - * - * @post The address range [dest_addr, size) in the process' address space - * contains the data that was within src_buffer. - * - * @post If an attempt is made to write into an unmapped region of memory, the writes - * will be ignored and an error will be logged. - * - * @post If a write is performed into a region of memory that is considered cached - * rasterizer memory, will cause the currently active rasterizer to be notified - * and will mark that region as invalidated to caches that the active - * graphics backend may be maintaining over the course of execution. - */ - void WriteBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - const void* src_buffer, std::size_t size); - - /** * Writes a range of bytes into the current process' address space at the specified * virtual address. * @@ -428,7 +385,6 @@ public: * Copies data within a process' address space to another location within the * same address space. * - * @param process The process that will have data copied within its address space. * @param dest_addr The destination virtual address to begin copying the data into. * @param src_addr The source virtual address to begin copying the data from. * @param size The size of the data to copy, in bytes. @@ -436,58 +392,50 @@ public: * @post The range [dest_addr, size) within the process' address space contains the * same data within the range [src_addr, size). */ - void CopyBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - Common::ProcessAddress src_addr, std::size_t size); + void CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr, + std::size_t size); /** * Zeros a range of bytes within the current process' address space at the specified * virtual address. * - * @param process The process that will have data zeroed within its address space. * @param dest_addr The destination virtual address to zero the data from. * @param size The size of the range to zero out, in bytes. * * @post The range [dest_addr, size) within the process' address space contains the * value 0. */ - void ZeroBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size); + void ZeroBlock(Common::ProcessAddress dest_addr, std::size_t size); /** * Invalidates a range of bytes within the current process' address space at the specified * virtual address. * - * @param process The process that will have data invalidated within its address space. * @param dest_addr The destination virtual address to invalidate the data from. * @param size The size of the range to invalidate, in bytes. * */ - Result InvalidateDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size); + Result InvalidateDataCache(Common::ProcessAddress dest_addr, std::size_t size); /** * Stores a range of bytes within the current process' address space at the specified * virtual address. * - * @param process The process that will have data stored within its address space. * @param dest_addr The destination virtual address to store the data from. * @param size The size of the range to store, in bytes. * */ - Result StoreDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size); + Result StoreDataCache(Common::ProcessAddress dest_addr, std::size_t size); /** * Flushes a range of bytes within the current process' address space at the specified * virtual address. * - * @param process The process that will have data flushed within its address space. * @param dest_addr The destination virtual address to flush the data from. * @param size The size of the range to flush, in bytes. * */ - Result FlushDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size); + Result FlushDataCache(Common::ProcessAddress dest_addr, std::size_t size); /** * Marks each page within the specified address range as cached or uncached. diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index d1284a3a7..8742dd164 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -39,11 +39,11 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta StandardVmCallbacks::~StandardVmCallbacks() = default; void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { - system.Memory().ReadBlock(SanitizeAddress(address), data, size); + system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size); } void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { - system.Memory().WriteBlock(SanitizeAddress(address), data, size); + system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size); } u64 StandardVmCallbacks::HidKeysDown() { diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 146c3f21e..6c3dc7369 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -264,7 +264,7 @@ void Reporter::SaveUnimplementedFunctionReport(Service::HLERequestContext& ctx, const auto title_id = system.GetApplicationProcessProgramID(); auto out = GetFullDataAuto(timestamp, title_id, system); - auto function_out = GetHLERequestContextData(ctx, system.Memory()); + auto function_out = GetHLERequestContextData(ctx, system.ApplicationMemory()); function_out["command_id"] = command_id; function_out["function_name"] = name; function_out["service_name"] = service_name; diff --git a/src/tests/common/container_hash.cpp b/src/tests/common/container_hash.cpp index 923ac62db..dc45565ef 100644 --- a/src/tests/common/container_hash.cpp +++ b/src/tests/common/container_hash.cpp @@ -17,25 +17,28 @@ TEST_CASE("ContainerHash", "[common]") { 33970, 45501, 5619, 15895, 33227, 27509, 25391, 37275, 60218, 17599, }; constexpr std::array<u32, 32> U32Values{ - 3838402410, 2029146863, 1730869921, 985528872, 186773874, 2094639868, 3324775932, - 1795512424, 2571165571, 3256934519, 2358691590, 2752682538, 1484336451, 378124520, - 3463015699, 3395942161, 1263211979, 3473632889, 3039822212, 2068707357, 2223837919, - 1823232191, 1583884041, 1264393380, 4087566993, 3188607101, 3933680362, 1464520765, - 1786838406, 1311734848, 2773642241, 3993641692, + 3838402410U, 2029146863U, 1730869921U, 985528872U, 186773874U, 2094639868U, 3324775932U, + 1795512424U, 2571165571U, 3256934519U, 2358691590U, 2752682538U, 1484336451U, 378124520U, + 3463015699U, 3395942161U, 1263211979U, 3473632889U, 3039822212U, 2068707357U, 2223837919U, + 1823232191U, 1583884041U, 1264393380U, 4087566993U, 3188607101U, 3933680362U, 1464520765U, + 1786838406U, 1311734848U, 2773642241U, 3993641692U, }; constexpr std::array<u64, 32> U64Values{ - 5908025796157537817, 10947547850358315100, 844798943576724669, 7999662937458523703, - 4006550374705895164, 1832550525423503632, 9323088254855830976, 12028890075598379412, - 6021511300787826236, 7864675007938747948, 18099387408859708806, 6438638299316820708, - 9029399285648501543, 18195459433089960253, 17214335092761966083, 5549347964591337833, - 14899526073304962015, 5058883181561464475, 7436311795731206973, 7535129567768649864, - 1287169596809258072, 8237671246353565927, 1715230541978016153, 8443157615068813300, - 6098675262328527839, 704652094100376853, 1303411723202926503, 7808312933946424854, - 6863726670433556594, 9870361541383217495, 9273671094091079488, 17541434976160119010, + 5908025796157537817ULL, 10947547850358315100ULL, 844798943576724669ULL, + 7999662937458523703ULL, 4006550374705895164ULL, 1832550525423503632ULL, + 9323088254855830976ULL, 12028890075598379412ULL, 6021511300787826236ULL, + 7864675007938747948ULL, 18099387408859708806ULL, 6438638299316820708ULL, + 9029399285648501543ULL, 18195459433089960253ULL, 17214335092761966083ULL, + 5549347964591337833ULL, 14899526073304962015ULL, 5058883181561464475ULL, + 7436311795731206973ULL, 7535129567768649864ULL, 1287169596809258072ULL, + 8237671246353565927ULL, 1715230541978016153ULL, 8443157615068813300ULL, + 6098675262328527839ULL, 704652094100376853ULL, 1303411723202926503ULL, + 7808312933946424854ULL, 6863726670433556594ULL, 9870361541383217495ULL, + 9273671094091079488ULL, 17541434976160119010ULL, }; - REQUIRE(Common::HashValue(U8Values) == 5867183267093890552); - REQUIRE(Common::HashValue(U16Values) == 9594135570564347135); - REQUIRE(Common::HashValue(U32Values) == 13123757214696618460); - REQUIRE(Common::HashValue(U64Values) == 7296500016546938380); + REQUIRE(Common::HashValue(U8Values) == 5867183267093890552ULL); + REQUIRE(Common::HashValue(U16Values) == 9594135570564347135ULL); + REQUIRE(Common::HashValue(U32Values) == 13123757214696618460ULL); + REQUIRE(Common::HashValue(U64Values) == 7296500016546938380ULL); } diff --git a/src/tests/common/range_map.cpp b/src/tests/common/range_map.cpp index d301ac5f6..faaefd49f 100644 --- a/src/tests/common/range_map.cpp +++ b/src/tests/common/range_map.cpp @@ -21,9 +21,9 @@ TEST_CASE("Range Map: Setup", "[video_core]") { my_map.Map(4000, 4500, MappedEnum::Valid_2); my_map.Map(4200, 4400, MappedEnum::Valid_2); my_map.Map(4200, 4400, MappedEnum::Valid_1); - REQUIRE(my_map.GetContinousSizeFrom(4200) == 200); - REQUIRE(my_map.GetContinousSizeFrom(3000) == 200); - REQUIRE(my_map.GetContinousSizeFrom(2900) == 0); + REQUIRE(my_map.GetContinuousSizeFrom(4200) == 200); + REQUIRE(my_map.GetContinuousSizeFrom(3000) == 200); + REQUIRE(my_map.GetContinuousSizeFrom(2900) == 0); REQUIRE(my_map.GetValueAt(2900) == MappedEnum::Invalid); REQUIRE(my_map.GetValueAt(3100) == MappedEnum::Valid_1); @@ -38,20 +38,20 @@ TEST_CASE("Range Map: Setup", "[video_core]") { my_map.Unmap(0, 6000); for (u64 address = 0; address < 10000; address += 1000) { - REQUIRE(my_map.GetContinousSizeFrom(address) == 0); + REQUIRE(my_map.GetContinuousSizeFrom(address) == 0); } my_map.Map(1000, 3000, MappedEnum::Valid_1); my_map.Map(4000, 5000, MappedEnum::Valid_1); my_map.Map(2500, 4100, MappedEnum::Valid_1); - REQUIRE(my_map.GetContinousSizeFrom(1000) == 4000); + REQUIRE(my_map.GetContinuousSizeFrom(1000) == 4000); my_map.Map(1000, 3000, MappedEnum::Valid_1); my_map.Map(4000, 5000, MappedEnum::Valid_2); my_map.Map(2500, 4100, MappedEnum::Valid_3); - REQUIRE(my_map.GetContinousSizeFrom(1000) == 1500); - REQUIRE(my_map.GetContinousSizeFrom(2500) == 1600); - REQUIRE(my_map.GetContinousSizeFrom(4100) == 900); + REQUIRE(my_map.GetContinuousSizeFrom(1000) == 1500); + REQUIRE(my_map.GetContinuousSizeFrom(2500) == 1600); + REQUIRE(my_map.GetContinuousSizeFrom(4100) == 900); REQUIRE(my_map.GetValueAt(900) == MappedEnum::Invalid); REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1); REQUIRE(my_map.GetValueAt(2500) == MappedEnum::Valid_3); @@ -59,8 +59,8 @@ TEST_CASE("Range Map: Setup", "[video_core]") { REQUIRE(my_map.GetValueAt(5000) == MappedEnum::Invalid); my_map.Map(2000, 6000, MappedEnum::Valid_3); - REQUIRE(my_map.GetContinousSizeFrom(1000) == 1000); - REQUIRE(my_map.GetContinousSizeFrom(3000) == 3000); + REQUIRE(my_map.GetContinuousSizeFrom(1000) == 1000); + REQUIRE(my_map.GetContinuousSizeFrom(3000) == 3000); REQUIRE(my_map.GetValueAt(1000) == MappedEnum::Valid_1); REQUIRE(my_map.GetValueAt(1999) == MappedEnum::Valid_1); REQUIRE(my_map.GetValueAt(1500) == MappedEnum::Valid_1); diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 1f656ffa8..abdc593df 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -1442,7 +1442,7 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) { } if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { address_size = - static_cast<u32>(gpu_memory->MaxContinousRange(gpu_addr_begin, address_size)); + static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, address_size)); } const u32 size = address_size; // TODO: Analyze stride and number of vertices vertex_buffers[index] = Binding{ diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 83924475b..01fb5b546 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -22,7 +22,7 @@ std::atomic<size_t> MemoryManager::unique_identifier_generator{}; MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 big_page_bits_, u64 page_bits_) - : system{system_}, memory{system.Memory()}, device_memory{system.DeviceMemory()}, + : system{system_}, memory{system.ApplicationMemory()}, device_memory{system.DeviceMemory()}, address_space_bits{address_space_bits_}, page_bits{page_bits_}, big_page_bits{big_page_bits_}, entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38, page_bits != big_page_bits ? page_bits : 0}, @@ -43,7 +43,7 @@ MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 big_entries.resize(big_page_table_size / 32, 0); big_page_table_cpu.resize(big_page_table_size); - big_page_continous.resize(big_page_table_size / continous_bits, 0); + big_page_continuous.resize(big_page_table_size / continuous_bits, 0); entries.resize(page_table_size / 32, 0); } @@ -85,17 +85,17 @@ PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const { return kind_map.GetValueAt(gpu_addr); } -inline bool MemoryManager::IsBigPageContinous(size_t big_page_index) const { - const u64 entry_mask = big_page_continous[big_page_index / continous_bits]; - const size_t sub_index = big_page_index % continous_bits; +inline bool MemoryManager::IsBigPageContinuous(size_t big_page_index) const { + const u64 entry_mask = big_page_continuous[big_page_index / continuous_bits]; + const size_t sub_index = big_page_index % continuous_bits; return ((entry_mask >> sub_index) & 0x1ULL) != 0; } -inline void MemoryManager::SetBigPageContinous(size_t big_page_index, bool value) { - const u64 continous_mask = big_page_continous[big_page_index / continous_bits]; - const size_t sub_index = big_page_index % continous_bits; - big_page_continous[big_page_index / continous_bits] = - (~(1ULL << sub_index) & continous_mask) | (value ? 1ULL << sub_index : 0); +inline void MemoryManager::SetBigPageContinuous(size_t big_page_index, bool value) { + const u64 continuous_mask = big_page_continuous[big_page_index / continuous_bits]; + const size_t sub_index = big_page_index % continuous_bits; + big_page_continuous[big_page_index / continuous_bits] = + (~(1ULL << sub_index) & continuous_mask) | (value ? 1ULL << sub_index : 0); } template <MemoryManager::EntryType entry_type> @@ -140,7 +140,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr const auto index = PageEntryIndex<true>(current_gpu_addr); const u32 sub_value = static_cast<u32>(current_cpu_addr >> cpu_page_bits); big_page_table_cpu[index] = sub_value; - const bool is_continous = ([&] { + const bool is_continuous = ([&] { uintptr_t base_ptr{ reinterpret_cast<uintptr_t>(memory.GetPointerSilent(current_cpu_addr))}; if (base_ptr == 0) { @@ -156,7 +156,7 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr } return true; })(); - SetBigPageContinous(index, is_continous); + SetBigPageContinuous(index, is_continuous); } remaining_size -= big_page_size; } @@ -378,7 +378,7 @@ void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std: if constexpr (is_safe) { rasterizer->FlushRegion(cpu_addr_base, copy_amount, which); } - if (!IsBigPageContinous(page_index)) [[unlikely]] { + if (!IsBigPageContinuous(page_index)) [[unlikely]] { memory.ReadBlockUnsafe(cpu_addr_base, dest_buffer, copy_amount); } else { u8* physical = memory.GetPointer(cpu_addr_base); @@ -427,7 +427,7 @@ void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffe if constexpr (is_safe) { rasterizer->InvalidateRegion(cpu_addr_base, copy_amount, which); } - if (!IsBigPageContinous(page_index)) [[unlikely]] { + if (!IsBigPageContinuous(page_index)) [[unlikely]] { memory.WriteBlockUnsafe(cpu_addr_base, src_buffer, copy_amount); } else { u8* physical = memory.GetPointer(cpu_addr_base); @@ -512,7 +512,7 @@ bool MemoryManager::IsMemoryDirty(GPUVAddr gpu_addr, size_t size, return result; } -size_t MemoryManager::MaxContinousRange(GPUVAddr gpu_addr, size_t size) const { +size_t MemoryManager::MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const { std::optional<VAddr> old_page_addr{}; size_t range_so_far = 0; bool result{false}; @@ -553,7 +553,7 @@ size_t MemoryManager::MaxContinousRange(GPUVAddr gpu_addr, size_t size) const { } size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const { - return kind_map.GetContinousSizeFrom(gpu_addr); + return kind_map.GetContinuousSizeFrom(gpu_addr); } void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size, @@ -594,7 +594,7 @@ void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { if (GetEntry<true>(gpu_addr) == EntryType::Mapped) [[likely]] { size_t page_index = gpu_addr >> big_page_bits; - if (IsBigPageContinous(page_index)) [[likely]] { + if (IsBigPageContinuous(page_index)) [[likely]] { const std::size_t page{(page_index & big_page_mask) + size}; return page <= big_page_size; } @@ -608,7 +608,7 @@ bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { return page <= Core::Memory::YUZU_PAGESIZE; } -bool MemoryManager::IsContinousRange(GPUVAddr gpu_addr, std::size_t size) const { +bool MemoryManager::IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const { std::optional<VAddr> old_page_addr{}; bool result{true}; auto fail = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset, diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 51ae2de68..fbbe856c4 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h @@ -94,7 +94,7 @@ public: /** * Checks if a gpu region is mapped by a single range of cpu addresses. */ - [[nodiscard]] bool IsContinousRange(GPUVAddr gpu_addr, std::size_t size) const; + [[nodiscard]] bool IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const; /** * Checks if a gpu region is mapped entirely. @@ -123,7 +123,7 @@ public: bool IsMemoryDirty(GPUVAddr gpu_addr, size_t size, VideoCommon::CacheType which = VideoCommon::CacheType::All) const; - size_t MaxContinousRange(GPUVAddr gpu_addr, size_t size) const; + size_t MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const; bool IsWithinGPUAddressRange(GPUVAddr gpu_addr) const { return gpu_addr < address_space_size; @@ -158,8 +158,8 @@ private: } } - inline bool IsBigPageContinous(size_t big_page_index) const; - inline void SetBigPageContinous(size_t big_page_index, bool value); + inline bool IsBigPageContinuous(size_t big_page_index) const; + inline void SetBigPageContinuous(size_t big_page_index, bool value); template <bool is_gpu_address> void GetSubmappedRangeImpl( @@ -213,10 +213,10 @@ private: Common::RangeMap<GPUVAddr, PTEKind> kind_map; Common::VirtualBuffer<u32> big_page_table_cpu; - std::vector<u64> big_page_continous; + std::vector<u64> big_page_continuous; std::vector<std::pair<VAddr, std::size_t>> page_stash{}; - static constexpr size_t continous_bits = 64; + static constexpr size_t continuous_bits = 64; const size_t unique_identifier; std::unique_ptr<VideoCommon::InvalidationAccumulator> accumulator; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 39f42ab90..62fb98b55 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1269,7 +1269,7 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA const ImageId new_image_id = slot_images.insert(runtime, new_info, gpu_addr, cpu_addr); Image& new_image = slot_images[new_image_id]; - if (!gpu_memory->IsContinousRange(new_image.gpu_addr, new_image.guest_size_bytes)) { + if (!gpu_memory->IsContinuousRange(new_image.gpu_addr, new_image.guest_size_bytes)) { new_image.flags |= ImageFlagBits::Sparse; } diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index fedb4a7bb..b42d48416 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -18,7 +18,7 @@ std::unique_ptr<VideoCore::RendererBase> CreateRenderer( Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, std::unique_ptr<Core::Frontend::GraphicsContext> context) { auto& telemetry_session = system.TelemetrySession(); - auto& cpu_memory = system.Memory(); + auto& cpu_memory = system.ApplicationMemory(); switch (Settings::values.renderer_backend.GetValue()) { case Settings::RendererBackend::OpenGL: diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 486d4dfaf..336f53700 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -375,6 +375,8 @@ const char* ToString(VkResult result) noexcept { return "VK_RESULT_MAX_ENUM"; case VkResult::VK_ERROR_COMPRESSION_EXHAUSTED_EXT: return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT"; + case VkResult::VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT: + return "VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT"; } return "Unknown"; } diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp index 93ad4b4f9..4559df5b1 100644 --- a/src/yuzu/applets/qt_amiibo_settings.cpp +++ b/src/yuzu/applets/qt_amiibo_settings.cpp @@ -245,12 +245,19 @@ void QtAmiiboSettingsDialog::SetSettingsDescription() { QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) { connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent, &GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection); + connect(this, &QtAmiiboSettings::MainWindowRequestExit, &parent, + &GMainWindow::AmiiboSettingsRequestExit, Qt::QueuedConnection); connect(&parent, &GMainWindow::AmiiboSettingsFinished, this, &QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection); } QtAmiiboSettings::~QtAmiiboSettings() = default; +void QtAmiiboSettings::Close() const { + callback = {}; + emit MainWindowRequestExit(); +} + void QtAmiiboSettings::ShowCabinetApplet( const Core::Frontend::CabinetCallback& callback_, const Core::Frontend::CabinetParameters& parameters, @@ -260,5 +267,7 @@ void QtAmiiboSettings::ShowCabinetApplet( } void QtAmiiboSettings::MainWindowFinished(bool is_success, const std::string& name) { - callback(is_success, name); + if (callback) { + callback(is_success, name); + } } diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h index 930c96739..bc389a33f 100644 --- a/src/yuzu/applets/qt_amiibo_settings.h +++ b/src/yuzu/applets/qt_amiibo_settings.h @@ -68,6 +68,7 @@ public: explicit QtAmiiboSettings(GMainWindow& parent); ~QtAmiiboSettings() override; + void Close() const override; void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_, const Core::Frontend::CabinetParameters& parameters, std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; @@ -75,6 +76,7 @@ public: signals: void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const; + void MainWindowRequestExit() const; private: void MainWindowFinished(bool is_success, const std::string& name); diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index c30b54499..00aafb8f8 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -300,7 +300,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() { if (num_connected_players < min_supported_players || num_connected_players > max_supported_players) { parameters_met = false; - ui->buttonBox->setEnabled(parameters_met); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parameters_met); return parameters_met; } @@ -327,7 +327,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() { }(); parameters_met = all_controllers_compatible; - ui->buttonBox->setEnabled(parameters_met); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parameters_met); return parameters_met; } @@ -678,18 +678,27 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() { QtControllerSelector::QtControllerSelector(GMainWindow& parent) { connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent, &GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection); + connect(this, &QtControllerSelector::MainWindowRequestExit, &parent, + &GMainWindow::ControllerSelectorRequestExit, Qt::QueuedConnection); connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this, &QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection); } QtControllerSelector::~QtControllerSelector() = default; +void QtControllerSelector::Close() const { + callback = {}; + emit MainWindowRequestExit(); +} + void QtControllerSelector::ReconfigureControllers( ReconfigureCallback callback_, const Core::Frontend::ControllerParameters& parameters) const { callback = std::move(callback_); emit MainWindowReconfigureControllers(parameters); } -void QtControllerSelector::MainWindowReconfigureFinished() { - callback(); +void QtControllerSelector::MainWindowReconfigureFinished(bool is_success) { + if (callback) { + callback(is_success); + } } diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index 16e99f507..2fdc35857 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -156,6 +156,7 @@ public: explicit QtControllerSelector(GMainWindow& parent); ~QtControllerSelector() override; + void Close() const override; void ReconfigureControllers( ReconfigureCallback callback_, const Core::Frontend::ControllerParameters& parameters) const override; @@ -163,9 +164,10 @@ public: signals: void MainWindowReconfigureControllers( const Core::Frontend::ControllerParameters& parameters) const; + void MainWindowRequestExit() const; private: - void MainWindowReconfigureFinished(); + void MainWindowReconfigureFinished(bool is_success); mutable ReconfigureCallback callback; }; diff --git a/src/yuzu/applets/qt_controller.ui b/src/yuzu/applets/qt_controller.ui index f5eccba70..729e921ee 100644 --- a/src/yuzu/applets/qt_controller.ui +++ b/src/yuzu/applets/qt_controller.ui @@ -2629,7 +2629,7 @@ <bool>true</bool> </property> <property name="standardButtons"> - <set>QDialogButtonBox::Ok</set> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> @@ -2649,5 +2649,11 @@ <receiver>QtControllerSelectorDialog</receiver> <slot>accept()</slot> </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>QtControllerSelectorDialog</receiver> + <slot>reject()</slot> + </connection> </connections> </ui> diff --git a/src/yuzu/applets/qt_error.cpp b/src/yuzu/applets/qt_error.cpp index e0190a979..1dc4f0383 100644 --- a/src/yuzu/applets/qt_error.cpp +++ b/src/yuzu/applets/qt_error.cpp @@ -8,12 +8,19 @@ QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) { connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent, &GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection); + connect(this, &QtErrorDisplay::MainWindowRequestExit, &parent, + &GMainWindow::ErrorDisplayRequestExit, Qt::QueuedConnection); connect(&parent, &GMainWindow::ErrorDisplayFinished, this, &QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection); } QtErrorDisplay::~QtErrorDisplay() = default; +void QtErrorDisplay::Close() const { + callback = {}; + emit MainWindowRequestExit(); +} + void QtErrorDisplay::ShowError(Result error, FinishedCallback finished) const { callback = std::move(finished); emit MainWindowDisplayError( @@ -55,5 +62,7 @@ void QtErrorDisplay::ShowCustomErrorText(Result error, std::string dialog_text, } void QtErrorDisplay::MainWindowFinishedError() { - callback(); + if (callback) { + callback(); + } } diff --git a/src/yuzu/applets/qt_error.h b/src/yuzu/applets/qt_error.h index e4e174721..957f170ad 100644 --- a/src/yuzu/applets/qt_error.h +++ b/src/yuzu/applets/qt_error.h @@ -16,6 +16,7 @@ public: explicit QtErrorDisplay(GMainWindow& parent); ~QtErrorDisplay() override; + void Close() const override; void ShowError(Result error, FinishedCallback finished) const override; void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, FinishedCallback finished) const override; @@ -24,6 +25,7 @@ public: signals: void MainWindowDisplayError(QString error_code, QString error_text) const; + void MainWindowRequestExit() const; private: void MainWindowFinishedError(); diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index 4145c5299..2448e46b6 100644 --- a/src/yuzu/applets/qt_profile_select.cpp +++ b/src/yuzu/applets/qt_profile_select.cpp @@ -46,11 +46,13 @@ QPixmap GetIcon(Common::UUID uuid) { } } // Anonymous namespace -QtProfileSelectionDialog::QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent) +QtProfileSelectionDialog::QtProfileSelectionDialog( + Core::HID::HIDCore& hid_core, QWidget* parent, + const Core::Frontend::ProfileSelectParameters& parameters) : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) { outer_layout = new QVBoxLayout; - instruction_label = new QLabel(tr("Select a user:")); + instruction_label = new QLabel(); scroll_area = new QScrollArea; @@ -120,7 +122,8 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, item_model->appendRow(item); setLayout(outer_layout); - setWindowTitle(tr("Profile Selector")); + SetWindowTitle(parameters); + SetDialogPurpose(parameters); resize(550, 400); } @@ -154,20 +157,101 @@ void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) { user_index = index.row(); } +void QtProfileSelectionDialog::SetWindowTitle( + const Core::Frontend::ProfileSelectParameters& parameters) { + using Service::AM::Applets::UiMode; + switch (parameters.mode) { + case UiMode::UserCreator: + case UiMode::UserCreatorForStarter: + setWindowTitle(tr("Profile Creator")); + return; + case UiMode::EnsureNetworkServiceAccountAvailable: + setWindowTitle(tr("Profile Selector")); + return; + case UiMode::UserIconEditor: + setWindowTitle(tr("Profile Icon Editor")); + return; + case UiMode::UserNicknameEditor: + setWindowTitle(tr("Profile Nickname Editor")); + return; + case UiMode::NintendoAccountAuthorizationRequestContext: + case UiMode::IntroduceExternalNetworkServiceAccount: + case UiMode::IntroduceExternalNetworkServiceAccountForRegistration: + case UiMode::NintendoAccountNnidLinker: + case UiMode::LicenseRequirementsForNetworkService: + case UiMode::LicenseRequirementsForNetworkServiceWithUserContextImpl: + case UiMode::UserCreatorForImmediateNaLoginTest: + case UiMode::UserQualificationPromoter: + case UiMode::UserSelector: + default: + setWindowTitle(tr("Profile Selector")); + } +} + +void QtProfileSelectionDialog::SetDialogPurpose( + const Core::Frontend::ProfileSelectParameters& parameters) { + using Service::AM::Applets::UserSelectionPurpose; + + switch (parameters.purpose) { + case UserSelectionPurpose::GameCardRegistration: + instruction_label->setText(tr("Who will receive the points?")); + return; + case UserSelectionPurpose::EShopLaunch: + instruction_label->setText(tr("Who is using Nintendo eShop?")); + return; + case UserSelectionPurpose::EShopItemShow: + instruction_label->setText(tr("Who is making this purchase?")); + return; + case UserSelectionPurpose::PicturePost: + instruction_label->setText(tr("Who is posting?")); + return; + case UserSelectionPurpose::NintendoAccountLinkage: + instruction_label->setText(tr("Select a user to link to a Nintendo Account.")); + return; + case UserSelectionPurpose::SettingsUpdate: + instruction_label->setText(tr("Change settings for which user?")); + return; + case UserSelectionPurpose::SaveDataDeletion: + instruction_label->setText(tr("Format data for which user?")); + return; + case UserSelectionPurpose::UserMigration: + instruction_label->setText(tr("Which user will be transferred to another console?")); + return; + case UserSelectionPurpose::SaveDataTransfer: + instruction_label->setText(tr("Send save data for which user?")); + return; + case UserSelectionPurpose::General: + default: + instruction_label->setText(tr("Select a user:")); + return; + } +} + QtProfileSelector::QtProfileSelector(GMainWindow& parent) { connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent, &GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection); + connect(this, &QtProfileSelector::MainWindowRequestExit, &parent, + &GMainWindow::ProfileSelectorRequestExit, Qt::QueuedConnection); connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this, &QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection); } QtProfileSelector::~QtProfileSelector() = default; -void QtProfileSelector::SelectProfile(SelectProfileCallback callback_) const { +void QtProfileSelector::Close() const { + callback = {}; + emit MainWindowRequestExit(); +} + +void QtProfileSelector::SelectProfile( + SelectProfileCallback callback_, + const Core::Frontend::ProfileSelectParameters& parameters) const { callback = std::move(callback_); - emit MainWindowSelectProfile(); + emit MainWindowSelectProfile(parameters); } void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) { - callback(uuid); + if (callback) { + callback(uuid); + } } diff --git a/src/yuzu/applets/qt_profile_select.h b/src/yuzu/applets/qt_profile_select.h index 637a3bda2..99056e274 100644 --- a/src/yuzu/applets/qt_profile_select.h +++ b/src/yuzu/applets/qt_profile_select.h @@ -28,7 +28,8 @@ class QtProfileSelectionDialog final : public QDialog { Q_OBJECT public: - explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent); + explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent, + const Core::Frontend::ProfileSelectParameters& parameters); ~QtProfileSelectionDialog() override; int exec() override; @@ -40,6 +41,9 @@ public: private: void SelectUser(const QModelIndex& index); + void SetWindowTitle(const Core::Frontend::ProfileSelectParameters& parameters); + void SetDialogPurpose(const Core::Frontend::ProfileSelectParameters& parameters); + int user_index = 0; QVBoxLayout* layout; @@ -65,10 +69,13 @@ public: explicit QtProfileSelector(GMainWindow& parent); ~QtProfileSelector() override; - void SelectProfile(SelectProfileCallback callback_) const override; + void Close() const override; + void SelectProfile(SelectProfileCallback callback_, + const Core::Frontend::ProfileSelectParameters& parameters) const override; signals: - void MainWindowSelectProfile() const; + void MainWindowSelectProfile(const Core::Frontend::ProfileSelectParameters& parameters) const; + void MainWindowRequestExit() const; private: void MainWindowFinishedSelection(std::optional<Common::UUID> uuid); diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h index 30ac8ecf6..ac23ce047 100644 --- a/src/yuzu/applets/qt_software_keyboard.h +++ b/src/yuzu/applets/qt_software_keyboard.h @@ -233,6 +233,10 @@ public: explicit QtSoftwareKeyboard(GMainWindow& parent); ~QtSoftwareKeyboard() override; + void Close() const override { + ExitKeyboard(); + } + void InitializeKeyboard(bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters, SubmitNormalCallback submit_normal_callback_, diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 0a5912326..28acc0ff8 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -393,6 +393,8 @@ void QtNXWebEngineView::FocusFirstLinkElement() { QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { connect(this, &QtWebBrowser::MainWindowOpenWebPage, &main_window, &GMainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection); + connect(this, &QtWebBrowser::MainWindowRequestExit, &main_window, + &GMainWindow::WebBrowserRequestExit, Qt::QueuedConnection); connect(&main_window, &GMainWindow::WebBrowserExtractOfflineRomFS, this, &QtWebBrowser::MainWindowExtractOfflineRomFS, Qt::QueuedConnection); connect(&main_window, &GMainWindow::WebBrowserClosed, this, @@ -401,6 +403,11 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { QtWebBrowser::~QtWebBrowser() = default; +void QtWebBrowser::Close() const { + callback = {}; + emit MainWindowRequestExit(); +} + void QtWebBrowser::OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback_, OpenWebPageCallback callback_) const { @@ -436,5 +443,7 @@ void QtWebBrowser::MainWindowExtractOfflineRomFS() { void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url) { - callback(exit_reason, last_url); + if (callback) { + callback(exit_reason, last_url); + } } diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h index ceae7926e..1234108ae 100644 --- a/src/yuzu/applets/qt_web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h @@ -196,6 +196,7 @@ public: explicit QtWebBrowser(GMainWindow& parent); ~QtWebBrowser() override; + void Close() const override; void OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback_, OpenWebPageCallback callback_) const override; @@ -206,6 +207,7 @@ public: signals: void MainWindowOpenWebPage(const std::string& main_url, const std::string& additional_args, bool is_local) const; + void MainWindowRequestExit() const; private: void MainWindowExtractOfflineRomFS(); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index ae14884b5..b79409a68 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -307,6 +307,8 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan system->Initialize(); Common::Log::Initialize(); + Common::Log::Start(); + LoadTranslation(); setAcceptDrops(true); @@ -449,8 +451,6 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan SetupPrepareForSleep(); - Common::Log::Start(); - QStringList args = QApplication::arguments(); if (args.size() < 2) { @@ -576,6 +576,10 @@ void GMainWindow::RegisterMetaTypes() { // Controller Applet qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); + // Profile Select Applet + qRegisterMetaType<Core::Frontend::ProfileSelectParameters>( + "Core::Frontend::ProfileSelectParameters"); + // Software Keyboard Applet qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>( "Core::Frontend::KeyboardInitializeParameters"); @@ -596,50 +600,81 @@ void GMainWindow::RegisterMetaTypes() { void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr<Service::NFP::NfpDevice> nfp_device) { - QtAmiiboSettingsDialog dialog(this, parameters, input_subsystem.get(), nfp_device); + cabinet_applet = + new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); + SCOPE_EXIT({ + cabinet_applet->deleteLater(); + cabinet_applet = nullptr; + }); - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | - Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - dialog.setWindowModality(Qt::WindowModal); - if (dialog.exec() == QDialog::Rejected) { + cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | + Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + cabinet_applet->setWindowModality(Qt::WindowModal); + + if (cabinet_applet->exec() == QDialog::Rejected) { emit AmiiboSettingsFinished(false, {}); return; } - emit AmiiboSettingsFinished(true, dialog.GetName()); + emit AmiiboSettingsFinished(true, cabinet_applet->GetName()); +} + +void GMainWindow::AmiiboSettingsRequestExit() { + if (cabinet_applet) { + cabinet_applet->reject(); + } } void GMainWindow::ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters) { - QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system); - - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | - Qt::WindowTitleHint | Qt::WindowSystemMenuHint); - dialog.setWindowModality(Qt::WindowModal); - dialog.exec(); + controller_applet = + new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); + SCOPE_EXIT({ + controller_applet->deleteLater(); + controller_applet = nullptr; + }); - emit ControllerSelectorReconfigureFinished(); + controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | + Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint); + controller_applet->setWindowModality(Qt::WindowModal); + bool is_success = controller_applet->exec() != QDialog::Rejected; // Don't forget to apply settings. + system->HIDCore().DisableAllControllerConfiguration(); system->ApplySettings(); config->Save(); UpdateStatusButtons(); + + emit ControllerSelectorReconfigureFinished(is_success); } -void GMainWindow::ProfileSelectorSelectProfile() { - QtProfileSelectionDialog dialog(system->HIDCore(), this); - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | - Qt::WindowTitleHint | Qt::WindowSystemMenuHint | - Qt::WindowCloseButtonHint); - dialog.setWindowModality(Qt::WindowModal); - if (dialog.exec() == QDialog::Rejected) { +void GMainWindow::ControllerSelectorRequestExit() { + if (controller_applet) { + controller_applet->reject(); + } +} + +void GMainWindow::ProfileSelectorSelectProfile( + const Core::Frontend::ProfileSelectParameters& parameters) { + profile_select_applet = new QtProfileSelectionDialog(system->HIDCore(), this, parameters); + SCOPE_EXIT({ + profile_select_applet->deleteLater(); + profile_select_applet = nullptr; + }); + + profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | + Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + profile_select_applet->setWindowModality(Qt::WindowModal); + if (profile_select_applet->exec() == QDialog::Rejected) { emit ProfileSelectorFinishedSelection(std::nullopt); return; } const Service::Account::ProfileManager manager; - const auto uuid = manager.GetUser(static_cast<std::size_t>(dialog.GetIndex())); + const auto uuid = manager.GetUser(static_cast<std::size_t>(profile_select_applet->GetIndex())); if (!uuid.has_value()) { emit ProfileSelectorFinishedSelection(std::nullopt); return; @@ -648,6 +683,12 @@ void GMainWindow::ProfileSelectorSelectProfile() { emit ProfileSelectorFinishedSelection(uuid); } +void GMainWindow::ProfileSelectorRequestExit() { + if (profile_select_applet) { + profile_select_applet->reject(); + } +} + void GMainWindow::SoftwareKeyboardInitialize( bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) { if (software_keyboard) { @@ -772,7 +813,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, return; } - QtNXWebEngineView web_browser_view(this, *system, input_subsystem.get()); + web_applet = new QtNXWebEngineView(this, *system, input_subsystem.get()); ui->action_Pause->setEnabled(false); ui->action_Restart->setEnabled(false); @@ -799,9 +840,9 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, loading_progress.setValue(1); if (is_local) { - web_browser_view.LoadLocalWebPage(main_url, additional_args); + web_applet->LoadLocalWebPage(main_url, additional_args); } else { - web_browser_view.LoadExternalWebPage(main_url, additional_args); + web_applet->LoadExternalWebPage(main_url, additional_args); } if (render_window->IsLoadingComplete()) { @@ -810,15 +851,15 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, const auto& layout = render_window->GetFramebufferLayout(); const auto scale_ratio = devicePixelRatioF(); - web_browser_view.resize(layout.screen.GetWidth() / scale_ratio, - layout.screen.GetHeight() / scale_ratio); - web_browser_view.move(layout.screen.left / scale_ratio, - (layout.screen.top / scale_ratio) + menuBar()->height()); - web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth() / scale_ratio) / - static_cast<qreal>(Layout::ScreenUndocked::Width)); + web_applet->resize(layout.screen.GetWidth() / scale_ratio, + layout.screen.GetHeight() / scale_ratio); + web_applet->move(layout.screen.left / scale_ratio, + (layout.screen.top / scale_ratio) + menuBar()->height()); + web_applet->setZoomFactor(static_cast<qreal>(layout.screen.GetWidth() / scale_ratio) / + static_cast<qreal>(Layout::ScreenUndocked::Width)); - web_browser_view.setFocus(); - web_browser_view.show(); + web_applet->setFocus(); + web_applet->show(); loading_progress.setValue(2); @@ -831,7 +872,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, // TODO (Morph): Remove this QAction* exit_action = new QAction(tr("Disable Web Applet"), this); - connect(exit_action, &QAction::triggered, this, [this, &web_browser_view] { + connect(exit_action, &QAction::triggered, this, [this] { const auto result = QMessageBox::warning( this, tr("Disable Web Applet"), tr("Disabling the web applet can lead to undefined behavior and should only be used " @@ -840,21 +881,21 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::Yes) { UISettings::values.disable_web_applet = true; - web_browser_view.SetFinished(true); + web_applet->SetFinished(true); } }); ui->menubar->addAction(exit_action); - while (!web_browser_view.IsFinished()) { + while (!web_applet->IsFinished()) { QCoreApplication::processEvents(); if (!exit_check) { - web_browser_view.page()->runJavaScript( + web_applet->page()->runJavaScript( QStringLiteral("end_applet;"), [&](const QVariant& variant) { exit_check = false; if (variant.toBool()) { - web_browser_view.SetFinished(true); - web_browser_view.SetExitReason( + web_applet->SetFinished(true); + web_applet->SetExitReason( Service::AM::Applets::WebExitReason::EndButtonPressed); } }); @@ -862,22 +903,22 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, exit_check = true; } - if (web_browser_view.GetCurrentURL().contains(QStringLiteral("localhost"))) { - if (!web_browser_view.IsFinished()) { - web_browser_view.SetFinished(true); - web_browser_view.SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); + if (web_applet->GetCurrentURL().contains(QStringLiteral("localhost"))) { + if (!web_applet->IsFinished()) { + web_applet->SetFinished(true); + web_applet->SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); } - web_browser_view.SetLastURL(web_browser_view.GetCurrentURL().toStdString()); + web_applet->SetLastURL(web_applet->GetCurrentURL().toStdString()); } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - const auto exit_reason = web_browser_view.GetExitReason(); - const auto last_url = web_browser_view.GetLastURL(); + const auto exit_reason = web_applet->GetExitReason(); + const auto last_url = web_applet->GetLastURL(); - web_browser_view.hide(); + web_applet->hide(); render_window->setFocus(); @@ -903,6 +944,15 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, #endif } +void GMainWindow::WebBrowserRequestExit() { +#ifdef YUZU_USE_QT_WEB_ENGINE + if (web_applet) { + web_applet->SetExitReason(Service::AM::Applets::WebExitReason::ExitRequested); + web_applet->SetFinished(true); + } +#endif +} + void GMainWindow::InitializeWidgets() { #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING ui->action_Report_Compatibility->setVisible(true); @@ -1675,8 +1725,9 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p return true; } -bool GMainWindow::SelectAndSetCurrentUser() { - QtProfileSelectionDialog dialog(system->HIDCore(), this); +bool GMainWindow::SelectAndSetCurrentUser( + const Core::Frontend::ProfileSelectParameters& parameters) { + QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -1722,7 +1773,13 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t Settings::LogSettings(); if (UISettings::values.select_user_on_boot) { - if (SelectAndSetCurrentUser() == false) { + const Core::Frontend::ProfileSelectParameters parameters{ + .mode = Service::AM::Applets::UiMode::UserSelector, + .invalid_uid_list = {}, + .display_options = {}, + .purpose = Service::AM::Applets::UserSelectionPurpose::General, + }; + if (SelectAndSetCurrentUser(parameters) == false) { return; } } @@ -2014,7 +2071,13 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target if (has_user_save) { // User save data const auto select_profile = [this] { - QtProfileSelectionDialog dialog(system->HIDCore(), this); + const Core::Frontend::ProfileSelectParameters parameters{ + .mode = Service::AM::Applets::UiMode::UserSelector, + .invalid_uid_list = {}, + .display_options = {}, + .purpose = Service::AM::Applets::UserSelectionPurpose::General, + }; + QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -3089,13 +3152,23 @@ void GMainWindow::OnSaveConfig() { } void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { - OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"), - Qt::AlignLeft | Qt::AlignVCenter); - dialog.exec(); + error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, + tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); + SCOPE_EXIT({ + error_applet->deleteLater(); + error_applet = nullptr; + }); + error_applet->exec(); emit ErrorDisplayFinished(); } +void GMainWindow::ErrorDisplayRequestExit() { + if (error_applet) { + error_applet->reject(); + } +} + void GMainWindow::OnMenuReportCompatibility() { #if defined(ARCHITECTURE_x86_64) && !defined(__APPLE__) const auto& caps = Common::GetCPUCaps(); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index a23b373a5..8b5c1d747 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -47,7 +47,11 @@ enum class DumpRomFSTarget; enum class InstalledEntryType; class GameListPlaceholder; +class QtAmiiboSettingsDialog; +class QtControllerSelectorDialog; +class QtProfileSelectionDialog; class QtSoftwareKeyboardDialog; +class QtNXWebEngineView; enum class StartGameType { Normal, // Can use custom configuration @@ -65,6 +69,7 @@ struct ControllerParameters; struct InlineAppearParameters; struct InlineTextParameters; struct KeyboardInitializeParameters; +struct ProfileSelectParameters; } // namespace Core::Frontend namespace DiscordRPC { @@ -161,7 +166,7 @@ signals: void AmiiboSettingsFinished(bool is_success, const std::string& name); - void ControllerSelectorReconfigureFinished(); + void ControllerSelectorReconfigureFinished(bool is_success); void ErrorDisplayFinished(); @@ -184,8 +189,10 @@ public slots: void OnSaveConfig(); void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr<Service::NFP::NfpDevice> nfp_device); + void AmiiboSettingsRequestExit(); void ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters); + void ControllerSelectorRequestExit(); void SoftwareKeyboardInitialize( bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); void SoftwareKeyboardShowNormal(); @@ -196,9 +203,12 @@ public slots: void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); void SoftwareKeyboardExit(); void ErrorDisplayDisplayError(QString error_code, QString error_text); - void ProfileSelectorSelectProfile(); + void ErrorDisplayRequestExit(); + void ProfileSelectorSelectProfile(const Core::Frontend::ProfileSelectParameters& parameters); + void ProfileSelectorRequestExit(); void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, bool is_local); + void WebBrowserRequestExit(); void OnAppFocusStateChanged(Qt::ApplicationState state); void OnTasStateChanged(); @@ -233,7 +243,7 @@ private: void SetDiscordEnabled(bool state); void LoadAmiibo(const QString& filename); - bool SelectAndSetCurrentUser(); + bool SelectAndSetCurrentUser(const Core::Frontend::ProfileSelectParameters& parameters); /** * Stores the filename in the recently loaded files list. @@ -466,7 +476,12 @@ private: QString last_filename_booted; // Applets + QtAmiiboSettingsDialog* cabinet_applet = nullptr; + QtControllerSelectorDialog* controller_applet = nullptr; + QtProfileSelectionDialog* profile_select_applet = nullptr; + QDialog* error_applet = nullptr; QtSoftwareKeyboardDialog* software_keyboard = nullptr; + QtNXWebEngineView* web_applet = nullptr; // True if amiibo file select is visible bool is_amiibo_file_select_active{}; |