summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs5
-rw-r--r--.github/workflows/android-build.yml2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt2
-rw-r--r--src/android/app/src/main/jni/native.cpp21
-rw-r--r--src/android/app/src/main/jni/native.h2
-rw-r--r--src/audio_core/adsp/apps/opus/opus_decode_object.cpp214
-rw-r--r--src/audio_core/adsp/apps/opus/opus_decoder.cpp4
-rw-r--r--src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp222
-rw-r--r--src/audio_core/opus/decoder.cpp358
-rw-r--r--src/audio_core/opus/decoder.h106
-rw-r--r--src/audio_core/opus/decoder_manager.cpp204
-rw-r--r--src/audio_core/opus/decoder_manager.h76
-rw-r--r--src/audio_core/opus/hardware_opus.cpp482
-rw-r--r--src/audio_core/opus/hardware_opus.h90
-rw-r--r--src/core/hid/emulated_controller.cpp37
-rw-r--r--src/core/hid/emulated_controller.h3
-rw-r--r--src/core/hle/service/acc/acc.cpp56
-rw-r--r--src/core/hle/service/am/applets/applets.h24
-rw-r--r--src/core/hle/service/hid/hid.cpp12
-rw-r--r--src/core/hle/service/sockets/bsd.cpp77
-rw-r--r--src/core/hle/service/sockets/bsd.h2
-rw-r--r--src/video_core/renderer_null/null_rasterizer.cpp13
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp2
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure_camera.h2
-rw-r--r--src/yuzu/configuration/configure_input.cpp2
-rw-r--r--src/yuzu/configuration/configure_input.h2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp8
-rw-r--r--src/yuzu/configuration/configure_input_advanced.h8
-rw-r--r--src/yuzu/configuration/configure_input_player.h2
-rw-r--r--src/yuzu/configuration/configure_per_game.h2
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp6
-rw-r--r--src/yuzu/configuration/configure_ringcon.h2
-rw-r--r--src/yuzu/configuration/configure_tas.h2
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.h2
-rw-r--r--src/yuzu/configuration/shared_translation.cpp1
-rw-r--r--src/yuzu/main.cpp23
-rw-r--r--src/yuzu/uisettings.h4
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
590aa937593e53a5d5e070fb623b228578b0b225f
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
250void EmulationSession::InitializeSystem() { 250void 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
665void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz) { 667void 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
673jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) { 678jint 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
7namespace AudioCore::ADSP::OpusDecoder { 7namespace AudioCore::ADSP::OpusDecoder {
8namespace { 8namespace {
9bool IsValidChannelCount(u32 channel_count) { 9bool 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
14u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) { 14u32 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
21OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) { 21OpusDecodeObject& 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
37s32 OpusDecodeObject::InitializeDecoder(u32 sample_rate, u32 channel_count) { 37s32 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
66s32 OpusDecodeObject::Shutdown() { 66s32 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
82s32 OpusDecodeObject::ResetDecoder() { 82s32 OpusDecodeObject::ResetDecoder() {
83 return opus_decoder_ctl(decoder, OPUS_RESET_STATE); 83 return opus_decoder_ctl(decoder, OPUS_RESET_STATE);
84} 84}
85 85
86s32 OpusDecodeObject::Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, 86s32 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
33bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 sterero_stream_count) { 33bool 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
7namespace AudioCore::ADSP::OpusDecoder { 7namespace AudioCore::ADSP::OpusDecoder {
8 8
9namespace { 9namespace {
10bool IsValidChannelCount(u32 channel_count) { 10bool IsValidChannelCount(u32 channel_count) {
11 return channel_count == 1 || channel_count == 2; 11 return channel_count == 1 || channel_count == 2;
12} 12}
13 13
14bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) { 14bool 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
20u32 OpusMultiStreamDecodeObject::GetWorkBufferSize(u32 total_stream_count, 20u32 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
29OpusMultiStreamDecodeObject& OpusMultiStreamDecodeObject::Initialize(u64 buffer, u64 buffer2) { 29OpusMultiStreamDecodeObject& 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
45s32 OpusMultiStreamDecodeObject::InitializeDecoder(u32 sample_rate, u32 total_stream_count, 45s32 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
70s32 OpusMultiStreamDecodeObject::Shutdown() { 70s32 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
86s32 OpusMultiStreamDecodeObject::ResetDecoder() { 86s32 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
90s32 OpusMultiStreamDecodeObject::Decode(u32& out_sample_count, u64 output_data, 90s32 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
11namespace AudioCore::OpusDecoder { 11namespace AudioCore::OpusDecoder {
12using namespace Service::Audio; 12using namespace Service::Audio;
13namespace { 13namespace {
14OpusPacketHeader ReverseHeader(OpusPacketHeader header) { 14OpusPacketHeader 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
22OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_) 22OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_)
23 : system{system_}, hardware_opus{hardware_opus_} {} 23 : system{system_}, hardware_opus{hardware_opus_} {}
24 24
25OpusDecoder::~OpusDecoder() { 25OpusDecoder::~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
31Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, 31Result 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
62Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params, 62Result 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
97Result OpusDecoder::DecodeInterleaved(u32* out_data_size, u64* out_time_taken, 97Result 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
133Result OpusDecoder::SetContext([[maybe_unused]] std::span<const u8> context) { 133Result 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
139Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken, 139Result 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
13namespace Core { 13namespace Core {
14class System; 14class System;
15} 15}
16 16
17namespace AudioCore::OpusDecoder { 17namespace AudioCore::OpusDecoder {
18class HardwareOpus; 18class HardwareOpus;
19 19
20class OpusDecoder { 20class OpusDecoder {
21public: 21public:
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
36private: 36private:
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
9namespace AudioCore::OpusDecoder { 9namespace AudioCore::OpusDecoder {
10using namespace Service::Audio; 10using namespace Service::Audio;
11 11
12namespace { 12namespace {
13bool IsValidChannelCount(u32 channel_count) { 13bool IsValidChannelCount(u32 channel_count) {
14 return channel_count == 1 || channel_count == 2; 14 return channel_count == 1 || channel_count == 2;
15} 15}
16 16
17bool IsValidMultiStreamChannelCount(u32 channel_count) { 17bool IsValidMultiStreamChannelCount(u32 channel_count) {
18 return channel_count > 0 && channel_count <= OpusStreamCountMax; 18 return channel_count > 0 && channel_count <= OpusStreamCountMax;
19} 19}
20 20
21bool IsValidSampleRate(u32 sample_rate) { 21bool 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
26bool IsValidStreamCount(u32 channel_count, u32 total_stream_count, u32 stereo_stream_count) { 26bool 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
34OpusDecoderManager::OpusDecoderManager(Core::System& system_) 34OpusDecoderManager::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
41Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) { 41Result 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
50Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) { 50Result 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
54Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) { 54Result 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
66Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, 66Result 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
79Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, 79Result 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
84Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, 84Result 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
11namespace Core { 11namespace Core {
12class System; 12class System;
13} 13}
14 14
15namespace AudioCore::OpusDecoder { 15namespace AudioCore::OpusDecoder {
16 16
17class OpusDecoderManager { 17class OpusDecoderManager {
18public: 18public:
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
32private: 32private:
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
10namespace AudioCore::OpusDecoder { 10namespace AudioCore::OpusDecoder {
11namespace { 11namespace {
12using namespace Service::Audio; 12using namespace Service::Audio;
13 13
14static constexpr Result ResultCodeFromLibOpusErrorCode(u64 error_code) { 14static 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
40HardwareOpus::HardwareOpus(Core::System& system_) 40HardwareOpus::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
45u64 HardwareOpus::GetWorkBufferSize(u32 channel) { 45u64 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
61u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { 61u64 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
76Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, 76Result 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
95Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, 95Result 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
122Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) { 122Result 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
136Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size) { 136Result 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
151Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data, 151Result 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
180Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data, 180Result 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
211Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) { 211Result 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
226Result HardwareOpus::UnmapMemory(void* buffer, u64 buffer_size) { 226Result 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
14namespace AudioCore::OpusDecoder { 14namespace AudioCore::OpusDecoder {
15class HardwareOpus { 15class HardwareOpus {
16public: 16public:
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
39private: 39private:
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
120void 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
131void EmulatedController::LoadDevices() { 144void 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
41static constexpr u32 SanitizeJPEGSize(std::size_t size) { 43static 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
49static 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
46class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> { 75class 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
72enum 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
72enum class LibraryAppletMode : u32 { 96enum 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) {
1353void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { 1353void 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
42template <typename T>
43T 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
49template <typename T>
50void 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
44void BSD::PollWork::Execute(BSD* bsd) { 56void 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
337void BSD::Shutdown(HLERequestContext& ctx) { 339void BSD::Shutdown(HLERequestContext& ctx) {
@@ -521,18 +523,19 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
521 523
522std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, 524std::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
738Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { 738Errno 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}
100void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, 101void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
101 const VideoCore::DiskResourceLoadCallback& callback) {} 102 const VideoCore::DiskResourceLoadCallback& callback) {}
102void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) {} 103void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) {
103void RasterizerNull::BindChannel(Tegra::Control::ChannelState& channel) {} 104 CreateChannel(channel);
104void RasterizerNull::ReleaseChannel(s32 channel_id) {} 105}
106void RasterizerNull::BindChannel(Tegra::Control::ChannelState& channel) {
107 BindToChannel(channel.bind_id);
108}
109void 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
10ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) 12ConfigureInputAdvanced::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 {
14class ConfigureInputAdvanced; 14class ConfigureInputAdvanced;
15} 15}
16 16
17namespace Core::HID {
18class HIDCore;
19} // namespace Core::HID
20
17class ConfigureInputAdvanced : public QWidget { 21class ConfigureInputAdvanced : public QWidget {
18 Q_OBJECT 22 Q_OBJECT
19 23
20public: 24public:
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) {
1908void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, 1908void 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
3486void GMainWindow::OnExit() { 3490void GMainWindow::OnExit() {
3487 OnStopGame(); 3491 ShutdownGame();
3488} 3492}
3489 3493
3490void GMainWindow::OnSaveConfig() { 3494void GMainWindow::OnSaveConfig() {
@@ -4272,7 +4276,7 @@ void GMainWindow::OnToggleStatusBar() {
4272} 4276}
4273 4277
4274void GMainWindow::OnAlbum() { 4278void 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
4297void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { 4301void 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
4321void GMainWindow::OnMiiEdit() { 4325void 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
4849bool GMainWindow::ConfirmClose() { 4853bool 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
4954bool GMainWindow::ConfirmForceLockedExit() { 4963bool 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",