diff options
40 files changed, 1096 insertions, 992 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..109f2f45e --- /dev/null +++ b/.git-blame-ignore-revs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | # SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | # CRLF -> LF | ||
| 5 | 90aa937593e53a5d5e070fb623b228578b0b225f | ||
diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 5893f860e..80aea4aa7 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml | |||
| @@ -40,11 +40,11 @@ jobs: | |||
| 40 | sudo apt-get install -y ccache apksigner glslang-dev glslang-tools | 40 | sudo apt-get install -y ccache apksigner glslang-dev glslang-tools |
| 41 | - name: Build | 41 | - name: Build |
| 42 | run: ./.ci/scripts/android/build.sh | 42 | run: ./.ci/scripts/android/build.sh |
| 43 | - name: Copy and sign artifacts | ||
| 44 | env: | 43 | env: |
| 45 | ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }} | 44 | ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }} |
| 46 | ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | 45 | ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} |
| 47 | ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }} | 46 | ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }} |
| 47 | - name: Copy artifacts | ||
| 48 | run: ./.ci/scripts/android/upload.sh | 48 | run: ./.ci/scripts/android/upload.sh |
| 49 | - name: Upload | 49 | - name: Upload |
| 50 | uses: actions/upload-artifact@v3 | 50 | uses: actions/upload-artifact@v3 |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index ed8fe6c3f..9ebd6c732 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | |||
| @@ -252,7 +252,7 @@ object NativeLibrary { | |||
| 252 | 252 | ||
| 253 | external fun reloadKeys(): Boolean | 253 | external fun reloadKeys(): Boolean |
| 254 | 254 | ||
| 255 | external fun initializeSystem() | 255 | external fun initializeSystem(reload: Boolean) |
| 256 | 256 | ||
| 257 | external fun defaultCPUCore(): Int | 257 | external fun defaultCPUCore(): Int |
| 258 | 258 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index ba1177426..211b7cf69 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | |||
| @@ -403,7 +403,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 403 | } else { | 403 | } else { |
| 404 | firmwarePath.deleteRecursively() | 404 | firmwarePath.deleteRecursively() |
| 405 | cacheFirmwareDir.copyRecursively(firmwarePath, true) | 405 | cacheFirmwareDir.copyRecursively(firmwarePath, true) |
| 406 | NativeLibrary.initializeSystem() | 406 | NativeLibrary.initializeSystem(true) |
| 407 | getString(R.string.save_file_imported_success) | 407 | getString(R.string.save_file_imported_success) |
| 408 | } | 408 | } |
| 409 | } catch (e: Exception) { | 409 | } catch (e: Exception) { |
| @@ -649,7 +649,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 649 | } | 649 | } |
| 650 | 650 | ||
| 651 | // Reinitialize relevant data | 651 | // Reinitialize relevant data |
| 652 | NativeLibrary.initializeSystem() | 652 | NativeLibrary.initializeSystem(true) |
| 653 | gamesViewModel.reloadGames(false) | 653 | gamesViewModel.reloadGames(false) |
| 654 | 654 | ||
| 655 | return@newInstance getString(R.string.user_data_import_success) | 655 | return@newInstance getString(R.string.user_data_import_success) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt index 79a07f7ef..5e9a1176a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt | |||
| @@ -15,7 +15,7 @@ object DirectoryInitialization { | |||
| 15 | fun start() { | 15 | fun start() { |
| 16 | if (!areDirectoriesReady) { | 16 | if (!areDirectoriesReady) { |
| 17 | initializeInternalStorage() | 17 | initializeInternalStorage() |
| 18 | NativeLibrary.initializeSystem() | 18 | NativeLibrary.initializeSystem(false) |
| 19 | areDirectoriesReady = true | 19 | areDirectoriesReady = true |
| 20 | } | 20 | } |
| 21 | } | 21 | } |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 2b1c6374d..1484cc224 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -247,11 +247,13 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) | |||
| 247 | } | 247 | } |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | void EmulationSession::InitializeSystem() { | 250 | void EmulationSession::InitializeSystem(bool reload) { |
| 251 | // Initialize logging system | 251 | if (!reload) { |
| 252 | Common::Log::Initialize(); | 252 | // Initialize logging system |
| 253 | Common::Log::SetColorConsoleBackendEnabled(true); | 253 | Common::Log::Initialize(); |
| 254 | Common::Log::Start(); | 254 | Common::Log::SetColorConsoleBackendEnabled(true); |
| 255 | Common::Log::Start(); | ||
| 256 | } | ||
| 255 | 257 | ||
| 256 | // Initialize filesystem. | 258 | // Initialize filesystem. |
| 257 | m_system.SetFilesystem(m_vfs); | 259 | m_system.SetFilesystem(m_vfs); |
| @@ -662,12 +664,15 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c | |||
| 662 | } | 664 | } |
| 663 | } | 665 | } |
| 664 | 666 | ||
| 665 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz) { | 667 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, |
| 668 | jboolean reload) { | ||
| 666 | // Create the default config.ini. | 669 | // Create the default config.ini. |
| 667 | Config{}; | 670 | Config{}; |
| 668 | // Initialize the emulated system. | 671 | // Initialize the emulated system. |
| 669 | EmulationSession::GetInstance().System().Initialize(); | 672 | if (!reload) { |
| 670 | EmulationSession::GetInstance().InitializeSystem(); | 673 | EmulationSession::GetInstance().System().Initialize(); |
| 674 | } | ||
| 675 | EmulationSession::GetInstance().InitializeSystem(reload); | ||
| 671 | } | 676 | } |
| 672 | 677 | ||
| 673 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { | 678 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { |
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index 9f915b160..6b02c44b5 100644 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h | |||
| @@ -43,7 +43,7 @@ public: | |||
| 43 | 43 | ||
| 44 | const Core::PerfStatsResults& PerfStats(); | 44 | const Core::PerfStatsResults& PerfStats(); |
| 45 | void ConfigureFilesystemProvider(const std::string& filepath); | 45 | void ConfigureFilesystemProvider(const std::string& filepath); |
| 46 | void InitializeSystem(); | 46 | void InitializeSystem(bool reload); |
| 47 | Core::SystemResultStatus InitializeEmulation(const std::string& filepath); | 47 | Core::SystemResultStatus InitializeEmulation(const std::string& filepath); |
| 48 | 48 | ||
| 49 | bool IsHandheldOnly(); | 49 | bool IsHandheldOnly(); |
diff --git a/src/audio_core/adsp/apps/opus/opus_decode_object.cpp b/src/audio_core/adsp/apps/opus/opus_decode_object.cpp index 2c16d3769..e2b9eb566 100644 --- a/src/audio_core/adsp/apps/opus/opus_decode_object.cpp +++ b/src/audio_core/adsp/apps/opus/opus_decode_object.cpp | |||
| @@ -1,107 +1,107 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "audio_core/adsp/apps/opus/opus_decode_object.h" | 4 | #include "audio_core/adsp/apps/opus/opus_decode_object.h" |
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | 6 | ||
| 7 | namespace AudioCore::ADSP::OpusDecoder { | 7 | namespace AudioCore::ADSP::OpusDecoder { |
| 8 | namespace { | 8 | namespace { |
| 9 | bool IsValidChannelCount(u32 channel_count) { | 9 | bool IsValidChannelCount(u32 channel_count) { |
| 10 | return channel_count == 1 || channel_count == 2; | 10 | return channel_count == 1 || channel_count == 2; |
| 11 | } | 11 | } |
| 12 | } // namespace | 12 | } // namespace |
| 13 | 13 | ||
| 14 | u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) { | 14 | u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) { |
| 15 | if (!IsValidChannelCount(channel_count)) { | 15 | if (!IsValidChannelCount(channel_count)) { |
| 16 | return 0; | 16 | return 0; |
| 17 | } | 17 | } |
| 18 | return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count); | 18 | return static_cast<u32>(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) { | 21 | OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) { |
| 22 | auto* new_decoder = reinterpret_cast<OpusDecodeObject*>(buffer); | 22 | auto* new_decoder = reinterpret_cast<OpusDecodeObject*>(buffer); |
| 23 | auto* comparison = reinterpret_cast<OpusDecodeObject*>(buffer2); | 23 | auto* comparison = reinterpret_cast<OpusDecodeObject*>(buffer2); |
| 24 | 24 | ||
| 25 | if (new_decoder->magic == DecodeObjectMagic) { | 25 | if (new_decoder->magic == DecodeObjectMagic) { |
| 26 | if (!new_decoder->initialized || | 26 | if (!new_decoder->initialized || |
| 27 | (new_decoder->initialized && new_decoder->self == comparison)) { | 27 | (new_decoder->initialized && new_decoder->self == comparison)) { |
| 28 | new_decoder->state_valid = true; | 28 | new_decoder->state_valid = true; |
| 29 | } | 29 | } |
| 30 | } else { | 30 | } else { |
| 31 | new_decoder->initialized = false; | 31 | new_decoder->initialized = false; |
| 32 | new_decoder->state_valid = true; | 32 | new_decoder->state_valid = true; |
| 33 | } | 33 | } |
| 34 | return *new_decoder; | 34 | return *new_decoder; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | s32 OpusDecodeObject::InitializeDecoder(u32 sample_rate, u32 channel_count) { | 37 | s32 OpusDecodeObject::InitializeDecoder(u32 sample_rate, u32 channel_count) { |
| 38 | if (!state_valid) { | 38 | if (!state_valid) { |
| 39 | return OPUS_INVALID_STATE; | 39 | return OPUS_INVALID_STATE; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | if (initialized) { | 42 | if (initialized) { |
| 43 | return OPUS_OK; | 43 | return OPUS_OK; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | // Unfortunately libopus does not expose the OpusDecoder struct publicly, so we can't include | 46 | // Unfortunately libopus does not expose the OpusDecoder struct publicly, so we can't include |
| 47 | // it in this class. Nintendo does not allocate memory, which is why we have a workbuffer | 47 | // it in this class. Nintendo does not allocate memory, which is why we have a workbuffer |
| 48 | // provided. | 48 | // provided. |
| 49 | // We could use _create and have libopus allocate it for us, but then we have to separately | 49 | // We could use _create and have libopus allocate it for us, but then we have to separately |
| 50 | // track which decoder is being used between this and multistream in order to call the correct | 50 | // track which decoder is being used between this and multistream in order to call the correct |
| 51 | // destroy from the host side. | 51 | // destroy from the host side. |
| 52 | // This is a bit cringe, but is safe as these objects are only ever initialized inside the given | 52 | // This is a bit cringe, but is safe as these objects are only ever initialized inside the given |
| 53 | // workbuffer, and GetWorkBufferSize will guarantee there's enough space to follow. | 53 | // workbuffer, and GetWorkBufferSize will guarantee there's enough space to follow. |
| 54 | decoder = (LibOpusDecoder*)(this + 1); | 54 | decoder = (LibOpusDecoder*)(this + 1); |
| 55 | s32 ret = opus_decoder_init(decoder, sample_rate, channel_count); | 55 | s32 ret = opus_decoder_init(decoder, sample_rate, channel_count); |
| 56 | if (ret == OPUS_OK) { | 56 | if (ret == OPUS_OK) { |
| 57 | magic = DecodeObjectMagic; | 57 | magic = DecodeObjectMagic; |
| 58 | initialized = true; | 58 | initialized = true; |
| 59 | state_valid = true; | 59 | state_valid = true; |
| 60 | self = this; | 60 | self = this; |
| 61 | final_range = 0; | 61 | final_range = 0; |
| 62 | } | 62 | } |
| 63 | return ret; | 63 | return ret; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | s32 OpusDecodeObject::Shutdown() { | 66 | s32 OpusDecodeObject::Shutdown() { |
| 67 | if (!state_valid) { | 67 | if (!state_valid) { |
| 68 | return OPUS_INVALID_STATE; | 68 | return OPUS_INVALID_STATE; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | if (initialized) { | 71 | if (initialized) { |
| 72 | magic = 0x0; | 72 | magic = 0x0; |
| 73 | initialized = false; | 73 | initialized = false; |
| 74 | state_valid = false; | 74 | state_valid = false; |
| 75 | self = nullptr; | 75 | self = nullptr; |
| 76 | final_range = 0; | 76 | final_range = 0; |
| 77 | decoder = nullptr; | 77 | decoder = nullptr; |
| 78 | } | 78 | } |
| 79 | return OPUS_OK; | 79 | return OPUS_OK; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | s32 OpusDecodeObject::ResetDecoder() { | 82 | s32 OpusDecodeObject::ResetDecoder() { |
| 83 | return opus_decoder_ctl(decoder, OPUS_RESET_STATE); | 83 | return opus_decoder_ctl(decoder, OPUS_RESET_STATE); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | s32 OpusDecodeObject::Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, | 86 | s32 OpusDecodeObject::Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, |
| 87 | u64 input_data, u64 input_data_size) { | 87 | u64 input_data, u64 input_data_size) { |
| 88 | ASSERT(initialized); | 88 | ASSERT(initialized); |
| 89 | out_sample_count = 0; | 89 | out_sample_count = 0; |
| 90 | 90 | ||
| 91 | if (!state_valid) { | 91 | if (!state_valid) { |
| 92 | return OPUS_INVALID_STATE; | 92 | return OPUS_INVALID_STATE; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | auto ret_code_or_samples = opus_decode( | 95 | auto ret_code_or_samples = opus_decode( |
| 96 | decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size), | 96 | decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size), |
| 97 | reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0); | 97 | reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0); |
| 98 | 98 | ||
| 99 | if (ret_code_or_samples < OPUS_OK) { | 99 | if (ret_code_or_samples < OPUS_OK) { |
| 100 | return ret_code_or_samples; | 100 | return ret_code_or_samples; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | out_sample_count = ret_code_or_samples; | 103 | out_sample_count = ret_code_or_samples; |
| 104 | return opus_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); | 104 | return opus_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | } // namespace AudioCore::ADSP::OpusDecoder | 107 | } // namespace AudioCore::ADSP::OpusDecoder |
diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.cpp b/src/audio_core/adsp/apps/opus/opus_decoder.cpp index 2084de128..75f0fb9ad 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.cpp +++ b/src/audio_core/adsp/apps/opus/opus_decoder.cpp | |||
| @@ -30,9 +30,9 @@ bool IsValidMultiStreamChannelCount(u32 channel_count) { | |||
| 30 | return channel_count <= OpusStreamCountMax; | 30 | return channel_count <= OpusStreamCountMax; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 sterero_stream_count) { | 33 | bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 stereo_stream_count) { |
| 34 | return IsValidMultiStreamChannelCount(total_stream_count) && total_stream_count > 0 && | 34 | return IsValidMultiStreamChannelCount(total_stream_count) && total_stream_count > 0 && |
| 35 | sterero_stream_count > 0 && sterero_stream_count <= total_stream_count; | 35 | stereo_stream_count >= 0 && stereo_stream_count <= total_stream_count; |
| 36 | } | 36 | } |
| 37 | } // namespace | 37 | } // namespace |
| 38 | 38 | ||
diff --git a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp b/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp index f6d362e68..7f1ed0450 100644 --- a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp +++ b/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp | |||
| @@ -1,111 +1,111 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "audio_core/adsp/apps/opus/opus_multistream_decode_object.h" | 4 | #include "audio_core/adsp/apps/opus/opus_multistream_decode_object.h" |
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | 6 | ||
| 7 | namespace AudioCore::ADSP::OpusDecoder { | 7 | namespace AudioCore::ADSP::OpusDecoder { |
| 8 | 8 | ||
| 9 | namespace { | 9 | namespace { |
| 10 | bool IsValidChannelCount(u32 channel_count) { | 10 | bool IsValidChannelCount(u32 channel_count) { |
| 11 | return channel_count == 1 || channel_count == 2; | 11 | return channel_count == 1 || channel_count == 2; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) { | 14 | bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) { |
| 15 | return total_stream_count > 0 && stereo_stream_count > 0 && | 15 | return total_stream_count > 0 && stereo_stream_count > 0 && |
| 16 | stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count); | 16 | stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count); |
| 17 | } | 17 | } |
| 18 | } // namespace | 18 | } // namespace |
| 19 | 19 | ||
| 20 | u32 OpusMultiStreamDecodeObject::GetWorkBufferSize(u32 total_stream_count, | 20 | u32 OpusMultiStreamDecodeObject::GetWorkBufferSize(u32 total_stream_count, |
| 21 | u32 stereo_stream_count) { | 21 | u32 stereo_stream_count) { |
| 22 | if (IsValidStreamCounts(total_stream_count, stereo_stream_count)) { | 22 | if (IsValidStreamCounts(total_stream_count, stereo_stream_count)) { |
| 23 | return static_cast<u32>(sizeof(OpusMultiStreamDecodeObject)) + | 23 | return static_cast<u32>(sizeof(OpusMultiStreamDecodeObject)) + |
| 24 | opus_multistream_decoder_get_size(total_stream_count, stereo_stream_count); | 24 | opus_multistream_decoder_get_size(total_stream_count, stereo_stream_count); |
| 25 | } | 25 | } |
| 26 | return 0; | 26 | return 0; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | OpusMultiStreamDecodeObject& OpusMultiStreamDecodeObject::Initialize(u64 buffer, u64 buffer2) { | 29 | OpusMultiStreamDecodeObject& OpusMultiStreamDecodeObject::Initialize(u64 buffer, u64 buffer2) { |
| 30 | auto* new_decoder = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer); | 30 | auto* new_decoder = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer); |
| 31 | auto* comparison = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer2); | 31 | auto* comparison = reinterpret_cast<OpusMultiStreamDecodeObject*>(buffer2); |
| 32 | 32 | ||
| 33 | if (new_decoder->magic == DecodeMultiStreamObjectMagic) { | 33 | if (new_decoder->magic == DecodeMultiStreamObjectMagic) { |
| 34 | if (!new_decoder->initialized || | 34 | if (!new_decoder->initialized || |
| 35 | (new_decoder->initialized && new_decoder->self == comparison)) { | 35 | (new_decoder->initialized && new_decoder->self == comparison)) { |
| 36 | new_decoder->state_valid = true; | 36 | new_decoder->state_valid = true; |
| 37 | } | 37 | } |
| 38 | } else { | 38 | } else { |
| 39 | new_decoder->initialized = false; | 39 | new_decoder->initialized = false; |
| 40 | new_decoder->state_valid = true; | 40 | new_decoder->state_valid = true; |
| 41 | } | 41 | } |
| 42 | return *new_decoder; | 42 | return *new_decoder; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | s32 OpusMultiStreamDecodeObject::InitializeDecoder(u32 sample_rate, u32 total_stream_count, | 45 | s32 OpusMultiStreamDecodeObject::InitializeDecoder(u32 sample_rate, u32 total_stream_count, |
| 46 | u32 channel_count, u32 stereo_stream_count, | 46 | u32 channel_count, u32 stereo_stream_count, |
| 47 | u8* mappings) { | 47 | u8* mappings) { |
| 48 | if (!state_valid) { | 48 | if (!state_valid) { |
| 49 | return OPUS_INVALID_STATE; | 49 | return OPUS_INVALID_STATE; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | if (initialized) { | 52 | if (initialized) { |
| 53 | return OPUS_OK; | 53 | return OPUS_OK; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | // See OpusDecodeObject::InitializeDecoder for an explanation of this | 56 | // See OpusDecodeObject::InitializeDecoder for an explanation of this |
| 57 | decoder = (LibOpusMSDecoder*)(this + 1); | 57 | decoder = (LibOpusMSDecoder*)(this + 1); |
| 58 | s32 ret = opus_multistream_decoder_init(decoder, sample_rate, channel_count, total_stream_count, | 58 | s32 ret = opus_multistream_decoder_init(decoder, sample_rate, channel_count, total_stream_count, |
| 59 | stereo_stream_count, mappings); | 59 | stereo_stream_count, mappings); |
| 60 | if (ret == OPUS_OK) { | 60 | if (ret == OPUS_OK) { |
| 61 | magic = DecodeMultiStreamObjectMagic; | 61 | magic = DecodeMultiStreamObjectMagic; |
| 62 | initialized = true; | 62 | initialized = true; |
| 63 | state_valid = true; | 63 | state_valid = true; |
| 64 | self = this; | 64 | self = this; |
| 65 | final_range = 0; | 65 | final_range = 0; |
| 66 | } | 66 | } |
| 67 | return ret; | 67 | return ret; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | s32 OpusMultiStreamDecodeObject::Shutdown() { | 70 | s32 OpusMultiStreamDecodeObject::Shutdown() { |
| 71 | if (!state_valid) { | 71 | if (!state_valid) { |
| 72 | return OPUS_INVALID_STATE; | 72 | return OPUS_INVALID_STATE; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | if (initialized) { | 75 | if (initialized) { |
| 76 | magic = 0x0; | 76 | magic = 0x0; |
| 77 | initialized = false; | 77 | initialized = false; |
| 78 | state_valid = false; | 78 | state_valid = false; |
| 79 | self = nullptr; | 79 | self = nullptr; |
| 80 | final_range = 0; | 80 | final_range = 0; |
| 81 | decoder = nullptr; | 81 | decoder = nullptr; |
| 82 | } | 82 | } |
| 83 | return OPUS_OK; | 83 | return OPUS_OK; |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | s32 OpusMultiStreamDecodeObject::ResetDecoder() { | 86 | s32 OpusMultiStreamDecodeObject::ResetDecoder() { |
| 87 | return opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE); | 87 | return opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | s32 OpusMultiStreamDecodeObject::Decode(u32& out_sample_count, u64 output_data, | 90 | s32 OpusMultiStreamDecodeObject::Decode(u32& out_sample_count, u64 output_data, |
| 91 | u64 output_data_size, u64 input_data, u64 input_data_size) { | 91 | u64 output_data_size, u64 input_data, u64 input_data_size) { |
| 92 | ASSERT(initialized); | 92 | ASSERT(initialized); |
| 93 | out_sample_count = 0; | 93 | out_sample_count = 0; |
| 94 | 94 | ||
| 95 | if (!state_valid) { | 95 | if (!state_valid) { |
| 96 | return OPUS_INVALID_STATE; | 96 | return OPUS_INVALID_STATE; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | auto ret_code_or_samples = opus_multistream_decode( | 99 | auto ret_code_or_samples = opus_multistream_decode( |
| 100 | decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size), | 100 | decoder, reinterpret_cast<const u8*>(input_data), static_cast<opus_int32>(input_data_size), |
| 101 | reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0); | 101 | reinterpret_cast<opus_int16*>(output_data), static_cast<opus_int32>(output_data_size), 0); |
| 102 | 102 | ||
| 103 | if (ret_code_or_samples < OPUS_OK) { | 103 | if (ret_code_or_samples < OPUS_OK) { |
| 104 | return ret_code_or_samples; | 104 | return ret_code_or_samples; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | out_sample_count = ret_code_or_samples; | 107 | out_sample_count = ret_code_or_samples; |
| 108 | return opus_multistream_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); | 108 | return opus_multistream_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | } // namespace AudioCore::ADSP::OpusDecoder | 111 | } // namespace AudioCore::ADSP::OpusDecoder |
diff --git a/src/audio_core/opus/decoder.cpp b/src/audio_core/opus/decoder.cpp index 5b23fce14..c6fd45f47 100644 --- a/src/audio_core/opus/decoder.cpp +++ b/src/audio_core/opus/decoder.cpp | |||
| @@ -1,179 +1,179 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "audio_core/opus/decoder.h" | 4 | #include "audio_core/opus/decoder.h" |
| 5 | #include "audio_core/opus/hardware_opus.h" | 5 | #include "audio_core/opus/hardware_opus.h" |
| 6 | #include "audio_core/opus/parameters.h" | 6 | #include "audio_core/opus/parameters.h" |
| 7 | #include "common/alignment.h" | 7 | #include "common/alignment.h" |
| 8 | #include "common/swap.h" | 8 | #include "common/swap.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | 10 | ||
| 11 | namespace AudioCore::OpusDecoder { | 11 | namespace AudioCore::OpusDecoder { |
| 12 | using namespace Service::Audio; | 12 | using namespace Service::Audio; |
| 13 | namespace { | 13 | namespace { |
| 14 | OpusPacketHeader ReverseHeader(OpusPacketHeader header) { | 14 | OpusPacketHeader ReverseHeader(OpusPacketHeader header) { |
| 15 | OpusPacketHeader out; | 15 | OpusPacketHeader out; |
| 16 | out.size = Common::swap32(header.size); | 16 | out.size = Common::swap32(header.size); |
| 17 | out.final_range = Common::swap32(header.final_range); | 17 | out.final_range = Common::swap32(header.final_range); |
| 18 | return out; | 18 | return out; |
| 19 | } | 19 | } |
| 20 | } // namespace | 20 | } // namespace |
| 21 | 21 | ||
| 22 | OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_) | 22 | OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_) |
| 23 | : system{system_}, hardware_opus{hardware_opus_} {} | 23 | : system{system_}, hardware_opus{hardware_opus_} {} |
| 24 | 24 | ||
| 25 | OpusDecoder::~OpusDecoder() { | 25 | OpusDecoder::~OpusDecoder() { |
| 26 | if (decode_object_initialized) { | 26 | if (decode_object_initialized) { |
| 27 | hardware_opus.ShutdownDecodeObject(shared_buffer.get(), shared_buffer_size); | 27 | hardware_opus.ShutdownDecodeObject(shared_buffer.get(), shared_buffer_size); |
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, | 31 | Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, |
| 32 | u64 transfer_memory_size) { | 32 | u64 transfer_memory_size) { |
| 33 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; | 33 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; |
| 34 | shared_buffer_size = transfer_memory_size; | 34 | shared_buffer_size = transfer_memory_size; |
| 35 | shared_buffer = std::make_unique<u8[]>(shared_buffer_size); | 35 | shared_buffer = std::make_unique<u8[]>(shared_buffer_size); |
| 36 | shared_memory_mapped = true; | 36 | shared_memory_mapped = true; |
| 37 | 37 | ||
| 38 | buffer_size = | 38 | buffer_size = |
| 39 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16); | 39 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16); |
| 40 | 40 | ||
| 41 | out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size}; | 41 | out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size}; |
| 42 | size_t in_data_size{0x600u}; | 42 | size_t in_data_size{0x600u}; |
| 43 | in_data = {out_data.data() - in_data_size, in_data_size}; | 43 | in_data = {out_data.data() - in_data_size, in_data_size}; |
| 44 | 44 | ||
| 45 | ON_RESULT_FAILURE { | 45 | ON_RESULT_FAILURE { |
| 46 | if (shared_memory_mapped) { | 46 | if (shared_memory_mapped) { |
| 47 | shared_memory_mapped = false; | 47 | shared_memory_mapped = false; |
| 48 | ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size))); | 48 | ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size))); |
| 49 | } | 49 | } |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | R_TRY(hardware_opus.InitializeDecodeObject(params.sample_rate, params.channel_count, | 52 | R_TRY(hardware_opus.InitializeDecodeObject(params.sample_rate, params.channel_count, |
| 53 | shared_buffer.get(), shared_buffer_size)); | 53 | shared_buffer.get(), shared_buffer_size)); |
| 54 | 54 | ||
| 55 | sample_rate = params.sample_rate; | 55 | sample_rate = params.sample_rate; |
| 56 | channel_count = params.channel_count; | 56 | channel_count = params.channel_count; |
| 57 | use_large_frame_size = params.use_large_frame_size; | 57 | use_large_frame_size = params.use_large_frame_size; |
| 58 | decode_object_initialized = true; | 58 | decode_object_initialized = true; |
| 59 | R_SUCCEED(); | 59 | R_SUCCEED(); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params, | 62 | Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params, |
| 63 | Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { | 63 | Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { |
| 64 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; | 64 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; |
| 65 | shared_buffer_size = transfer_memory_size; | 65 | shared_buffer_size = transfer_memory_size; |
| 66 | shared_buffer = std::make_unique<u8[]>(shared_buffer_size); | 66 | shared_buffer = std::make_unique<u8[]>(shared_buffer_size); |
| 67 | shared_memory_mapped = true; | 67 | shared_memory_mapped = true; |
| 68 | 68 | ||
| 69 | buffer_size = | 69 | buffer_size = |
| 70 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16); | 70 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16); |
| 71 | 71 | ||
| 72 | out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size}; | 72 | out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size}; |
| 73 | size_t in_data_size{Common::AlignUp(1500ull * params.total_stream_count, 64u)}; | 73 | size_t in_data_size{Common::AlignUp(1500ull * params.total_stream_count, 64u)}; |
| 74 | in_data = {out_data.data() - in_data_size, in_data_size}; | 74 | in_data = {out_data.data() - in_data_size, in_data_size}; |
| 75 | 75 | ||
| 76 | ON_RESULT_FAILURE { | 76 | ON_RESULT_FAILURE { |
| 77 | if (shared_memory_mapped) { | 77 | if (shared_memory_mapped) { |
| 78 | shared_memory_mapped = false; | 78 | shared_memory_mapped = false; |
| 79 | ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size))); | 79 | ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size))); |
| 80 | } | 80 | } |
| 81 | }; | 81 | }; |
| 82 | 82 | ||
| 83 | R_TRY(hardware_opus.InitializeMultiStreamDecodeObject( | 83 | R_TRY(hardware_opus.InitializeMultiStreamDecodeObject( |
| 84 | params.sample_rate, params.channel_count, params.total_stream_count, | 84 | params.sample_rate, params.channel_count, params.total_stream_count, |
| 85 | params.stereo_stream_count, params.mappings.data(), shared_buffer.get(), | 85 | params.stereo_stream_count, params.mappings.data(), shared_buffer.get(), |
| 86 | shared_buffer_size)); | 86 | shared_buffer_size)); |
| 87 | 87 | ||
| 88 | sample_rate = params.sample_rate; | 88 | sample_rate = params.sample_rate; |
| 89 | channel_count = params.channel_count; | 89 | channel_count = params.channel_count; |
| 90 | total_stream_count = params.total_stream_count; | 90 | total_stream_count = params.total_stream_count; |
| 91 | stereo_stream_count = params.stereo_stream_count; | 91 | stereo_stream_count = params.stereo_stream_count; |
| 92 | use_large_frame_size = params.use_large_frame_size; | 92 | use_large_frame_size = params.use_large_frame_size; |
| 93 | decode_object_initialized = true; | 93 | decode_object_initialized = true; |
| 94 | R_SUCCEED(); | 94 | R_SUCCEED(); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | Result OpusDecoder::DecodeInterleaved(u32* out_data_size, u64* out_time_taken, | 97 | Result OpusDecoder::DecodeInterleaved(u32* out_data_size, u64* out_time_taken, |
| 98 | u32* out_sample_count, std::span<const u8> input_data, | 98 | u32* out_sample_count, std::span<const u8> input_data, |
| 99 | std::span<u8> output_data, bool reset) { | 99 | std::span<u8> output_data, bool reset) { |
| 100 | u32 out_samples; | 100 | u32 out_samples; |
| 101 | u64 time_taken{}; | 101 | u64 time_taken{}; |
| 102 | 102 | ||
| 103 | R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall); | 103 | R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall); |
| 104 | 104 | ||
| 105 | auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())}; | 105 | auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())}; |
| 106 | OpusPacketHeader header{ReverseHeader(*header_p)}; | 106 | OpusPacketHeader header{ReverseHeader(*header_p)}; |
| 107 | 107 | ||
| 108 | R_UNLESS(in_data.size_bytes() >= header.size && | 108 | R_UNLESS(in_data.size_bytes() >= header.size && |
| 109 | header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(), | 109 | header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(), |
| 110 | ResultBufferTooSmall); | 110 | ResultBufferTooSmall); |
| 111 | 111 | ||
| 112 | if (!shared_memory_mapped) { | 112 | if (!shared_memory_mapped) { |
| 113 | R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size)); | 113 | R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size)); |
| 114 | shared_memory_mapped = true; | 114 | shared_memory_mapped = true; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size); | 117 | std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size); |
| 118 | 118 | ||
| 119 | R_TRY(hardware_opus.DecodeInterleaved(out_samples, out_data.data(), out_data.size_bytes(), | 119 | R_TRY(hardware_opus.DecodeInterleaved(out_samples, out_data.data(), out_data.size_bytes(), |
| 120 | channel_count, in_data.data(), header.size, | 120 | channel_count, in_data.data(), header.size, |
| 121 | shared_buffer.get(), time_taken, reset)); | 121 | shared_buffer.get(), time_taken, reset)); |
| 122 | 122 | ||
| 123 | std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16)); | 123 | std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16)); |
| 124 | 124 | ||
| 125 | *out_data_size = header.size + sizeof(OpusPacketHeader); | 125 | *out_data_size = header.size + sizeof(OpusPacketHeader); |
| 126 | *out_sample_count = out_samples; | 126 | *out_sample_count = out_samples; |
| 127 | if (out_time_taken) { | 127 | if (out_time_taken) { |
| 128 | *out_time_taken = time_taken / 1000; | 128 | *out_time_taken = time_taken / 1000; |
| 129 | } | 129 | } |
| 130 | R_SUCCEED(); | 130 | R_SUCCEED(); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | Result OpusDecoder::SetContext([[maybe_unused]] std::span<const u8> context) { | 133 | Result OpusDecoder::SetContext([[maybe_unused]] std::span<const u8> context) { |
| 134 | R_SUCCEED_IF(shared_memory_mapped); | 134 | R_SUCCEED_IF(shared_memory_mapped); |
| 135 | shared_memory_mapped = true; | 135 | shared_memory_mapped = true; |
| 136 | R_RETURN(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size)); | 136 | R_RETURN(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size)); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken, | 139 | Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken, |
| 140 | u32* out_sample_count, | 140 | u32* out_sample_count, |
| 141 | std::span<const u8> input_data, | 141 | std::span<const u8> input_data, |
| 142 | std::span<u8> output_data, bool reset) { | 142 | std::span<u8> output_data, bool reset) { |
| 143 | u32 out_samples; | 143 | u32 out_samples; |
| 144 | u64 time_taken{}; | 144 | u64 time_taken{}; |
| 145 | 145 | ||
| 146 | R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall); | 146 | R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall); |
| 147 | 147 | ||
| 148 | auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())}; | 148 | auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())}; |
| 149 | OpusPacketHeader header{ReverseHeader(*header_p)}; | 149 | OpusPacketHeader header{ReverseHeader(*header_p)}; |
| 150 | 150 | ||
| 151 | LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}", | 151 | LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}", |
| 152 | header.size, input_data.size_bytes(), in_data.size_bytes()); | 152 | header.size, input_data.size_bytes(), in_data.size_bytes()); |
| 153 | 153 | ||
| 154 | R_UNLESS(in_data.size_bytes() >= header.size && | 154 | R_UNLESS(in_data.size_bytes() >= header.size && |
| 155 | header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(), | 155 | header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(), |
| 156 | ResultBufferTooSmall); | 156 | ResultBufferTooSmall); |
| 157 | 157 | ||
| 158 | if (!shared_memory_mapped) { | 158 | if (!shared_memory_mapped) { |
| 159 | R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size)); | 159 | R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size)); |
| 160 | shared_memory_mapped = true; | 160 | shared_memory_mapped = true; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size); | 163 | std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size); |
| 164 | 164 | ||
| 165 | R_TRY(hardware_opus.DecodeInterleavedForMultiStream( | 165 | R_TRY(hardware_opus.DecodeInterleavedForMultiStream( |
| 166 | out_samples, out_data.data(), out_data.size_bytes(), channel_count, in_data.data(), | 166 | out_samples, out_data.data(), out_data.size_bytes(), channel_count, in_data.data(), |
| 167 | header.size, shared_buffer.get(), time_taken, reset)); | 167 | header.size, shared_buffer.get(), time_taken, reset)); |
| 168 | 168 | ||
| 169 | std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16)); | 169 | std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16)); |
| 170 | 170 | ||
| 171 | *out_data_size = header.size + sizeof(OpusPacketHeader); | 171 | *out_data_size = header.size + sizeof(OpusPacketHeader); |
| 172 | *out_sample_count = out_samples; | 172 | *out_sample_count = out_samples; |
| 173 | if (out_time_taken) { | 173 | if (out_time_taken) { |
| 174 | *out_time_taken = time_taken / 1000; | 174 | *out_time_taken = time_taken / 1000; |
| 175 | } | 175 | } |
| 176 | R_SUCCEED(); | 176 | R_SUCCEED(); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | } // namespace AudioCore::OpusDecoder | 179 | } // namespace AudioCore::OpusDecoder |
diff --git a/src/audio_core/opus/decoder.h b/src/audio_core/opus/decoder.h index d08d8a4a4..fd728958a 100644 --- a/src/audio_core/opus/decoder.h +++ b/src/audio_core/opus/decoder.h | |||
| @@ -1,53 +1,53 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <span> | 6 | #include <span> |
| 7 | 7 | ||
| 8 | #include "audio_core/opus/parameters.h" | 8 | #include "audio_core/opus/parameters.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/hle/kernel/k_transfer_memory.h" | 10 | #include "core/hle/kernel/k_transfer_memory.h" |
| 11 | #include "core/hle/service/audio/errors.h" | 11 | #include "core/hle/service/audio/errors.h" |
| 12 | 12 | ||
| 13 | namespace Core { | 13 | namespace Core { |
| 14 | class System; | 14 | class System; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | namespace AudioCore::OpusDecoder { | 17 | namespace AudioCore::OpusDecoder { |
| 18 | class HardwareOpus; | 18 | class HardwareOpus; |
| 19 | 19 | ||
| 20 | class OpusDecoder { | 20 | class OpusDecoder { |
| 21 | public: | 21 | public: |
| 22 | explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_); | 22 | explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_); |
| 23 | ~OpusDecoder(); | 23 | ~OpusDecoder(); |
| 24 | 24 | ||
| 25 | Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, | 25 | Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, |
| 26 | u64 transfer_memory_size); | 26 | u64 transfer_memory_size); |
| 27 | Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory, | 27 | Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory, |
| 28 | u64 transfer_memory_size); | 28 | u64 transfer_memory_size); |
| 29 | Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count, | 29 | Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count, |
| 30 | std::span<const u8> input_data, std::span<u8> output_data, bool reset); | 30 | std::span<const u8> input_data, std::span<u8> output_data, bool reset); |
| 31 | Result SetContext([[maybe_unused]] std::span<const u8> context); | 31 | Result SetContext([[maybe_unused]] std::span<const u8> context); |
| 32 | Result DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken, | 32 | Result DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken, |
| 33 | u32* out_sample_count, std::span<const u8> input_data, | 33 | u32* out_sample_count, std::span<const u8> input_data, |
| 34 | std::span<u8> output_data, bool reset); | 34 | std::span<u8> output_data, bool reset); |
| 35 | 35 | ||
| 36 | private: | 36 | private: |
| 37 | Core::System& system; | 37 | Core::System& system; |
| 38 | HardwareOpus& hardware_opus; | 38 | HardwareOpus& hardware_opus; |
| 39 | std::unique_ptr<u8[]> shared_buffer{}; | 39 | std::unique_ptr<u8[]> shared_buffer{}; |
| 40 | u64 shared_buffer_size; | 40 | u64 shared_buffer_size; |
| 41 | std::span<u8> in_data{}; | 41 | std::span<u8> in_data{}; |
| 42 | std::span<u8> out_data{}; | 42 | std::span<u8> out_data{}; |
| 43 | u64 buffer_size{}; | 43 | u64 buffer_size{}; |
| 44 | s32 sample_rate{}; | 44 | s32 sample_rate{}; |
| 45 | s32 channel_count{}; | 45 | s32 channel_count{}; |
| 46 | bool use_large_frame_size{false}; | 46 | bool use_large_frame_size{false}; |
| 47 | s32 total_stream_count{}; | 47 | s32 total_stream_count{}; |
| 48 | s32 stereo_stream_count{}; | 48 | s32 stereo_stream_count{}; |
| 49 | bool shared_memory_mapped{false}; | 49 | bool shared_memory_mapped{false}; |
| 50 | bool decode_object_initialized{false}; | 50 | bool decode_object_initialized{false}; |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | } // namespace AudioCore::OpusDecoder | 53 | } // namespace AudioCore::OpusDecoder |
diff --git a/src/audio_core/opus/decoder_manager.cpp b/src/audio_core/opus/decoder_manager.cpp index 4a5382973..1464880a1 100644 --- a/src/audio_core/opus/decoder_manager.cpp +++ b/src/audio_core/opus/decoder_manager.cpp | |||
| @@ -1,102 +1,102 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "audio_core/adsp/apps/opus/opus_decoder.h" | 4 | #include "audio_core/adsp/apps/opus/opus_decoder.h" |
| 5 | #include "audio_core/opus/decoder_manager.h" | 5 | #include "audio_core/opus/decoder_manager.h" |
| 6 | #include "common/alignment.h" | 6 | #include "common/alignment.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | 8 | ||
| 9 | namespace AudioCore::OpusDecoder { | 9 | namespace AudioCore::OpusDecoder { |
| 10 | using namespace Service::Audio; | 10 | using namespace Service::Audio; |
| 11 | 11 | ||
| 12 | namespace { | 12 | namespace { |
| 13 | bool IsValidChannelCount(u32 channel_count) { | 13 | bool IsValidChannelCount(u32 channel_count) { |
| 14 | return channel_count == 1 || channel_count == 2; | 14 | return channel_count == 1 || channel_count == 2; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | bool IsValidMultiStreamChannelCount(u32 channel_count) { | 17 | bool IsValidMultiStreamChannelCount(u32 channel_count) { |
| 18 | return channel_count > 0 && channel_count <= OpusStreamCountMax; | 18 | return channel_count > 0 && channel_count <= OpusStreamCountMax; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | bool IsValidSampleRate(u32 sample_rate) { | 21 | bool IsValidSampleRate(u32 sample_rate) { |
| 22 | return sample_rate == 8'000 || sample_rate == 12'000 || sample_rate == 16'000 || | 22 | return sample_rate == 8'000 || sample_rate == 12'000 || sample_rate == 16'000 || |
| 23 | sample_rate == 24'000 || sample_rate == 48'000; | 23 | sample_rate == 24'000 || sample_rate == 48'000; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | bool IsValidStreamCount(u32 channel_count, u32 total_stream_count, u32 stereo_stream_count) { | 26 | bool IsValidStreamCount(u32 channel_count, u32 total_stream_count, u32 stereo_stream_count) { |
| 27 | return total_stream_count > 0 && stereo_stream_count > 0 && | 27 | return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 && |
| 28 | stereo_stream_count <= total_stream_count && | 28 | stereo_stream_count <= total_stream_count && |
| 29 | total_stream_count + stereo_stream_count <= channel_count; | 29 | total_stream_count + stereo_stream_count <= channel_count; |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | } // namespace | 32 | } // namespace |
| 33 | 33 | ||
| 34 | OpusDecoderManager::OpusDecoderManager(Core::System& system_) | 34 | OpusDecoderManager::OpusDecoderManager(Core::System& system_) |
| 35 | : system{system_}, hardware_opus{system} { | 35 | : system{system_}, hardware_opus{system} { |
| 36 | for (u32 i = 0; i < MaxChannels; i++) { | 36 | for (u32 i = 0; i < MaxChannels; i++) { |
| 37 | required_workbuffer_sizes[i] = hardware_opus.GetWorkBufferSize(1 + i); | 37 | required_workbuffer_sizes[i] = hardware_opus.GetWorkBufferSize(1 + i); |
| 38 | } | 38 | } |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) { | 41 | Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) { |
| 42 | OpusParametersEx ex{ | 42 | OpusParametersEx ex{ |
| 43 | .sample_rate = params.sample_rate, | 43 | .sample_rate = params.sample_rate, |
| 44 | .channel_count = params.channel_count, | 44 | .channel_count = params.channel_count, |
| 45 | .use_large_frame_size = false, | 45 | .use_large_frame_size = false, |
| 46 | }; | 46 | }; |
| 47 | R_RETURN(GetWorkBufferSizeExEx(ex, out_size)); | 47 | R_RETURN(GetWorkBufferSizeExEx(ex, out_size)); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) { | 50 | Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) { |
| 51 | R_RETURN(GetWorkBufferSizeExEx(params, out_size)); | 51 | R_RETURN(GetWorkBufferSizeExEx(params, out_size)); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) { | 54 | Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) { |
| 55 | R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount); | 55 | R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount); |
| 56 | R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); | 56 | R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); |
| 57 | 57 | ||
| 58 | auto work_buffer_size{required_workbuffer_sizes[params.channel_count - 1]}; | 58 | auto work_buffer_size{required_workbuffer_sizes[params.channel_count - 1]}; |
| 59 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; | 59 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; |
| 60 | work_buffer_size += | 60 | work_buffer_size += |
| 61 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64); | 61 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64); |
| 62 | out_size = work_buffer_size + 0x600; | 62 | out_size = work_buffer_size + 0x600; |
| 63 | R_SUCCEED(); | 63 | R_SUCCEED(); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, | 66 | Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, |
| 67 | u64& out_size) { | 67 | u64& out_size) { |
| 68 | OpusMultiStreamParametersEx ex{ | 68 | OpusMultiStreamParametersEx ex{ |
| 69 | .sample_rate = params.sample_rate, | 69 | .sample_rate = params.sample_rate, |
| 70 | .channel_count = params.channel_count, | 70 | .channel_count = params.channel_count, |
| 71 | .total_stream_count = params.total_stream_count, | 71 | .total_stream_count = params.total_stream_count, |
| 72 | .stereo_stream_count = params.stereo_stream_count, | 72 | .stereo_stream_count = params.stereo_stream_count, |
| 73 | .use_large_frame_size = false, | 73 | .use_large_frame_size = false, |
| 74 | .mappings = {}, | 74 | .mappings = {}, |
| 75 | }; | 75 | }; |
| 76 | R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size)); | 76 | R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size)); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, | 79 | Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, |
| 80 | u64& out_size) { | 80 | u64& out_size) { |
| 81 | R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size)); | 81 | R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size)); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, | 84 | Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, |
| 85 | u64& out_size) { | 85 | u64& out_size) { |
| 86 | R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount); | 86 | R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount); |
| 87 | R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); | 87 | R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); |
| 88 | R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count, | 88 | R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count, |
| 89 | params.stereo_stream_count), | 89 | params.stereo_stream_count), |
| 90 | ResultInvalidOpusSampleRate); | 90 | ResultInvalidOpusSampleRate); |
| 91 | 91 | ||
| 92 | auto work_buffer_size{hardware_opus.GetWorkBufferSizeForMultiStream( | 92 | auto work_buffer_size{hardware_opus.GetWorkBufferSizeForMultiStream( |
| 93 | params.total_stream_count, params.stereo_stream_count)}; | 93 | params.total_stream_count, params.stereo_stream_count)}; |
| 94 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; | 94 | auto frame_size{params.use_large_frame_size ? 5760 : 1920}; |
| 95 | work_buffer_size += Common::AlignUp(1500 * params.total_stream_count, 64); | 95 | work_buffer_size += Common::AlignUp(1500 * params.total_stream_count, 64); |
| 96 | work_buffer_size += | 96 | work_buffer_size += |
| 97 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64); | 97 | Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 64); |
| 98 | out_size = work_buffer_size; | 98 | out_size = work_buffer_size; |
| 99 | R_SUCCEED(); | 99 | R_SUCCEED(); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | } // namespace AudioCore::OpusDecoder | 102 | } // namespace AudioCore::OpusDecoder |
diff --git a/src/audio_core/opus/decoder_manager.h b/src/audio_core/opus/decoder_manager.h index 466e1967b..70ebc4bab 100644 --- a/src/audio_core/opus/decoder_manager.h +++ b/src/audio_core/opus/decoder_manager.h | |||
| @@ -1,38 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "audio_core/opus/hardware_opus.h" | 6 | #include "audio_core/opus/hardware_opus.h" |
| 7 | #include "audio_core/opus/parameters.h" | 7 | #include "audio_core/opus/parameters.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/hle/service/audio/errors.h" | 9 | #include "core/hle/service/audio/errors.h" |
| 10 | 10 | ||
| 11 | namespace Core { | 11 | namespace Core { |
| 12 | class System; | 12 | class System; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | namespace AudioCore::OpusDecoder { | 15 | namespace AudioCore::OpusDecoder { |
| 16 | 16 | ||
| 17 | class OpusDecoderManager { | 17 | class OpusDecoderManager { |
| 18 | public: | 18 | public: |
| 19 | OpusDecoderManager(Core::System& system); | 19 | OpusDecoderManager(Core::System& system); |
| 20 | 20 | ||
| 21 | HardwareOpus& GetHardwareOpus() { | 21 | HardwareOpus& GetHardwareOpus() { |
| 22 | return hardware_opus; | 22 | return hardware_opus; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | Result GetWorkBufferSize(OpusParameters& params, u64& out_size); | 25 | Result GetWorkBufferSize(OpusParameters& params, u64& out_size); |
| 26 | Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size); | 26 | Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size); |
| 27 | Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size); | 27 | Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size); |
| 28 | Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size); | 28 | Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size); |
| 29 | Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size); | 29 | Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size); |
| 30 | Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size); | 30 | Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size); |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
| 33 | Core::System& system; | 33 | Core::System& system; |
| 34 | HardwareOpus hardware_opus; | 34 | HardwareOpus hardware_opus; |
| 35 | std::array<u64, MaxChannels> required_workbuffer_sizes{}; | 35 | std::array<u64, MaxChannels> required_workbuffer_sizes{}; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | } // namespace AudioCore::OpusDecoder | 38 | } // namespace AudioCore::OpusDecoder |
diff --git a/src/audio_core/opus/hardware_opus.cpp b/src/audio_core/opus/hardware_opus.cpp index d6544dcb0..5ff71ab2d 100644 --- a/src/audio_core/opus/hardware_opus.cpp +++ b/src/audio_core/opus/hardware_opus.cpp | |||
| @@ -1,241 +1,241 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <array> | 4 | #include <array> |
| 5 | 5 | ||
| 6 | #include "audio_core/audio_core.h" | 6 | #include "audio_core/audio_core.h" |
| 7 | #include "audio_core/opus/hardware_opus.h" | 7 | #include "audio_core/opus/hardware_opus.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | 9 | ||
| 10 | namespace AudioCore::OpusDecoder { | 10 | namespace AudioCore::OpusDecoder { |
| 11 | namespace { | 11 | namespace { |
| 12 | using namespace Service::Audio; | 12 | using namespace Service::Audio; |
| 13 | 13 | ||
| 14 | static constexpr Result ResultCodeFromLibOpusErrorCode(u64 error_code) { | 14 | static constexpr Result ResultCodeFromLibOpusErrorCode(u64 error_code) { |
| 15 | s32 error{static_cast<s32>(error_code)}; | 15 | s32 error{static_cast<s32>(error_code)}; |
| 16 | ASSERT(error <= OPUS_OK); | 16 | ASSERT(error <= OPUS_OK); |
| 17 | switch (error) { | 17 | switch (error) { |
| 18 | case OPUS_ALLOC_FAIL: | 18 | case OPUS_ALLOC_FAIL: |
| 19 | R_THROW(ResultLibOpusAllocFail); | 19 | R_THROW(ResultLibOpusAllocFail); |
| 20 | case OPUS_INVALID_STATE: | 20 | case OPUS_INVALID_STATE: |
| 21 | R_THROW(ResultLibOpusInvalidState); | 21 | R_THROW(ResultLibOpusInvalidState); |
| 22 | case OPUS_UNIMPLEMENTED: | 22 | case OPUS_UNIMPLEMENTED: |
| 23 | R_THROW(ResultLibOpusUnimplemented); | 23 | R_THROW(ResultLibOpusUnimplemented); |
| 24 | case OPUS_INVALID_PACKET: | 24 | case OPUS_INVALID_PACKET: |
| 25 | R_THROW(ResultLibOpusInvalidPacket); | 25 | R_THROW(ResultLibOpusInvalidPacket); |
| 26 | case OPUS_INTERNAL_ERROR: | 26 | case OPUS_INTERNAL_ERROR: |
| 27 | R_THROW(ResultLibOpusInternalError); | 27 | R_THROW(ResultLibOpusInternalError); |
| 28 | case OPUS_BUFFER_TOO_SMALL: | 28 | case OPUS_BUFFER_TOO_SMALL: |
| 29 | R_THROW(ResultBufferTooSmall); | 29 | R_THROW(ResultBufferTooSmall); |
| 30 | case OPUS_BAD_ARG: | 30 | case OPUS_BAD_ARG: |
| 31 | R_THROW(ResultLibOpusBadArg); | 31 | R_THROW(ResultLibOpusBadArg); |
| 32 | case OPUS_OK: | 32 | case OPUS_OK: |
| 33 | R_RETURN(ResultSuccess); | 33 | R_RETURN(ResultSuccess); |
| 34 | } | 34 | } |
| 35 | UNREACHABLE(); | 35 | UNREACHABLE(); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | } // namespace | 38 | } // namespace |
| 39 | 39 | ||
| 40 | HardwareOpus::HardwareOpus(Core::System& system_) | 40 | HardwareOpus::HardwareOpus(Core::System& system_) |
| 41 | : system{system_}, opus_decoder{system.AudioCore().ADSP().OpusDecoder()} { | 41 | : system{system_}, opus_decoder{system.AudioCore().ADSP().OpusDecoder()} { |
| 42 | opus_decoder.SetSharedMemory(shared_memory); | 42 | opus_decoder.SetSharedMemory(shared_memory); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | u64 HardwareOpus::GetWorkBufferSize(u32 channel) { | 45 | u64 HardwareOpus::GetWorkBufferSize(u32 channel) { |
| 46 | if (!opus_decoder.IsRunning()) { | 46 | if (!opus_decoder.IsRunning()) { |
| 47 | return 0; | 47 | return 0; |
| 48 | } | 48 | } |
| 49 | std::scoped_lock l{mutex}; | 49 | std::scoped_lock l{mutex}; |
| 50 | shared_memory.host_send_data[0] = channel; | 50 | shared_memory.host_send_data[0] = channel; |
| 51 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::GetWorkBufferSize); | 51 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::GetWorkBufferSize); |
| 52 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 52 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 53 | if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeOK) { | 53 | if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeOK) { |
| 54 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 54 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 55 | ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg); | 55 | ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg); |
| 56 | return 0; | 56 | return 0; |
| 57 | } | 57 | } |
| 58 | return shared_memory.dsp_return_data[0]; | 58 | return shared_memory.dsp_return_data[0]; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { | 61 | u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { |
| 62 | std::scoped_lock l{mutex}; | 62 | std::scoped_lock l{mutex}; |
| 63 | shared_memory.host_send_data[0] = total_stream_count; | 63 | shared_memory.host_send_data[0] = total_stream_count; |
| 64 | shared_memory.host_send_data[1] = stereo_stream_count; | 64 | shared_memory.host_send_data[1] = stereo_stream_count; |
| 65 | opus_decoder.Send(ADSP::Direction::DSP, | 65 | opus_decoder.Send(ADSP::Direction::DSP, |
| 66 | ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStream); | 66 | ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStream); |
| 67 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 67 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 68 | if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK) { | 68 | if (msg != ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK) { |
| 69 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 69 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 70 | ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg); | 70 | ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg); |
| 71 | return 0; | 71 | return 0; |
| 72 | } | 72 | } |
| 73 | return shared_memory.dsp_return_data[0]; | 73 | return shared_memory.dsp_return_data[0]; |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, | 76 | Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, |
| 77 | u64 buffer_size) { | 77 | u64 buffer_size) { |
| 78 | std::scoped_lock l{mutex}; | 78 | std::scoped_lock l{mutex}; |
| 79 | shared_memory.host_send_data[0] = (u64)buffer; | 79 | shared_memory.host_send_data[0] = (u64)buffer; |
| 80 | shared_memory.host_send_data[1] = buffer_size; | 80 | shared_memory.host_send_data[1] = buffer_size; |
| 81 | shared_memory.host_send_data[2] = sample_rate; | 81 | shared_memory.host_send_data[2] = sample_rate; |
| 82 | shared_memory.host_send_data[3] = channel_count; | 82 | shared_memory.host_send_data[3] = channel_count; |
| 83 | 83 | ||
| 84 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::InitializeDecodeObject); | 84 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::InitializeDecodeObject); |
| 85 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 85 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 86 | if (msg != ADSP::OpusDecoder::Message::InitializeDecodeObjectOK) { | 86 | if (msg != ADSP::OpusDecoder::Message::InitializeDecodeObjectOK) { |
| 87 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 87 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 88 | ADSP::OpusDecoder::Message::InitializeDecodeObjectOK, msg); | 88 | ADSP::OpusDecoder::Message::InitializeDecodeObjectOK, msg); |
| 89 | R_THROW(ResultInvalidOpusDSPReturnCode); | 89 | R_THROW(ResultInvalidOpusDSPReturnCode); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); | 92 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, | 95 | Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, |
| 96 | u32 total_stream_count, | 96 | u32 total_stream_count, |
| 97 | u32 stereo_stream_count, void* mappings, | 97 | u32 stereo_stream_count, void* mappings, |
| 98 | void* buffer, u64 buffer_size) { | 98 | void* buffer, u64 buffer_size) { |
| 99 | std::scoped_lock l{mutex}; | 99 | std::scoped_lock l{mutex}; |
| 100 | shared_memory.host_send_data[0] = (u64)buffer; | 100 | shared_memory.host_send_data[0] = (u64)buffer; |
| 101 | shared_memory.host_send_data[1] = buffer_size; | 101 | shared_memory.host_send_data[1] = buffer_size; |
| 102 | shared_memory.host_send_data[2] = sample_rate; | 102 | shared_memory.host_send_data[2] = sample_rate; |
| 103 | shared_memory.host_send_data[3] = channel_count; | 103 | shared_memory.host_send_data[3] = channel_count; |
| 104 | shared_memory.host_send_data[4] = total_stream_count; | 104 | shared_memory.host_send_data[4] = total_stream_count; |
| 105 | shared_memory.host_send_data[5] = stereo_stream_count; | 105 | shared_memory.host_send_data[5] = stereo_stream_count; |
| 106 | 106 | ||
| 107 | ASSERT(channel_count <= MaxChannels); | 107 | ASSERT(channel_count <= MaxChannels); |
| 108 | std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8)); | 108 | std::memcpy(shared_memory.channel_mapping.data(), mappings, channel_count * sizeof(u8)); |
| 109 | 109 | ||
| 110 | opus_decoder.Send(ADSP::Direction::DSP, | 110 | opus_decoder.Send(ADSP::Direction::DSP, |
| 111 | ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObject); | 111 | ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObject); |
| 112 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 112 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 113 | if (msg != ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK) { | 113 | if (msg != ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK) { |
| 114 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 114 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 115 | ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK, msg); | 115 | ADSP::OpusDecoder::Message::InitializeMultiStreamDecodeObjectOK, msg); |
| 116 | R_THROW(ResultInvalidOpusDSPReturnCode); | 116 | R_THROW(ResultInvalidOpusDSPReturnCode); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); | 119 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) { | 122 | Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) { |
| 123 | std::scoped_lock l{mutex}; | 123 | std::scoped_lock l{mutex}; |
| 124 | shared_memory.host_send_data[0] = (u64)buffer; | 124 | shared_memory.host_send_data[0] = (u64)buffer; |
| 125 | shared_memory.host_send_data[1] = buffer_size; | 125 | shared_memory.host_send_data[1] = buffer_size; |
| 126 | 126 | ||
| 127 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::ShutdownDecodeObject); | 127 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::ShutdownDecodeObject); |
| 128 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 128 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 129 | ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, | 129 | ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, |
| 130 | "Expected Opus shutdown code {}, got {}", | 130 | "Expected Opus shutdown code {}, got {}", |
| 131 | ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, msg); | 131 | ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, msg); |
| 132 | 132 | ||
| 133 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); | 133 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size) { | 136 | Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size) { |
| 137 | std::scoped_lock l{mutex}; | 137 | std::scoped_lock l{mutex}; |
| 138 | shared_memory.host_send_data[0] = (u64)buffer; | 138 | shared_memory.host_send_data[0] = (u64)buffer; |
| 139 | shared_memory.host_send_data[1] = buffer_size; | 139 | shared_memory.host_send_data[1] = buffer_size; |
| 140 | 140 | ||
| 141 | opus_decoder.Send(ADSP::Direction::DSP, | 141 | opus_decoder.Send(ADSP::Direction::DSP, |
| 142 | ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObject); | 142 | ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObject); |
| 143 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 143 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 144 | ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, | 144 | ASSERT_MSG(msg == ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, |
| 145 | "Expected Opus shutdown code {}, got {}", | 145 | "Expected Opus shutdown code {}, got {}", |
| 146 | ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, msg); | 146 | ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, msg); |
| 147 | 147 | ||
| 148 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); | 148 | R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data, | 151 | Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data, |
| 152 | u64 output_data_size, u32 channel_count, void* input_data, | 152 | u64 output_data_size, u32 channel_count, void* input_data, |
| 153 | u64 input_data_size, void* buffer, u64& out_time_taken, | 153 | u64 input_data_size, void* buffer, u64& out_time_taken, |
| 154 | bool reset) { | 154 | bool reset) { |
| 155 | std::scoped_lock l{mutex}; | 155 | std::scoped_lock l{mutex}; |
| 156 | shared_memory.host_send_data[0] = (u64)buffer; | 156 | shared_memory.host_send_data[0] = (u64)buffer; |
| 157 | shared_memory.host_send_data[1] = (u64)input_data; | 157 | shared_memory.host_send_data[1] = (u64)input_data; |
| 158 | shared_memory.host_send_data[2] = input_data_size; | 158 | shared_memory.host_send_data[2] = input_data_size; |
| 159 | shared_memory.host_send_data[3] = (u64)output_data; | 159 | shared_memory.host_send_data[3] = (u64)output_data; |
| 160 | shared_memory.host_send_data[4] = output_data_size; | 160 | shared_memory.host_send_data[4] = output_data_size; |
| 161 | shared_memory.host_send_data[5] = 0; | 161 | shared_memory.host_send_data[5] = 0; |
| 162 | shared_memory.host_send_data[6] = reset; | 162 | shared_memory.host_send_data[6] = reset; |
| 163 | 163 | ||
| 164 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::DecodeInterleaved); | 164 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::DecodeInterleaved); |
| 165 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 165 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 166 | if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedOK) { | 166 | if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedOK) { |
| 167 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 167 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 168 | ADSP::OpusDecoder::Message::DecodeInterleavedOK, msg); | 168 | ADSP::OpusDecoder::Message::DecodeInterleavedOK, msg); |
| 169 | R_THROW(ResultInvalidOpusDSPReturnCode); | 169 | R_THROW(ResultInvalidOpusDSPReturnCode); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])}; | 172 | auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])}; |
| 173 | if (error_code == OPUS_OK) { | 173 | if (error_code == OPUS_OK) { |
| 174 | out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]); | 174 | out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]); |
| 175 | out_time_taken = 1000 * shared_memory.dsp_return_data[2]; | 175 | out_time_taken = 1000 * shared_memory.dsp_return_data[2]; |
| 176 | } | 176 | } |
| 177 | R_RETURN(ResultCodeFromLibOpusErrorCode(error_code)); | 177 | R_RETURN(ResultCodeFromLibOpusErrorCode(error_code)); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data, | 180 | Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data, |
| 181 | u64 output_data_size, u32 channel_count, | 181 | u64 output_data_size, u32 channel_count, |
| 182 | void* input_data, u64 input_data_size, | 182 | void* input_data, u64 input_data_size, |
| 183 | void* buffer, u64& out_time_taken, | 183 | void* buffer, u64& out_time_taken, |
| 184 | bool reset) { | 184 | bool reset) { |
| 185 | std::scoped_lock l{mutex}; | 185 | std::scoped_lock l{mutex}; |
| 186 | shared_memory.host_send_data[0] = (u64)buffer; | 186 | shared_memory.host_send_data[0] = (u64)buffer; |
| 187 | shared_memory.host_send_data[1] = (u64)input_data; | 187 | shared_memory.host_send_data[1] = (u64)input_data; |
| 188 | shared_memory.host_send_data[2] = input_data_size; | 188 | shared_memory.host_send_data[2] = input_data_size; |
| 189 | shared_memory.host_send_data[3] = (u64)output_data; | 189 | shared_memory.host_send_data[3] = (u64)output_data; |
| 190 | shared_memory.host_send_data[4] = output_data_size; | 190 | shared_memory.host_send_data[4] = output_data_size; |
| 191 | shared_memory.host_send_data[5] = 0; | 191 | shared_memory.host_send_data[5] = 0; |
| 192 | shared_memory.host_send_data[6] = reset; | 192 | shared_memory.host_send_data[6] = reset; |
| 193 | 193 | ||
| 194 | opus_decoder.Send(ADSP::Direction::DSP, | 194 | opus_decoder.Send(ADSP::Direction::DSP, |
| 195 | ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStream); | 195 | ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStream); |
| 196 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 196 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 197 | if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK) { | 197 | if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK) { |
| 198 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 198 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 199 | ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK, msg); | 199 | ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK, msg); |
| 200 | R_THROW(ResultInvalidOpusDSPReturnCode); | 200 | R_THROW(ResultInvalidOpusDSPReturnCode); |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])}; | 203 | auto error_code{static_cast<s32>(shared_memory.dsp_return_data[0])}; |
| 204 | if (error_code == OPUS_OK) { | 204 | if (error_code == OPUS_OK) { |
| 205 | out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]); | 205 | out_sample_count = static_cast<u32>(shared_memory.dsp_return_data[1]); |
| 206 | out_time_taken = 1000 * shared_memory.dsp_return_data[2]; | 206 | out_time_taken = 1000 * shared_memory.dsp_return_data[2]; |
| 207 | } | 207 | } |
| 208 | R_RETURN(ResultCodeFromLibOpusErrorCode(error_code)); | 208 | R_RETURN(ResultCodeFromLibOpusErrorCode(error_code)); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) { | 211 | Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) { |
| 212 | std::scoped_lock l{mutex}; | 212 | std::scoped_lock l{mutex}; |
| 213 | shared_memory.host_send_data[0] = (u64)buffer; | 213 | shared_memory.host_send_data[0] = (u64)buffer; |
| 214 | shared_memory.host_send_data[1] = buffer_size; | 214 | shared_memory.host_send_data[1] = buffer_size; |
| 215 | 215 | ||
| 216 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::MapMemory); | 216 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::MapMemory); |
| 217 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 217 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 218 | if (msg != ADSP::OpusDecoder::Message::MapMemoryOK) { | 218 | if (msg != ADSP::OpusDecoder::Message::MapMemoryOK) { |
| 219 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 219 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 220 | ADSP::OpusDecoder::Message::MapMemoryOK, msg); | 220 | ADSP::OpusDecoder::Message::MapMemoryOK, msg); |
| 221 | R_THROW(ResultInvalidOpusDSPReturnCode); | 221 | R_THROW(ResultInvalidOpusDSPReturnCode); |
| 222 | } | 222 | } |
| 223 | R_SUCCEED(); | 223 | R_SUCCEED(); |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | Result HardwareOpus::UnmapMemory(void* buffer, u64 buffer_size) { | 226 | Result HardwareOpus::UnmapMemory(void* buffer, u64 buffer_size) { |
| 227 | std::scoped_lock l{mutex}; | 227 | std::scoped_lock l{mutex}; |
| 228 | shared_memory.host_send_data[0] = (u64)buffer; | 228 | shared_memory.host_send_data[0] = (u64)buffer; |
| 229 | shared_memory.host_send_data[1] = buffer_size; | 229 | shared_memory.host_send_data[1] = buffer_size; |
| 230 | 230 | ||
| 231 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::UnmapMemory); | 231 | opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::UnmapMemory); |
| 232 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); | 232 | auto msg = opus_decoder.Receive(ADSP::Direction::Host); |
| 233 | if (msg != ADSP::OpusDecoder::Message::UnmapMemoryOK) { | 233 | if (msg != ADSP::OpusDecoder::Message::UnmapMemoryOK) { |
| 234 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", | 234 | LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", |
| 235 | ADSP::OpusDecoder::Message::UnmapMemoryOK, msg); | 235 | ADSP::OpusDecoder::Message::UnmapMemoryOK, msg); |
| 236 | R_THROW(ResultInvalidOpusDSPReturnCode); | 236 | R_THROW(ResultInvalidOpusDSPReturnCode); |
| 237 | } | 237 | } |
| 238 | R_SUCCEED(); | 238 | R_SUCCEED(); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | } // namespace AudioCore::OpusDecoder | 241 | } // namespace AudioCore::OpusDecoder |
diff --git a/src/audio_core/opus/hardware_opus.h b/src/audio_core/opus/hardware_opus.h index 7013a6b40..b10184baa 100644 --- a/src/audio_core/opus/hardware_opus.h +++ b/src/audio_core/opus/hardware_opus.h | |||
| @@ -1,45 +1,45 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <mutex> | 6 | #include <mutex> |
| 7 | #include <opus.h> | 7 | #include <opus.h> |
| 8 | 8 | ||
| 9 | #include "audio_core/adsp/apps/opus/opus_decoder.h" | 9 | #include "audio_core/adsp/apps/opus/opus_decoder.h" |
| 10 | #include "audio_core/adsp/apps/opus/shared_memory.h" | 10 | #include "audio_core/adsp/apps/opus/shared_memory.h" |
| 11 | #include "audio_core/adsp/mailbox.h" | 11 | #include "audio_core/adsp/mailbox.h" |
| 12 | #include "core/hle/service/audio/errors.h" | 12 | #include "core/hle/service/audio/errors.h" |
| 13 | 13 | ||
| 14 | namespace AudioCore::OpusDecoder { | 14 | namespace AudioCore::OpusDecoder { |
| 15 | class HardwareOpus { | 15 | class HardwareOpus { |
| 16 | public: | 16 | public: |
| 17 | HardwareOpus(Core::System& system); | 17 | HardwareOpus(Core::System& system); |
| 18 | 18 | ||
| 19 | u64 GetWorkBufferSize(u32 channel); | 19 | u64 GetWorkBufferSize(u32 channel); |
| 20 | u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); | 20 | u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); |
| 21 | 21 | ||
| 22 | Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, | 22 | Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, |
| 23 | u64 buffer_size); | 23 | u64 buffer_size); |
| 24 | Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, | 24 | Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, |
| 25 | u32 totaL_stream_count, u32 stereo_stream_count, | 25 | u32 totaL_stream_count, u32 stereo_stream_count, |
| 26 | void* mappings, void* buffer, u64 buffer_size); | 26 | void* mappings, void* buffer, u64 buffer_size); |
| 27 | Result ShutdownDecodeObject(void* buffer, u64 buffer_size); | 27 | Result ShutdownDecodeObject(void* buffer, u64 buffer_size); |
| 28 | Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size); | 28 | Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size); |
| 29 | Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size, | 29 | Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size, |
| 30 | u32 channel_count, void* input_data, u64 input_data_size, void* buffer, | 30 | u32 channel_count, void* input_data, u64 input_data_size, void* buffer, |
| 31 | u64& out_time_taken, bool reset); | 31 | u64& out_time_taken, bool reset); |
| 32 | Result DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data, | 32 | Result DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data, |
| 33 | u64 output_data_size, u32 channel_count, | 33 | u64 output_data_size, u32 channel_count, |
| 34 | void* input_data, u64 input_data_size, void* buffer, | 34 | void* input_data, u64 input_data_size, void* buffer, |
| 35 | u64& out_time_taken, bool reset); | 35 | u64& out_time_taken, bool reset); |
| 36 | Result MapMemory(void* buffer, u64 buffer_size); | 36 | Result MapMemory(void* buffer, u64 buffer_size); |
| 37 | Result UnmapMemory(void* buffer, u64 buffer_size); | 37 | Result UnmapMemory(void* buffer, u64 buffer_size); |
| 38 | 38 | ||
| 39 | private: | 39 | private: |
| 40 | Core::System& system; | 40 | Core::System& system; |
| 41 | std::mutex mutex; | 41 | std::mutex mutex; |
| 42 | ADSP::OpusDecoder::OpusDecoder& opus_decoder; | 42 | ADSP::OpusDecoder::OpusDecoder& opus_decoder; |
| 43 | ADSP::OpusDecoder::SharedMemory shared_memory; | 43 | ADSP::OpusDecoder::SharedMemory shared_memory; |
| 44 | }; | 44 | }; |
| 45 | } // namespace AudioCore::OpusDecoder | 45 | } // namespace AudioCore::OpusDecoder |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 8e2894449..b08a71446 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -96,18 +96,7 @@ void EmulatedController::ReloadFromSettings() { | |||
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | controller.color_values = {}; | 98 | controller.color_values = {}; |
| 99 | controller.colors_state.fullkey = { | 99 | ReloadColorsFromSettings(); |
| 100 | .body = GetNpadColor(player.body_color_left), | ||
| 101 | .button = GetNpadColor(player.button_color_left), | ||
| 102 | }; | ||
| 103 | controller.colors_state.left = { | ||
| 104 | .body = GetNpadColor(player.body_color_left), | ||
| 105 | .button = GetNpadColor(player.button_color_left), | ||
| 106 | }; | ||
| 107 | controller.colors_state.right = { | ||
| 108 | .body = GetNpadColor(player.body_color_right), | ||
| 109 | .button = GetNpadColor(player.button_color_right), | ||
| 110 | }; | ||
| 111 | 100 | ||
| 112 | ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs); | 101 | ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs); |
| 113 | 102 | ||
| @@ -128,6 +117,30 @@ void EmulatedController::ReloadFromSettings() { | |||
| 128 | ReloadInput(); | 117 | ReloadInput(); |
| 129 | } | 118 | } |
| 130 | 119 | ||
| 120 | void EmulatedController::ReloadColorsFromSettings() { | ||
| 121 | const auto player_index = NpadIdTypeToIndex(npad_id_type); | ||
| 122 | const auto& player = Settings::values.players.GetValue()[player_index]; | ||
| 123 | |||
| 124 | // Avoid updating colors if overridden by physical controller | ||
| 125 | if (controller.color_values[LeftIndex].body != 0 && | ||
| 126 | controller.color_values[RightIndex].body != 0) { | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | |||
| 130 | controller.colors_state.fullkey = { | ||
| 131 | .body = GetNpadColor(player.body_color_left), | ||
| 132 | .button = GetNpadColor(player.button_color_left), | ||
| 133 | }; | ||
| 134 | controller.colors_state.left = { | ||
| 135 | .body = GetNpadColor(player.body_color_left), | ||
| 136 | .button = GetNpadColor(player.button_color_left), | ||
| 137 | }; | ||
| 138 | controller.colors_state.right = { | ||
| 139 | .body = GetNpadColor(player.body_color_right), | ||
| 140 | .button = GetNpadColor(player.button_color_right), | ||
| 141 | }; | ||
| 142 | } | ||
| 143 | |||
| 131 | void EmulatedController::LoadDevices() { | 144 | void EmulatedController::LoadDevices() { |
| 132 | // TODO(german77): Use more buttons to detect the correct device | 145 | // TODO(german77): Use more buttons to detect the correct device |
| 133 | const auto left_joycon = button_params[Settings::NativeButton::DRight]; | 146 | const auto left_joycon = button_params[Settings::NativeButton::DRight]; |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index d4500583e..ea18c2343 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -253,6 +253,9 @@ public: | |||
| 253 | /// Overrides current mapped devices with the stored configuration and reloads all input devices | 253 | /// Overrides current mapped devices with the stored configuration and reloads all input devices |
| 254 | void ReloadFromSettings(); | 254 | void ReloadFromSettings(); |
| 255 | 255 | ||
| 256 | /// Updates current colors with the ones stored in the configuration | ||
| 257 | void ReloadColorsFromSettings(); | ||
| 258 | |||
| 256 | /// Saves the current mapped configuration | 259 | /// Saves the current mapped configuration |
| 257 | void SaveCurrentConfig(); | 260 | void SaveCurrentConfig(); |
| 258 | 261 | ||
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 1b1c8190e..f21553644 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -3,11 +3,13 @@ | |||
| 3 | 3 | ||
| 4 | #include <algorithm> | 4 | #include <algorithm> |
| 5 | #include <array> | 5 | #include <array> |
| 6 | |||
| 6 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 7 | #include "common/fs/file.h" | 8 | #include "common/fs/file.h" |
| 8 | #include "common/fs/path_util.h" | 9 | #include "common/fs/path_util.h" |
| 9 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 10 | #include "common/polyfill_ranges.h" | 11 | #include "common/polyfill_ranges.h" |
| 12 | #include "common/stb.h" | ||
| 11 | #include "common/string_util.h" | 13 | #include "common/string_util.h" |
| 12 | #include "common/swap.h" | 14 | #include "common/swap.h" |
| 13 | #include "core/constants.h" | 15 | #include "core/constants.h" |
| @@ -38,9 +40,36 @@ static std::filesystem::path GetImagePath(const Common::UUID& uuid) { | |||
| 38 | fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString()); | 40 | fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString()); |
| 39 | } | 41 | } |
| 40 | 42 | ||
| 41 | static constexpr u32 SanitizeJPEGSize(std::size_t size) { | 43 | static void JPGToMemory(void* context, void* data, int len) { |
| 44 | std::vector<u8>* jpg_image = static_cast<std::vector<u8>*>(context); | ||
| 45 | unsigned char* jpg = static_cast<unsigned char*>(data); | ||
| 46 | jpg_image->insert(jpg_image->end(), jpg, jpg + len); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void SanitizeJPEGImageSize(std::vector<u8>& image) { | ||
| 42 | constexpr std::size_t max_jpeg_image_size = 0x20000; | 50 | constexpr std::size_t max_jpeg_image_size = 0x20000; |
| 43 | return static_cast<u32>(std::min(size, max_jpeg_image_size)); | 51 | constexpr int profile_dimensions = 256; |
| 52 | int original_width, original_height, color_channels; | ||
| 53 | |||
| 54 | const auto plain_image = | ||
| 55 | stbi_load_from_memory(image.data(), static_cast<int>(image.size()), &original_width, | ||
| 56 | &original_height, &color_channels, STBI_rgb); | ||
| 57 | |||
| 58 | // Resize image to match 256*256 | ||
| 59 | if (original_width != profile_dimensions || original_height != profile_dimensions) { | ||
| 60 | // Use vector instead of array to avoid overflowing the stack | ||
| 61 | std::vector<u8> out_image(profile_dimensions * profile_dimensions * STBI_rgb); | ||
| 62 | stbir_resize_uint8_srgb(plain_image, original_width, original_height, 0, out_image.data(), | ||
| 63 | profile_dimensions, profile_dimensions, 0, STBI_rgb, 0, | ||
| 64 | STBIR_FILTER_BOX); | ||
| 65 | image.clear(); | ||
| 66 | if (!stbi_write_jpg_to_func(JPGToMemory, &image, profile_dimensions, profile_dimensions, | ||
| 67 | STBI_rgb, out_image.data(), 0)) { | ||
| 68 | LOG_ERROR(Service_ACC, "Failed to resize the user provided image."); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | image.resize(std::min(image.size(), max_jpeg_image_size)); | ||
| 44 | } | 73 | } |
| 45 | 74 | ||
| 46 | class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> { | 75 | class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> { |
| @@ -339,19 +368,20 @@ protected: | |||
| 339 | LOG_WARNING(Service_ACC, | 368 | LOG_WARNING(Service_ACC, |
| 340 | "Failed to load user provided image! Falling back to built-in backup..."); | 369 | "Failed to load user provided image! Falling back to built-in backup..."); |
| 341 | ctx.WriteBuffer(Core::Constants::ACCOUNT_BACKUP_JPEG); | 370 | ctx.WriteBuffer(Core::Constants::ACCOUNT_BACKUP_JPEG); |
| 342 | rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); | 371 | rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); |
| 343 | return; | 372 | return; |
| 344 | } | 373 | } |
| 345 | 374 | ||
| 346 | const u32 size = SanitizeJPEGSize(image.GetSize()); | 375 | std::vector<u8> buffer(image.GetSize()); |
| 347 | std::vector<u8> buffer(size); | ||
| 348 | 376 | ||
| 349 | if (image.Read(buffer) != buffer.size()) { | 377 | if (image.Read(buffer) != buffer.size()) { |
| 350 | LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image."); | 378 | LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image."); |
| 351 | } | 379 | } |
| 352 | 380 | ||
| 381 | SanitizeJPEGImageSize(buffer); | ||
| 382 | |||
| 353 | ctx.WriteBuffer(buffer); | 383 | ctx.WriteBuffer(buffer); |
| 354 | rb.Push<u32>(size); | 384 | rb.Push(static_cast<u32>(buffer.size())); |
| 355 | } | 385 | } |
| 356 | 386 | ||
| 357 | void GetImageSize(HLERequestContext& ctx) { | 387 | void GetImageSize(HLERequestContext& ctx) { |
| @@ -365,10 +395,18 @@ protected: | |||
| 365 | if (!image.IsOpen()) { | 395 | if (!image.IsOpen()) { |
| 366 | LOG_WARNING(Service_ACC, | 396 | LOG_WARNING(Service_ACC, |
| 367 | "Failed to load user provided image! Falling back to built-in backup..."); | 397 | "Failed to load user provided image! Falling back to built-in backup..."); |
| 368 | rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); | 398 | rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); |
| 369 | } else { | 399 | return; |
| 370 | rb.Push(SanitizeJPEGSize(image.GetSize())); | ||
| 371 | } | 400 | } |
| 401 | |||
| 402 | std::vector<u8> buffer(image.GetSize()); | ||
| 403 | |||
| 404 | if (image.Read(buffer) != buffer.size()) { | ||
| 405 | LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image."); | ||
| 406 | } | ||
| 407 | |||
| 408 | SanitizeJPEGImageSize(buffer); | ||
| 409 | rb.Push(static_cast<u32>(buffer.size())); | ||
| 372 | } | 410 | } |
| 373 | 411 | ||
| 374 | void Store(HLERequestContext& ctx) { | 412 | void Store(HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index f02bbc450..0bf2598b7 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h | |||
| @@ -69,6 +69,30 @@ enum class AppletId : u32 { | |||
| 69 | MyPage = 0x1A, | 69 | MyPage = 0x1A, |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | enum class AppletProgramId : u64 { | ||
| 73 | QLaunch = 0x0100000000001000ull, | ||
| 74 | Auth = 0x0100000000001001ull, | ||
| 75 | Cabinet = 0x0100000000001002ull, | ||
| 76 | Controller = 0x0100000000001003ull, | ||
| 77 | DataErase = 0x0100000000001004ull, | ||
| 78 | Error = 0x0100000000001005ull, | ||
| 79 | NetConnect = 0x0100000000001006ull, | ||
| 80 | ProfileSelect = 0x0100000000001007ull, | ||
| 81 | SoftwareKeyboard = 0x0100000000001008ull, | ||
| 82 | MiiEdit = 0x0100000000001009ull, | ||
| 83 | Web = 0x010000000000100Aull, | ||
| 84 | Shop = 0x010000000000100Bull, | ||
| 85 | OverlayDisplay = 0x010000000000100Cull, | ||
| 86 | PhotoViewer = 0x010000000000100Dull, | ||
| 87 | Settings = 0x010000000000100Eull, | ||
| 88 | OfflineWeb = 0x010000000000100Full, | ||
| 89 | LoginShare = 0x0100000000001010ull, | ||
| 90 | WebAuth = 0x0100000000001011ull, | ||
| 91 | Starter = 0x0100000000001012ull, | ||
| 92 | MyPage = 0x0100000000001013ull, | ||
| 93 | MaxProgramId = 0x0100000000001FFFull, | ||
| 94 | }; | ||
| 95 | |||
| 72 | enum class LibraryAppletMode : u32 { | 96 | enum class LibraryAppletMode : u32 { |
| 73 | AllForeground = 0, | 97 | AllForeground = 0, |
| 74 | Background = 1, | 98 | Background = 1, |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 929dd5f03..1d4101be9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -1353,7 +1353,7 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) { | |||
| 1353 | void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { | 1353 | void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { |
| 1354 | IPC::RequestParser rp{ctx}; | 1354 | IPC::RequestParser rp{ctx}; |
| 1355 | struct Parameters { | 1355 | struct Parameters { |
| 1356 | bool unintended_home_button_input_protection; | 1356 | bool is_enabled; |
| 1357 | INSERT_PADDING_BYTES_NOINIT(3); | 1357 | INSERT_PADDING_BYTES_NOINIT(3); |
| 1358 | Core::HID::NpadIdType npad_id; | 1358 | Core::HID::NpadIdType npad_id; |
| 1359 | u64 applet_resource_user_id; | 1359 | u64 applet_resource_user_id; |
| @@ -1364,13 +1364,11 @@ void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { | |||
| 1364 | 1364 | ||
| 1365 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); | 1365 | auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); |
| 1366 | const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled( | 1366 | const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled( |
| 1367 | parameters.unintended_home_button_input_protection, parameters.npad_id); | 1367 | parameters.is_enabled, parameters.npad_id); |
| 1368 | 1368 | ||
| 1369 | LOG_WARNING(Service_HID, | 1369 | LOG_DEBUG(Service_HID, |
| 1370 | "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={}," | 1370 | "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}", |
| 1371 | "applet_resource_user_id={}", | 1371 | parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id); |
| 1372 | parameters.unintended_home_button_input_protection, parameters.npad_id, | ||
| 1373 | parameters.applet_resource_user_id); | ||
| 1374 | 1372 | ||
| 1375 | IPC::ResponseBuilder rb{ctx, 2}; | 1373 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1376 | rb.Push(result); | 1374 | rb.Push(result); |
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 85849d5f3..dd652ca42 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -39,6 +39,18 @@ bool IsConnectionBased(Type type) { | |||
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | template <typename T> | ||
| 43 | T GetValue(std::span<const u8> buffer) { | ||
| 44 | T t{}; | ||
| 45 | std::memcpy(&t, buffer.data(), std::min(sizeof(T), buffer.size())); | ||
| 46 | return t; | ||
| 47 | } | ||
| 48 | |||
| 49 | template <typename T> | ||
| 50 | void PutValue(std::span<u8> buffer, const T& t) { | ||
| 51 | std::memcpy(buffer.data(), &t, std::min(sizeof(T), buffer.size())); | ||
| 52 | } | ||
| 53 | |||
| 42 | } // Anonymous namespace | 54 | } // Anonymous namespace |
| 43 | 55 | ||
| 44 | void BSD::PollWork::Execute(BSD* bsd) { | 56 | void BSD::PollWork::Execute(BSD* bsd) { |
| @@ -316,22 +328,12 @@ void BSD::SetSockOpt(HLERequestContext& ctx) { | |||
| 316 | const s32 fd = rp.Pop<s32>(); | 328 | const s32 fd = rp.Pop<s32>(); |
| 317 | const u32 level = rp.Pop<u32>(); | 329 | const u32 level = rp.Pop<u32>(); |
| 318 | const OptName optname = static_cast<OptName>(rp.Pop<u32>()); | 330 | const OptName optname = static_cast<OptName>(rp.Pop<u32>()); |
| 319 | 331 | const auto optval = ctx.ReadBuffer(); | |
| 320 | const auto buffer = ctx.ReadBuffer(); | ||
| 321 | const u8* optval = buffer.empty() ? nullptr : buffer.data(); | ||
| 322 | size_t optlen = buffer.size(); | ||
| 323 | |||
| 324 | std::array<u64, 2> values; | ||
| 325 | if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) { | ||
| 326 | std::memcpy(values.data(), buffer.data(), sizeof(values)); | ||
| 327 | optlen = sizeof(values); | ||
| 328 | optval = reinterpret_cast<const u8*>(values.data()); | ||
| 329 | } | ||
| 330 | 332 | ||
| 331 | LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, | 333 | LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, |
| 332 | static_cast<u32>(optname), optlen); | 334 | static_cast<u32>(optname), optval.size()); |
| 333 | 335 | ||
| 334 | BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval)); | 336 | BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval)); |
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | void BSD::Shutdown(HLERequestContext& ctx) { | 339 | void BSD::Shutdown(HLERequestContext& ctx) { |
| @@ -521,18 +523,19 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco | |||
| 521 | 523 | ||
| 522 | std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, | 524 | std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, |
| 523 | s32 nfds, s32 timeout) { | 525 | s32 nfds, s32 timeout) { |
| 524 | if (write_buffer.size() < nfds * sizeof(PollFD)) { | 526 | if (nfds <= 0) { |
| 525 | return {-1, Errno::INVAL}; | ||
| 526 | } | ||
| 527 | |||
| 528 | if (nfds == 0) { | ||
| 529 | // When no entries are provided, -1 is returned with errno zero | 527 | // When no entries are provided, -1 is returned with errno zero |
| 530 | return {-1, Errno::SUCCESS}; | 528 | return {-1, Errno::SUCCESS}; |
| 531 | } | 529 | } |
| 530 | if (read_buffer.size() < nfds * sizeof(PollFD)) { | ||
| 531 | return {-1, Errno::INVAL}; | ||
| 532 | } | ||
| 533 | if (write_buffer.size() < nfds * sizeof(PollFD)) { | ||
| 534 | return {-1, Errno::INVAL}; | ||
| 535 | } | ||
| 532 | 536 | ||
| 533 | const size_t length = std::min(read_buffer.size(), write_buffer.size()); | ||
| 534 | std::vector<PollFD> fds(nfds); | 537 | std::vector<PollFD> fds(nfds); |
| 535 | std::memcpy(fds.data(), read_buffer.data(), length); | 538 | std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD)); |
| 536 | 539 | ||
| 537 | if (timeout >= 0) { | 540 | if (timeout >= 0) { |
| 538 | const s64 seconds = timeout / 1000; | 541 | const s64 seconds = timeout / 1000; |
| @@ -580,7 +583,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con | |||
| 580 | for (size_t i = 0; i < num; ++i) { | 583 | for (size_t i = 0; i < num; ++i) { |
| 581 | fds[i].revents = Translate(host_pollfds[i].revents); | 584 | fds[i].revents = Translate(host_pollfds[i].revents); |
| 582 | } | 585 | } |
| 583 | std::memcpy(write_buffer.data(), fds.data(), length); | 586 | std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD)); |
| 584 | 587 | ||
| 585 | return Translate(result); | 588 | return Translate(result); |
| 586 | } | 589 | } |
| @@ -608,8 +611,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) { | |||
| 608 | new_descriptor.is_connection_based = descriptor.is_connection_based; | 611 | new_descriptor.is_connection_based = descriptor.is_connection_based; |
| 609 | 612 | ||
| 610 | const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); | 613 | const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); |
| 611 | const size_t length = std::min(sizeof(guest_addr_in), write_buffer.size()); | 614 | PutValue(write_buffer, guest_addr_in); |
| 612 | std::memcpy(write_buffer.data(), &guest_addr_in, length); | ||
| 613 | 615 | ||
| 614 | return {new_fd, Errno::SUCCESS}; | 616 | return {new_fd, Errno::SUCCESS}; |
| 615 | } | 617 | } |
| @@ -619,8 +621,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) { | |||
| 619 | return Errno::BADF; | 621 | return Errno::BADF; |
| 620 | } | 622 | } |
| 621 | ASSERT(addr.size() == sizeof(SockAddrIn)); | 623 | ASSERT(addr.size() == sizeof(SockAddrIn)); |
| 622 | SockAddrIn addr_in; | 624 | auto addr_in = GetValue<SockAddrIn>(addr); |
| 623 | std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); | ||
| 624 | 625 | ||
| 625 | return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); | 626 | return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); |
| 626 | } | 627 | } |
| @@ -631,8 +632,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) { | |||
| 631 | } | 632 | } |
| 632 | 633 | ||
| 633 | UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); | 634 | UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); |
| 634 | SockAddrIn addr_in; | 635 | auto addr_in = GetValue<SockAddrIn>(addr); |
| 635 | std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); | ||
| 636 | 636 | ||
| 637 | return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); | 637 | return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); |
| 638 | } | 638 | } |
| @@ -650,7 +650,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) { | |||
| 650 | 650 | ||
| 651 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); | 651 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); |
| 652 | write_buffer.resize(sizeof(guest_addrin)); | 652 | write_buffer.resize(sizeof(guest_addrin)); |
| 653 | std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); | 653 | PutValue(write_buffer, guest_addrin); |
| 654 | return Translate(bsd_errno); | 654 | return Translate(bsd_errno); |
| 655 | } | 655 | } |
| 656 | 656 | ||
| @@ -667,7 +667,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) { | |||
| 667 | 667 | ||
| 668 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); | 668 | ASSERT(write_buffer.size() >= sizeof(guest_addrin)); |
| 669 | write_buffer.resize(sizeof(guest_addrin)); | 669 | write_buffer.resize(sizeof(guest_addrin)); |
| 670 | std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); | 670 | PutValue(write_buffer, guest_addrin); |
| 671 | return Translate(bsd_errno); | 671 | return Translate(bsd_errno); |
| 672 | } | 672 | } |
| 673 | 673 | ||
| @@ -725,7 +725,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o | |||
| 725 | optval.size() == sizeof(Errno), { return Errno::INVAL; }, | 725 | optval.size() == sizeof(Errno), { return Errno::INVAL; }, |
| 726 | "Incorrect getsockopt option size"); | 726 | "Incorrect getsockopt option size"); |
| 727 | optval.resize(sizeof(Errno)); | 727 | optval.resize(sizeof(Errno)); |
| 728 | memcpy(optval.data(), &translated_pending_err, sizeof(Errno)); | 728 | PutValue(optval, translated_pending_err); |
| 729 | } | 729 | } |
| 730 | return Translate(getsockopt_err); | 730 | return Translate(getsockopt_err); |
| 731 | } | 731 | } |
| @@ -735,7 +735,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o | |||
| 735 | } | 735 | } |
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { | 738 | Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) { |
| 739 | if (!IsFileDescriptorValid(fd)) { | 739 | if (!IsFileDescriptorValid(fd)) { |
| 740 | return Errno::BADF; | 740 | return Errno::BADF; |
| 741 | } | 741 | } |
| @@ -748,17 +748,15 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con | |||
| 748 | Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); | 748 | Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); |
| 749 | 749 | ||
| 750 | if (optname == OptName::LINGER) { | 750 | if (optname == OptName::LINGER) { |
| 751 | ASSERT(optlen == sizeof(Linger)); | 751 | ASSERT(optval.size() == sizeof(Linger)); |
| 752 | Linger linger; | 752 | auto linger = GetValue<Linger>(optval); |
| 753 | std::memcpy(&linger, optval, sizeof(linger)); | ||
| 754 | ASSERT(linger.onoff == 0 || linger.onoff == 1); | 753 | ASSERT(linger.onoff == 0 || linger.onoff == 1); |
| 755 | 754 | ||
| 756 | return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); | 755 | return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); |
| 757 | } | 756 | } |
| 758 | 757 | ||
| 759 | ASSERT(optlen == sizeof(u32)); | 758 | ASSERT(optval.size() == sizeof(u32)); |
| 760 | u32 value; | 759 | auto value = GetValue<u32>(optval); |
| 761 | std::memcpy(&value, optval, sizeof(value)); | ||
| 762 | 760 | ||
| 763 | switch (optname) { | 761 | switch (optname) { |
| 764 | case OptName::REUSEADDR: | 762 | case OptName::REUSEADDR: |
| @@ -862,7 +860,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess | |||
| 862 | } else { | 860 | } else { |
| 863 | ASSERT(addr.size() == sizeof(SockAddrIn)); | 861 | ASSERT(addr.size() == sizeof(SockAddrIn)); |
| 864 | const SockAddrIn result = Translate(addr_in); | 862 | const SockAddrIn result = Translate(addr_in); |
| 865 | std::memcpy(addr.data(), &result, sizeof(result)); | 863 | PutValue(addr, result); |
| 866 | } | 864 | } |
| 867 | } | 865 | } |
| 868 | 866 | ||
| @@ -886,8 +884,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes | |||
| 886 | Network::SockAddrIn* p_addr_in = nullptr; | 884 | Network::SockAddrIn* p_addr_in = nullptr; |
| 887 | if (!addr.empty()) { | 885 | if (!addr.empty()) { |
| 888 | ASSERT(addr.size() == sizeof(SockAddrIn)); | 886 | ASSERT(addr.size() == sizeof(SockAddrIn)); |
| 889 | SockAddrIn guest_addr_in; | 887 | auto guest_addr_in = GetValue<SockAddrIn>(addr); |
| 890 | std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in)); | ||
| 891 | addr_in = Translate(guest_addr_in); | 888 | addr_in = Translate(guest_addr_in); |
| 892 | p_addr_in = &addr_in; | 889 | p_addr_in = &addr_in; |
| 893 | } | 890 | } |
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 161f22b9b..4f69d382c 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h | |||
| @@ -163,7 +163,7 @@ private: | |||
| 163 | Errno ListenImpl(s32 fd, s32 backlog); | 163 | Errno ListenImpl(s32 fd, s32 backlog); |
| 164 | std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); | 164 | std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); |
| 165 | Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval); | 165 | Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval); |
| 166 | Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval); | 166 | Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval); |
| 167 | Errno ShutdownImpl(s32 fd, s32 how); | 167 | Errno ShutdownImpl(s32 fd, s32 how); |
| 168 | std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); | 168 | std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); |
| 169 | std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, | 169 | std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, |
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp index 65cd5aa06..4f1d5b548 100644 --- a/src/video_core/renderer_null/null_rasterizer.cpp +++ b/src/video_core/renderer_null/null_rasterizer.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/alignment.h" | 4 | #include "common/alignment.h" |
| 5 | #include "core/memory.h" | 5 | #include "core/memory.h" |
| 6 | #include "video_core/control/channel_state.h" | ||
| 6 | #include "video_core/host1x/host1x.h" | 7 | #include "video_core/host1x/host1x.h" |
| 7 | #include "video_core/memory_manager.h" | 8 | #include "video_core/memory_manager.h" |
| 8 | #include "video_core/renderer_null/null_rasterizer.h" | 9 | #include "video_core/renderer_null/null_rasterizer.h" |
| @@ -99,8 +100,14 @@ bool RasterizerNull::AccelerateDisplay(const Tegra::FramebufferConfig& config, | |||
| 99 | } | 100 | } |
| 100 | void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, | 101 | void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, |
| 101 | const VideoCore::DiskResourceLoadCallback& callback) {} | 102 | const VideoCore::DiskResourceLoadCallback& callback) {} |
| 102 | void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) {} | 103 | void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) { |
| 103 | void RasterizerNull::BindChannel(Tegra::Control::ChannelState& channel) {} | 104 | CreateChannel(channel); |
| 104 | void RasterizerNull::ReleaseChannel(s32 channel_id) {} | 105 | } |
| 106 | void RasterizerNull::BindChannel(Tegra::Control::ChannelState& channel) { | ||
| 107 | BindToChannel(channel.bind_id); | ||
| 108 | } | ||
| 109 | void RasterizerNull::ReleaseChannel(s32 channel_id) { | ||
| 110 | EraseChannel(channel_id); | ||
| 111 | } | ||
| 105 | 112 | ||
| 106 | } // namespace Null | 113 | } // namespace Null |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 3983b2eb7..c0e8431e4 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -82,7 +82,7 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | if (y_negate) { | 84 | if (y_negate) { |
| 85 | y += height; | 85 | y += conv(static_cast<f32>(regs.surface_clip.height)); |
| 86 | height = -height; | 86 | height = -height; |
| 87 | } | 87 | } |
| 88 | 88 | ||
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 74ec4f771..1589ba057 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project | 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h index 9a90512b3..3d822da7b 100644 --- a/src/yuzu/configuration/configure_camera.h +++ b/src/yuzu/configuration/configure_camera.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Text : Copyright 2022 yuzu Emulator Project | 1 | // Text : Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 3dcad2701..02e23cce6 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp | |||
| @@ -152,7 +152,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, | |||
| 152 | connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged, | 152 | connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged, |
| 153 | [this](bool is_handheld) { UpdateDockedState(is_handheld); }); | 153 | [this](bool is_handheld) { UpdateDockedState(is_handheld); }); |
| 154 | 154 | ||
| 155 | advanced = new ConfigureInputAdvanced(this); | 155 | advanced = new ConfigureInputAdvanced(hid_core, this); |
| 156 | ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); | 156 | ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); |
| 157 | ui->tabAdvanced->layout()->addWidget(advanced); | 157 | ui->tabAdvanced->layout()->addWidget(advanced); |
| 158 | 158 | ||
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 136cd3a0a..beb503dae 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project | 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index 3cfd5d439..441cea3f6 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp | |||
| @@ -4,11 +4,13 @@ | |||
| 4 | #include <QColorDialog> | 4 | #include <QColorDialog> |
| 5 | #include "common/settings.h" | 5 | #include "common/settings.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hid/emulated_controller.h" | ||
| 8 | #include "core/hid/hid_core.h" | ||
| 7 | #include "ui_configure_input_advanced.h" | 9 | #include "ui_configure_input_advanced.h" |
| 8 | #include "yuzu/configuration/configure_input_advanced.h" | 10 | #include "yuzu/configuration/configure_input_advanced.h" |
| 9 | 11 | ||
| 10 | ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) | 12 | ConfigureInputAdvanced::ConfigureInputAdvanced(Core::HID::HIDCore& hid_core_, QWidget* parent) |
| 11 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()) { | 13 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()), hid_core{hid_core_} { |
| 12 | ui->setupUi(this); | 14 | ui->setupUi(this); |
| 13 | 15 | ||
| 14 | controllers_color_buttons = {{ | 16 | controllers_color_buttons = {{ |
| @@ -123,6 +125,8 @@ void ConfigureInputAdvanced::ApplyConfiguration() { | |||
| 123 | player.button_color_left = colors[1]; | 125 | player.button_color_left = colors[1]; |
| 124 | player.body_color_right = colors[2]; | 126 | player.body_color_right = colors[2]; |
| 125 | player.button_color_right = colors[3]; | 127 | player.button_color_right = colors[3]; |
| 128 | |||
| 129 | hid_core.GetEmulatedControllerByIndex(player_idx)->ReloadColorsFromSettings(); | ||
| 126 | } | 130 | } |
| 127 | 131 | ||
| 128 | Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked(); | 132 | Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked(); |
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h index fc1230284..41f822c4a 100644 --- a/src/yuzu/configuration/configure_input_advanced.h +++ b/src/yuzu/configuration/configure_input_advanced.h | |||
| @@ -14,11 +14,15 @@ namespace Ui { | |||
| 14 | class ConfigureInputAdvanced; | 14 | class ConfigureInputAdvanced; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | namespace Core::HID { | ||
| 18 | class HIDCore; | ||
| 19 | } // namespace Core::HID | ||
| 20 | |||
| 17 | class ConfigureInputAdvanced : public QWidget { | 21 | class ConfigureInputAdvanced : public QWidget { |
| 18 | Q_OBJECT | 22 | Q_OBJECT |
| 19 | 23 | ||
| 20 | public: | 24 | public: |
| 21 | explicit ConfigureInputAdvanced(QWidget* parent = nullptr); | 25 | explicit ConfigureInputAdvanced(Core::HID::HIDCore& hid_core_, QWidget* parent = nullptr); |
| 22 | ~ConfigureInputAdvanced() override; | 26 | ~ConfigureInputAdvanced() override; |
| 23 | 27 | ||
| 24 | void ApplyConfiguration(); | 28 | void ApplyConfiguration(); |
| @@ -44,4 +48,6 @@ private: | |||
| 44 | 48 | ||
| 45 | std::array<std::array<QColor, 4>, 8> controllers_colors; | 49 | std::array<std::array<QColor, 4>, 8> controllers_colors; |
| 46 | std::array<std::array<QPushButton*, 4>, 8> controllers_color_buttons; | 50 | std::array<std::array<QPushButton*, 4>, 8> controllers_color_buttons; |
| 51 | |||
| 52 | Core::HID::HIDCore& hid_core; | ||
| 47 | }; | 53 | }; |
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index d3255d2b4..fda09e925 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project | 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index 1a727f32c..cc2513001 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index a47089988..6d2219bf5 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp | |||
| @@ -306,10 +306,10 @@ void ConfigureProfileManager::SetUserImage() { | |||
| 306 | return; | 306 | return; |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | // Some games crash when the profile image is too big. Resize any image bigger than 256x256 | 309 | // Profile image must be 256x256 |
| 310 | QImage image(image_path); | 310 | QImage image(image_path); |
| 311 | if (image.width() > 256 || image.height() > 256) { | 311 | if (image.width() != 256 || image.height() != 256) { |
| 312 | image = image.scaled(256, 256, Qt::KeepAspectRatio); | 312 | image = image.scaled(256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); |
| 313 | if (!image.save(image_path)) { | 313 | if (!image.save(image_path)) { |
| 314 | QMessageBox::warning(this, tr("Error resizing user image"), | 314 | QMessageBox::warning(this, tr("Error resizing user image"), |
| 315 | tr("Unable to resize image")); | 315 | tr("Unable to resize image")); |
diff --git a/src/yuzu/configuration/configure_ringcon.h b/src/yuzu/configuration/configure_ringcon.h index b23c27906..6fd95e2b8 100644 --- a/src/yuzu/configuration/configure_ringcon.h +++ b/src/yuzu/configuration/configure_ringcon.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/configure_tas.h b/src/yuzu/configuration/configure_tas.h index 4a6b0ba4e..a91891906 100644 --- a/src/yuzu/configuration/configure_tas.h +++ b/src/yuzu/configuration/configure_tas.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.h b/src/yuzu/configuration/configure_touchscreen_advanced.h index 034dc0d46..b6fdffdc8 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.h +++ b/src/yuzu/configuration/configure_touchscreen_advanced.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project | 1 | // SPDX-FileCopyrightText: 2016 Citra Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 3fe448f27..1434b1a56 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp | |||
| @@ -156,7 +156,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { | |||
| 156 | // Ui General | 156 | // Ui General |
| 157 | INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); | 157 | INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); |
| 158 | INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); | 158 | INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); |
| 159 | INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", ""); | ||
| 160 | INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); | 159 | INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); |
| 161 | INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); | 160 | INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); |
| 162 | INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); | 161 | INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index db9da6dc8..ce0c71021 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1908,7 +1908,10 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { | |||
| 1908 | void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, | 1908 | void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, |
| 1909 | StartGameType type, AmLaunchType launch_type) { | 1909 | StartGameType type, AmLaunchType launch_type) { |
| 1910 | LOG_INFO(Frontend, "yuzu starting..."); | 1910 | LOG_INFO(Frontend, "yuzu starting..."); |
| 1911 | StoreRecentFile(filename); // Put the filename on top of the list | 1911 | |
| 1912 | if (program_id > static_cast<u64>(Service::AM::Applets::AppletProgramId::MaxProgramId)) { | ||
| 1913 | StoreRecentFile(filename); // Put the filename on top of the list | ||
| 1914 | } | ||
| 1912 | 1915 | ||
| 1913 | // Save configurations | 1916 | // Save configurations |
| 1914 | UpdateUISettings(); | 1917 | UpdateUISettings(); |
| @@ -2174,6 +2177,7 @@ void GMainWindow::ShutdownGame() { | |||
| 2174 | return; | 2177 | return; |
| 2175 | } | 2178 | } |
| 2176 | 2179 | ||
| 2180 | play_time_manager->Stop(); | ||
| 2177 | OnShutdownBegin(); | 2181 | OnShutdownBegin(); |
| 2178 | OnEmulationStopTimeExpired(); | 2182 | OnEmulationStopTimeExpired(); |
| 2179 | OnEmulationStopped(); | 2183 | OnEmulationStopped(); |
| @@ -3484,7 +3488,7 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) { | |||
| 3484 | } | 3488 | } |
| 3485 | 3489 | ||
| 3486 | void GMainWindow::OnExit() { | 3490 | void GMainWindow::OnExit() { |
| 3487 | OnStopGame(); | 3491 | ShutdownGame(); |
| 3488 | } | 3492 | } |
| 3489 | 3493 | ||
| 3490 | void GMainWindow::OnSaveConfig() { | 3494 | void GMainWindow::OnSaveConfig() { |
| @@ -4272,7 +4276,7 @@ void GMainWindow::OnToggleStatusBar() { | |||
| 4272 | } | 4276 | } |
| 4273 | 4277 | ||
| 4274 | void GMainWindow::OnAlbum() { | 4278 | void GMainWindow::OnAlbum() { |
| 4275 | constexpr u64 AlbumId = 0x010000000000100Dull; | 4279 | constexpr u64 AlbumId = static_cast<u64>(Service::AM::Applets::AppletProgramId::PhotoViewer); |
| 4276 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); | 4280 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); |
| 4277 | if (!bis_system) { | 4281 | if (!bis_system) { |
| 4278 | QMessageBox::warning(this, tr("No firmware available"), | 4282 | QMessageBox::warning(this, tr("No firmware available"), |
| @@ -4295,7 +4299,7 @@ void GMainWindow::OnAlbum() { | |||
| 4295 | } | 4299 | } |
| 4296 | 4300 | ||
| 4297 | void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { | 4301 | void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { |
| 4298 | constexpr u64 CabinetId = 0x0100000000001002ull; | 4302 | constexpr u64 CabinetId = static_cast<u64>(Service::AM::Applets::AppletProgramId::Cabinet); |
| 4299 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); | 4303 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); |
| 4300 | if (!bis_system) { | 4304 | if (!bis_system) { |
| 4301 | QMessageBox::warning(this, tr("No firmware available"), | 4305 | QMessageBox::warning(this, tr("No firmware available"), |
| @@ -4319,7 +4323,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { | |||
| 4319 | } | 4323 | } |
| 4320 | 4324 | ||
| 4321 | void GMainWindow::OnMiiEdit() { | 4325 | void GMainWindow::OnMiiEdit() { |
| 4322 | constexpr u64 MiiEditId = 0x0100000000001009ull; | 4326 | constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); |
| 4323 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); | 4327 | auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); |
| 4324 | if (!bis_system) { | 4328 | if (!bis_system) { |
| 4325 | QMessageBox::warning(this, tr("No firmware available"), | 4329 | QMessageBox::warning(this, tr("No firmware available"), |
| @@ -4847,7 +4851,12 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe | |||
| 4847 | } | 4851 | } |
| 4848 | 4852 | ||
| 4849 | bool GMainWindow::ConfirmClose() { | 4853 | bool GMainWindow::ConfirmClose() { |
| 4850 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { | 4854 | if (emu_thread == nullptr || |
| 4855 | UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) { | ||
| 4856 | return true; | ||
| 4857 | } | ||
| 4858 | if (!system->GetExitLocked() && | ||
| 4859 | UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) { | ||
| 4851 | return true; | 4860 | return true; |
| 4852 | } | 4861 | } |
| 4853 | const auto text = tr("Are you sure you want to close yuzu?"); | 4862 | const auto text = tr("Are you sure you want to close yuzu?"); |
| @@ -4952,7 +4961,7 @@ bool GMainWindow::ConfirmChangeGame() { | |||
| 4952 | } | 4961 | } |
| 4953 | 4962 | ||
| 4954 | bool GMainWindow::ConfirmForceLockedExit() { | 4963 | bool GMainWindow::ConfirmForceLockedExit() { |
| 4955 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { | 4964 | if (emu_thread == nullptr) { |
| 4956 | return true; | 4965 | return true; |
| 4957 | } | 4966 | } |
| 4958 | const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" | 4967 | const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index b62ff620c..77d992c54 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -93,10 +93,6 @@ struct Values { | |||
| 93 | Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; | 93 | Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; |
| 94 | Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui}; | 94 | Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui}; |
| 95 | 95 | ||
| 96 | Setting<bool> confirm_before_closing{ | ||
| 97 | linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default, | ||
| 98 | true, true}; | ||
| 99 | |||
| 100 | SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, | 96 | SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, |
| 101 | ConfirmStop::Ask_Always, | 97 | ConfirmStop::Ask_Always, |
| 102 | "confirmStop", | 98 | "confirmStop", |