diff options
Diffstat (limited to 'src')
71 files changed, 987 insertions, 547 deletions
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp index 8619a3f03..fe3a898ad 100644 --- a/src/audio_core/audio_out.cpp +++ b/src/audio_core/audio_out.cpp | |||
| @@ -43,6 +43,10 @@ std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, | |||
| 43 | return stream->GetTagsAndReleaseBuffers(max_count); | 43 | return stream->GetTagsAndReleaseBuffers(max_count); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream) { | ||
| 47 | return stream->GetTagsAndReleaseBuffers(); | ||
| 48 | } | ||
| 49 | |||
| 46 | void AudioOut::StartStream(StreamPtr stream) { | 50 | void AudioOut::StartStream(StreamPtr stream) { |
| 47 | stream->Play(); | 51 | stream->Play(); |
| 48 | } | 52 | } |
diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h index b07588287..6ce08cd0d 100644 --- a/src/audio_core/audio_out.h +++ b/src/audio_core/audio_out.h | |||
| @@ -31,6 +31,9 @@ public: | |||
| 31 | /// Returns a vector of recently released buffers specified by tag for the specified stream | 31 | /// Returns a vector of recently released buffers specified by tag for the specified stream |
| 32 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); | 32 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); |
| 33 | 33 | ||
| 34 | /// Returns a vector of all recently released buffers specified by tag for the specified stream | ||
| 35 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream); | ||
| 36 | |||
| 34 | /// Starts an audio stream for playback | 37 | /// Starts an audio stream for playback |
| 35 | void StartStream(StreamPtr stream); | 38 | void StartStream(StreamPtr stream); |
| 36 | 39 | ||
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index a7e851bb8..e1ded84e0 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <limits> | ||
| 5 | #include <vector> | 6 | #include <vector> |
| 6 | 7 | ||
| 7 | #include "audio_core/audio_out.h" | 8 | #include "audio_core/audio_out.h" |
| @@ -14,6 +15,59 @@ | |||
| 14 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 15 | #include "core/settings.h" | 16 | #include "core/settings.h" |
| 16 | 17 | ||
| 18 | namespace { | ||
| 19 | [[nodiscard]] static constexpr s16 ClampToS16(s32 value) { | ||
| 20 | return static_cast<s16>(std::clamp(value, s32{std::numeric_limits<s16>::min()}, | ||
| 21 | s32{std::numeric_limits<s16>::max()})); | ||
| 22 | } | ||
| 23 | |||
| 24 | [[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) { | ||
| 25 | // Mix 50% from left and 50% from right channel | ||
| 26 | constexpr float l_mix_amount = 50.0f / 100.0f; | ||
| 27 | constexpr float r_mix_amount = 50.0f / 100.0f; | ||
| 28 | return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) + | ||
| 29 | (static_cast<float>(r_channel) * r_mix_amount))); | ||
| 30 | } | ||
| 31 | |||
| 32 | [[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel, | ||
| 33 | s16 fc_channel, | ||
| 34 | [[maybe_unused]] s16 lf_channel, | ||
| 35 | s16 bl_channel, s16 br_channel) { | ||
| 36 | // Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels | ||
| 37 | // are mixed to be 36.94% | ||
| 38 | |||
| 39 | constexpr float front_mix_amount = 36.94f / 100.0f; | ||
| 40 | constexpr float center_mix_amount = 26.12f / 100.0f; | ||
| 41 | constexpr float back_mix_amount = 36.94f / 100.0f; | ||
| 42 | |||
| 43 | // Mix 50% from left and 50% from right channel | ||
| 44 | const auto left = front_mix_amount * static_cast<float>(fl_channel) + | ||
| 45 | center_mix_amount * static_cast<float>(fc_channel) + | ||
| 46 | back_mix_amount * static_cast<float>(bl_channel); | ||
| 47 | |||
| 48 | const auto right = front_mix_amount * static_cast<float>(fr_channel) + | ||
| 49 | center_mix_amount * static_cast<float>(fc_channel) + | ||
| 50 | back_mix_amount * static_cast<float>(br_channel); | ||
| 51 | |||
| 52 | return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))}; | ||
| 53 | } | ||
| 54 | |||
| 55 | [[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients( | ||
| 56 | s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel, | ||
| 57 | const std::array<float_le, 4>& coeff) { | ||
| 58 | const auto left = | ||
| 59 | static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + | ||
| 60 | static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0]; | ||
| 61 | |||
| 62 | const auto right = | ||
| 63 | static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + | ||
| 64 | static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0]; | ||
| 65 | |||
| 66 | return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))}; | ||
| 67 | } | ||
| 68 | |||
| 69 | } // namespace | ||
| 70 | |||
| 17 | namespace AudioCore { | 71 | namespace AudioCore { |
| 18 | AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | 72 | AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, |
| 19 | AudioCommon::AudioRendererParameter params, | 73 | AudioCommon::AudioRendererParameter params, |
| @@ -62,10 +116,6 @@ Stream::State AudioRenderer::GetStreamState() const { | |||
| 62 | return stream->GetState(); | 116 | return stream->GetState(); |
| 63 | } | 117 | } |
| 64 | 118 | ||
| 65 | static constexpr s16 ClampToS16(s32 value) { | ||
| 66 | return static_cast<s16>(std::clamp(value, -32768, 32767)); | ||
| 67 | } | ||
| 68 | |||
| 69 | ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, | 119 | ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, |
| 70 | std::vector<u8>& output_params) { | 120 | std::vector<u8>& output_params) { |
| 71 | 121 | ||
| @@ -104,8 +154,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param | |||
| 104 | } | 154 | } |
| 105 | } | 155 | } |
| 106 | 156 | ||
| 107 | auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, | 157 | const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, |
| 108 | splitter_context, effect_context); | 158 | splitter_context, effect_context); |
| 109 | 159 | ||
| 110 | if (mix_result.IsError()) { | 160 | if (mix_result.IsError()) { |
| 111 | LOG_ERROR(Audio, "Failed to update mix parameters"); | 161 | LOG_ERROR(Audio, "Failed to update mix parameters"); |
| @@ -194,20 +244,22 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||
| 194 | for (std::size_t i = 0; i < BUFFER_SIZE; i++) { | 244 | for (std::size_t i = 0; i < BUFFER_SIZE; i++) { |
| 195 | if (channel_count == 1) { | 245 | if (channel_count == 1) { |
| 196 | const auto sample = ClampToS16(mix_buffers[0][i]); | 246 | const auto sample = ClampToS16(mix_buffers[0][i]); |
| 197 | buffer[i * stream_channel_count + 0] = sample; | 247 | |
| 198 | if (stream_channel_count > 1) { | 248 | // Place sample in all channels |
| 199 | buffer[i * stream_channel_count + 1] = sample; | 249 | for (u32 channel = 0; channel < stream_channel_count; channel++) { |
| 250 | buffer[i * stream_channel_count + channel] = sample; | ||
| 200 | } | 251 | } |
| 252 | |||
| 201 | if (stream_channel_count == 6) { | 253 | if (stream_channel_count == 6) { |
| 202 | buffer[i * stream_channel_count + 2] = sample; | 254 | // Output stream has a LF channel, mute it! |
| 203 | buffer[i * stream_channel_count + 4] = sample; | 255 | buffer[i * stream_channel_count + 3] = 0; |
| 204 | buffer[i * stream_channel_count + 5] = sample; | ||
| 205 | } | 256 | } |
| 257 | |||
| 206 | } else if (channel_count == 2) { | 258 | } else if (channel_count == 2) { |
| 207 | const auto l_sample = ClampToS16(mix_buffers[0][i]); | 259 | const auto l_sample = ClampToS16(mix_buffers[0][i]); |
| 208 | const auto r_sample = ClampToS16(mix_buffers[1][i]); | 260 | const auto r_sample = ClampToS16(mix_buffers[1][i]); |
| 209 | if (stream_channel_count == 1) { | 261 | if (stream_channel_count == 1) { |
| 210 | buffer[i * stream_channel_count + 0] = l_sample; | 262 | buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample); |
| 211 | } else if (stream_channel_count == 2) { | 263 | } else if (stream_channel_count == 2) { |
| 212 | buffer[i * stream_channel_count + 0] = l_sample; | 264 | buffer[i * stream_channel_count + 0] = l_sample; |
| 213 | buffer[i * stream_channel_count + 1] = r_sample; | 265 | buffer[i * stream_channel_count + 1] = r_sample; |
| @@ -215,8 +267,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||
| 215 | buffer[i * stream_channel_count + 0] = l_sample; | 267 | buffer[i * stream_channel_count + 0] = l_sample; |
| 216 | buffer[i * stream_channel_count + 1] = r_sample; | 268 | buffer[i * stream_channel_count + 1] = r_sample; |
| 217 | 269 | ||
| 218 | buffer[i * stream_channel_count + 2] = | 270 | // Combine both left and right channels to the center channel |
| 219 | ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2); | 271 | buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample); |
| 220 | 272 | ||
| 221 | buffer[i * stream_channel_count + 4] = l_sample; | 273 | buffer[i * stream_channel_count + 4] = l_sample; |
| 222 | buffer[i * stream_channel_count + 5] = r_sample; | 274 | buffer[i * stream_channel_count + 5] = r_sample; |
| @@ -231,17 +283,25 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||
| 231 | const auto br_sample = ClampToS16(mix_buffers[5][i]); | 283 | const auto br_sample = ClampToS16(mix_buffers[5][i]); |
| 232 | 284 | ||
| 233 | if (stream_channel_count == 1) { | 285 | if (stream_channel_count == 1) { |
| 234 | buffer[i * stream_channel_count + 0] = fc_sample; | 286 | // Games seem to ignore the center channel half the time, we use the front left |
| 287 | // and right channel for mixing as that's where majority of the audio goes | ||
| 288 | buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample); | ||
| 235 | } else if (stream_channel_count == 2) { | 289 | } else if (stream_channel_count == 2) { |
| 236 | buffer[i * stream_channel_count + 0] = | 290 | // Mix all channels into 2 channels |
| 237 | static_cast<s16>(0.3694f * static_cast<float>(fl_sample) + | 291 | if (sink_context.HasDownMixingCoefficients()) { |
| 238 | 0.2612f * static_cast<float>(fc_sample) + | 292 | const auto [left, right] = Mix6To2WithCoefficients( |
| 239 | 0.3694f * static_cast<float>(bl_sample)); | 293 | fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample, |
| 240 | buffer[i * stream_channel_count + 1] = | 294 | sink_context.GetDownmixCoefficients()); |
| 241 | static_cast<s16>(0.3694f * static_cast<float>(fr_sample) + | 295 | buffer[i * stream_channel_count + 0] = left; |
| 242 | 0.2612f * static_cast<float>(fc_sample) + | 296 | buffer[i * stream_channel_count + 1] = right; |
| 243 | 0.3694f * static_cast<float>(br_sample)); | 297 | } else { |
| 298 | const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample, | ||
| 299 | lf_sample, bl_sample, br_sample); | ||
| 300 | buffer[i * stream_channel_count + 0] = left; | ||
| 301 | buffer[i * stream_channel_count + 1] = right; | ||
| 302 | } | ||
| 244 | } else if (stream_channel_count == 6) { | 303 | } else if (stream_channel_count == 6) { |
| 304 | // Pass through | ||
| 245 | buffer[i * stream_channel_count + 0] = fl_sample; | 305 | buffer[i * stream_channel_count + 0] = fl_sample; |
| 246 | buffer[i * stream_channel_count + 1] = fr_sample; | 306 | buffer[i * stream_channel_count + 1] = fr_sample; |
| 247 | buffer[i * stream_channel_count + 2] = fc_sample; | 307 | buffer[i * stream_channel_count + 2] = fc_sample; |
| @@ -259,7 +319,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||
| 259 | } | 319 | } |
| 260 | 320 | ||
| 261 | void AudioRenderer::ReleaseAndQueueBuffers() { | 321 | void AudioRenderer::ReleaseAndQueueBuffers() { |
| 262 | const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)}; | 322 | const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)}; |
| 263 | for (const auto& tag : released_buffers) { | 323 | for (const auto& tag : released_buffers) { |
| 264 | QueueMixedBuffer(tag); | 324 | QueueMixedBuffer(tag); |
| 265 | } | 325 | } |
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index 2fd93e058..a85219045 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h | |||
| @@ -36,16 +36,10 @@ class Memory; | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | namespace AudioCore { | 38 | namespace AudioCore { |
| 39 | using DSPStateHolder = std::array<VoiceState*, 6>; | 39 | using DSPStateHolder = std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>; |
| 40 | 40 | ||
| 41 | class AudioOut; | 41 | class AudioOut; |
| 42 | 42 | ||
| 43 | struct RendererInfo { | ||
| 44 | u64_le elasped_frame_count{}; | ||
| 45 | INSERT_PADDING_WORDS(2); | ||
| 46 | }; | ||
| 47 | static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size"); | ||
| 48 | |||
| 49 | class AudioRenderer { | 43 | class AudioRenderer { |
| 50 | public: | 44 | public: |
| 51 | AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | 45 | AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, |
| @@ -53,14 +47,14 @@ public: | |||
| 53 | std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); | 47 | std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); |
| 54 | ~AudioRenderer(); | 48 | ~AudioRenderer(); |
| 55 | 49 | ||
| 56 | ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, | 50 | [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, |
| 57 | std::vector<u8>& output_params); | 51 | std::vector<u8>& output_params); |
| 58 | void QueueMixedBuffer(Buffer::Tag tag); | 52 | void QueueMixedBuffer(Buffer::Tag tag); |
| 59 | void ReleaseAndQueueBuffers(); | 53 | void ReleaseAndQueueBuffers(); |
| 60 | u32 GetSampleRate() const; | 54 | [[nodiscard]] u32 GetSampleRate() const; |
| 61 | u32 GetSampleCount() const; | 55 | [[nodiscard]] u32 GetSampleCount() const; |
| 62 | u32 GetMixBufferCount() const; | 56 | [[nodiscard]] u32 GetMixBufferCount() const; |
| 63 | Stream::State GetStreamState() const; | 57 | [[nodiscard]] Stream::State GetStreamState() const; |
| 64 | 58 | ||
| 65 | private: | 59 | private: |
| 66 | BehaviorInfo behavior_info{}; | 60 | BehaviorInfo behavior_info{}; |
diff --git a/src/audio_core/behavior_info.h b/src/audio_core/behavior_info.h index 512a4ebe3..5a96bf75e 100644 --- a/src/audio_core/behavior_info.h +++ b/src/audio_core/behavior_info.h | |||
| @@ -43,22 +43,22 @@ public: | |||
| 43 | void ClearError(); | 43 | void ClearError(); |
| 44 | void UpdateFlags(u64_le dest_flags); | 44 | void UpdateFlags(u64_le dest_flags); |
| 45 | void SetUserRevision(u32_le revision); | 45 | void SetUserRevision(u32_le revision); |
| 46 | u32_le GetUserRevision() const; | 46 | [[nodiscard]] u32_le GetUserRevision() const; |
| 47 | u32_le GetProcessRevision() const; | 47 | [[nodiscard]] u32_le GetProcessRevision() const; |
| 48 | 48 | ||
| 49 | bool IsAdpcmLoopContextBugFixed() const; | 49 | [[nodiscard]] bool IsAdpcmLoopContextBugFixed() const; |
| 50 | bool IsSplitterSupported() const; | 50 | [[nodiscard]] bool IsSplitterSupported() const; |
| 51 | bool IsLongSizePreDelaySupported() const; | 51 | [[nodiscard]] bool IsLongSizePreDelaySupported() const; |
| 52 | bool IsAudioRendererProcessingTimeLimit80PercentSupported() const; | 52 | [[nodiscard]] bool IsAudioRendererProcessingTimeLimit80PercentSupported() const; |
| 53 | bool IsAudioRendererProcessingTimeLimit75PercentSupported() const; | 53 | [[nodiscard]] bool IsAudioRendererProcessingTimeLimit75PercentSupported() const; |
| 54 | bool IsAudioRendererProcessingTimeLimit70PercentSupported() const; | 54 | [[nodiscard]] bool IsAudioRendererProcessingTimeLimit70PercentSupported() const; |
| 55 | bool IsElapsedFrameCountSupported() const; | 55 | [[nodiscard]] bool IsElapsedFrameCountSupported() const; |
| 56 | bool IsMemoryPoolForceMappingEnabled() const; | 56 | [[nodiscard]] bool IsMemoryPoolForceMappingEnabled() const; |
| 57 | bool IsFlushVoiceWaveBuffersSupported() const; | 57 | [[nodiscard]] bool IsFlushVoiceWaveBuffersSupported() const; |
| 58 | bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const; | 58 | [[nodiscard]] bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const; |
| 59 | bool IsVoicePitchAndSrcSkippedSupported() const; | 59 | [[nodiscard]] bool IsVoicePitchAndSrcSkippedSupported() const; |
| 60 | bool IsMixInParameterDirtyOnlyUpdateSupported() const; | 60 | [[nodiscard]] bool IsMixInParameterDirtyOnlyUpdateSupported() const; |
| 61 | bool IsSplitterBugFixed() const; | 61 | [[nodiscard]] bool IsSplitterBugFixed() const; |
| 62 | void CopyErrorInfo(OutParams& dst); | 62 | void CopyErrorInfo(OutParams& dst); |
| 63 | 63 | ||
| 64 | private: | 64 | private: |
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h index 53e57748b..87ece00c4 100644 --- a/src/audio_core/command_generator.h +++ b/src/audio_core/command_generator.h | |||
| @@ -39,13 +39,13 @@ public: | |||
| 39 | void PreCommand(); | 39 | void PreCommand(); |
| 40 | void PostCommand(); | 40 | void PostCommand(); |
| 41 | 41 | ||
| 42 | s32* GetChannelMixBuffer(s32 channel); | 42 | [[nodiscard]] s32* GetChannelMixBuffer(s32 channel); |
| 43 | const s32* GetChannelMixBuffer(s32 channel) const; | 43 | [[nodiscard]] const s32* GetChannelMixBuffer(s32 channel) const; |
| 44 | s32* GetMixBuffer(std::size_t index); | 44 | [[nodiscard]] s32* GetMixBuffer(std::size_t index); |
| 45 | const s32* GetMixBuffer(std::size_t index) const; | 45 | [[nodiscard]] const s32* GetMixBuffer(std::size_t index) const; |
| 46 | std::size_t GetMixChannelBufferOffset(s32 channel) const; | 46 | [[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const; |
| 47 | 47 | ||
| 48 | std::size_t GetTotalMixBufferCount() const; | 48 | [[nodiscard]] std::size_t GetTotalMixBufferCount() const; |
| 49 | 49 | ||
| 50 | private: | 50 | private: |
| 51 | void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); | 51 | void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); |
| @@ -73,7 +73,7 @@ private: | |||
| 73 | void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | 73 | void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |
| 74 | void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | 74 | void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |
| 75 | void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | 75 | void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |
| 76 | ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); | 76 | [[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); |
| 77 | 77 | ||
| 78 | s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, | 78 | s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, |
| 79 | u32 sample_count, u32 write_offset, u32 write_count); | 79 | u32 sample_count, u32 write_offset, u32 write_count); |
diff --git a/src/audio_core/common.h b/src/audio_core/common.h index 7b4a1e9e8..ec59a3ba9 100644 --- a/src/audio_core/common.h +++ b/src/audio_core/common.h | |||
| @@ -22,7 +22,7 @@ constexpr std::size_t MAX_CHANNEL_COUNT = 6; | |||
| 22 | constexpr std::size_t MAX_WAVE_BUFFERS = 4; | 22 | constexpr std::size_t MAX_WAVE_BUFFERS = 4; |
| 23 | constexpr std::size_t MAX_SAMPLE_HISTORY = 4; | 23 | constexpr std::size_t MAX_SAMPLE_HISTORY = 4; |
| 24 | constexpr u32 STREAM_SAMPLE_RATE = 48000; | 24 | constexpr u32 STREAM_SAMPLE_RATE = 48000; |
| 25 | constexpr u32 STREAM_NUM_CHANNELS = 6; | 25 | constexpr u32 STREAM_NUM_CHANNELS = 2; |
| 26 | constexpr s32 NO_SPLITTER = -1; | 26 | constexpr s32 NO_SPLITTER = -1; |
| 27 | constexpr s32 NO_MIX = 0x7fffffff; | 27 | constexpr s32 NO_MIX = 0x7fffffff; |
| 28 | constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); | 28 | constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); |
diff --git a/src/audio_core/effect_context.h b/src/audio_core/effect_context.h index 2c4ce53ef..03c5a0f04 100644 --- a/src/audio_core/effect_context.h +++ b/src/audio_core/effect_context.h | |||
| @@ -189,11 +189,11 @@ public: | |||
| 189 | 189 | ||
| 190 | virtual void Update(EffectInfo::InParams& in_params) = 0; | 190 | virtual void Update(EffectInfo::InParams& in_params) = 0; |
| 191 | virtual void UpdateForCommandGeneration() = 0; | 191 | virtual void UpdateForCommandGeneration() = 0; |
| 192 | UsageState GetUsage() const; | 192 | [[nodiscard]] UsageState GetUsage() const; |
| 193 | EffectType GetType() const; | 193 | [[nodiscard]] EffectType GetType() const; |
| 194 | bool IsEnabled() const; | 194 | [[nodiscard]] bool IsEnabled() const; |
| 195 | s32 GetMixID() const; | 195 | [[nodiscard]] s32 GetMixID() const; |
| 196 | s32 GetProcessingOrder() const; | 196 | [[nodiscard]] s32 GetProcessingOrder() const; |
| 197 | 197 | ||
| 198 | protected: | 198 | protected: |
| 199 | UsageState usage{UsageState::Invalid}; | 199 | UsageState usage{UsageState::Invalid}; |
| @@ -257,10 +257,10 @@ public: | |||
| 257 | 257 | ||
| 258 | void Update(EffectInfo::InParams& in_params) override; | 258 | void Update(EffectInfo::InParams& in_params) override; |
| 259 | void UpdateForCommandGeneration() override; | 259 | void UpdateForCommandGeneration() override; |
| 260 | VAddr GetSendInfo() const; | 260 | [[nodiscard]] VAddr GetSendInfo() const; |
| 261 | VAddr GetSendBuffer() const; | 261 | [[nodiscard]] VAddr GetSendBuffer() const; |
| 262 | VAddr GetRecvInfo() const; | 262 | [[nodiscard]] VAddr GetRecvInfo() const; |
| 263 | VAddr GetRecvBuffer() const; | 263 | [[nodiscard]] VAddr GetRecvBuffer() const; |
| 264 | 264 | ||
| 265 | private: | 265 | private: |
| 266 | VAddr send_info{}; | 266 | VAddr send_info{}; |
| @@ -309,10 +309,10 @@ public: | |||
| 309 | explicit EffectContext(std::size_t effect_count); | 309 | explicit EffectContext(std::size_t effect_count); |
| 310 | ~EffectContext(); | 310 | ~EffectContext(); |
| 311 | 311 | ||
| 312 | std::size_t GetCount() const; | 312 | [[nodiscard]] std::size_t GetCount() const; |
| 313 | EffectBase* GetInfo(std::size_t i); | 313 | [[nodiscard]] EffectBase* GetInfo(std::size_t i); |
| 314 | EffectBase* RetargetEffect(std::size_t i, EffectType effect); | 314 | [[nodiscard]] EffectBase* RetargetEffect(std::size_t i, EffectType effect); |
| 315 | const EffectBase* GetInfo(std::size_t i) const; | 315 | [[nodiscard]] const EffectBase* GetInfo(std::size_t i) const; |
| 316 | 316 | ||
| 317 | private: | 317 | private: |
| 318 | std::size_t effect_count{}; | 318 | std::size_t effect_count{}; |
diff --git a/src/audio_core/mix_context.h b/src/audio_core/mix_context.h index 6a588eeb4..68bc673c6 100644 --- a/src/audio_core/mix_context.h +++ b/src/audio_core/mix_context.h | |||
| @@ -62,17 +62,17 @@ public: | |||
| 62 | ServerMixInfo(); | 62 | ServerMixInfo(); |
| 63 | ~ServerMixInfo(); | 63 | ~ServerMixInfo(); |
| 64 | 64 | ||
| 65 | const ServerMixInfo::InParams& GetInParams() const; | 65 | [[nodiscard]] const ServerMixInfo::InParams& GetInParams() const; |
| 66 | ServerMixInfo::InParams& GetInParams(); | 66 | [[nodiscard]] ServerMixInfo::InParams& GetInParams(); |
| 67 | 67 | ||
| 68 | bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, | 68 | bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, |
| 69 | BehaviorInfo& behavior_info, SplitterContext& splitter_context, | 69 | BehaviorInfo& behavior_info, SplitterContext& splitter_context, |
| 70 | EffectContext& effect_context); | 70 | EffectContext& effect_context); |
| 71 | bool HasAnyConnection() const; | 71 | [[nodiscard]] bool HasAnyConnection() const; |
| 72 | void Cleanup(); | 72 | void Cleanup(); |
| 73 | void SetEffectCount(std::size_t count); | 73 | void SetEffectCount(std::size_t count); |
| 74 | void ResetEffectProcessingOrder(); | 74 | void ResetEffectProcessingOrder(); |
| 75 | s32 GetEffectOrder(std::size_t i) const; | 75 | [[nodiscard]] s32 GetEffectOrder(std::size_t i) const; |
| 76 | 76 | ||
| 77 | private: | 77 | private: |
| 78 | std::vector<s32> effect_processing_order; | 78 | std::vector<s32> effect_processing_order; |
| @@ -91,15 +91,15 @@ public: | |||
| 91 | void SortInfo(); | 91 | void SortInfo(); |
| 92 | bool TsortInfo(SplitterContext& splitter_context); | 92 | bool TsortInfo(SplitterContext& splitter_context); |
| 93 | 93 | ||
| 94 | std::size_t GetCount() const; | 94 | [[nodiscard]] std::size_t GetCount() const; |
| 95 | ServerMixInfo& GetInfo(std::size_t i); | 95 | [[nodiscard]] ServerMixInfo& GetInfo(std::size_t i); |
| 96 | const ServerMixInfo& GetInfo(std::size_t i) const; | 96 | [[nodiscard]] const ServerMixInfo& GetInfo(std::size_t i) const; |
| 97 | ServerMixInfo& GetSortedInfo(std::size_t i); | 97 | [[nodiscard]] ServerMixInfo& GetSortedInfo(std::size_t i); |
| 98 | const ServerMixInfo& GetSortedInfo(std::size_t i) const; | 98 | [[nodiscard]] const ServerMixInfo& GetSortedInfo(std::size_t i) const; |
| 99 | ServerMixInfo& GetFinalMixInfo(); | 99 | [[nodiscard]] ServerMixInfo& GetFinalMixInfo(); |
| 100 | const ServerMixInfo& GetFinalMixInfo() const; | 100 | [[nodiscard]] const ServerMixInfo& GetFinalMixInfo() const; |
| 101 | EdgeMatrix& GetEdgeMatrix(); | 101 | [[nodiscard]] EdgeMatrix& GetEdgeMatrix(); |
| 102 | const EdgeMatrix& GetEdgeMatrix() const; | 102 | [[nodiscard]] const EdgeMatrix& GetEdgeMatrix() const; |
| 103 | 103 | ||
| 104 | private: | 104 | private: |
| 105 | void CalcMixBufferOffset(); | 105 | void CalcMixBufferOffset(); |
diff --git a/src/audio_core/sink_context.cpp b/src/audio_core/sink_context.cpp index 0882b411a..b29b47890 100644 --- a/src/audio_core/sink_context.cpp +++ b/src/audio_core/sink_context.cpp | |||
| @@ -12,10 +12,16 @@ std::size_t SinkContext::GetCount() const { | |||
| 12 | return sink_count; | 12 | return sink_count; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | void SinkContext::UpdateMainSink(SinkInfo::InParams& in) { | 15 | void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) { |
| 16 | ASSERT(in.type == SinkTypes::Device); | ||
| 17 | |||
| 18 | has_downmix_coefs = in.device.down_matrix_enabled; | ||
| 19 | if (has_downmix_coefs) { | ||
| 20 | downmix_coefficients = in.device.down_matrix_coef; | ||
| 21 | } | ||
| 16 | in_use = in.in_use; | 22 | in_use = in.in_use; |
| 17 | use_count = in.device.input_count; | 23 | use_count = in.device.input_count; |
| 18 | std::memcpy(buffers.data(), in.device.input.data(), AudioCommon::MAX_CHANNEL_COUNT); | 24 | buffers = in.device.input; |
| 19 | } | 25 | } |
| 20 | 26 | ||
| 21 | bool SinkContext::InUse() const { | 27 | bool SinkContext::InUse() const { |
| @@ -28,4 +34,12 @@ std::vector<u8> SinkContext::OutputBuffers() const { | |||
| 28 | return buffer_ret; | 34 | return buffer_ret; |
| 29 | } | 35 | } |
| 30 | 36 | ||
| 37 | bool SinkContext::HasDownMixingCoefficients() const { | ||
| 38 | return has_downmix_coefs; | ||
| 39 | } | ||
| 40 | |||
| 41 | const DownmixCoefficients& SinkContext::GetDownmixCoefficients() const { | ||
| 42 | return downmix_coefficients; | ||
| 43 | } | ||
| 44 | |||
| 31 | } // namespace AudioCore | 45 | } // namespace AudioCore |
diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h index d7aa72ba7..e2e7880b7 100644 --- a/src/audio_core/sink_context.h +++ b/src/audio_core/sink_context.h | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | 11 | ||
| 12 | namespace AudioCore { | 12 | namespace AudioCore { |
| 13 | 13 | ||
| 14 | using DownmixCoefficients = std::array<float_le, 4>; | ||
| 15 | |||
| 14 | enum class SinkTypes : u8 { | 16 | enum class SinkTypes : u8 { |
| 15 | Invalid = 0, | 17 | Invalid = 0, |
| 16 | Device = 1, | 18 | Device = 1, |
| @@ -50,7 +52,7 @@ public: | |||
| 50 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; | 52 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; |
| 51 | INSERT_UNION_PADDING_BYTES(1); | 53 | INSERT_UNION_PADDING_BYTES(1); |
| 52 | bool down_matrix_enabled; | 54 | bool down_matrix_enabled; |
| 53 | std::array<float_le, 4> down_matrix_coef; | 55 | DownmixCoefficients down_matrix_coef; |
| 54 | }; | 56 | }; |
| 55 | static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); | 57 | static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); |
| 56 | 58 | ||
| @@ -74,16 +76,21 @@ public: | |||
| 74 | explicit SinkContext(std::size_t sink_count); | 76 | explicit SinkContext(std::size_t sink_count); |
| 75 | ~SinkContext(); | 77 | ~SinkContext(); |
| 76 | 78 | ||
| 77 | std::size_t GetCount() const; | 79 | [[nodiscard]] std::size_t GetCount() const; |
| 80 | |||
| 81 | void UpdateMainSink(const SinkInfo::InParams& in); | ||
| 82 | [[nodiscard]] bool InUse() const; | ||
| 83 | [[nodiscard]] std::vector<u8> OutputBuffers() const; | ||
| 78 | 84 | ||
| 79 | void UpdateMainSink(SinkInfo::InParams& in); | 85 | [[nodiscard]] bool HasDownMixingCoefficients() const; |
| 80 | bool InUse() const; | 86 | [[nodiscard]] const DownmixCoefficients& GetDownmixCoefficients() const; |
| 81 | std::vector<u8> OutputBuffers() const; | ||
| 82 | 87 | ||
| 83 | private: | 88 | private: |
| 84 | bool in_use{false}; | 89 | bool in_use{false}; |
| 85 | s32 use_count{}; | 90 | s32 use_count{}; |
| 86 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; | 91 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; |
| 87 | std::size_t sink_count{}; | 92 | std::size_t sink_count{}; |
| 93 | bool has_downmix_coefs{false}; | ||
| 94 | DownmixCoefficients downmix_coefficients{}; | ||
| 88 | }; | 95 | }; |
| 89 | } // namespace AudioCore | 96 | } // namespace AudioCore |
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 4bbb1e0c4..41bc2f4d6 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -136,4 +136,14 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count) | |||
| 136 | return tags; | 136 | return tags; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() { | ||
| 140 | std::vector<Buffer::Tag> tags; | ||
| 141 | tags.reserve(released_buffers.size()); | ||
| 142 | while (!released_buffers.empty()) { | ||
| 143 | tags.push_back(released_buffers.front()->GetTag()); | ||
| 144 | released_buffers.pop(); | ||
| 145 | } | ||
| 146 | return tags; | ||
| 147 | } | ||
| 148 | |||
| 139 | } // namespace AudioCore | 149 | } // namespace AudioCore |
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 6437b8591..71c2d0b4f 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h | |||
| @@ -57,37 +57,40 @@ public: | |||
| 57 | bool QueueBuffer(BufferPtr&& buffer); | 57 | bool QueueBuffer(BufferPtr&& buffer); |
| 58 | 58 | ||
| 59 | /// Returns true if the audio stream contains a buffer with the specified tag | 59 | /// Returns true if the audio stream contains a buffer with the specified tag |
| 60 | bool ContainsBuffer(Buffer::Tag tag) const; | 60 | [[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const; |
| 61 | 61 | ||
| 62 | /// Returns a vector of recently released buffers specified by tag | 62 | /// Returns a vector of recently released buffers specified by tag |
| 63 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count); | 63 | [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count); |
| 64 | |||
| 65 | /// Returns a vector of all recently released buffers specified by tag | ||
| 66 | [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(); | ||
| 64 | 67 | ||
| 65 | void SetVolume(float volume); | 68 | void SetVolume(float volume); |
| 66 | 69 | ||
| 67 | float GetVolume() const { | 70 | [[nodiscard]] float GetVolume() const { |
| 68 | return game_volume; | 71 | return game_volume; |
| 69 | } | 72 | } |
| 70 | 73 | ||
| 71 | /// Returns true if the stream is currently playing | 74 | /// Returns true if the stream is currently playing |
| 72 | bool IsPlaying() const { | 75 | [[nodiscard]] bool IsPlaying() const { |
| 73 | return state == State::Playing; | 76 | return state == State::Playing; |
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | /// Returns the number of queued buffers | 79 | /// Returns the number of queued buffers |
| 77 | std::size_t GetQueueSize() const { | 80 | [[nodiscard]] std::size_t GetQueueSize() const { |
| 78 | return queued_buffers.size(); | 81 | return queued_buffers.size(); |
| 79 | } | 82 | } |
| 80 | 83 | ||
| 81 | /// Gets the sample rate | 84 | /// Gets the sample rate |
| 82 | u32 GetSampleRate() const { | 85 | [[nodiscard]] u32 GetSampleRate() const { |
| 83 | return sample_rate; | 86 | return sample_rate; |
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | /// Gets the number of channels | 89 | /// Gets the number of channels |
| 87 | u32 GetNumChannels() const; | 90 | [[nodiscard]] u32 GetNumChannels() const; |
| 88 | 91 | ||
| 89 | /// Get the state | 92 | /// Get the state |
| 90 | State GetState() const; | 93 | [[nodiscard]] State GetState() const; |
| 91 | 94 | ||
| 92 | private: | 95 | private: |
| 93 | /// Plays the next queued buffer in the audio stream, starting playback if necessary | 96 | /// Plays the next queued buffer in the audio stream, starting playback if necessary |
| @@ -97,7 +100,7 @@ private: | |||
| 97 | void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); | 100 | void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); |
| 98 | 101 | ||
| 99 | /// Gets the number of core cycles when the specified buffer will be released | 102 | /// Gets the number of core cycles when the specified buffer will be released |
| 100 | std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; | 103 | [[nodiscard]] std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; |
| 101 | 104 | ||
| 102 | u32 sample_rate; ///< Sample rate of the stream | 105 | u32 sample_rate; ///< Sample rate of the stream |
| 103 | Format format; ///< Format of the stream | 106 | Format format; ///< Format of the stream |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 9253e05b7..7ca3652af 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -145,7 +145,7 @@ struct System::Impl { | |||
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { | 147 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 148 | LOG_DEBUG(HW_Memory, "initialized OK"); | 148 | LOG_DEBUG(Core, "initialized OK"); |
| 149 | 149 | ||
| 150 | device_memory = std::make_unique<Core::DeviceMemory>(); | 150 | device_memory = std::make_unique<Core::DeviceMemory>(); |
| 151 | 151 | ||
| @@ -187,7 +187,7 @@ struct System::Impl { | |||
| 187 | 187 | ||
| 188 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); | 188 | service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); |
| 189 | 189 | ||
| 190 | Service::Init(service_manager, system); | 190 | services = std::make_unique<Service::Services>(service_manager, system); |
| 191 | GDBStub::DeferStart(); | 191 | GDBStub::DeferStart(); |
| 192 | 192 | ||
| 193 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); | 193 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); |
| @@ -208,9 +208,11 @@ struct System::Impl { | |||
| 208 | return ResultStatus::Success; | 208 | return ResultStatus::Success; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, | 211 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 212 | const std::string& filepath) { | 212 | std::size_t program_index) { |
| 213 | app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath)); | 213 | app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), |
| 214 | program_index); | ||
| 215 | |||
| 214 | if (!app_loader) { | 216 | if (!app_loader) { |
| 215 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); | 217 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |
| 216 | return ResultStatus::ErrorGetLoader; | 218 | return ResultStatus::ErrorGetLoader; |
| @@ -296,7 +298,7 @@ struct System::Impl { | |||
| 296 | 298 | ||
| 297 | // Shutdown emulation session | 299 | // Shutdown emulation session |
| 298 | GDBStub::Shutdown(); | 300 | GDBStub::Shutdown(); |
| 299 | Service::Shutdown(); | 301 | services.reset(); |
| 300 | service_manager.reset(); | 302 | service_manager.reset(); |
| 301 | cheat_engine.reset(); | 303 | cheat_engine.reset(); |
| 302 | telemetry_session.reset(); | 304 | telemetry_session.reset(); |
| @@ -306,8 +308,8 @@ struct System::Impl { | |||
| 306 | cpu_manager.Shutdown(); | 308 | cpu_manager.Shutdown(); |
| 307 | 309 | ||
| 308 | // Shutdown kernel and core timing | 310 | // Shutdown kernel and core timing |
| 309 | kernel.Shutdown(); | ||
| 310 | core_timing.Shutdown(); | 311 | core_timing.Shutdown(); |
| 312 | kernel.Shutdown(); | ||
| 311 | 313 | ||
| 312 | // Close app loader | 314 | // Close app loader |
| 313 | app_loader.reset(); | 315 | app_loader.reset(); |
| @@ -398,6 +400,9 @@ struct System::Impl { | |||
| 398 | /// Service manager | 400 | /// Service manager |
| 399 | std::shared_ptr<Service::SM::ServiceManager> service_manager; | 401 | std::shared_ptr<Service::SM::ServiceManager> service_manager; |
| 400 | 402 | ||
| 403 | /// Services | ||
| 404 | std::unique_ptr<Service::Services> services; | ||
| 405 | |||
| 401 | /// Telemetry session for this emulation session | 406 | /// Telemetry session for this emulation session |
| 402 | std::unique_ptr<Core::TelemetrySession> telemetry_session; | 407 | std::unique_ptr<Core::TelemetrySession> telemetry_session; |
| 403 | 408 | ||
| @@ -413,6 +418,8 @@ struct System::Impl { | |||
| 413 | bool is_multicore{}; | 418 | bool is_multicore{}; |
| 414 | bool is_async_gpu{}; | 419 | bool is_async_gpu{}; |
| 415 | 420 | ||
| 421 | ExecuteProgramCallback execute_program_callback; | ||
| 422 | |||
| 416 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; | 423 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; |
| 417 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; | 424 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; |
| 418 | }; | 425 | }; |
| @@ -444,8 +451,13 @@ void System::InvalidateCpuInstructionCaches() { | |||
| 444 | impl->kernel.InvalidateAllInstructionCaches(); | 451 | impl->kernel.InvalidateAllInstructionCaches(); |
| 445 | } | 452 | } |
| 446 | 453 | ||
| 447 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 454 | void System::Shutdown() { |
| 448 | return impl->Load(*this, emu_window, filepath); | 455 | impl->Shutdown(); |
| 456 | } | ||
| 457 | |||
| 458 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, | ||
| 459 | std::size_t program_index) { | ||
| 460 | return impl->Load(*this, emu_window, filepath, program_index); | ||
| 449 | } | 461 | } |
| 450 | 462 | ||
| 451 | bool System::IsPoweredOn() const { | 463 | bool System::IsPoweredOn() const { |
| @@ -632,7 +644,11 @@ const std::string& System::GetStatusDetails() const { | |||
| 632 | return impl->status_details; | 644 | return impl->status_details; |
| 633 | } | 645 | } |
| 634 | 646 | ||
| 635 | Loader::AppLoader& System::GetAppLoader() const { | 647 | Loader::AppLoader& System::GetAppLoader() { |
| 648 | return *impl->app_loader; | ||
| 649 | } | ||
| 650 | |||
| 651 | const Loader::AppLoader& System::GetAppLoader() const { | ||
| 636 | return *impl->app_loader; | 652 | return *impl->app_loader; |
| 637 | } | 653 | } |
| 638 | 654 | ||
| @@ -748,14 +764,6 @@ const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const { | |||
| 748 | return impl->build_id; | 764 | return impl->build_id; |
| 749 | } | 765 | } |
| 750 | 766 | ||
| 751 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | ||
| 752 | return impl->Init(*this, emu_window); | ||
| 753 | } | ||
| 754 | |||
| 755 | void System::Shutdown() { | ||
| 756 | impl->Shutdown(); | ||
| 757 | } | ||
| 758 | |||
| 759 | Service::SM::ServiceManager& System::ServiceManager() { | 767 | Service::SM::ServiceManager& System::ServiceManager() { |
| 760 | return *impl->service_manager; | 768 | return *impl->service_manager; |
| 761 | } | 769 | } |
| @@ -786,4 +794,16 @@ bool System::IsMulticore() const { | |||
| 786 | return impl->is_multicore; | 794 | return impl->is_multicore; |
| 787 | } | 795 | } |
| 788 | 796 | ||
| 797 | void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) { | ||
| 798 | impl->execute_program_callback = std::move(callback); | ||
| 799 | } | ||
| 800 | |||
| 801 | void System::ExecuteProgram(std::size_t program_index) { | ||
| 802 | if (impl->execute_program_callback) { | ||
| 803 | impl->execute_program_callback(program_index); | ||
| 804 | } else { | ||
| 805 | LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend"); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 789 | } // namespace Core | 809 | } // namespace Core |
diff --git a/src/core/core.h b/src/core/core.h index 6db896bae..f642befc0 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <functional> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <string> | 10 | #include <string> |
| 10 | #include <vector> | 11 | #include <vector> |
| @@ -144,19 +145,19 @@ public: | |||
| 144 | * Run the OS and Application | 145 | * Run the OS and Application |
| 145 | * This function will start emulation and run the relevant devices | 146 | * This function will start emulation and run the relevant devices |
| 146 | */ | 147 | */ |
| 147 | ResultStatus Run(); | 148 | [[nodiscard]] ResultStatus Run(); |
| 148 | 149 | ||
| 149 | /** | 150 | /** |
| 150 | * Pause the OS and Application | 151 | * Pause the OS and Application |
| 151 | * This function will pause emulation and stop the relevant devices | 152 | * This function will pause emulation and stop the relevant devices |
| 152 | */ | 153 | */ |
| 153 | ResultStatus Pause(); | 154 | [[nodiscard]] ResultStatus Pause(); |
| 154 | 155 | ||
| 155 | /** | 156 | /** |
| 156 | * Step the CPU one instruction | 157 | * Step the CPU one instruction |
| 157 | * @return Result status, indicating whether or not the operation succeeded. | 158 | * @return Result status, indicating whether or not the operation succeeded. |
| 158 | */ | 159 | */ |
| 159 | ResultStatus SingleStep(); | 160 | [[nodiscard]] ResultStatus SingleStep(); |
| 160 | 161 | ||
| 161 | /** | 162 | /** |
| 162 | * Invalidate the CPU instruction caches | 163 | * Invalidate the CPU instruction caches |
| @@ -173,22 +174,24 @@ public: | |||
| 173 | * @param emu_window Reference to the host-system window used for video output and keyboard | 174 | * @param emu_window Reference to the host-system window used for video output and keyboard |
| 174 | * input. | 175 | * input. |
| 175 | * @param filepath String path to the executable application to load on the host file system. | 176 | * @param filepath String path to the executable application to load on the host file system. |
| 177 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 176 | * @returns ResultStatus code, indicating if the operation succeeded. | 178 | * @returns ResultStatus code, indicating if the operation succeeded. |
| 177 | */ | 179 | */ |
| 178 | ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath); | 180 | [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 181 | std::size_t program_index = 0); | ||
| 179 | 182 | ||
| 180 | /** | 183 | /** |
| 181 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an | 184 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an |
| 182 | * application). | 185 | * application). |
| 183 | * @returns True if the emulated system is powered on, otherwise false. | 186 | * @returns True if the emulated system is powered on, otherwise false. |
| 184 | */ | 187 | */ |
| 185 | bool IsPoweredOn() const; | 188 | [[nodiscard]] bool IsPoweredOn() const; |
| 186 | 189 | ||
| 187 | /// Gets a reference to the telemetry session for this emulation session. | 190 | /// Gets a reference to the telemetry session for this emulation session. |
| 188 | Core::TelemetrySession& TelemetrySession(); | 191 | [[nodiscard]] Core::TelemetrySession& TelemetrySession(); |
| 189 | 192 | ||
| 190 | /// Gets a reference to the telemetry session for this emulation session. | 193 | /// Gets a reference to the telemetry session for this emulation session. |
| 191 | const Core::TelemetrySession& TelemetrySession() const; | 194 | [[nodiscard]] const Core::TelemetrySession& TelemetrySession() const; |
| 192 | 195 | ||
| 193 | /// Prepare the core emulation for a reschedule | 196 | /// Prepare the core emulation for a reschedule |
| 194 | void PrepareReschedule(); | 197 | void PrepareReschedule(); |
| @@ -197,185 +200,178 @@ public: | |||
| 197 | void PrepareReschedule(u32 core_index); | 200 | void PrepareReschedule(u32 core_index); |
| 198 | 201 | ||
| 199 | /// Gets and resets core performance statistics | 202 | /// Gets and resets core performance statistics |
| 200 | PerfStatsResults GetAndResetPerfStats(); | 203 | [[nodiscard]] PerfStatsResults GetAndResetPerfStats(); |
| 201 | 204 | ||
| 202 | /// Gets an ARM interface to the CPU core that is currently running | 205 | /// Gets an ARM interface to the CPU core that is currently running |
| 203 | ARM_Interface& CurrentArmInterface(); | 206 | [[nodiscard]] ARM_Interface& CurrentArmInterface(); |
| 204 | 207 | ||
| 205 | /// Gets an ARM interface to the CPU core that is currently running | 208 | /// Gets an ARM interface to the CPU core that is currently running |
| 206 | const ARM_Interface& CurrentArmInterface() const; | 209 | [[nodiscard]] const ARM_Interface& CurrentArmInterface() const; |
| 207 | 210 | ||
| 208 | /// Gets the index of the currently running CPU core | 211 | /// Gets the index of the currently running CPU core |
| 209 | std::size_t CurrentCoreIndex() const; | 212 | [[nodiscard]] std::size_t CurrentCoreIndex() const; |
| 210 | 213 | ||
| 211 | /// Gets the scheduler for the CPU core that is currently running | 214 | /// Gets the scheduler for the CPU core that is currently running |
| 212 | Kernel::Scheduler& CurrentScheduler(); | 215 | [[nodiscard]] Kernel::Scheduler& CurrentScheduler(); |
| 213 | 216 | ||
| 214 | /// Gets the scheduler for the CPU core that is currently running | 217 | /// Gets the scheduler for the CPU core that is currently running |
| 215 | const Kernel::Scheduler& CurrentScheduler() const; | 218 | [[nodiscard]] const Kernel::Scheduler& CurrentScheduler() const; |
| 216 | 219 | ||
| 217 | /// Gets the physical core for the CPU core that is currently running | 220 | /// Gets the physical core for the CPU core that is currently running |
| 218 | Kernel::PhysicalCore& CurrentPhysicalCore(); | 221 | [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); |
| 219 | 222 | ||
| 220 | /// Gets the physical core for the CPU core that is currently running | 223 | /// Gets the physical core for the CPU core that is currently running |
| 221 | const Kernel::PhysicalCore& CurrentPhysicalCore() const; | 224 | [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const; |
| 222 | 225 | ||
| 223 | /// Gets a reference to an ARM interface for the CPU core with the specified index | 226 | /// Gets a reference to an ARM interface for the CPU core with the specified index |
| 224 | ARM_Interface& ArmInterface(std::size_t core_index); | 227 | [[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index); |
| 225 | 228 | ||
| 226 | /// Gets a const reference to an ARM interface from the CPU core with the specified index | 229 | /// Gets a const reference to an ARM interface from the CPU core with the specified index |
| 227 | const ARM_Interface& ArmInterface(std::size_t core_index) const; | 230 | [[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const; |
| 228 | 231 | ||
| 229 | CpuManager& GetCpuManager(); | 232 | /// Gets a reference to the underlying CPU manager. |
| 233 | [[nodiscard]] CpuManager& GetCpuManager(); | ||
| 230 | 234 | ||
| 231 | const CpuManager& GetCpuManager() const; | 235 | /// Gets a const reference to the underlying CPU manager |
| 236 | [[nodiscard]] const CpuManager& GetCpuManager() const; | ||
| 232 | 237 | ||
| 233 | /// Gets a reference to the exclusive monitor | 238 | /// Gets a reference to the exclusive monitor |
| 234 | ExclusiveMonitor& Monitor(); | 239 | [[nodiscard]] ExclusiveMonitor& Monitor(); |
| 235 | 240 | ||
| 236 | /// Gets a constant reference to the exclusive monitor | 241 | /// Gets a constant reference to the exclusive monitor |
| 237 | const ExclusiveMonitor& Monitor() const; | 242 | [[nodiscard]] const ExclusiveMonitor& Monitor() const; |
| 238 | 243 | ||
| 239 | /// Gets a mutable reference to the system memory instance. | 244 | /// Gets a mutable reference to the system memory instance. |
| 240 | Core::Memory::Memory& Memory(); | 245 | [[nodiscard]] Core::Memory::Memory& Memory(); |
| 241 | 246 | ||
| 242 | /// Gets a constant reference to the system memory instance. | 247 | /// Gets a constant reference to the system memory instance. |
| 243 | const Core::Memory::Memory& Memory() const; | 248 | [[nodiscard]] const Core::Memory::Memory& Memory() const; |
| 244 | 249 | ||
| 245 | /// Gets a mutable reference to the GPU interface | 250 | /// Gets a mutable reference to the GPU interface |
| 246 | Tegra::GPU& GPU(); | 251 | [[nodiscard]] Tegra::GPU& GPU(); |
| 247 | 252 | ||
| 248 | /// Gets an immutable reference to the GPU interface. | 253 | /// Gets an immutable reference to the GPU interface. |
| 249 | const Tegra::GPU& GPU() const; | 254 | [[nodiscard]] const Tegra::GPU& GPU() const; |
| 250 | 255 | ||
| 251 | /// Gets a mutable reference to the renderer. | 256 | /// Gets a mutable reference to the renderer. |
| 252 | VideoCore::RendererBase& Renderer(); | 257 | [[nodiscard]] VideoCore::RendererBase& Renderer(); |
| 253 | 258 | ||
| 254 | /// Gets an immutable reference to the renderer. | 259 | /// Gets an immutable reference to the renderer. |
| 255 | const VideoCore::RendererBase& Renderer() const; | 260 | [[nodiscard]] const VideoCore::RendererBase& Renderer() const; |
| 256 | 261 | ||
| 257 | /// Gets the scheduler for the CPU core with the specified index | 262 | /// Gets the scheduler for the CPU core with the specified index |
| 258 | Kernel::Scheduler& Scheduler(std::size_t core_index); | 263 | [[nodiscard]] Kernel::Scheduler& Scheduler(std::size_t core_index); |
| 259 | 264 | ||
| 260 | /// Gets the scheduler for the CPU core with the specified index | 265 | /// Gets the scheduler for the CPU core with the specified index |
| 261 | const Kernel::Scheduler& Scheduler(std::size_t core_index) const; | 266 | [[nodiscard]] const Kernel::Scheduler& Scheduler(std::size_t core_index) const; |
| 262 | 267 | ||
| 263 | /// Gets the global scheduler | 268 | /// Gets the global scheduler |
| 264 | Kernel::GlobalScheduler& GlobalScheduler(); | 269 | [[nodiscard]] Kernel::GlobalScheduler& GlobalScheduler(); |
| 265 | 270 | ||
| 266 | /// Gets the global scheduler | 271 | /// Gets the global scheduler |
| 267 | const Kernel::GlobalScheduler& GlobalScheduler() const; | 272 | [[nodiscard]] const Kernel::GlobalScheduler& GlobalScheduler() const; |
| 268 | 273 | ||
| 269 | /// Gets the manager for the guest device memory | 274 | /// Gets the manager for the guest device memory |
| 270 | Core::DeviceMemory& DeviceMemory(); | 275 | [[nodiscard]] Core::DeviceMemory& DeviceMemory(); |
| 271 | 276 | ||
| 272 | /// Gets the manager for the guest device memory | 277 | /// Gets the manager for the guest device memory |
| 273 | const Core::DeviceMemory& DeviceMemory() const; | 278 | [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const; |
| 274 | 279 | ||
| 275 | /// Provides a pointer to the current process | 280 | /// Provides a pointer to the current process |
| 276 | Kernel::Process* CurrentProcess(); | 281 | [[nodiscard]] Kernel::Process* CurrentProcess(); |
| 277 | 282 | ||
| 278 | /// Provides a constant pointer to the current process. | 283 | /// Provides a constant pointer to the current process. |
| 279 | const Kernel::Process* CurrentProcess() const; | 284 | [[nodiscard]] const Kernel::Process* CurrentProcess() const; |
| 280 | 285 | ||
| 281 | /// Provides a reference to the core timing instance. | 286 | /// Provides a reference to the core timing instance. |
| 282 | Timing::CoreTiming& CoreTiming(); | 287 | [[nodiscard]] Timing::CoreTiming& CoreTiming(); |
| 283 | 288 | ||
| 284 | /// Provides a constant reference to the core timing instance. | 289 | /// Provides a constant reference to the core timing instance. |
| 285 | const Timing::CoreTiming& CoreTiming() const; | 290 | [[nodiscard]] const Timing::CoreTiming& CoreTiming() const; |
| 286 | 291 | ||
| 287 | /// Provides a reference to the interrupt manager instance. | 292 | /// Provides a reference to the interrupt manager instance. |
| 288 | Core::Hardware::InterruptManager& InterruptManager(); | 293 | [[nodiscard]] Core::Hardware::InterruptManager& InterruptManager(); |
| 289 | 294 | ||
| 290 | /// Provides a constant reference to the interrupt manager instance. | 295 | /// Provides a constant reference to the interrupt manager instance. |
| 291 | const Core::Hardware::InterruptManager& InterruptManager() const; | 296 | [[nodiscard]] const Core::Hardware::InterruptManager& InterruptManager() const; |
| 292 | 297 | ||
| 293 | /// Provides a reference to the kernel instance. | 298 | /// Provides a reference to the kernel instance. |
| 294 | Kernel::KernelCore& Kernel(); | 299 | [[nodiscard]] Kernel::KernelCore& Kernel(); |
| 295 | 300 | ||
| 296 | /// Provides a constant reference to the kernel instance. | 301 | /// Provides a constant reference to the kernel instance. |
| 297 | const Kernel::KernelCore& Kernel() const; | 302 | [[nodiscard]] const Kernel::KernelCore& Kernel() const; |
| 298 | 303 | ||
| 299 | /// Provides a reference to the internal PerfStats instance. | 304 | /// Provides a reference to the internal PerfStats instance. |
| 300 | Core::PerfStats& GetPerfStats(); | 305 | [[nodiscard]] Core::PerfStats& GetPerfStats(); |
| 301 | 306 | ||
| 302 | /// Provides a constant reference to the internal PerfStats instance. | 307 | /// Provides a constant reference to the internal PerfStats instance. |
| 303 | const Core::PerfStats& GetPerfStats() const; | 308 | [[nodiscard]] const Core::PerfStats& GetPerfStats() const; |
| 304 | 309 | ||
| 305 | /// Provides a reference to the frame limiter; | 310 | /// Provides a reference to the frame limiter; |
| 306 | Core::FrameLimiter& FrameLimiter(); | 311 | [[nodiscard]] Core::FrameLimiter& FrameLimiter(); |
| 307 | 312 | ||
| 308 | /// Provides a constant referent to the frame limiter | 313 | /// Provides a constant referent to the frame limiter |
| 309 | const Core::FrameLimiter& FrameLimiter() const; | 314 | [[nodiscard]] const Core::FrameLimiter& FrameLimiter() const; |
| 310 | 315 | ||
| 311 | /// Gets the name of the current game | 316 | /// Gets the name of the current game |
| 312 | Loader::ResultStatus GetGameName(std::string& out) const; | 317 | [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const; |
| 313 | 318 | ||
| 314 | void SetStatus(ResultStatus new_status, const char* details); | 319 | void SetStatus(ResultStatus new_status, const char* details); |
| 315 | 320 | ||
| 316 | const std::string& GetStatusDetails() const; | 321 | [[nodiscard]] const std::string& GetStatusDetails() const; |
| 317 | 322 | ||
| 318 | Loader::AppLoader& GetAppLoader() const; | 323 | [[nodiscard]] Loader::AppLoader& GetAppLoader(); |
| 324 | [[nodiscard]] const Loader::AppLoader& GetAppLoader() const; | ||
| 319 | 325 | ||
| 320 | Service::SM::ServiceManager& ServiceManager(); | 326 | [[nodiscard]] Service::SM::ServiceManager& ServiceManager(); |
| 321 | const Service::SM::ServiceManager& ServiceManager() const; | 327 | [[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const; |
| 322 | 328 | ||
| 323 | void SetFilesystem(FileSys::VirtualFilesystem vfs); | 329 | void SetFilesystem(FileSys::VirtualFilesystem vfs); |
| 324 | 330 | ||
| 325 | FileSys::VirtualFilesystem GetFilesystem() const; | 331 | [[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const; |
| 326 | 332 | ||
| 327 | void RegisterCheatList(const std::vector<Memory::CheatEntry>& list, | 333 | void RegisterCheatList(const std::vector<Memory::CheatEntry>& list, |
| 328 | const std::array<u8, 0x20>& build_id, VAddr main_region_begin, | 334 | const std::array<u8, 0x20>& build_id, VAddr main_region_begin, |
| 329 | u64 main_region_size); | 335 | u64 main_region_size); |
| 330 | 336 | ||
| 331 | void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); | 337 | void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); |
| 332 | |||
| 333 | void SetDefaultAppletFrontendSet(); | 338 | void SetDefaultAppletFrontendSet(); |
| 334 | 339 | ||
| 335 | Service::AM::Applets::AppletManager& GetAppletManager(); | 340 | [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); |
| 336 | 341 | [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const; | |
| 337 | const Service::AM::Applets::AppletManager& GetAppletManager() const; | ||
| 338 | 342 | ||
| 339 | void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); | 343 | void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); |
| 340 | 344 | ||
| 341 | FileSys::ContentProvider& GetContentProvider(); | 345 | [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); |
| 342 | 346 | [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const; | |
| 343 | const FileSys::ContentProvider& GetContentProvider() const; | ||
| 344 | 347 | ||
| 345 | Service::FileSystem::FileSystemController& GetFileSystemController(); | 348 | [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController(); |
| 346 | 349 | [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const; | |
| 347 | const Service::FileSystem::FileSystemController& GetFileSystemController() const; | ||
| 348 | 350 | ||
| 349 | void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, | 351 | void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, |
| 350 | FileSys::ContentProvider* provider); | 352 | FileSys::ContentProvider* provider); |
| 351 | 353 | ||
| 352 | void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); | 354 | void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); |
| 353 | 355 | ||
| 354 | const Reporter& GetReporter() const; | 356 | [[nodiscard]] const Reporter& GetReporter() const; |
| 355 | |||
| 356 | Service::Glue::ARPManager& GetARPManager(); | ||
| 357 | 357 | ||
| 358 | const Service::Glue::ARPManager& GetARPManager() const; | 358 | [[nodiscard]] Service::Glue::ARPManager& GetARPManager(); |
| 359 | [[nodiscard]] const Service::Glue::ARPManager& GetARPManager() const; | ||
| 359 | 360 | ||
| 360 | Service::APM::Controller& GetAPMController(); | 361 | [[nodiscard]] Service::APM::Controller& GetAPMController(); |
| 362 | [[nodiscard]] const Service::APM::Controller& GetAPMController() const; | ||
| 361 | 363 | ||
| 362 | const Service::APM::Controller& GetAPMController() const; | 364 | [[nodiscard]] Service::LM::Manager& GetLogManager(); |
| 365 | [[nodiscard]] const Service::LM::Manager& GetLogManager() const; | ||
| 363 | 366 | ||
| 364 | Service::LM::Manager& GetLogManager(); | 367 | [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); |
| 365 | 368 | [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; | |
| 366 | const Service::LM::Manager& GetLogManager() const; | ||
| 367 | |||
| 368 | Service::Time::TimeManager& GetTimeManager(); | ||
| 369 | |||
| 370 | const Service::Time::TimeManager& GetTimeManager() const; | ||
| 371 | 369 | ||
| 372 | void SetExitLock(bool locked); | 370 | void SetExitLock(bool locked); |
| 373 | 371 | [[nodiscard]] bool GetExitLock() const; | |
| 374 | bool GetExitLock() const; | ||
| 375 | 372 | ||
| 376 | void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); | 373 | void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); |
| 377 | 374 | [[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const; | |
| 378 | const CurrentBuildProcessID& GetCurrentProcessBuildID() const; | ||
| 379 | 375 | ||
| 380 | /// Register a host thread as an emulated CPU Core. | 376 | /// Register a host thread as an emulated CPU Core. |
| 381 | void RegisterCoreThread(std::size_t id); | 377 | void RegisterCoreThread(std::size_t id); |
| @@ -390,18 +386,27 @@ public: | |||
| 390 | void ExitDynarmicProfile(); | 386 | void ExitDynarmicProfile(); |
| 391 | 387 | ||
| 392 | /// Tells if system is running on multicore. | 388 | /// Tells if system is running on multicore. |
| 393 | bool IsMulticore() const; | 389 | [[nodiscard]] bool IsMulticore() const; |
| 394 | 390 | ||
| 395 | private: | 391 | /// Type used for the frontend to designate a callback for System to re-launch the application |
| 396 | System(); | 392 | /// using a specified program index. |
| 393 | using ExecuteProgramCallback = std::function<void(std::size_t)>; | ||
| 397 | 394 | ||
| 398 | /** | 395 | /** |
| 399 | * Initialize the emulated system. | 396 | * Registers a callback from the frontend for System to re-launch the application using a |
| 400 | * @param emu_window Reference to the host-system window used for video output and keyboard | 397 | * specified program index. |
| 401 | * input. | 398 | * @param callback Callback from the frontend to relaunch the application. |
| 402 | * @return ResultStatus code, indicating if the operation succeeded. | 399 | */ |
| 400 | void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback); | ||
| 401 | |||
| 402 | /** | ||
| 403 | * Instructs the frontend to re-launch the application using the specified program_index. | ||
| 404 | * @param program_index Specifies the index within the application of the program to launch. | ||
| 403 | */ | 405 | */ |
| 404 | ResultStatus Init(Frontend::EmuWindow& emu_window); | 406 | void ExecuteProgram(std::size_t program_index); |
| 407 | |||
| 408 | private: | ||
| 409 | System(); | ||
| 405 | 410 | ||
| 406 | struct Impl; | 411 | struct Impl; |
| 407 | std::unique_ptr<Impl> impl; | 412 | std::unique_ptr<Impl> impl; |
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 983210197..100e90d82 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/fiber.h" | 5 | #include "common/fiber.h" |
| 6 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 7 | #include "common/scope_exit.h" | ||
| 7 | #include "common/thread.h" | 8 | #include "common/thread.h" |
| 8 | #include "core/arm/exclusive_monitor.h" | 9 | #include "core/arm/exclusive_monitor.h" |
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| @@ -343,6 +344,16 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 343 | data.initialized = true; | 344 | data.initialized = true; |
| 344 | const bool sc_sync = !is_async_gpu && !is_multicore; | 345 | const bool sc_sync = !is_async_gpu && !is_multicore; |
| 345 | bool sc_sync_first_use = sc_sync; | 346 | bool sc_sync_first_use = sc_sync; |
| 347 | |||
| 348 | // Cleanup | ||
| 349 | SCOPE_EXIT({ | ||
| 350 | data.host_context->Exit(); | ||
| 351 | data.enter_barrier.reset(); | ||
| 352 | data.exit_barrier.reset(); | ||
| 353 | data.initialized = false; | ||
| 354 | MicroProfileOnThreadExit(); | ||
| 355 | }); | ||
| 356 | |||
| 346 | /// Running | 357 | /// Running |
| 347 | while (running_mode) { | 358 | while (running_mode) { |
| 348 | data.is_running = false; | 359 | data.is_running = false; |
| @@ -351,6 +362,12 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 351 | system.GPU().ObtainContext(); | 362 | system.GPU().ObtainContext(); |
| 352 | sc_sync_first_use = false; | 363 | sc_sync_first_use = false; |
| 353 | } | 364 | } |
| 365 | |||
| 366 | // Abort if emulation was killed before the session really starts | ||
| 367 | if (!system.IsPoweredOn()) { | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | |||
| 354 | auto& scheduler = system.Kernel().CurrentScheduler(); | 371 | auto& scheduler = system.Kernel().CurrentScheduler(); |
| 355 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 372 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 356 | data.is_running = true; | 373 | data.is_running = true; |
| @@ -360,13 +377,6 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 360 | data.exit_barrier->Wait(); | 377 | data.exit_barrier->Wait(); |
| 361 | data.is_paused = false; | 378 | data.is_paused = false; |
| 362 | } | 379 | } |
| 363 | /// Time to cleanup | ||
| 364 | data.host_context->Exit(); | ||
| 365 | data.enter_barrier.reset(); | ||
| 366 | data.exit_barrier.reset(); | ||
| 367 | data.initialized = false; | ||
| 368 | |||
| 369 | MicroProfileOnThreadExit(); | ||
| 370 | } | 380 | } |
| 371 | 381 | ||
| 372 | } // namespace Core | 382 | } // namespace Core |
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 956da68f7..8dee5590b 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -29,7 +29,7 @@ constexpr std::array partition_names{ | |||
| 29 | "logo", | 29 | "logo", |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | XCI::XCI(VirtualFile file_) | 32 | XCI::XCI(VirtualFile file_, std::size_t program_index) |
| 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, | 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, |
| 34 | partitions(partition_names.size()), | 34 | partitions(partition_names.size()), |
| 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { | 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { |
| @@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_) | |||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | secure_partition = std::make_shared<NSP>( | 64 | secure_partition = std::make_shared<NSP>( |
| 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)])); | 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]), |
| 66 | program_index); | ||
| 66 | 67 | ||
| 67 | ncas = secure_partition->GetNCAsCollapsed(); | 68 | ncas = secure_partition->GetNCAsCollapsed(); |
| 68 | program = | 69 | program = |
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 2d0a0f285..4960e90fe 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h | |||
| @@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo }; | |||
| 78 | 78 | ||
| 79 | class XCI : public ReadOnlyVfsDirectory { | 79 | class XCI : public ReadOnlyVfsDirectory { |
| 80 | public: | 80 | public: |
| 81 | explicit XCI(VirtualFile file); | 81 | explicit XCI(VirtualFile file, std::size_t program_index = 0); |
| 82 | ~XCI() override; | 82 | ~XCI() override; |
| 83 | 83 | ||
| 84 | Loader::ResultStatus GetStatus() const; | 84 | Loader::ResultStatus GetStatus() const; |
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index 90641d23b..c05735ddd 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -20,8 +20,8 @@ | |||
| 20 | 20 | ||
| 21 | namespace FileSys { | 21 | namespace FileSys { |
| 22 | 22 | ||
| 23 | NSP::NSP(VirtualFile file_) | 23 | NSP::NSP(VirtualFile file_, std::size_t program_index) |
| 24 | : file(std::move(file_)), status{Loader::ResultStatus::Success}, | 24 | : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success}, |
| 25 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { | 25 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { |
| 26 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { | 26 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { |
| 27 | status = pfs->GetStatus(); | 27 | status = pfs->GetStatus(); |
| @@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType | |||
| 146 | if (extracted) | 146 | if (extracted) |
| 147 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); | 147 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); |
| 148 | 148 | ||
| 149 | const auto title_id_iter = ncas.find(title_id); | 149 | const auto title_id_iter = ncas.find(title_id + program_index); |
| 150 | if (title_id_iter == ncas.end()) | 150 | if (title_id_iter == ncas.end()) |
| 151 | return nullptr; | 151 | return nullptr; |
| 152 | 152 | ||
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index c70a11b5b..54581a6f3 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h | |||
| @@ -27,7 +27,7 @@ enum class ContentRecordType : u8; | |||
| 27 | 27 | ||
| 28 | class NSP : public ReadOnlyVfsDirectory { | 28 | class NSP : public ReadOnlyVfsDirectory { |
| 29 | public: | 29 | public: |
| 30 | explicit NSP(VirtualFile file); | 30 | explicit NSP(VirtualFile file, std::size_t program_index = 0); |
| 31 | ~NSP() override; | 31 | ~NSP() override; |
| 32 | 32 | ||
| 33 | Loader::ResultStatus GetStatus() const; | 33 | Loader::ResultStatus GetStatus() const; |
| @@ -69,6 +69,8 @@ private: | |||
| 69 | 69 | ||
| 70 | VirtualFile file; | 70 | VirtualFile file; |
| 71 | 71 | ||
| 72 | const std::size_t program_index; | ||
| 73 | |||
| 72 | bool extracted = false; | 74 | bool extracted = false; |
| 73 | Loader::ResultStatus status; | 75 | Loader::ResultStatus status; |
| 74 | std::map<u64, Loader::ResultStatus> program_status; | 76 | std::map<u64, Loader::ResultStatus> program_status; |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 3e8780243..276d2b906 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -102,8 +102,8 @@ public: | |||
| 102 | float render_surface_scale = 1.0f; | 102 | float render_surface_scale = 1.0f; |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | /// Polls window events | 105 | /// Called from GPU thread when a frame is displayed. |
| 106 | virtual void PollEvents() = 0; | 106 | virtual void OnFrameDisplayed() {} |
| 107 | 107 | ||
| 108 | /** | 108 | /** |
| 109 | * Returns a GraphicsContext that the frontend provides to be used for rendering. | 109 | * Returns a GraphicsContext that the frontend provides to be used for rendering. |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index bafd1ced7..e3b770d66 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -681,7 +681,7 @@ static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { | |||
| 681 | } | 681 | } |
| 682 | 682 | ||
| 683 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | 683 | /// Used to output a message on a debug hardware unit - does nothing on a retail unit |
| 684 | static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { | 684 | static void OutputDebugString(Core::System& system, VAddr address, u64 len) { |
| 685 | if (len == 0) { | 685 | if (len == 0) { |
| 686 | return; | 686 | return; |
| 687 | } | 687 | } |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 63421b963..703a9b234 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -246,9 +246,8 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { | |||
| 246 | 246 | ||
| 247 | IDebugFunctions::~IDebugFunctions() = default; | 247 | IDebugFunctions::~IDebugFunctions() = default; |
| 248 | 248 | ||
| 249 | ISelfController::ISelfController(Core::System& system, | 249 | ISelfController::ISelfController(Core::System& system, NVFlinger::NVFlinger& nvflinger) |
| 250 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger) | 250 | : ServiceFramework("ISelfController"), system(system), nvflinger(nvflinger) { |
| 251 | : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) { | ||
| 252 | // clang-format off | 251 | // clang-format off |
| 253 | static const FunctionInfo functions[] = { | 252 | static const FunctionInfo functions[] = { |
| 254 | {0, &ISelfController::Exit, "Exit"}, | 253 | {0, &ISelfController::Exit, "Exit"}, |
| @@ -458,8 +457,8 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) | |||
| 458 | 457 | ||
| 459 | // TODO(Subv): Find out how AM determines the display to use, for now just | 458 | // TODO(Subv): Find out how AM determines the display to use, for now just |
| 460 | // create the layer in the Default display. | 459 | // create the layer in the Default display. |
| 461 | const auto display_id = nvflinger->OpenDisplay("Default"); | 460 | const auto display_id = nvflinger.OpenDisplay("Default"); |
| 462 | const auto layer_id = nvflinger->CreateLayer(*display_id); | 461 | const auto layer_id = nvflinger.CreateLayer(*display_id); |
| 463 | 462 | ||
| 464 | IPC::ResponseBuilder rb{ctx, 4}; | 463 | IPC::ResponseBuilder rb{ctx, 4}; |
| 465 | rb.Push(RESULT_SUCCESS); | 464 | rb.Push(RESULT_SUCCESS); |
| @@ -476,8 +475,8 @@ void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestConte | |||
| 476 | // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse | 475 | // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse |
| 477 | // side effects. | 476 | // side effects. |
| 478 | // TODO: Support multiple layers | 477 | // TODO: Support multiple layers |
| 479 | const auto display_id = nvflinger->OpenDisplay("Default"); | 478 | const auto display_id = nvflinger.OpenDisplay("Default"); |
| 480 | const auto layer_id = nvflinger->CreateLayer(*display_id); | 479 | const auto layer_id = nvflinger.CreateLayer(*display_id); |
| 481 | 480 | ||
| 482 | IPC::ResponseBuilder rb{ctx, 4}; | 481 | IPC::ResponseBuilder rb{ctx, 4}; |
| 483 | rb.Push(RESULT_SUCCESS); | 482 | rb.Push(RESULT_SUCCESS); |
| @@ -1189,9 +1188,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1189 | {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, | 1188 | {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, |
| 1190 | {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, | 1189 | {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, |
| 1191 | {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, | 1190 | {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, |
| 1192 | {120, nullptr, "ExecuteProgram"}, | 1191 | {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, |
| 1193 | {121, nullptr, "ClearUserChannel"}, | 1192 | {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, |
| 1194 | {122, nullptr, "UnpopToUserChannel"}, | 1193 | {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, |
| 1195 | {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, | 1194 | {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, |
| 1196 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, | 1195 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, |
| 1197 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, | 1196 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, |
| @@ -1562,6 +1561,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque | |||
| 1562 | rb.Push<u32>(0); | 1561 | rb.Push<u32>(0); |
| 1563 | } | 1562 | } |
| 1564 | 1563 | ||
| 1564 | void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) { | ||
| 1565 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1566 | |||
| 1567 | IPC::RequestParser rp{ctx}; | ||
| 1568 | [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); | ||
| 1569 | [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); | ||
| 1570 | const auto program_index = rp.Pop<u64>(); | ||
| 1571 | |||
| 1572 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1573 | rb.Push(RESULT_SUCCESS); | ||
| 1574 | |||
| 1575 | system.ExecuteProgram(program_index); | ||
| 1576 | } | ||
| 1577 | |||
| 1578 | void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) { | ||
| 1579 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1580 | |||
| 1581 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1582 | rb.Push(RESULT_SUCCESS); | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) { | ||
| 1586 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1587 | |||
| 1588 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1589 | rb.Push(RESULT_SUCCESS); | ||
| 1590 | } | ||
| 1591 | |||
| 1565 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { | 1592 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { |
| 1566 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 1593 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 1567 | 1594 | ||
| @@ -1586,8 +1613,8 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe | |||
| 1586 | rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); | 1613 | rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); |
| 1587 | } | 1614 | } |
| 1588 | 1615 | ||
| 1589 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1616 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 1590 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { | 1617 | Core::System& system) { |
| 1591 | auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); | 1618 | auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); |
| 1592 | // Needed on game boot | 1619 | // Needed on game boot |
| 1593 | message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); | 1620 | message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index bcc06affe..af97c303a 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -121,8 +121,7 @@ public: | |||
| 121 | 121 | ||
| 122 | class ISelfController final : public ServiceFramework<ISelfController> { | 122 | class ISelfController final : public ServiceFramework<ISelfController> { |
| 123 | public: | 123 | public: |
| 124 | explicit ISelfController(Core::System& system_, | 124 | explicit ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_); |
| 125 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger_); | ||
| 126 | ~ISelfController() override; | 125 | ~ISelfController() override; |
| 127 | 126 | ||
| 128 | private: | 127 | private: |
| @@ -156,7 +155,7 @@ private: | |||
| 156 | }; | 155 | }; |
| 157 | 156 | ||
| 158 | Core::System& system; | 157 | Core::System& system; |
| 159 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 158 | NVFlinger::NVFlinger& nvflinger; |
| 160 | Kernel::EventPair launchable_event; | 159 | Kernel::EventPair launchable_event; |
| 161 | Kernel::EventPair accumulated_suspended_tick_changed_event; | 160 | Kernel::EventPair accumulated_suspended_tick_changed_event; |
| 162 | 161 | ||
| @@ -288,6 +287,9 @@ private: | |||
| 288 | void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); | 287 | void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); |
| 289 | void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); | 288 | void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); |
| 290 | void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); | 289 | void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); |
| 290 | void ExecuteProgram(Kernel::HLERequestContext& ctx); | ||
| 291 | void ClearUserChannel(Kernel::HLERequestContext& ctx); | ||
| 292 | void UnpopToUserChannel(Kernel::HLERequestContext& ctx); | ||
| 291 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); | 293 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); |
| 292 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); | 294 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); |
| 293 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); | 295 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); |
| @@ -332,7 +334,7 @@ public: | |||
| 332 | }; | 334 | }; |
| 333 | 335 | ||
| 334 | /// Registers all AM services with the specified service manager. | 336 | /// Registers all AM services with the specified service manager. |
| 335 | void InstallInterfaces(SM::ServiceManager& service_manager, | 337 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 336 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system); | 338 | Core::System& system); |
| 337 | 339 | ||
| 338 | } // namespace Service::AM | 340 | } // namespace Service::AM |
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index be23ca747..7de506b70 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp | |||
| @@ -13,10 +13,10 @@ namespace Service::AM { | |||
| 13 | 13 | ||
| 14 | class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { | 14 | class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { |
| 15 | public: | 15 | public: |
| 16 | explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 16 | explicit ILibraryAppletProxy(NVFlinger::NVFlinger& nvflinger, |
| 17 | std::shared_ptr<AppletMessageQueue> msg_queue, | 17 | std::shared_ptr<AppletMessageQueue> msg_queue, |
| 18 | Core::System& system) | 18 | Core::System& system) |
| 19 | : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), | 19 | : ServiceFramework("ILibraryAppletProxy"), nvflinger(nvflinger), |
| 20 | msg_queue(std::move(msg_queue)), system(system) { | 20 | msg_queue(std::move(msg_queue)), system(system) { |
| 21 | // clang-format off | 21 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 22 | static const FunctionInfo functions[] = { |
| @@ -109,16 +109,16 @@ private: | |||
| 109 | rb.PushIpcInterface<IApplicationFunctions>(system); | 109 | rb.PushIpcInterface<IApplicationFunctions>(system); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 112 | NVFlinger::NVFlinger& nvflinger; |
| 113 | std::shared_ptr<AppletMessageQueue> msg_queue; | 113 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 114 | Core::System& system; | 114 | Core::System& system; |
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { | 117 | class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { |
| 118 | public: | 118 | public: |
| 119 | explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 119 | explicit ISystemAppletProxy(NVFlinger::NVFlinger& nvflinger, |
| 120 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 120 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) |
| 121 | : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), | 121 | : ServiceFramework("ISystemAppletProxy"), nvflinger(nvflinger), |
| 122 | msg_queue(std::move(msg_queue)), system(system) { | 122 | msg_queue(std::move(msg_queue)), system(system) { |
| 123 | // clang-format off | 123 | // clang-format off |
| 124 | static const FunctionInfo functions[] = { | 124 | static const FunctionInfo functions[] = { |
| @@ -220,7 +220,8 @@ private: | |||
| 220 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 221 | rb.PushIpcInterface<IApplicationCreator>(); | 221 | rb.PushIpcInterface<IApplicationCreator>(); |
| 222 | } | 222 | } |
| 223 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 223 | |
| 224 | NVFlinger::NVFlinger& nvflinger; | ||
| 224 | std::shared_ptr<AppletMessageQueue> msg_queue; | 225 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 225 | Core::System& system; | 226 | Core::System& system; |
| 226 | }; | 227 | }; |
| @@ -249,10 +250,10 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { | |||
| 249 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system); | 250 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system); |
| 250 | } | 251 | } |
| 251 | 252 | ||
| 252 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 253 | AppletAE::AppletAE(NVFlinger::NVFlinger& nvflinger, std::shared_ptr<AppletMessageQueue> msg_queue, |
| 253 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 254 | Core::System& system) |
| 254 | : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), | 255 | : ServiceFramework("appletAE"), nvflinger(nvflinger), msg_queue(std::move(msg_queue)), |
| 255 | msg_queue(std::move(msg_queue)), system(system) { | 256 | system(system) { |
| 256 | // clang-format off | 257 | // clang-format off |
| 257 | static const FunctionInfo functions[] = { | 258 | static const FunctionInfo functions[] = { |
| 258 | {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, | 259 | {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, |
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h index 2e3e45915..761844a1f 100644 --- a/src/core/hle/service/am/applet_ae.h +++ b/src/core/hle/service/am/applet_ae.h | |||
| @@ -23,7 +23,7 @@ class AppletMessageQueue; | |||
| 23 | 23 | ||
| 24 | class AppletAE final : public ServiceFramework<AppletAE> { | 24 | class AppletAE final : public ServiceFramework<AppletAE> { |
| 25 | public: | 25 | public: |
| 26 | explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 26 | explicit AppletAE(NVFlinger::NVFlinger& nvflinger, |
| 27 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); | 27 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); |
| 28 | ~AppletAE() override; | 28 | ~AppletAE() override; |
| 29 | 29 | ||
| @@ -34,7 +34,7 @@ private: | |||
| 34 | void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); | 34 | void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); |
| 35 | void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); | 35 | void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); |
| 36 | 36 | ||
| 37 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 37 | NVFlinger::NVFlinger& nvflinger; |
| 38 | std::shared_ptr<AppletMessageQueue> msg_queue; | 38 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 39 | Core::System& system; | 39 | Core::System& system; |
| 40 | }; | 40 | }; |
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index a2ffaa440..7bed86ec4 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp | |||
| @@ -12,9 +12,9 @@ namespace Service::AM { | |||
| 12 | 12 | ||
| 13 | class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { | 13 | class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { |
| 14 | public: | 14 | public: |
| 15 | explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 15 | explicit IApplicationProxy(NVFlinger::NVFlinger& nvflinger, |
| 16 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 16 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) |
| 17 | : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), | 17 | : ServiceFramework("IApplicationProxy"), nvflinger(nvflinger), |
| 18 | msg_queue(std::move(msg_queue)), system(system) { | 18 | msg_queue(std::move(msg_queue)), system(system) { |
| 19 | // clang-format off | 19 | // clang-format off |
| 20 | static const FunctionInfo functions[] = { | 20 | static const FunctionInfo functions[] = { |
| @@ -98,7 +98,7 @@ private: | |||
| 98 | rb.PushIpcInterface<IApplicationFunctions>(system); | 98 | rb.PushIpcInterface<IApplicationFunctions>(system); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 101 | NVFlinger::NVFlinger& nvflinger; |
| 102 | std::shared_ptr<AppletMessageQueue> msg_queue; | 102 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 103 | Core::System& system; | 103 | Core::System& system; |
| 104 | }; | 104 | }; |
| @@ -111,10 +111,10 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { | |||
| 111 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system); | 111 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 114 | AppletOE::AppletOE(NVFlinger::NVFlinger& nvflinger, std::shared_ptr<AppletMessageQueue> msg_queue, |
| 115 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) | 115 | Core::System& system) |
| 116 | : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), | 116 | : ServiceFramework("appletOE"), nvflinger(nvflinger), msg_queue(std::move(msg_queue)), |
| 117 | msg_queue(std::move(msg_queue)), system(system) { | 117 | system(system) { |
| 118 | static const FunctionInfo functions[] = { | 118 | static const FunctionInfo functions[] = { |
| 119 | {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, | 119 | {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, |
| 120 | }; | 120 | }; |
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h index 758da792d..88906d354 100644 --- a/src/core/hle/service/am/applet_oe.h +++ b/src/core/hle/service/am/applet_oe.h | |||
| @@ -23,7 +23,7 @@ class AppletMessageQueue; | |||
| 23 | 23 | ||
| 24 | class AppletOE final : public ServiceFramework<AppletOE> { | 24 | class AppletOE final : public ServiceFramework<AppletOE> { |
| 25 | public: | 25 | public: |
| 26 | explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 26 | explicit AppletOE(NVFlinger::NVFlinger& nvflinger, |
| 27 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); | 27 | std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); |
| 28 | ~AppletOE() override; | 28 | ~AppletOE() override; |
| 29 | 29 | ||
| @@ -32,7 +32,7 @@ public: | |||
| 32 | private: | 32 | private: |
| 33 | void OpenApplicationProxy(Kernel::HLERequestContext& ctx); | 33 | void OpenApplicationProxy(Kernel::HLERequestContext& ctx); |
| 34 | 34 | ||
| 35 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 35 | NVFlinger::NVFlinger& nvflinger; |
| 36 | std::shared_ptr<AppletMessageQueue> msg_queue; | 36 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 37 | Core::System& system; | 37 | Core::System& system; |
| 38 | }; | 38 | }; |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index fbfda2d5b..fb4979af2 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -188,17 +188,19 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co | |||
| 188 | return RESULT_SUCCESS; | 188 | return RESULT_SUCCESS; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | /// Initialize ServiceManager | 191 | /// Initialize Services |
| 192 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | 192 | Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) |
| 193 | : nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} { | ||
| 194 | |||
| 193 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it | 195 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it |
| 194 | // here and pass it into the respective InstallInterfaces functions. | 196 | // here and pass it into the respective InstallInterfaces functions. |
| 195 | auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system); | 197 | |
| 196 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); | 198 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); |
| 197 | 199 | ||
| 198 | SM::ServiceManager::InstallInterfaces(sm, system.Kernel()); | 200 | SM::ServiceManager::InstallInterfaces(sm, system.Kernel()); |
| 199 | 201 | ||
| 200 | Account::InstallInterfaces(system); | 202 | Account::InstallInterfaces(system); |
| 201 | AM::InstallInterfaces(*sm, nv_flinger, system); | 203 | AM::InstallInterfaces(*sm, *nv_flinger, system); |
| 202 | AOC::InstallInterfaces(*sm, system); | 204 | AOC::InstallInterfaces(*sm, system); |
| 203 | APM::InstallInterfaces(system); | 205 | APM::InstallInterfaces(system); |
| 204 | Audio::InstallInterfaces(*sm, system); | 206 | Audio::InstallInterfaces(*sm, system); |
| @@ -246,14 +248,10 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | |||
| 246 | SSL::InstallInterfaces(*sm); | 248 | SSL::InstallInterfaces(*sm); |
| 247 | Time::InstallInterfaces(system); | 249 | Time::InstallInterfaces(system); |
| 248 | USB::InstallInterfaces(*sm); | 250 | USB::InstallInterfaces(*sm); |
| 249 | VI::InstallInterfaces(*sm, nv_flinger); | 251 | VI::InstallInterfaces(*sm, *nv_flinger); |
| 250 | WLAN::InstallInterfaces(*sm); | 252 | WLAN::InstallInterfaces(*sm); |
| 251 | |||
| 252 | LOG_DEBUG(Service, "initialized OK"); | ||
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | /// Shutdown ServiceManager | 255 | Services::~Services() = default; |
| 256 | void Shutdown() { | 256 | |
| 257 | LOG_DEBUG(Service, "shutdown OK"); | ||
| 258 | } | ||
| 259 | } // namespace Service | 257 | } // namespace Service |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index a01ef3353..ed4792289 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -29,7 +29,11 @@ namespace Service { | |||
| 29 | 29 | ||
| 30 | namespace FileSystem { | 30 | namespace FileSystem { |
| 31 | class FileSystemController; | 31 | class FileSystemController; |
| 32 | } // namespace FileSystem | 32 | } |
| 33 | |||
| 34 | namespace NVFlinger { | ||
| 35 | class NVFlinger; | ||
| 36 | } | ||
| 33 | 37 | ||
| 34 | namespace SM { | 38 | namespace SM { |
| 35 | class ServiceManager; | 39 | class ServiceManager; |
| @@ -181,10 +185,17 @@ private: | |||
| 181 | } | 185 | } |
| 182 | }; | 186 | }; |
| 183 | 187 | ||
| 184 | /// Initialize ServiceManager | 188 | /** |
| 185 | void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); | 189 | * The purpose of this class is to own any objects that need to be shared across the other service |
| 190 | * implementations. Will be torn down when the global system instance is shutdown. | ||
| 191 | */ | ||
| 192 | class Services final { | ||
| 193 | public: | ||
| 194 | explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); | ||
| 195 | ~Services(); | ||
| 186 | 196 | ||
| 187 | /// Shutdown ServiceManager | 197 | private: |
| 188 | void Shutdown(); | 198 | std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; |
| 199 | }; | ||
| 189 | 200 | ||
| 190 | } // namespace Service | 201 | } // namespace Service |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 55e00dd93..86bd604f4 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -492,8 +492,8 @@ private: | |||
| 492 | 492 | ||
| 493 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { | 493 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { |
| 494 | public: | 494 | public: |
| 495 | explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 495 | explicit IHOSBinderDriver(NVFlinger::NVFlinger& nv_flinger) |
| 496 | : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) { | 496 | : ServiceFramework("IHOSBinderDriver"), nv_flinger(nv_flinger) { |
| 497 | static const FunctionInfo functions[] = { | 497 | static const FunctionInfo functions[] = { |
| 498 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, | 498 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, |
| 499 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, | 499 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, |
| @@ -530,8 +530,8 @@ private: | |||
| 530 | LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, | 530 | LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, |
| 531 | static_cast<u32>(transaction), flags); | 531 | static_cast<u32>(transaction), flags); |
| 532 | 532 | ||
| 533 | const auto guard = nv_flinger->Lock(); | 533 | const auto guard = nv_flinger.Lock(); |
| 534 | auto& buffer_queue = nv_flinger->FindBufferQueue(id); | 534 | auto& buffer_queue = nv_flinger.FindBufferQueue(id); |
| 535 | 535 | ||
| 536 | switch (transaction) { | 536 | switch (transaction) { |
| 537 | case TransactionId::Connect: { | 537 | case TransactionId::Connect: { |
| @@ -570,8 +570,8 @@ private: | |||
| 570 | [=, this](std::shared_ptr<Kernel::Thread> thread, | 570 | [=, this](std::shared_ptr<Kernel::Thread> thread, |
| 571 | Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { | 571 | Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { |
| 572 | // Repeat TransactParcel DequeueBuffer when a buffer is available | 572 | // Repeat TransactParcel DequeueBuffer when a buffer is available |
| 573 | const auto guard = nv_flinger->Lock(); | 573 | const auto guard = nv_flinger.Lock(); |
| 574 | auto& buffer_queue = nv_flinger->FindBufferQueue(id); | 574 | auto& buffer_queue = nv_flinger.FindBufferQueue(id); |
| 575 | auto result = buffer_queue.DequeueBuffer(width, height); | 575 | auto result = buffer_queue.DequeueBuffer(width, height); |
| 576 | ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); | 576 | ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); |
| 577 | 577 | ||
| @@ -676,7 +676,7 @@ private: | |||
| 676 | 676 | ||
| 677 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); | 677 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); |
| 678 | 678 | ||
| 679 | const auto& buffer_queue = nv_flinger->FindBufferQueue(id); | 679 | const auto& buffer_queue = nv_flinger.FindBufferQueue(id); |
| 680 | 680 | ||
| 681 | // TODO(Subv): Find out what this actually is. | 681 | // TODO(Subv): Find out what this actually is. |
| 682 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 682 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| @@ -684,8 +684,8 @@ private: | |||
| 684 | rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent()); | 684 | rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent()); |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 687 | NVFlinger::NVFlinger& nv_flinger; |
| 688 | }; // namespace VI | 688 | }; |
| 689 | 689 | ||
| 690 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { | 690 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { |
| 691 | public: | 691 | public: |
| @@ -790,8 +790,8 @@ private: | |||
| 790 | 790 | ||
| 791 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 791 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
| 792 | public: | 792 | public: |
| 793 | explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 793 | explicit IManagerDisplayService(NVFlinger::NVFlinger& nv_flinger) |
| 794 | : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { | 794 | : ServiceFramework("IManagerDisplayService"), nv_flinger(nv_flinger) { |
| 795 | // clang-format off | 795 | // clang-format off |
| 796 | static const FunctionInfo functions[] = { | 796 | static const FunctionInfo functions[] = { |
| 797 | {200, nullptr, "AllocateProcessHeapBlock"}, | 797 | {200, nullptr, "AllocateProcessHeapBlock"}, |
| @@ -893,7 +893,7 @@ private: | |||
| 893 | "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", | 893 | "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", |
| 894 | unknown, display, aruid); | 894 | unknown, display, aruid); |
| 895 | 895 | ||
| 896 | const auto layer_id = nv_flinger->CreateLayer(display); | 896 | const auto layer_id = nv_flinger.CreateLayer(display); |
| 897 | if (!layer_id) { | 897 | if (!layer_id) { |
| 898 | LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); | 898 | LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); |
| 899 | IPC::ResponseBuilder rb{ctx, 2}; | 899 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -930,12 +930,12 @@ private: | |||
| 930 | rb.Push(RESULT_SUCCESS); | 930 | rb.Push(RESULT_SUCCESS); |
| 931 | } | 931 | } |
| 932 | 932 | ||
| 933 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 933 | NVFlinger::NVFlinger& nv_flinger; |
| 934 | }; | 934 | }; |
| 935 | 935 | ||
| 936 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { | 936 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { |
| 937 | public: | 937 | public: |
| 938 | explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 938 | explicit IApplicationDisplayService(NVFlinger::NVFlinger& nv_flinger); |
| 939 | 939 | ||
| 940 | private: | 940 | private: |
| 941 | enum class ConvertedScaleMode : u64 { | 941 | enum class ConvertedScaleMode : u64 { |
| @@ -1010,7 +1010,7 @@ private: | |||
| 1010 | 1010 | ||
| 1011 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); | 1011 | ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); |
| 1012 | 1012 | ||
| 1013 | const auto display_id = nv_flinger->OpenDisplay(name); | 1013 | const auto display_id = nv_flinger.OpenDisplay(name); |
| 1014 | if (!display_id) { | 1014 | if (!display_id) { |
| 1015 | LOG_ERROR(Service_VI, "Display not found! display_name={}", name); | 1015 | LOG_ERROR(Service_VI, "Display not found! display_name={}", name); |
| 1016 | IPC::ResponseBuilder rb{ctx, 2}; | 1016 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1110,7 +1110,7 @@ private: | |||
| 1110 | 1110 | ||
| 1111 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); | 1111 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); |
| 1112 | 1112 | ||
| 1113 | const auto display_id = nv_flinger->OpenDisplay(display_name); | 1113 | const auto display_id = nv_flinger.OpenDisplay(display_name); |
| 1114 | if (!display_id) { | 1114 | if (!display_id) { |
| 1115 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); | 1115 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); |
| 1116 | IPC::ResponseBuilder rb{ctx, 2}; | 1116 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1118,7 +1118,7 @@ private: | |||
| 1118 | return; | 1118 | return; |
| 1119 | } | 1119 | } |
| 1120 | 1120 | ||
| 1121 | const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id); | 1121 | const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id); |
| 1122 | if (!buffer_queue_id) { | 1122 | if (!buffer_queue_id) { |
| 1123 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); | 1123 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); |
| 1124 | IPC::ResponseBuilder rb{ctx, 2}; | 1124 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1138,7 +1138,7 @@ private: | |||
| 1138 | 1138 | ||
| 1139 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); | 1139 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); |
| 1140 | 1140 | ||
| 1141 | nv_flinger->CloseLayer(layer_id); | 1141 | nv_flinger.CloseLayer(layer_id); |
| 1142 | 1142 | ||
| 1143 | IPC::ResponseBuilder rb{ctx, 2}; | 1143 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1144 | rb.Push(RESULT_SUCCESS); | 1144 | rb.Push(RESULT_SUCCESS); |
| @@ -1154,7 +1154,7 @@ private: | |||
| 1154 | 1154 | ||
| 1155 | // TODO(Subv): What's the difference between a Stray and a Managed layer? | 1155 | // TODO(Subv): What's the difference between a Stray and a Managed layer? |
| 1156 | 1156 | ||
| 1157 | const auto layer_id = nv_flinger->CreateLayer(display_id); | 1157 | const auto layer_id = nv_flinger.CreateLayer(display_id); |
| 1158 | if (!layer_id) { | 1158 | if (!layer_id) { |
| 1159 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id); | 1159 | LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id); |
| 1160 | IPC::ResponseBuilder rb{ctx, 2}; | 1160 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1162,7 +1162,7 @@ private: | |||
| 1162 | return; | 1162 | return; |
| 1163 | } | 1163 | } |
| 1164 | 1164 | ||
| 1165 | const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id); | 1165 | const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id); |
| 1166 | if (!buffer_queue_id) { | 1166 | if (!buffer_queue_id) { |
| 1167 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); | 1167 | LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); |
| 1168 | IPC::ResponseBuilder rb{ctx, 2}; | 1168 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1193,7 +1193,7 @@ private: | |||
| 1193 | 1193 | ||
| 1194 | LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); | 1194 | LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); |
| 1195 | 1195 | ||
| 1196 | const auto vsync_event = nv_flinger->FindVsyncEvent(display_id); | 1196 | const auto vsync_event = nv_flinger.FindVsyncEvent(display_id); |
| 1197 | if (!vsync_event) { | 1197 | if (!vsync_event) { |
| 1198 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); | 1198 | LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); |
| 1199 | IPC::ResponseBuilder rb{ctx, 2}; | 1199 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -1258,12 +1258,11 @@ private: | |||
| 1258 | } | 1258 | } |
| 1259 | } | 1259 | } |
| 1260 | 1260 | ||
| 1261 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 1261 | NVFlinger::NVFlinger& nv_flinger; |
| 1262 | }; | 1262 | }; |
| 1263 | 1263 | ||
| 1264 | IApplicationDisplayService::IApplicationDisplayService( | 1264 | IApplicationDisplayService::IApplicationDisplayService(NVFlinger::NVFlinger& nv_flinger) |
| 1265 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 1265 | : ServiceFramework("IApplicationDisplayService"), nv_flinger(nv_flinger) { |
| 1266 | : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) { | ||
| 1267 | static const FunctionInfo functions[] = { | 1266 | static const FunctionInfo functions[] = { |
| 1268 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, | 1267 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, |
| 1269 | {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, | 1268 | {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, |
| @@ -1304,8 +1303,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { | |||
| 1304 | return false; | 1303 | return false; |
| 1305 | } | 1304 | } |
| 1306 | 1305 | ||
| 1307 | void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, | 1306 | void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, NVFlinger::NVFlinger& nv_flinger, |
| 1308 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, | ||
| 1309 | Permission permission) { | 1307 | Permission permission) { |
| 1310 | IPC::RequestParser rp{ctx}; | 1308 | IPC::RequestParser rp{ctx}; |
| 1311 | const auto policy = rp.PopEnum<Policy>(); | 1309 | const auto policy = rp.PopEnum<Policy>(); |
| @@ -1319,11 +1317,10 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, | |||
| 1319 | 1317 | ||
| 1320 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1318 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1321 | rb.Push(RESULT_SUCCESS); | 1319 | rb.Push(RESULT_SUCCESS); |
| 1322 | rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger)); | 1320 | rb.PushIpcInterface<IApplicationDisplayService>(nv_flinger); |
| 1323 | } | 1321 | } |
| 1324 | 1322 | ||
| 1325 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1323 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nv_flinger) { |
| 1326 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { | ||
| 1327 | std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager); | 1324 | std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager); |
| 1328 | std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager); | 1325 | std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager); |
| 1329 | std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); | 1326 | std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); |
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 6b66f8b81..5229fa753 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h | |||
| @@ -43,12 +43,11 @@ enum class Policy { | |||
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | namespace detail { | 45 | namespace detail { |
| 46 | void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, | 46 | void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, NVFlinger::NVFlinger& nv_flinger, |
| 47 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, Permission permission); | 47 | Permission permission); |
| 48 | } // namespace detail | 48 | } // namespace detail |
| 49 | 49 | ||
| 50 | /// Registers all VI services with the specified service manager. | 50 | /// Registers all VI services with the specified service manager. |
| 51 | void InstallInterfaces(SM::ServiceManager& service_manager, | 51 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nv_flinger); |
| 52 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | ||
| 53 | 52 | ||
| 54 | } // namespace Service::VI | 53 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 06070087f..41da3ee93 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp | |||
| @@ -8,8 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::VI { | 9 | namespace Service::VI { |
| 10 | 10 | ||
| 11 | VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_M::VI_M(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:m"}, nv_flinger{nv_flinger} { |
| 12 | : ServiceFramework{"vi:m"}, nv_flinger{std::move(nv_flinger)} { | ||
| 13 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 14 | {2, &VI_M::GetDisplayService, "GetDisplayService"}, | 13 | {2, &VI_M::GetDisplayService, "GetDisplayService"}, |
| 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 14 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 290e06689..ee2489874 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h | |||
| @@ -18,13 +18,13 @@ namespace Service::VI { | |||
| 18 | 18 | ||
| 19 | class VI_M final : public ServiceFramework<VI_M> { | 19 | class VI_M final : public ServiceFramework<VI_M> { |
| 20 | public: | 20 | public: |
| 21 | explicit VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 21 | explicit VI_M(NVFlinger::NVFlinger& nv_flinger); |
| 22 | ~VI_M() override; | 22 | ~VI_M() override; |
| 23 | 23 | ||
| 24 | private: | 24 | private: |
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 26 | 26 | ||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 27 | NVFlinger::NVFlinger& nv_flinger; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | } // namespace Service::VI | 30 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp index 57c596cc4..6acb51e2a 100644 --- a/src/core/hle/service/vi/vi_s.cpp +++ b/src/core/hle/service/vi/vi_s.cpp | |||
| @@ -8,8 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::VI { | 9 | namespace Service::VI { |
| 10 | 10 | ||
| 11 | VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_S::VI_S(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:s"}, nv_flinger{nv_flinger} { |
| 12 | : ServiceFramework{"vi:s"}, nv_flinger{std::move(nv_flinger)} { | ||
| 13 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 14 | {1, &VI_S::GetDisplayService, "GetDisplayService"}, | 13 | {1, &VI_S::GetDisplayService, "GetDisplayService"}, |
| 15 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 14 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h index 47804dc0b..6790673ab 100644 --- a/src/core/hle/service/vi/vi_s.h +++ b/src/core/hle/service/vi/vi_s.h | |||
| @@ -18,13 +18,13 @@ namespace Service::VI { | |||
| 18 | 18 | ||
| 19 | class VI_S final : public ServiceFramework<VI_S> { | 19 | class VI_S final : public ServiceFramework<VI_S> { |
| 20 | public: | 20 | public: |
| 21 | explicit VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 21 | explicit VI_S(NVFlinger::NVFlinger& nv_flinger); |
| 22 | ~VI_S() override; | 22 | ~VI_S() override; |
| 23 | 23 | ||
| 24 | private: | 24 | private: |
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 26 | 26 | ||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 27 | NVFlinger::NVFlinger& nv_flinger; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | } // namespace Service::VI | 30 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index 6b7329345..44e00a4f6 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp | |||
| @@ -8,8 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::VI { | 9 | namespace Service::VI { |
| 10 | 10 | ||
| 11 | VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | 11 | VI_U::VI_U(NVFlinger::NVFlinger& nv_flinger) : ServiceFramework{"vi:u"}, nv_flinger{nv_flinger} { |
| 12 | : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { | ||
| 13 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 14 | {0, &VI_U::GetDisplayService, "GetDisplayService"}, | 13 | {0, &VI_U::GetDisplayService, "GetDisplayService"}, |
| 15 | {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 14 | {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h index 19bdb73b0..b59f986f0 100644 --- a/src/core/hle/service/vi/vi_u.h +++ b/src/core/hle/service/vi/vi_u.h | |||
| @@ -18,13 +18,13 @@ namespace Service::VI { | |||
| 18 | 18 | ||
| 19 | class VI_U final : public ServiceFramework<VI_U> { | 19 | class VI_U final : public ServiceFramework<VI_U> { |
| 20 | public: | 20 | public: |
| 21 | explicit VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); | 21 | explicit VI_U(NVFlinger::NVFlinger& nv_flinger); |
| 22 | ~VI_U() override; | 22 | ~VI_U() override; |
| 23 | 23 | ||
| 24 | private: | 24 | private: |
| 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 25 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 26 | 26 | ||
| 27 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 27 | NVFlinger::NVFlinger& nv_flinger; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | } // namespace Service::VI | 30 | } // namespace Service::VI |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index deffe7379..d91c15561 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -198,10 +198,11 @@ AppLoader::~AppLoader() = default; | |||
| 198 | * @param system The system context to use. | 198 | * @param system The system context to use. |
| 199 | * @param file The file to retrieve the loader for | 199 | * @param file The file to retrieve the loader for |
| 200 | * @param type The file type | 200 | * @param type The file type |
| 201 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 201 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type | 202 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type |
| 202 | */ | 203 | */ |
| 203 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, | 204 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, |
| 204 | FileType type) { | 205 | FileType type, std::size_t program_index) { |
| 205 | switch (type) { | 206 | switch (type) { |
| 206 | // Standard ELF file format. | 207 | // Standard ELF file format. |
| 207 | case FileType::ELF: | 208 | case FileType::ELF: |
| @@ -222,7 +223,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 222 | // NX XCI (nX Card Image) file format. | 223 | // NX XCI (nX Card Image) file format. |
| 223 | case FileType::XCI: | 224 | case FileType::XCI: |
| 224 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), | 225 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), |
| 225 | system.GetContentProvider()); | 226 | system.GetContentProvider(), program_index); |
| 226 | 227 | ||
| 227 | // NX NAX (NintendoAesXts) file format. | 228 | // NX NAX (NintendoAesXts) file format. |
| 228 | case FileType::NAX: | 229 | case FileType::NAX: |
| @@ -231,7 +232,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 231 | // NX NSP (Nintendo Submission Package) file format | 232 | // NX NSP (Nintendo Submission Package) file format |
| 232 | case FileType::NSP: | 233 | case FileType::NSP: |
| 233 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), | 234 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), |
| 234 | system.GetContentProvider()); | 235 | system.GetContentProvider(), program_index); |
| 235 | 236 | ||
| 236 | // NX KIP (Kernel Internal Process) file format | 237 | // NX KIP (Kernel Internal Process) file format |
| 237 | case FileType::KIP: | 238 | case FileType::KIP: |
| @@ -246,7 +247,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 246 | } | 247 | } |
| 247 | } | 248 | } |
| 248 | 249 | ||
| 249 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file) { | 250 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 251 | std::size_t program_index) { | ||
| 250 | FileType type = IdentifyFile(file); | 252 | FileType type = IdentifyFile(file); |
| 251 | const FileType filename_type = GuessFromFilename(file->GetName()); | 253 | const FileType filename_type = GuessFromFilename(file->GetName()); |
| 252 | 254 | ||
| @@ -260,7 +262,7 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile | |||
| 260 | 262 | ||
| 261 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); | 263 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); |
| 262 | 264 | ||
| 263 | return GetFileLoader(system, std::move(file), type); | 265 | return GetFileLoader(system, std::move(file), type, program_index); |
| 264 | } | 266 | } |
| 265 | 267 | ||
| 266 | } // namespace Loader | 268 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 8dc2d7615..36e79e71d 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -293,9 +293,11 @@ protected: | |||
| 293 | * | 293 | * |
| 294 | * @param system The system context. | 294 | * @param system The system context. |
| 295 | * @param file The bootable file. | 295 | * @param file The bootable file. |
| 296 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 296 | * | 297 | * |
| 297 | * @return the best loader for this file. | 298 | * @return the best loader for this file. |
| 298 | */ | 299 | */ |
| 299 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file); | 300 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 301 | std::size_t program_index = 0); | ||
| 300 | 302 | ||
| 301 | } // namespace Loader | 303 | } // namespace Loader |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index e821937fd..928f64c8c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -23,8 +23,9 @@ namespace Loader { | |||
| 23 | 23 | ||
| 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, | 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, |
| 25 | const Service::FileSystem::FileSystemController& fsc, | 25 | const Service::FileSystem::FileSystemController& fsc, |
| 26 | const FileSys::ContentProvider& content_provider) | 26 | const FileSys::ContentProvider& content_provider, |
| 27 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), | 27 | std::size_t program_index) |
| 28 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)), | ||
| 28 | title_id(nsp->GetProgramTitleID()) { | 29 | title_id(nsp->GetProgramTitleID()) { |
| 29 | 30 | ||
| 30 | if (nsp->GetStatus() != ResultStatus::Success) { | 31 | if (nsp->GetStatus() != ResultStatus::Success) { |
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 36e8e3533..f0518ac47 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -28,7 +28,8 @@ class AppLoader_NSP final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_NSP(FileSys::VirtualFile file, | 29 | explicit AppLoader_NSP(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider); | 31 | const FileSys::ContentProvider& content_provider, |
| 32 | std::size_t program_index); | ||
| 32 | ~AppLoader_NSP() override; | 33 | ~AppLoader_NSP() override; |
| 33 | 34 | ||
| 34 | /** | 35 | /** |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 536e721fc..aaa250cea 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -22,8 +22,9 @@ namespace Loader { | |||
| 22 | 22 | ||
| 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, | 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, |
| 24 | const Service::FileSystem::FileSystemController& fsc, | 24 | const Service::FileSystem::FileSystemController& fsc, |
| 25 | const FileSys::ContentProvider& content_provider) | 25 | const FileSys::ContentProvider& content_provider, |
| 26 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), | 26 | std::size_t program_index) |
| 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)), | ||
| 27 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { | 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { |
| 28 | if (xci->GetStatus() != ResultStatus::Success) { | 29 | if (xci->GetStatus() != ResultStatus::Success) { |
| 29 | return; | 30 | return; |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 6dc1f9243..764dc8328 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -28,7 +28,8 @@ class AppLoader_XCI final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_XCI(FileSys::VirtualFile file, | 29 | explicit AppLoader_XCI(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider); | 31 | const FileSys::ContentProvider& content_provider, |
| 32 | std::size_t program_index); | ||
| 32 | ~AppLoader_XCI() override; | 33 | ~AppLoader_XCI() override; |
| 33 | 34 | ||
| 34 | /** | 35 | /** |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 1d1b2e08a..5682e5ca5 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -56,8 +56,8 @@ else() | |||
| 56 | -Werror=reorder | 56 | -Werror=reorder |
| 57 | -Werror=shadow | 57 | -Werror=shadow |
| 58 | -Werror=sign-compare | 58 | -Werror=sign-compare |
| 59 | -Werror=unused-but-set-parameter | 59 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> |
| 60 | -Werror=unused-but-set-variable | 60 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
| 61 | -Werror=unused-variable | 61 | -Werror=unused-variable |
| 62 | ) | 62 | ) |
| 63 | endif() | 63 | endif() |
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp index 74744d7f3..d748c1c04 100755 --- a/src/input_common/analog_from_button.cpp +++ b/src/input_common/analog_from_button.cpp | |||
| @@ -2,6 +2,10 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <chrono> | ||
| 6 | #include <cmath> | ||
| 7 | #include <thread> | ||
| 8 | #include "common/math_util.h" | ||
| 5 | #include "input_common/analog_from_button.h" | 9 | #include "input_common/analog_from_button.h" |
| 6 | 10 | ||
| 7 | namespace InputCommon { | 11 | namespace InputCommon { |
| @@ -11,31 +15,104 @@ public: | |||
| 11 | using Button = std::unique_ptr<Input::ButtonDevice>; | 15 | using Button = std::unique_ptr<Input::ButtonDevice>; |
| 12 | 16 | ||
| 13 | Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_, | 17 | Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_, |
| 14 | float modifier_scale_) | 18 | float modifier_scale_, float modifier_angle_) |
| 15 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), | 19 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), |
| 16 | right(std::move(right_)), modifier(std::move(modifier_)), | 20 | right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), |
| 17 | modifier_scale(modifier_scale_) {} | 21 | modifier_angle(modifier_angle_) { |
| 18 | 22 | update_thread = std::thread(&Analog::UpdateStatus, this); | |
| 19 | std::tuple<float, float> GetStatus() const override { | 23 | } |
| 20 | constexpr float SQRT_HALF = 0.707106781f; | ||
| 21 | int x = 0, y = 0; | ||
| 22 | 24 | ||
| 23 | if (right->GetStatus()) { | 25 | ~Analog() override { |
| 24 | ++x; | 26 | update_thread_running = false; |
| 27 | if (update_thread.joinable()) { | ||
| 28 | update_thread.join(); | ||
| 25 | } | 29 | } |
| 26 | if (left->GetStatus()) { | 30 | } |
| 27 | --x; | 31 | |
| 32 | void MoveToDirection(bool enable, float to_angle) { | ||
| 33 | if (!enable) { | ||
| 34 | return; | ||
| 28 | } | 35 | } |
| 29 | if (up->GetStatus()) { | 36 | constexpr float TAU = Common::PI * 2.0f; |
| 30 | ++y; | 37 | // Use wider angle to ease the transition. |
| 38 | constexpr float aperture = TAU * 0.15f; | ||
| 39 | const float top_limit = to_angle + aperture; | ||
| 40 | const float bottom_limit = to_angle - aperture; | ||
| 41 | |||
| 42 | if ((angle > to_angle && angle <= top_limit) || | ||
| 43 | (angle + TAU > to_angle && angle + TAU <= top_limit)) { | ||
| 44 | angle -= modifier_angle; | ||
| 45 | if (angle < 0) { | ||
| 46 | angle += TAU; | ||
| 47 | } | ||
| 48 | } else if ((angle >= bottom_limit && angle < to_angle) || | ||
| 49 | (angle - TAU >= bottom_limit && angle - TAU < to_angle)) { | ||
| 50 | angle += modifier_angle; | ||
| 51 | if (angle >= TAU) { | ||
| 52 | angle -= TAU; | ||
| 53 | } | ||
| 54 | } else { | ||
| 55 | angle = to_angle; | ||
| 31 | } | 56 | } |
| 32 | if (down->GetStatus()) { | 57 | } |
| 33 | --y; | 58 | |
| 59 | void UpdateStatus() { | ||
| 60 | while (update_thread_running) { | ||
| 61 | const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; | ||
| 62 | |||
| 63 | bool r = right->GetStatus(); | ||
| 64 | bool l = left->GetStatus(); | ||
| 65 | bool u = up->GetStatus(); | ||
| 66 | bool d = down->GetStatus(); | ||
| 67 | |||
| 68 | // Eliminate contradictory movements | ||
| 69 | if (r && l) { | ||
| 70 | r = false; | ||
| 71 | l = false; | ||
| 72 | } | ||
| 73 | if (u && d) { | ||
| 74 | u = false; | ||
| 75 | d = false; | ||
| 76 | } | ||
| 77 | |||
| 78 | // Move to the right | ||
| 79 | MoveToDirection(r && !u && !d, 0.0f); | ||
| 80 | |||
| 81 | // Move to the upper right | ||
| 82 | MoveToDirection(r && u && !d, Common::PI * 0.25f); | ||
| 83 | |||
| 84 | // Move up | ||
| 85 | MoveToDirection(u && !l && !r, Common::PI * 0.5f); | ||
| 86 | |||
| 87 | // Move to the upper left | ||
| 88 | MoveToDirection(l && u && !d, Common::PI * 0.75f); | ||
| 89 | |||
| 90 | // Move to the left | ||
| 91 | MoveToDirection(l && !u && !d, Common::PI); | ||
| 92 | |||
| 93 | // Move to the bottom left | ||
| 94 | MoveToDirection(l && !u && d, Common::PI * 1.25f); | ||
| 95 | |||
| 96 | // Move down | ||
| 97 | MoveToDirection(d && !l && !r, Common::PI * 1.5f); | ||
| 98 | |||
| 99 | // Move to the bottom right | ||
| 100 | MoveToDirection(r && !u && d, Common::PI * 1.75f); | ||
| 101 | |||
| 102 | // Move if a key is pressed | ||
| 103 | if (r || l || u || d) { | ||
| 104 | amplitude = coef; | ||
| 105 | } else { | ||
| 106 | amplitude = 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | // Delay the update rate to 100hz | ||
| 110 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||
| 34 | } | 111 | } |
| 112 | } | ||
| 35 | 113 | ||
| 36 | const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; | 114 | std::tuple<float, float> GetStatus() const override { |
| 37 | return std::make_tuple(static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF), | 115 | return std::make_tuple(std::cos(angle) * amplitude, std::sin(angle) * amplitude); |
| 38 | static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); | ||
| 39 | } | 116 | } |
| 40 | 117 | ||
| 41 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 118 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| @@ -59,6 +136,11 @@ private: | |||
| 59 | Button right; | 136 | Button right; |
| 60 | Button modifier; | 137 | Button modifier; |
| 61 | float modifier_scale; | 138 | float modifier_scale; |
| 139 | float modifier_angle; | ||
| 140 | float angle{}; | ||
| 141 | float amplitude{}; | ||
| 142 | std::thread update_thread; | ||
| 143 | bool update_thread_running{true}; | ||
| 62 | }; | 144 | }; |
| 63 | 145 | ||
| 64 | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { | 146 | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { |
| @@ -69,8 +151,10 @@ std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::Para | |||
| 69 | auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine)); | 151 | auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine)); |
| 70 | auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); | 152 | auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); |
| 71 | auto modifier_scale = params.Get("modifier_scale", 0.5f); | 153 | auto modifier_scale = params.Get("modifier_scale", 0.5f); |
| 154 | auto modifier_angle = params.Get("modifier_angle", 0.035f); | ||
| 72 | return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left), | 155 | return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left), |
| 73 | std::move(right), std::move(modifier), modifier_scale); | 156 | std::move(right), std::move(modifier), modifier_scale, |
| 157 | modifier_angle); | ||
| 74 | } | 158 | } |
| 75 | 159 | ||
| 76 | } // namespace InputCommon | 160 | } // namespace InputCommon |
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 4e8c7e8b9..4d1052414 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -299,7 +299,8 @@ public: | |||
| 299 | return gcadapter->RumblePlay(port, 0); | 299 | return gcadapter->RumblePlay(port, 0); |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { | 302 | bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high, |
| 303 | [[maybe_unused]] f32 freq_high) const override { | ||
| 303 | const auto mean_amplitude = (amp_low + amp_high) * 0.5f; | 304 | const auto mean_amplitude = (amp_low + amp_high) * 0.5f; |
| 304 | const auto processed_amplitude = | 305 | const auto processed_amplitude = |
| 305 | static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); | 306 | static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index c16928e98..7827e324c 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -400,7 +400,8 @@ public: | |||
| 400 | return joystick->RumblePlay(0, 0); | 400 | return joystick->RumblePlay(0, 0); |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { | 403 | bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high, |
| 404 | [[maybe_unused]] f32 freq_high) const override { | ||
| 404 | const auto process_amplitude = [](f32 amplitude) { | 405 | const auto process_amplitude = [](f32 amplitude) { |
| 405 | return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF); | 406 | return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF); |
| 406 | }; | 407 | }; |
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index 10b07d338..c0bb90048 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp | |||
| @@ -189,11 +189,11 @@ void Client::ReloadSocket(const std::string& host, u16 port, std::size_t pad_ind | |||
| 189 | StartCommunication(client, host, port, pad_index, client_id); | 189 | StartCommunication(client, host, port, pad_index, client_id); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | void Client::OnVersion(Response::Version data) { | 192 | void Client::OnVersion([[maybe_unused]] Response::Version data) { |
| 193 | LOG_TRACE(Input, "Version packet received: {}", data.version); | 193 | LOG_TRACE(Input, "Version packet received: {}", data.version); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | void Client::OnPortInfo(Response::PortInfo data) { | 196 | void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { |
| 197 | LOG_TRACE(Input, "PortInfo packet received: {}", data.model); | 197 | LOG_TRACE(Input, "PortInfo packet received: {}", data.model); |
| 198 | } | 198 | } |
| 199 | 199 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 2ccca1993..c869bb0e2 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -151,8 +151,8 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 151 | 151 | ||
| 152 | rasterizer->TickFrame(); | 152 | rasterizer->TickFrame(); |
| 153 | 153 | ||
| 154 | render_window.PollEvents(); | ||
| 155 | context->SwapBuffers(); | 154 | context->SwapBuffers(); |
| 155 | render_window.OnFrameDisplayed(); | ||
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | 158 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index da5c550ea..fffae528e 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include <boost/functional/hash.hpp> | 9 | #include <boost/functional/hash.hpp> |
| 10 | 10 | ||
| 11 | #include "common/bit_cast.h" | ||
| 11 | #include "common/cityhash.h" | 12 | #include "common/cityhash.h" |
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 14 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| @@ -60,7 +61,13 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta | |||
| 60 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); | 61 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); |
| 61 | topology.Assign(regs.draw.topology); | 62 | topology.Assign(regs.draw.topology); |
| 62 | 63 | ||
| 63 | std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast | 64 | alpha_raw = 0; |
| 65 | const auto test_func = | ||
| 66 | regs.alpha_test_enabled == 1 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always; | ||
| 67 | alpha_test_func.Assign(PackComparisonOp(test_func)); | ||
| 68 | alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref); | ||
| 69 | |||
| 70 | point_size = Common::BitCast<u32>(regs.point_size); | ||
| 64 | 71 | ||
| 65 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 72 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 66 | binding_divisors[index] = | 73 | binding_divisors[index] = |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 2c18eeaae..42480e8d0 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -187,6 +187,13 @@ struct FixedPipelineState { | |||
| 187 | BitField<23, 1, u32> rasterize_enable; | 187 | BitField<23, 1, u32> rasterize_enable; |
| 188 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; | 188 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; |
| 189 | }; | 189 | }; |
| 190 | |||
| 191 | u32 alpha_test_ref; ///< Alpha test reference value | ||
| 192 | union { | ||
| 193 | u32 alpha_raw; | ||
| 194 | BitField<0, 3, u32> alpha_test_func; | ||
| 195 | }; | ||
| 196 | |||
| 190 | u32 point_size; | 197 | u32 point_size; |
| 191 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; | 198 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; |
| 192 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; | 199 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index f2610868e..a2173edd2 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -252,8 +252,6 @@ RendererVulkan::~RendererVulkan() { | |||
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 254 | void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 255 | render_window.PollEvents(); | ||
| 256 | |||
| 257 | if (!framebuffer) { | 255 | if (!framebuffer) { |
| 258 | return; | 256 | return; |
| 259 | } | 257 | } |
| @@ -283,7 +281,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 283 | rasterizer->TickFrame(); | 281 | rasterizer->TickFrame(); |
| 284 | } | 282 | } |
| 285 | 283 | ||
| 286 | render_window.PollEvents(); | 284 | render_window.OnFrameDisplayed(); |
| 287 | } | 285 | } |
| 288 | 286 | ||
| 289 | bool RendererVulkan::Init() { | 287 | bool RendererVulkan::Init() { |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index dedc9c466..f9efe526d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "common/bit_cast.h" | ||
| 10 | #include "common/microprofile.h" | 11 | #include "common/microprofile.h" |
| 11 | #include "core/core.h" | 12 | #include "core/core.h" |
| 12 | #include "core/memory.h" | 13 | #include "core/memory.h" |
| @@ -344,6 +345,11 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { | |||
| 344 | } | 345 | } |
| 345 | specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; | 346 | specialization.ndc_minus_one_to_one = fixed_state.ndc_minus_one_to_one; |
| 346 | 347 | ||
| 348 | // Alpha test | ||
| 349 | specialization.alpha_test_func = | ||
| 350 | FixedPipelineState::UnpackComparisonOp(fixed_state.alpha_test_func.Value()); | ||
| 351 | specialization.alpha_test_ref = Common::BitCast<float>(fixed_state.alpha_test_ref); | ||
| 352 | |||
| 347 | SPIRVProgram program; | 353 | SPIRVProgram program; |
| 348 | std::vector<VkDescriptorSetLayoutBinding> bindings; | 354 | std::vector<VkDescriptorSetLayoutBinding> bindings; |
| 349 | 355 | ||
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index a20452b87..1c52f40bb 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -2075,6 +2075,45 @@ private: | |||
| 2075 | return {}; | 2075 | return {}; |
| 2076 | } | 2076 | } |
| 2077 | 2077 | ||
| 2078 | Id MaxwellToSpirvComparison(Maxwell::ComparisonOp compare_op, Id operand_1, Id operand_2) { | ||
| 2079 | using Compare = Maxwell::ComparisonOp; | ||
| 2080 | switch (compare_op) { | ||
| 2081 | case Compare::NeverOld: | ||
| 2082 | return v_false; // Never let the test pass | ||
| 2083 | case Compare::LessOld: | ||
| 2084 | return OpFOrdLessThan(t_bool, operand_1, operand_2); | ||
| 2085 | case Compare::EqualOld: | ||
| 2086 | return OpFOrdEqual(t_bool, operand_1, operand_2); | ||
| 2087 | case Compare::LessEqualOld: | ||
| 2088 | return OpFOrdLessThanEqual(t_bool, operand_1, operand_2); | ||
| 2089 | case Compare::GreaterOld: | ||
| 2090 | return OpFOrdGreaterThan(t_bool, operand_1, operand_2); | ||
| 2091 | case Compare::NotEqualOld: | ||
| 2092 | return OpFOrdNotEqual(t_bool, operand_1, operand_2); | ||
| 2093 | case Compare::GreaterEqualOld: | ||
| 2094 | return OpFOrdGreaterThanEqual(t_bool, operand_1, operand_2); | ||
| 2095 | default: | ||
| 2096 | UNREACHABLE(); | ||
| 2097 | } | ||
| 2098 | } | ||
| 2099 | |||
| 2100 | void AlphaTest(Id pointer) { | ||
| 2101 | if (specialization.alpha_test_func == Maxwell::ComparisonOp::AlwaysOld) { | ||
| 2102 | return; | ||
| 2103 | } | ||
| 2104 | const Id true_label = OpLabel(); | ||
| 2105 | const Id discard_label = OpLabel(); | ||
| 2106 | const Id alpha_reference = Constant(t_float, specialization.alpha_test_ref); | ||
| 2107 | const Id alpha_value = OpLoad(t_float, pointer); | ||
| 2108 | const Id condition = | ||
| 2109 | MaxwellToSpirvComparison(specialization.alpha_test_func, alpha_value, alpha_reference); | ||
| 2110 | |||
| 2111 | OpBranchConditional(condition, true_label, discard_label); | ||
| 2112 | AddLabel(discard_label); | ||
| 2113 | OpKill(); | ||
| 2114 | AddLabel(true_label); | ||
| 2115 | } | ||
| 2116 | |||
| 2078 | void PreExit() { | 2117 | void PreExit() { |
| 2079 | if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { | 2118 | if (stage == ShaderType::Vertex && specialization.ndc_minus_one_to_one) { |
| 2080 | const u32 position_index = out_indices.position.value(); | 2119 | const u32 position_index = out_indices.position.value(); |
| @@ -2097,8 +2136,6 @@ private: | |||
| 2097 | UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, | 2136 | UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, |
| 2098 | "Sample mask write is unimplemented"); | 2137 | "Sample mask write is unimplemented"); |
| 2099 | 2138 | ||
| 2100 | // TODO(Rodrigo): Alpha testing | ||
| 2101 | |||
| 2102 | // Write the color outputs using the data in the shader registers, disabled | 2139 | // Write the color outputs using the data in the shader registers, disabled |
| 2103 | // rendertargets/components are skipped in the register assignment. | 2140 | // rendertargets/components are skipped in the register assignment. |
| 2104 | u32 current_reg = 0; | 2141 | u32 current_reg = 0; |
| @@ -2110,6 +2147,9 @@ private: | |||
| 2110 | } | 2147 | } |
| 2111 | const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); | 2148 | const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); |
| 2112 | OpStore(pointer, SafeGetRegister(current_reg)); | 2149 | OpStore(pointer, SafeGetRegister(current_reg)); |
| 2150 | if (rt == 0 && component == 3) { | ||
| 2151 | AlphaTest(pointer); | ||
| 2152 | } | ||
| 2113 | ++current_reg; | 2153 | ++current_reg; |
| 2114 | } | 2154 | } |
| 2115 | } | 2155 | } |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index 2b0e90396..cd3d0a415 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h | |||
| @@ -95,6 +95,8 @@ struct Specialization final { | |||
| 95 | std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; | 95 | std::bitset<Maxwell::NumVertexAttributes> enabled_attributes; |
| 96 | std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; | 96 | std::array<Maxwell::VertexAttribute::Type, Maxwell::NumVertexAttributes> attribute_types{}; |
| 97 | bool ndc_minus_one_to_one{}; | 97 | bool ndc_minus_one_to_one{}; |
| 98 | float alpha_test_ref{}; | ||
| 99 | Maxwell::ComparisonOp alpha_test_func{}; | ||
| 98 | }; | 100 | }; |
| 99 | // Old gcc versions don't consider this trivially copyable. | 101 | // Old gcc versions don't consider this trivially copyable. |
| 100 | // static_assert(std::is_trivially_copyable_v<Specialization>); | 102 | // static_assert(std::is_trivially_copyable_v<Specialization>); |
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index 618d309d2..1ed4212ee 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp | |||
| @@ -212,10 +212,10 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) { | |||
| 212 | return 0; | 212 | return 0; |
| 213 | case TextureFormat::R8G24: | 213 | case TextureFormat::R8G24: |
| 214 | if (component == 0) { | 214 | if (component == 0) { |
| 215 | return 8; | 215 | return 24; |
| 216 | } | 216 | } |
| 217 | if (component == 1) { | 217 | if (component == 1) { |
| 218 | return 24; | 218 | return 8; |
| 219 | } | 219 | } |
| 220 | return 0; | 220 | return 0; |
| 221 | case TextureFormat::R8G8: | 221 | case TextureFormat::R8G8: |
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp index 8ecfec770..6944478f3 100644 --- a/src/yuzu/applets/controller.cpp +++ b/src/yuzu/applets/controller.cpp | |||
| @@ -72,40 +72,6 @@ bool IsControllerCompatible(Settings::ControllerType controller_type, | |||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | /// Maps the controller type combobox index to Controller Type enum | ||
| 76 | constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) { | ||
| 77 | switch (index) { | ||
| 78 | case 0: | ||
| 79 | default: | ||
| 80 | return Settings::ControllerType::ProController; | ||
| 81 | case 1: | ||
| 82 | return Settings::ControllerType::DualJoyconDetached; | ||
| 83 | case 2: | ||
| 84 | return Settings::ControllerType::LeftJoycon; | ||
| 85 | case 3: | ||
| 86 | return Settings::ControllerType::RightJoycon; | ||
| 87 | case 4: | ||
| 88 | return Settings::ControllerType::Handheld; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Maps the Controller Type enum to controller type combobox index | ||
| 93 | constexpr int GetIndexFromControllerType(Settings::ControllerType type) { | ||
| 94 | switch (type) { | ||
| 95 | case Settings::ControllerType::ProController: | ||
| 96 | default: | ||
| 97 | return 0; | ||
| 98 | case Settings::ControllerType::DualJoyconDetached: | ||
| 99 | return 1; | ||
| 100 | case Settings::ControllerType::LeftJoycon: | ||
| 101 | return 2; | ||
| 102 | case Settings::ControllerType::RightJoycon: | ||
| 103 | return 3; | ||
| 104 | case Settings::ControllerType::Handheld: | ||
| 105 | return 4; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | } // namespace | 75 | } // namespace |
| 110 | 76 | ||
| 111 | QtControllerSelectorDialog::QtControllerSelectorDialog( | 77 | QtControllerSelectorDialog::QtControllerSelectorDialog( |
| @@ -184,6 +150,11 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( | |||
| 184 | // This avoids unintentionally changing the states of elements while loading them in. | 150 | // This avoids unintentionally changing the states of elements while loading them in. |
| 185 | SetSupportedControllers(); | 151 | SetSupportedControllers(); |
| 186 | DisableUnsupportedPlayers(); | 152 | DisableUnsupportedPlayers(); |
| 153 | |||
| 154 | for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { | ||
| 155 | SetEmulatedControllers(player_index); | ||
| 156 | } | ||
| 157 | |||
| 187 | LoadConfiguration(); | 158 | LoadConfiguration(); |
| 188 | 159 | ||
| 189 | for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { | 160 | for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { |
| @@ -223,8 +194,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( | |||
| 223 | 194 | ||
| 224 | if (i == 0) { | 195 | if (i == 0) { |
| 225 | connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged), | 196 | connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged), |
| 226 | [this](int index) { | 197 | [this, i](int index) { |
| 227 | UpdateDockedState(GetControllerTypeFromIndex(index) == | 198 | UpdateDockedState(GetControllerTypeFromIndex(index, i) == |
| 228 | Settings::ControllerType::Handheld); | 199 | Settings::ControllerType::Handheld); |
| 229 | }); | 200 | }); |
| 230 | } | 201 | } |
| @@ -281,8 +252,8 @@ void QtControllerSelectorDialog::LoadConfiguration() { | |||
| 281 | (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); | 252 | (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); |
| 282 | player_groupboxes[index]->setChecked(connected); | 253 | player_groupboxes[index]->setChecked(connected); |
| 283 | connected_controller_checkboxes[index]->setChecked(connected); | 254 | connected_controller_checkboxes[index]->setChecked(connected); |
| 284 | emulated_controllers[index]->setCurrentIndex( | 255 | emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType( |
| 285 | GetIndexFromControllerType(Settings::values.players.GetValue()[index].controller_type)); | 256 | Settings::values.players.GetValue()[index].controller_type, index)); |
| 286 | } | 257 | } |
| 287 | 258 | ||
| 288 | UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); | 259 | UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); |
| @@ -338,7 +309,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() { | |||
| 338 | } | 309 | } |
| 339 | 310 | ||
| 340 | const auto compatible = IsControllerCompatible( | 311 | const auto compatible = IsControllerCompatible( |
| 341 | GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()), | 312 | GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex(), index), |
| 342 | parameters); | 313 | parameters); |
| 343 | 314 | ||
| 344 | // If any controller is found to be incompatible, return false early. | 315 | // If any controller is found to be incompatible, return false early. |
| @@ -422,6 +393,63 @@ void QtControllerSelectorDialog::SetSupportedControllers() { | |||
| 422 | } | 393 | } |
| 423 | } | 394 | } |
| 424 | 395 | ||
| 396 | void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) { | ||
| 397 | auto& pairs = index_controller_type_pairs[player_index]; | ||
| 398 | |||
| 399 | pairs.clear(); | ||
| 400 | emulated_controllers[player_index]->clear(); | ||
| 401 | |||
| 402 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 403 | Settings::ControllerType::ProController); | ||
| 404 | emulated_controllers[player_index]->addItem(tr("Pro Controller")); | ||
| 405 | |||
| 406 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 407 | Settings::ControllerType::DualJoyconDetached); | ||
| 408 | emulated_controllers[player_index]->addItem(tr("Dual Joycons")); | ||
| 409 | |||
| 410 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 411 | Settings::ControllerType::LeftJoycon); | ||
| 412 | emulated_controllers[player_index]->addItem(tr("Left Joycon")); | ||
| 413 | |||
| 414 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 415 | Settings::ControllerType::RightJoycon); | ||
| 416 | emulated_controllers[player_index]->addItem(tr("Right Joycon")); | ||
| 417 | |||
| 418 | if (player_index == 0) { | ||
| 419 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 420 | Settings::ControllerType::Handheld); | ||
| 421 | emulated_controllers[player_index]->addItem(tr("Handheld")); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( | ||
| 426 | int index, std::size_t player_index) const { | ||
| 427 | const auto& pairs = index_controller_type_pairs[player_index]; | ||
| 428 | |||
| 429 | const auto it = std::find_if(pairs.begin(), pairs.end(), | ||
| 430 | [index](const auto& pair) { return pair.first == index; }); | ||
| 431 | |||
| 432 | if (it == pairs.end()) { | ||
| 433 | return Settings::ControllerType::ProController; | ||
| 434 | } | ||
| 435 | |||
| 436 | return it->second; | ||
| 437 | } | ||
| 438 | |||
| 439 | int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type, | ||
| 440 | std::size_t player_index) const { | ||
| 441 | const auto& pairs = index_controller_type_pairs[player_index]; | ||
| 442 | |||
| 443 | const auto it = std::find_if(pairs.begin(), pairs.end(), | ||
| 444 | [type](const auto& pair) { return pair.second == type; }); | ||
| 445 | |||
| 446 | if (it == pairs.end()) { | ||
| 447 | return 0; | ||
| 448 | } | ||
| 449 | |||
| 450 | return it->first; | ||
| 451 | } | ||
| 452 | |||
| 425 | void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) { | 453 | void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) { |
| 426 | if (!player_groupboxes[player_index]->isChecked()) { | 454 | if (!player_groupboxes[player_index]->isChecked()) { |
| 427 | connected_controller_icons[player_index]->setStyleSheet(QString{}); | 455 | connected_controller_icons[player_index]->setStyleSheet(QString{}); |
| @@ -430,7 +458,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) | |||
| 430 | } | 458 | } |
| 431 | 459 | ||
| 432 | const QString stylesheet = [this, player_index] { | 460 | const QString stylesheet = [this, player_index] { |
| 433 | switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) { | 461 | switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), |
| 462 | player_index)) { | ||
| 434 | case Settings::ControllerType::ProController: | 463 | case Settings::ControllerType::ProController: |
| 435 | return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); | 464 | return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); |
| 436 | case Settings::ControllerType::DualJoyconDetached: | 465 | case Settings::ControllerType::DualJoyconDetached: |
| @@ -446,6 +475,12 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) | |||
| 446 | } | 475 | } |
| 447 | }(); | 476 | }(); |
| 448 | 477 | ||
| 478 | if (stylesheet.isEmpty()) { | ||
| 479 | connected_controller_icons[player_index]->setStyleSheet(QString{}); | ||
| 480 | player_labels[player_index]->show(); | ||
| 481 | return; | ||
| 482 | } | ||
| 483 | |||
| 449 | const QString theme = [] { | 484 | const QString theme = [] { |
| 450 | if (QIcon::themeName().contains(QStringLiteral("dark"))) { | 485 | if (QIcon::themeName().contains(QStringLiteral("dark"))) { |
| 451 | return QStringLiteral("_dark"); | 486 | return QStringLiteral("_dark"); |
| @@ -463,8 +498,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) | |||
| 463 | void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { | 498 | void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { |
| 464 | auto& player = Settings::values.players.GetValue()[player_index]; | 499 | auto& player = Settings::values.players.GetValue()[player_index]; |
| 465 | 500 | ||
| 466 | const auto controller_type = | 501 | const auto controller_type = GetControllerTypeFromIndex( |
| 467 | GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()); | 502 | emulated_controllers[player_index]->currentIndex(), player_index); |
| 468 | const auto player_connected = player_groupboxes[player_index]->isChecked() && | 503 | const auto player_connected = player_groupboxes[player_index]->isChecked() && |
| 469 | controller_type != Settings::ControllerType::Handheld; | 504 | controller_type != Settings::ControllerType::Handheld; |
| 470 | 505 | ||
| @@ -507,8 +542,8 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) | |||
| 507 | 542 | ||
| 508 | void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { | 543 | void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { |
| 509 | if (!player_groupboxes[player_index]->isChecked() || | 544 | if (!player_groupboxes[player_index]->isChecked() || |
| 510 | GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) == | 545 | GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), |
| 511 | Settings::ControllerType::Handheld) { | 546 | player_index) == Settings::ControllerType::Handheld) { |
| 512 | led_patterns_boxes[player_index][0]->setChecked(false); | 547 | led_patterns_boxes[player_index][0]->setChecked(false); |
| 513 | led_patterns_boxes[player_index][1]->setChecked(false); | 548 | led_patterns_boxes[player_index][1]->setChecked(false); |
| 514 | led_patterns_boxes[player_index][2]->setChecked(false); | 549 | led_patterns_boxes[player_index][2]->setChecked(false); |
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h index 4344e1dd0..7a421d856 100644 --- a/src/yuzu/applets/controller.h +++ b/src/yuzu/applets/controller.h | |||
| @@ -22,6 +22,10 @@ namespace InputCommon { | |||
| 22 | class InputSubsystem; | 22 | class InputSubsystem; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | namespace Settings { | ||
| 26 | enum class ControllerType; | ||
| 27 | } | ||
| 28 | |||
| 25 | namespace Ui { | 29 | namespace Ui { |
| 26 | class QtControllerSelectorDialog; | 30 | class QtControllerSelectorDialog; |
| 27 | } | 31 | } |
| @@ -57,6 +61,15 @@ private: | |||
| 57 | // Sets the controller icons for "Supported Controller Types". | 61 | // Sets the controller icons for "Supported Controller Types". |
| 58 | void SetSupportedControllers(); | 62 | void SetSupportedControllers(); |
| 59 | 63 | ||
| 64 | // Sets the emulated controllers per player. | ||
| 65 | void SetEmulatedControllers(std::size_t player_index); | ||
| 66 | |||
| 67 | // Gets the Controller Type for a given controller combobox index per player. | ||
| 68 | Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const; | ||
| 69 | |||
| 70 | // Gets the controller combobox index for a given Controller Type per player. | ||
| 71 | int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const; | ||
| 72 | |||
| 60 | // Updates the controller icons per player. | 73 | // Updates the controller icons per player. |
| 61 | void UpdateControllerIcon(std::size_t player_index); | 74 | void UpdateControllerIcon(std::size_t player_index); |
| 62 | 75 | ||
| @@ -114,6 +127,10 @@ private: | |||
| 114 | // Comboboxes with a list of emulated controllers per player. | 127 | // Comboboxes with a list of emulated controllers per player. |
| 115 | std::array<QComboBox*, NUM_PLAYERS> emulated_controllers; | 128 | std::array<QComboBox*, NUM_PLAYERS> emulated_controllers; |
| 116 | 129 | ||
| 130 | /// Pairs of emulated controller index and Controller Type enum per player. | ||
| 131 | std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS> | ||
| 132 | index_controller_type_pairs; | ||
| 133 | |||
| 117 | // Labels representing the number of connected controllers | 134 | // Labels representing the number of connected controllers |
| 118 | // above the "Connected Controllers" checkboxes. | 135 | // above the "Connected Controllers" checkboxes. |
| 119 | std::array<QLabel*, NUM_PLAYERS> connected_controller_labels; | 136 | std::array<QLabel*, NUM_PLAYERS> connected_controller_labels; |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d62b0efc2..ea8f0d7b1 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -302,13 +302,19 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | |||
| 302 | this->setMouseTracking(true); | 302 | this->setMouseTracking(true); |
| 303 | 303 | ||
| 304 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); | 304 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); |
| 305 | connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, | ||
| 306 | Qt::QueuedConnection); | ||
| 307 | } | ||
| 308 | |||
| 309 | void GRenderWindow::ExecuteProgram(std::size_t program_index) { | ||
| 310 | emit ExecuteProgramSignal(program_index); | ||
| 305 | } | 311 | } |
| 306 | 312 | ||
| 307 | GRenderWindow::~GRenderWindow() { | 313 | GRenderWindow::~GRenderWindow() { |
| 308 | input_subsystem->Shutdown(); | 314 | input_subsystem->Shutdown(); |
| 309 | } | 315 | } |
| 310 | 316 | ||
| 311 | void GRenderWindow::PollEvents() { | 317 | void GRenderWindow::OnFrameDisplayed() { |
| 312 | if (!first_frame) { | 318 | if (!first_frame) { |
| 313 | first_frame = true; | 319 | first_frame = true; |
| 314 | emit FirstFrameDisplayed(); | 320 | emit FirstFrameDisplayed(); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index ca35cf831..a6d788d40 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -131,7 +131,7 @@ public: | |||
| 131 | ~GRenderWindow() override; | 131 | ~GRenderWindow() override; |
| 132 | 132 | ||
| 133 | // EmuWindow implementation. | 133 | // EmuWindow implementation. |
| 134 | void PollEvents() override; | 134 | void OnFrameDisplayed() override; |
| 135 | bool IsShown() const override; | 135 | bool IsShown() const override; |
| 136 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | 136 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; |
| 137 | 137 | ||
| @@ -166,6 +166,12 @@ public: | |||
| 166 | 166 | ||
| 167 | std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; | 167 | std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; |
| 168 | 168 | ||
| 169 | /** | ||
| 170 | * Instructs the window to re-launch the application using the specified program_index. | ||
| 171 | * @param program_index Specifies the index within the application of the program to launch. | ||
| 172 | */ | ||
| 173 | void ExecuteProgram(std::size_t program_index); | ||
| 174 | |||
| 169 | public slots: | 175 | public slots: |
| 170 | void OnEmulationStarting(EmuThread* emu_thread); | 176 | void OnEmulationStarting(EmuThread* emu_thread); |
| 171 | void OnEmulationStopping(); | 177 | void OnEmulationStopping(); |
| @@ -175,6 +181,7 @@ signals: | |||
| 175 | /// Emitted when the window is closed | 181 | /// Emitted when the window is closed |
| 176 | void Closed(); | 182 | void Closed(); |
| 177 | void FirstFrameDisplayed(); | 183 | void FirstFrameDisplayed(); |
| 184 | void ExecuteProgramSignal(std::size_t program_index); | ||
| 178 | 185 | ||
| 179 | private: | 186 | private: |
| 180 | void TouchBeginEvent(const QTouchEvent* event); | 187 | void TouchBeginEvent(const QTouchEvent* event); |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 56ab32a35..918bfb56b 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #include "yuzu/configuration/input_profiles.h" | 27 | #include "yuzu/configuration/input_profiles.h" |
| 28 | #include "yuzu/util/limitable_input_dialog.h" | 28 | #include "yuzu/util/limitable_input_dialog.h" |
| 29 | 29 | ||
| 30 | using namespace Service::HID; | ||
| 31 | |||
| 30 | const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> | 32 | const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> |
| 31 | ConfigureInputPlayer::analog_sub_buttons{{ | 33 | ConfigureInputPlayer::analog_sub_buttons{{ |
| 32 | "up", | 34 | "up", |
| @@ -47,48 +49,12 @@ void UpdateController(Settings::ControllerType controller_type, std::size_t npad | |||
| 47 | } | 49 | } |
| 48 | Service::SM::ServiceManager& sm = system.ServiceManager(); | 50 | Service::SM::ServiceManager& sm = system.ServiceManager(); |
| 49 | 51 | ||
| 50 | auto& npad = | 52 | auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>( |
| 51 | sm.GetService<Service::HID::Hid>("hid") | 53 | HidController::NPad); |
| 52 | ->GetAppletResource() | ||
| 53 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); | ||
| 54 | 54 | ||
| 55 | npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); | 55 | npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | /// Maps the controller type combobox index to Controller Type enum | ||
| 59 | constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) { | ||
| 60 | switch (index) { | ||
| 61 | case 0: | ||
| 62 | default: | ||
| 63 | return Settings::ControllerType::ProController; | ||
| 64 | case 1: | ||
| 65 | return Settings::ControllerType::DualJoyconDetached; | ||
| 66 | case 2: | ||
| 67 | return Settings::ControllerType::LeftJoycon; | ||
| 68 | case 3: | ||
| 69 | return Settings::ControllerType::RightJoycon; | ||
| 70 | case 4: | ||
| 71 | return Settings::ControllerType::Handheld; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | /// Maps the Controller Type enum to controller type combobox index | ||
| 76 | constexpr int GetIndexFromControllerType(Settings::ControllerType type) { | ||
| 77 | switch (type) { | ||
| 78 | case Settings::ControllerType::ProController: | ||
| 79 | default: | ||
| 80 | return 0; | ||
| 81 | case Settings::ControllerType::DualJoyconDetached: | ||
| 82 | return 1; | ||
| 83 | case Settings::ControllerType::LeftJoycon: | ||
| 84 | return 2; | ||
| 85 | case Settings::ControllerType::RightJoycon: | ||
| 86 | return 3; | ||
| 87 | case Settings::ControllerType::Handheld: | ||
| 88 | return 4; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | QString GetKeyName(int key_code) { | 58 | QString GetKeyName(int key_code) { |
| 93 | switch (key_code) { | 59 | switch (key_code) { |
| 94 | case Qt::LeftButton: | 60 | case Qt::LeftButton: |
| @@ -453,18 +419,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 453 | connect(ui->groupConnectedController, &QGroupBox::toggled, | 419 | connect(ui->groupConnectedController, &QGroupBox::toggled, |
| 454 | [this](bool checked) { emit Connected(checked); }); | 420 | [this](bool checked) { emit Connected(checked); }); |
| 455 | 421 | ||
| 456 | // Set up controller type. Only Player 1 can choose Handheld. | ||
| 457 | ui->comboControllerType->clear(); | ||
| 458 | |||
| 459 | QStringList controller_types = { | ||
| 460 | tr("Pro Controller"), | ||
| 461 | tr("Dual Joycons"), | ||
| 462 | tr("Left Joycon"), | ||
| 463 | tr("Right Joycon"), | ||
| 464 | }; | ||
| 465 | |||
| 466 | if (player_index == 0) { | 422 | if (player_index == 0) { |
| 467 | controller_types.append(tr("Handheld")); | ||
| 468 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), | 423 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), |
| 469 | [this](int index) { | 424 | [this](int index) { |
| 470 | emit HandheldStateChanged(GetControllerTypeFromIndex(index) == | 425 | emit HandheldStateChanged(GetControllerTypeFromIndex(index) == |
| @@ -480,12 +435,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 480 | if (debug) { | 435 | if (debug) { |
| 481 | ui->buttonScreenshot->setEnabled(false); | 436 | ui->buttonScreenshot->setEnabled(false); |
| 482 | ui->buttonHome->setEnabled(false); | 437 | ui->buttonHome->setEnabled(false); |
| 483 | QStringList debug_controller_types = { | 438 | ui->comboControllerType->addItem(tr("Pro Controller")); |
| 484 | tr("Pro Controller"), | ||
| 485 | }; | ||
| 486 | ui->comboControllerType->addItems(debug_controller_types); | ||
| 487 | } else { | 439 | } else { |
| 488 | ui->comboControllerType->addItems(controller_types); | 440 | SetConnectableControllers(); |
| 489 | } | 441 | } |
| 490 | 442 | ||
| 491 | UpdateControllerIcon(); | 443 | UpdateControllerIcon(); |
| @@ -667,7 +619,7 @@ void ConfigureInputPlayer::LoadConfiguration() { | |||
| 667 | return; | 619 | return; |
| 668 | } | 620 | } |
| 669 | 621 | ||
| 670 | ui->comboControllerType->setCurrentIndex(static_cast<int>(player.controller_type)); | 622 | ui->comboControllerType->setCurrentIndex(GetIndexFromControllerType(player.controller_type)); |
| 671 | ui->groupConnectedController->setChecked( | 623 | ui->groupConnectedController->setChecked( |
| 672 | player.connected || | 624 | player.connected || |
| 673 | (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected)); | 625 | (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected)); |
| @@ -841,6 +793,82 @@ void ConfigureInputPlayer::UpdateUI() { | |||
| 841 | } | 793 | } |
| 842 | } | 794 | } |
| 843 | 795 | ||
| 796 | void ConfigureInputPlayer::SetConnectableControllers() { | ||
| 797 | const auto add_controllers = [this](bool enable_all, | ||
| 798 | Controller_NPad::NpadStyleSet npad_style_set = {}) { | ||
| 799 | index_controller_type_pairs.clear(); | ||
| 800 | ui->comboControllerType->clear(); | ||
| 801 | |||
| 802 | if (enable_all || npad_style_set.pro_controller == 1) { | ||
| 803 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 804 | Settings::ControllerType::ProController); | ||
| 805 | ui->comboControllerType->addItem(tr("Pro Controller")); | ||
| 806 | } | ||
| 807 | |||
| 808 | if (enable_all || npad_style_set.joycon_dual == 1) { | ||
| 809 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 810 | Settings::ControllerType::DualJoyconDetached); | ||
| 811 | ui->comboControllerType->addItem(tr("Dual Joycons")); | ||
| 812 | } | ||
| 813 | |||
| 814 | if (enable_all || npad_style_set.joycon_left == 1) { | ||
| 815 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 816 | Settings::ControllerType::LeftJoycon); | ||
| 817 | ui->comboControllerType->addItem(tr("Left Joycon")); | ||
| 818 | } | ||
| 819 | |||
| 820 | if (enable_all || npad_style_set.joycon_right == 1) { | ||
| 821 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 822 | Settings::ControllerType::RightJoycon); | ||
| 823 | ui->comboControllerType->addItem(tr("Right Joycon")); | ||
| 824 | } | ||
| 825 | |||
| 826 | if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) { | ||
| 827 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 828 | Settings::ControllerType::Handheld); | ||
| 829 | ui->comboControllerType->addItem(tr("Handheld")); | ||
| 830 | } | ||
| 831 | }; | ||
| 832 | |||
| 833 | Core::System& system{Core::System::GetInstance()}; | ||
| 834 | |||
| 835 | if (!system.IsPoweredOn()) { | ||
| 836 | add_controllers(true); | ||
| 837 | return; | ||
| 838 | } | ||
| 839 | |||
| 840 | Service::SM::ServiceManager& sm = system.ServiceManager(); | ||
| 841 | |||
| 842 | auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>( | ||
| 843 | HidController::NPad); | ||
| 844 | |||
| 845 | add_controllers(false, npad.GetSupportedStyleSet()); | ||
| 846 | } | ||
| 847 | |||
| 848 | Settings::ControllerType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { | ||
| 849 | const auto it = | ||
| 850 | std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), | ||
| 851 | [index](const auto& pair) { return pair.first == index; }); | ||
| 852 | |||
| 853 | if (it == index_controller_type_pairs.end()) { | ||
| 854 | return Settings::ControllerType::ProController; | ||
| 855 | } | ||
| 856 | |||
| 857 | return it->second; | ||
| 858 | } | ||
| 859 | |||
| 860 | int ConfigureInputPlayer::GetIndexFromControllerType(Settings::ControllerType type) const { | ||
| 861 | const auto it = | ||
| 862 | std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), | ||
| 863 | [type](const auto& pair) { return pair.second == type; }); | ||
| 864 | |||
| 865 | if (it == index_controller_type_pairs.end()) { | ||
| 866 | return -1; | ||
| 867 | } | ||
| 868 | |||
| 869 | return it->first; | ||
| 870 | } | ||
| 871 | |||
| 844 | void ConfigureInputPlayer::UpdateInputDevices() { | 872 | void ConfigureInputPlayer::UpdateInputDevices() { |
| 845 | input_devices = input_subsystem->GetInputDevices(); | 873 | input_devices = input_subsystem->GetInputDevices(); |
| 846 | ui->comboDevices->clear(); | 874 | ui->comboDevices->clear(); |
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 23cf6f958..9c30879a2 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <optional> | 10 | #include <optional> |
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <vector> | ||
| 12 | 13 | ||
| 13 | #include <QWidget> | 14 | #include <QWidget> |
| 14 | 15 | ||
| @@ -112,6 +113,15 @@ private: | |||
| 112 | /// Update UI to reflect current configuration. | 113 | /// Update UI to reflect current configuration. |
| 113 | void UpdateUI(); | 114 | void UpdateUI(); |
| 114 | 115 | ||
| 116 | /// Sets the available controllers. | ||
| 117 | void SetConnectableControllers(); | ||
| 118 | |||
| 119 | /// Gets the Controller Type for a given controller combobox index. | ||
| 120 | Settings::ControllerType GetControllerTypeFromIndex(int index) const; | ||
| 121 | |||
| 122 | /// Gets the controller combobox index for a given Controller Type. | ||
| 123 | int GetIndexFromControllerType(Settings::ControllerType type) const; | ||
| 124 | |||
| 115 | /// Update the available input devices. | 125 | /// Update the available input devices. |
| 116 | void UpdateInputDevices(); | 126 | void UpdateInputDevices(); |
| 117 | 127 | ||
| @@ -151,6 +161,9 @@ private: | |||
| 151 | std::unique_ptr<QTimer> timeout_timer; | 161 | std::unique_ptr<QTimer> timeout_timer; |
| 152 | std::unique_ptr<QTimer> poll_timer; | 162 | std::unique_ptr<QTimer> poll_timer; |
| 153 | 163 | ||
| 164 | /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. | ||
| 165 | std::vector<std::pair<int, Settings::ControllerType>> index_controller_type_pairs; | ||
| 166 | |||
| 154 | static constexpr int PLAYER_COUNT = 8; | 167 | static constexpr int PLAYER_COUNT = 8; |
| 155 | std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox; | 168 | std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox; |
| 156 | 169 | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e704cc656..805619ccf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -978,7 +978,7 @@ void GMainWindow::AllowOSSleep() { | |||
| 978 | #endif | 978 | #endif |
| 979 | } | 979 | } |
| 980 | 980 | ||
| 981 | bool GMainWindow::LoadROM(const QString& filename) { | 981 | bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { |
| 982 | // Shutdown previous session if the emu thread is still active... | 982 | // Shutdown previous session if the emu thread is still active... |
| 983 | if (emu_thread != nullptr) | 983 | if (emu_thread != nullptr) |
| 984 | ShutdownGame(); | 984 | ShutdownGame(); |
| @@ -1003,7 +1003,8 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 1003 | 1003 | ||
| 1004 | system.RegisterHostThread(); | 1004 | system.RegisterHostThread(); |
| 1005 | 1005 | ||
| 1006 | const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; | 1006 | const Core::System::ResultStatus result{ |
| 1007 | system.Load(*render_window, filename.toStdString(), program_index)}; | ||
| 1007 | 1008 | ||
| 1008 | const auto drd_callout = | 1009 | const auto drd_callout = |
| 1009 | (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; | 1010 | (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; |
| @@ -1085,14 +1086,18 @@ void GMainWindow::SelectAndSetCurrentUser() { | |||
| 1085 | Settings::values.current_user = dialog.GetIndex(); | 1086 | Settings::values.current_user = dialog.GetIndex(); |
| 1086 | } | 1087 | } |
| 1087 | 1088 | ||
| 1088 | void GMainWindow::BootGame(const QString& filename) { | 1089 | void GMainWindow::BootGame(const QString& filename, std::size_t program_index) { |
| 1089 | LOG_INFO(Frontend, "yuzu starting..."); | 1090 | LOG_INFO(Frontend, "yuzu starting..."); |
| 1090 | StoreRecentFile(filename); // Put the filename on top of the list | 1091 | StoreRecentFile(filename); // Put the filename on top of the list |
| 1091 | 1092 | ||
| 1092 | u64 title_id{0}; | 1093 | u64 title_id{0}; |
| 1094 | |||
| 1095 | last_filename_booted = filename; | ||
| 1096 | |||
| 1093 | auto& system = Core::System::GetInstance(); | 1097 | auto& system = Core::System::GetInstance(); |
| 1094 | const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); | 1098 | const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); |
| 1095 | const auto loader = Loader::GetLoader(system, v_file); | 1099 | const auto loader = Loader::GetLoader(system, v_file, program_index); |
| 1100 | |||
| 1096 | if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { | 1101 | if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { |
| 1097 | // Load per game settings | 1102 | // Load per game settings |
| 1098 | Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); | 1103 | Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); |
| @@ -1106,7 +1111,7 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1106 | SelectAndSetCurrentUser(); | 1111 | SelectAndSetCurrentUser(); |
| 1107 | } | 1112 | } |
| 1108 | 1113 | ||
| 1109 | if (!LoadROM(filename)) | 1114 | if (!LoadROM(filename, program_index)) |
| 1110 | return; | 1115 | return; |
| 1111 | 1116 | ||
| 1112 | // Create and start the emulation thread | 1117 | // Create and start the emulation thread |
| @@ -1114,6 +1119,10 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1114 | emit EmulationStarting(emu_thread.get()); | 1119 | emit EmulationStarting(emu_thread.get()); |
| 1115 | emu_thread->start(); | 1120 | emu_thread->start(); |
| 1116 | 1121 | ||
| 1122 | // Register an ExecuteProgram callback such that Core can execute a sub-program | ||
| 1123 | system.RegisterExecuteProgramCallback( | ||
| 1124 | [this](std::size_t program_index) { render_window->ExecuteProgram(program_index); }); | ||
| 1125 | |||
| 1117 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); | 1126 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); |
| 1118 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views | 1127 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views |
| 1119 | // before the CPU continues | 1128 | // before the CPU continues |
| @@ -2136,6 +2145,11 @@ void GMainWindow::OnLoadComplete() { | |||
| 2136 | loading_screen->OnLoadComplete(); | 2145 | loading_screen->OnLoadComplete(); |
| 2137 | } | 2146 | } |
| 2138 | 2147 | ||
| 2148 | void GMainWindow::OnExecuteProgram(std::size_t program_index) { | ||
| 2149 | ShutdownGame(); | ||
| 2150 | BootGame(last_filename_booted, program_index); | ||
| 2151 | } | ||
| 2152 | |||
| 2139 | void GMainWindow::ErrorDisplayDisplayError(QString body) { | 2153 | void GMainWindow::ErrorDisplayDisplayError(QString body) { |
| 2140 | QMessageBox::critical(this, tr("Error Display"), body); | 2154 | QMessageBox::critical(this, tr("Error Display"), body); |
| 2141 | emit ErrorDisplayFinished(); | 2155 | emit ErrorDisplayFinished(); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b380a66f3..6242341d1 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -131,6 +131,7 @@ signals: | |||
| 131 | 131 | ||
| 132 | public slots: | 132 | public slots: |
| 133 | void OnLoadComplete(); | 133 | void OnLoadComplete(); |
| 134 | void OnExecuteProgram(std::size_t program_index); | ||
| 134 | void ControllerSelectorReconfigureControllers( | 135 | void ControllerSelectorReconfigureControllers( |
| 135 | const Core::Frontend::ControllerParameters& parameters); | 136 | const Core::Frontend::ControllerParameters& parameters); |
| 136 | void ErrorDisplayDisplayError(QString body); | 137 | void ErrorDisplayDisplayError(QString body); |
| @@ -154,8 +155,8 @@ private: | |||
| 154 | void PreventOSSleep(); | 155 | void PreventOSSleep(); |
| 155 | void AllowOSSleep(); | 156 | void AllowOSSleep(); |
| 156 | 157 | ||
| 157 | bool LoadROM(const QString& filename); | 158 | bool LoadROM(const QString& filename, std::size_t program_index); |
| 158 | void BootGame(const QString& filename); | 159 | void BootGame(const QString& filename, std::size_t program_index = 0); |
| 159 | void ShutdownGame(); | 160 | void ShutdownGame(); |
| 160 | 161 | ||
| 161 | void ShowTelemetryCallout(); | 162 | void ShowTelemetryCallout(); |
| @@ -317,6 +318,9 @@ private: | |||
| 317 | // Install progress dialog | 318 | // Install progress dialog |
| 318 | QProgressDialog* install_progress; | 319 | QProgressDialog* install_progress; |
| 319 | 320 | ||
| 321 | // Last game booted, used for multi-process apps | ||
| 322 | QString last_filename_booted; | ||
| 323 | |||
| 320 | protected: | 324 | protected: |
| 321 | void dropEvent(QDropEvent* event) override; | 325 | void dropEvent(QDropEvent* event) override; |
| 322 | void dragEnterEvent(QDragEnterEvent* event) override; | 326 | void dragEnterEvent(QDragEnterEvent* event) override; |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 521209622..c4a4a36be 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -121,62 +121,64 @@ void EmuWindow_SDL2::Fullscreen() { | |||
| 121 | SDL_MaximizeWindow(render_window); | 121 | SDL_MaximizeWindow(render_window); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | void EmuWindow_SDL2::PollEvents() { | 124 | void EmuWindow_SDL2::WaitEvent() { |
| 125 | // Called on main thread | ||
| 125 | SDL_Event event; | 126 | SDL_Event event; |
| 126 | 127 | ||
| 127 | // SDL_PollEvent returns 0 when there are no more events in the event queue | 128 | if (!SDL_WaitEvent(&event)) { |
| 128 | while (SDL_PollEvent(&event)) { | 129 | LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", SDL_GetError()); |
| 129 | switch (event.type) { | 130 | exit(1); |
| 130 | case SDL_WINDOWEVENT: | 131 | } |
| 131 | switch (event.window.event) { | 132 | |
| 132 | case SDL_WINDOWEVENT_SIZE_CHANGED: | 133 | switch (event.type) { |
| 133 | case SDL_WINDOWEVENT_RESIZED: | 134 | case SDL_WINDOWEVENT: |
| 134 | case SDL_WINDOWEVENT_MAXIMIZED: | 135 | switch (event.window.event) { |
| 135 | case SDL_WINDOWEVENT_RESTORED: | 136 | case SDL_WINDOWEVENT_SIZE_CHANGED: |
| 136 | OnResize(); | 137 | case SDL_WINDOWEVENT_RESIZED: |
| 137 | break; | 138 | case SDL_WINDOWEVENT_MAXIMIZED: |
| 138 | case SDL_WINDOWEVENT_MINIMIZED: | 139 | case SDL_WINDOWEVENT_RESTORED: |
| 139 | case SDL_WINDOWEVENT_EXPOSED: | 140 | OnResize(); |
| 140 | is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED; | ||
| 141 | OnResize(); | ||
| 142 | break; | ||
| 143 | case SDL_WINDOWEVENT_CLOSE: | ||
| 144 | is_open = false; | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | break; | ||
| 148 | case SDL_KEYDOWN: | ||
| 149 | case SDL_KEYUP: | ||
| 150 | OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state); | ||
| 151 | break; | ||
| 152 | case SDL_MOUSEMOTION: | ||
| 153 | // ignore if it came from touch | ||
| 154 | if (event.button.which != SDL_TOUCH_MOUSEID) | ||
| 155 | OnMouseMotion(event.motion.x, event.motion.y); | ||
| 156 | break; | ||
| 157 | case SDL_MOUSEBUTTONDOWN: | ||
| 158 | case SDL_MOUSEBUTTONUP: | ||
| 159 | // ignore if it came from touch | ||
| 160 | if (event.button.which != SDL_TOUCH_MOUSEID) { | ||
| 161 | OnMouseButton(event.button.button, event.button.state, event.button.x, | ||
| 162 | event.button.y); | ||
| 163 | } | ||
| 164 | break; | ||
| 165 | case SDL_FINGERDOWN: | ||
| 166 | OnFingerDown(event.tfinger.x, event.tfinger.y); | ||
| 167 | break; | ||
| 168 | case SDL_FINGERMOTION: | ||
| 169 | OnFingerMotion(event.tfinger.x, event.tfinger.y); | ||
| 170 | break; | 141 | break; |
| 171 | case SDL_FINGERUP: | 142 | case SDL_WINDOWEVENT_MINIMIZED: |
| 172 | OnFingerUp(); | 143 | case SDL_WINDOWEVENT_EXPOSED: |
| 144 | is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED; | ||
| 145 | OnResize(); | ||
| 173 | break; | 146 | break; |
| 174 | case SDL_QUIT: | 147 | case SDL_WINDOWEVENT_CLOSE: |
| 175 | is_open = false; | 148 | is_open = false; |
| 176 | break; | 149 | break; |
| 177 | default: | ||
| 178 | break; | ||
| 179 | } | 150 | } |
| 151 | break; | ||
| 152 | case SDL_KEYDOWN: | ||
| 153 | case SDL_KEYUP: | ||
| 154 | OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state); | ||
| 155 | break; | ||
| 156 | case SDL_MOUSEMOTION: | ||
| 157 | // ignore if it came from touch | ||
| 158 | if (event.button.which != SDL_TOUCH_MOUSEID) | ||
| 159 | OnMouseMotion(event.motion.x, event.motion.y); | ||
| 160 | break; | ||
| 161 | case SDL_MOUSEBUTTONDOWN: | ||
| 162 | case SDL_MOUSEBUTTONUP: | ||
| 163 | // ignore if it came from touch | ||
| 164 | if (event.button.which != SDL_TOUCH_MOUSEID) { | ||
| 165 | OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y); | ||
| 166 | } | ||
| 167 | break; | ||
| 168 | case SDL_FINGERDOWN: | ||
| 169 | OnFingerDown(event.tfinger.x, event.tfinger.y); | ||
| 170 | break; | ||
| 171 | case SDL_FINGERMOTION: | ||
| 172 | OnFingerMotion(event.tfinger.x, event.tfinger.y); | ||
| 173 | break; | ||
| 174 | case SDL_FINGERUP: | ||
| 175 | OnFingerUp(); | ||
| 176 | break; | ||
| 177 | case SDL_QUIT: | ||
| 178 | is_open = false; | ||
| 179 | break; | ||
| 180 | default: | ||
| 181 | break; | ||
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | const u32 current_time = SDL_GetTicks(); | 184 | const u32 current_time = SDL_GetTicks(); |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 53d756c3c..a93141240 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h | |||
| @@ -23,38 +23,38 @@ public: | |||
| 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); | 23 | explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); |
| 24 | ~EmuWindow_SDL2(); | 24 | ~EmuWindow_SDL2(); |
| 25 | 25 | ||
| 26 | /// Polls window events | ||
| 27 | void PollEvents() override; | ||
| 28 | |||
| 29 | /// Whether the window is still open, and a close request hasn't yet been sent | 26 | /// Whether the window is still open, and a close request hasn't yet been sent |
| 30 | bool IsOpen() const; | 27 | bool IsOpen() const; |
| 31 | 28 | ||
| 32 | /// Returns if window is shown (not minimized) | 29 | /// Returns if window is shown (not minimized) |
| 33 | bool IsShown() const override; | 30 | bool IsShown() const override; |
| 34 | 31 | ||
| 32 | /// Wait for the next event on the main thread. | ||
| 33 | void WaitEvent(); | ||
| 34 | |||
| 35 | protected: | 35 | protected: |
| 36 | /// Called by PollEvents when a key is pressed or released. | 36 | /// Called by WaitEvent when a key is pressed or released. |
| 37 | void OnKeyEvent(int key, u8 state); | 37 | void OnKeyEvent(int key, u8 state); |
| 38 | 38 | ||
| 39 | /// Called by PollEvents when the mouse moves. | 39 | /// Called by WaitEvent when the mouse moves. |
| 40 | void OnMouseMotion(s32 x, s32 y); | 40 | void OnMouseMotion(s32 x, s32 y); |
| 41 | 41 | ||
| 42 | /// Called by PollEvents when a mouse button is pressed or released | 42 | /// Called by WaitEvent when a mouse button is pressed or released |
| 43 | void OnMouseButton(u32 button, u8 state, s32 x, s32 y); | 43 | void OnMouseButton(u32 button, u8 state, s32 x, s32 y); |
| 44 | 44 | ||
| 45 | /// Translates pixel position (0..1) to pixel positions | 45 | /// Translates pixel position (0..1) to pixel positions |
| 46 | std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const; | 46 | std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const; |
| 47 | 47 | ||
| 48 | /// Called by PollEvents when a finger starts touching the touchscreen | 48 | /// Called by WaitEvent when a finger starts touching the touchscreen |
| 49 | void OnFingerDown(float x, float y); | 49 | void OnFingerDown(float x, float y); |
| 50 | 50 | ||
| 51 | /// Called by PollEvents when a finger moves while touching the touchscreen | 51 | /// Called by WaitEvent when a finger moves while touching the touchscreen |
| 52 | void OnFingerMotion(float x, float y); | 52 | void OnFingerMotion(float x, float y); |
| 53 | 53 | ||
| 54 | /// Called by PollEvents when a finger stops touching the touchscreen | 54 | /// Called by WaitEvent when a finger stops touching the touchscreen |
| 55 | void OnFingerUp(); | 55 | void OnFingerUp(); |
| 56 | 56 | ||
| 57 | /// Called by PollEvents when any event that may cause the window to be resized occurs | 57 | /// Called by WaitEvent when any event that may cause the window to be resized occurs |
| 58 | void OnResize(); | 58 | void OnResize(); |
| 59 | 59 | ||
| 60 | /// Called when user passes the fullscreen parameter flag | 60 | /// Called when user passes the fullscreen parameter flag |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 3a76c785f..ba6e89249 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -240,11 +240,11 @@ int main(int argc, char** argv) { | |||
| 240 | system.CurrentProcess()->GetTitleID(), false, | 240 | system.CurrentProcess()->GetTitleID(), false, |
| 241 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); | 241 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); |
| 242 | 242 | ||
| 243 | system.Run(); | 243 | void(system.Run()); |
| 244 | while (emu_window->IsOpen()) { | 244 | while (emu_window->IsOpen()) { |
| 245 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | 245 | emu_window->WaitEvent(); |
| 246 | } | 246 | } |
| 247 | system.Pause(); | 247 | void(system.Pause()); |
| 248 | system.Shutdown(); | 248 | system.Shutdown(); |
| 249 | 249 | ||
| 250 | detached_tasks.WaitForAllTasks(); | 250 | detached_tasks.WaitForAllTasks(); |
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp index 78f75fb38..358e03870 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp | |||
| @@ -109,8 +109,6 @@ EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { | |||
| 109 | SDL_Quit(); | 109 | SDL_Quit(); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | void EmuWindow_SDL2_Hide::PollEvents() {} | ||
| 113 | |||
| 114 | bool EmuWindow_SDL2_Hide::IsShown() const { | 112 | bool EmuWindow_SDL2_Hide::IsShown() const { |
| 115 | return false; | 113 | return false; |
| 116 | } | 114 | } |
diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h index a553b4b95..adccdf35e 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h | |||
| @@ -17,9 +17,6 @@ public: | |||
| 17 | explicit EmuWindow_SDL2_Hide(); | 17 | explicit EmuWindow_SDL2_Hide(); |
| 18 | ~EmuWindow_SDL2_Hide(); | 18 | ~EmuWindow_SDL2_Hide(); |
| 19 | 19 | ||
| 20 | /// Polls window events | ||
| 21 | void PollEvents() override; | ||
| 22 | |||
| 23 | /// Whether the screen is being shown or not. | 20 | /// Whether the screen is being shown or not. |
| 24 | bool IsShown() const override; | 21 | bool IsShown() const override; |
| 25 | 22 | ||
diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp index 5798ce43a..88e4bd1f7 100644 --- a/src/yuzu_tester/yuzu.cpp +++ b/src/yuzu_tester/yuzu.cpp | |||
| @@ -256,11 +256,11 @@ int main(int argc, char** argv) { | |||
| 256 | 256 | ||
| 257 | system.GPU().Start(); | 257 | system.GPU().Start(); |
| 258 | 258 | ||
| 259 | system.Run(); | 259 | void(system.Run()); |
| 260 | while (!finished) { | 260 | while (!finished) { |
| 261 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); | 261 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
| 262 | } | 262 | } |
| 263 | system.Pause(); | 263 | void(system.Pause()); |
| 264 | 264 | ||
| 265 | detached_tasks.WaitForAllTasks(); | 265 | detached_tasks.WaitForAllTasks(); |
| 266 | return return_value; | 266 | return return_value; |