diff options
Diffstat (limited to 'src')
31 files changed, 442 insertions, 187 deletions
diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index 043ce8875..b5c0ef0e6 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp | |||
| @@ -121,8 +121,7 @@ u64 DeviceSession::GetPlayedSampleCount() const { | |||
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | std::optional<std::chrono::nanoseconds> DeviceSession::ThreadFunc() { | 123 | std::optional<std::chrono::nanoseconds> DeviceSession::ThreadFunc() { |
| 124 | // Add 5ms of samples at a 48K sample rate. | 124 | played_sample_count = stream->GetExpectedPlayedSampleCount(); |
| 125 | played_sample_count += 48'000 * INCREMENT_TIME / 1s; | ||
| 126 | if (type == Sink::StreamType::Out) { | 125 | if (type == Sink::StreamType::Out) { |
| 127 | system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioOutManager, true); | 126 | system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioOutManager, true); |
| 128 | } else { | 127 | } else { |
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() { | |||
| 189 | max_time = std::min(command_buffer.time_limit, max_time); | 189 | max_time = std::min(command_buffer.time_limit, max_time); |
| 190 | command_list_processor.SetProcessTimeMax(max_time); | 190 | command_list_processor.SetProcessTimeMax(max_time); |
| 191 | 191 | ||
| 192 | streams[index]->WaitFreeSpace(); | ||
| 193 | |||
| 192 | // Process the command list | 194 | // Process the command list |
| 193 | { | 195 | { |
| 194 | MICROPROFILE_SCOPE(Audio_Renderer); | 196 | 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 @@ | |||
| 10 | #include "audio_core/renderer/adsp/command_buffer.h" | 10 | #include "audio_core/renderer/adsp/command_buffer.h" |
| 11 | #include "audio_core/renderer/adsp/command_list_processor.h" | 11 | #include "audio_core/renderer/adsp/command_list_processor.h" |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/polyfill_thread.h" | ||
| 13 | #include "common/reader_writer_queue.h" | 14 | #include "common/reader_writer_queue.h" |
| 14 | #include "common/thread.h" | 15 | #include "common/thread.h" |
| 15 | 16 | ||
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", | |||
| 15 | MP_RGB(60, 19, 97)); | 15 | MP_RGB(60, 19, 97)); |
| 16 | 16 | ||
| 17 | namespace AudioCore::AudioRenderer { | 17 | namespace AudioCore::AudioRenderer { |
| 18 | constexpr std::chrono::nanoseconds RENDER_TIME{5'000'000UL}; | ||
| 19 | 18 | ||
| 20 | SystemManager::SystemManager(Core::System& core_) | 19 | SystemManager::SystemManager(Core::System& core_) |
| 21 | : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()}, | 20 | : core{core_}, adsp{core.AudioCore().GetADSP()}, mailbox{adsp.GetRenderMailbox()} {} |
| 22 | thread_event{Core::Timing::CreateEvent( | ||
| 23 | "AudioRendererSystemManager", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) { | ||
| 24 | return ThreadFunc2(time); | ||
| 25 | })} {} | ||
| 26 | 21 | ||
| 27 | SystemManager::~SystemManager() { | 22 | SystemManager::~SystemManager() { |
| 28 | Stop(); | 23 | Stop(); |
| @@ -33,8 +28,6 @@ bool SystemManager::InitializeUnsafe() { | |||
| 33 | if (adsp.Start()) { | 28 | if (adsp.Start()) { |
| 34 | active = true; | 29 | active = true; |
| 35 | thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); }); | 30 | thread = std::jthread([this](std::stop_token stop_token) { ThreadFunc(); }); |
| 36 | core.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), RENDER_TIME, | ||
| 37 | thread_event); | ||
| 38 | } | 31 | } |
| 39 | } | 32 | } |
| 40 | 33 | ||
| @@ -45,7 +38,6 @@ void SystemManager::Stop() { | |||
| 45 | if (!active) { | 38 | if (!active) { |
| 46 | return; | 39 | return; |
| 47 | } | 40 | } |
| 48 | core.CoreTiming().UnscheduleEvent(thread_event, {}); | ||
| 49 | active = false; | 41 | active = false; |
| 50 | update.store(true); | 42 | update.store(true); |
| 51 | update.notify_all(); | 43 | update.notify_all(); |
| @@ -111,16 +103,7 @@ void SystemManager::ThreadFunc() { | |||
| 111 | 103 | ||
| 112 | adsp.Signal(); | 104 | adsp.Signal(); |
| 113 | adsp.Wait(); | 105 | adsp.Wait(); |
| 114 | |||
| 115 | update.wait(false); | ||
| 116 | update.store(false); | ||
| 117 | } | 106 | } |
| 118 | } | 107 | } |
| 119 | 108 | ||
| 120 | std::optional<std::chrono::nanoseconds> SystemManager::ThreadFunc2(s64 time) { | ||
| 121 | update.store(true); | ||
| 122 | update.notify_all(); | ||
| 123 | return std::nullopt; | ||
| 124 | } | ||
| 125 | |||
| 126 | } // namespace AudioCore::AudioRenderer | 109 | } // 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: | |||
| 68 | */ | 68 | */ |
| 69 | void ThreadFunc(); | 69 | void ThreadFunc(); |
| 70 | 70 | ||
| 71 | /** | ||
| 72 | * Signalling core timing thread to run ThreadFunc. | ||
| 73 | */ | ||
| 74 | std::optional<std::chrono::nanoseconds> ThreadFunc2(s64 time); | ||
| 75 | |||
| 76 | enum class StreamState { | 71 | enum class StreamState { |
| 77 | Filling, | 72 | Filling, |
| 78 | Steady, | 73 | Steady, |
| @@ -95,8 +90,6 @@ private: | |||
| 95 | ADSP::ADSP& adsp; | 90 | ADSP::ADSP& adsp; |
| 96 | /// AudioRenderer mailbox for communication | 91 | /// AudioRenderer mailbox for communication |
| 97 | ADSP::AudioRenderer_Mailbox* mailbox{}; | 92 | ADSP::AudioRenderer_Mailbox* mailbox{}; |
| 98 | /// Core timing event to signal main thread | ||
| 99 | std::shared_ptr<Core::Timing::EventType> thread_event; | ||
| 100 | /// Atomic for main thread to wait on | 93 | /// Atomic for main thread to wait on |
| 101 | std::atomic<bool> update{}; | 94 | std::atomic<bool> update{}; |
| 102 | }; | 95 | }; |
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: | |||
| 101 | ~CubebSinkStream() override { | 101 | ~CubebSinkStream() override { |
| 102 | LOG_DEBUG(Service_Audio, "Destructing cubeb stream {}", name); | 102 | LOG_DEBUG(Service_Audio, "Destructing cubeb stream {}", name); |
| 103 | 103 | ||
| 104 | Unstall(); | ||
| 105 | |||
| 106 | if (!ctx) { | 104 | if (!ctx) { |
| 107 | return; | 105 | return; |
| 108 | } | 106 | } |
| @@ -143,8 +141,6 @@ public: | |||
| 143 | * Stop the sink stream. | 141 | * Stop the sink stream. |
| 144 | */ | 142 | */ |
| 145 | void Stop() override { | 143 | void Stop() override { |
| 146 | Unstall(); | ||
| 147 | |||
| 148 | if (!ctx || paused) { | 144 | if (!ctx || paused) { |
| 149 | return; | 145 | return; |
| 150 | } | 146 | } |
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: | |||
| 88 | * Finalize the sink stream. | 88 | * Finalize the sink stream. |
| 89 | */ | 89 | */ |
| 90 | void Finalize() override { | 90 | void Finalize() override { |
| 91 | Unstall(); | ||
| 92 | if (device == 0) { | 91 | if (device == 0) { |
| 93 | return; | 92 | return; |
| 94 | } | 93 | } |
| @@ -116,7 +115,6 @@ public: | |||
| 116 | * Stop the sink stream. | 115 | * Stop the sink stream. |
| 117 | */ | 116 | */ |
| 118 | void Stop() override { | 117 | void Stop() override { |
| 119 | Unstall(); | ||
| 120 | if (device == 0 || paused) { | 118 | if (device == 0 || paused) { |
| 121 | return; | 119 | return; |
| 122 | } | 120 | } |
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 @@ | |||
| 14 | #include "common/fixed_point.h" | 14 | #include "common/fixed_point.h" |
| 15 | #include "common/settings.h" | 15 | #include "common/settings.h" |
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/core_timing.h" | ||
| 18 | #include "core/core_timing_util.h" | ||
| 17 | 19 | ||
| 18 | namespace AudioCore::Sink { | 20 | namespace AudioCore::Sink { |
| 19 | 21 | ||
| @@ -149,10 +151,6 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n | |||
| 149 | return; | 151 | return; |
| 150 | } | 152 | } |
| 151 | 153 | ||
| 152 | if (queued_buffers > max_queue_size) { | ||
| 153 | Stall(); | ||
| 154 | } | ||
| 155 | |||
| 156 | while (frames_written < num_frames) { | 154 | while (frames_written < num_frames) { |
| 157 | // If the playing buffer has been consumed or has no frames, we need a new one | 155 | // If the playing buffer has been consumed or has no frames, we need a new one |
| 158 | if (playing_buffer.consumed || playing_buffer.frames == 0) { | 156 | 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 | |||
| 187 | } | 185 | } |
| 188 | 186 | ||
| 189 | std::memcpy(&last_frame[0], &input_buffer[(frames_written - 1) * frame_size], frame_size_bytes); | 187 | std::memcpy(&last_frame[0], &input_buffer[(frames_written - 1) * frame_size], frame_size_bytes); |
| 190 | |||
| 191 | if (queued_buffers <= max_queue_size) { | ||
| 192 | Unstall(); | ||
| 193 | } | ||
| 194 | } | 188 | } |
| 195 | 189 | ||
| 196 | void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::size_t num_frames) { | 190 | 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 | |||
| 198 | const std::size_t frame_size = num_channels; | 192 | const std::size_t frame_size = num_channels; |
| 199 | const std::size_t frame_size_bytes = frame_size * sizeof(s16); | 193 | const std::size_t frame_size_bytes = frame_size * sizeof(s16); |
| 200 | size_t frames_written{0}; | 194 | size_t frames_written{0}; |
| 195 | size_t actual_frames_written{0}; | ||
| 201 | 196 | ||
| 202 | // If we're paused or going to shut down, we don't want to consume buffers as coretiming is | 197 | // If we're paused or going to shut down, we don't want to consume buffers as coretiming is |
| 203 | // paused and we'll desync, so just play silence. | 198 | // paused and we'll desync, so just play silence. |
| 204 | if (system.IsPaused() || system.IsShuttingDown()) { | 199 | if (system.IsPaused() || system.IsShuttingDown()) { |
| 200 | if (system.IsShuttingDown()) { | ||
| 201 | release_cv.notify_one(); | ||
| 202 | } | ||
| 203 | |||
| 205 | static constexpr std::array<s16, 6> silence{}; | 204 | static constexpr std::array<s16, 6> silence{}; |
| 206 | for (size_t i = frames_written; i < num_frames; i++) { | 205 | for (size_t i = frames_written; i < num_frames; i++) { |
| 207 | std::memcpy(&output_buffer[i * frame_size], &silence[0], frame_size_bytes); | 206 | 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 | |||
| 209 | return; | 208 | return; |
| 210 | } | 209 | } |
| 211 | 210 | ||
| 212 | // Due to many frames being queued up with nvdec (5 frames or so?), a lot of buffers also get | ||
| 213 | // queued up (30+) but not all at once, which causes constant stalling here, so just let the | ||
| 214 | // video play out without attempting to stall. | ||
| 215 | // Can hopefully remove this later with a more complete NVDEC implementation. | ||
| 216 | const auto nvdec_active{system.AudioCore().IsNVDECActive()}; | ||
| 217 | |||
| 218 | // Core timing cannot be paused in single-core mode, so Stall ends up being called over and over | ||
| 219 | // and never recovers to a normal state, so just skip attempting to sync things on single-core. | ||
| 220 | if (system.IsMulticore() && !nvdec_active && queued_buffers > max_queue_size) { | ||
| 221 | Stall(); | ||
| 222 | } else if (system.IsMulticore() && queued_buffers <= max_queue_size) { | ||
| 223 | Unstall(); | ||
| 224 | } | ||
| 225 | |||
| 226 | while (frames_written < num_frames) { | 211 | while (frames_written < num_frames) { |
| 227 | // If the playing buffer has been consumed or has no frames, we need a new one | 212 | // If the playing buffer has been consumed or has no frames, we need a new one |
| 228 | if (playing_buffer.consumed || playing_buffer.frames == 0) { | 213 | if (playing_buffer.consumed || playing_buffer.frames == 0) { |
| @@ -237,6 +222,10 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz | |||
| 237 | } | 222 | } |
| 238 | // Successfully dequeued a new buffer. | 223 | // Successfully dequeued a new buffer. |
| 239 | queued_buffers--; | 224 | queued_buffers--; |
| 225 | |||
| 226 | { std::unique_lock lk{release_mutex}; } | ||
| 227 | |||
| 228 | release_cv.notify_one(); | ||
| 240 | } | 229 | } |
| 241 | 230 | ||
| 242 | // Get the minimum frames available between the currently playing buffer, and the | 231 | // 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 | |||
| 248 | frames_available * frame_size); | 237 | frames_available * frame_size); |
| 249 | 238 | ||
| 250 | frames_written += frames_available; | 239 | frames_written += frames_available; |
| 240 | actual_frames_written += frames_available; | ||
| 251 | playing_buffer.frames_played += frames_available; | 241 | playing_buffer.frames_played += frames_available; |
| 252 | 242 | ||
| 253 | // If that's all the frames in the current buffer, add its samples and mark it as | 243 | // 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 | |||
| 260 | std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size], | 250 | std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size], |
| 261 | frame_size_bytes); | 251 | frame_size_bytes); |
| 262 | 252 | ||
| 263 | if (system.IsMulticore() && queued_buffers <= max_queue_size) { | 253 | { |
| 264 | Unstall(); | 254 | std::scoped_lock lk{sample_count_lock}; |
| 255 | last_sample_count_update_time = | ||
| 256 | Core::Timing::CyclesToUs(system.CoreTiming().GetClockTicks()); | ||
| 257 | min_played_sample_count = max_played_sample_count; | ||
| 258 | max_played_sample_count += actual_frames_written; | ||
| 265 | } | 259 | } |
| 266 | } | 260 | } |
| 267 | 261 | ||
| 268 | void SinkStream::Stall() { | 262 | u64 SinkStream::GetExpectedPlayedSampleCount() { |
| 269 | std::scoped_lock lk{stall_guard}; | 263 | std::scoped_lock lk{sample_count_lock}; |
| 270 | if (stalled_lock) { | 264 | auto cur_time{Core::Timing::CyclesToUs(system.CoreTiming().GetClockTicks())}; |
| 271 | return; | 265 | auto time_delta{cur_time - last_sample_count_update_time}; |
| 272 | } | 266 | auto exp_played_sample_count{min_played_sample_count + |
| 273 | stalled_lock = system.StallApplication(); | 267 | (TargetSampleRate * time_delta) / std::chrono::seconds{1}}; |
| 268 | |||
| 269 | return std::min<u64>(exp_played_sample_count, max_played_sample_count); | ||
| 274 | } | 270 | } |
| 275 | 271 | ||
| 276 | void SinkStream::Unstall() { | 272 | void SinkStream::WaitFreeSpace() { |
| 277 | std::scoped_lock lk{stall_guard}; | 273 | std::unique_lock lk{release_mutex}; |
| 278 | if (!stalled_lock) { | 274 | release_cv.wait( |
| 279 | return; | 275 | lk, [this]() { return queued_buffers < max_queue_size || system.IsShuttingDown(); }); |
| 280 | } | ||
| 281 | system.UnstallApplication(); | ||
| 282 | stalled_lock.unlock(); | ||
| 283 | } | 276 | } |
| 284 | 277 | ||
| 285 | } // namespace AudioCore::Sink | 278 | } // 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 @@ | |||
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <chrono> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <mutex> | 10 | #include <mutex> |
| 10 | #include <span> | 11 | #include <span> |
| @@ -14,6 +15,7 @@ | |||
| 14 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 15 | #include "common/reader_writer_queue.h" | 16 | #include "common/reader_writer_queue.h" |
| 16 | #include "common/ring_buffer.h" | 17 | #include "common/ring_buffer.h" |
| 18 | #include "common/thread.h" | ||
| 17 | 19 | ||
| 18 | namespace Core { | 20 | namespace Core { |
| 19 | class System; | 21 | class System; |
| @@ -53,9 +55,7 @@ struct SinkBuffer { | |||
| 53 | class SinkStream { | 55 | class SinkStream { |
| 54 | public: | 56 | public: |
| 55 | explicit SinkStream(Core::System& system_, StreamType type_) : system{system_}, type{type_} {} | 57 | explicit SinkStream(Core::System& system_, StreamType type_) : system{system_}, type{type_} {} |
| 56 | virtual ~SinkStream() { | 58 | virtual ~SinkStream() {} |
| 57 | Unstall(); | ||
| 58 | } | ||
| 59 | 59 | ||
| 60 | /** | 60 | /** |
| 61 | * Finalize the sink stream. | 61 | * Finalize the sink stream. |
| @@ -201,14 +201,16 @@ public: | |||
| 201 | void ProcessAudioOutAndRender(std::span<s16> output_buffer, std::size_t num_frames); | 201 | void ProcessAudioOutAndRender(std::span<s16> output_buffer, std::size_t num_frames); |
| 202 | 202 | ||
| 203 | /** | 203 | /** |
| 204 | * Stall core processes if the audio thread falls too far behind. | 204 | * Get the total number of samples expected to have been played by this stream. |
| 205 | * | ||
| 206 | * @return The number of samples. | ||
| 205 | */ | 207 | */ |
| 206 | void Stall(); | 208 | u64 GetExpectedPlayedSampleCount(); |
| 207 | 209 | ||
| 208 | /** | 210 | /** |
| 209 | * Unstall core processes. | 211 | * Waits for free space in the sample ring buffer |
| 210 | */ | 212 | */ |
| 211 | void Unstall(); | 213 | void WaitFreeSpace(); |
| 212 | 214 | ||
| 213 | protected: | 215 | protected: |
| 214 | /// Core system | 216 | /// Core system |
| @@ -237,12 +239,21 @@ private: | |||
| 237 | std::atomic<u32> queued_buffers{}; | 239 | std::atomic<u32> queued_buffers{}; |
| 238 | /// The ring size for audio out buffers (usually 4, rarely 2 or 8) | 240 | /// The ring size for audio out buffers (usually 4, rarely 2 or 8) |
| 239 | u32 max_queue_size{}; | 241 | u32 max_queue_size{}; |
| 242 | /// Locks access to sample count tracking info | ||
| 243 | std::mutex sample_count_lock; | ||
| 244 | /// Minimum number of total samples that have been played since the last callback | ||
| 245 | u64 min_played_sample_count{}; | ||
| 246 | /// Maximum number of total samples that can be played since the last callback | ||
| 247 | u64 max_played_sample_count{}; | ||
| 248 | /// The time the two above tracking variables were last written to | ||
| 249 | std::chrono::microseconds last_sample_count_update_time{}; | ||
| 240 | /// Set by the audio render/in/out system which uses this stream | 250 | /// Set by the audio render/in/out system which uses this stream |
| 241 | f32 system_volume{1.0f}; | 251 | f32 system_volume{1.0f}; |
| 242 | /// Set via IAudioDevice service calls | 252 | /// Set via IAudioDevice service calls |
| 243 | f32 device_volume{1.0f}; | 253 | f32 device_volume{1.0f}; |
| 244 | std::mutex stall_guard; | 254 | /// Signalled when ring buffer entries are consumed |
| 245 | std::unique_lock<std::mutex> stalled_lock; | 255 | std::condition_variable release_cv; |
| 256 | std::mutex release_mutex; | ||
| 246 | }; | 257 | }; |
| 247 | 258 | ||
| 248 | using SinkStreamPtr = std::unique_ptr<SinkStream>; | 259 | using SinkStreamPtr = std::unique_ptr<SinkStream>; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index cab21a88e..dfdcbe35a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <dynarmic/interface/A32/a32.h> | 6 | #include <dynarmic/interface/A32/a32.h> |
| 7 | #include <dynarmic/interface/A32/config.h> | 7 | #include <dynarmic/interface/A32/config.h> |
| 8 | #include <dynarmic/interface/A32/context.h> | ||
| 9 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 10 | #include "common/literals.h" | 9 | #include "common/literals.h" |
| 11 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| @@ -410,21 +409,19 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { | |||
| 410 | } | 409 | } |
| 411 | 410 | ||
| 412 | void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { | 411 | void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { |
| 413 | Dynarmic::A32::Context context; | 412 | Dynarmic::A32::Jit* j = jit.load(); |
| 414 | jit.load()->SaveContext(context); | 413 | ctx.cpu_registers = j->Regs(); |
| 415 | ctx.cpu_registers = context.Regs(); | 414 | ctx.extension_registers = j->ExtRegs(); |
| 416 | ctx.extension_registers = context.ExtRegs(); | 415 | ctx.cpsr = j->Cpsr(); |
| 417 | ctx.cpsr = context.Cpsr(); | 416 | ctx.fpscr = j->Fpscr(); |
| 418 | ctx.fpscr = context.Fpscr(); | ||
| 419 | } | 417 | } |
| 420 | 418 | ||
| 421 | void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { | 419 | void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { |
| 422 | Dynarmic::A32::Context context; | 420 | Dynarmic::A32::Jit* j = jit.load(); |
| 423 | context.Regs() = ctx.cpu_registers; | 421 | j->Regs() = ctx.cpu_registers; |
| 424 | context.ExtRegs() = ctx.extension_registers; | 422 | j->ExtRegs() = ctx.extension_registers; |
| 425 | context.SetCpsr(ctx.cpsr); | 423 | j->SetCpsr(ctx.cpsr); |
| 426 | context.SetFpscr(ctx.fpscr); | 424 | j->SetFpscr(ctx.fpscr); |
| 427 | jit.load()->LoadContext(context); | ||
| 428 | } | 425 | } |
| 429 | 426 | ||
| 430 | void ARM_Dynarmic_32::SignalInterrupt() { | 427 | void ARM_Dynarmic_32::SignalInterrupt() { |
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 8e586e938..3300d4f79 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp | |||
| @@ -71,7 +71,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac | |||
| 71 | } | 71 | } |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | callback(); | 74 | callback(true); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | } // namespace Core::Frontend | 77 | } // namespace Core::Frontend |
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index 5c488387d..19a2db6bf 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h | |||
| @@ -37,7 +37,7 @@ struct ControllerParameters { | |||
| 37 | 37 | ||
| 38 | class ControllerApplet : public Applet { | 38 | class ControllerApplet : public Applet { |
| 39 | public: | 39 | public: |
| 40 | using ReconfigureCallback = std::function<void()>; | 40 | using ReconfigureCallback = std::function<void(bool)>; |
| 41 | 41 | ||
| 42 | virtual ~ControllerApplet(); | 42 | virtual ~ControllerApplet(); |
| 43 | 43 | ||
diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp index 910d20c0d..c18f17a36 100644 --- a/src/core/frontend/applets/profile_select.cpp +++ b/src/core/frontend/applets/profile_select.cpp | |||
| @@ -11,7 +11,8 @@ ProfileSelectApplet::~ProfileSelectApplet() = default; | |||
| 11 | 11 | ||
| 12 | void DefaultProfileSelectApplet::Close() const {} | 12 | void DefaultProfileSelectApplet::Close() const {} |
| 13 | 13 | ||
| 14 | void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback) const { | 14 | void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback, |
| 15 | const ProfileSelectParameters& parameters) const { | ||
| 15 | Service::Account::ProfileManager manager; | 16 | Service::Account::ProfileManager manager; |
| 16 | callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{})); | 17 | callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{})); |
| 17 | LOG_INFO(Service_ACC, "called, selecting current user instead of prompting..."); | 18 | 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 76e963535..92e2737ea 100644 --- a/src/core/frontend/applets/profile_select.h +++ b/src/core/frontend/applets/profile_select.h | |||
| @@ -5,25 +5,35 @@ | |||
| 5 | 5 | ||
| 6 | #include <functional> | 6 | #include <functional> |
| 7 | #include <optional> | 7 | #include <optional> |
| 8 | #include "common/uuid.h" | ||
| 9 | 8 | ||
| 9 | #include "common/uuid.h" | ||
| 10 | #include "core/frontend/applets/applet.h" | 10 | #include "core/frontend/applets/applet.h" |
| 11 | #include "core/hle/service/am/applets/applet_profile_select.h" | ||
| 11 | 12 | ||
| 12 | namespace Core::Frontend { | 13 | namespace Core::Frontend { |
| 13 | 14 | ||
| 15 | struct ProfileSelectParameters { | ||
| 16 | Service::AM::Applets::UiMode mode; | ||
| 17 | std::array<Common::UUID, 8> invalid_uid_list; | ||
| 18 | Service::AM::Applets::UiSettingsDisplayOptions display_options; | ||
| 19 | Service::AM::Applets::UserSelectionPurpose purpose; | ||
| 20 | }; | ||
| 21 | |||
| 14 | class ProfileSelectApplet : public Applet { | 22 | class ProfileSelectApplet : public Applet { |
| 15 | public: | 23 | public: |
| 16 | using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>; | 24 | using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>; |
| 17 | 25 | ||
| 18 | virtual ~ProfileSelectApplet(); | 26 | virtual ~ProfileSelectApplet(); |
| 19 | 27 | ||
| 20 | virtual void SelectProfile(SelectProfileCallback callback) const = 0; | 28 | virtual void SelectProfile(SelectProfileCallback callback, |
| 29 | const ProfileSelectParameters& parameters) const = 0; | ||
| 21 | }; | 30 | }; |
| 22 | 31 | ||
| 23 | class DefaultProfileSelectApplet final : public ProfileSelectApplet { | 32 | class DefaultProfileSelectApplet final : public ProfileSelectApplet { |
| 24 | public: | 33 | public: |
| 25 | void Close() const override; | 34 | void Close() const override; |
| 26 | void SelectProfile(SelectProfileCallback callback) const override; | 35 | void SelectProfile(SelectProfileCallback callback, |
| 36 | const ProfileSelectParameters& parameters) const override; | ||
| 27 | }; | 37 | }; |
| 28 | 38 | ||
| 29 | } // namespace Core::Frontend | 39 | } // namespace Core::Frontend |
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 2d1d115d7..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() { | |||
| 224 | parameters.allow_dual_joycons, parameters.allow_left_joycon, | 224 | parameters.allow_dual_joycons, parameters.allow_left_joycon, |
| 225 | parameters.allow_right_joycon); | 225 | parameters.allow_right_joycon); |
| 226 | 226 | ||
| 227 | frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters); | 227 | frontend.ReconfigureControllers( |
| 228 | [this](bool is_success) { ConfigurationComplete(is_success); }, parameters); | ||
| 228 | break; | 229 | break; |
| 229 | } | 230 | } |
| 230 | case ControllerSupportMode::ShowControllerStrapGuide: | 231 | case ControllerSupportMode::ShowControllerStrapGuide: |
| @@ -232,16 +233,16 @@ void Controller::Execute() { | |||
| 232 | case ControllerSupportMode::ShowControllerKeyRemappingForSystem: | 233 | case ControllerSupportMode::ShowControllerKeyRemappingForSystem: |
| 233 | UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", | 234 | UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", |
| 234 | controller_private_arg.mode); | 235 | controller_private_arg.mode); |
| 235 | ConfigurationComplete(); | 236 | ConfigurationComplete(true); |
| 236 | break; | 237 | break; |
| 237 | default: { | 238 | default: { |
| 238 | ConfigurationComplete(); | 239 | ConfigurationComplete(true); |
| 239 | break; | 240 | break; |
| 240 | } | 241 | } |
| 241 | } | 242 | } |
| 242 | } | 243 | } |
| 243 | 244 | ||
| 244 | void Controller::ConfigurationComplete() { | 245 | void Controller::ConfigurationComplete(bool is_success) { |
| 245 | ControllerSupportResultInfo result_info{}; | 246 | ControllerSupportResultInfo result_info{}; |
| 246 | 247 | ||
| 247 | // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. | 248 | // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. |
| @@ -250,7 +251,8 @@ void Controller::ConfigurationComplete() { | |||
| 250 | 251 | ||
| 251 | result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId()); | 252 | result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId()); |
| 252 | 253 | ||
| 253 | result_info.result = 0; | 254 | result_info.result = |
| 255 | is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel; | ||
| 254 | 256 | ||
| 255 | LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}", | 257 | LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}", |
| 256 | result_info.player_count, result_info.selected_id, result_info.result); | 258 | result_info.player_count, result_info.selected_id, result_info.result); |
diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h index 1fbabee11..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 { | |||
| 48 | MaxControllerSupportCaller, | 48 | MaxControllerSupportCaller, |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | enum class ControllerSupportResult : u32 { | ||
| 52 | Success = 0, | ||
| 53 | Cancel = 2, | ||
| 54 | }; | ||
| 55 | |||
| 51 | struct ControllerSupportArgPrivate { | 56 | struct ControllerSupportArgPrivate { |
| 52 | u32 arg_private_size{}; | 57 | u32 arg_private_size{}; |
| 53 | u32 arg_size{}; | 58 | u32 arg_size{}; |
| @@ -112,7 +117,7 @@ struct ControllerSupportResultInfo { | |||
| 112 | s8 player_count{}; | 117 | s8 player_count{}; |
| 113 | INSERT_PADDING_BYTES(3); | 118 | INSERT_PADDING_BYTES(3); |
| 114 | u32 selected_id{}; | 119 | u32 selected_id{}; |
| 115 | u32 result{}; | 120 | ControllerSupportResult result{}; |
| 116 | }; | 121 | }; |
| 117 | static_assert(sizeof(ControllerSupportResultInfo) == 0xC, | 122 | static_assert(sizeof(ControllerSupportResultInfo) == 0xC, |
| 118 | "ControllerSupportResultInfo has incorrect size."); | 123 | "ControllerSupportResultInfo has incorrect size."); |
| @@ -131,7 +136,7 @@ public: | |||
| 131 | void Execute() override; | 136 | void Execute() override; |
| 132 | Result RequestExit() override; | 137 | Result RequestExit() override; |
| 133 | 138 | ||
| 134 | void ConfigurationComplete(); | 139 | void ConfigurationComplete(bool is_success); |
| 135 | 140 | ||
| 136 | private: | 141 | private: |
| 137 | const Core::Frontend::ControllerApplet& frontend; | 142 | const Core::Frontend::ControllerApplet& frontend; |
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 07abc2563..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() { | |||
| 25 | final_data.clear(); | 25 | final_data.clear(); |
| 26 | 26 | ||
| 27 | Applet::Initialize(); | 27 | Applet::Initialize(); |
| 28 | profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; | ||
| 28 | 29 | ||
| 29 | const auto user_config_storage = broker.PopNormalDataToApplet(); | 30 | const auto user_config_storage = broker.PopNormalDataToApplet(); |
| 30 | ASSERT(user_config_storage != nullptr); | 31 | ASSERT(user_config_storage != nullptr); |
| 31 | const auto& user_config = user_config_storage->GetData(); | 32 | const auto& user_config = user_config_storage->GetData(); |
| 32 | 33 | ||
| 33 | ASSERT(user_config.size() >= sizeof(UserSelectionConfig)); | 34 | LOG_INFO(Service_AM, "Initializing Profile Select Applet with version={}", |
| 34 | std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig)); | 35 | profile_select_version); |
| 36 | |||
| 37 | switch (profile_select_version) { | ||
| 38 | case ProfileSelectAppletVersion::Version1: | ||
| 39 | ASSERT(user_config.size() == sizeof(UiSettingsV1)); | ||
| 40 | std::memcpy(&config_old, user_config.data(), sizeof(UiSettingsV1)); | ||
| 41 | break; | ||
| 42 | case ProfileSelectAppletVersion::Version2: | ||
| 43 | case ProfileSelectAppletVersion::Version3: | ||
| 44 | ASSERT(user_config.size() == sizeof(UiSettings)); | ||
| 45 | std::memcpy(&config, user_config.data(), sizeof(UiSettings)); | ||
| 46 | break; | ||
| 47 | default: | ||
| 48 | UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); | ||
| 49 | break; | ||
| 50 | } | ||
| 35 | } | 51 | } |
| 36 | 52 | ||
| 37 | bool ProfileSelect::TransactionComplete() const { | 53 | bool ProfileSelect::TransactionComplete() const { |
| @@ -52,11 +68,37 @@ void ProfileSelect::Execute() { | |||
| 52 | return; | 68 | return; |
| 53 | } | 69 | } |
| 54 | 70 | ||
| 55 | frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); }); | 71 | Core::Frontend::ProfileSelectParameters parameters{}; |
| 72 | |||
| 73 | switch (profile_select_version) { | ||
| 74 | case ProfileSelectAppletVersion::Version1: | ||
| 75 | parameters = { | ||
| 76 | .mode = config_old.mode, | ||
| 77 | .invalid_uid_list = config_old.invalid_uid_list, | ||
| 78 | .display_options = config_old.display_options, | ||
| 79 | .purpose = UserSelectionPurpose::General, | ||
| 80 | }; | ||
| 81 | break; | ||
| 82 | case ProfileSelectAppletVersion::Version2: | ||
| 83 | case ProfileSelectAppletVersion::Version3: | ||
| 84 | parameters = { | ||
| 85 | .mode = config.mode, | ||
| 86 | .invalid_uid_list = config.invalid_uid_list, | ||
| 87 | .display_options = config.display_options, | ||
| 88 | .purpose = config.purpose, | ||
| 89 | }; | ||
| 90 | break; | ||
| 91 | default: | ||
| 92 | UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version); | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | |||
| 96 | frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); }, | ||
| 97 | parameters); | ||
| 56 | } | 98 | } |
| 57 | 99 | ||
| 58 | void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { | 100 | void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { |
| 59 | UserSelectionOutput output{}; | 101 | UiReturnArg output{}; |
| 60 | 102 | ||
| 61 | if (uuid.has_value() && uuid->IsValid()) { | 103 | if (uuid.has_value() && uuid->IsValid()) { |
| 62 | output.result = 0; | 104 | output.result = 0; |
| @@ -67,7 +109,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { | |||
| 67 | output.uuid_selected = Common::InvalidUUID; | 109 | output.uuid_selected = Common::InvalidUUID; |
| 68 | } | 110 | } |
| 69 | 111 | ||
| 70 | final_data = std::vector<u8>(sizeof(UserSelectionOutput)); | 112 | final_data = std::vector<u8>(sizeof(UiReturnArg)); |
| 71 | std::memcpy(final_data.data(), &output, final_data.size()); | 113 | std::memcpy(final_data.data(), &output, final_data.size()); |
| 72 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); | 114 | broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); |
| 73 | broker.SignalStateChanged(); | 115 | broker.SignalStateChanged(); |
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 85705c216..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; | |||
| 16 | 16 | ||
| 17 | namespace Service::AM::Applets { | 17 | namespace Service::AM::Applets { |
| 18 | 18 | ||
| 19 | struct UserSelectionConfig { | 19 | enum class ProfileSelectAppletVersion : u32 { |
| 20 | // TODO(DarkLordZach): RE this structure | 20 | Version1 = 0x1, // 1.0.0+ |
| 21 | // It seems to be flags and the like that determine the UI of the applet on the switch... from | 21 | Version2 = 0x10000, // 2.0.0+ |
| 22 | // my research this is safe to ignore for now. | 22 | Version3 = 0x20000, // 6.0.0+ |
| 23 | INSERT_PADDING_BYTES(0xA0); | ||
| 24 | }; | 23 | }; |
| 25 | static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size."); | ||
| 26 | 24 | ||
| 27 | struct UserSelectionOutput { | 25 | // This is nn::account::UiMode |
| 26 | enum class UiMode { | ||
| 27 | UserSelector, | ||
| 28 | UserCreator, | ||
| 29 | EnsureNetworkServiceAccountAvailable, | ||
| 30 | UserIconEditor, | ||
| 31 | UserNicknameEditor, | ||
| 32 | UserCreatorForStarter, | ||
| 33 | NintendoAccountAuthorizationRequestContext, | ||
| 34 | IntroduceExternalNetworkServiceAccount, | ||
| 35 | IntroduceExternalNetworkServiceAccountForRegistration, | ||
| 36 | NintendoAccountNnidLinker, | ||
| 37 | LicenseRequirementsForNetworkService, | ||
| 38 | LicenseRequirementsForNetworkServiceWithUserContextImpl, | ||
| 39 | UserCreatorForImmediateNaLoginTest, | ||
| 40 | UserQualificationPromoter, | ||
| 41 | }; | ||
| 42 | |||
| 43 | // This is nn::account::UserSelectionPurpose | ||
| 44 | enum class UserSelectionPurpose { | ||
| 45 | General, | ||
| 46 | GameCardRegistration, | ||
| 47 | EShopLaunch, | ||
| 48 | EShopItemShow, | ||
| 49 | PicturePost, | ||
| 50 | NintendoAccountLinkage, | ||
| 51 | SettingsUpdate, | ||
| 52 | SaveDataDeletion, | ||
| 53 | UserMigration, | ||
| 54 | SaveDataTransfer, | ||
| 55 | }; | ||
| 56 | |||
| 57 | // This is nn::account::NintendoAccountStartupDialogType | ||
| 58 | enum class NintendoAccountStartupDialogType { | ||
| 59 | LoginAndCreate, | ||
| 60 | Login, | ||
| 61 | Create, | ||
| 62 | }; | ||
| 63 | |||
| 64 | // This is nn::account::UserSelectionSettingsForSystemService | ||
| 65 | struct UserSelectionSettingsForSystemService { | ||
| 66 | UserSelectionPurpose purpose; | ||
| 67 | bool enable_user_creation; | ||
| 68 | INSERT_PADDING_BYTES(0x3); | ||
| 69 | }; | ||
| 70 | static_assert(sizeof(UserSelectionSettingsForSystemService) == 0x8, | ||
| 71 | "UserSelectionSettingsForSystemService has incorrect size."); | ||
| 72 | |||
| 73 | struct UiSettingsDisplayOptions { | ||
| 74 | bool is_network_service_account_required; | ||
| 75 | bool is_skip_enabled; | ||
| 76 | bool is_system_or_launcher; | ||
| 77 | bool is_registration_permitted; | ||
| 78 | bool show_skip_button; | ||
| 79 | bool aditional_select; | ||
| 80 | bool show_user_selector; | ||
| 81 | bool is_unqualified_user_selectable; | ||
| 82 | }; | ||
| 83 | static_assert(sizeof(UiSettingsDisplayOptions) == 0x8, | ||
| 84 | "UiSettingsDisplayOptions has incorrect size."); | ||
| 85 | |||
| 86 | struct UiSettingsV1 { | ||
| 87 | UiMode mode; | ||
| 88 | INSERT_PADDING_BYTES(0x4); | ||
| 89 | std::array<Common::UUID, 8> invalid_uid_list; | ||
| 90 | u64 application_id; | ||
| 91 | UiSettingsDisplayOptions display_options; | ||
| 92 | }; | ||
| 93 | static_assert(sizeof(UiSettingsV1) == 0x98, "UiSettings has incorrect size."); | ||
| 94 | |||
| 95 | // This is nn::account::UiSettings | ||
| 96 | struct UiSettings { | ||
| 97 | UiMode mode; | ||
| 98 | INSERT_PADDING_BYTES(0x4); | ||
| 99 | std::array<Common::UUID, 8> invalid_uid_list; | ||
| 100 | u64 application_id; | ||
| 101 | UiSettingsDisplayOptions display_options; | ||
| 102 | UserSelectionPurpose purpose; | ||
| 103 | INSERT_PADDING_BYTES(0x4); | ||
| 104 | }; | ||
| 105 | static_assert(sizeof(UiSettings) == 0xA0, "UiSettings has incorrect size."); | ||
| 106 | |||
| 107 | // This is nn::account::UiReturnArg | ||
| 108 | struct UiReturnArg { | ||
| 28 | u64 result; | 109 | u64 result; |
| 29 | Common::UUID uuid_selected; | 110 | Common::UUID uuid_selected; |
| 30 | }; | 111 | }; |
| 31 | static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size."); | 112 | static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); |
| 32 | 113 | ||
| 33 | class ProfileSelect final : public Applet { | 114 | class ProfileSelect final : public Applet { |
| 34 | public: | 115 | public: |
| @@ -49,7 +130,10 @@ public: | |||
| 49 | private: | 130 | private: |
| 50 | const Core::Frontend::ProfileSelectApplet& frontend; | 131 | const Core::Frontend::ProfileSelectApplet& frontend; |
| 51 | 132 | ||
| 52 | UserSelectionConfig config; | 133 | UiSettings config; |
| 134 | UiSettingsV1 config_old; | ||
| 135 | ProfileSelectAppletVersion profile_select_version; | ||
| 136 | |||
| 53 | bool complete = false; | 137 | bool complete = false; |
| 54 | Result status = ResultSuccess; | 138 | Result status = ResultSuccess; |
| 55 | std::vector<u8> final_data; | 139 | std::vector<u8> final_data; |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 21bd7b0c5..8abf71608 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -70,7 +70,6 @@ Result Controller_NPad::VerifyValidSixAxisSensorHandle( | |||
| 70 | const Core::HID::SixAxisSensorHandle& device_handle) { | 70 | const Core::HID::SixAxisSensorHandle& device_handle) { |
| 71 | const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); | 71 | const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); |
| 72 | const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; | 72 | const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; |
| 73 | const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; | ||
| 74 | 73 | ||
| 75 | if (!npad_id) { | 74 | if (!npad_id) { |
| 76 | return InvalidNpadId; | 75 | return InvalidNpadId; |
| @@ -78,10 +77,6 @@ Result Controller_NPad::VerifyValidSixAxisSensorHandle( | |||
| 78 | if (!device_index) { | 77 | if (!device_index) { |
| 79 | return NpadDeviceIndexOutOfRange; | 78 | return NpadDeviceIndexOutOfRange; |
| 80 | } | 79 | } |
| 81 | // This doesn't get validated on nnsdk | ||
| 82 | if (!npad_type) { | ||
| 83 | return NpadInvalidHandle; | ||
| 84 | } | ||
| 85 | 80 | ||
| 86 | return ResultSuccess; | 81 | return ResultSuccess; |
| 87 | } | 82 | } |
| @@ -819,12 +814,12 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode | |||
| 819 | return communication_mode; | 814 | return communication_mode; |
| 820 | } | 815 | } |
| 821 | 816 | ||
| 822 | Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, | 817 | bool Controller_NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, |
| 823 | NpadJoyDeviceType npad_device_type, | 818 | NpadJoyDeviceType npad_device_type, |
| 824 | NpadJoyAssignmentMode assignment_mode) { | 819 | NpadJoyAssignmentMode assignment_mode) { |
| 825 | if (!IsNpadIdValid(npad_id)) { | 820 | if (!IsNpadIdValid(npad_id)) { |
| 826 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | 821 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 827 | return InvalidNpadId; | 822 | return false; |
| 828 | } | 823 | } |
| 829 | 824 | ||
| 830 | auto& controller = GetControllerFromNpadIdType(npad_id); | 825 | auto& controller = GetControllerFromNpadIdType(npad_id); |
| @@ -833,7 +828,7 @@ Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, | |||
| 833 | } | 828 | } |
| 834 | 829 | ||
| 835 | if (!controller.device->IsConnected()) { | 830 | if (!controller.device->IsConnected()) { |
| 836 | return ResultSuccess; | 831 | return false; |
| 837 | } | 832 | } |
| 838 | 833 | ||
| 839 | if (assignment_mode == NpadJoyAssignmentMode::Dual) { | 834 | if (assignment_mode == NpadJoyAssignmentMode::Dual) { |
| @@ -842,52 +837,52 @@ Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, | |||
| 842 | controller.is_dual_left_connected = true; | 837 | controller.is_dual_left_connected = true; |
| 843 | controller.is_dual_right_connected = false; | 838 | controller.is_dual_right_connected = false; |
| 844 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | 839 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); |
| 845 | return ResultSuccess; | 840 | return false; |
| 846 | } | 841 | } |
| 847 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { | 842 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { |
| 848 | DisconnectNpad(npad_id); | 843 | DisconnectNpad(npad_id); |
| 849 | controller.is_dual_left_connected = false; | 844 | controller.is_dual_left_connected = false; |
| 850 | controller.is_dual_right_connected = true; | 845 | controller.is_dual_right_connected = true; |
| 851 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | 846 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); |
| 852 | return ResultSuccess; | 847 | return false; |
| 853 | } | 848 | } |
| 854 | return ResultSuccess; | 849 | return false; |
| 855 | } | 850 | } |
| 856 | 851 | ||
| 857 | // This is for NpadJoyAssignmentMode::Single | 852 | // This is for NpadJoyAssignmentMode::Single |
| 858 | 853 | ||
| 859 | // Only JoyconDual get affected by this function | 854 | // Only JoyconDual get affected by this function |
| 860 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { | 855 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { |
| 861 | return ResultSuccess; | 856 | return false; |
| 862 | } | 857 | } |
| 863 | 858 | ||
| 864 | if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { | 859 | if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { |
| 865 | DisconnectNpad(npad_id); | 860 | DisconnectNpad(npad_id); |
| 866 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); | 861 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); |
| 867 | return ResultSuccess; | 862 | return false; |
| 868 | } | 863 | } |
| 869 | if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { | 864 | if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { |
| 870 | DisconnectNpad(npad_id); | 865 | DisconnectNpad(npad_id); |
| 871 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); | 866 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); |
| 872 | return ResultSuccess; | 867 | return false; |
| 873 | } | 868 | } |
| 874 | 869 | ||
| 875 | // We have two controllers connected to the same npad_id we need to split them | 870 | // We have two controllers connected to the same npad_id we need to split them |
| 876 | const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId(); | 871 | new_npad_id = hid_core.GetFirstDisconnectedNpadId(); |
| 877 | auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); | 872 | auto& controller_2 = GetControllerFromNpadIdType(new_npad_id); |
| 878 | DisconnectNpad(npad_id); | 873 | DisconnectNpad(npad_id); |
| 879 | if (npad_device_type == NpadJoyDeviceType::Left) { | 874 | if (npad_device_type == NpadJoyDeviceType::Left) { |
| 880 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); | 875 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); |
| 881 | controller_2.is_dual_left_connected = false; | 876 | controller_2.is_dual_left_connected = false; |
| 882 | controller_2.is_dual_right_connected = true; | 877 | controller_2.is_dual_right_connected = true; |
| 883 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); | 878 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); |
| 884 | } else { | 879 | } else { |
| 885 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); | 880 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); |
| 886 | controller_2.is_dual_left_connected = true; | 881 | controller_2.is_dual_left_connected = true; |
| 887 | controller_2.is_dual_right_connected = false; | 882 | controller_2.is_dual_right_connected = false; |
| 888 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); | 883 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); |
| 889 | } | 884 | } |
| 890 | return ResultSuccess; | 885 | return true; |
| 891 | } | 886 | } |
| 892 | 887 | ||
| 893 | bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, | 888 | bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, |
| @@ -1131,6 +1126,7 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { | |||
| 1131 | WriteEmptyEntry(shared_memory); | 1126 | WriteEmptyEntry(shared_memory); |
| 1132 | return ResultSuccess; | 1127 | return ResultSuccess; |
| 1133 | } | 1128 | } |
| 1129 | |||
| 1134 | Result Controller_NPad::SetGyroscopeZeroDriftMode( | 1130 | Result Controller_NPad::SetGyroscopeZeroDriftMode( |
| 1135 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, | 1131 | const Core::HID::SixAxisSensorHandle& sixaxis_handle, |
| 1136 | Core::HID::GyroscopeZeroDriftMode drift_mode) { | 1132 | Core::HID::GyroscopeZeroDriftMode drift_mode) { |
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: | |||
| 102 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); | 102 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); |
| 103 | NpadCommunicationMode GetNpadCommunicationMode() const; | 103 | NpadCommunicationMode GetNpadCommunicationMode() const; |
| 104 | 104 | ||
| 105 | Result SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, | 105 | bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, |
| 106 | NpadJoyAssignmentMode assignment_mode); | 106 | NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); |
| 107 | 107 | ||
| 108 | bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, | 108 | bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, |
| 109 | const Core::HID::VibrationValue& vibration_value); | 109 | 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_) | |||
| 302 | {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, | 302 | {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, |
| 303 | {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"}, | 303 | {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"}, |
| 304 | {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, | 304 | {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, |
| 305 | {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, | 305 | {133, &Hid::SetNpadJoyAssignmentModeSingleWithDestination, "SetNpadJoyAssignmentModeSingleWithDestination"}, |
| 306 | {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"}, | 306 | {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"}, |
| 307 | {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"}, | 307 | {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"}, |
| 308 | {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"}, | 308 | {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"}, |
| @@ -1180,8 +1180,10 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) { | |||
| 1180 | 1180 | ||
| 1181 | const auto parameters{rp.PopRaw<Parameters>()}; | 1181 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1182 | 1182 | ||
| 1183 | Core::HID::NpadIdType new_npad_id{}; | ||
| 1183 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | 1184 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1184 | controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, | 1185 | controller.SetNpadMode(new_npad_id, parameters.npad_id, |
| 1186 | Controller_NPad::NpadJoyDeviceType::Left, | ||
| 1185 | Controller_NPad::NpadJoyAssignmentMode::Single); | 1187 | Controller_NPad::NpadJoyAssignmentMode::Single); |
| 1186 | 1188 | ||
| 1187 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1189 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| @@ -1203,8 +1205,9 @@ void Hid::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) { | |||
| 1203 | 1205 | ||
| 1204 | const auto parameters{rp.PopRaw<Parameters>()}; | 1206 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1205 | 1207 | ||
| 1208 | Core::HID::NpadIdType new_npad_id{}; | ||
| 1206 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | 1209 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1207 | controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, | 1210 | controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, |
| 1208 | Controller_NPad::NpadJoyAssignmentMode::Single); | 1211 | Controller_NPad::NpadJoyAssignmentMode::Single); |
| 1209 | 1212 | ||
| 1210 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", | 1213 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", |
| @@ -1226,8 +1229,10 @@ void Hid::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) { | |||
| 1226 | 1229 | ||
| 1227 | const auto parameters{rp.PopRaw<Parameters>()}; | 1230 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1228 | 1231 | ||
| 1232 | Core::HID::NpadIdType new_npad_id{}; | ||
| 1229 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | 1233 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1230 | controller.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual); | 1234 | controller.SetNpadMode(new_npad_id, parameters.npad_id, {}, |
| 1235 | Controller_NPad::NpadJoyAssignmentMode::Dual); | ||
| 1231 | 1236 | ||
| 1232 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, | 1237 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 1233 | parameters.applet_resource_user_id); | 1238 | parameters.applet_resource_user_id); |
| @@ -1369,6 +1374,34 @@ void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { | |||
| 1369 | rb.Push(result); | 1374 | rb.Push(result); |
| 1370 | } | 1375 | } |
| 1371 | 1376 | ||
| 1377 | void Hid::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx) { | ||
| 1378 | IPC::RequestParser rp{ctx}; | ||
| 1379 | struct Parameters { | ||
| 1380 | Core::HID::NpadIdType npad_id; | ||
| 1381 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 1382 | u64 applet_resource_user_id; | ||
| 1383 | Controller_NPad::NpadJoyDeviceType npad_joy_device_type; | ||
| 1384 | }; | ||
| 1385 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | ||
| 1386 | |||
| 1387 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 1388 | |||
| 1389 | Core::HID::NpadIdType new_npad_id{}; | ||
| 1390 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | ||
| 1391 | const auto is_reassigned = | ||
| 1392 | controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, | ||
| 1393 | Controller_NPad::NpadJoyAssignmentMode::Single); | ||
| 1394 | |||
| 1395 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", | ||
| 1396 | parameters.npad_id, parameters.applet_resource_user_id, | ||
| 1397 | parameters.npad_joy_device_type); | ||
| 1398 | |||
| 1399 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 1400 | rb.Push(ResultSuccess); | ||
| 1401 | rb.Push(is_reassigned); | ||
| 1402 | rb.PushEnum(new_npad_id); | ||
| 1403 | } | ||
| 1404 | |||
| 1372 | void Hid::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { | 1405 | void Hid::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { |
| 1373 | IPC::RequestParser rp{ctx}; | 1406 | IPC::RequestParser rp{ctx}; |
| 1374 | struct Parameters { | 1407 | 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: | |||
| 151 | void SwapNpadAssignment(HLERequestContext& ctx); | 151 | void SwapNpadAssignment(HLERequestContext& ctx); |
| 152 | void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx); | 152 | void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx); |
| 153 | void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx); | 153 | void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx); |
| 154 | void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx); | ||
| 154 | void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx); | 155 | void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx); |
| 155 | void SetNpadCaptureButtonAssignment(HLERequestContext& ctx); | 156 | void SetNpadCaptureButtonAssignment(HLERequestContext& ctx); |
| 156 | void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx); | 157 | void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx); |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 63821d496..62fb98b55 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -1176,13 +1176,13 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | |||
| 1176 | const size_t size_bytes = CalculateGuestSizeInBytes(new_info); | 1176 | const size_t size_bytes = CalculateGuestSizeInBytes(new_info); |
| 1177 | const bool broken_views = runtime.HasBrokenTextureViewFormats(); | 1177 | const bool broken_views = runtime.HasBrokenTextureViewFormats(); |
| 1178 | const bool native_bgr = runtime.HasNativeBgr(); | 1178 | const bool native_bgr = runtime.HasNativeBgr(); |
| 1179 | std::vector<ImageId> overlap_ids; | 1179 | boost::container::small_vector<ImageId, 4> overlap_ids; |
| 1180 | std::unordered_set<ImageId> overlaps_found; | 1180 | std::unordered_set<ImageId> overlaps_found; |
| 1181 | std::vector<ImageId> left_aliased_ids; | 1181 | boost::container::small_vector<ImageId, 4> left_aliased_ids; |
| 1182 | std::vector<ImageId> right_aliased_ids; | 1182 | boost::container::small_vector<ImageId, 4> right_aliased_ids; |
| 1183 | std::unordered_set<ImageId> ignore_textures; | 1183 | std::unordered_set<ImageId> ignore_textures; |
| 1184 | std::vector<ImageId> bad_overlap_ids; | 1184 | boost::container::small_vector<ImageId, 4> bad_overlap_ids; |
| 1185 | std::vector<ImageId> all_siblings; | 1185 | boost::container::small_vector<ImageId, 4> all_siblings; |
| 1186 | const bool this_is_linear = info.type == ImageType::Linear; | 1186 | const bool this_is_linear = info.type == ImageType::Linear; |
| 1187 | const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) { | 1187 | const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) { |
| 1188 | if (True(overlap.flags & ImageFlagBits::Remapped)) { | 1188 | if (True(overlap.flags & ImageFlagBits::Remapped)) { |
| @@ -1298,16 +1298,16 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA | |||
| 1298 | Image& overlap = slot_images[overlap_id]; | 1298 | Image& overlap = slot_images[overlap_id]; |
| 1299 | if (True(overlap.flags & ImageFlagBits::GpuModified)) { | 1299 | if (True(overlap.flags & ImageFlagBits::GpuModified)) { |
| 1300 | new_image.flags |= ImageFlagBits::GpuModified; | 1300 | new_image.flags |= ImageFlagBits::GpuModified; |
| 1301 | } | 1301 | const auto& resolution = Settings::values.resolution_info; |
| 1302 | const auto& resolution = Settings::values.resolution_info; | 1302 | const SubresourceBase base = new_image.TryFindBase(overlap.gpu_addr).value(); |
| 1303 | const SubresourceBase base = new_image.TryFindBase(overlap.gpu_addr).value(); | 1303 | const u32 up_scale = can_rescale ? resolution.up_scale : 1; |
| 1304 | const u32 up_scale = can_rescale ? resolution.up_scale : 1; | 1304 | const u32 down_shift = can_rescale ? resolution.down_shift : 0; |
| 1305 | const u32 down_shift = can_rescale ? resolution.down_shift : 0; | 1305 | auto copies = MakeShrinkImageCopies(new_info, overlap.info, base, up_scale, down_shift); |
| 1306 | auto copies = MakeShrinkImageCopies(new_info, overlap.info, base, up_scale, down_shift); | 1306 | if (overlap.info.num_samples != new_image.info.num_samples) { |
| 1307 | if (overlap.info.num_samples != new_image.info.num_samples) { | 1307 | runtime.CopyImageMSAA(new_image, overlap, std::move(copies)); |
| 1308 | runtime.CopyImageMSAA(new_image, overlap, std::move(copies)); | 1308 | } else { |
| 1309 | } else { | 1309 | runtime.CopyImage(new_image, overlap, std::move(copies)); |
| 1310 | runtime.CopyImage(new_image, overlap, std::move(copies)); | 1310 | } |
| 1311 | } | 1311 | } |
| 1312 | if (True(overlap.flags & ImageFlagBits::Tracked)) { | 1312 | if (True(overlap.flags & ImageFlagBits::Tracked)) { |
| 1313 | UntrackImage(overlap, overlap_id); | 1313 | UntrackImage(overlap, overlap_id); |
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 { | |||
| 375 | return "VK_RESULT_MAX_ENUM"; | 375 | return "VK_RESULT_MAX_ENUM"; |
| 376 | case VkResult::VK_ERROR_COMPRESSION_EXHAUSTED_EXT: | 376 | case VkResult::VK_ERROR_COMPRESSION_EXHAUSTED_EXT: |
| 377 | return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT"; | 377 | return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT"; |
| 378 | case VkResult::VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT: | ||
| 379 | return "VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT"; | ||
| 378 | } | 380 | } |
| 379 | return "Unknown"; | 381 | return "Unknown"; |
| 380 | } | 382 | } |
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 79018a7f6..00aafb8f8 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp | |||
| @@ -300,7 +300,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() { | |||
| 300 | if (num_connected_players < min_supported_players || | 300 | if (num_connected_players < min_supported_players || |
| 301 | num_connected_players > max_supported_players) { | 301 | num_connected_players > max_supported_players) { |
| 302 | parameters_met = false; | 302 | parameters_met = false; |
| 303 | ui->buttonBox->setEnabled(parameters_met); | 303 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parameters_met); |
| 304 | return parameters_met; | 304 | return parameters_met; |
| 305 | } | 305 | } |
| 306 | 306 | ||
| @@ -327,7 +327,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() { | |||
| 327 | }(); | 327 | }(); |
| 328 | 328 | ||
| 329 | parameters_met = all_controllers_compatible; | 329 | parameters_met = all_controllers_compatible; |
| 330 | ui->buttonBox->setEnabled(parameters_met); | 330 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parameters_met); |
| 331 | return parameters_met; | 331 | return parameters_met; |
| 332 | } | 332 | } |
| 333 | 333 | ||
| @@ -697,8 +697,8 @@ void QtControllerSelector::ReconfigureControllers( | |||
| 697 | emit MainWindowReconfigureControllers(parameters); | 697 | emit MainWindowReconfigureControllers(parameters); |
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | void QtControllerSelector::MainWindowReconfigureFinished() { | 700 | void QtControllerSelector::MainWindowReconfigureFinished(bool is_success) { |
| 701 | if (callback) { | 701 | if (callback) { |
| 702 | callback(); | 702 | callback(is_success); |
| 703 | } | 703 | } |
| 704 | } | 704 | } |
diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index 2ef7e488f..2fdc35857 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h | |||
| @@ -167,7 +167,7 @@ signals: | |||
| 167 | void MainWindowRequestExit() const; | 167 | void MainWindowRequestExit() const; |
| 168 | 168 | ||
| 169 | private: | 169 | private: |
| 170 | void MainWindowReconfigureFinished(); | 170 | void MainWindowReconfigureFinished(bool is_success); |
| 171 | 171 | ||
| 172 | mutable ReconfigureCallback callback; | 172 | mutable ReconfigureCallback callback; |
| 173 | }; | 173 | }; |
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 @@ | |||
| 2629 | <bool>true</bool> | 2629 | <bool>true</bool> |
| 2630 | </property> | 2630 | </property> |
| 2631 | <property name="standardButtons"> | 2631 | <property name="standardButtons"> |
| 2632 | <set>QDialogButtonBox::Ok</set> | 2632 | <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> |
| 2633 | </property> | 2633 | </property> |
| 2634 | </widget> | 2634 | </widget> |
| 2635 | </item> | 2635 | </item> |
| @@ -2649,5 +2649,11 @@ | |||
| 2649 | <receiver>QtControllerSelectorDialog</receiver> | 2649 | <receiver>QtControllerSelectorDialog</receiver> |
| 2650 | <slot>accept()</slot> | 2650 | <slot>accept()</slot> |
| 2651 | </connection> | 2651 | </connection> |
| 2652 | <connection> | ||
| 2653 | <sender>buttonBox</sender> | ||
| 2654 | <signal>rejected()</signal> | ||
| 2655 | <receiver>QtControllerSelectorDialog</receiver> | ||
| 2656 | <slot>reject()</slot> | ||
| 2657 | </connection> | ||
| 2652 | </connections> | 2658 | </connections> |
| 2653 | </ui> | 2659 | </ui> |
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index c0a1d5ab7..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) { | |||
| 46 | } | 46 | } |
| 47 | } // Anonymous namespace | 47 | } // Anonymous namespace |
| 48 | 48 | ||
| 49 | QtProfileSelectionDialog::QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent) | 49 | QtProfileSelectionDialog::QtProfileSelectionDialog( |
| 50 | Core::HID::HIDCore& hid_core, QWidget* parent, | ||
| 51 | const Core::Frontend::ProfileSelectParameters& parameters) | ||
| 50 | : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) { | 52 | : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) { |
| 51 | outer_layout = new QVBoxLayout; | 53 | outer_layout = new QVBoxLayout; |
| 52 | 54 | ||
| 53 | instruction_label = new QLabel(tr("Select a user:")); | 55 | instruction_label = new QLabel(); |
| 54 | 56 | ||
| 55 | scroll_area = new QScrollArea; | 57 | scroll_area = new QScrollArea; |
| 56 | 58 | ||
| @@ -120,7 +122,8 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, | |||
| 120 | item_model->appendRow(item); | 122 | item_model->appendRow(item); |
| 121 | 123 | ||
| 122 | setLayout(outer_layout); | 124 | setLayout(outer_layout); |
| 123 | setWindowTitle(tr("Profile Selector")); | 125 | SetWindowTitle(parameters); |
| 126 | SetDialogPurpose(parameters); | ||
| 124 | resize(550, 400); | 127 | resize(550, 400); |
| 125 | } | 128 | } |
| 126 | 129 | ||
| @@ -154,6 +157,76 @@ void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) { | |||
| 154 | user_index = index.row(); | 157 | user_index = index.row(); |
| 155 | } | 158 | } |
| 156 | 159 | ||
| 160 | void QtProfileSelectionDialog::SetWindowTitle( | ||
| 161 | const Core::Frontend::ProfileSelectParameters& parameters) { | ||
| 162 | using Service::AM::Applets::UiMode; | ||
| 163 | switch (parameters.mode) { | ||
| 164 | case UiMode::UserCreator: | ||
| 165 | case UiMode::UserCreatorForStarter: | ||
| 166 | setWindowTitle(tr("Profile Creator")); | ||
| 167 | return; | ||
| 168 | case UiMode::EnsureNetworkServiceAccountAvailable: | ||
| 169 | setWindowTitle(tr("Profile Selector")); | ||
| 170 | return; | ||
| 171 | case UiMode::UserIconEditor: | ||
| 172 | setWindowTitle(tr("Profile Icon Editor")); | ||
| 173 | return; | ||
| 174 | case UiMode::UserNicknameEditor: | ||
| 175 | setWindowTitle(tr("Profile Nickname Editor")); | ||
| 176 | return; | ||
| 177 | case UiMode::NintendoAccountAuthorizationRequestContext: | ||
| 178 | case UiMode::IntroduceExternalNetworkServiceAccount: | ||
| 179 | case UiMode::IntroduceExternalNetworkServiceAccountForRegistration: | ||
| 180 | case UiMode::NintendoAccountNnidLinker: | ||
| 181 | case UiMode::LicenseRequirementsForNetworkService: | ||
| 182 | case UiMode::LicenseRequirementsForNetworkServiceWithUserContextImpl: | ||
| 183 | case UiMode::UserCreatorForImmediateNaLoginTest: | ||
| 184 | case UiMode::UserQualificationPromoter: | ||
| 185 | case UiMode::UserSelector: | ||
| 186 | default: | ||
| 187 | setWindowTitle(tr("Profile Selector")); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | void QtProfileSelectionDialog::SetDialogPurpose( | ||
| 192 | const Core::Frontend::ProfileSelectParameters& parameters) { | ||
| 193 | using Service::AM::Applets::UserSelectionPurpose; | ||
| 194 | |||
| 195 | switch (parameters.purpose) { | ||
| 196 | case UserSelectionPurpose::GameCardRegistration: | ||
| 197 | instruction_label->setText(tr("Who will receive the points?")); | ||
| 198 | return; | ||
| 199 | case UserSelectionPurpose::EShopLaunch: | ||
| 200 | instruction_label->setText(tr("Who is using Nintendo eShop?")); | ||
| 201 | return; | ||
| 202 | case UserSelectionPurpose::EShopItemShow: | ||
| 203 | instruction_label->setText(tr("Who is making this purchase?")); | ||
| 204 | return; | ||
| 205 | case UserSelectionPurpose::PicturePost: | ||
| 206 | instruction_label->setText(tr("Who is posting?")); | ||
| 207 | return; | ||
| 208 | case UserSelectionPurpose::NintendoAccountLinkage: | ||
| 209 | instruction_label->setText(tr("Select a user to link to a Nintendo Account.")); | ||
| 210 | return; | ||
| 211 | case UserSelectionPurpose::SettingsUpdate: | ||
| 212 | instruction_label->setText(tr("Change settings for which user?")); | ||
| 213 | return; | ||
| 214 | case UserSelectionPurpose::SaveDataDeletion: | ||
| 215 | instruction_label->setText(tr("Format data for which user?")); | ||
| 216 | return; | ||
| 217 | case UserSelectionPurpose::UserMigration: | ||
| 218 | instruction_label->setText(tr("Which user will be transferred to another console?")); | ||
| 219 | return; | ||
| 220 | case UserSelectionPurpose::SaveDataTransfer: | ||
| 221 | instruction_label->setText(tr("Send save data for which user?")); | ||
| 222 | return; | ||
| 223 | case UserSelectionPurpose::General: | ||
| 224 | default: | ||
| 225 | instruction_label->setText(tr("Select a user:")); | ||
| 226 | return; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 157 | QtProfileSelector::QtProfileSelector(GMainWindow& parent) { | 230 | QtProfileSelector::QtProfileSelector(GMainWindow& parent) { |
| 158 | connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent, | 231 | connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent, |
| 159 | &GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection); | 232 | &GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection); |
| @@ -170,9 +243,11 @@ void QtProfileSelector::Close() const { | |||
| 170 | emit MainWindowRequestExit(); | 243 | emit MainWindowRequestExit(); |
| 171 | } | 244 | } |
| 172 | 245 | ||
| 173 | void QtProfileSelector::SelectProfile(SelectProfileCallback callback_) const { | 246 | void QtProfileSelector::SelectProfile( |
| 247 | SelectProfileCallback callback_, | ||
| 248 | const Core::Frontend::ProfileSelectParameters& parameters) const { | ||
| 174 | callback = std::move(callback_); | 249 | callback = std::move(callback_); |
| 175 | emit MainWindowSelectProfile(); | 250 | emit MainWindowSelectProfile(parameters); |
| 176 | } | 251 | } |
| 177 | 252 | ||
| 178 | void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) { | 253 | void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) { |
diff --git a/src/yuzu/applets/qt_profile_select.h b/src/yuzu/applets/qt_profile_select.h index 9f214d071..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 { | |||
| 28 | Q_OBJECT | 28 | Q_OBJECT |
| 29 | 29 | ||
| 30 | public: | 30 | public: |
| 31 | explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent); | 31 | explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent, |
| 32 | const Core::Frontend::ProfileSelectParameters& parameters); | ||
| 32 | ~QtProfileSelectionDialog() override; | 33 | ~QtProfileSelectionDialog() override; |
| 33 | 34 | ||
| 34 | int exec() override; | 35 | int exec() override; |
| @@ -40,6 +41,9 @@ public: | |||
| 40 | private: | 41 | private: |
| 41 | void SelectUser(const QModelIndex& index); | 42 | void SelectUser(const QModelIndex& index); |
| 42 | 43 | ||
| 44 | void SetWindowTitle(const Core::Frontend::ProfileSelectParameters& parameters); | ||
| 45 | void SetDialogPurpose(const Core::Frontend::ProfileSelectParameters& parameters); | ||
| 46 | |||
| 43 | int user_index = 0; | 47 | int user_index = 0; |
| 44 | 48 | ||
| 45 | QVBoxLayout* layout; | 49 | QVBoxLayout* layout; |
| @@ -66,10 +70,11 @@ public: | |||
| 66 | ~QtProfileSelector() override; | 70 | ~QtProfileSelector() override; |
| 67 | 71 | ||
| 68 | void Close() const override; | 72 | void Close() const override; |
| 69 | void SelectProfile(SelectProfileCallback callback_) const override; | 73 | void SelectProfile(SelectProfileCallback callback_, |
| 74 | const Core::Frontend::ProfileSelectParameters& parameters) const override; | ||
| 70 | 75 | ||
| 71 | signals: | 76 | signals: |
| 72 | void MainWindowSelectProfile() const; | 77 | void MainWindowSelectProfile(const Core::Frontend::ProfileSelectParameters& parameters) const; |
| 73 | void MainWindowRequestExit() const; | 78 | void MainWindowRequestExit() const; |
| 74 | 79 | ||
| 75 | private: | 80 | private: |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0c60a90cb..b79409a68 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -576,6 +576,10 @@ void GMainWindow::RegisterMetaTypes() { | |||
| 576 | // Controller Applet | 576 | // Controller Applet |
| 577 | qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); | 577 | qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); |
| 578 | 578 | ||
| 579 | // Profile Select Applet | ||
| 580 | qRegisterMetaType<Core::Frontend::ProfileSelectParameters>( | ||
| 581 | "Core::Frontend::ProfileSelectParameters"); | ||
| 582 | |||
| 579 | // Software Keyboard Applet | 583 | // Software Keyboard Applet |
| 580 | qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>( | 584 | qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>( |
| 581 | "Core::Frontend::KeyboardInitializeParameters"); | 585 | "Core::Frontend::KeyboardInitializeParameters"); |
| @@ -634,15 +638,16 @@ void GMainWindow::ControllerSelectorReconfigureControllers( | |||
| 634 | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | | 638 | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | |
| 635 | Qt::WindowSystemMenuHint); | 639 | Qt::WindowSystemMenuHint); |
| 636 | controller_applet->setWindowModality(Qt::WindowModal); | 640 | controller_applet->setWindowModality(Qt::WindowModal); |
| 637 | controller_applet->exec(); | 641 | bool is_success = controller_applet->exec() != QDialog::Rejected; |
| 638 | |||
| 639 | emit ControllerSelectorReconfigureFinished(); | ||
| 640 | 642 | ||
| 641 | // Don't forget to apply settings. | 643 | // Don't forget to apply settings. |
| 644 | system->HIDCore().DisableAllControllerConfiguration(); | ||
| 642 | system->ApplySettings(); | 645 | system->ApplySettings(); |
| 643 | config->Save(); | 646 | config->Save(); |
| 644 | 647 | ||
| 645 | UpdateStatusButtons(); | 648 | UpdateStatusButtons(); |
| 649 | |||
| 650 | emit ControllerSelectorReconfigureFinished(is_success); | ||
| 646 | } | 651 | } |
| 647 | 652 | ||
| 648 | void GMainWindow::ControllerSelectorRequestExit() { | 653 | void GMainWindow::ControllerSelectorRequestExit() { |
| @@ -651,8 +656,9 @@ void GMainWindow::ControllerSelectorRequestExit() { | |||
| 651 | } | 656 | } |
| 652 | } | 657 | } |
| 653 | 658 | ||
| 654 | void GMainWindow::ProfileSelectorSelectProfile() { | 659 | void GMainWindow::ProfileSelectorSelectProfile( |
| 655 | profile_select_applet = new QtProfileSelectionDialog(system->HIDCore(), this); | 660 | const Core::Frontend::ProfileSelectParameters& parameters) { |
| 661 | profile_select_applet = new QtProfileSelectionDialog(system->HIDCore(), this, parameters); | ||
| 656 | SCOPE_EXIT({ | 662 | SCOPE_EXIT({ |
| 657 | profile_select_applet->deleteLater(); | 663 | profile_select_applet->deleteLater(); |
| 658 | profile_select_applet = nullptr; | 664 | profile_select_applet = nullptr; |
| @@ -1719,8 +1725,9 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p | |||
| 1719 | return true; | 1725 | return true; |
| 1720 | } | 1726 | } |
| 1721 | 1727 | ||
| 1722 | bool GMainWindow::SelectAndSetCurrentUser() { | 1728 | bool GMainWindow::SelectAndSetCurrentUser( |
| 1723 | QtProfileSelectionDialog dialog(system->HIDCore(), this); | 1729 | const Core::Frontend::ProfileSelectParameters& parameters) { |
| 1730 | QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); | ||
| 1724 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | | 1731 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | |
| 1725 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | 1732 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); |
| 1726 | dialog.setWindowModality(Qt::WindowModal); | 1733 | dialog.setWindowModality(Qt::WindowModal); |
| @@ -1766,7 +1773,13 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1766 | Settings::LogSettings(); | 1773 | Settings::LogSettings(); |
| 1767 | 1774 | ||
| 1768 | if (UISettings::values.select_user_on_boot) { | 1775 | if (UISettings::values.select_user_on_boot) { |
| 1769 | if (SelectAndSetCurrentUser() == false) { | 1776 | const Core::Frontend::ProfileSelectParameters parameters{ |
| 1777 | .mode = Service::AM::Applets::UiMode::UserSelector, | ||
| 1778 | .invalid_uid_list = {}, | ||
| 1779 | .display_options = {}, | ||
| 1780 | .purpose = Service::AM::Applets::UserSelectionPurpose::General, | ||
| 1781 | }; | ||
| 1782 | if (SelectAndSetCurrentUser(parameters) == false) { | ||
| 1770 | return; | 1783 | return; |
| 1771 | } | 1784 | } |
| 1772 | } | 1785 | } |
| @@ -2058,7 +2071,13 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | |||
| 2058 | if (has_user_save) { | 2071 | if (has_user_save) { |
| 2059 | // User save data | 2072 | // User save data |
| 2060 | const auto select_profile = [this] { | 2073 | const auto select_profile = [this] { |
| 2061 | QtProfileSelectionDialog dialog(system->HIDCore(), this); | 2074 | const Core::Frontend::ProfileSelectParameters parameters{ |
| 2075 | .mode = Service::AM::Applets::UiMode::UserSelector, | ||
| 2076 | .invalid_uid_list = {}, | ||
| 2077 | .display_options = {}, | ||
| 2078 | .purpose = Service::AM::Applets::UserSelectionPurpose::General, | ||
| 2079 | }; | ||
| 2080 | QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); | ||
| 2062 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | | 2081 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | |
| 2063 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | 2082 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); |
| 2064 | dialog.setWindowModality(Qt::WindowModal); | 2083 | dialog.setWindowModality(Qt::WindowModal); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index a99938eaa..8b5c1d747 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -69,6 +69,7 @@ struct ControllerParameters; | |||
| 69 | struct InlineAppearParameters; | 69 | struct InlineAppearParameters; |
| 70 | struct InlineTextParameters; | 70 | struct InlineTextParameters; |
| 71 | struct KeyboardInitializeParameters; | 71 | struct KeyboardInitializeParameters; |
| 72 | struct ProfileSelectParameters; | ||
| 72 | } // namespace Core::Frontend | 73 | } // namespace Core::Frontend |
| 73 | 74 | ||
| 74 | namespace DiscordRPC { | 75 | namespace DiscordRPC { |
| @@ -165,7 +166,7 @@ signals: | |||
| 165 | 166 | ||
| 166 | void AmiiboSettingsFinished(bool is_success, const std::string& name); | 167 | void AmiiboSettingsFinished(bool is_success, const std::string& name); |
| 167 | 168 | ||
| 168 | void ControllerSelectorReconfigureFinished(); | 169 | void ControllerSelectorReconfigureFinished(bool is_success); |
| 169 | 170 | ||
| 170 | void ErrorDisplayFinished(); | 171 | void ErrorDisplayFinished(); |
| 171 | 172 | ||
| @@ -203,7 +204,7 @@ public slots: | |||
| 203 | void SoftwareKeyboardExit(); | 204 | void SoftwareKeyboardExit(); |
| 204 | void ErrorDisplayDisplayError(QString error_code, QString error_text); | 205 | void ErrorDisplayDisplayError(QString error_code, QString error_text); |
| 205 | void ErrorDisplayRequestExit(); | 206 | void ErrorDisplayRequestExit(); |
| 206 | void ProfileSelectorSelectProfile(); | 207 | void ProfileSelectorSelectProfile(const Core::Frontend::ProfileSelectParameters& parameters); |
| 207 | void ProfileSelectorRequestExit(); | 208 | void ProfileSelectorRequestExit(); |
| 208 | void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, | 209 | void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, |
| 209 | bool is_local); | 210 | bool is_local); |
| @@ -242,7 +243,7 @@ private: | |||
| 242 | void SetDiscordEnabled(bool state); | 243 | void SetDiscordEnabled(bool state); |
| 243 | void LoadAmiibo(const QString& filename); | 244 | void LoadAmiibo(const QString& filename); |
| 244 | 245 | ||
| 245 | bool SelectAndSetCurrentUser(); | 246 | bool SelectAndSetCurrentUser(const Core::Frontend::ProfileSelectParameters& parameters); |
| 246 | 247 | ||
| 247 | /** | 248 | /** |
| 248 | * Stores the filename in the recently loaded files list. | 249 | * Stores the filename in the recently loaded files list. |