diff options
110 files changed, 2223 insertions, 1455 deletions
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml index d85a949aa..0b4bbd341 100644 --- a/.ci/templates/build-msvc.yml +++ b/.ci/templates/build-msvc.yml | |||
| @@ -4,9 +4,11 @@ parameters: | |||
| 4 | version: '' | 4 | version: '' |
| 5 | 5 | ||
| 6 | steps: | 6 | steps: |
| 7 | - script: choco install vulkan-sdk | ||
| 8 | displayName: 'Install vulkan-sdk' | ||
| 7 | - script: python -m pip install --upgrade pip conan | 9 | - script: python -m pip install --upgrade pip conan |
| 8 | displayName: 'Install conan' | 10 | displayName: 'Install conan' |
| 9 | - script: mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd .. | 11 | - script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd .. |
| 10 | displayName: 'Configure CMake' | 12 | displayName: 'Configure CMake' |
| 11 | - task: MSBuild@1 | 13 | - task: MSBuild@1 |
| 12 | displayName: 'Build' | 14 | displayName: 'Build' |
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/common/logging/backend.cpp b/src/common/logging/backend.cpp index 7859344b9..631f64d05 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "common/logging/text_formatter.h" | 23 | #include "common/logging/text_formatter.h" |
| 24 | #include "common/string_util.h" | 24 | #include "common/string_util.h" |
| 25 | #include "common/threadsafe_queue.h" | 25 | #include "common/threadsafe_queue.h" |
| 26 | #include "core/settings.h" | ||
| 26 | 27 | ||
| 27 | namespace Log { | 28 | namespace Log { |
| 28 | 29 | ||
| @@ -152,10 +153,19 @@ FileBackend::FileBackend(const std::string& filename) | |||
| 152 | void FileBackend::Write(const Entry& entry) { | 153 | void FileBackend::Write(const Entry& entry) { |
| 153 | // prevent logs from going over the maximum size (in case its spamming and the user doesn't | 154 | // prevent logs from going over the maximum size (in case its spamming and the user doesn't |
| 154 | // know) | 155 | // know) |
| 155 | constexpr std::size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L; | 156 | constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024; |
| 156 | if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { | 157 | constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024; |
| 158 | |||
| 159 | if (!file.IsOpen()) { | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | if (Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN_EXTENDED) { | ||
| 164 | return; | ||
| 165 | } else if (!Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN) { | ||
| 157 | return; | 166 | return; |
| 158 | } | 167 | } |
| 168 | |||
| 159 | bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n')); | 169 | bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n')); |
| 160 | if (entry.log_level >= Level::Error) { | 170 | if (entry.log_level >= Level::Error) { |
| 161 | file.Flush(); | 171 | file.Flush(); |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 242796008..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(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; |
| @@ -224,7 +226,7 @@ struct System::Impl { | |||
| 224 | return init_result; | 226 | return init_result; |
| 225 | } | 227 | } |
| 226 | 228 | ||
| 227 | telemetry_session->AddInitialInfo(*app_loader); | 229 | telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); |
| 228 | auto main_process = | 230 | auto main_process = |
| 229 | Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); | 231 | Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); |
| 230 | const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); | 232 | const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); |
| @@ -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(); |
| @@ -338,7 +340,7 @@ struct System::Impl { | |||
| 338 | Service::Glue::ApplicationLaunchProperty launch{}; | 340 | Service::Glue::ApplicationLaunchProperty launch{}; |
| 339 | launch.title_id = process.GetTitleID(); | 341 | launch.title_id = process.GetTitleID(); |
| 340 | 342 | ||
| 341 | FileSys::PatchManager pm{launch.title_id}; | 343 | FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider}; |
| 342 | launch.version = pm.GetGameVersion().value_or(0); | 344 | launch.version = pm.GetGameVersion().value_or(0); |
| 343 | 345 | ||
| 344 | // TODO(DarkLordZach): When FSController/Game Card Support is added, if | 346 | // TODO(DarkLordZach): When FSController/Game Card Support is added, if |
| @@ -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/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 807b05821..e9d1607d0 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -112,7 +112,10 @@ bool IsDirValidAndNonEmpty(const VirtualDir& dir) { | |||
| 112 | } | 112 | } |
| 113 | } // Anonymous namespace | 113 | } // Anonymous namespace |
| 114 | 114 | ||
| 115 | PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} | 115 | PatchManager::PatchManager(u64 title_id_, |
| 116 | const Service::FileSystem::FileSystemController& fs_controller_, | ||
| 117 | const ContentProvider& content_provider_) | ||
| 118 | : title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {} | ||
| 116 | 119 | ||
| 117 | PatchManager::~PatchManager() = default; | 120 | PatchManager::~PatchManager() = default; |
| 118 | 121 | ||
| @@ -128,34 +131,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 128 | 131 | ||
| 129 | if (Settings::values.dump_exefs) { | 132 | if (Settings::values.dump_exefs) { |
| 130 | LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); | 133 | LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); |
| 131 | const auto dump_dir = | 134 | const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id); |
| 132 | Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id); | ||
| 133 | if (dump_dir != nullptr) { | 135 | if (dump_dir != nullptr) { |
| 134 | const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); | 136 | const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); |
| 135 | VfsRawCopyD(exefs, exefs_dir); | 137 | VfsRawCopyD(exefs, exefs_dir); |
| 136 | } | 138 | } |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 140 | |||
| 141 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 141 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 142 | const auto update_disabled = | 142 | const auto update_disabled = |
| 143 | std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); | 143 | std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); |
| 144 | 144 | ||
| 145 | // Game Updates | 145 | // Game Updates |
| 146 | const auto update_tid = GetUpdateTitleID(title_id); | 146 | const auto update_tid = GetUpdateTitleID(title_id); |
| 147 | const auto update = installed.GetEntry(update_tid, ContentRecordType::Program); | 147 | const auto update = content_provider.GetEntry(update_tid, ContentRecordType::Program); |
| 148 | 148 | ||
| 149 | if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr && | 149 | if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr && |
| 150 | update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { | 150 | update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { |
| 151 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", | 151 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", |
| 152 | FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); | 152 | FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0))); |
| 153 | exefs = update->GetExeFS(); | 153 | exefs = update->GetExeFS(); |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | // LayeredExeFS | 156 | // LayeredExeFS |
| 157 | const auto load_dir = | 157 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 158 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 159 | if (load_dir != nullptr && load_dir->GetSize() > 0) { | 158 | if (load_dir != nullptr && load_dir->GetSize() > 0) { |
| 160 | auto patch_dirs = load_dir->GetSubdirectories(); | 159 | auto patch_dirs = load_dir->GetSubdirectories(); |
| 161 | std::sort( | 160 | std::sort( |
| @@ -241,8 +240,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st | |||
| 241 | if (Settings::values.dump_nso) { | 240 | if (Settings::values.dump_nso) { |
| 242 | LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id, | 241 | LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id, |
| 243 | title_id); | 242 | title_id); |
| 244 | const auto dump_dir = | 243 | const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id); |
| 245 | Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id); | ||
| 246 | if (dump_dir != nullptr) { | 244 | if (dump_dir != nullptr) { |
| 247 | const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); | 245 | const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); |
| 248 | const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id)); | 246 | const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id)); |
| @@ -254,8 +252,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st | |||
| 254 | 252 | ||
| 255 | LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); | 253 | LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); |
| 256 | 254 | ||
| 257 | const auto load_dir = | 255 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 258 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 259 | if (load_dir == nullptr) { | 256 | if (load_dir == nullptr) { |
| 260 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); | 257 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
| 261 | return nso; | 258 | return nso; |
| @@ -298,8 +295,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const { | |||
| 298 | 295 | ||
| 299 | LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id); | 296 | LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id); |
| 300 | 297 | ||
| 301 | const auto load_dir = | 298 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 302 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 303 | if (load_dir == nullptr) { | 299 | if (load_dir == nullptr) { |
| 304 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); | 300 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
| 305 | return false; | 301 | return false; |
| @@ -313,8 +309,8 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const { | |||
| 313 | } | 309 | } |
| 314 | 310 | ||
| 315 | std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( | 311 | std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( |
| 316 | const Core::System& system, const BuildID& build_id_) const { | 312 | const BuildID& build_id_) const { |
| 317 | const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id); | 313 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 318 | if (load_dir == nullptr) { | 314 | if (load_dir == nullptr) { |
| 319 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); | 315 | LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
| 320 | return {}; | 316 | return {}; |
| @@ -347,9 +343,9 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( | |||
| 347 | return out; | 343 | return out; |
| 348 | } | 344 | } |
| 349 | 345 | ||
| 350 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { | 346 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type, |
| 351 | const auto load_dir = | 347 | const Service::FileSystem::FileSystemController& fs_controller) { |
| 352 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | 348 | const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 353 | if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || | 349 | if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || |
| 354 | load_dir == nullptr || load_dir->GetSize() <= 0) { | 350 | load_dir == nullptr || load_dir->GetSize() <= 0) { |
| 355 | return; | 351 | return; |
| @@ -411,19 +407,19 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content | |||
| 411 | const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}", | 407 | const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}", |
| 412 | title_id, static_cast<u8>(type)); | 408 | title_id, static_cast<u8>(type)); |
| 413 | 409 | ||
| 414 | if (type == ContentRecordType::Program || type == ContentRecordType::Data) | 410 | if (type == ContentRecordType::Program || type == ContentRecordType::Data) { |
| 415 | LOG_INFO(Loader, "{}", log_string); | 411 | LOG_INFO(Loader, "{}", log_string); |
| 416 | else | 412 | } else { |
| 417 | LOG_DEBUG(Loader, "{}", log_string); | 413 | LOG_DEBUG(Loader, "{}", log_string); |
| 414 | } | ||
| 418 | 415 | ||
| 419 | if (romfs == nullptr) | 416 | if (romfs == nullptr) { |
| 420 | return romfs; | 417 | return romfs; |
| 421 | 418 | } | |
| 422 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 423 | 419 | ||
| 424 | // Game Updates | 420 | // Game Updates |
| 425 | const auto update_tid = GetUpdateTitleID(title_id); | 421 | const auto update_tid = GetUpdateTitleID(title_id); |
| 426 | const auto update = installed.GetEntryRaw(update_tid, type); | 422 | const auto update = content_provider.GetEntryRaw(update_tid, type); |
| 427 | 423 | ||
| 428 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 424 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 429 | const auto update_disabled = | 425 | const auto update_disabled = |
| @@ -434,7 +430,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content | |||
| 434 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && | 430 | if (new_nca->GetStatus() == Loader::ResultStatus::Success && |
| 435 | new_nca->GetRomFS() != nullptr) { | 431 | new_nca->GetRomFS() != nullptr) { |
| 436 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", | 432 | LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", |
| 437 | FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); | 433 | FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0))); |
| 438 | romfs = new_nca->GetRomFS(); | 434 | romfs = new_nca->GetRomFS(); |
| 439 | } | 435 | } |
| 440 | } else if (!update_disabled && update_raw != nullptr) { | 436 | } else if (!update_disabled && update_raw != nullptr) { |
| @@ -447,7 +443,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content | |||
| 447 | } | 443 | } |
| 448 | 444 | ||
| 449 | // LayeredFS | 445 | // LayeredFS |
| 450 | ApplyLayeredFS(romfs, title_id, type); | 446 | ApplyLayeredFS(romfs, title_id, type, fs_controller); |
| 451 | 447 | ||
| 452 | return romfs; | 448 | return romfs; |
| 453 | } | 449 | } |
| @@ -458,12 +454,11 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 458 | } | 454 | } |
| 459 | 455 | ||
| 460 | std::map<std::string, std::string, std::less<>> out; | 456 | std::map<std::string, std::string, std::less<>> out; |
| 461 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 462 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 457 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 463 | 458 | ||
| 464 | // Game Updates | 459 | // Game Updates |
| 465 | const auto update_tid = GetUpdateTitleID(title_id); | 460 | const auto update_tid = GetUpdateTitleID(title_id); |
| 466 | PatchManager update{update_tid}; | 461 | PatchManager update{update_tid, fs_controller, content_provider}; |
| 467 | const auto metadata = update.GetControlMetadata(); | 462 | const auto metadata = update.GetControlMetadata(); |
| 468 | const auto& nacp = metadata.first; | 463 | const auto& nacp = metadata.first; |
| 469 | 464 | ||
| @@ -474,8 +469,8 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 474 | if (nacp != nullptr) { | 469 | if (nacp != nullptr) { |
| 475 | out.insert_or_assign(update_label, nacp->GetVersionString()); | 470 | out.insert_or_assign(update_label, nacp->GetVersionString()); |
| 476 | } else { | 471 | } else { |
| 477 | if (installed.HasEntry(update_tid, ContentRecordType::Program)) { | 472 | if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { |
| 478 | const auto meta_ver = installed.GetEntryVersion(update_tid); | 473 | const auto meta_ver = content_provider.GetEntryVersion(update_tid); |
| 479 | if (meta_ver.value_or(0) == 0) { | 474 | if (meta_ver.value_or(0) == 0) { |
| 480 | out.insert_or_assign(update_label, ""); | 475 | out.insert_or_assign(update_label, ""); |
| 481 | } else { | 476 | } else { |
| @@ -487,8 +482,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 487 | } | 482 | } |
| 488 | 483 | ||
| 489 | // General Mods (LayeredFS and IPS) | 484 | // General Mods (LayeredFS and IPS) |
| 490 | const auto mod_dir = | 485 | const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id); |
| 491 | Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); | ||
| 492 | if (mod_dir != nullptr && mod_dir->GetSize() > 0) { | 486 | if (mod_dir != nullptr && mod_dir->GetSize() > 0) { |
| 493 | for (const auto& mod : mod_dir->GetSubdirectories()) { | 487 | for (const auto& mod : mod_dir->GetSubdirectories()) { |
| 494 | std::string types; | 488 | std::string types; |
| @@ -532,13 +526,15 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 532 | } | 526 | } |
| 533 | 527 | ||
| 534 | // DLC | 528 | // DLC |
| 535 | const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); | 529 | const auto dlc_entries = |
| 530 | content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); | ||
| 536 | std::vector<ContentProviderEntry> dlc_match; | 531 | std::vector<ContentProviderEntry> dlc_match; |
| 537 | dlc_match.reserve(dlc_entries.size()); | 532 | dlc_match.reserve(dlc_entries.size()); |
| 538 | std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), | 533 | std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), |
| 539 | [this, &installed](const ContentProviderEntry& entry) { | 534 | [this](const ContentProviderEntry& entry) { |
| 540 | return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && | 535 | return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && |
| 541 | installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success; | 536 | content_provider.GetEntry(entry)->GetStatus() == |
| 537 | Loader::ResultStatus::Success; | ||
| 542 | }); | 538 | }); |
| 543 | if (!dlc_match.empty()) { | 539 | if (!dlc_match.empty()) { |
| 544 | // Ensure sorted so DLC IDs show in order. | 540 | // Ensure sorted so DLC IDs show in order. |
| @@ -559,19 +555,16 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 559 | } | 555 | } |
| 560 | 556 | ||
| 561 | std::optional<u32> PatchManager::GetGameVersion() const { | 557 | std::optional<u32> PatchManager::GetGameVersion() const { |
| 562 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | ||
| 563 | const auto update_tid = GetUpdateTitleID(title_id); | 558 | const auto update_tid = GetUpdateTitleID(title_id); |
| 564 | if (installed.HasEntry(update_tid, ContentRecordType::Program)) { | 559 | if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { |
| 565 | return installed.GetEntryVersion(update_tid); | 560 | return content_provider.GetEntryVersion(update_tid); |
| 566 | } | 561 | } |
| 567 | 562 | ||
| 568 | return installed.GetEntryVersion(title_id); | 563 | return content_provider.GetEntryVersion(title_id); |
| 569 | } | 564 | } |
| 570 | 565 | ||
| 571 | PatchManager::Metadata PatchManager::GetControlMetadata() const { | 566 | PatchManager::Metadata PatchManager::GetControlMetadata() const { |
| 572 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | 567 | const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control); |
| 573 | |||
| 574 | const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control); | ||
| 575 | if (base_control_nca == nullptr) { | 568 | if (base_control_nca == nullptr) { |
| 576 | return {}; | 569 | return {}; |
| 577 | } | 570 | } |
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index 1f28c6241..fb1853035 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h | |||
| @@ -17,8 +17,13 @@ namespace Core { | |||
| 17 | class System; | 17 | class System; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | namespace Service::FileSystem { | ||
| 21 | class FileSystemController; | ||
| 22 | } | ||
| 23 | |||
| 20 | namespace FileSys { | 24 | namespace FileSys { |
| 21 | 25 | ||
| 26 | class ContentProvider; | ||
| 22 | class NCA; | 27 | class NCA; |
| 23 | class NACP; | 28 | class NACP; |
| 24 | 29 | ||
| @@ -29,7 +34,9 @@ public: | |||
| 29 | using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; | 34 | using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; |
| 30 | using PatchVersionNames = std::map<std::string, std::string, std::less<>>; | 35 | using PatchVersionNames = std::map<std::string, std::string, std::less<>>; |
| 31 | 36 | ||
| 32 | explicit PatchManager(u64 title_id); | 37 | explicit PatchManager(u64 title_id_, |
| 38 | const Service::FileSystem::FileSystemController& fs_controller_, | ||
| 39 | const ContentProvider& content_provider_); | ||
| 33 | ~PatchManager(); | 40 | ~PatchManager(); |
| 34 | 41 | ||
| 35 | [[nodiscard]] u64 GetTitleID() const; | 42 | [[nodiscard]] u64 GetTitleID() const; |
| @@ -50,7 +57,7 @@ public: | |||
| 50 | 57 | ||
| 51 | // Creates a CheatList object with all | 58 | // Creates a CheatList object with all |
| 52 | [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList( | 59 | [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList( |
| 53 | const Core::System& system, const BuildID& build_id) const; | 60 | const BuildID& build_id) const; |
| 54 | 61 | ||
| 55 | // Currently tracked RomFS patches: | 62 | // Currently tracked RomFS patches: |
| 56 | // - Game Updates | 63 | // - Game Updates |
| @@ -80,6 +87,8 @@ private: | |||
| 80 | const std::string& build_id) const; | 87 | const std::string& build_id) const; |
| 81 | 88 | ||
| 82 | u64 title_id; | 89 | u64 title_id; |
| 90 | const Service::FileSystem::FileSystemController& fs_controller; | ||
| 91 | const ContentProvider& content_provider; | ||
| 83 | }; | 92 | }; |
| 84 | 93 | ||
| 85 | } // namespace FileSys | 94 | } // namespace FileSys |
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index e967a254e..987199747 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -37,10 +37,12 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) { | |||
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { | 39 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { |
| 40 | if (!updatable) | 40 | if (!updatable) { |
| 41 | return MakeResult<VirtualFile>(file); | 41 | return MakeResult<VirtualFile>(file); |
| 42 | } | ||
| 42 | 43 | ||
| 43 | const PatchManager patch_manager(current_process_title_id); | 44 | const PatchManager patch_manager{current_process_title_id, filesystem_controller, |
| 45 | content_provider}; | ||
| 44 | return MakeResult<VirtualFile>( | 46 | return MakeResult<VirtualFile>( |
| 45 | patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); | 47 | patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); |
| 46 | } | 48 | } |
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/input.h b/src/core/frontend/input.h index 25ac5af46..11c2e96ca 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -30,10 +30,12 @@ public: | |||
| 30 | virtual StatusType GetStatus() const { | 30 | virtual StatusType GetStatus() const { |
| 31 | return {}; | 31 | return {}; |
| 32 | } | 32 | } |
| 33 | virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { | 33 | virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { |
| 34 | return {}; | 34 | return {}; |
| 35 | } | 35 | } |
| 36 | virtual bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const { | 36 | virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low, |
| 37 | [[maybe_unused]] f32 amp_high, | ||
| 38 | [[maybe_unused]] f32 freq_high) const { | ||
| 37 | return {}; | 39 | return {}; |
| 38 | } | 40 | } |
| 39 | }; | 41 | }; |
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/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index ded52ea0b..c2c11dbcb 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -742,8 +742,10 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx | |||
| 742 | bool is_locked = false; | 742 | bool is_locked = false; |
| 743 | 743 | ||
| 744 | if (res != Loader::ResultStatus::Success) { | 744 | if (res != Loader::ResultStatus::Success) { |
| 745 | FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; | 745 | const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(), |
| 746 | auto nacp_unique = pm.GetControlMetadata().first; | 746 | system.GetFileSystemController(), |
| 747 | system.GetContentProvider()}; | ||
| 748 | const auto nacp_unique = pm.GetControlMetadata().first; | ||
| 747 | 749 | ||
| 748 | if (nacp_unique != nullptr) { | 750 | if (nacp_unique != nullptr) { |
| 749 | is_locked = nacp_unique->GetUserAccountSwitchLock(); | 751 | is_locked = nacp_unique->GetUserAccountSwitchLock(); |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index eb097738a..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"}, |
| @@ -1381,13 +1380,16 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { | |||
| 1381 | const auto res = [this] { | 1380 | const auto res = [this] { |
| 1382 | const auto title_id = system.CurrentProcess()->GetTitleID(); | 1381 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 1383 | 1382 | ||
| 1384 | FileSys::PatchManager pm{title_id}; | 1383 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 1384 | system.GetContentProvider()}; | ||
| 1385 | auto res = pm.GetControlMetadata(); | 1385 | auto res = pm.GetControlMetadata(); |
| 1386 | if (res.first != nullptr) { | 1386 | if (res.first != nullptr) { |
| 1387 | return res; | 1387 | return res; |
| 1388 | } | 1388 | } |
| 1389 | 1389 | ||
| 1390 | FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; | 1390 | const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |
| 1391 | system.GetFileSystemController(), | ||
| 1392 | system.GetContentProvider()}; | ||
| 1391 | return pm_update.GetControlMetadata(); | 1393 | return pm_update.GetControlMetadata(); |
| 1392 | }(); | 1394 | }(); |
| 1393 | 1395 | ||
| @@ -1415,13 +1417,16 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { | |||
| 1415 | const auto res = [this] { | 1417 | const auto res = [this] { |
| 1416 | const auto title_id = system.CurrentProcess()->GetTitleID(); | 1418 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 1417 | 1419 | ||
| 1418 | FileSys::PatchManager pm{title_id}; | 1420 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 1421 | system.GetContentProvider()}; | ||
| 1419 | auto res = pm.GetControlMetadata(); | 1422 | auto res = pm.GetControlMetadata(); |
| 1420 | if (res.first != nullptr) { | 1423 | if (res.first != nullptr) { |
| 1421 | return res; | 1424 | return res; |
| 1422 | } | 1425 | } |
| 1423 | 1426 | ||
| 1424 | FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; | 1427 | const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |
| 1428 | system.GetFileSystemController(), | ||
| 1429 | system.GetContentProvider()}; | ||
| 1425 | return pm_update.GetControlMetadata(); | 1430 | return pm_update.GetControlMetadata(); |
| 1426 | }(); | 1431 | }(); |
| 1427 | 1432 | ||
| @@ -1556,6 +1561,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque | |||
| 1556 | rb.Push<u32>(0); | 1561 | rb.Push<u32>(0); |
| 1557 | } | 1562 | } |
| 1558 | 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 | |||
| 1559 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { | 1592 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { |
| 1560 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 1593 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 1561 | 1594 | ||
| @@ -1580,8 +1613,8 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe | |||
| 1580 | rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); | 1613 | rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); |
| 1581 | } | 1614 | } |
| 1582 | 1615 | ||
| 1583 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1616 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, |
| 1584 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { | 1617 | Core::System& system) { |
| 1585 | auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); | 1618 | auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); |
| 1586 | // Needed on game boot | 1619 | // Needed on game boot |
| 1587 | 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/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index e58b2c518..173b36da4 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -164,7 +164,8 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { | |||
| 164 | rb.Push(RESULT_SUCCESS); | 164 | rb.Push(RESULT_SUCCESS); |
| 165 | 165 | ||
| 166 | const auto title_id = system.CurrentProcess()->GetTitleID(); | 166 | const auto title_id = system.CurrentProcess()->GetTitleID(); |
| 167 | FileSys::PatchManager pm{title_id}; | 167 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 168 | system.GetContentProvider()}; | ||
| 168 | 169 | ||
| 169 | const auto res = pm.GetControlMetadata(); | 170 | const auto res = pm.GetControlMetadata(); |
| 170 | if (res.first == nullptr) { | 171 | if (res.first == nullptr) { |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 3cdef4888..2e53cae5b 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -455,7 +455,9 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy | |||
| 455 | const auto res = system.GetAppLoader().ReadControlData(nacp); | 455 | const auto res = system.GetAppLoader().ReadControlData(nacp); |
| 456 | 456 | ||
| 457 | if (res != Loader::ResultStatus::Success) { | 457 | if (res != Loader::ResultStatus::Success) { |
| 458 | FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; | 458 | const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(), |
| 459 | system.GetFileSystemController(), | ||
| 460 | system.GetContentProvider()}; | ||
| 459 | const auto metadata = pm.GetControlMetadata(); | 461 | const auto metadata = pm.GetControlMetadata(); |
| 460 | const auto& nacp_unique = metadata.first; | 462 | const auto& nacp_unique = metadata.first; |
| 461 | 463 | ||
| @@ -728,7 +730,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 728 | void InstallInterfaces(Core::System& system) { | 730 | void InstallInterfaces(Core::System& system) { |
| 729 | std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager()); | 731 | std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager()); |
| 730 | std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager()); | 732 | std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager()); |
| 731 | std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter()) | 733 | std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetContentProvider(), |
| 734 | system.GetReporter()) | ||
| 732 | ->InstallAsService(system.ServiceManager()); | 735 | ->InstallAsService(system.ServiceManager()); |
| 733 | } | 736 | } |
| 734 | 737 | ||
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 649128be4..031c6dbf6 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -650,8 +650,10 @@ private: | |||
| 650 | u64 next_entry_index = 0; | 650 | u64 next_entry_index = 0; |
| 651 | }; | 651 | }; |
| 652 | 652 | ||
| 653 | FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) | 653 | FSP_SRV::FSP_SRV(FileSystemController& fsc_, const FileSys::ContentProvider& content_provider_, |
| 654 | : ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) { | 654 | const Core::Reporter& reporter_) |
| 655 | : ServiceFramework("fsp-srv"), fsc(fsc_), content_provider{content_provider_}, | ||
| 656 | reporter(reporter_) { | ||
| 655 | // clang-format off | 657 | // clang-format off |
| 656 | static const FunctionInfo functions[] = { | 658 | static const FunctionInfo functions[] = { |
| 657 | {0, nullptr, "OpenFileSystem"}, | 659 | {0, nullptr, "OpenFileSystem"}, |
| @@ -968,7 +970,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { | |||
| 968 | return; | 970 | return; |
| 969 | } | 971 | } |
| 970 | 972 | ||
| 971 | FileSys::PatchManager pm{title_id}; | 973 | const FileSys::PatchManager pm{title_id, fsc, content_provider}; |
| 972 | 974 | ||
| 973 | auto storage = std::make_shared<IStorage>( | 975 | auto storage = std::make_shared<IStorage>( |
| 974 | pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); | 976 | pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 4964e874e..6c7239e6a 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -12,8 +12,9 @@ class Reporter; | |||
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | namespace FileSys { | 14 | namespace FileSys { |
| 15 | class ContentProvider; | ||
| 15 | class FileSystemBackend; | 16 | class FileSystemBackend; |
| 16 | } | 17 | } // namespace FileSys |
| 17 | 18 | ||
| 18 | namespace Service::FileSystem { | 19 | namespace Service::FileSystem { |
| 19 | 20 | ||
| @@ -32,7 +33,8 @@ enum class LogMode : u32 { | |||
| 32 | 33 | ||
| 33 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { | 34 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { |
| 34 | public: | 35 | public: |
| 35 | explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter); | 36 | explicit FSP_SRV(FileSystemController& fsc_, const FileSys::ContentProvider& content_provider_, |
| 37 | const Core::Reporter& reporter_); | ||
| 36 | ~FSP_SRV() override; | 38 | ~FSP_SRV() override; |
| 37 | 39 | ||
| 38 | private: | 40 | private: |
| @@ -55,6 +57,7 @@ private: | |||
| 55 | void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); | 57 | void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); |
| 56 | 58 | ||
| 57 | FileSystemController& fsc; | 59 | FileSystemController& fsc; |
| 60 | const FileSys::ContentProvider& content_provider; | ||
| 58 | 61 | ||
| 59 | FileSys::VirtualFile romfs; | 62 | FileSys::VirtualFile romfs; |
| 60 | u64 current_process_id = 0; | 63 | u64 current_process_id = 0; |
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 58ee1f712..2594e6839 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | ||
| 6 | #include "core/file_sys/control_metadata.h" | 7 | #include "core/file_sys/control_metadata.h" |
| 7 | #include "core/file_sys/patch_manager.h" | 8 | #include "core/file_sys/patch_manager.h" |
| 8 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| @@ -29,8 +30,8 @@ IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountPro | |||
| 29 | 30 | ||
| 30 | IAccountProxyInterface::~IAccountProxyInterface() = default; | 31 | IAccountProxyInterface::~IAccountProxyInterface() = default; |
| 31 | 32 | ||
| 32 | IApplicationManagerInterface::IApplicationManagerInterface() | 33 | IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_) |
| 33 | : ServiceFramework{"IApplicationManagerInterface"} { | 34 | : ServiceFramework{"IApplicationManagerInterface"}, system{system_} { |
| 34 | // clang-format off | 35 | // clang-format off |
| 35 | static const FunctionInfo functions[] = { | 36 | static const FunctionInfo functions[] = { |
| 36 | {0, nullptr, "ListApplicationRecord"}, | 37 | {0, nullptr, "ListApplicationRecord"}, |
| @@ -298,7 +299,8 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC | |||
| 298 | 299 | ||
| 299 | const auto size = ctx.GetWriteBufferSize(); | 300 | const auto size = ctx.GetWriteBufferSize(); |
| 300 | 301 | ||
| 301 | const FileSys::PatchManager pm{title_id}; | 302 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 303 | system.GetContentProvider()}; | ||
| 302 | const auto control = pm.GetControlMetadata(); | 304 | const auto control = pm.GetControlMetadata(); |
| 303 | 305 | ||
| 304 | std::vector<u8> out; | 306 | std::vector<u8> out; |
| @@ -538,14 +540,14 @@ IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface() | |||
| 538 | 540 | ||
| 539 | IFactoryResetInterface::~IFactoryResetInterface() = default; | 541 | IFactoryResetInterface::~IFactoryResetInterface() = default; |
| 540 | 542 | ||
| 541 | NS::NS(const char* name) : ServiceFramework{name} { | 543 | NS::NS(const char* name, Core::System& system_) : ServiceFramework{name}, system{system_} { |
| 542 | // clang-format off | 544 | // clang-format off |
| 543 | static const FunctionInfo functions[] = { | 545 | static const FunctionInfo functions[] = { |
| 544 | {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, | 546 | {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, |
| 545 | {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, | 547 | {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, |
| 546 | {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, | 548 | {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, |
| 547 | {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, | 549 | {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, |
| 548 | {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, | 550 | {7996, &NS::PushIApplicationManagerInterface, "GetApplicationManagerInterface"}, |
| 549 | {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, | 551 | {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, |
| 550 | {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, | 552 | {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, |
| 551 | {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, | 553 | {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, |
| @@ -558,7 +560,7 @@ NS::NS(const char* name) : ServiceFramework{name} { | |||
| 558 | NS::~NS() = default; | 560 | NS::~NS() = default; |
| 559 | 561 | ||
| 560 | std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { | 562 | std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { |
| 561 | return GetInterface<IApplicationManagerInterface>(); | 563 | return GetInterface<IApplicationManagerInterface>(system); |
| 562 | } | 564 | } |
| 563 | 565 | ||
| 564 | class NS_DEV final : public ServiceFramework<NS_DEV> { | 566 | class NS_DEV final : public ServiceFramework<NS_DEV> { |
| @@ -678,11 +680,11 @@ public: | |||
| 678 | 680 | ||
| 679 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 681 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 680 | 682 | ||
| 681 | std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); | 683 | std::make_shared<NS>("ns:am2", system)->InstallAsService(service_manager); |
| 682 | std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); | 684 | std::make_shared<NS>("ns:ec", system)->InstallAsService(service_manager); |
| 683 | std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); | 685 | std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager); |
| 684 | std::make_shared<NS>("ns:rt")->InstallAsService(service_manager); | 686 | std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager); |
| 685 | std::make_shared<NS>("ns:web")->InstallAsService(service_manager); | 687 | std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager); |
| 686 | 688 | ||
| 687 | std::make_shared<NS_DEV>()->InstallAsService(service_manager); | 689 | std::make_shared<NS_DEV>()->InstallAsService(service_manager); |
| 688 | std::make_shared<NS_SU>()->InstallAsService(service_manager); | 690 | std::make_shared<NS_SU>()->InstallAsService(service_manager); |
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index c2554b878..c90ccd755 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | 8 | ||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service { | 13 | namespace Service { |
| 10 | 14 | ||
| 11 | namespace FileSystem { | 15 | namespace FileSystem { |
| @@ -22,7 +26,7 @@ public: | |||
| 22 | 26 | ||
| 23 | class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { | 27 | class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { |
| 24 | public: | 28 | public: |
| 25 | explicit IApplicationManagerInterface(); | 29 | explicit IApplicationManagerInterface(Core::System& system_); |
| 26 | ~IApplicationManagerInterface() override; | 30 | ~IApplicationManagerInterface() override; |
| 27 | 31 | ||
| 28 | ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages); | 32 | ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages); |
| @@ -32,6 +36,8 @@ private: | |||
| 32 | void GetApplicationControlData(Kernel::HLERequestContext& ctx); | 36 | void GetApplicationControlData(Kernel::HLERequestContext& ctx); |
| 33 | void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx); | 37 | void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx); |
| 34 | void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx); | 38 | void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx); |
| 39 | |||
| 40 | Core::System& system; | ||
| 35 | }; | 41 | }; |
| 36 | 42 | ||
| 37 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { | 43 | class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { |
| @@ -72,13 +78,13 @@ public: | |||
| 72 | 78 | ||
| 73 | class NS final : public ServiceFramework<NS> { | 79 | class NS final : public ServiceFramework<NS> { |
| 74 | public: | 80 | public: |
| 75 | explicit NS(const char* name); | 81 | explicit NS(const char* name, Core::System& system_); |
| 76 | ~NS() override; | 82 | ~NS() override; |
| 77 | 83 | ||
| 78 | std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const; | 84 | std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const; |
| 79 | 85 | ||
| 80 | private: | 86 | private: |
| 81 | template <typename T> | 87 | template <typename T, typename... Args> |
| 82 | void PushInterface(Kernel::HLERequestContext& ctx) { | 88 | void PushInterface(Kernel::HLERequestContext& ctx) { |
| 83 | LOG_DEBUG(Service_NS, "called"); | 89 | LOG_DEBUG(Service_NS, "called"); |
| 84 | 90 | ||
| @@ -87,13 +93,23 @@ private: | |||
| 87 | rb.PushIpcInterface<T>(); | 93 | rb.PushIpcInterface<T>(); |
| 88 | } | 94 | } |
| 89 | 95 | ||
| 90 | template <typename T> | 96 | void PushIApplicationManagerInterface(Kernel::HLERequestContext& ctx) { |
| 91 | std::shared_ptr<T> GetInterface() const { | 97 | LOG_DEBUG(Service_NS, "called"); |
| 98 | |||
| 99 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 100 | rb.Push(RESULT_SUCCESS); | ||
| 101 | rb.PushIpcInterface<IApplicationManagerInterface>(system); | ||
| 102 | } | ||
| 103 | |||
| 104 | template <typename T, typename... Args> | ||
| 105 | std::shared_ptr<T> GetInterface(Args&&... args) const { | ||
| 92 | static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>, | 106 | static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>, |
| 93 | "Not a base of ServiceFrameworkBase"); | 107 | "Not a base of ServiceFrameworkBase"); |
| 94 | 108 | ||
| 95 | return std::make_shared<T>(); | 109 | return std::make_shared<T>(std::forward<Args>(args)...); |
| 96 | } | 110 | } |
| 111 | |||
| 112 | Core::System& system; | ||
| 97 | }; | 113 | }; |
| 98 | 114 | ||
| 99 | /// Registers all NS services with the specified service manager. | 115 | /// Registers all NS services with the specified service manager. |
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index 0240d6643..5681599ba 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h | |||
| @@ -24,25 +24,37 @@ public: | |||
| 24 | explicit nvdevice(Core::System& system) : system{system} {} | 24 | explicit nvdevice(Core::System& system) : system{system} {} |
| 25 | virtual ~nvdevice() = default; | 25 | virtual ~nvdevice() = default; |
| 26 | 26 | ||
| 27 | union Ioctl { | 27 | /** |
| 28 | u32_le raw; | 28 | * Handles an ioctl1 request. |
| 29 | BitField<0, 8, u32> cmd; | 29 | * @param command The ioctl command id. |
| 30 | BitField<8, 8, u32> group; | 30 | * @param input A buffer containing the input data for the ioctl. |
| 31 | BitField<16, 14, u32> length; | 31 | * @param output A buffer where the output data will be written to. |
| 32 | BitField<30, 1, u32> is_in; | 32 | * @returns The result code of the ioctl. |
| 33 | BitField<31, 1, u32> is_out; | 33 | */ |
| 34 | }; | 34 | virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 35 | std::vector<u8>& output) = 0; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Handles an ioctl2 request. | ||
| 39 | * @param command The ioctl command id. | ||
| 40 | * @param input A buffer containing the input data for the ioctl. | ||
| 41 | * @param inline_input A buffer containing the input data for the ioctl which has been inlined. | ||
| 42 | * @param output A buffer where the output data will be written to. | ||
| 43 | * @returns The result code of the ioctl. | ||
| 44 | */ | ||
| 45 | virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 46 | const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; | ||
| 35 | 47 | ||
| 36 | /** | 48 | /** |
| 37 | * Handles an ioctl request. | 49 | * Handles an ioctl3 request. |
| 38 | * @param command The ioctl command id. | 50 | * @param command The ioctl command id. |
| 39 | * @param input A buffer containing the input data for the ioctl. | 51 | * @param input A buffer containing the input data for the ioctl. |
| 40 | * @param output A buffer where the output data will be written to. | 52 | * @param output A buffer where the output data will be written to. |
| 53 | * @param inline_output A buffer where the inlined output data will be written to. | ||
| 41 | * @returns The result code of the ioctl. | 54 | * @returns The result code of the ioctl. |
| 42 | */ | 55 | */ |
| 43 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 56 | virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 44 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 57 | std::vector<u8>& inline_output) = 0; |
| 45 | IoctlVersion version) = 0; | ||
| 46 | 58 | ||
| 47 | protected: | 59 | protected: |
| 48 | Core::System& system; | 60 | Core::System& system; |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 3f7b8e670..ce615c758 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | |||
| @@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de | |||
| 18 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 18 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 19 | nvdisp_disp0 ::~nvdisp_disp0() = default; | 19 | nvdisp_disp0 ::~nvdisp_disp0() = default; |
| 20 | 20 | ||
| 21 | u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 22 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | std::vector<u8>& output) { |
| 23 | IoctlVersion version) { | 23 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 24 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 24 | return NvResult::NotImplemented; |
| 25 | return 0; | 25 | } |
| 26 | |||
| 27 | NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 28 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 29 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 30 | return NvResult::NotImplemented; | ||
| 31 | } | ||
| 32 | |||
| 33 | NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 34 | std::vector<u8>& inline_output) { | ||
| 35 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 36 | return NvResult::NotImplemented; | ||
| 26 | } | 37 | } |
| 27 | 38 | ||
| 28 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, | 39 | void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, |
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 6fcdeee84..55a33b7e4 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | |||
| @@ -20,9 +20,11 @@ public: | |||
| 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 20 | explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 21 | ~nvdisp_disp0() override; | 21 | ~nvdisp_disp0() override; |
| 22 | 22 | ||
| 23 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 24 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 24 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 25 | IoctlVersion version) override; | 25 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 26 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 27 | std::vector<u8>& inline_output) override; | ||
| 26 | 28 | ||
| 27 | /// Performs a screen flip, drawing the buffer pointed to by the handle. | 29 | /// Performs a screen flip, drawing the buffer pointed to by the handle. |
| 28 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, | 30 | void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index f2529a12e..6b062e10e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -17,59 +17,77 @@ | |||
| 17 | 17 | ||
| 18 | namespace Service::Nvidia::Devices { | 18 | namespace Service::Nvidia::Devices { |
| 19 | 19 | ||
| 20 | namespace NvErrCodes { | ||
| 21 | constexpr u32 Success{}; | ||
| 22 | constexpr u32 OutOfMemory{static_cast<u32>(-12)}; | ||
| 23 | constexpr u32 InvalidInput{static_cast<u32>(-22)}; | ||
| 24 | } // namespace NvErrCodes | ||
| 25 | |||
| 26 | nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 20 | nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 27 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 21 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 28 | nvhost_as_gpu::~nvhost_as_gpu() = default; | 22 | nvhost_as_gpu::~nvhost_as_gpu() = default; |
| 29 | 23 | ||
| 30 | u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 24 | NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 31 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 25 | std::vector<u8>& output) { |
| 32 | IoctlVersion version) { | 26 | switch (command.group) { |
| 33 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 27 | case 'A': |
| 34 | command.raw, input.size(), output.size()); | 28 | switch (command.cmd) { |
| 35 | 29 | case 0x1: | |
| 36 | switch (static_cast<IoctlCommand>(command.raw)) { | 30 | return BindChannel(input, output); |
| 37 | case IoctlCommand::IocInitalizeExCommand: | 31 | case 0x2: |
| 38 | return InitalizeEx(input, output); | 32 | return AllocateSpace(input, output); |
| 39 | case IoctlCommand::IocAllocateSpaceCommand: | 33 | case 0x3: |
| 40 | return AllocateSpace(input, output); | 34 | return FreeSpace(input, output); |
| 41 | case IoctlCommand::IocMapBufferExCommand: | 35 | case 0x5: |
| 42 | return MapBufferEx(input, output); | 36 | return UnmapBuffer(input, output); |
| 43 | case IoctlCommand::IocBindChannelCommand: | 37 | case 0x6: |
| 44 | return BindChannel(input, output); | 38 | return MapBufferEx(input, output); |
| 45 | case IoctlCommand::IocGetVaRegionsCommand: | 39 | case 0x8: |
| 46 | return GetVARegions(input, output); | 40 | return GetVARegions(input, output); |
| 47 | case IoctlCommand::IocUnmapBufferCommand: | 41 | case 0x9: |
| 48 | return UnmapBuffer(input, output); | 42 | return InitalizeEx(input, output); |
| 49 | case IoctlCommand::IocFreeSpaceCommand: | 43 | case 0x14: |
| 50 | return FreeSpace(input, output); | 44 | return Remap(input, output); |
| 45 | default: | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | break; | ||
| 51 | default: | 49 | default: |
| 52 | break; | 50 | break; |
| 53 | } | 51 | } |
| 54 | 52 | ||
| 55 | if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) { | 53 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 56 | return Remap(input, output); | 54 | return NvResult::NotImplemented; |
| 57 | } | 55 | } |
| 56 | |||
| 57 | NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 58 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 59 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 60 | return NvResult::NotImplemented; | ||
| 61 | } | ||
| 58 | 62 | ||
| 59 | UNIMPLEMENTED_MSG("Unimplemented ioctl command"); | 63 | NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 60 | return 0; | 64 | std::vector<u8>& inline_output) { |
| 65 | switch (command.group) { | ||
| 66 | case 'A': | ||
| 67 | switch (command.cmd) { | ||
| 68 | case 0x8: | ||
| 69 | return GetVARegions(input, output, inline_output); | ||
| 70 | default: | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 78 | return NvResult::NotImplemented; | ||
| 61 | } | 79 | } |
| 62 | 80 | ||
| 63 | u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { | 81 | NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { |
| 64 | IoctlInitalizeEx params{}; | 82 | IoctlInitalizeEx params{}; |
| 65 | std::memcpy(¶ms, input.data(), input.size()); | 83 | std::memcpy(¶ms, input.data(), input.size()); |
| 66 | 84 | ||
| 67 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); | 85 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); |
| 68 | 86 | ||
| 69 | return 0; | 87 | return NvResult::Success; |
| 70 | } | 88 | } |
| 71 | 89 | ||
| 72 | u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { | 90 | NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { |
| 73 | IoctlAllocSpace params{}; | 91 | IoctlAllocSpace params{}; |
| 74 | std::memcpy(¶ms, input.data(), input.size()); | 92 | std::memcpy(¶ms, input.data(), input.size()); |
| 75 | 93 | ||
| @@ -83,17 +101,17 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& | |||
| 83 | params.offset = system.GPU().MemoryManager().Allocate(size, params.align); | 101 | params.offset = system.GPU().MemoryManager().Allocate(size, params.align); |
| 84 | } | 102 | } |
| 85 | 103 | ||
| 86 | auto result{NvErrCodes::Success}; | 104 | auto result = NvResult::Success; |
| 87 | if (!params.offset) { | 105 | if (!params.offset) { |
| 88 | LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); | 106 | LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); |
| 89 | result = NvErrCodes::OutOfMemory; | 107 | result = NvResult::InsufficientMemory; |
| 90 | } | 108 | } |
| 91 | 109 | ||
| 92 | std::memcpy(output.data(), ¶ms, output.size()); | 110 | std::memcpy(output.data(), ¶ms, output.size()); |
| 93 | return result; | 111 | return result; |
| 94 | } | 112 | } |
| 95 | 113 | ||
| 96 | u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { | 114 | NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { |
| 97 | IoctlFreeSpace params{}; | 115 | IoctlFreeSpace params{}; |
| 98 | std::memcpy(¶ms, input.data(), input.size()); | 116 | std::memcpy(¶ms, input.data(), input.size()); |
| 99 | 117 | ||
| @@ -104,15 +122,15 @@ u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 104 | static_cast<std::size_t>(params.pages) * params.page_size); | 122 | static_cast<std::size_t>(params.pages) * params.page_size); |
| 105 | 123 | ||
| 106 | std::memcpy(output.data(), ¶ms, output.size()); | 124 | std::memcpy(output.data(), ¶ms, output.size()); |
| 107 | return NvErrCodes::Success; | 125 | return NvResult::Success; |
| 108 | } | 126 | } |
| 109 | 127 | ||
| 110 | u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { | 128 | NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { |
| 111 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); | 129 | const auto num_entries = input.size() / sizeof(IoctlRemapEntry); |
| 112 | 130 | ||
| 113 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); | 131 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); |
| 114 | 132 | ||
| 115 | auto result{NvErrCodes::Success}; | 133 | auto result = NvResult::Success; |
| 116 | std::vector<IoctlRemapEntry> entries(num_entries); | 134 | std::vector<IoctlRemapEntry> entries(num_entries); |
| 117 | std::memcpy(entries.data(), input.data(), input.size()); | 135 | std::memcpy(entries.data(), input.data(), input.size()); |
| 118 | 136 | ||
| @@ -123,7 +141,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 123 | const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; | 141 | const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; |
| 124 | if (!object) { | 142 | if (!object) { |
| 125 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); | 143 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); |
| 126 | result = NvErrCodes::InvalidInput; | 144 | result = NvResult::InvalidState; |
| 127 | break; | 145 | break; |
| 128 | } | 146 | } |
| 129 | 147 | ||
| @@ -134,7 +152,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 134 | 152 | ||
| 135 | if (!addr) { | 153 | if (!addr) { |
| 136 | LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); | 154 | LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); |
| 137 | result = NvErrCodes::InvalidInput; | 155 | result = NvResult::InvalidState; |
| 138 | break; | 156 | break; |
| 139 | } | 157 | } |
| 140 | } | 158 | } |
| @@ -143,7 +161,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 143 | return result; | 161 | return result; |
| 144 | } | 162 | } |
| 145 | 163 | ||
| 146 | u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { | 164 | NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { |
| 147 | IoctlMapBufferEx params{}; | 165 | IoctlMapBufferEx params{}; |
| 148 | std::memcpy(¶ms, input.data(), input.size()); | 166 | std::memcpy(¶ms, input.data(), input.size()); |
| 149 | 167 | ||
| @@ -157,7 +175,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 157 | if (!object) { | 175 | if (!object) { |
| 158 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); | 176 | LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); |
| 159 | std::memcpy(output.data(), ¶ms, output.size()); | 177 | std::memcpy(output.data(), ¶ms, output.size()); |
| 160 | return NvErrCodes::InvalidInput; | 178 | return NvResult::InvalidState; |
| 161 | } | 179 | } |
| 162 | 180 | ||
| 163 | // The real nvservices doesn't make a distinction between handles and ids, and | 181 | // The real nvservices doesn't make a distinction between handles and ids, and |
| @@ -184,16 +202,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 184 | params.mapping_size, params.offset); | 202 | params.mapping_size, params.offset); |
| 185 | 203 | ||
| 186 | std::memcpy(output.data(), ¶ms, output.size()); | 204 | std::memcpy(output.data(), ¶ms, output.size()); |
| 187 | return NvErrCodes::InvalidInput; | 205 | return NvResult::InvalidState; |
| 188 | } | 206 | } |
| 189 | 207 | ||
| 190 | std::memcpy(output.data(), ¶ms, output.size()); | 208 | std::memcpy(output.data(), ¶ms, output.size()); |
| 191 | return NvErrCodes::Success; | 209 | return NvResult::Success; |
| 192 | } else { | 210 | } else { |
| 193 | LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); | 211 | LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); |
| 194 | 212 | ||
| 195 | std::memcpy(output.data(), ¶ms, output.size()); | 213 | std::memcpy(output.data(), ¶ms, output.size()); |
| 196 | return NvErrCodes::InvalidInput; | 214 | return NvResult::InvalidState; |
| 197 | } | 215 | } |
| 198 | } | 216 | } |
| 199 | 217 | ||
| @@ -213,10 +231,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 213 | params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); | 231 | params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); |
| 214 | } | 232 | } |
| 215 | 233 | ||
| 216 | auto result{NvErrCodes::Success}; | 234 | auto result = NvResult::Success; |
| 217 | if (!params.offset) { | 235 | if (!params.offset) { |
| 218 | LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); | 236 | LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); |
| 219 | result = NvErrCodes::InvalidInput; | 237 | result = NvResult::InvalidState; |
| 220 | } else { | 238 | } else { |
| 221 | AddBufferMap(params.offset, size, physical_address, is_alloc); | 239 | AddBufferMap(params.offset, size, physical_address, is_alloc); |
| 222 | } | 240 | } |
| @@ -225,7 +243,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 225 | return result; | 243 | return result; |
| 226 | } | 244 | } |
| 227 | 245 | ||
| 228 | u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | 246 | NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { |
| 229 | IoctlUnmapBuffer params{}; | 247 | IoctlUnmapBuffer params{}; |
| 230 | std::memcpy(¶ms, input.data(), input.size()); | 248 | std::memcpy(¶ms, input.data(), input.size()); |
| 231 | 249 | ||
| @@ -238,20 +256,42 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 238 | } | 256 | } |
| 239 | 257 | ||
| 240 | std::memcpy(output.data(), ¶ms, output.size()); | 258 | std::memcpy(output.data(), ¶ms, output.size()); |
| 241 | return NvErrCodes::Success; | 259 | return NvResult::Success; |
| 242 | } | 260 | } |
| 243 | 261 | ||
| 244 | u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { | 262 | NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { |
| 245 | IoctlBindChannel params{}; | 263 | IoctlBindChannel params{}; |
| 246 | std::memcpy(¶ms, input.data(), input.size()); | 264 | std::memcpy(¶ms, input.data(), input.size()); |
| 247 | 265 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd); | |
| 248 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); | ||
| 249 | 266 | ||
| 250 | channel = params.fd; | 267 | channel = params.fd; |
| 251 | return 0; | 268 | return NvResult::Success; |
| 269 | } | ||
| 270 | |||
| 271 | NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 272 | IoctlGetVaRegions params{}; | ||
| 273 | std::memcpy(¶ms, input.data(), input.size()); | ||
| 274 | |||
| 275 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, | ||
| 276 | params.buf_size); | ||
| 277 | |||
| 278 | params.buf_size = 0x30; | ||
| 279 | params.regions[0].offset = 0x04000000; | ||
| 280 | params.regions[0].page_size = 0x1000; | ||
| 281 | params.regions[0].pages = 0x3fbfff; | ||
| 282 | |||
| 283 | params.regions[1].offset = 0x04000000; | ||
| 284 | params.regions[1].page_size = 0x10000; | ||
| 285 | params.regions[1].pages = 0x1bffff; | ||
| 286 | |||
| 287 | // TODO(ogniK): This probably can stay stubbed but should add support way way later | ||
| 288 | |||
| 289 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 290 | return NvResult::Success; | ||
| 252 | } | 291 | } |
| 253 | 292 | ||
| 254 | u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { | 293 | NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, |
| 294 | std::vector<u8>& inline_output) { | ||
| 255 | IoctlGetVaRegions params{}; | 295 | IoctlGetVaRegions params{}; |
| 256 | std::memcpy(¶ms, input.data(), input.size()); | 296 | std::memcpy(¶ms, input.data(), input.size()); |
| 257 | 297 | ||
| @@ -270,7 +310,8 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o | |||
| 270 | // TODO(ogniK): This probably can stay stubbed but should add support way way later | 310 | // TODO(ogniK): This probably can stay stubbed but should add support way way later |
| 271 | 311 | ||
| 272 | std::memcpy(output.data(), ¶ms, output.size()); | 312 | std::memcpy(output.data(), ¶ms, output.size()); |
| 273 | return 0; | 313 | std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size()); |
| 314 | return NvResult::Success; | ||
| 274 | } | 315 | } |
| 275 | 316 | ||
| 276 | std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { | 317 | std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index fcdb40d93..08035fa0e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | |||
| @@ -30,9 +30,11 @@ public: | |||
| 30 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 30 | explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 31 | ~nvhost_as_gpu() override; | 31 | ~nvhost_as_gpu() override; |
| 32 | 32 | ||
| 33 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 33 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 34 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 34 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 35 | IoctlVersion version) override; | 35 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 36 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 37 | std::vector<u8>& inline_output) override; | ||
| 36 | 38 | ||
| 37 | private: | 39 | private: |
| 38 | class BufferMap final { | 40 | class BufferMap final { |
| @@ -74,32 +76,21 @@ private: | |||
| 74 | bool is_allocated{}; | 76 | bool is_allocated{}; |
| 75 | }; | 77 | }; |
| 76 | 78 | ||
| 77 | enum class IoctlCommand : u32_le { | ||
| 78 | IocInitalizeExCommand = 0x40284109, | ||
| 79 | IocAllocateSpaceCommand = 0xC0184102, | ||
| 80 | IocRemapCommand = 0x00000014, | ||
| 81 | IocMapBufferExCommand = 0xC0284106, | ||
| 82 | IocBindChannelCommand = 0x40044101, | ||
| 83 | IocGetVaRegionsCommand = 0xC0404108, | ||
| 84 | IocUnmapBufferCommand = 0xC0084105, | ||
| 85 | IocFreeSpaceCommand = 0xC0104103, | ||
| 86 | }; | ||
| 87 | |||
| 88 | struct IoctlInitalizeEx { | 79 | struct IoctlInitalizeEx { |
| 89 | u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default | 80 | u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default |
| 90 | s32_le as_fd; // ignored; passes 0 | 81 | s32_le as_fd{}; // ignored; passes 0 |
| 91 | u32_le flags; // passes 0 | 82 | u32_le flags{}; // passes 0 |
| 92 | u32_le reserved; // ignored; passes 0 | 83 | u32_le reserved{}; // ignored; passes 0 |
| 93 | u64_le unk0; | 84 | u64_le unk0{}; |
| 94 | u64_le unk1; | 85 | u64_le unk1{}; |
| 95 | u64_le unk2; | 86 | u64_le unk2{}; |
| 96 | }; | 87 | }; |
| 97 | static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); | 88 | static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); |
| 98 | 89 | ||
| 99 | struct IoctlAllocSpace { | 90 | struct IoctlAllocSpace { |
| 100 | u32_le pages; | 91 | u32_le pages{}; |
| 101 | u32_le page_size; | 92 | u32_le page_size{}; |
| 102 | AddressSpaceFlags flags; | 93 | AddressSpaceFlags flags{}; |
| 103 | INSERT_PADDING_WORDS(1); | 94 | INSERT_PADDING_WORDS(1); |
| 104 | union { | 95 | union { |
| 105 | u64_le offset; | 96 | u64_le offset; |
| @@ -109,70 +100,73 @@ private: | |||
| 109 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); | 100 | static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); |
| 110 | 101 | ||
| 111 | struct IoctlFreeSpace { | 102 | struct IoctlFreeSpace { |
| 112 | u64_le offset; | 103 | u64_le offset{}; |
| 113 | u32_le pages; | 104 | u32_le pages{}; |
| 114 | u32_le page_size; | 105 | u32_le page_size{}; |
| 115 | }; | 106 | }; |
| 116 | static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); | 107 | static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); |
| 117 | 108 | ||
| 118 | struct IoctlRemapEntry { | 109 | struct IoctlRemapEntry { |
| 119 | u16_le flags; | 110 | u16_le flags{}; |
| 120 | u16_le kind; | 111 | u16_le kind{}; |
| 121 | u32_le nvmap_handle; | 112 | u32_le nvmap_handle{}; |
| 122 | u32_le map_offset; | 113 | u32_le map_offset{}; |
| 123 | u32_le offset; | 114 | u32_le offset{}; |
| 124 | u32_le pages; | 115 | u32_le pages{}; |
| 125 | }; | 116 | }; |
| 126 | static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); | 117 | static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); |
| 127 | 118 | ||
| 128 | struct IoctlMapBufferEx { | 119 | struct IoctlMapBufferEx { |
| 129 | AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable | 120 | AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable |
| 130 | u32_le kind; // -1 is default | 121 | u32_le kind{}; // -1 is default |
| 131 | u32_le nvmap_handle; | 122 | u32_le nvmap_handle{}; |
| 132 | u32_le page_size; // 0 means don't care | 123 | u32_le page_size{}; // 0 means don't care |
| 133 | s64_le buffer_offset; | 124 | s64_le buffer_offset{}; |
| 134 | u64_le mapping_size; | 125 | u64_le mapping_size{}; |
| 135 | s64_le offset; | 126 | s64_le offset{}; |
| 136 | }; | 127 | }; |
| 137 | static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); | 128 | static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); |
| 138 | 129 | ||
| 139 | struct IoctlUnmapBuffer { | 130 | struct IoctlUnmapBuffer { |
| 140 | s64_le offset; | 131 | s64_le offset{}; |
| 141 | }; | 132 | }; |
| 142 | static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); | 133 | static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); |
| 143 | 134 | ||
| 144 | struct IoctlBindChannel { | 135 | struct IoctlBindChannel { |
| 145 | u32_le fd; | 136 | s32_le fd{}; |
| 146 | }; | 137 | }; |
| 147 | static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); | 138 | static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); |
| 148 | 139 | ||
| 149 | struct IoctlVaRegion { | 140 | struct IoctlVaRegion { |
| 150 | u64_le offset; | 141 | u64_le offset{}; |
| 151 | u32_le page_size; | 142 | u32_le page_size{}; |
| 152 | INSERT_PADDING_WORDS(1); | 143 | INSERT_PADDING_WORDS(1); |
| 153 | u64_le pages; | 144 | u64_le pages{}; |
| 154 | }; | 145 | }; |
| 155 | static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); | 146 | static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); |
| 156 | 147 | ||
| 157 | struct IoctlGetVaRegions { | 148 | struct IoctlGetVaRegions { |
| 158 | u64_le buf_addr; // (contained output user ptr on linux, ignored) | 149 | u64_le buf_addr{}; // (contained output user ptr on linux, ignored) |
| 159 | u32_le buf_size; // forced to 2*sizeof(struct va_region) | 150 | u32_le buf_size{}; // forced to 2*sizeof(struct va_region) |
| 160 | u32_le reserved; | 151 | u32_le reserved{}; |
| 161 | IoctlVaRegion regions[2]; | 152 | IoctlVaRegion regions[2]{}; |
| 162 | }; | 153 | }; |
| 163 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, | 154 | static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, |
| 164 | "IoctlGetVaRegions is incorrect size"); | 155 | "IoctlGetVaRegions is incorrect size"); |
| 165 | 156 | ||
| 166 | u32 channel{}; | 157 | s32 channel{}; |
| 158 | |||
| 159 | NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 160 | NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 161 | NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 162 | NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 163 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 164 | NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 165 | NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 167 | 166 | ||
| 168 | u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); | 167 | NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); |
| 169 | u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); | 168 | NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output, |
| 170 | u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); | 169 | std::vector<u8>& inline_output); |
| 171 | u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 172 | u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 173 | u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 174 | u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 175 | u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 176 | 170 | ||
| 177 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; | 171 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; |
| 178 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); | 172 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 8356a8139..d90cf90a8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -20,41 +20,54 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface, | |||
| 20 | : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} | 20 | : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} |
| 21 | nvhost_ctrl::~nvhost_ctrl() = default; | 21 | nvhost_ctrl::~nvhost_ctrl() = default; |
| 22 | 22 | ||
| 23 | u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 24 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 24 | switch (command.group) { |
| 25 | IoctlVersion version) { | 25 | case 0x0: |
| 26 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 26 | switch (command.cmd) { |
| 27 | command.raw, input.size(), output.size()); | 27 | case 0x1b: |
| 28 | 28 | return NvOsGetConfigU32(input, output); | |
| 29 | switch (static_cast<IoctlCommand>(command.raw)) { | 29 | case 0x1c: |
| 30 | case IoctlCommand::IocGetConfigCommand: | 30 | return IocCtrlClearEventWait(input, output); |
| 31 | return NvOsGetConfigU32(input, output); | 31 | case 0x1d: |
| 32 | case IoctlCommand::IocCtrlEventWaitCommand: | 32 | return IocCtrlEventWait(input, output, false); |
| 33 | return IocCtrlEventWait(input, output, false, ctrl); | 33 | case 0x1e: |
| 34 | case IoctlCommand::IocCtrlEventWaitAsyncCommand: | 34 | return IocCtrlEventWait(input, output, true); |
| 35 | return IocCtrlEventWait(input, output, true, ctrl); | 35 | case 0x1f: |
| 36 | case IoctlCommand::IocCtrlEventRegisterCommand: | 36 | return IocCtrlEventRegister(input, output); |
| 37 | return IocCtrlEventRegister(input, output); | 37 | case 0x20: |
| 38 | case IoctlCommand::IocCtrlEventUnregisterCommand: | 38 | return IocCtrlEventUnregister(input, output); |
| 39 | return IocCtrlEventUnregister(input, output); | 39 | } |
| 40 | case IoctlCommand::IocCtrlClearEventWaitCommand: | 40 | break; |
| 41 | return IocCtrlClearEventWait(input, output); | ||
| 42 | default: | 41 | default: |
| 43 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 42 | break; |
| 44 | return 0; | ||
| 45 | } | 43 | } |
| 44 | |||
| 45 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 46 | return NvResult::NotImplemented; | ||
| 47 | } | ||
| 48 | |||
| 49 | NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 50 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 51 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 52 | return NvResult::NotImplemented; | ||
| 53 | } | ||
| 54 | |||
| 55 | NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 56 | std::vector<u8>& inline_output) { | ||
| 57 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 58 | return NvResult::NotImplemented; | ||
| 46 | } | 59 | } |
| 47 | 60 | ||
| 48 | u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { | 61 | NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { |
| 49 | IocGetConfigParams params{}; | 62 | IocGetConfigParams params{}; |
| 50 | std::memcpy(¶ms, input.data(), sizeof(params)); | 63 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 51 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), | 64 | LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), |
| 52 | params.param_str.data()); | 65 | params.param_str.data()); |
| 53 | return 0x30006; // Returns error on production mode | 66 | return NvResult::ConfigVarNotFound; // Returns error on production mode |
| 54 | } | 67 | } |
| 55 | 68 | ||
| 56 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, | 69 | NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, |
| 57 | bool is_async, IoctlCtrl& ctrl) { | 70 | bool is_async) { |
| 58 | IocCtrlEventWaitParams params{}; | 71 | IocCtrlEventWaitParams params{}; |
| 59 | std::memcpy(¶ms, input.data(), sizeof(params)); | 72 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 60 | LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", | 73 | LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", |
| @@ -126,10 +139,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 126 | params.value |= event_id; | 139 | params.value |= event_id; |
| 127 | event.event.writable->Clear(); | 140 | event.event.writable->Clear(); |
| 128 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); | 141 | gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); |
| 129 | if (!is_async && ctrl.fresh_call) { | 142 | if (!is_async) { |
| 130 | ctrl.must_delay = true; | ||
| 131 | ctrl.timeout = params.timeout; | ||
| 132 | ctrl.event_id = event_id; | ||
| 133 | return NvResult::Timeout; | 143 | return NvResult::Timeout; |
| 134 | } | 144 | } |
| 135 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 145 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| @@ -139,7 +149,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& | |||
| 139 | return NvResult::BadParameter; | 149 | return NvResult::BadParameter; |
| 140 | } | 150 | } |
| 141 | 151 | ||
| 142 | u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { | 152 | NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { |
| 143 | IocCtrlEventRegisterParams params{}; | 153 | IocCtrlEventRegisterParams params{}; |
| 144 | std::memcpy(¶ms, input.data(), sizeof(params)); | 154 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 145 | const u32 event_id = params.user_event_id & 0x00FF; | 155 | const u32 event_id = params.user_event_id & 0x00FF; |
| @@ -154,7 +164,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector< | |||
| 154 | return NvResult::Success; | 164 | return NvResult::Success; |
| 155 | } | 165 | } |
| 156 | 166 | ||
| 157 | u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { | 167 | NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, |
| 168 | std::vector<u8>& output) { | ||
| 158 | IocCtrlEventUnregisterParams params{}; | 169 | IocCtrlEventUnregisterParams params{}; |
| 159 | std::memcpy(¶ms, input.data(), sizeof(params)); | 170 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 160 | const u32 event_id = params.user_event_id & 0x00FF; | 171 | const u32 event_id = params.user_event_id & 0x00FF; |
| @@ -169,7 +180,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto | |||
| 169 | return NvResult::Success; | 180 | return NvResult::Success; |
| 170 | } | 181 | } |
| 171 | 182 | ||
| 172 | u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { | 183 | NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { |
| 173 | IocCtrlEventSignalParams params{}; | 184 | IocCtrlEventSignalParams params{}; |
| 174 | std::memcpy(¶ms, input.data(), sizeof(params)); | 185 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 175 | 186 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 24ad96cb9..c5aa1362a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -18,132 +18,113 @@ public: | |||
| 18 | SyncpointManager& syncpoint_manager); | 18 | SyncpointManager& syncpoint_manager); |
| 19 | ~nvhost_ctrl() override; | 19 | ~nvhost_ctrl() override; |
| 20 | 20 | ||
| 21 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 22 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 23 | IoctlVersion version) override; | 23 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 24 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 25 | std::vector<u8>& inline_output) override; | ||
| 24 | 26 | ||
| 25 | private: | 27 | private: |
| 26 | enum class IoctlCommand : u32_le { | ||
| 27 | IocSyncptReadCommand = 0xC0080014, | ||
| 28 | IocSyncptIncrCommand = 0x40040015, | ||
| 29 | IocSyncptWaitCommand = 0xC00C0016, | ||
| 30 | IocModuleMutexCommand = 0x40080017, | ||
| 31 | IocModuleRegRDWRCommand = 0xC0180018, | ||
| 32 | IocSyncptWaitexCommand = 0xC0100019, | ||
| 33 | IocSyncptReadMaxCommand = 0xC008001A, | ||
| 34 | IocGetConfigCommand = 0xC183001B, | ||
| 35 | IocCtrlClearEventWaitCommand = 0xC004001C, | ||
| 36 | IocCtrlEventWaitCommand = 0xC010001D, | ||
| 37 | IocCtrlEventWaitAsyncCommand = 0xC010001E, | ||
| 38 | IocCtrlEventRegisterCommand = 0xC004001F, | ||
| 39 | IocCtrlEventUnregisterCommand = 0xC0040020, | ||
| 40 | IocCtrlEventKillCommand = 0x40080021, | ||
| 41 | }; | ||
| 42 | struct IocSyncptReadParams { | 28 | struct IocSyncptReadParams { |
| 43 | u32_le id; | 29 | u32_le id{}; |
| 44 | u32_le value; | 30 | u32_le value{}; |
| 45 | }; | 31 | }; |
| 46 | static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); | 32 | static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); |
| 47 | 33 | ||
| 48 | struct IocSyncptIncrParams { | 34 | struct IocSyncptIncrParams { |
| 49 | u32_le id; | 35 | u32_le id{}; |
| 50 | }; | 36 | }; |
| 51 | static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); | 37 | static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); |
| 52 | 38 | ||
| 53 | struct IocSyncptWaitParams { | 39 | struct IocSyncptWaitParams { |
| 54 | u32_le id; | 40 | u32_le id{}; |
| 55 | u32_le thresh; | 41 | u32_le thresh{}; |
| 56 | s32_le timeout; | 42 | s32_le timeout{}; |
| 57 | }; | 43 | }; |
| 58 | static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); | 44 | static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); |
| 59 | 45 | ||
| 60 | struct IocModuleMutexParams { | 46 | struct IocModuleMutexParams { |
| 61 | u32_le id; | 47 | u32_le id{}; |
| 62 | u32_le lock; // (0 = unlock and 1 = lock) | 48 | u32_le lock{}; // (0 = unlock and 1 = lock) |
| 63 | }; | 49 | }; |
| 64 | static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); | 50 | static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); |
| 65 | 51 | ||
| 66 | struct IocModuleRegRDWRParams { | 52 | struct IocModuleRegRDWRParams { |
| 67 | u32_le id; | 53 | u32_le id{}; |
| 68 | u32_le num_offsets; | 54 | u32_le num_offsets{}; |
| 69 | u32_le block_size; | 55 | u32_le block_size{}; |
| 70 | u32_le offsets; | 56 | u32_le offsets{}; |
| 71 | u32_le values; | 57 | u32_le values{}; |
| 72 | u32_le write; | 58 | u32_le write{}; |
| 73 | }; | 59 | }; |
| 74 | static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); | 60 | static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); |
| 75 | 61 | ||
| 76 | struct IocSyncptWaitexParams { | 62 | struct IocSyncptWaitexParams { |
| 77 | u32_le id; | 63 | u32_le id{}; |
| 78 | u32_le thresh; | 64 | u32_le thresh{}; |
| 79 | s32_le timeout; | 65 | s32_le timeout{}; |
| 80 | u32_le value; | 66 | u32_le value{}; |
| 81 | }; | 67 | }; |
| 82 | static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); | 68 | static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); |
| 83 | 69 | ||
| 84 | struct IocSyncptReadMaxParams { | 70 | struct IocSyncptReadMaxParams { |
| 85 | u32_le id; | 71 | u32_le id{}; |
| 86 | u32_le value; | 72 | u32_le value{}; |
| 87 | }; | 73 | }; |
| 88 | static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); | 74 | static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); |
| 89 | 75 | ||
| 90 | struct IocGetConfigParams { | 76 | struct IocGetConfigParams { |
| 91 | std::array<char, 0x41> domain_str; | 77 | std::array<char, 0x41> domain_str{}; |
| 92 | std::array<char, 0x41> param_str; | 78 | std::array<char, 0x41> param_str{}; |
| 93 | std::array<char, 0x101> config_str; | 79 | std::array<char, 0x101> config_str{}; |
| 94 | }; | 80 | }; |
| 95 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); | 81 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); |
| 96 | 82 | ||
| 97 | struct IocCtrlEventSignalParams { | 83 | struct IocCtrlEventSignalParams { |
| 98 | u32_le event_id; | 84 | u32_le event_id{}; |
| 99 | }; | 85 | }; |
| 100 | static_assert(sizeof(IocCtrlEventSignalParams) == 4, | 86 | static_assert(sizeof(IocCtrlEventSignalParams) == 4, |
| 101 | "IocCtrlEventSignalParams is incorrect size"); | 87 | "IocCtrlEventSignalParams is incorrect size"); |
| 102 | 88 | ||
| 103 | struct IocCtrlEventWaitParams { | 89 | struct IocCtrlEventWaitParams { |
| 104 | u32_le syncpt_id; | 90 | u32_le syncpt_id{}; |
| 105 | u32_le threshold; | 91 | u32_le threshold{}; |
| 106 | s32_le timeout; | 92 | s32_le timeout{}; |
| 107 | u32_le value; | 93 | u32_le value{}; |
| 108 | }; | 94 | }; |
| 109 | static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); | 95 | static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); |
| 110 | 96 | ||
| 111 | struct IocCtrlEventWaitAsyncParams { | 97 | struct IocCtrlEventWaitAsyncParams { |
| 112 | u32_le syncpt_id; | 98 | u32_le syncpt_id{}; |
| 113 | u32_le threshold; | 99 | u32_le threshold{}; |
| 114 | u32_le timeout; | 100 | u32_le timeout{}; |
| 115 | u32_le value; | 101 | u32_le value{}; |
| 116 | }; | 102 | }; |
| 117 | static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, | 103 | static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, |
| 118 | "IocCtrlEventWaitAsyncParams is incorrect size"); | 104 | "IocCtrlEventWaitAsyncParams is incorrect size"); |
| 119 | 105 | ||
| 120 | struct IocCtrlEventRegisterParams { | 106 | struct IocCtrlEventRegisterParams { |
| 121 | u32_le user_event_id; | 107 | u32_le user_event_id{}; |
| 122 | }; | 108 | }; |
| 123 | static_assert(sizeof(IocCtrlEventRegisterParams) == 4, | 109 | static_assert(sizeof(IocCtrlEventRegisterParams) == 4, |
| 124 | "IocCtrlEventRegisterParams is incorrect size"); | 110 | "IocCtrlEventRegisterParams is incorrect size"); |
| 125 | 111 | ||
| 126 | struct IocCtrlEventUnregisterParams { | 112 | struct IocCtrlEventUnregisterParams { |
| 127 | u32_le user_event_id; | 113 | u32_le user_event_id{}; |
| 128 | }; | 114 | }; |
| 129 | static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, | 115 | static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, |
| 130 | "IocCtrlEventUnregisterParams is incorrect size"); | 116 | "IocCtrlEventUnregisterParams is incorrect size"); |
| 131 | 117 | ||
| 132 | struct IocCtrlEventKill { | 118 | struct IocCtrlEventKill { |
| 133 | u64_le user_events; | 119 | u64_le user_events{}; |
| 134 | }; | 120 | }; |
| 135 | static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); | 121 | static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); |
| 136 | 122 | ||
| 137 | u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); | 123 | NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); |
| 138 | 124 | NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); | |
| 139 | u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, | 125 | NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); |
| 140 | IoctlCtrl& ctrl); | 126 | NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); |
| 141 | 127 | NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); | |
| 142 | u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 143 | |||
| 144 | u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 145 | |||
| 146 | u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 147 | 128 | ||
| 148 | EventInterface& events_interface; | 129 | EventInterface& events_interface; |
| 149 | SyncpointManager& syncpoint_manager; | 130 | SyncpointManager& syncpoint_manager; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index fba89e7a6..2d7ea433c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -15,39 +15,66 @@ namespace Service::Nvidia::Devices { | |||
| 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} | 15 | nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} |
| 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; | 16 | nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, | 18 | NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 19 | const std::vector<u8>& input2, std::vector<u8>& output, | 19 | std::vector<u8>& output) { |
| 20 | std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { | 20 | switch (command.group) { |
| 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | case 'G': |
| 22 | command.raw, input.size(), output.size()); | 22 | switch (command.cmd) { |
| 23 | 23 | case 0x1: | |
| 24 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | return ZCullGetCtxSize(input, output); |
| 25 | case IoctlCommand::IocGetCharacteristicsCommand: | 25 | case 0x2: |
| 26 | return GetCharacteristics(input, output, output2, version); | 26 | return ZCullGetInfo(input, output); |
| 27 | case IoctlCommand::IocGetTPCMasksCommand: | 27 | case 0x3: |
| 28 | return GetTPCMasks(input, output, output2, version); | 28 | return ZBCSetTable(input, output); |
| 29 | case IoctlCommand::IocGetActiveSlotMaskCommand: | 29 | case 0x4: |
| 30 | return GetActiveSlotMask(input, output); | 30 | return ZBCQueryTable(input, output); |
| 31 | case IoctlCommand::IocZcullGetCtxSizeCommand: | 31 | case 0x5: |
| 32 | return ZCullGetCtxSize(input, output); | 32 | return GetCharacteristics(input, output); |
| 33 | case IoctlCommand::IocZcullGetInfo: | 33 | case 0x6: |
| 34 | return ZCullGetInfo(input, output); | 34 | return GetTPCMasks(input, output); |
| 35 | case IoctlCommand::IocZbcSetTable: | 35 | case 0x7: |
| 36 | return ZBCSetTable(input, output); | 36 | return FlushL2(input, output); |
| 37 | case IoctlCommand::IocZbcQueryTable: | 37 | case 0x14: |
| 38 | return ZBCQueryTable(input, output); | 38 | return GetActiveSlotMask(input, output); |
| 39 | case IoctlCommand::IocFlushL2: | 39 | case 0x1c: |
| 40 | return FlushL2(input, output); | 40 | return GetGpuTime(input, output); |
| 41 | case IoctlCommand::IocGetGpuTime: | 41 | default: |
| 42 | return GetGpuTime(input, output); | 42 | break; |
| 43 | } | ||
| 44 | break; | ||
| 45 | } | ||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 47 | return NvResult::NotImplemented; | ||
| 48 | } | ||
| 49 | |||
| 50 | NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 51 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 52 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 53 | return NvResult::NotImplemented; | ||
| 54 | } | ||
| 55 | |||
| 56 | NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, | ||
| 57 | std::vector<u8>& output, std::vector<u8>& inline_output) { | ||
| 58 | switch (command.group) { | ||
| 59 | case 'G': | ||
| 60 | switch (command.cmd) { | ||
| 61 | case 0x5: | ||
| 62 | return GetCharacteristics(input, output, inline_output); | ||
| 63 | case 0x6: | ||
| 64 | return GetTPCMasks(input, output, inline_output); | ||
| 65 | default: | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | break; | ||
| 43 | default: | 69 | default: |
| 44 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 70 | break; |
| 45 | return 0; | ||
| 46 | } | 71 | } |
| 72 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 73 | return NvResult::NotImplemented; | ||
| 47 | } | 74 | } |
| 48 | 75 | ||
| 49 | u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, | 76 | NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, |
| 50 | std::vector<u8>& output2, IoctlVersion version) { | 77 | std::vector<u8>& output) { |
| 51 | LOG_DEBUG(Service_NVDRV, "called"); | 78 | LOG_DEBUG(Service_NVDRV, "called"); |
| 52 | IoctlCharacteristics params{}; | 79 | IoctlCharacteristics params{}; |
| 53 | std::memcpy(¶ms, input.data(), input.size()); | 80 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -88,36 +115,83 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto | |||
| 88 | params.gc.gr_compbit_store_base_hw = 0x0; | 115 | params.gc.gr_compbit_store_base_hw = 0x0; |
| 89 | params.gpu_characteristics_buf_size = 0xA0; | 116 | params.gpu_characteristics_buf_size = 0xA0; |
| 90 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) | 117 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) |
| 118 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 119 | return NvResult::Success; | ||
| 120 | } | ||
| 91 | 121 | ||
| 92 | if (version == IoctlVersion::Version3) { | 122 | NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 93 | std::memcpy(output.data(), input.data(), output.size()); | 123 | std::vector<u8>& inline_output) { |
| 94 | std::memcpy(output2.data(), ¶ms.gc, output2.size()); | 124 | LOG_DEBUG(Service_NVDRV, "called"); |
| 95 | } else { | 125 | IoctlCharacteristics params{}; |
| 96 | std::memcpy(output.data(), ¶ms, output.size()); | 126 | std::memcpy(¶ms, input.data(), input.size()); |
| 97 | } | 127 | params.gc.arch = 0x120; |
| 98 | return 0; | 128 | params.gc.impl = 0xb; |
| 129 | params.gc.rev = 0xa1; | ||
| 130 | params.gc.num_gpc = 0x1; | ||
| 131 | params.gc.l2_cache_size = 0x40000; | ||
| 132 | params.gc.on_board_video_memory_size = 0x0; | ||
| 133 | params.gc.num_tpc_per_gpc = 0x2; | ||
| 134 | params.gc.bus_type = 0x20; | ||
| 135 | params.gc.big_page_size = 0x20000; | ||
| 136 | params.gc.compression_page_size = 0x20000; | ||
| 137 | params.gc.pde_coverage_bit_count = 0x1B; | ||
| 138 | params.gc.available_big_page_sizes = 0x30000; | ||
| 139 | params.gc.gpc_mask = 0x1; | ||
| 140 | params.gc.sm_arch_sm_version = 0x503; | ||
| 141 | params.gc.sm_arch_spa_version = 0x503; | ||
| 142 | params.gc.sm_arch_warp_count = 0x80; | ||
| 143 | params.gc.gpu_va_bit_count = 0x28; | ||
| 144 | params.gc.reserved = 0x0; | ||
| 145 | params.gc.flags = 0x55; | ||
| 146 | params.gc.twod_class = 0x902D; | ||
| 147 | params.gc.threed_class = 0xB197; | ||
| 148 | params.gc.compute_class = 0xB1C0; | ||
| 149 | params.gc.gpfifo_class = 0xB06F; | ||
| 150 | params.gc.inline_to_memory_class = 0xA140; | ||
| 151 | params.gc.dma_copy_class = 0xB0B5; | ||
| 152 | params.gc.max_fbps_count = 0x1; | ||
| 153 | params.gc.fbp_en_mask = 0x0; | ||
| 154 | params.gc.max_ltc_per_fbp = 0x2; | ||
| 155 | params.gc.max_lts_per_ltc = 0x1; | ||
| 156 | params.gc.max_tex_per_tpc = 0x0; | ||
| 157 | params.gc.max_gpc_count = 0x1; | ||
| 158 | params.gc.rop_l2_en_mask_0 = 0x21D70; | ||
| 159 | params.gc.rop_l2_en_mask_1 = 0x0; | ||
| 160 | params.gc.chipname = 0x6230326D67; | ||
| 161 | params.gc.gr_compbit_store_base_hw = 0x0; | ||
| 162 | params.gpu_characteristics_buf_size = 0xA0; | ||
| 163 | params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) | ||
| 164 | |||
| 165 | std::memcpy(output.data(), input.data(), output.size()); | ||
| 166 | std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size()); | ||
| 167 | return NvResult::Success; | ||
| 99 | } | 168 | } |
| 100 | 169 | ||
| 101 | u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, | 170 | NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) { |
| 102 | std::vector<u8>& output2, IoctlVersion version) { | ||
| 103 | IoctlGpuGetTpcMasksArgs params{}; | 171 | IoctlGpuGetTpcMasksArgs params{}; |
| 104 | std::memcpy(¶ms, input.data(), input.size()); | 172 | std::memcpy(¶ms, input.data(), input.size()); |
| 105 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); | 173 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| 106 | if (params.mask_buffer_size != 0) { | 174 | if (params.mask_buffer_size != 0) { |
| 107 | params.tcp_mask = 3; | 175 | params.tcp_mask = 3; |
| 108 | } | 176 | } |
| 177 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 178 | return NvResult::Success; | ||
| 179 | } | ||
| 109 | 180 | ||
| 110 | if (version == IoctlVersion::Version3) { | 181 | NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, |
| 111 | std::memcpy(output.data(), input.data(), output.size()); | 182 | std::vector<u8>& inline_output) { |
| 112 | std::memcpy(output2.data(), ¶ms.tcp_mask, output2.size()); | 183 | IoctlGpuGetTpcMasksArgs params{}; |
| 113 | } else { | 184 | std::memcpy(¶ms, input.data(), input.size()); |
| 114 | std::memcpy(output.data(), ¶ms, output.size()); | 185 | LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); |
| 186 | if (params.mask_buffer_size != 0) { | ||
| 187 | params.tcp_mask = 3; | ||
| 115 | } | 188 | } |
| 116 | 189 | std::memcpy(output.data(), ¶ms, output.size()); | |
| 117 | return 0; | 190 | std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size()); |
| 191 | return NvResult::Success; | ||
| 118 | } | 192 | } |
| 119 | 193 | ||
| 120 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { | 194 | NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { |
| 121 | LOG_DEBUG(Service_NVDRV, "called"); | 195 | LOG_DEBUG(Service_NVDRV, "called"); |
| 122 | 196 | ||
| 123 | IoctlActiveSlotMask params{}; | 197 | IoctlActiveSlotMask params{}; |
| @@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector | |||
| 127 | params.slot = 0x07; | 201 | params.slot = 0x07; |
| 128 | params.mask = 0x01; | 202 | params.mask = 0x01; |
| 129 | std::memcpy(output.data(), ¶ms, output.size()); | 203 | std::memcpy(output.data(), ¶ms, output.size()); |
| 130 | return 0; | 204 | return NvResult::Success; |
| 131 | } | 205 | } |
| 132 | 206 | ||
| 133 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { | 207 | NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { |
| 134 | LOG_DEBUG(Service_NVDRV, "called"); | 208 | LOG_DEBUG(Service_NVDRV, "called"); |
| 135 | 209 | ||
| 136 | IoctlZcullGetCtxSize params{}; | 210 | IoctlZcullGetCtxSize params{}; |
| @@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u | |||
| 139 | } | 213 | } |
| 140 | params.size = 0x1; | 214 | params.size = 0x1; |
| 141 | std::memcpy(output.data(), ¶ms, output.size()); | 215 | std::memcpy(output.data(), ¶ms, output.size()); |
| 142 | return 0; | 216 | return NvResult::Success; |
| 143 | } | 217 | } |
| 144 | 218 | ||
| 145 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { | 219 | NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { |
| 146 | LOG_DEBUG(Service_NVDRV, "called"); | 220 | LOG_DEBUG(Service_NVDRV, "called"); |
| 147 | 221 | ||
| 148 | IoctlNvgpuGpuZcullGetInfoArgs params{}; | 222 | IoctlNvgpuGpuZcullGetInfoArgs params{}; |
| @@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& | |||
| 162 | params.subregion_height_align_pixels = 0x40; | 236 | params.subregion_height_align_pixels = 0x40; |
| 163 | params.subregion_count = 0x10; | 237 | params.subregion_count = 0x10; |
| 164 | std::memcpy(output.data(), ¶ms, output.size()); | 238 | std::memcpy(output.data(), ¶ms, output.size()); |
| 165 | return 0; | 239 | return NvResult::Success; |
| 166 | } | 240 | } |
| 167 | 241 | ||
| 168 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { | 242 | NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 169 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 243 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 170 | 244 | ||
| 171 | IoctlZbcSetTable params{}; | 245 | IoctlZbcSetTable params{}; |
| 172 | std::memcpy(¶ms, input.data(), input.size()); | 246 | std::memcpy(¶ms, input.data(), input.size()); |
| 173 | // TODO(ogniK): What does this even actually do? | 247 | // TODO(ogniK): What does this even actually do? |
| 174 | std::memcpy(output.data(), ¶ms, output.size()); | 248 | std::memcpy(output.data(), ¶ms, output.size()); |
| 175 | return 0; | 249 | return NvResult::Success; |
| 176 | } | 250 | } |
| 177 | 251 | ||
| 178 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { | 252 | NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 179 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 253 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 180 | 254 | ||
| 181 | IoctlZbcQueryTable params{}; | 255 | IoctlZbcQueryTable params{}; |
| 182 | std::memcpy(¶ms, input.data(), input.size()); | 256 | std::memcpy(¶ms, input.data(), input.size()); |
| 183 | // TODO : To implement properly | 257 | // TODO : To implement properly |
| 184 | std::memcpy(output.data(), ¶ms, output.size()); | 258 | std::memcpy(output.data(), ¶ms, output.size()); |
| 185 | return 0; | 259 | return NvResult::Success; |
| 186 | } | 260 | } |
| 187 | 261 | ||
| 188 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { | 262 | NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 189 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 263 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 190 | 264 | ||
| 191 | IoctlFlushL2 params{}; | 265 | IoctlFlushL2 params{}; |
| 192 | std::memcpy(¶ms, input.data(), input.size()); | 266 | std::memcpy(¶ms, input.data(), input.size()); |
| 193 | // TODO : To implement properly | 267 | // TODO : To implement properly |
| 194 | std::memcpy(output.data(), ¶ms, output.size()); | 268 | std::memcpy(output.data(), ¶ms, output.size()); |
| 195 | return 0; | 269 | return NvResult::Success; |
| 196 | } | 270 | } |
| 197 | 271 | ||
| 198 | u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { | 272 | NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { |
| 199 | LOG_DEBUG(Service_NVDRV, "called"); | 273 | LOG_DEBUG(Service_NVDRV, "called"); |
| 200 | 274 | ||
| 201 | IoctlGetGpuTime params{}; | 275 | IoctlGetGpuTime params{}; |
| 202 | std::memcpy(¶ms, input.data(), input.size()); | 276 | std::memcpy(¶ms, input.data(), input.size()); |
| 203 | params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); | 277 | params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); |
| 204 | std::memcpy(output.data(), ¶ms, output.size()); | 278 | std::memcpy(output.data(), ¶ms, output.size()); |
| 205 | return 0; | 279 | return NvResult::Success; |
| 206 | } | 280 | } |
| 207 | 281 | ||
| 208 | } // namespace Service::Nvidia::Devices | 282 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index ef60f72ce..137b88238 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -16,32 +16,13 @@ public: | |||
| 16 | explicit nvhost_ctrl_gpu(Core::System& system); | 16 | explicit nvhost_ctrl_gpu(Core::System& system); |
| 17 | ~nvhost_ctrl_gpu() override; | 17 | ~nvhost_ctrl_gpu() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 21 | IoctlVersion version) override; | 21 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 22 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 23 | std::vector<u8>& inline_output) override; | ||
| 22 | 24 | ||
| 23 | private: | 25 | private: |
| 24 | enum class IoctlCommand : u32_le { | ||
| 25 | IocGetCharacteristicsCommand = 0xC0B04705, | ||
| 26 | IocGetTPCMasksCommand = 0xC0184706, | ||
| 27 | IocGetActiveSlotMaskCommand = 0x80084714, | ||
| 28 | IocZcullGetCtxSizeCommand = 0x80044701, | ||
| 29 | IocZcullGetInfo = 0x80284702, | ||
| 30 | IocZbcSetTable = 0x402C4703, | ||
| 31 | IocZbcQueryTable = 0xC0344704, | ||
| 32 | IocFlushL2 = 0x40084707, | ||
| 33 | IocInvalICache = 0x4008470D, | ||
| 34 | IocSetMmudebugMode = 0x4008470E, | ||
| 35 | IocSetSmDebugMode = 0x4010470F, | ||
| 36 | IocWaitForPause = 0xC0084710, | ||
| 37 | IocGetTcpExceptionEnStatus = 0x80084711, | ||
| 38 | IocNumVsms = 0x80084712, | ||
| 39 | IocVsmsMapping = 0xC0044713, | ||
| 40 | IocGetErrorChannelUserData = 0xC008471B, | ||
| 41 | IocGetGpuTime = 0xC010471C, | ||
| 42 | IocGetCpuTimeCorrelationInfo = 0xC108471D, | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct IoctlGpuCharacteristics { | 26 | struct IoctlGpuCharacteristics { |
| 46 | u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) | 27 | u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) |
| 47 | u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) | 28 | u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) |
| @@ -159,17 +140,21 @@ private: | |||
| 159 | }; | 140 | }; |
| 160 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); | 141 | static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); |
| 161 | 142 | ||
| 162 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, | 143 | NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); |
| 163 | std::vector<u8>& output2, IoctlVersion version); | 144 | NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, |
| 164 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2, | 145 | std::vector<u8>& inline_output); |
| 165 | IoctlVersion version); | 146 | |
| 166 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); | 147 | NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); |
| 167 | u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); | 148 | NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, |
| 168 | u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); | 149 | std::vector<u8>& inline_output); |
| 169 | u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | 150 | |
| 170 | u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | 151 | NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); |
| 171 | u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | 152 | NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); |
| 172 | u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | 153 | NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); |
| 154 | NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 155 | NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 156 | NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 157 | NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 173 | }; | 158 | }; |
| 174 | 159 | ||
| 175 | } // namespace Service::Nvidia::Devices | 160 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b1d9d55b5..af8b3d9f1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -23,107 +23,132 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, | |||
| 23 | 23 | ||
| 24 | nvhost_gpu::~nvhost_gpu() = default; | 24 | nvhost_gpu::~nvhost_gpu() = default; |
| 25 | 25 | ||
| 26 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 26 | NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 27 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 27 | switch (command.group) { |
| 28 | IoctlVersion version) { | 28 | case 0x0: |
| 29 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 29 | switch (command.cmd) { |
| 30 | command.raw, input.size(), output.size()); | 30 | case 0x3: |
| 31 | 31 | return GetWaitbase(input, output); | |
| 32 | switch (static_cast<IoctlCommand>(command.raw)) { | 32 | default: |
| 33 | case IoctlCommand::IocSetNVMAPfdCommand: | 33 | break; |
| 34 | return SetNVMAPfd(input, output); | 34 | } |
| 35 | case IoctlCommand::IocSetClientDataCommand: | 35 | break; |
| 36 | return SetClientData(input, output); | 36 | case 'H': |
| 37 | case IoctlCommand::IocGetClientDataCommand: | 37 | switch (command.cmd) { |
| 38 | return GetClientData(input, output); | 38 | case 0x1: |
| 39 | case IoctlCommand::IocZCullBind: | 39 | return SetNVMAPfd(input, output); |
| 40 | return ZCullBind(input, output); | 40 | case 0x3: |
| 41 | case IoctlCommand::IocSetErrorNotifierCommand: | 41 | return ChannelSetTimeout(input, output); |
| 42 | return SetErrorNotifier(input, output); | 42 | case 0x8: |
| 43 | case IoctlCommand::IocChannelSetPriorityCommand: | 43 | return SubmitGPFIFOBase(input, output, false); |
| 44 | return SetChannelPriority(input, output); | 44 | case 0x9: |
| 45 | case IoctlCommand::IocAllocGPFIFOEx2Command: | 45 | return AllocateObjectContext(input, output); |
| 46 | return AllocGPFIFOEx2(input, output); | 46 | case 0xb: |
| 47 | case IoctlCommand::IocAllocObjCtxCommand: | 47 | return ZCullBind(input, output); |
| 48 | return AllocateObjectContext(input, output); | 48 | case 0xc: |
| 49 | case IoctlCommand::IocChannelGetWaitbaseCommand: | 49 | return SetErrorNotifier(input, output); |
| 50 | return GetWaitbase(input, output); | 50 | case 0xd: |
| 51 | case IoctlCommand::IocChannelSetTimeoutCommand: | 51 | return SetChannelPriority(input, output); |
| 52 | return ChannelSetTimeout(input, output); | 52 | case 0x1a: |
| 53 | case IoctlCommand::IocChannelSetTimeslice: | 53 | return AllocGPFIFOEx2(input, output); |
| 54 | return ChannelSetTimeslice(input, output); | 54 | case 0x1b: |
| 55 | default: | 55 | return SubmitGPFIFOBase(input, output, true); |
| 56 | case 0x1d: | ||
| 57 | return ChannelSetTimeslice(input, output); | ||
| 58 | default: | ||
| 59 | break; | ||
| 60 | } | ||
| 61 | break; | ||
| 62 | case 'G': | ||
| 63 | switch (command.cmd) { | ||
| 64 | case 0x14: | ||
| 65 | return SetClientData(input, output); | ||
| 66 | case 0x15: | ||
| 67 | return GetClientData(input, output); | ||
| 68 | default: | ||
| 69 | break; | ||
| 70 | } | ||
| 56 | break; | 71 | break; |
| 57 | } | 72 | } |
| 73 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 74 | return NvResult::NotImplemented; | ||
| 75 | }; | ||
| 58 | 76 | ||
| 59 | if (command.group == NVGPU_IOCTL_MAGIC) { | 77 | NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 60 | if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { | 78 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 61 | return SubmitGPFIFO(input, output); | 79 | switch (command.group) { |
| 62 | } | 80 | case 'H': |
| 63 | if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { | 81 | switch (command.cmd) { |
| 64 | return KickoffPB(input, output, input2, version); | 82 | case 0x1b: |
| 83 | return SubmitGPFIFOBase(input, inline_input, output); | ||
| 65 | } | 84 | } |
| 85 | break; | ||
| 66 | } | 86 | } |
| 87 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 88 | return NvResult::NotImplemented; | ||
| 89 | } | ||
| 67 | 90 | ||
| 68 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 91 | NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 69 | return 0; | 92 | std::vector<u8>& inline_output) { |
| 70 | }; | 93 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 94 | return NvResult::NotImplemented; | ||
| 95 | } | ||
| 71 | 96 | ||
| 72 | u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 97 | NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { |
| 73 | IoctlSetNvmapFD params{}; | 98 | IoctlSetNvmapFD params{}; |
| 74 | std::memcpy(¶ms, input.data(), input.size()); | 99 | std::memcpy(¶ms, input.data(), input.size()); |
| 75 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 100 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 76 | 101 | ||
| 77 | nvmap_fd = params.nvmap_fd; | 102 | nvmap_fd = params.nvmap_fd; |
| 78 | return 0; | 103 | return NvResult::Success; |
| 79 | } | 104 | } |
| 80 | 105 | ||
| 81 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 106 | NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 82 | LOG_DEBUG(Service_NVDRV, "called"); | 107 | LOG_DEBUG(Service_NVDRV, "called"); |
| 83 | 108 | ||
| 84 | IoctlClientData params{}; | 109 | IoctlClientData params{}; |
| 85 | std::memcpy(¶ms, input.data(), input.size()); | 110 | std::memcpy(¶ms, input.data(), input.size()); |
| 86 | user_data = params.data; | 111 | user_data = params.data; |
| 87 | return 0; | 112 | return NvResult::Success; |
| 88 | } | 113 | } |
| 89 | 114 | ||
| 90 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 115 | NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 91 | LOG_DEBUG(Service_NVDRV, "called"); | 116 | LOG_DEBUG(Service_NVDRV, "called"); |
| 92 | 117 | ||
| 93 | IoctlClientData params{}; | 118 | IoctlClientData params{}; |
| 94 | std::memcpy(¶ms, input.data(), input.size()); | 119 | std::memcpy(¶ms, input.data(), input.size()); |
| 95 | params.data = user_data; | 120 | params.data = user_data; |
| 96 | std::memcpy(output.data(), ¶ms, output.size()); | 121 | std::memcpy(output.data(), ¶ms, output.size()); |
| 97 | return 0; | 122 | return NvResult::Success; |
| 98 | } | 123 | } |
| 99 | 124 | ||
| 100 | u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { | 125 | NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { |
| 101 | std::memcpy(&zcull_params, input.data(), input.size()); | 126 | std::memcpy(&zcull_params, input.data(), input.size()); |
| 102 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, | 127 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, |
| 103 | zcull_params.mode); | 128 | zcull_params.mode); |
| 104 | 129 | ||
| 105 | std::memcpy(output.data(), &zcull_params, output.size()); | 130 | std::memcpy(output.data(), &zcull_params, output.size()); |
| 106 | return 0; | 131 | return NvResult::Success; |
| 107 | } | 132 | } |
| 108 | 133 | ||
| 109 | u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { | 134 | NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { |
| 110 | IoctlSetErrorNotifier params{}; | 135 | IoctlSetErrorNotifier params{}; |
| 111 | std::memcpy(¶ms, input.data(), input.size()); | 136 | std::memcpy(¶ms, input.data(), input.size()); |
| 112 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, | 137 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, |
| 113 | params.size, params.mem); | 138 | params.size, params.mem); |
| 114 | 139 | ||
| 115 | std::memcpy(output.data(), ¶ms, output.size()); | 140 | std::memcpy(output.data(), ¶ms, output.size()); |
| 116 | return 0; | 141 | return NvResult::Success; |
| 117 | } | 142 | } |
| 118 | 143 | ||
| 119 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { | 144 | NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { |
| 120 | std::memcpy(&channel_priority, input.data(), input.size()); | 145 | std::memcpy(&channel_priority, input.data(), input.size()); |
| 121 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); | 146 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); |
| 122 | 147 | ||
| 123 | return 0; | 148 | return NvResult::Success; |
| 124 | } | 149 | } |
| 125 | 150 | ||
| 126 | u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { | 151 | NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 127 | IoctlAllocGpfifoEx2 params{}; | 152 | IoctlAllocGpfifoEx2 params{}; |
| 128 | std::memcpy(¶ms, input.data(), input.size()); | 153 | std::memcpy(¶ms, input.data(), input.size()); |
| 129 | LOG_WARNING(Service_NVDRV, | 154 | LOG_WARNING(Service_NVDRV, |
| @@ -137,10 +162,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 137 | params.fence_out = channel_fence; | 162 | params.fence_out = channel_fence; |
| 138 | 163 | ||
| 139 | std::memcpy(output.data(), ¶ms, output.size()); | 164 | std::memcpy(output.data(), ¶ms, output.size()); |
| 140 | return 0; | 165 | return NvResult::Success; |
| 141 | } | 166 | } |
| 142 | 167 | ||
| 143 | u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { | 168 | NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { |
| 144 | IoctlAllocObjCtx params{}; | 169 | IoctlAllocObjCtx params{}; |
| 145 | std::memcpy(¶ms, input.data(), input.size()); | 170 | std::memcpy(¶ms, input.data(), input.size()); |
| 146 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, | 171 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, |
| @@ -148,7 +173,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 148 | 173 | ||
| 149 | params.obj_id = 0x0; | 174 | params.obj_id = 0x0; |
| 150 | std::memcpy(output.data(), ¶ms, output.size()); | 175 | std::memcpy(output.data(), ¶ms, output.size()); |
| 151 | return 0; | 176 | return NvResult::Success; |
| 152 | } | 177 | } |
| 153 | 178 | ||
| 154 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { | 179 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { |
| @@ -192,8 +217,8 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence | |||
| 192 | return result; | 217 | return result; |
| 193 | } | 218 | } |
| 194 | 219 | ||
| 195 | u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | 220 | NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, |
| 196 | Tegra::CommandList&& entries) { | 221 | Tegra::CommandList&& entries) { |
| 197 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | 222 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, |
| 198 | params.num_entries, params.flags.raw); | 223 | params.num_entries, params.flags.raw); |
| 199 | 224 | ||
| @@ -227,69 +252,70 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out | |||
| 227 | } | 252 | } |
| 228 | 253 | ||
| 229 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); | 254 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); |
| 230 | return 0; | 255 | return NvResult::Success; |
| 231 | } | 256 | } |
| 232 | 257 | ||
| 233 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 258 | NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, |
| 259 | bool kickoff) { | ||
| 234 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 260 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 235 | UNIMPLEMENTED(); | 261 | UNIMPLEMENTED(); |
| 262 | return NvResult::InvalidSize; | ||
| 236 | } | 263 | } |
| 237 | IoctlSubmitGpfifo params{}; | 264 | IoctlSubmitGpfifo params{}; |
| 238 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 265 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 239 | |||
| 240 | Tegra::CommandList entries(params.num_entries); | 266 | Tegra::CommandList entries(params.num_entries); |
| 241 | std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], | 267 | |
| 242 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 268 | if (kickoff) { |
| 269 | system.Memory().ReadBlock(params.address, entries.command_lists.data(), | ||
| 270 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 271 | } else { | ||
| 272 | std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], | ||
| 273 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 274 | } | ||
| 243 | 275 | ||
| 244 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | 276 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 245 | } | 277 | } |
| 246 | 278 | ||
| 247 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 279 | NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, |
| 248 | const std::vector<u8>& input2, IoctlVersion version) { | 280 | const std::vector<u8>& input_inline, |
| 281 | std::vector<u8>& output) { | ||
| 249 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 282 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 250 | UNIMPLEMENTED(); | 283 | UNIMPLEMENTED(); |
| 284 | return NvResult::InvalidSize; | ||
| 251 | } | 285 | } |
| 252 | IoctlSubmitGpfifo params{}; | 286 | IoctlSubmitGpfifo params{}; |
| 253 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 287 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 254 | |||
| 255 | Tegra::CommandList entries(params.num_entries); | 288 | Tegra::CommandList entries(params.num_entries); |
| 256 | if (version == IoctlVersion::Version2) { | 289 | std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size()); |
| 257 | std::memcpy(entries.command_lists.data(), input2.data(), | ||
| 258 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 259 | } else { | ||
| 260 | system.Memory().ReadBlock(params.address, entries.command_lists.data(), | ||
| 261 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 262 | } | ||
| 263 | |||
| 264 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | 290 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 265 | } | 291 | } |
| 266 | 292 | ||
| 267 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 293 | NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
| 268 | IoctlGetWaitbase params{}; | 294 | IoctlGetWaitbase params{}; |
| 269 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 295 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 270 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); | 296 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); |
| 271 | 297 | ||
| 272 | params.value = 0; // Seems to be hard coded at 0 | 298 | params.value = 0; // Seems to be hard coded at 0 |
| 273 | std::memcpy(output.data(), ¶ms, output.size()); | 299 | std::memcpy(output.data(), ¶ms, output.size()); |
| 274 | return 0; | 300 | return NvResult::Success; |
| 275 | } | 301 | } |
| 276 | 302 | ||
| 277 | u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { | 303 | NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { |
| 278 | IoctlChannelSetTimeout params{}; | 304 | IoctlChannelSetTimeout params{}; |
| 279 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); | 305 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); |
| 280 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); | 306 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); |
| 281 | 307 | ||
| 282 | return 0; | 308 | return NvResult::Success; |
| 283 | } | 309 | } |
| 284 | 310 | ||
| 285 | u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { | 311 | NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { |
| 286 | IoctlSetTimeslice params{}; | 312 | IoctlSetTimeslice params{}; |
| 287 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); | 313 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); |
| 288 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); | 314 | LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); |
| 289 | 315 | ||
| 290 | channel_timeslice = params.timeslice; | 316 | channel_timeslice = params.timeslice; |
| 291 | 317 | ||
| 292 | return 0; | 318 | return NvResult::Success; |
| 293 | } | 319 | } |
| 294 | 320 | ||
| 295 | } // namespace Service::Nvidia::Devices | 321 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index a252fc06d..e0298b4fe 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -20,43 +20,19 @@ class SyncpointManager; | |||
| 20 | namespace Service::Nvidia::Devices { | 20 | namespace Service::Nvidia::Devices { |
| 21 | 21 | ||
| 22 | class nvmap; | 22 | class nvmap; |
| 23 | constexpr u32 NVGPU_IOCTL_MAGIC('H'); | ||
| 24 | constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8); | ||
| 25 | constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); | ||
| 26 | |||
| 27 | class nvhost_gpu final : public nvdevice { | 23 | class nvhost_gpu final : public nvdevice { |
| 28 | public: | 24 | public: |
| 29 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, | 25 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 30 | SyncpointManager& syncpoint_manager); | 26 | SyncpointManager& syncpoint_manager); |
| 31 | ~nvhost_gpu() override; | 27 | ~nvhost_gpu() override; |
| 32 | 28 | ||
| 33 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 29 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 34 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 30 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 35 | IoctlVersion version) override; | 31 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 32 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 33 | std::vector<u8>& inline_output) override; | ||
| 36 | 34 | ||
| 37 | private: | 35 | private: |
| 38 | enum class IoctlCommand : u32_le { | ||
| 39 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 40 | IocAllocGPFIFOCommand = 0x40084805, | ||
| 41 | IocSetClientDataCommand = 0x40084714, | ||
| 42 | IocGetClientDataCommand = 0x80084715, | ||
| 43 | IocZCullBind = 0xc010480b, | ||
| 44 | IocSetErrorNotifierCommand = 0xC018480C, | ||
| 45 | IocChannelSetPriorityCommand = 0x4004480D, | ||
| 46 | IocEnableCommand = 0x0000480E, | ||
| 47 | IocDisableCommand = 0x0000480F, | ||
| 48 | IocPreemptCommand = 0x00004810, | ||
| 49 | IocForceResetCommand = 0x00004811, | ||
| 50 | IocEventIdControlCommand = 0x40084812, | ||
| 51 | IocGetErrorNotificationCommand = 0xC0104817, | ||
| 52 | IocAllocGPFIFOExCommand = 0x40204818, | ||
| 53 | IocAllocGPFIFOEx2Command = 0xC020481A, | ||
| 54 | IocAllocObjCtxCommand = 0xC0104809, | ||
| 55 | IocChannelGetWaitbaseCommand = 0xC0080003, | ||
| 56 | IocChannelSetTimeoutCommand = 0x40044803, | ||
| 57 | IocChannelSetTimeslice = 0xC004481D, | ||
| 58 | }; | ||
| 59 | |||
| 60 | enum class CtxObjects : u32_le { | 36 | enum class CtxObjects : u32_le { |
| 61 | Ctx2D = 0x902D, | 37 | Ctx2D = 0x902D, |
| 62 | Ctx3D = 0xB197, | 38 | Ctx3D = 0xB197, |
| @@ -67,63 +43,63 @@ private: | |||
| 67 | }; | 43 | }; |
| 68 | 44 | ||
| 69 | struct IoctlSetNvmapFD { | 45 | struct IoctlSetNvmapFD { |
| 70 | u32_le nvmap_fd; | 46 | s32_le nvmap_fd{}; |
| 71 | }; | 47 | }; |
| 72 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 48 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 73 | 49 | ||
| 74 | struct IoctlChannelSetTimeout { | 50 | struct IoctlChannelSetTimeout { |
| 75 | u32_le timeout; | 51 | u32_le timeout{}; |
| 76 | }; | 52 | }; |
| 77 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); | 53 | static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); |
| 78 | 54 | ||
| 79 | struct IoctlAllocGPFIFO { | 55 | struct IoctlAllocGPFIFO { |
| 80 | u32_le num_entries; | 56 | u32_le num_entries{}; |
| 81 | u32_le flags; | 57 | u32_le flags{}; |
| 82 | }; | 58 | }; |
| 83 | static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); | 59 | static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); |
| 84 | 60 | ||
| 85 | struct IoctlClientData { | 61 | struct IoctlClientData { |
| 86 | u64_le data; | 62 | u64_le data{}; |
| 87 | }; | 63 | }; |
| 88 | static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); | 64 | static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); |
| 89 | 65 | ||
| 90 | struct IoctlZCullBind { | 66 | struct IoctlZCullBind { |
| 91 | u64_le gpu_va; | 67 | u64_le gpu_va{}; |
| 92 | u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf | 68 | u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf |
| 93 | INSERT_PADDING_WORDS(1); | 69 | INSERT_PADDING_WORDS(1); |
| 94 | }; | 70 | }; |
| 95 | static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); | 71 | static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); |
| 96 | 72 | ||
| 97 | struct IoctlSetErrorNotifier { | 73 | struct IoctlSetErrorNotifier { |
| 98 | u64_le offset; | 74 | u64_le offset{}; |
| 99 | u64_le size; | 75 | u64_le size{}; |
| 100 | u32_le mem; // nvmap object handle | 76 | u32_le mem{}; // nvmap object handle |
| 101 | INSERT_PADDING_WORDS(1); | 77 | INSERT_PADDING_WORDS(1); |
| 102 | }; | 78 | }; |
| 103 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); | 79 | static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); |
| 104 | 80 | ||
| 105 | struct IoctlChannelSetPriority { | 81 | struct IoctlChannelSetPriority { |
| 106 | u32_le priority; | 82 | u32_le priority{}; |
| 107 | }; | 83 | }; |
| 108 | static_assert(sizeof(IoctlChannelSetPriority) == 4, | 84 | static_assert(sizeof(IoctlChannelSetPriority) == 4, |
| 109 | "IoctlChannelSetPriority is incorrect size"); | 85 | "IoctlChannelSetPriority is incorrect size"); |
| 110 | 86 | ||
| 111 | struct IoctlSetTimeslice { | 87 | struct IoctlSetTimeslice { |
| 112 | u32_le timeslice; | 88 | u32_le timeslice{}; |
| 113 | }; | 89 | }; |
| 114 | static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); | 90 | static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); |
| 115 | 91 | ||
| 116 | struct IoctlEventIdControl { | 92 | struct IoctlEventIdControl { |
| 117 | u32_le cmd; // 0=disable, 1=enable, 2=clear | 93 | u32_le cmd{}; // 0=disable, 1=enable, 2=clear |
| 118 | u32_le id; | 94 | u32_le id{}; |
| 119 | }; | 95 | }; |
| 120 | static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); | 96 | static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); |
| 121 | 97 | ||
| 122 | struct IoctlGetErrorNotification { | 98 | struct IoctlGetErrorNotification { |
| 123 | u64_le timestamp; | 99 | u64_le timestamp{}; |
| 124 | u32_le info32; | 100 | u32_le info32{}; |
| 125 | u16_le info16; | 101 | u16_le info16{}; |
| 126 | u16_le status; // always 0xFFFF | 102 | u16_le status{}; // always 0xFFFF |
| 127 | }; | 103 | }; |
| 128 | static_assert(sizeof(IoctlGetErrorNotification) == 16, | 104 | static_assert(sizeof(IoctlGetErrorNotification) == 16, |
| 129 | "IoctlGetErrorNotification is incorrect size"); | 105 | "IoctlGetErrorNotification is incorrect size"); |
| @@ -131,39 +107,39 @@ private: | |||
| 131 | static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); | 107 | static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); |
| 132 | 108 | ||
| 133 | struct IoctlAllocGpfifoEx { | 109 | struct IoctlAllocGpfifoEx { |
| 134 | u32_le num_entries; | 110 | u32_le num_entries{}; |
| 135 | u32_le flags; | 111 | u32_le flags{}; |
| 136 | u32_le unk0; | 112 | u32_le unk0{}; |
| 137 | u32_le unk1; | 113 | u32_le unk1{}; |
| 138 | u32_le unk2; | 114 | u32_le unk2{}; |
| 139 | u32_le unk3; | 115 | u32_le unk3{}; |
| 140 | u32_le unk4; | 116 | u32_le unk4{}; |
| 141 | u32_le unk5; | 117 | u32_le unk5{}; |
| 142 | }; | 118 | }; |
| 143 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); | 119 | static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); |
| 144 | 120 | ||
| 145 | struct IoctlAllocGpfifoEx2 { | 121 | struct IoctlAllocGpfifoEx2 { |
| 146 | u32_le num_entries; // in | 122 | u32_le num_entries{}; // in |
| 147 | u32_le flags; // in | 123 | u32_le flags{}; // in |
| 148 | u32_le unk0; // in (1 works) | 124 | u32_le unk0{}; // in (1 works) |
| 149 | Fence fence_out; // out | 125 | Fence fence_out{}; // out |
| 150 | u32_le unk1; // in | 126 | u32_le unk1{}; // in |
| 151 | u32_le unk2; // in | 127 | u32_le unk2{}; // in |
| 152 | u32_le unk3; // in | 128 | u32_le unk3{}; // in |
| 153 | }; | 129 | }; |
| 154 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); | 130 | static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); |
| 155 | 131 | ||
| 156 | struct IoctlAllocObjCtx { | 132 | struct IoctlAllocObjCtx { |
| 157 | u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, | 133 | u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, |
| 158 | // 0xB06F=channel_gpfifo | 134 | // 0xB06F=channel_gpfifo |
| 159 | u32_le flags; | 135 | u32_le flags{}; |
| 160 | u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported | 136 | u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported |
| 161 | }; | 137 | }; |
| 162 | static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); | 138 | static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); |
| 163 | 139 | ||
| 164 | struct IoctlSubmitGpfifo { | 140 | struct IoctlSubmitGpfifo { |
| 165 | u64_le address; // pointer to gpfifo entry structs | 141 | u64_le address{}; // pointer to gpfifo entry structs |
| 166 | u32_le num_entries; // number of fence objects being submitted | 142 | u32_le num_entries{}; // number of fence objects being submitted |
| 167 | union { | 143 | union { |
| 168 | u32_le raw; | 144 | u32_le raw; |
| 169 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list | 145 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list |
| @@ -172,7 +148,7 @@ private: | |||
| 172 | BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt | 148 | BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt |
| 173 | BitField<8, 1, u32_le> increment; // increment the returned fence | 149 | BitField<8, 1, u32_le> increment; // increment the returned fence |
| 174 | } flags; | 150 | } flags; |
| 175 | Fence fence_out; // returned new fence object for others to wait on | 151 | Fence fence_out{}; // returned new fence object for others to wait on |
| 176 | 152 | ||
| 177 | u32 AddIncrementValue() const { | 153 | u32 AddIncrementValue() const { |
| 178 | return flags.add_increment.Value() << 1; | 154 | return flags.add_increment.Value() << 1; |
| @@ -182,33 +158,34 @@ private: | |||
| 182 | "IoctlSubmitGpfifo is incorrect size"); | 158 | "IoctlSubmitGpfifo is incorrect size"); |
| 183 | 159 | ||
| 184 | struct IoctlGetWaitbase { | 160 | struct IoctlGetWaitbase { |
| 185 | u32 unknown; // seems to be ignored? Nintendo added this | 161 | u32 unknown{}; // seems to be ignored? Nintendo added this |
| 186 | u32 value; | 162 | u32 value{}; |
| 187 | }; | 163 | }; |
| 188 | static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); | 164 | static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); |
| 189 | 165 | ||
| 190 | u32_le nvmap_fd{}; | 166 | s32_le nvmap_fd{}; |
| 191 | u64_le user_data{}; | 167 | u64_le user_data{}; |
| 192 | IoctlZCullBind zcull_params{}; | 168 | IoctlZCullBind zcull_params{}; |
| 193 | u32_le channel_priority{}; | 169 | u32_le channel_priority{}; |
| 194 | u32_le channel_timeslice{}; | 170 | u32_le channel_timeslice{}; |
| 195 | 171 | ||
| 196 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | 172 | NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); |
| 197 | u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); | 173 | NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output); |
| 198 | u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output); | 174 | NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output); |
| 199 | u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); | 175 | NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); |
| 200 | u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); | 176 | NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); |
| 201 | u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); | 177 | NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); |
| 202 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); | 178 | NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); |
| 203 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); | 179 | NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); |
| 204 | u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | 180 | NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, |
| 205 | Tegra::CommandList&& entries); | 181 | Tegra::CommandList&& entries); |
| 206 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); | 182 | NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output, |
| 207 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 183 | bool kickoff = false); |
| 208 | const std::vector<u8>& input2, IoctlVersion version); | 184 | NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline, |
| 209 | u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | 185 | std::vector<u8>& output); |
| 210 | u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 186 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); |
| 211 | u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | 187 | NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); |
| 188 | NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 212 | 189 | ||
| 213 | std::shared_ptr<nvmap> nvmap_dev; | 190 | std::shared_ptr<nvmap> nvmap_dev; |
| 214 | SyncpointManager& syncpoint_manager; | 191 | SyncpointManager& syncpoint_manager; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index b6df48360..d8735491c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -15,46 +15,58 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de | |||
| 15 | : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} | 15 | : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} |
| 16 | nvhost_nvdec::~nvhost_nvdec() = default; | 16 | nvhost_nvdec::~nvhost_nvdec() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 18 | NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 19 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 19 | std::vector<u8>& output) { |
| 20 | IoctlVersion version) { | 20 | switch (command.group) { |
| 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | case 0x0: |
| 22 | command.raw, input.size(), output.size()); | 22 | switch (command.cmd) { |
| 23 | 23 | case 0x1: | |
| 24 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | return Submit(input, output); |
| 25 | case IoctlCommand::IocSetNVMAPfdCommand: | 25 | case 0x2: |
| 26 | return SetNVMAPfd(input); | 26 | return GetSyncpoint(input, output); |
| 27 | case IoctlCommand::IocSubmit: | 27 | case 0x3: |
| 28 | return Submit(input, output); | 28 | return GetWaitbase(input, output); |
| 29 | case IoctlCommand::IocGetSyncpoint: | 29 | case 0x7: |
| 30 | return GetSyncpoint(input, output); | 30 | return SetSubmitTimeout(input, output); |
| 31 | case IoctlCommand::IocGetWaitbase: | 31 | case 0x9: |
| 32 | return GetWaitbase(input, output); | 32 | return MapBuffer(input, output); |
| 33 | case IoctlCommand::IocMapBuffer: | 33 | case 0xa: { |
| 34 | case IoctlCommand::IocMapBuffer2: | 34 | if (command.length == 0x1c) { |
| 35 | case IoctlCommand::IocMapBuffer3: | 35 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); |
| 36 | case IoctlCommand::IocMapBufferEx: | 36 | Tegra::ChCommandHeaderList cmdlist(1); |
| 37 | return MapBuffer(input, output); | 37 | cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; |
| 38 | case IoctlCommand::IocUnmapBufferEx: { | 38 | system.GPU().PushCommandBuffer(cmdlist); |
| 39 | // This command is sent when the video stream has ended, flush all video contexts | 39 | } |
| 40 | // This is usually sent in the folowing order: vic, nvdec, vic. | 40 | return UnmapBuffer(input, output); |
| 41 | // Inform the GPU to clear any remaining nvdec buffers when this is detected. | 41 | } |
| 42 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); | 42 | default: |
| 43 | Tegra::ChCommandHeaderList cmdlist(1); | 43 | break; |
| 44 | cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; | 44 | } |
| 45 | system.GPU().PushCommandBuffer(cmdlist); | 45 | break; |
| 46 | [[fallthrough]]; // fallthrough to unmap buffers | 46 | case 'H': |
| 47 | }; | 47 | switch (command.cmd) { |
| 48 | case IoctlCommand::IocUnmapBuffer: | 48 | case 0x1: |
| 49 | case IoctlCommand::IocUnmapBuffer2: | 49 | return SetNVMAPfd(input); |
| 50 | case IoctlCommand::IocUnmapBuffer3: | 50 | default: |
| 51 | return UnmapBuffer(input, output); | 51 | break; |
| 52 | case IoctlCommand::IocSetSubmitTimeout: | 52 | } |
| 53 | return SetSubmitTimeout(input, output); | 53 | break; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); | 56 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 57 | return 0; | 57 | return NvResult::NotImplemented; |
| 58 | } | ||
| 59 | |||
| 60 | NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 61 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 62 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 63 | return NvResult::NotImplemented; | ||
| 64 | } | ||
| 65 | |||
| 66 | NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 67 | std::vector<u8>& inline_output) { | ||
| 68 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 69 | return NvResult::NotImplemented; | ||
| 58 | } | 70 | } |
| 59 | 71 | ||
| 60 | } // namespace Service::Nvidia::Devices | 72 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 102777ddd..79b8b6de1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -14,26 +14,11 @@ public: | |||
| 14 | explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 14 | explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 15 | ~nvhost_nvdec() override; | 15 | ~nvhost_nvdec() override; |
| 16 | 16 | ||
| 17 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 17 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 18 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 18 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 19 | IoctlVersion version) override; | 19 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 20 | 20 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | |
| 21 | private: | 21 | std::vector<u8>& inline_output) override; |
| 22 | enum class IoctlCommand : u32_le { | ||
| 23 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 24 | IocSubmit = 0xC0400001, | ||
| 25 | IocGetSyncpoint = 0xC0080002, | ||
| 26 | IocGetWaitbase = 0xC0080003, | ||
| 27 | IocMapBuffer = 0xC01C0009, | ||
| 28 | IocMapBuffer2 = 0xC16C0009, | ||
| 29 | IocMapBuffer3 = 0xC15C0009, | ||
| 30 | IocMapBufferEx = 0xC0A40009, | ||
| 31 | IocUnmapBuffer = 0xC0A4000A, | ||
| 32 | IocUnmapBuffer2 = 0xC16C000A, | ||
| 33 | IocUnmapBufferEx = 0xC01C000A, | ||
| 34 | IocUnmapBuffer3 = 0xC15C000A, | ||
| 35 | IocSetSubmitTimeout = 0x40040007, | ||
| 36 | }; | ||
| 37 | }; | 22 | }; |
| 38 | 23 | ||
| 39 | } // namespace Service::Nvidia::Devices | 24 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 30f03f845..b49cecb42 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | |||
| @@ -36,26 +36,20 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s | |||
| 36 | } | 36 | } |
| 37 | } // Anonymous namespace | 37 | } // Anonymous namespace |
| 38 | 38 | ||
| 39 | namespace NvErrCodes { | ||
| 40 | constexpr u32 Success{}; | ||
| 41 | [[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)}; | ||
| 42 | constexpr u32 InvalidInput{static_cast<u32>(-22)}; | ||
| 43 | } // namespace NvErrCodes | ||
| 44 | |||
| 45 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 39 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 46 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 40 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} |
| 47 | nvhost_nvdec_common::~nvhost_nvdec_common() = default; | 41 | nvhost_nvdec_common::~nvhost_nvdec_common() = default; |
| 48 | 42 | ||
| 49 | u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { | 43 | NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { |
| 50 | IoctlSetNvmapFD params{}; | 44 | IoctlSetNvmapFD params{}; |
| 51 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD)); | 45 | std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD)); |
| 52 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 46 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 53 | 47 | ||
| 54 | nvmap_fd = params.nvmap_fd; | 48 | nvmap_fd = params.nvmap_fd; |
| 55 | return 0; | 49 | return NvResult::Success; |
| 56 | } | 50 | } |
| 57 | 51 | ||
| 58 | u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | 52 | NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { |
| 59 | IoctlSubmit params{}; | 53 | IoctlSubmit params{}; |
| 60 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); | 54 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); |
| 61 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); | 55 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); |
| @@ -83,12 +77,12 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o | |||
| 83 | 77 | ||
| 84 | for (const auto& cmd_buffer : command_buffers) { | 78 | for (const auto& cmd_buffer : command_buffers) { |
| 85 | auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); | 79 | auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); |
| 86 | ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;); | 80 | ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); |
| 87 | const auto map = FindBufferMap(object->dma_map_addr); | 81 | const auto map = FindBufferMap(object->dma_map_addr); |
| 88 | if (!map) { | 82 | if (!map) { |
| 89 | LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}", | 83 | LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}", |
| 90 | object->addr, object->dma_map_addr); | 84 | object->addr, object->dma_map_addr); |
| 91 | return 0; | 85 | return NvResult::Success; |
| 92 | } | 86 | } |
| 93 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); | 87 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); |
| 94 | gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), | 88 | gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), |
| @@ -105,10 +99,10 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o | |||
| 105 | offset = WriteVectors(output, syncpt_increments, offset); | 99 | offset = WriteVectors(output, syncpt_increments, offset); |
| 106 | offset = WriteVectors(output, wait_checks, offset); | 100 | offset = WriteVectors(output, wait_checks, offset); |
| 107 | 101 | ||
| 108 | return NvErrCodes::Success; | 102 | return NvResult::Success; |
| 109 | } | 103 | } |
| 110 | 104 | ||
| 111 | u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { | 105 | NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { |
| 112 | IoctlGetSyncpoint params{}; | 106 | IoctlGetSyncpoint params{}; |
| 113 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); | 107 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); |
| 114 | LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); | 108 | LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); |
| @@ -118,18 +112,18 @@ u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector< | |||
| 118 | params.value = 0; | 112 | params.value = 0; |
| 119 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); | 113 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); |
| 120 | 114 | ||
| 121 | return NvErrCodes::Success; | 115 | return NvResult::Success; |
| 122 | } | 116 | } |
| 123 | 117 | ||
| 124 | u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 118 | NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
| 125 | IoctlGetWaitbase params{}; | 119 | IoctlGetWaitbase params{}; |
| 126 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 120 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 127 | params.value = 0; // Seems to be hard coded at 0 | 121 | params.value = 0; // Seems to be hard coded at 0 |
| 128 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); | 122 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); |
| 129 | return 0; | 123 | return NvResult::Success; |
| 130 | } | 124 | } |
| 131 | 125 | ||
| 132 | u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | 126 | NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { |
| 133 | IoctlMapBuffer params{}; | 127 | IoctlMapBuffer params{}; |
| 134 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | 128 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); |
| 135 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | 129 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); |
| @@ -143,7 +137,7 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8> | |||
| 143 | if (!object) { | 137 | if (!object) { |
| 144 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); | 138 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); |
| 145 | std::memcpy(output.data(), ¶ms, output.size()); | 139 | std::memcpy(output.data(), ¶ms, output.size()); |
| 146 | return NvErrCodes::InvalidInput; | 140 | return NvResult::InvalidState; |
| 147 | } | 141 | } |
| 148 | if (object->dma_map_addr == 0) { | 142 | if (object->dma_map_addr == 0) { |
| 149 | // NVDEC and VIC memory is in the 32-bit address space | 143 | // NVDEC and VIC memory is in the 32-bit address space |
| @@ -165,10 +159,10 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8> | |||
| 165 | std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), | 159 | std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), |
| 166 | cmd_buffer_handles.size() * sizeof(MapBufferEntry)); | 160 | cmd_buffer_handles.size() * sizeof(MapBufferEntry)); |
| 167 | 161 | ||
| 168 | return NvErrCodes::Success; | 162 | return NvResult::Success; |
| 169 | } | 163 | } |
| 170 | 164 | ||
| 171 | u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | 165 | NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { |
| 172 | IoctlMapBuffer params{}; | 166 | IoctlMapBuffer params{}; |
| 173 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); | 167 | std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); |
| 174 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); | 168 | std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); |
| @@ -181,7 +175,7 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u | |||
| 181 | if (!object) { | 175 | if (!object) { |
| 182 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); | 176 | LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); |
| 183 | std::memcpy(output.data(), ¶ms, output.size()); | 177 | std::memcpy(output.data(), ¶ms, output.size()); |
| 184 | return NvErrCodes::InvalidInput; | 178 | return NvResult::InvalidState; |
| 185 | } | 179 | } |
| 186 | if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { | 180 | if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { |
| 187 | gpu.MemoryManager().Unmap(object->dma_map_addr, *size); | 181 | gpu.MemoryManager().Unmap(object->dma_map_addr, *size); |
| @@ -193,13 +187,14 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u | |||
| 193 | object->dma_map_addr = 0; | 187 | object->dma_map_addr = 0; |
| 194 | } | 188 | } |
| 195 | std::memset(output.data(), 0, output.size()); | 189 | std::memset(output.data(), 0, output.size()); |
| 196 | return NvErrCodes::Success; | 190 | return NvResult::Success; |
| 197 | } | 191 | } |
| 198 | 192 | ||
| 199 | u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) { | 193 | NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, |
| 194 | std::vector<u8>& output) { | ||
| 200 | std::memcpy(&submit_timeout, input.data(), input.size()); | 195 | std::memcpy(&submit_timeout, input.data(), input.size()); |
| 201 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 196 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 202 | return NvErrCodes::Success; | 197 | return NvResult::Success; |
| 203 | } | 198 | } |
| 204 | 199 | ||
| 205 | std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( | 200 | std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index c249c5349..86ba3a4d1 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | |||
| @@ -18,9 +18,37 @@ public: | |||
| 18 | explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 18 | explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 19 | ~nvhost_nvdec_common() override; | 19 | ~nvhost_nvdec_common() override; |
| 20 | 20 | ||
| 21 | virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 21 | /** |
| 22 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 22 | * Handles an ioctl1 request. |
| 23 | IoctlVersion version) = 0; | 23 | * @param command The ioctl command id. |
| 24 | * @param input A buffer containing the input data for the ioctl. | ||
| 25 | * @param output A buffer where the output data will be written to. | ||
| 26 | * @returns The result code of the ioctl. | ||
| 27 | */ | ||
| 28 | virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, | ||
| 29 | std::vector<u8>& output) = 0; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Handles an ioctl2 request. | ||
| 33 | * @param command The ioctl command id. | ||
| 34 | * @param input A buffer containing the input data for the ioctl. | ||
| 35 | * @param inline_input A buffer containing the input data for the ioctl which has been inlined. | ||
| 36 | * @param output A buffer where the output data will be written to. | ||
| 37 | * @returns The result code of the ioctl. | ||
| 38 | */ | ||
| 39 | virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 40 | const std::vector<u8>& inline_input, std::vector<u8>& output) = 0; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Handles an ioctl3 request. | ||
| 44 | * @param command The ioctl command id. | ||
| 45 | * @param input A buffer containing the input data for the ioctl. | ||
| 46 | * @param output A buffer where the output data will be written to. | ||
| 47 | * @param inline_output A buffer where the inlined output data will be written to. | ||
| 48 | * @returns The result code of the ioctl. | ||
| 49 | */ | ||
| 50 | virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 51 | std::vector<u8>& inline_output) = 0; | ||
| 24 | 52 | ||
| 25 | protected: | 53 | protected: |
| 26 | class BufferMap final { | 54 | class BufferMap final { |
| @@ -63,102 +91,102 @@ protected: | |||
| 63 | }; | 91 | }; |
| 64 | 92 | ||
| 65 | struct IoctlSetNvmapFD { | 93 | struct IoctlSetNvmapFD { |
| 66 | u32_le nvmap_fd; | 94 | s32_le nvmap_fd{}; |
| 67 | }; | 95 | }; |
| 68 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 96 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 69 | 97 | ||
| 70 | struct IoctlSubmitCommandBuffer { | 98 | struct IoctlSubmitCommandBuffer { |
| 71 | u32_le id; | 99 | u32_le id{}; |
| 72 | u32_le offset; | 100 | u32_le offset{}; |
| 73 | u32_le count; | 101 | u32_le count{}; |
| 74 | }; | 102 | }; |
| 75 | static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC, | 103 | static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC, |
| 76 | "IoctlSubmitCommandBuffer is incorrect size"); | 104 | "IoctlSubmitCommandBuffer is incorrect size"); |
| 77 | struct IoctlSubmit { | 105 | struct IoctlSubmit { |
| 78 | u32_le cmd_buffer_count; | 106 | u32_le cmd_buffer_count{}; |
| 79 | u32_le relocation_count; | 107 | u32_le relocation_count{}; |
| 80 | u32_le syncpoint_count; | 108 | u32_le syncpoint_count{}; |
| 81 | u32_le fence_count; | 109 | u32_le fence_count{}; |
| 82 | }; | 110 | }; |
| 83 | static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size"); | 111 | static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size"); |
| 84 | 112 | ||
| 85 | struct CommandBuffer { | 113 | struct CommandBuffer { |
| 86 | s32 memory_id; | 114 | s32 memory_id{}; |
| 87 | u32 offset; | 115 | u32 offset{}; |
| 88 | s32 word_count; | 116 | s32 word_count{}; |
| 89 | }; | 117 | }; |
| 90 | static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size"); | 118 | static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size"); |
| 91 | 119 | ||
| 92 | struct Reloc { | 120 | struct Reloc { |
| 93 | s32 cmdbuffer_memory; | 121 | s32 cmdbuffer_memory{}; |
| 94 | s32 cmdbuffer_offset; | 122 | s32 cmdbuffer_offset{}; |
| 95 | s32 target; | 123 | s32 target{}; |
| 96 | s32 target_offset; | 124 | s32 target_offset{}; |
| 97 | }; | 125 | }; |
| 98 | static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size"); | 126 | static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size"); |
| 99 | 127 | ||
| 100 | struct SyncptIncr { | 128 | struct SyncptIncr { |
| 101 | u32 id; | 129 | u32 id{}; |
| 102 | u32 increments; | 130 | u32 increments{}; |
| 103 | }; | 131 | }; |
| 104 | static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size"); | 132 | static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size"); |
| 105 | 133 | ||
| 106 | struct Fence { | 134 | struct Fence { |
| 107 | u32 id; | 135 | u32 id{}; |
| 108 | u32 value; | 136 | u32 value{}; |
| 109 | }; | 137 | }; |
| 110 | static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size"); | 138 | static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size"); |
| 111 | 139 | ||
| 112 | struct IoctlGetSyncpoint { | 140 | struct IoctlGetSyncpoint { |
| 113 | // Input | 141 | // Input |
| 114 | u32_le param; | 142 | u32_le param{}; |
| 115 | // Output | 143 | // Output |
| 116 | u32_le value; | 144 | u32_le value{}; |
| 117 | }; | 145 | }; |
| 118 | static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size"); | 146 | static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size"); |
| 119 | 147 | ||
| 120 | struct IoctlGetWaitbase { | 148 | struct IoctlGetWaitbase { |
| 121 | u32_le unknown; // seems to be ignored? Nintendo added this | 149 | u32_le unknown{}; // seems to be ignored? Nintendo added this |
| 122 | u32_le value; | 150 | u32_le value{}; |
| 123 | }; | 151 | }; |
| 124 | static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size"); | 152 | static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size"); |
| 125 | 153 | ||
| 126 | struct IoctlMapBuffer { | 154 | struct IoctlMapBuffer { |
| 127 | u32_le num_entries; | 155 | u32_le num_entries{}; |
| 128 | u32_le data_address; // Ignored by the driver. | 156 | u32_le data_address{}; // Ignored by the driver. |
| 129 | u32_le attach_host_ch_das; | 157 | u32_le attach_host_ch_das{}; |
| 130 | }; | 158 | }; |
| 131 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); | 159 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); |
| 132 | 160 | ||
| 133 | struct IocGetIdParams { | 161 | struct IocGetIdParams { |
| 134 | // Input | 162 | // Input |
| 135 | u32_le param; | 163 | u32_le param{}; |
| 136 | // Output | 164 | // Output |
| 137 | u32_le value; | 165 | u32_le value{}; |
| 138 | }; | 166 | }; |
| 139 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); | 167 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); |
| 140 | 168 | ||
| 141 | // Used for mapping and unmapping command buffers | 169 | // Used for mapping and unmapping command buffers |
| 142 | struct MapBufferEntry { | 170 | struct MapBufferEntry { |
| 143 | u32_le map_handle; | 171 | u32_le map_handle{}; |
| 144 | u32_le map_address; | 172 | u32_le map_address{}; |
| 145 | }; | 173 | }; |
| 146 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); | 174 | static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); |
| 147 | 175 | ||
| 148 | /// Ioctl command implementations | 176 | /// Ioctl command implementations |
| 149 | u32 SetNVMAPfd(const std::vector<u8>& input); | 177 | NvResult SetNVMAPfd(const std::vector<u8>& input); |
| 150 | u32 Submit(const std::vector<u8>& input, std::vector<u8>& output); | 178 | NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output); |
| 151 | u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); | 179 | NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); |
| 152 | u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | 180 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); |
| 153 | u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | 181 | NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); |
| 154 | u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | 182 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); |
| 155 | u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 183 | NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); |
| 156 | 184 | ||
| 157 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; | 185 | std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; |
| 158 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); | 186 | void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); |
| 159 | std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); | 187 | std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); |
| 160 | 188 | ||
| 161 | u32_le nvmap_fd{}; | 189 | s32_le nvmap_fd{}; |
| 162 | u32_le submit_timeout{}; | 190 | u32_le submit_timeout{}; |
| 163 | std::shared_ptr<nvmap> nvmap_dev; | 191 | std::shared_ptr<nvmap> nvmap_dev; |
| 164 | 192 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 96e7b7dab..2d06955c0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -13,28 +13,44 @@ namespace Service::Nvidia::Devices { | |||
| 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} | 13 | nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} |
| 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; | 14 | nvhost_nvjpg::~nvhost_nvjpg() = default; |
| 15 | 15 | ||
| 16 | u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 16 | NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input, |
| 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 17 | std::vector<u8>& output) { |
| 18 | IoctlVersion version) { | 18 | switch (command.group) { |
| 19 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 19 | case 'H': |
| 20 | command.raw, input.size(), output.size()); | 20 | switch (command.cmd) { |
| 21 | 21 | case 0x1: | |
| 22 | switch (static_cast<IoctlCommand>(command.raw)) { | 22 | return SetNVMAPfd(input, output); |
| 23 | case IoctlCommand::IocSetNVMAPfdCommand: | 23 | default: |
| 24 | return SetNVMAPfd(input, output); | 24 | break; |
| 25 | } | ||
| 26 | break; | ||
| 27 | default: | ||
| 28 | break; | ||
| 25 | } | 29 | } |
| 26 | 30 | ||
| 27 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 31 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 28 | return 0; | 32 | return NvResult::NotImplemented; |
| 29 | } | 33 | } |
| 30 | 34 | ||
| 31 | u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | 35 | NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 36 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 37 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 38 | return NvResult::NotImplemented; | ||
| 39 | } | ||
| 40 | |||
| 41 | NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 42 | std::vector<u8>& inline_output) { | ||
| 43 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 44 | return NvResult::NotImplemented; | ||
| 45 | } | ||
| 46 | |||
| 47 | NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 32 | IoctlSetNvmapFD params{}; | 48 | IoctlSetNvmapFD params{}; |
| 33 | std::memcpy(¶ms, input.data(), input.size()); | 49 | std::memcpy(¶ms, input.data(), input.size()); |
| 34 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 50 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 35 | 51 | ||
| 36 | nvmap_fd = params.nvmap_fd; | 52 | nvmap_fd = params.nvmap_fd; |
| 37 | return 0; | 53 | return NvResult::Success; |
| 38 | } | 54 | } |
| 39 | 55 | ||
| 40 | } // namespace Service::Nvidia::Devices | 56 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 98dcac52f..43948d18d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | |||
| @@ -16,23 +16,21 @@ public: | |||
| 16 | explicit nvhost_nvjpg(Core::System& system); | 16 | explicit nvhost_nvjpg(Core::System& system); |
| 17 | ~nvhost_nvjpg() override; | 17 | ~nvhost_nvjpg() override; |
| 18 | 18 | ||
| 19 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 19 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 20 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 20 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 21 | IoctlVersion version) override; | 21 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 22 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 23 | std::vector<u8>& inline_output) override; | ||
| 22 | 24 | ||
| 23 | private: | 25 | private: |
| 24 | enum class IoctlCommand : u32_le { | ||
| 25 | IocSetNVMAPfdCommand = 0x40044801, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct IoctlSetNvmapFD { | 26 | struct IoctlSetNvmapFD { |
| 29 | u32_le nvmap_fd; | 27 | s32_le nvmap_fd{}; |
| 30 | }; | 28 | }; |
| 31 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); | 29 | static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); |
| 32 | 30 | ||
| 33 | u32_le nvmap_fd{}; | 31 | s32_le nvmap_fd{}; |
| 34 | 32 | ||
| 35 | u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); | 33 | NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); |
| 36 | }; | 34 | }; |
| 37 | 35 | ||
| 38 | } // namespace Service::Nvidia::Devices | 36 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 60db54d00..805fe86ae 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -15,36 +15,50 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | |||
| 15 | 15 | ||
| 16 | nvhost_vic::~nvhost_vic() = default; | 16 | nvhost_vic::~nvhost_vic() = default; |
| 17 | 17 | ||
| 18 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 18 | NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { |
| 19 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 19 | switch (command.group) { |
| 20 | IoctlVersion version) { | 20 | case 0x0: |
| 21 | LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", | 21 | switch (command.cmd) { |
| 22 | command.raw, input.size(), output.size()); | 22 | case 0x1: |
| 23 | 23 | return Submit(input, output); | |
| 24 | switch (static_cast<IoctlCommand>(command.raw)) { | 24 | case 0x2: |
| 25 | case IoctlCommand::IocSetNVMAPfdCommand: | 25 | return GetSyncpoint(input, output); |
| 26 | return SetNVMAPfd(input); | 26 | case 0x3: |
| 27 | case IoctlCommand::IocSubmit: | 27 | return GetWaitbase(input, output); |
| 28 | return Submit(input, output); | 28 | case 0x9: |
| 29 | case IoctlCommand::IocGetSyncpoint: | 29 | return MapBuffer(input, output); |
| 30 | return GetSyncpoint(input, output); | 30 | case 0xa: |
| 31 | case IoctlCommand::IocGetWaitbase: | 31 | return UnmapBuffer(input, output); |
| 32 | return GetWaitbase(input, output); | 32 | default: |
| 33 | case IoctlCommand::IocMapBuffer: | 33 | break; |
| 34 | case IoctlCommand::IocMapBuffer2: | 34 | } |
| 35 | case IoctlCommand::IocMapBuffer3: | 35 | break; |
| 36 | case IoctlCommand::IocMapBuffer4: | 36 | case 'H': |
| 37 | case IoctlCommand::IocMapBufferEx: | 37 | switch (command.cmd) { |
| 38 | return MapBuffer(input, output); | 38 | case 0x1: |
| 39 | case IoctlCommand::IocUnmapBuffer: | 39 | return SetNVMAPfd(input); |
| 40 | case IoctlCommand::IocUnmapBuffer2: | 40 | default: |
| 41 | case IoctlCommand::IocUnmapBuffer3: | 41 | break; |
| 42 | case IoctlCommand::IocUnmapBufferEx: | 42 | } |
| 43 | return UnmapBuffer(input, output); | 43 | break; |
| 44 | default: | ||
| 45 | break; | ||
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); | 48 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); |
| 47 | return 0; | 49 | return NvResult::NotImplemented; |
| 50 | } | ||
| 51 | |||
| 52 | NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 53 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 54 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 55 | return NvResult::NotImplemented; | ||
| 56 | } | ||
| 57 | |||
| 58 | NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 59 | std::vector<u8>& inline_output) { | ||
| 60 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 61 | return NvResult::NotImplemented; | ||
| 48 | } | 62 | } |
| 49 | 63 | ||
| 50 | } // namespace Service::Nvidia::Devices | 64 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index f975b190c..b2e11f4d4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -13,25 +13,11 @@ class nvhost_vic final : public nvhost_nvdec_common { | |||
| 13 | public: | 13 | public: |
| 14 | explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 14 | explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); |
| 15 | ~nvhost_vic(); | 15 | ~nvhost_vic(); |
| 16 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 17 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 18 | IoctlVersion version) override; | ||
| 19 | 16 | ||
| 20 | private: | 17 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; |
| 21 | enum class IoctlCommand : u32_le { | 18 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, |
| 22 | IocSetNVMAPfdCommand = 0x40044801, | 19 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; |
| 23 | IocSubmit = 0xC0400001, | 20 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, |
| 24 | IocGetSyncpoint = 0xC0080002, | 21 | std::vector<u8>& inline_output) override; |
| 25 | IocGetWaitbase = 0xC0080003, | ||
| 26 | IocMapBuffer = 0xC01C0009, | ||
| 27 | IocMapBuffer2 = 0xC0340009, | ||
| 28 | IocMapBuffer3 = 0xC0140009, | ||
| 29 | IocMapBuffer4 = 0xC00C0009, | ||
| 30 | IocMapBufferEx = 0xC03C0009, | ||
| 31 | IocUnmapBuffer = 0xC03C000A, | ||
| 32 | IocUnmapBuffer2 = 0xC034000A, | ||
| 33 | IocUnmapBuffer3 = 0xC00C000A, | ||
| 34 | IocUnmapBufferEx = 0xC01C000A, | ||
| 35 | }; | ||
| 36 | }; | 22 | }; |
| 37 | } // namespace Service::Nvidia::Devices | 23 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 9436e16ad..4015a2740 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -11,13 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 13 | 13 | ||
| 14 | namespace NvErrCodes { | ||
| 15 | enum { | ||
| 16 | OperationNotPermitted = -1, | ||
| 17 | InvalidValue = -22, | ||
| 18 | }; | ||
| 19 | } | ||
| 20 | |||
| 21 | nvmap::nvmap(Core::System& system) : nvdevice(system) { | 14 | nvmap::nvmap(Core::System& system) : nvdevice(system) { |
| 22 | // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to | 15 | // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to |
| 23 | // represent this. | 16 | // represent this. |
| @@ -26,6 +19,46 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) { | |||
| 26 | 19 | ||
| 27 | nvmap::~nvmap() = default; | 20 | nvmap::~nvmap() = default; |
| 28 | 21 | ||
| 22 | NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 23 | switch (command.group) { | ||
| 24 | case 0x1: | ||
| 25 | switch (command.cmd) { | ||
| 26 | case 0x1: | ||
| 27 | return IocCreate(input, output); | ||
| 28 | case 0x3: | ||
| 29 | return IocFromId(input, output); | ||
| 30 | case 0x4: | ||
| 31 | return IocAlloc(input, output); | ||
| 32 | case 0x5: | ||
| 33 | return IocFree(input, output); | ||
| 34 | case 0x9: | ||
| 35 | return IocParam(input, output); | ||
| 36 | case 0xe: | ||
| 37 | return IocGetId(input, output); | ||
| 38 | default: | ||
| 39 | break; | ||
| 40 | } | ||
| 41 | break; | ||
| 42 | default: | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | |||
| 46 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 47 | return NvResult::NotImplemented; | ||
| 48 | } | ||
| 49 | |||
| 50 | NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 51 | const std::vector<u8>& inline_input, std::vector<u8>& output) { | ||
| 52 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 53 | return NvResult::NotImplemented; | ||
| 54 | } | ||
| 55 | |||
| 56 | NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 57 | std::vector<u8>& inline_output) { | ||
| 58 | UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw); | ||
| 59 | return NvResult::NotImplemented; | ||
| 60 | } | ||
| 61 | |||
| 29 | VAddr nvmap::GetObjectAddress(u32 handle) const { | 62 | VAddr nvmap::GetObjectAddress(u32 handle) const { |
| 30 | auto object = GetObject(handle); | 63 | auto object = GetObject(handle); |
| 31 | ASSERT(object); | 64 | ASSERT(object); |
| @@ -33,28 +66,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const { | |||
| 33 | return object->addr; | 66 | return object->addr; |
| 34 | } | 67 | } |
| 35 | 68 | ||
| 36 | u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 37 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 38 | IoctlVersion version) { | ||
| 39 | switch (static_cast<IoctlCommand>(command.raw)) { | ||
| 40 | case IoctlCommand::Create: | ||
| 41 | return IocCreate(input, output); | ||
| 42 | case IoctlCommand::Alloc: | ||
| 43 | return IocAlloc(input, output); | ||
| 44 | case IoctlCommand::GetId: | ||
| 45 | return IocGetId(input, output); | ||
| 46 | case IoctlCommand::FromId: | ||
| 47 | return IocFromId(input, output); | ||
| 48 | case IoctlCommand::Param: | ||
| 49 | return IocParam(input, output); | ||
| 50 | case IoctlCommand::Free: | ||
| 51 | return IocFree(input, output); | ||
| 52 | } | ||
| 53 | |||
| 54 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | u32 nvmap::CreateObject(u32 size) { | 69 | u32 nvmap::CreateObject(u32 size) { |
| 59 | // Create a new nvmap object and obtain a handle to it. | 70 | // Create a new nvmap object and obtain a handle to it. |
| 60 | auto object = std::make_shared<Object>(); | 71 | auto object = std::make_shared<Object>(); |
| @@ -70,35 +81,35 @@ u32 nvmap::CreateObject(u32 size) { | |||
| 70 | return handle; | 81 | return handle; |
| 71 | } | 82 | } |
| 72 | 83 | ||
| 73 | u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { | 84 | NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { |
| 74 | IocCreateParams params; | 85 | IocCreateParams params; |
| 75 | std::memcpy(¶ms, input.data(), sizeof(params)); | 86 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 76 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); | 87 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); |
| 77 | 88 | ||
| 78 | if (!params.size) { | 89 | if (!params.size) { |
| 79 | LOG_ERROR(Service_NVDRV, "Size is 0"); | 90 | LOG_ERROR(Service_NVDRV, "Size is 0"); |
| 80 | return static_cast<u32>(NvErrCodes::InvalidValue); | 91 | return NvResult::BadValue; |
| 81 | } | 92 | } |
| 82 | 93 | ||
| 83 | params.handle = CreateObject(params.size); | 94 | params.handle = CreateObject(params.size); |
| 84 | 95 | ||
| 85 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 96 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 86 | return 0; | 97 | return NvResult::Success; |
| 87 | } | 98 | } |
| 88 | 99 | ||
| 89 | u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | 100 | NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { |
| 90 | IocAllocParams params; | 101 | IocAllocParams params; |
| 91 | std::memcpy(¶ms, input.data(), sizeof(params)); | 102 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 92 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); | 103 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); |
| 93 | 104 | ||
| 94 | if (!params.handle) { | 105 | if (!params.handle) { |
| 95 | LOG_ERROR(Service_NVDRV, "Handle is 0"); | 106 | LOG_ERROR(Service_NVDRV, "Handle is 0"); |
| 96 | return static_cast<u32>(NvErrCodes::InvalidValue); | 107 | return NvResult::BadValue; |
| 97 | } | 108 | } |
| 98 | 109 | ||
| 99 | if ((params.align - 1) & params.align) { | 110 | if ((params.align - 1) & params.align) { |
| 100 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); | 111 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); |
| 101 | return static_cast<u32>(NvErrCodes::InvalidValue); | 112 | return NvResult::BadValue; |
| 102 | } | 113 | } |
| 103 | 114 | ||
| 104 | const u32 min_alignment = 0x1000; | 115 | const u32 min_alignment = 0x1000; |
| @@ -109,12 +120,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 109 | auto object = GetObject(params.handle); | 120 | auto object = GetObject(params.handle); |
| 110 | if (!object) { | 121 | if (!object) { |
| 111 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 122 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 112 | return static_cast<u32>(NvErrCodes::InvalidValue); | 123 | return NvResult::BadValue; |
| 113 | } | 124 | } |
| 114 | 125 | ||
| 115 | if (object->status == Object::Status::Allocated) { | 126 | if (object->status == Object::Status::Allocated) { |
| 116 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); | 127 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); |
| 117 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 128 | return NvResult::InsufficientMemory; |
| 118 | } | 129 | } |
| 119 | 130 | ||
| 120 | object->flags = params.flags; | 131 | object->flags = params.flags; |
| @@ -124,10 +135,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 124 | object->status = Object::Status::Allocated; | 135 | object->status = Object::Status::Allocated; |
| 125 | 136 | ||
| 126 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 137 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 127 | return 0; | 138 | return NvResult::Success; |
| 128 | } | 139 | } |
| 129 | 140 | ||
| 130 | u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | 141 | NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { |
| 131 | IocGetIdParams params; | 142 | IocGetIdParams params; |
| 132 | std::memcpy(¶ms, input.data(), sizeof(params)); | 143 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 133 | 144 | ||
| @@ -135,22 +146,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 135 | 146 | ||
| 136 | if (!params.handle) { | 147 | if (!params.handle) { |
| 137 | LOG_ERROR(Service_NVDRV, "Handle is zero"); | 148 | LOG_ERROR(Service_NVDRV, "Handle is zero"); |
| 138 | return static_cast<u32>(NvErrCodes::InvalidValue); | 149 | return NvResult::BadValue; |
| 139 | } | 150 | } |
| 140 | 151 | ||
| 141 | auto object = GetObject(params.handle); | 152 | auto object = GetObject(params.handle); |
| 142 | if (!object) { | 153 | if (!object) { |
| 143 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 154 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 144 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 155 | return NvResult::BadValue; |
| 145 | } | 156 | } |
| 146 | 157 | ||
| 147 | params.id = object->id; | 158 | params.id = object->id; |
| 148 | 159 | ||
| 149 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 160 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 150 | return 0; | 161 | return NvResult::Success; |
| 151 | } | 162 | } |
| 152 | 163 | ||
| 153 | u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | 164 | NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { |
| 154 | IocFromIdParams params; | 165 | IocFromIdParams params; |
| 155 | std::memcpy(¶ms, input.data(), sizeof(params)); | 166 | std::memcpy(¶ms, input.data(), sizeof(params)); |
| 156 | 167 | ||
| @@ -160,13 +171,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 160 | [&](const auto& entry) { return entry.second->id == params.id; }); | 171 | [&](const auto& entry) { return entry.second->id == params.id; }); |
| 161 | if (itr == handles.end()) { | 172 | if (itr == handles.end()) { |
| 162 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 173 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 163 | return static_cast<u32>(NvErrCodes::InvalidValue); | 174 | return NvResult::BadValue; |
| 164 | } | 175 | } |
| 165 | 176 | ||
| 166 | auto& object = itr->second; | 177 | auto& object = itr->second; |
| 167 | if (object->status != Object::Status::Allocated) { | 178 | if (object->status != Object::Status::Allocated) { |
| 168 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | 179 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); |
| 169 | return static_cast<u32>(NvErrCodes::InvalidValue); | 180 | return NvResult::BadValue; |
| 170 | } | 181 | } |
| 171 | 182 | ||
| 172 | itr->second->refcount++; | 183 | itr->second->refcount++; |
| @@ -175,10 +186,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 175 | params.handle = itr->first; | 186 | params.handle = itr->first; |
| 176 | 187 | ||
| 177 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 188 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 178 | return 0; | 189 | return NvResult::Success; |
| 179 | } | 190 | } |
| 180 | 191 | ||
| 181 | u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | 192 | NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { |
| 182 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; | 193 | enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; |
| 183 | 194 | ||
| 184 | IocParamParams params; | 195 | IocParamParams params; |
| @@ -189,12 +200,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 189 | auto object = GetObject(params.handle); | 200 | auto object = GetObject(params.handle); |
| 190 | if (!object) { | 201 | if (!object) { |
| 191 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 202 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 192 | return static_cast<u32>(NvErrCodes::InvalidValue); | 203 | return NvResult::BadValue; |
| 193 | } | 204 | } |
| 194 | 205 | ||
| 195 | if (object->status != Object::Status::Allocated) { | 206 | if (object->status != Object::Status::Allocated) { |
| 196 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | 207 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); |
| 197 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 208 | return NvResult::BadValue; |
| 198 | } | 209 | } |
| 199 | 210 | ||
| 200 | switch (static_cast<ParamTypes>(params.param)) { | 211 | switch (static_cast<ParamTypes>(params.param)) { |
| @@ -216,10 +227,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 216 | } | 227 | } |
| 217 | 228 | ||
| 218 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 229 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 219 | return 0; | 230 | return NvResult::Success; |
| 220 | } | 231 | } |
| 221 | 232 | ||
| 222 | u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | 233 | NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { |
| 223 | // TODO(Subv): These flags are unconfirmed. | 234 | // TODO(Subv): These flags are unconfirmed. |
| 224 | enum FreeFlags { | 235 | enum FreeFlags { |
| 225 | Freed = 0, | 236 | Freed = 0, |
| @@ -234,14 +245,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 234 | auto itr = handles.find(params.handle); | 245 | auto itr = handles.find(params.handle); |
| 235 | if (itr == handles.end()) { | 246 | if (itr == handles.end()) { |
| 236 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | 247 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); |
| 237 | return static_cast<u32>(NvErrCodes::InvalidValue); | 248 | return NvResult::BadValue; |
| 238 | } | 249 | } |
| 239 | if (!itr->second->refcount) { | 250 | if (!itr->second->refcount) { |
| 240 | LOG_ERROR( | 251 | LOG_ERROR( |
| 241 | Service_NVDRV, | 252 | Service_NVDRV, |
| 242 | "There is no references to this object. The object is already freed. handle={:08X}", | 253 | "There is no references to this object. The object is already freed. handle={:08X}", |
| 243 | params.handle); | 254 | params.handle); |
| 244 | return static_cast<u32>(NvErrCodes::InvalidValue); | 255 | return NvResult::BadValue; |
| 245 | } | 256 | } |
| 246 | 257 | ||
| 247 | itr->second->refcount--; | 258 | itr->second->refcount--; |
| @@ -261,7 +272,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 261 | handles.erase(params.handle); | 272 | handles.erase(params.handle); |
| 262 | 273 | ||
| 263 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 274 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 264 | return 0; | 275 | return NvResult::Success; |
| 265 | } | 276 | } |
| 266 | 277 | ||
| 267 | } // namespace Service::Nvidia::Devices | 278 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 04b9ef540..4484bd79f 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h | |||
| @@ -19,13 +19,15 @@ public: | |||
| 19 | explicit nvmap(Core::System& system); | 19 | explicit nvmap(Core::System& system); |
| 20 | ~nvmap() override; | 20 | ~nvmap() override; |
| 21 | 21 | ||
| 22 | NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; | ||
| 23 | NvResult Ioctl2(Ioctl command, const std::vector<u8>& input, | ||
| 24 | const std::vector<u8>& inline_input, std::vector<u8>& output) override; | ||
| 25 | NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output, | ||
| 26 | std::vector<u8>& inline_output) override; | ||
| 27 | |||
| 22 | /// Returns the allocated address of an nvmap object given its handle. | 28 | /// Returns the allocated address of an nvmap object given its handle. |
| 23 | VAddr GetObjectAddress(u32 handle) const; | 29 | VAddr GetObjectAddress(u32 handle) const; |
| 24 | 30 | ||
| 25 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | ||
| 26 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | ||
| 27 | IoctlVersion version) override; | ||
| 28 | |||
| 29 | /// Represents an nvmap object. | 31 | /// Represents an nvmap object. |
| 30 | struct Object { | 32 | struct Object { |
| 31 | enum class Status { Created, Allocated }; | 33 | enum class Status { Created, Allocated }; |
| @@ -58,76 +60,68 @@ private: | |||
| 58 | /// Mapping of currently allocated handles to the objects they represent. | 60 | /// Mapping of currently allocated handles to the objects they represent. |
| 59 | std::unordered_map<u32, std::shared_ptr<Object>> handles; | 61 | std::unordered_map<u32, std::shared_ptr<Object>> handles; |
| 60 | 62 | ||
| 61 | enum class IoctlCommand : u32 { | ||
| 62 | Create = 0xC0080101, | ||
| 63 | FromId = 0xC0080103, | ||
| 64 | Alloc = 0xC0200104, | ||
| 65 | Free = 0xC0180105, | ||
| 66 | Param = 0xC00C0109, | ||
| 67 | GetId = 0xC008010E, | ||
| 68 | }; | ||
| 69 | struct IocCreateParams { | 63 | struct IocCreateParams { |
| 70 | // Input | 64 | // Input |
| 71 | u32_le size; | 65 | u32_le size{}; |
| 72 | // Output | 66 | // Output |
| 73 | u32_le handle; | 67 | u32_le handle{}; |
| 74 | }; | 68 | }; |
| 75 | static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); | 69 | static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); |
| 76 | 70 | ||
| 77 | struct IocFromIdParams { | 71 | struct IocFromIdParams { |
| 78 | // Input | 72 | // Input |
| 79 | u32_le id; | 73 | u32_le id{}; |
| 80 | // Output | 74 | // Output |
| 81 | u32_le handle; | 75 | u32_le handle{}; |
| 82 | }; | 76 | }; |
| 83 | static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); | 77 | static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); |
| 84 | 78 | ||
| 85 | struct IocAllocParams { | 79 | struct IocAllocParams { |
| 86 | // Input | 80 | // Input |
| 87 | u32_le handle; | 81 | u32_le handle{}; |
| 88 | u32_le heap_mask; | 82 | u32_le heap_mask{}; |
| 89 | u32_le flags; | 83 | u32_le flags{}; |
| 90 | u32_le align; | 84 | u32_le align{}; |
| 91 | u8 kind; | 85 | u8 kind{}; |
| 92 | INSERT_PADDING_BYTES(7); | 86 | INSERT_PADDING_BYTES(7); |
| 93 | u64_le addr; | 87 | u64_le addr{}; |
| 94 | }; | 88 | }; |
| 95 | static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); | 89 | static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); |
| 96 | 90 | ||
| 97 | struct IocFreeParams { | 91 | struct IocFreeParams { |
| 98 | u32_le handle; | 92 | u32_le handle{}; |
| 99 | INSERT_PADDING_BYTES(4); | 93 | INSERT_PADDING_BYTES(4); |
| 100 | u64_le address; | 94 | u64_le address{}; |
| 101 | u32_le size; | 95 | u32_le size{}; |
| 102 | u32_le flags; | 96 | u32_le flags{}; |
| 103 | }; | 97 | }; |
| 104 | static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); | 98 | static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); |
| 105 | 99 | ||
| 106 | struct IocParamParams { | 100 | struct IocParamParams { |
| 107 | // Input | 101 | // Input |
| 108 | u32_le handle; | 102 | u32_le handle{}; |
| 109 | u32_le param; | 103 | u32_le param{}; |
| 110 | // Output | 104 | // Output |
| 111 | u32_le result; | 105 | u32_le result{}; |
| 112 | }; | 106 | }; |
| 113 | static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); | 107 | static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); |
| 114 | 108 | ||
| 115 | struct IocGetIdParams { | 109 | struct IocGetIdParams { |
| 116 | // Output | 110 | // Output |
| 117 | u32_le id; | 111 | u32_le id{}; |
| 118 | // Input | 112 | // Input |
| 119 | u32_le handle; | 113 | u32_le handle{}; |
| 120 | }; | 114 | }; |
| 121 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); | 115 | static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); |
| 122 | 116 | ||
| 123 | u32 CreateObject(u32 size); | 117 | u32 CreateObject(u32 size); |
| 124 | 118 | ||
| 125 | u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); | 119 | NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output); |
| 126 | u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); | 120 | NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); |
| 127 | u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); | 121 | NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output); |
| 128 | u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); | 122 | NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output); |
| 129 | u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); | 123 | NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output); |
| 130 | u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); | 124 | NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output); |
| 131 | }; | 125 | }; |
| 132 | 126 | ||
| 133 | } // namespace Service::Nvidia::Devices | 127 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 88fbfa9b0..f6c38e853 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -23,124 +23,170 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) { | |||
| 23 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { | 23 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { |
| 24 | LOG_DEBUG(Service_NVDRV, "called"); | 24 | LOG_DEBUG(Service_NVDRV, "called"); |
| 25 | 25 | ||
| 26 | if (!is_initialized) { | ||
| 27 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 28 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 26 | const auto& buffer = ctx.ReadBuffer(); | 32 | const auto& buffer = ctx.ReadBuffer(); |
| 27 | std::string device_name(buffer.begin(), buffer.end()); | 33 | const std::string device_name(buffer.begin(), buffer.end()); |
| 34 | DeviceFD fd = nvdrv->Open(device_name); | ||
| 28 | 35 | ||
| 29 | u32 fd = nvdrv->Open(device_name); | ||
| 30 | IPC::ResponseBuilder rb{ctx, 4}; | 36 | IPC::ResponseBuilder rb{ctx, 4}; |
| 31 | rb.Push(RESULT_SUCCESS); | 37 | rb.Push(RESULT_SUCCESS); |
| 32 | rb.Push<u32>(fd); | 38 | rb.Push<DeviceFD>(fd); |
| 33 | rb.Push<u32>(0); | 39 | rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); |
| 40 | } | ||
| 41 | |||
| 42 | void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) { | ||
| 43 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 44 | rb.Push(RESULT_SUCCESS); | ||
| 45 | rb.PushEnum(result); | ||
| 34 | } | 46 | } |
| 35 | 47 | ||
| 36 | void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { | 48 | void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) { |
| 37 | IPC::RequestParser rp{ctx}; | 49 | IPC::RequestParser rp{ctx}; |
| 38 | u32 fd = rp.Pop<u32>(); | 50 | const auto fd = rp.Pop<DeviceFD>(); |
| 39 | u32 command = rp.Pop<u32>(); | 51 | const auto command = rp.PopRaw<Ioctl>(); |
| 40 | 52 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | |
| 41 | /// Ioctl 3 has 2 outputs, first in the input params, second is the result | 53 | |
| 42 | std::vector<u8> output(ctx.GetWriteBufferSize(0)); | 54 | if (!is_initialized) { |
| 43 | std::vector<u8> output2; | 55 | ServiceError(ctx, NvResult::NotInitialized); |
| 44 | if (version == IoctlVersion::Version3) { | 56 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); |
| 45 | output2.resize((ctx.GetWriteBufferSize(1))); | 57 | return; |
| 46 | } | 58 | } |
| 47 | 59 | ||
| 48 | /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. | 60 | // Check device |
| 49 | /// KickOfPB uses this | 61 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); |
| 50 | auto input = ctx.ReadBuffer(0); | 62 | const auto input_buffer = ctx.ReadBuffer(0); |
| 51 | 63 | ||
| 52 | std::vector<u8> input2; | 64 | const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer); |
| 53 | if (version == IoctlVersion::Version2) { | ||
| 54 | input2 = ctx.ReadBuffer(1); | ||
| 55 | } | ||
| 56 | 65 | ||
| 57 | IoctlCtrl ctrl{}; | 66 | if (command.is_out != 0) { |
| 58 | 67 | ctx.WriteBuffer(output_buffer); | |
| 59 | u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version); | ||
| 60 | |||
| 61 | if (ctrl.must_delay) { | ||
| 62 | ctrl.fresh_call = false; | ||
| 63 | ctx.SleepClientThread( | ||
| 64 | "NVServices::DelayedResponse", ctrl.timeout, | ||
| 65 | [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_, | ||
| 66 | Kernel::ThreadWakeupReason reason) { | ||
| 67 | IoctlCtrl ctrl2{ctrl}; | ||
| 68 | std::vector<u8> tmp_output = output; | ||
| 69 | std::vector<u8> tmp_output2 = output2; | ||
| 70 | const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, | ||
| 71 | tmp_output2, ctrl2, version); | ||
| 72 | ctx_.WriteBuffer(tmp_output, 0); | ||
| 73 | if (version == IoctlVersion::Version3) { | ||
| 74 | ctx_.WriteBuffer(tmp_output2, 1); | ||
| 75 | } | ||
| 76 | IPC::ResponseBuilder rb{ctx_, 3}; | ||
| 77 | rb.Push(RESULT_SUCCESS); | ||
| 78 | rb.Push(ioctl_result); | ||
| 79 | }, | ||
| 80 | nvdrv->GetEventWriteable(ctrl.event_id)); | ||
| 81 | } else { | ||
| 82 | ctx.WriteBuffer(output); | ||
| 83 | if (version == IoctlVersion::Version3) { | ||
| 84 | ctx.WriteBuffer(output2, 1); | ||
| 85 | } | ||
| 86 | } | 68 | } |
| 69 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 3}; | 70 | IPC::ResponseBuilder rb{ctx, 3}; |
| 88 | rb.Push(RESULT_SUCCESS); | 71 | rb.Push(RESULT_SUCCESS); |
| 89 | rb.Push(result); | 72 | rb.PushEnum(nv_result); |
| 90 | } | ||
| 91 | |||
| 92 | void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | ||
| 93 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 94 | IoctlBase(ctx, IoctlVersion::Version1); | ||
| 95 | } | 73 | } |
| 96 | 74 | ||
| 97 | void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { | 75 | void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { |
| 98 | LOG_DEBUG(Service_NVDRV, "called"); | 76 | IPC::RequestParser rp{ctx}; |
| 99 | IoctlBase(ctx, IoctlVersion::Version2); | 77 | const auto fd = rp.Pop<DeviceFD>(); |
| 78 | const auto command = rp.PopRaw<Ioctl>(); | ||
| 79 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | ||
| 80 | |||
| 81 | if (!is_initialized) { | ||
| 82 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 83 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | const auto input_buffer = ctx.ReadBuffer(0); | ||
| 88 | const auto input_inlined_buffer = ctx.ReadBuffer(1); | ||
| 89 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | ||
| 90 | |||
| 91 | const auto nv_result = | ||
| 92 | nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer); | ||
| 93 | |||
| 94 | if (command.is_out != 0) { | ||
| 95 | ctx.WriteBuffer(output_buffer); | ||
| 96 | } | ||
| 97 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 99 | rb.Push(RESULT_SUCCESS); | ||
| 100 | rb.PushEnum(nv_result); | ||
| 100 | } | 101 | } |
| 101 | 102 | ||
| 102 | void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { | 103 | void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { |
| 103 | LOG_DEBUG(Service_NVDRV, "called"); | 104 | IPC::RequestParser rp{ctx}; |
| 104 | IoctlBase(ctx, IoctlVersion::Version3); | 105 | const auto fd = rp.Pop<DeviceFD>(); |
| 106 | const auto command = rp.PopRaw<Ioctl>(); | ||
| 107 | LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw); | ||
| 108 | |||
| 109 | if (!is_initialized) { | ||
| 110 | ServiceError(ctx, NvResult::NotInitialized); | ||
| 111 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | |||
| 115 | const auto input_buffer = ctx.ReadBuffer(0); | ||
| 116 | std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0)); | ||
| 117 | std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1)); | ||
| 118 | |||
| 119 | const auto nv_result = | ||
| 120 | nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline); | ||
| 121 | |||
| 122 | if (command.is_out != 0) { | ||
| 123 | ctx.WriteBuffer(output_buffer, 0); | ||
| 124 | ctx.WriteBuffer(output_buffer_inline, 1); | ||
| 125 | } | ||
| 126 | |||
| 127 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 128 | rb.Push(RESULT_SUCCESS); | ||
| 129 | rb.PushEnum(nv_result); | ||
| 105 | } | 130 | } |
| 106 | 131 | ||
| 107 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { | 132 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { |
| 108 | LOG_DEBUG(Service_NVDRV, "called"); | 133 | LOG_DEBUG(Service_NVDRV, "called"); |
| 109 | 134 | ||
| 110 | IPC::RequestParser rp{ctx}; | 135 | if (!is_initialized) { |
| 111 | u32 fd = rp.Pop<u32>(); | 136 | ServiceError(ctx, NvResult::NotInitialized); |
| 137 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 138 | return; | ||
| 139 | } | ||
| 112 | 140 | ||
| 113 | auto result = nvdrv->Close(fd); | 141 | IPC::RequestParser rp{ctx}; |
| 142 | const auto fd = rp.Pop<DeviceFD>(); | ||
| 143 | const auto result = nvdrv->Close(fd); | ||
| 114 | 144 | ||
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 145 | IPC::ResponseBuilder rb{ctx, 3}; |
| 116 | rb.Push(result); | 146 | rb.Push(RESULT_SUCCESS); |
| 147 | rb.PushEnum(result); | ||
| 117 | } | 148 | } |
| 118 | 149 | ||
| 119 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { | 150 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { |
| 120 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 151 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 121 | 152 | ||
| 153 | is_initialized = true; | ||
| 154 | |||
| 122 | IPC::ResponseBuilder rb{ctx, 3}; | 155 | IPC::ResponseBuilder rb{ctx, 3}; |
| 123 | rb.Push(RESULT_SUCCESS); | 156 | rb.Push(RESULT_SUCCESS); |
| 124 | rb.Push<u32>(0); | 157 | rb.PushEnum(NvResult::Success); |
| 125 | } | 158 | } |
| 126 | 159 | ||
| 127 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { | 160 | void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { |
| 128 | IPC::RequestParser rp{ctx}; | 161 | IPC::RequestParser rp{ctx}; |
| 129 | u32 fd = rp.Pop<u32>(); | 162 | const auto fd = rp.Pop<DeviceFD>(); |
| 130 | // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 | 163 | const auto event_id = rp.Pop<u32>() & 0x00FF; |
| 131 | u32 event_id = rp.Pop<u32>() & 0x000000FF; | ||
| 132 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); | 164 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); |
| 133 | 165 | ||
| 134 | IPC::ResponseBuilder rb{ctx, 3, 1}; | 166 | if (!is_initialized) { |
| 135 | rb.Push(RESULT_SUCCESS); | 167 | ServiceError(ctx, NvResult::NotInitialized); |
| 168 | LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | |||
| 172 | const auto nv_result = nvdrv->VerifyFD(fd); | ||
| 173 | if (nv_result != NvResult::Success) { | ||
| 174 | LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd); | ||
| 175 | ServiceError(ctx, nv_result); | ||
| 176 | return; | ||
| 177 | } | ||
| 178 | |||
| 136 | if (event_id < MaxNvEvents) { | 179 | if (event_id < MaxNvEvents) { |
| 180 | IPC::ResponseBuilder rb{ctx, 3, 1}; | ||
| 181 | rb.Push(RESULT_SUCCESS); | ||
| 137 | auto event = nvdrv->GetEvent(event_id); | 182 | auto event = nvdrv->GetEvent(event_id); |
| 138 | event->Clear(); | 183 | event->Clear(); |
| 139 | rb.PushCopyObjects(event); | 184 | rb.PushCopyObjects(event); |
| 140 | rb.Push<u32>(NvResult::Success); | 185 | rb.PushEnum(NvResult::Success); |
| 141 | } else { | 186 | } else { |
| 142 | rb.Push<u32>(0); | 187 | IPC::ResponseBuilder rb{ctx, 3}; |
| 143 | rb.Push<u32>(NvResult::BadParameter); | 188 | rb.Push(RESULT_SUCCESS); |
| 189 | rb.PushEnum(NvResult::BadParameter); | ||
| 144 | } | 190 | } |
| 145 | } | 191 | } |
| 146 | 192 | ||
| @@ -151,7 +197,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) { | |||
| 151 | 197 | ||
| 152 | IPC::ResponseBuilder rb{ctx, 3}; | 198 | IPC::ResponseBuilder rb{ctx, 3}; |
| 153 | rb.Push(RESULT_SUCCESS); | 199 | rb.Push(RESULT_SUCCESS); |
| 154 | rb.Push<u32>(0); | 200 | rb.PushEnum(NvResult::Success); |
| 155 | } | 201 | } |
| 156 | 202 | ||
| 157 | void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { | 203 | void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { |
| @@ -164,8 +210,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct | |||
| 164 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { | 210 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { |
| 165 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 211 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 166 | 212 | ||
| 167 | IPC::ResponseBuilder rb{ctx, 2}; | 213 | IPC::ResponseBuilder rb{ctx, 3}; |
| 168 | rb.Push(RESULT_SUCCESS); | 214 | rb.Push(RESULT_SUCCESS); |
| 215 | rb.PushEnum(NvResult::Success); | ||
| 169 | } | 216 | } |
| 170 | 217 | ||
| 171 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { | 218 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { |
| @@ -181,7 +228,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | |||
| 181 | : ServiceFramework(name), nvdrv(std::move(nvdrv)) { | 228 | : ServiceFramework(name), nvdrv(std::move(nvdrv)) { |
| 182 | static const FunctionInfo functions[] = { | 229 | static const FunctionInfo functions[] = { |
| 183 | {0, &NVDRV::Open, "Open"}, | 230 | {0, &NVDRV::Open, "Open"}, |
| 184 | {1, &NVDRV::Ioctl, "Ioctl"}, | 231 | {1, &NVDRV::Ioctl1, "Ioctl"}, |
| 185 | {2, &NVDRV::Close, "Close"}, | 232 | {2, &NVDRV::Close, "Close"}, |
| 186 | {3, &NVDRV::Initialize, "Initialize"}, | 233 | {3, &NVDRV::Initialize, "Initialize"}, |
| 187 | {4, &NVDRV::QueryEvent, "QueryEvent"}, | 234 | {4, &NVDRV::QueryEvent, "QueryEvent"}, |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 72e17a728..e05f905ae 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | 23 | ||
| 24 | private: | 24 | private: |
| 25 | void Open(Kernel::HLERequestContext& ctx); | 25 | void Open(Kernel::HLERequestContext& ctx); |
| 26 | void Ioctl(Kernel::HLERequestContext& ctx); | 26 | void Ioctl1(Kernel::HLERequestContext& ctx); |
| 27 | void Ioctl2(Kernel::HLERequestContext& ctx); | 27 | void Ioctl2(Kernel::HLERequestContext& ctx); |
| 28 | void Ioctl3(Kernel::HLERequestContext& ctx); | 28 | void Ioctl3(Kernel::HLERequestContext& ctx); |
| 29 | void Close(Kernel::HLERequestContext& ctx); | 29 | void Close(Kernel::HLERequestContext& ctx); |
| @@ -33,11 +33,13 @@ private: | |||
| 33 | void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); | 33 | void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); |
| 34 | void GetStatus(Kernel::HLERequestContext& ctx); | 34 | void GetStatus(Kernel::HLERequestContext& ctx); |
| 35 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); | 35 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); |
| 36 | void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); | 36 | |
| 37 | void ServiceError(Kernel::HLERequestContext& ctx, NvResult result); | ||
| 37 | 38 | ||
| 38 | std::shared_ptr<Module> nvdrv; | 39 | std::shared_ptr<Module> nvdrv; |
| 39 | 40 | ||
| 40 | u64 pid{}; | 41 | u64 pid{}; |
| 42 | bool is_initialized{}; | ||
| 41 | }; | 43 | }; |
| 42 | 44 | ||
| 43 | } // namespace Service::Nvidia | 45 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 529b03471..3294bc0e7 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h | |||
| @@ -1,12 +1,16 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include <array> | 3 | #include <array> |
| 4 | #include "common/bit_field.h" | ||
| 4 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 5 | 6 | ||
| 6 | namespace Service::Nvidia { | 7 | namespace Service::Nvidia { |
| 7 | 8 | ||
| 8 | constexpr u32 MaxSyncPoints = 192; | 9 | constexpr u32 MaxSyncPoints = 192; |
| 9 | constexpr u32 MaxNvEvents = 64; | 10 | constexpr u32 MaxNvEvents = 64; |
| 11 | using DeviceFD = s32; | ||
| 12 | |||
| 13 | constexpr DeviceFD INVALID_NVDRV_FD = -1; | ||
| 10 | 14 | ||
| 11 | struct Fence { | 15 | struct Fence { |
| 12 | s32 id; | 16 | s32 id; |
| @@ -20,11 +24,61 @@ struct MultiFence { | |||
| 20 | std::array<Fence, 4> fences; | 24 | std::array<Fence, 4> fences; |
| 21 | }; | 25 | }; |
| 22 | 26 | ||
| 23 | enum NvResult : u32 { | 27 | enum class NvResult : u32 { |
| 24 | Success = 0, | 28 | Success = 0x0, |
| 25 | BadParameter = 4, | 29 | NotImplemented = 0x1, |
| 26 | Timeout = 5, | 30 | NotSupported = 0x2, |
| 27 | ResourceError = 15, | 31 | NotInitialized = 0x3, |
| 32 | BadParameter = 0x4, | ||
| 33 | Timeout = 0x5, | ||
| 34 | InsufficientMemory = 0x6, | ||
| 35 | ReadOnlyAttribute = 0x7, | ||
| 36 | InvalidState = 0x8, | ||
| 37 | InvalidAddress = 0x9, | ||
| 38 | InvalidSize = 0xA, | ||
| 39 | BadValue = 0xB, | ||
| 40 | AlreadyAllocated = 0xD, | ||
| 41 | Busy = 0xE, | ||
| 42 | ResourceError = 0xF, | ||
| 43 | CountMismatch = 0x10, | ||
| 44 | OverFlow = 0x11, | ||
| 45 | InsufficientTransferMemory = 0x1000, | ||
| 46 | InsufficientVideoMemory = 0x10000, | ||
| 47 | BadSurfaceColorScheme = 0x10001, | ||
| 48 | InvalidSurface = 0x10002, | ||
| 49 | SurfaceNotSupported = 0x10003, | ||
| 50 | DispInitFailed = 0x20000, | ||
| 51 | DispAlreadyAttached = 0x20001, | ||
| 52 | DispTooManyDisplays = 0x20002, | ||
| 53 | DispNoDisplaysAttached = 0x20003, | ||
| 54 | DispModeNotSupported = 0x20004, | ||
| 55 | DispNotFound = 0x20005, | ||
| 56 | DispAttachDissallowed = 0x20006, | ||
| 57 | DispTypeNotSupported = 0x20007, | ||
| 58 | DispAuthenticationFailed = 0x20008, | ||
| 59 | DispNotAttached = 0x20009, | ||
| 60 | DispSamePwrState = 0x2000A, | ||
| 61 | DispEdidFailure = 0x2000B, | ||
| 62 | DispDsiReadAckError = 0x2000C, | ||
| 63 | DispDsiReadInvalidResp = 0x2000D, | ||
| 64 | FileWriteFailed = 0x30000, | ||
| 65 | FileReadFailed = 0x30001, | ||
| 66 | EndOfFile = 0x30002, | ||
| 67 | FileOperationFailed = 0x30003, | ||
| 68 | DirOperationFailed = 0x30004, | ||
| 69 | EndOfDirList = 0x30005, | ||
| 70 | ConfigVarNotFound = 0x30006, | ||
| 71 | InvalidConfigVar = 0x30007, | ||
| 72 | LibraryNotFound = 0x30008, | ||
| 73 | SymbolNotFound = 0x30009, | ||
| 74 | MemoryMapFailed = 0x3000A, | ||
| 75 | IoctlFailed = 0x3000F, | ||
| 76 | AccessDenied = 0x30010, | ||
| 77 | DeviceNotFound = 0x30011, | ||
| 78 | KernelDriverNotFound = 0x30012, | ||
| 79 | FileNotFound = 0x30013, | ||
| 80 | PathAlreadyExists = 0x30014, | ||
| 81 | ModuleNotPresent = 0xA000E, | ||
| 28 | }; | 82 | }; |
| 29 | 83 | ||
| 30 | enum class EventState { | 84 | enum class EventState { |
| @@ -34,21 +88,13 @@ enum class EventState { | |||
| 34 | Busy = 3, | 88 | Busy = 3, |
| 35 | }; | 89 | }; |
| 36 | 90 | ||
| 37 | enum class IoctlVersion : u32 { | 91 | union Ioctl { |
| 38 | Version1, | 92 | u32_le raw; |
| 39 | Version2, | 93 | BitField<0, 8, u32> cmd; |
| 40 | Version3, | 94 | BitField<8, 8, u32> group; |
| 41 | }; | 95 | BitField<16, 14, u32> length; |
| 42 | 96 | BitField<30, 1, u32> is_in; | |
| 43 | struct IoctlCtrl { | 97 | BitField<31, 1, u32> is_out; |
| 44 | // First call done to the servioce for services that call itself again after a call. | ||
| 45 | bool fresh_call{true}; | ||
| 46 | // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep | ||
| 47 | bool must_delay{}; | ||
| 48 | // Timeout for the delay | ||
| 49 | s64 timeout{}; | ||
| 50 | // NV Event Id | ||
| 51 | s32 event_id{-1}; | ||
| 52 | }; | 98 | }; |
| 53 | 99 | ||
| 54 | } // namespace Service::Nvidia | 100 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 046a1f28c..bdbbedd0d 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -62,36 +62,101 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { | |||
| 62 | 62 | ||
| 63 | Module::~Module() = default; | 63 | Module::~Module() = default; |
| 64 | 64 | ||
| 65 | u32 Module::Open(const std::string& device_name) { | 65 | NvResult Module::VerifyFD(DeviceFD fd) const { |
| 66 | ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", | 66 | if (fd < 0) { |
| 67 | device_name); | 67 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 68 | return NvResult::InvalidState; | ||
| 69 | } | ||
| 70 | |||
| 71 | if (open_files.find(fd) == open_files.end()) { | ||
| 72 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 73 | return NvResult::NotImplemented; | ||
| 74 | } | ||
| 75 | |||
| 76 | return NvResult::Success; | ||
| 77 | } | ||
| 78 | |||
| 79 | DeviceFD Module::Open(const std::string& device_name) { | ||
| 80 | if (devices.find(device_name) == devices.end()) { | ||
| 81 | LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); | ||
| 82 | return INVALID_NVDRV_FD; | ||
| 83 | } | ||
| 68 | 84 | ||
| 69 | auto device = devices[device_name]; | 85 | auto device = devices[device_name]; |
| 70 | const u32 fd = next_fd++; | 86 | const DeviceFD fd = next_fd++; |
| 71 | 87 | ||
| 72 | open_files[fd] = std::move(device); | 88 | open_files[fd] = std::move(device); |
| 73 | 89 | ||
| 74 | return fd; | 90 | return fd; |
| 75 | } | 91 | } |
| 76 | 92 | ||
| 77 | u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, | 93 | NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 78 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 94 | std::vector<u8>& output) { |
| 79 | IoctlVersion version) { | 95 | if (fd < 0) { |
| 80 | auto itr = open_files.find(fd); | 96 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); |
| 81 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 97 | return NvResult::InvalidState; |
| 98 | } | ||
| 82 | 99 | ||
| 83 | auto& device = itr->second; | 100 | const auto itr = open_files.find(fd); |
| 84 | return device->ioctl({command}, input, input2, output, output2, ctrl, version); | 101 | |
| 102 | if (itr == open_files.end()) { | ||
| 103 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 104 | return NvResult::NotImplemented; | ||
| 105 | } | ||
| 106 | |||
| 107 | return itr->second->Ioctl1(command, input, output); | ||
| 85 | } | 108 | } |
| 86 | 109 | ||
| 87 | ResultCode Module::Close(u32 fd) { | 110 | NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 88 | auto itr = open_files.find(fd); | 111 | const std::vector<u8>& inline_input, std::vector<u8>& output) { |
| 89 | ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); | 112 | if (fd < 0) { |
| 113 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 114 | return NvResult::InvalidState; | ||
| 115 | } | ||
| 116 | |||
| 117 | const auto itr = open_files.find(fd); | ||
| 118 | |||
| 119 | if (itr == open_files.end()) { | ||
| 120 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 121 | return NvResult::NotImplemented; | ||
| 122 | } | ||
| 123 | |||
| 124 | return itr->second->Ioctl2(command, input, inline_input, output); | ||
| 125 | } | ||
| 126 | |||
| 127 | NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 128 | std::vector<u8>& output, std::vector<u8>& inline_output) { | ||
| 129 | if (fd < 0) { | ||
| 130 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 131 | return NvResult::InvalidState; | ||
| 132 | } | ||
| 133 | |||
| 134 | const auto itr = open_files.find(fd); | ||
| 135 | |||
| 136 | if (itr == open_files.end()) { | ||
| 137 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 138 | return NvResult::NotImplemented; | ||
| 139 | } | ||
| 140 | |||
| 141 | return itr->second->Ioctl3(command, input, output, inline_output); | ||
| 142 | } | ||
| 143 | |||
| 144 | NvResult Module::Close(DeviceFD fd) { | ||
| 145 | if (fd < 0) { | ||
| 146 | LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd); | ||
| 147 | return NvResult::InvalidState; | ||
| 148 | } | ||
| 149 | |||
| 150 | const auto itr = open_files.find(fd); | ||
| 151 | |||
| 152 | if (itr == open_files.end()) { | ||
| 153 | LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd); | ||
| 154 | return NvResult::NotImplemented; | ||
| 155 | } | ||
| 90 | 156 | ||
| 91 | open_files.erase(itr); | 157 | open_files.erase(itr); |
| 92 | 158 | ||
| 93 | // TODO(flerovium): return correct result code if operation failed. | 159 | return NvResult::Success; |
| 94 | return RESULT_SUCCESS; | ||
| 95 | } | 160 | } |
| 96 | 161 | ||
| 97 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { | 162 | void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index f3d863dac..7654bb026 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -112,14 +112,23 @@ public: | |||
| 112 | return std::static_pointer_cast<T>(itr->second); | 112 | return std::static_pointer_cast<T>(itr->second); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | NvResult VerifyFD(DeviceFD fd) const; | ||
| 116 | |||
| 115 | /// Opens a device node and returns a file descriptor to it. | 117 | /// Opens a device node and returns a file descriptor to it. |
| 116 | u32 Open(const std::string& device_name); | 118 | DeviceFD Open(const std::string& device_name); |
| 119 | |||
| 117 | /// Sends an ioctl command to the specified file descriptor. | 120 | /// Sends an ioctl command to the specified file descriptor. |
| 118 | u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, | 121 | NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, |
| 119 | std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, | 122 | std::vector<u8>& output); |
| 120 | IoctlVersion version); | 123 | |
| 124 | NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 125 | const std::vector<u8>& inline_input, std::vector<u8>& output); | ||
| 126 | |||
| 127 | NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input, | ||
| 128 | std::vector<u8>& output, std::vector<u8>& inline_output); | ||
| 129 | |||
| 121 | /// Closes a device file descriptor and returns operation success. | 130 | /// Closes a device file descriptor and returns operation success. |
| 122 | ResultCode Close(u32 fd); | 131 | NvResult Close(DeviceFD fd); |
| 123 | 132 | ||
| 124 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); | 133 | void SignalSyncpt(const u32 syncpoint_id, const u32 value); |
| 125 | 134 | ||
| @@ -132,10 +141,10 @@ private: | |||
| 132 | SyncpointManager syncpoint_manager; | 141 | SyncpointManager syncpoint_manager; |
| 133 | 142 | ||
| 134 | /// Id to use for the next open file descriptor. | 143 | /// Id to use for the next open file descriptor. |
| 135 | u32 next_fd = 1; | 144 | DeviceFD next_fd = 1; |
| 136 | 145 | ||
| 137 | /// Mapping of file descriptors to the devices they reference. | 146 | /// Mapping of file descriptors to the devices they reference. |
| 138 | std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; | 147 | std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files; |
| 139 | 148 | ||
| 140 | /// Mapping of device node names to their implementation. | 149 | /// Mapping of device node names to their implementation. |
| 141 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; | 150 | std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; |
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/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 394a1bf26..2002dc4f2 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -114,7 +114,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | if (override_update) { | 116 | if (override_update) { |
| 117 | const FileSys::PatchManager patch_manager(metadata.GetTitleID()); | 117 | const FileSys::PatchManager patch_manager( |
| 118 | metadata.GetTitleID(), system.GetFileSystemController(), system.GetContentProvider()); | ||
| 118 | dir = patch_manager.PatchExeFS(dir); | 119 | dir = patch_manager.PatchExeFS(dir); |
| 119 | } | 120 | } |
| 120 | 121 | ||
| @@ -160,7 +161,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 160 | modules.clear(); | 161 | modules.clear(); |
| 161 | const VAddr base_address{process.PageTable().GetCodeRegionStart()}; | 162 | const VAddr base_address{process.PageTable().GetCodeRegionStart()}; |
| 162 | VAddr next_load_addr{base_address}; | 163 | VAddr next_load_addr{base_address}; |
| 163 | const FileSys::PatchManager pm{metadata.GetTitleID()}; | 164 | const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), |
| 165 | system.GetContentProvider()}; | ||
| 164 | for (const auto& module : static_modules) { | 166 | for (const auto& module : static_modules) { |
| 165 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; | 167 | const FileSys::VirtualFile module_file{dir->GetFile(module)}; |
| 166 | if (!module_file) { | 168 | if (!module_file) { |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 9bc3a8840..d91c15561 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "common/string_util.h" | 12 | #include "common/string_util.h" |
| 13 | #include "core/core.h" | ||
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/loader/deconstructed_rom_directory.h" | 15 | #include "core/loader/deconstructed_rom_directory.h" |
| 15 | #include "core/loader/elf.h" | 16 | #include "core/loader/elf.h" |
| @@ -194,15 +195,15 @@ AppLoader::~AppLoader() = default; | |||
| 194 | 195 | ||
| 195 | /** | 196 | /** |
| 196 | * Get a loader for a file with a specific type | 197 | * Get a loader for a file with a specific type |
| 197 | * @param file The file to load | 198 | * @param system The system context to use. |
| 198 | * @param type The type of the file | 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(FileSys::VirtualFile file, FileType type) { | 204 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, |
| 205 | FileType type, std::size_t program_index) { | ||
| 204 | switch (type) { | 206 | switch (type) { |
| 205 | |||
| 206 | // Standard ELF file format. | 207 | // Standard ELF file format. |
| 207 | case FileType::ELF: | 208 | case FileType::ELF: |
| 208 | return std::make_unique<AppLoader_ELF>(std::move(file)); | 209 | return std::make_unique<AppLoader_ELF>(std::move(file)); |
| @@ -221,7 +222,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 221 | 222 | ||
| 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)); | 225 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), |
| 226 | system.GetContentProvider(), program_index); | ||
| 225 | 227 | ||
| 226 | // NX NAX (NintendoAesXts) file format. | 228 | // NX NAX (NintendoAesXts) file format. |
| 227 | case FileType::NAX: | 229 | case FileType::NAX: |
| @@ -229,7 +231,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 229 | 231 | ||
| 230 | // NX NSP (Nintendo Submission Package) file format | 232 | // NX NSP (Nintendo Submission Package) file format |
| 231 | case FileType::NSP: | 233 | case FileType::NSP: |
| 232 | return std::make_unique<AppLoader_NSP>(std::move(file)); | 234 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), |
| 235 | system.GetContentProvider(), program_index); | ||
| 233 | 236 | ||
| 234 | // NX KIP (Kernel Internal Process) file format | 237 | // NX KIP (Kernel Internal Process) file format |
| 235 | case FileType::KIP: | 238 | case FileType::KIP: |
| @@ -244,20 +247,22 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT | |||
| 244 | } | 247 | } |
| 245 | } | 248 | } |
| 246 | 249 | ||
| 247 | std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) { | 250 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 251 | std::size_t program_index) { | ||
| 248 | FileType type = IdentifyFile(file); | 252 | FileType type = IdentifyFile(file); |
| 249 | FileType filename_type = GuessFromFilename(file->GetName()); | 253 | const FileType filename_type = GuessFromFilename(file->GetName()); |
| 250 | 254 | ||
| 251 | // Special case: 00 is either a NCA or NAX. | 255 | // Special case: 00 is either a NCA or NAX. |
| 252 | if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { | 256 | if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { |
| 253 | LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); | 257 | LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); |
| 254 | if (FileType::Unknown == type) | 258 | if (FileType::Unknown == type) { |
| 255 | type = filename_type; | 259 | type = filename_type; |
| 260 | } | ||
| 256 | } | 261 | } |
| 257 | 262 | ||
| 258 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); | 263 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); |
| 259 | 264 | ||
| 260 | return GetFileLoader(std::move(file), type); | 265 | return GetFileLoader(system, std::move(file), type, program_index); |
| 261 | } | 266 | } |
| 262 | 267 | ||
| 263 | } // namespace Loader | 268 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index ac60b097a..36e79e71d 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -290,9 +290,14 @@ protected: | |||
| 290 | 290 | ||
| 291 | /** | 291 | /** |
| 292 | * Identifies a bootable file and return a suitable loader | 292 | * Identifies a bootable file and return a suitable loader |
| 293 | * @param file The bootable file | 293 | * |
| 294 | * @return the best loader for this file | 294 | * @param system The system context. |
| 295 | * @param file The bootable file. | ||
| 296 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 297 | * | ||
| 298 | * @return the best loader for this file. | ||
| 295 | */ | 299 | */ |
| 296 | std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file); | 300 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 301 | std::size_t program_index = 0); | ||
| 297 | 302 | ||
| 298 | } // namespace Loader | 303 | } // namespace Loader |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 497f438a1..aa85c1a29 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -149,7 +149,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S | |||
| 149 | // Apply cheats if they exist and the program has a valid title ID | 149 | // Apply cheats if they exist and the program has a valid title ID |
| 150 | if (pm) { | 150 | if (pm) { |
| 151 | system.SetCurrentProcessBuildID(nso_header.build_id); | 151 | system.SetCurrentProcessBuildID(nso_header.build_id); |
| 152 | const auto cheats = pm->CreateCheatList(system, nso_header.build_id); | 152 | const auto cheats = pm->CreateCheatList(nso_header.build_id); |
| 153 | if (!cheats.empty()) { | 153 | if (!cheats.empty()) { |
| 154 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); | 154 | system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); |
| 155 | } | 155 | } |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 15e528fa8..928f64c8c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -21,26 +21,34 @@ | |||
| 21 | 21 | ||
| 22 | namespace Loader { | 22 | namespace Loader { |
| 23 | 23 | ||
| 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) | 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, |
| 25 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), | 25 | const Service::FileSystem::FileSystemController& fsc, |
| 26 | const FileSys::ContentProvider& content_provider, | ||
| 27 | std::size_t program_index) | ||
| 28 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)), | ||
| 26 | title_id(nsp->GetProgramTitleID()) { | 29 | title_id(nsp->GetProgramTitleID()) { |
| 27 | 30 | ||
| 28 | if (nsp->GetStatus() != ResultStatus::Success) | 31 | if (nsp->GetStatus() != ResultStatus::Success) { |
| 29 | return; | 32 | return; |
| 33 | } | ||
| 30 | 34 | ||
| 31 | if (nsp->IsExtractedType()) { | 35 | if (nsp->IsExtractedType()) { |
| 32 | secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); | 36 | secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); |
| 33 | } else { | 37 | } else { |
| 34 | const auto control_nca = | 38 | const auto control_nca = |
| 35 | nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); | 39 | nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); |
| 36 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) | 40 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) { |
| 37 | return; | 41 | return; |
| 42 | } | ||
| 38 | 43 | ||
| 39 | std::tie(nacp_file, icon_file) = | 44 | std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] { |
| 40 | FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca); | 45 | const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider}; |
| 46 | return pm.ParseControlNCA(*control_nca); | ||
| 47 | }(); | ||
| 41 | 48 | ||
| 42 | if (title_id == 0) | 49 | if (title_id == 0) { |
| 43 | return; | 50 | return; |
| 51 | } | ||
| 44 | 52 | ||
| 45 | secondary_loader = std::make_unique<AppLoader_NCA>( | 53 | secondary_loader = std::make_unique<AppLoader_NCA>( |
| 46 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); | 54 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); |
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index b27deb686..f0518ac47 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -9,15 +9,16 @@ | |||
| 9 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| 10 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 11 | 11 | ||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace FileSys { | 12 | namespace FileSys { |
| 13 | class ContentProvider; | ||
| 17 | class NACP; | 14 | class NACP; |
| 18 | class NSP; | 15 | class NSP; |
| 19 | } // namespace FileSys | 16 | } // namespace FileSys |
| 20 | 17 | ||
| 18 | namespace Service::FileSystem { | ||
| 19 | class FileSystemController; | ||
| 20 | } | ||
| 21 | |||
| 21 | namespace Loader { | 22 | namespace Loader { |
| 22 | 23 | ||
| 23 | class AppLoader_NCA; | 24 | class AppLoader_NCA; |
| @@ -25,7 +26,10 @@ class AppLoader_NCA; | |||
| 25 | /// Loads an XCI file | 26 | /// Loads an XCI file |
| 26 | class AppLoader_NSP final : public AppLoader { | 27 | class AppLoader_NSP final : public AppLoader { |
| 27 | public: | 28 | public: |
| 28 | explicit AppLoader_NSP(FileSys::VirtualFile file); | 29 | explicit AppLoader_NSP(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | ||
| 31 | const FileSys::ContentProvider& content_provider, | ||
| 32 | std::size_t program_index); | ||
| 29 | ~AppLoader_NSP() override; | 33 | ~AppLoader_NSP() override; |
| 30 | 34 | ||
| 31 | /** | 35 | /** |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 25e83af0f..aaa250cea 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -20,18 +20,25 @@ | |||
| 20 | 20 | ||
| 21 | namespace Loader { | 21 | namespace Loader { |
| 22 | 22 | ||
| 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) | 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, |
| 24 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), | 24 | const Service::FileSystem::FileSystemController& fsc, |
| 25 | const FileSys::ContentProvider& content_provider, | ||
| 26 | std::size_t program_index) | ||
| 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)), | ||
| 25 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { | 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { |
| 26 | if (xci->GetStatus() != ResultStatus::Success) | 29 | if (xci->GetStatus() != ResultStatus::Success) { |
| 27 | return; | 30 | return; |
| 31 | } | ||
| 28 | 32 | ||
| 29 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); | 33 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); |
| 30 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) | 34 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) { |
| 31 | return; | 35 | return; |
| 36 | } | ||
| 32 | 37 | ||
| 33 | std::tie(nacp_file, icon_file) = | 38 | std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] { |
| 34 | FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(*control_nca); | 39 | const FileSys::PatchManager pm{xci->GetProgramTitleID(), fsc, content_provider}; |
| 40 | return pm.ParseControlNCA(*control_nca); | ||
| 41 | }(); | ||
| 35 | } | 42 | } |
| 36 | 43 | ||
| 37 | AppLoader_XCI::~AppLoader_XCI() = default; | 44 | AppLoader_XCI::~AppLoader_XCI() = default; |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 04aea286f..764dc8328 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -9,15 +9,16 @@ | |||
| 9 | #include "core/file_sys/vfs.h" | 9 | #include "core/file_sys/vfs.h" |
| 10 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 11 | 11 | ||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace FileSys { | 12 | namespace FileSys { |
| 13 | class ContentProvider; | ||
| 17 | class NACP; | 14 | class NACP; |
| 18 | class XCI; | 15 | class XCI; |
| 19 | } // namespace FileSys | 16 | } // namespace FileSys |
| 20 | 17 | ||
| 18 | namespace Service::FileSystem { | ||
| 19 | class FileSystemController; | ||
| 20 | } | ||
| 21 | |||
| 21 | namespace Loader { | 22 | namespace Loader { |
| 22 | 23 | ||
| 23 | class AppLoader_NCA; | 24 | class AppLoader_NCA; |
| @@ -25,7 +26,10 @@ class AppLoader_NCA; | |||
| 25 | /// Loads an XCI file | 26 | /// Loads an XCI file |
| 26 | class AppLoader_XCI final : public AppLoader { | 27 | class AppLoader_XCI final : public AppLoader { |
| 27 | public: | 28 | public: |
| 28 | explicit AppLoader_XCI(FileSys::VirtualFile file); | 29 | explicit AppLoader_XCI(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | ||
| 31 | const FileSys::ContentProvider& content_provider, | ||
| 32 | std::size_t program_index); | ||
| 29 | ~AppLoader_XCI() override; | 33 | ~AppLoader_XCI() override; |
| 30 | 34 | ||
| 31 | /** | 35 | /** |
diff --git a/src/core/settings.h b/src/core/settings.h index 476c3fdf3..1143aba5d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -215,6 +215,7 @@ struct Values { | |||
| 215 | bool reporting_services; | 215 | bool reporting_services; |
| 216 | bool quest_flag; | 216 | bool quest_flag; |
| 217 | bool disable_macro_jit; | 217 | bool disable_macro_jit; |
| 218 | bool extended_logging; | ||
| 218 | 219 | ||
| 219 | // Misceallaneous | 220 | // Misceallaneous |
| 220 | std::string log_filter; | 221 | std::string log_filter; |
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index e0908186b..d11b15f38 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp | |||
| @@ -147,7 +147,9 @@ TelemetrySession::~TelemetrySession() { | |||
| 147 | } | 147 | } |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { | 150 | void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, |
| 151 | const Service::FileSystem::FileSystemController& fsc, | ||
| 152 | const FileSys::ContentProvider& content_provider) { | ||
| 151 | // Log one-time top-level information | 153 | // Log one-time top-level information |
| 152 | AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); | 154 | AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); |
| 153 | 155 | ||
| @@ -167,7 +169,10 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { | |||
| 167 | app_loader.ReadTitle(name); | 169 | app_loader.ReadTitle(name); |
| 168 | 170 | ||
| 169 | if (name.empty()) { | 171 | if (name.empty()) { |
| 170 | const auto metadata = FileSys::PatchManager(program_id).GetControlMetadata(); | 172 | const auto metadata = [&content_provider, &fsc, program_id] { |
| 173 | const FileSys::PatchManager pm{program_id, fsc, content_provider}; | ||
| 174 | return pm.GetControlMetadata(); | ||
| 175 | }(); | ||
| 171 | if (metadata.first != nullptr) { | 176 | if (metadata.first != nullptr) { |
| 172 | name = metadata.first->GetApplicationName(); | 177 | name = metadata.first->GetApplicationName(); |
| 173 | } | 178 | } |
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index 66789d4bd..6f3d45bea 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h | |||
| @@ -7,10 +7,18 @@ | |||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include "common/telemetry.h" | 8 | #include "common/telemetry.h" |
| 9 | 9 | ||
| 10 | namespace FileSys { | ||
| 11 | class ContentProvider; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Loader { | 14 | namespace Loader { |
| 11 | class AppLoader; | 15 | class AppLoader; |
| 12 | } | 16 | } |
| 13 | 17 | ||
| 18 | namespace Service::FileSystem { | ||
| 19 | class FileSystemController; | ||
| 20 | } | ||
| 21 | |||
| 14 | namespace Core { | 22 | namespace Core { |
| 15 | 23 | ||
| 16 | /** | 24 | /** |
| @@ -40,10 +48,14 @@ public: | |||
| 40 | * - Title file format | 48 | * - Title file format |
| 41 | * - Miscellaneous settings values. | 49 | * - Miscellaneous settings values. |
| 42 | * | 50 | * |
| 43 | * @param app_loader The application loader to use to retrieve | 51 | * @param app_loader The application loader to use to retrieve |
| 44 | * title-specific information. | 52 | * title-specific information. |
| 53 | * @param fsc Filesystem controller to use to retrieve info. | ||
| 54 | * @param content_provider Content provider to use to retrieve info. | ||
| 45 | */ | 55 | */ |
| 46 | void AddInitialInfo(Loader::AppLoader& app_loader); | 56 | void AddInitialInfo(Loader::AppLoader& app_loader, |
| 57 | const Service::FileSystem::FileSystemController& fsc, | ||
| 58 | const FileSys::ContentProvider& content_provider); | ||
| 47 | 59 | ||
| 48 | /** | 60 | /** |
| 49 | * Wrapper around the Telemetry::FieldCollection::AddField method. | 61 | * Wrapper around the Telemetry::FieldCollection::AddField method. |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 7b39a38c1..1d1b2e08a 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -31,6 +31,9 @@ add_library(input_common STATIC | |||
| 31 | 31 | ||
| 32 | if (MSVC) | 32 | if (MSVC) |
| 33 | target_compile_options(input_common PRIVATE | 33 | target_compile_options(input_common PRIVATE |
| 34 | /W4 | ||
| 35 | /WX | ||
| 36 | |||
| 34 | # 'expression' : signed/unsigned mismatch | 37 | # 'expression' : signed/unsigned mismatch |
| 35 | /we4018 | 38 | /we4018 |
| 36 | # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) | 39 | # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) |
| @@ -46,6 +49,7 @@ if (MSVC) | |||
| 46 | ) | 49 | ) |
| 47 | else() | 50 | else() |
| 48 | target_compile_options(input_common PRIVATE | 51 | target_compile_options(input_common PRIVATE |
| 52 | -Werror | ||
| 49 | -Werror=conversion | 53 | -Werror=conversion |
| 50 | -Werror=ignored-qualifiers | 54 | -Werror=ignored-qualifiers |
| 51 | -Werror=implicit-fallthrough | 55 | -Werror=implicit-fallthrough |
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 d95574bb5..4d1052414 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -96,7 +96,6 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param | |||
| 96 | adapter.get()); | 96 | adapter.get()); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | UNREACHABLE(); | ||
| 100 | return nullptr; | 99 | return nullptr; |
| 101 | } | 100 | } |
| 102 | 101 | ||
| @@ -300,7 +299,8 @@ public: | |||
| 300 | return gcadapter->RumblePlay(port, 0); | 299 | return gcadapter->RumblePlay(port, 0); |
| 301 | } | 300 | } |
| 302 | 301 | ||
| 303 | 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 { | ||
| 304 | const auto mean_amplitude = (amp_low + amp_high) * 0.5f; | 304 | const auto mean_amplitude = (amp_low + amp_high) * 0.5f; |
| 305 | const auto processed_amplitude = | 305 | const auto processed_amplitude = |
| 306 | 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.h b/src/input_common/sdl/sdl.h index f3554be9a..42bbf14d4 100644 --- a/src/input_common/sdl/sdl.h +++ b/src/input_common/sdl/sdl.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | /// Unregisters SDL device factories and shut them down. | 23 | /// Unregisters SDL device factories and shut them down. |
| 24 | virtual ~State() = default; | 24 | virtual ~State() = default; |
| 25 | 25 | ||
| 26 | virtual Pollers GetPollers(Polling::DeviceType type) { | 26 | virtual Pollers GetPollers(Polling::DeviceType) { |
| 27 | return {}; | 27 | return {}; |
| 28 | } | 28 | } |
| 29 | 29 | ||
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index c395d96cf..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 | }; |
| @@ -864,6 +865,8 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve | |||
| 864 | Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid, | 865 | Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid, |
| 865 | const SDL_GameControllerButtonBind& binding) { | 866 | const SDL_GameControllerButtonBind& binding) { |
| 866 | switch (binding.bindType) { | 867 | switch (binding.bindType) { |
| 868 | case SDL_CONTROLLER_BINDTYPE_NONE: | ||
| 869 | break; | ||
| 867 | case SDL_CONTROLLER_BINDTYPE_AXIS: | 870 | case SDL_CONTROLLER_BINDTYPE_AXIS: |
| 868 | return BuildAnalogParamPackageForButton(port, guid, binding.value.axis); | 871 | return BuildAnalogParamPackageForButton(port, guid, binding.value.axis); |
| 869 | case SDL_CONTROLLER_BINDTYPE_BUTTON: | 872 | case SDL_CONTROLLER_BINDTYPE_BUTTON: |
| @@ -984,7 +987,7 @@ class SDLPoller : public InputCommon::Polling::DevicePoller { | |||
| 984 | public: | 987 | public: |
| 985 | explicit SDLPoller(SDLState& state_) : state(state_) {} | 988 | explicit SDLPoller(SDLState& state_) : state(state_) {} |
| 986 | 989 | ||
| 987 | void Start(const std::string& device_id) override { | 990 | void Start([[maybe_unused]] const std::string& device_id) override { |
| 988 | state.event_queue.Clear(); | 991 | state.event_queue.Clear(); |
| 989 | state.polling = true; | 992 | state.polling = true; |
| 990 | } | 993 | } |
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index c37716aae..a07124a86 100644 --- a/src/input_common/touch_from_button.cpp +++ b/src/input_common/touch_from_button.cpp | |||
| @@ -44,8 +44,7 @@ private: | |||
| 44 | std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map; | 44 | std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map; |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create( | 47 | std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create(const Common::ParamPackage&) { |
| 48 | const Common::ParamPackage& params) { | ||
| 49 | return std::make_unique<TouchFromButtonDevice>(); | 48 | return std::make_unique<TouchFromButtonDevice>(); |
| 50 | } | 49 | } |
| 51 | 50 | ||
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index 3677e79ca..c0bb90048 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp | |||
| @@ -63,7 +63,7 @@ public: | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | private: | 65 | private: |
| 66 | void HandleReceive(const boost::system::error_code& error, std::size_t bytes_transferred) { | 66 | void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { |
| 67 | if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { | 67 | if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { |
| 68 | switch (*type) { | 68 | switch (*type) { |
| 69 | case Type::Version: { | 69 | case Type::Version: { |
| @@ -90,7 +90,7 @@ private: | |||
| 90 | StartReceive(); | 90 | StartReceive(); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | void HandleSend(const boost::system::error_code& error) { | 93 | void HandleSend(const boost::system::error_code&) { |
| 94 | boost::system::error_code _ignored{}; | 94 | boost::system::error_code _ignored{}; |
| 95 | // Send a request for getting port info for the pad | 95 | // Send a request for getting port info for the pad |
| 96 | const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}}; | 96 | const Request::PortInfo port_info{1, {static_cast<u8>(pad_index), 0, 0, 0}}; |
| @@ -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 | ||
| @@ -369,7 +369,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 369 | u16 max_y{}; | 369 | u16 max_y{}; |
| 370 | 370 | ||
| 371 | Status current_status{Status::Initialized}; | 371 | Status current_status{Status::Initialized}; |
| 372 | SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, | 372 | SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, |
| 373 | [&](Response::PadData data) { | 373 | [&](Response::PadData data) { |
| 374 | if (current_status == Status::Initialized) { | 374 | if (current_status == Status::Initialized) { |
| 375 | // Receiving data means the communication is ready now | 375 | // Receiving data means the communication is ready now |
diff --git a/src/input_common/udp/protocol.h b/src/input_common/udp/protocol.h index 3ba4d1fc8..fc1aea4b9 100644 --- a/src/input_common/udp/protocol.h +++ b/src/input_common/udp/protocol.h | |||
| @@ -7,7 +7,16 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <optional> | 8 | #include <optional> |
| 9 | #include <type_traits> | 9 | #include <type_traits> |
| 10 | |||
| 11 | #ifdef _MSC_VER | ||
| 12 | #pragma warning(push) | ||
| 13 | #pragma warning(disable : 4701) | ||
| 14 | #endif | ||
| 10 | #include <boost/crc.hpp> | 15 | #include <boost/crc.hpp> |
| 16 | #ifdef _MSC_VER | ||
| 17 | #pragma warning(pop) | ||
| 18 | #endif | ||
| 19 | |||
| 11 | #include "common/bit_field.h" | 20 | #include "common/bit_field.h" |
| 12 | #include "common/swap.h" | 21 | #include "common/swap.h" |
| 13 | 22 | ||
| @@ -93,7 +102,7 @@ static_assert(std::is_trivially_copyable_v<PadData>, | |||
| 93 | 102 | ||
| 94 | /** | 103 | /** |
| 95 | * Creates a message with the proper header data that can be sent to the server. | 104 | * Creates a message with the proper header data that can be sent to the server. |
| 96 | * @param T data Request body to send | 105 | * @param data Request body to send |
| 97 | * @param client_id ID of the udp client (usually not checked on the server) | 106 | * @param client_id ID of the udp client (usually not checked on the server) |
| 98 | */ | 107 | */ |
| 99 | template <typename T> | 108 | template <typename T> |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index cdcde7c59..cfddbde5d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -1156,7 +1156,7 @@ void RasterizerOpenGL::SyncViewport() { | |||
| 1156 | flags[Dirty::ClipControl] = false; | 1156 | flags[Dirty::ClipControl] = false; |
| 1157 | 1157 | ||
| 1158 | bool flip_y = false; | 1158 | bool flip_y = false; |
| 1159 | if (regs.viewport_transform[0].scale_y < 0.0) { | 1159 | if (regs.viewport_transform[0].scale_y < 0.0f) { |
| 1160 | flip_y = !flip_y; | 1160 | flip_y = !flip_y; |
| 1161 | } | 1161 | } |
| 1162 | if (regs.screen_y_control.y_negate != 0) { | 1162 | if (regs.screen_y_control.y_negate != 0) { |
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp index 39cc3b869..6920afdf2 100644 --- a/src/video_core/shader/async_shaders.cpp +++ b/src/video_core/shader/async_shaders.cpp | |||
| @@ -43,8 +43,8 @@ void AsyncShaders::AllocateWorkers() { | |||
| 43 | // Create workers | 43 | // Create workers |
| 44 | for (std::size_t i = 0; i < num_workers; i++) { | 44 | for (std::size_t i = 0; i < num_workers; i++) { |
| 45 | context_list.push_back(emu_window.CreateSharedContext()); | 45 | context_list.push_back(emu_window.CreateSharedContext()); |
| 46 | worker_threads.push_back( | 46 | worker_threads.emplace_back(&AsyncShaders::ShaderCompilerThread, this, |
| 47 | std::thread(&AsyncShaders::ShaderCompilerThread, this, context_list[i].get())); | 47 | context_list[i].get()); |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
| 50 | 50 | ||
| @@ -106,8 +106,7 @@ std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() { | |||
| 106 | std::vector<Result> results; | 106 | std::vector<Result> results; |
| 107 | { | 107 | { |
| 108 | std::unique_lock lock{completed_mutex}; | 108 | std::unique_lock lock{completed_mutex}; |
| 109 | results.assign(std::make_move_iterator(finished_work.begin()), | 109 | results = std::move(finished_work); |
| 110 | std::make_move_iterator(finished_work.end())); | ||
| 111 | finished_work.clear(); | 110 | finished_work.clear(); |
| 112 | } | 111 | } |
| 113 | return results; | 112 | return results; |
| @@ -116,11 +115,10 @@ std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() { | |||
| 116 | void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device, | 115 | void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device, |
| 117 | Tegra::Engines::ShaderType shader_type, u64 uid, | 116 | Tegra::Engines::ShaderType shader_type, u64 uid, |
| 118 | std::vector<u64> code, std::vector<u64> code_b, | 117 | std::vector<u64> code, std::vector<u64> code_b, |
| 119 | u32 main_offset, | 118 | u32 main_offset, CompilerSettings compiler_settings, |
| 120 | VideoCommon::Shader::CompilerSettings compiler_settings, | 119 | const Registry& registry, VAddr cpu_addr) { |
| 121 | const VideoCommon::Shader::Registry& registry, | 120 | std::unique_lock lock(queue_mutex); |
| 122 | VAddr cpu_addr) { | 121 | pending_queue.push({ |
| 123 | WorkerParams params{ | ||
| 124 | .backend = device.UseAssemblyShaders() ? Backend::GLASM : Backend::OpenGL, | 122 | .backend = device.UseAssemblyShaders() ? Backend::GLASM : Backend::OpenGL, |
| 125 | .device = &device, | 123 | .device = &device, |
| 126 | .shader_type = shader_type, | 124 | .shader_type = shader_type, |
| @@ -131,9 +129,7 @@ void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device, | |||
| 131 | .compiler_settings = compiler_settings, | 129 | .compiler_settings = compiler_settings, |
| 132 | .registry = registry, | 130 | .registry = registry, |
| 133 | .cpu_address = cpu_addr, | 131 | .cpu_address = cpu_addr, |
| 134 | }; | 132 | }); |
| 135 | std::unique_lock lock(queue_mutex); | ||
| 136 | pending_queue.push(std::move(params)); | ||
| 137 | cv.notify_one(); | 133 | cv.notify_one(); |
| 138 | } | 134 | } |
| 139 | 135 | ||
| @@ -145,7 +141,8 @@ void AsyncShaders::QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, | |||
| 145 | std::vector<VkDescriptorSetLayoutBinding> bindings, | 141 | std::vector<VkDescriptorSetLayoutBinding> bindings, |
| 146 | Vulkan::SPIRVProgram program, | 142 | Vulkan::SPIRVProgram program, |
| 147 | Vulkan::GraphicsPipelineCacheKey key) { | 143 | Vulkan::GraphicsPipelineCacheKey key) { |
| 148 | WorkerParams params{ | 144 | std::unique_lock lock(queue_mutex); |
| 145 | pending_queue.push({ | ||
| 149 | .backend = Backend::Vulkan, | 146 | .backend = Backend::Vulkan, |
| 150 | .pp_cache = pp_cache, | 147 | .pp_cache = pp_cache, |
| 151 | .vk_device = &device, | 148 | .vk_device = &device, |
| @@ -153,13 +150,10 @@ void AsyncShaders::QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, | |||
| 153 | .descriptor_pool = &descriptor_pool, | 150 | .descriptor_pool = &descriptor_pool, |
| 154 | .update_descriptor_queue = &update_descriptor_queue, | 151 | .update_descriptor_queue = &update_descriptor_queue, |
| 155 | .renderpass_cache = &renderpass_cache, | 152 | .renderpass_cache = &renderpass_cache, |
| 156 | .bindings = bindings, | 153 | .bindings = std::move(bindings), |
| 157 | .program = program, | 154 | .program = std::move(program), |
| 158 | .key = key, | 155 | .key = key, |
| 159 | }; | 156 | }); |
| 160 | |||
| 161 | std::unique_lock lock(queue_mutex); | ||
| 162 | pending_queue.push(std::move(params)); | ||
| 163 | cv.notify_one(); | 157 | cv.notify_one(); |
| 164 | } | 158 | } |
| 165 | 159 | ||
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/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d62b0efc2..f0338cf7a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -302,6 +302,12 @@ 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() { |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index ca35cf831..503b4f89e 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -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/config.cpp b/src/yuzu/configuration/config.cpp index 6fa842cd5..3c423a271 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -649,6 +649,8 @@ void Config::ReadDebuggingValues() { | |||
| 649 | Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool(); | 649 | Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool(); |
| 650 | Settings::values.disable_macro_jit = | 650 | Settings::values.disable_macro_jit = |
| 651 | ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); | 651 | ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); |
| 652 | Settings::values.extended_logging = | ||
| 653 | ReadSetting(QStringLiteral("extended_logging"), false).toBool(); | ||
| 652 | 654 | ||
| 653 | qt_config->endGroup(); | 655 | qt_config->endGroup(); |
| 654 | } | 656 | } |
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 2bfe2c306..027099ab7 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -41,6 +41,7 @@ void ConfigureDebug::SetConfiguration() { | |||
| 41 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); | 41 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); |
| 42 | ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | 42 | ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); |
| 43 | ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit); | 43 | ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit); |
| 44 | ui->extended_logging->setChecked(Settings::values.extended_logging); | ||
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | void ConfigureDebug::ApplyConfiguration() { | 47 | void ConfigureDebug::ApplyConfiguration() { |
| @@ -53,6 +54,7 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 53 | Settings::values.quest_flag = ui->quest_flag->isChecked(); | 54 | Settings::values.quest_flag = ui->quest_flag->isChecked(); |
| 54 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); | 55 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); |
| 55 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); | 56 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); |
| 57 | Settings::values.extended_logging = ui->extended_logging->isChecked(); | ||
| 56 | Debugger::ToggleConsole(); | 58 | Debugger::ToggleConsole(); |
| 57 | Log::Filter filter; | 59 | Log::Filter filter; |
| 58 | filter.ParseFilterString(Settings::values.log_filter); | 60 | filter.ParseFilterString(Settings::values.log_filter); |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 9d6feb9f7..6f94fe304 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -90,7 +90,7 @@ | |||
| 90 | <item> | 90 | <item> |
| 91 | <widget class="QCheckBox" name="toggle_console"> | 91 | <widget class="QCheckBox" name="toggle_console"> |
| 92 | <property name="text"> | 92 | <property name="text"> |
| 93 | <string>Show Log Console (Windows Only)</string> | 93 | <string>Show Log in Console</string> |
| 94 | </property> | 94 | </property> |
| 95 | </widget> | 95 | </widget> |
| 96 | </item> | 96 | </item> |
| @@ -103,6 +103,34 @@ | |||
| 103 | </item> | 103 | </item> |
| 104 | </layout> | 104 | </layout> |
| 105 | </item> | 105 | </item> |
| 106 | <item> | ||
| 107 | <widget class="QCheckBox" name="extended_logging"> | ||
| 108 | <property name="enabled"> | ||
| 109 | <bool>true</bool> | ||
| 110 | </property> | ||
| 111 | <property name="toolTip"> | ||
| 112 | <string>When checked, the max size of the log increases from 100 MB to 1 GB</string> | ||
| 113 | </property> | ||
| 114 | <property name="text"> | ||
| 115 | <string>Enable Extended Logging</string> | ||
| 116 | </property> | ||
| 117 | </widget> | ||
| 118 | </item> | ||
| 119 | <item> | ||
| 120 | <widget class="QLabel" name="label_3"> | ||
| 121 | <property name="font"> | ||
| 122 | <font> | ||
| 123 | <italic>true</italic> | ||
| 124 | </font> | ||
| 125 | </property> | ||
| 126 | <property name="text"> | ||
| 127 | <string>This will be reset automatically when yuzu closes.</string> | ||
| 128 | </property> | ||
| 129 | <property name="indent"> | ||
| 130 | <number>20</number> | ||
| 131 | </property> | ||
| 132 | </widget> | ||
| 133 | </item> | ||
| 106 | </layout> | 134 | </layout> |
| 107 | </widget> | 135 | </widget> |
| 108 | </item> | 136 | </item> |
| @@ -115,7 +143,7 @@ | |||
| 115 | <item> | 143 | <item> |
| 116 | <layout class="QHBoxLayout" name="horizontalLayout_4"> | 144 | <layout class="QHBoxLayout" name="horizontalLayout_4"> |
| 117 | <item> | 145 | <item> |
| 118 | <widget class="QLabel" name="label_3"> | 146 | <widget class="QLabel" name="label_4"> |
| 119 | <property name="text"> | 147 | <property name="text"> |
| 120 | <string>Arguments String</string> | 148 | <string>Arguments String</string> |
| 121 | </property> | 149 | </property> |
| @@ -140,8 +168,8 @@ | |||
| 140 | <property name="enabled"> | 168 | <property name="enabled"> |
| 141 | <bool>true</bool> | 169 | <bool>true</bool> |
| 142 | </property> | 170 | </property> |
| 143 | <property name="whatsThis"> | 171 | <property name="toolTip"> |
| 144 | <string>When checked, the graphics API enters in a slower debugging mode</string> | 172 | <string>When checked, the graphics API enters a slower debugging mode</string> |
| 145 | </property> | 173 | </property> |
| 146 | <property name="text"> | 174 | <property name="text"> |
| 147 | <string>Enable Graphics Debugging</string> | 175 | <string>Enable Graphics Debugging</string> |
| @@ -153,8 +181,8 @@ | |||
| 153 | <property name="enabled"> | 181 | <property name="enabled"> |
| 154 | <bool>true</bool> | 182 | <bool>true</bool> |
| 155 | </property> | 183 | </property> |
| 156 | <property name="whatsThis"> | 184 | <property name="toolTip"> |
| 157 | <string>When checked, it disables the macro Just In Time compiler. Enabled this makes games run slower</string> | 185 | <string>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</string> |
| 158 | </property> | 186 | </property> |
| 159 | <property name="text"> | 187 | <property name="text"> |
| 160 | <string>Disable Macro JIT</string> | 188 | <string>Disable Macro JIT</string> |
| @@ -169,7 +197,7 @@ | |||
| 169 | <property name="title"> | 197 | <property name="title"> |
| 170 | <string>Dump</string> | 198 | <string>Dump</string> |
| 171 | </property> | 199 | </property> |
| 172 | <layout class="QVBoxLayout" name="verticalLayout_6"> | 200 | <layout class="QVBoxLayout" name="verticalLayout_7"> |
| 173 | <item> | 201 | <item> |
| 174 | <widget class="QCheckBox" name="reporting_services"> | 202 | <widget class="QCheckBox" name="reporting_services"> |
| 175 | <property name="text"> | 203 | <property name="text"> |
| @@ -178,7 +206,7 @@ | |||
| 178 | </widget> | 206 | </widget> |
| 179 | </item> | 207 | </item> |
| 180 | <item> | 208 | <item> |
| 181 | <widget class="QLabel" name="label"> | 209 | <widget class="QLabel" name="label_5"> |
| 182 | <property name="font"> | 210 | <property name="font"> |
| 183 | <font> | 211 | <font> |
| 184 | <italic>true</italic> | 212 | <italic>true</italic> |
| @@ -200,7 +228,7 @@ | |||
| 200 | <property name="title"> | 228 | <property name="title"> |
| 201 | <string>Advanced</string> | 229 | <string>Advanced</string> |
| 202 | </property> | 230 | </property> |
| 203 | <layout class="QVBoxLayout" name="verticalLayout_7"> | 231 | <layout class="QVBoxLayout" name="verticalLayout_8"> |
| 204 | <item> | 232 | <item> |
| 205 | <widget class="QCheckBox" name="quest_flag"> | 233 | <widget class="QCheckBox" name="quest_flag"> |
| 206 | <property name="text"> | 234 | <property name="text"> |
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 81464dd37..8eac3bd9d 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include "common/common_paths.h" | 17 | #include "common/common_paths.h" |
| 18 | #include "common/file_util.h" | 18 | #include "common/file_util.h" |
| 19 | #include "core/core.h" | ||
| 19 | #include "core/file_sys/control_metadata.h" | 20 | #include "core/file_sys/control_metadata.h" |
| 20 | #include "core/file_sys/patch_manager.h" | 21 | #include "core/file_sys/patch_manager.h" |
| 21 | #include "core/file_sys/xts_archive.h" | 22 | #include "core/file_sys/xts_archive.h" |
| @@ -89,9 +90,11 @@ void ConfigurePerGame::LoadConfiguration() { | |||
| 89 | ui->display_title_id->setText( | 90 | ui->display_title_id->setText( |
| 90 | QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper()); | 91 | QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper()); |
| 91 | 92 | ||
| 92 | FileSys::PatchManager pm{title_id}; | 93 | auto& system = Core::System::GetInstance(); |
| 94 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), | ||
| 95 | system.GetContentProvider()}; | ||
| 93 | const auto control = pm.GetControlMetadata(); | 96 | const auto control = pm.GetControlMetadata(); |
| 94 | const auto loader = Loader::GetLoader(file); | 97 | const auto loader = Loader::GetLoader(system, file); |
| 95 | 98 | ||
| 96 | if (control.first != nullptr) { | 99 | if (control.first != nullptr) { |
| 97 | ui->display_version->setText(QString::fromStdString(control.first->GetVersionString())); | 100 | ui->display_version->setText(QString::fromStdString(control.first->GetVersionString())); |
diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 793fd8975..cdeeec01c 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp | |||
| @@ -112,8 +112,10 @@ void ConfigurePerGameAddons::LoadConfiguration() { | |||
| 112 | return; | 112 | return; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | FileSys::PatchManager pm{title_id}; | 115 | auto& system = Core::System::GetInstance(); |
| 116 | const auto loader = Loader::GetLoader(file); | 116 | const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
| 117 | system.GetContentProvider()}; | ||
| 118 | const auto loader = Loader::GetLoader(system, file); | ||
| 117 | 119 | ||
| 118 | FileSys::VirtualFile update_raw; | 120 | FileSys::VirtualFile update_raw; |
| 119 | loader->ReadUpdateRaw(update_raw); | 121 | loader->ReadUpdateRaw(update_raw); |
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index e0ce45fd9..23643aea2 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp | |||
| @@ -235,12 +235,11 @@ GameListWorker::~GameListWorker() = default; | |||
| 235 | void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { | 235 | void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { |
| 236 | using namespace FileSys; | 236 | using namespace FileSys; |
| 237 | 237 | ||
| 238 | const auto& cache = | 238 | auto& system = Core::System::GetInstance(); |
| 239 | dynamic_cast<ContentProviderUnion&>(Core::System::GetInstance().GetContentProvider()); | 239 | const auto& cache = dynamic_cast<ContentProviderUnion&>(system.GetContentProvider()); |
| 240 | 240 | ||
| 241 | std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> installed_games; | 241 | auto installed_games = cache.ListEntriesFilterOrigin(std::nullopt, TitleType::Application, |
| 242 | installed_games = cache.ListEntriesFilterOrigin(std::nullopt, TitleType::Application, | 242 | ContentRecordType::Program); |
| 243 | ContentRecordType::Program); | ||
| 244 | 243 | ||
| 245 | if (parent_dir->type() == static_cast<int>(GameListItemType::SdmcDir)) { | 244 | if (parent_dir->type() == static_cast<int>(GameListItemType::SdmcDir)) { |
| 246 | installed_games = cache.ListEntriesFilterOrigin( | 245 | installed_games = cache.ListEntriesFilterOrigin( |
| @@ -254,23 +253,27 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { | |||
| 254 | } | 253 | } |
| 255 | 254 | ||
| 256 | for (const auto& [slot, game] : installed_games) { | 255 | for (const auto& [slot, game] : installed_games) { |
| 257 | if (slot == ContentProviderUnionSlot::FrontendManual) | 256 | if (slot == ContentProviderUnionSlot::FrontendManual) { |
| 258 | continue; | 257 | continue; |
| 258 | } | ||
| 259 | 259 | ||
| 260 | const auto file = cache.GetEntryUnparsed(game.title_id, game.type); | 260 | const auto file = cache.GetEntryUnparsed(game.title_id, game.type); |
| 261 | std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file); | 261 | std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(system, file); |
| 262 | if (!loader) | 262 | if (!loader) { |
| 263 | continue; | 263 | continue; |
| 264 | } | ||
| 264 | 265 | ||
| 265 | std::vector<u8> icon; | 266 | std::vector<u8> icon; |
| 266 | std::string name; | 267 | std::string name; |
| 267 | u64 program_id = 0; | 268 | u64 program_id = 0; |
| 268 | loader->ReadProgramId(program_id); | 269 | loader->ReadProgramId(program_id); |
| 269 | 270 | ||
| 270 | const PatchManager patch{program_id}; | 271 | const PatchManager patch{program_id, system.GetFileSystemController(), |
| 272 | system.GetContentProvider()}; | ||
| 271 | const auto control = cache.GetEntry(game.title_id, ContentRecordType::Control); | 273 | const auto control = cache.GetEntry(game.title_id, ContentRecordType::Control); |
| 272 | if (control != nullptr) | 274 | if (control != nullptr) { |
| 273 | GetMetadataFromControlNCA(patch, *control, icon, name); | 275 | GetMetadataFromControlNCA(patch, *control, icon, name); |
| 276 | } | ||
| 274 | 277 | ||
| 275 | emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id, | 278 | emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id, |
| 276 | compatibility_list, patch), | 279 | compatibility_list, patch), |
| @@ -280,9 +283,11 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { | |||
| 280 | 283 | ||
| 281 | void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_path, | 284 | void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_path, |
| 282 | unsigned int recursion, GameListDir* parent_dir) { | 285 | unsigned int recursion, GameListDir* parent_dir) { |
| 283 | const auto callback = [this, target, recursion, | 286 | auto& system = Core::System::GetInstance(); |
| 284 | parent_dir](u64* num_entries_out, const std::string& directory, | 287 | |
| 285 | const std::string& virtual_name) -> bool { | 288 | const auto callback = [this, target, recursion, parent_dir, |
| 289 | &system](u64* num_entries_out, const std::string& directory, | ||
| 290 | const std::string& virtual_name) -> bool { | ||
| 286 | if (stop_processing) { | 291 | if (stop_processing) { |
| 287 | // Breaks the callback loop. | 292 | // Breaks the callback loop. |
| 288 | return false; | 293 | return false; |
| @@ -293,7 +298,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa | |||
| 293 | if (!is_dir && | 298 | if (!is_dir && |
| 294 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { | 299 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { |
| 295 | const auto file = vfs->OpenFile(physical_name, FileSys::Mode::Read); | 300 | const auto file = vfs->OpenFile(physical_name, FileSys::Mode::Read); |
| 296 | auto loader = Loader::GetLoader(file); | 301 | auto loader = Loader::GetLoader(system, file); |
| 297 | if (!loader) { | 302 | if (!loader) { |
| 298 | return true; | 303 | return true; |
| 299 | } | 304 | } |
| @@ -331,7 +336,8 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa | |||
| 331 | std::string name = " "; | 336 | std::string name = " "; |
| 332 | [[maybe_unused]] const auto res3 = loader->ReadTitle(name); | 337 | [[maybe_unused]] const auto res3 = loader->ReadTitle(name); |
| 333 | 338 | ||
| 334 | const FileSys::PatchManager patch{program_id}; | 339 | const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), |
| 340 | system.GetContentProvider()}; | ||
| 335 | 341 | ||
| 336 | emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id, | 342 | emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id, |
| 337 | compatibility_list, patch), | 343 | compatibility_list, patch), |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9dabd8889..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}; |
| 1093 | 1094 | ||
| 1095 | last_filename_booted = filename; | ||
| 1096 | |||
| 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(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 |
| @@ -1144,9 +1153,13 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1144 | 1153 | ||
| 1145 | std::string title_name; | 1154 | std::string title_name; |
| 1146 | std::string title_version; | 1155 | std::string title_version; |
| 1147 | const auto res = Core::System::GetInstance().GetGameName(title_name); | 1156 | const auto res = system.GetGameName(title_name); |
| 1148 | 1157 | ||
| 1149 | const auto metadata = FileSys::PatchManager(title_id).GetControlMetadata(); | 1158 | const auto metadata = [&system, title_id] { |
| 1159 | const FileSys::PatchManager pm(title_id, system.GetFileSystemController(), | ||
| 1160 | system.GetContentProvider()); | ||
| 1161 | return pm.GetControlMetadata(); | ||
| 1162 | }(); | ||
| 1150 | if (metadata.first != nullptr) { | 1163 | if (metadata.first != nullptr) { |
| 1151 | title_version = metadata.first->GetVersionString(); | 1164 | title_version = metadata.first->GetVersionString(); |
| 1152 | title_name = metadata.first->GetApplicationName(); | 1165 | title_name = metadata.first->GetApplicationName(); |
| @@ -1157,7 +1170,7 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1157 | LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); | 1170 | LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); |
| 1158 | UpdateWindowTitle(title_name, title_version); | 1171 | UpdateWindowTitle(title_name, title_version); |
| 1159 | 1172 | ||
| 1160 | loading_screen->Prepare(Core::System::GetInstance().GetAppLoader()); | 1173 | loading_screen->Prepare(system.GetAppLoader()); |
| 1161 | loading_screen->show(); | 1174 | loading_screen->show(); |
| 1162 | 1175 | ||
| 1163 | emulation_running = true; | 1176 | emulation_running = true; |
| @@ -1276,16 +1289,18 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | |||
| 1276 | const std::string& game_path) { | 1289 | const std::string& game_path) { |
| 1277 | std::string path; | 1290 | std::string path; |
| 1278 | QString open_target; | 1291 | QString open_target; |
| 1292 | auto& system = Core::System::GetInstance(); | ||
| 1279 | 1293 | ||
| 1280 | const auto [user_save_size, device_save_size] = [this, &program_id, &game_path] { | 1294 | const auto [user_save_size, device_save_size] = [this, &game_path, &program_id, &system] { |
| 1281 | FileSys::PatchManager pm{program_id}; | 1295 | const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), |
| 1296 | system.GetContentProvider()}; | ||
| 1282 | const auto control = pm.GetControlMetadata().first; | 1297 | const auto control = pm.GetControlMetadata().first; |
| 1283 | if (control != nullptr) { | 1298 | if (control != nullptr) { |
| 1284 | return std::make_pair(control->GetDefaultNormalSaveSize(), | 1299 | return std::make_pair(control->GetDefaultNormalSaveSize(), |
| 1285 | control->GetDeviceSaveDataSize()); | 1300 | control->GetDeviceSaveDataSize()); |
| 1286 | } else { | 1301 | } else { |
| 1287 | const auto file = Core::GetGameFileFromPath(vfs, game_path); | 1302 | const auto file = Core::GetGameFileFromPath(vfs, game_path); |
| 1288 | const auto loader = Loader::GetLoader(file); | 1303 | const auto loader = Loader::GetLoader(system, file); |
| 1289 | 1304 | ||
| 1290 | FileSys::NACP nacp{}; | 1305 | FileSys::NACP nacp{}; |
| 1291 | loader->ReadControlData(nacp); | 1306 | loader->ReadControlData(nacp); |
| @@ -1612,7 +1627,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 1612 | "cancelled the operation.")); | 1627 | "cancelled the operation.")); |
| 1613 | }; | 1628 | }; |
| 1614 | 1629 | ||
| 1615 | const auto loader = Loader::GetLoader(vfs->OpenFile(game_path, FileSys::Mode::Read)); | 1630 | auto& system = Core::System::GetInstance(); |
| 1631 | const auto loader = Loader::GetLoader(system, vfs->OpenFile(game_path, FileSys::Mode::Read)); | ||
| 1616 | if (loader == nullptr) { | 1632 | if (loader == nullptr) { |
| 1617 | failed(); | 1633 | failed(); |
| 1618 | return; | 1634 | return; |
| @@ -1624,7 +1640,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 1624 | return; | 1640 | return; |
| 1625 | } | 1641 | } |
| 1626 | 1642 | ||
| 1627 | const auto& installed = Core::System::GetInstance().GetContentProvider(); | 1643 | const auto& installed = system.GetContentProvider(); |
| 1628 | const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id); | 1644 | const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id); |
| 1629 | 1645 | ||
| 1630 | if (!romfs_title_id) { | 1646 | if (!romfs_title_id) { |
| @@ -1639,7 +1655,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 1639 | 1655 | ||
| 1640 | if (*romfs_title_id == program_id) { | 1656 | if (*romfs_title_id == program_id) { |
| 1641 | const u64 ivfc_offset = loader->ReadRomFSIVFCOffset(); | 1657 | const u64 ivfc_offset = loader->ReadRomFSIVFCOffset(); |
| 1642 | FileSys::PatchManager pm{program_id}; | 1658 | const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), installed}; |
| 1643 | romfs = pm.PatchRomFS(file, ivfc_offset, FileSys::ContentRecordType::Program); | 1659 | romfs = pm.PatchRomFS(file, ivfc_offset, FileSys::ContentRecordType::Program); |
| 1644 | } else { | 1660 | } else { |
| 1645 | romfs = installed.GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS(); | 1661 | romfs = installed.GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS(); |
| @@ -1756,7 +1772,8 @@ void GMainWindow::OnGameListShowList(bool show) { | |||
| 1756 | void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { | 1772 | void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { |
| 1757 | u64 title_id{}; | 1773 | u64 title_id{}; |
| 1758 | const auto v_file = Core::GetGameFileFromPath(vfs, file); | 1774 | const auto v_file = Core::GetGameFileFromPath(vfs, file); |
| 1759 | const auto loader = Loader::GetLoader(v_file); | 1775 | const auto loader = Loader::GetLoader(Core::System::GetInstance(), v_file); |
| 1776 | |||
| 1760 | if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { | 1777 | if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { |
| 1761 | QMessageBox::information(this, tr("Properties"), | 1778 | QMessageBox::information(this, tr("Properties"), |
| 1762 | tr("The game properties could not be loaded.")); | 1779 | tr("The game properties could not be loaded.")); |
| @@ -2128,6 +2145,11 @@ void GMainWindow::OnLoadComplete() { | |||
| 2128 | loading_screen->OnLoadComplete(); | 2145 | loading_screen->OnLoadComplete(); |
| 2129 | } | 2146 | } |
| 2130 | 2147 | ||
| 2148 | void GMainWindow::OnExecuteProgram(std::size_t program_index) { | ||
| 2149 | ShutdownGame(); | ||
| 2150 | BootGame(last_filename_booted, program_index); | ||
| 2151 | } | ||
| 2152 | |||
| 2131 | void GMainWindow::ErrorDisplayDisplayError(QString body) { | 2153 | void GMainWindow::ErrorDisplayDisplayError(QString body) { |
| 2132 | QMessageBox::critical(this, tr("Error Display"), body); | 2154 | QMessageBox::critical(this, tr("Error Display"), body); |
| 2133 | 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/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 3a76c785f..14a23c71b 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 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
| 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/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; |