summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/cubeb_sink.cpp2
-rw-r--r--src/audio_core/stream.cpp26
-rw-r--r--src/audio_core/stream.h4
-rw-r--r--src/common/alignment.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp30
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp34
-rw-r--r--src/core/core.cpp6
-rw-r--r--src/core/core_timing.cpp6
-rw-r--r--src/core/crypto/key_manager.cpp12
-rw-r--r--src/core/file_sys/bis_factory.cpp23
-rw-r--r--src/core/file_sys/sdmc_factory.cpp4
-rw-r--r--src/core/file_sys/vfs_real.cpp27
-rw-r--r--src/core/frontend/framebuffer_layout.cpp2
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/hle/kernel/scheduler.cpp21
-rw-r--r--src/core/hle/service/am/am.cpp42
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/nim/nim.cpp88
-rw-r--r--src/core/hle/service/npns/npns.cpp1
-rw-r--r--src/core/hle/service/ns/ns.cpp25
-rw-r--r--src/core/hle/service/ns/ns.h6
-rw-r--r--src/core/hle/service/ns/pl_u.cpp2
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp11
-rw-r--r--src/core/hle/service/nvdrv/interface.h4
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp8
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.h4
-rw-r--r--src/core/hle/service/pcie/pcie.cpp3
-rw-r--r--src/core/hle/service/pcv/pcv.cpp3
-rw-r--r--src/core/hle/service/pm/pm.cpp34
-rw-r--r--src/core/hle/service/prepo/prepo.cpp5
-rw-r--r--src/core/hle/service/psc/psc.cpp2
-rw-r--r--src/core/hle/service/ptm/psm.cpp1
-rw-r--r--src/core/hle/service/set/set.cpp10
-rw-r--r--src/core/hle/service/sm/controller.cpp21
-rw-r--r--src/core/hle/service/sm/controller.h6
-rw-r--r--src/core/hle/service/sockets/nsd.cpp6
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp25
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h2
-rw-r--r--src/core/hle/service/spl/module.cpp2
-rw-r--r--src/core/hle/service/spl/spl.cpp39
-rw-r--r--src/core/hle/service/time/time.cpp7
-rw-r--r--src/core/hle/service/usb/usb.cpp31
-rw-r--r--src/core/hle/service/vi/vi.cpp22
-rw-r--r--src/core/hle/service/vi/vi_u.cpp1
-rw-r--r--src/core/hle/service/wlan/wlan.cpp102
-rw-r--r--src/core/perf_stats.cpp5
-rw-r--r--src/core/settings.cpp84
-rw-r--r--src/core/settings.h171
-rw-r--r--src/core/telemetry_session.cpp27
-rw-r--r--src/input_common/CMakeLists.txt3
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp11
-rw-r--r--src/input_common/gcadapter/gc_adapter.h15
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp45
-rw-r--r--src/input_common/gcadapter/gc_poller.h2
-rw-r--r--src/input_common/main.cpp1
-rw-r--r--src/input_common/udp/client.cpp2
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h6
-rw-r--r--src/video_core/gpu.cpp2
-rw-r--r--src/video_core/query_cache.h2
-rw-r--r--src/video_core/renderer_base.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp8
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp2
-rw-r--r--src/video_core/texture_cache/texture_cache.h2
-rw-r--r--src/video_core/textures/texture.cpp2
-rw-r--r--src/video_core/video_core.cpp8
-rw-r--r--src/yuzu/CMakeLists.txt25
-rw-r--r--src/yuzu/bootmanager.cpp8
-rw-r--r--src/yuzu/configuration/config.cpp424
-rw-r--r--src/yuzu/configuration/config.h29
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp76
-rw-r--r--src/yuzu/configuration/configuration_shared.h36
-rw-r--r--src/yuzu/configuration/configure.ui22
-rw-r--r--src/yuzu/configuration/configure_audio.cpp82
-rw-r--r--src/yuzu/configuration/configure_audio.h2
-rw-r--r--src/yuzu/configuration/configure_audio.ui50
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp61
-rw-r--r--src/yuzu/configuration/configure_cpu.h33
-rw-r--r--src/yuzu/configuration/configure_cpu.ui92
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.cpp65
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.h31
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.ui174
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.ui7
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp9
-rw-r--r--src/yuzu/configuration/configure_filesystem.cpp27
-rw-r--r--src/yuzu/configuration/configure_filesystem.ui121
-rw-r--r--src/yuzu/configuration/configure_general.cpp80
-rw-r--r--src/yuzu/configuration/configure_general.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp150
-rw-r--r--src/yuzu/configuration/configure_graphics.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.ui36
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp106
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h2
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp140
-rw-r--r--src/yuzu/configuration/configure_per_game.h51
-rw-r--r--src/yuzu/configuration/configure_per_game.ui350
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.cpp (renamed from src/yuzu/configuration/configure_per_general.cpp)95
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.h (renamed from src/yuzu/configuration/configure_per_general.h)16
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.ui38
-rw-r--r--src/yuzu/configuration/configure_per_general.ui276
-rw-r--r--src/yuzu/configuration/configure_system.cpp190
-rw-r--r--src/yuzu/configuration/configure_system.h2
-rw-r--r--src/yuzu/game_list.cpp4
-rw-r--r--src/yuzu/install_dialog.cpp72
-rw-r--r--src/yuzu/install_dialog.h36
-rw-r--r--src/yuzu/main.cpp474
-rw-r--r--src/yuzu/main.h16
-rw-r--r--src/yuzu/main.ui2
-rw-r--r--src/yuzu_cmd/config.cpp94
-rw-r--r--src/yuzu_cmd/default_ini.h36
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp2
-rw-r--r--src/yuzu_tester/config.cpp63
-rw-r--r--src/yuzu_tester/default_ini.h33
118 files changed, 3408 insertions, 1479 deletions
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index c4e0e30fe..41bf5cd4d 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -193,7 +193,7 @@ long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const
193 const std::size_t samples_to_write = num_channels * num_frames; 193 const std::size_t samples_to_write = num_channels * num_frames;
194 std::size_t samples_written; 194 std::size_t samples_written;
195 195
196 if (Settings::values.enable_audio_stretching) { 196 if (Settings::values.enable_audio_stretching.GetValue()) {
197 const std::vector<s16> in{impl->queue.Pop()}; 197 const std::vector<s16> in{impl->queue.Pop()};
198 const std::size_t num_in{in.size() / num_channels}; 198 const std::size_t num_in{in.size() / num_channels};
199 s16* const out{reinterpret_cast<s16*>(buffer)}; 199 s16* const out{reinterpret_cast<s16*>(buffer)};
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index dfc4805d9..aab3e979a 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -38,7 +38,7 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format fo
38 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { 38 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} {
39 39
40 release_event = Core::Timing::CreateEvent( 40 release_event = Core::Timing::CreateEvent(
41 name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(); }); 41 name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(cycles_late); });
42} 42}
43 43
44void Stream::Play() { 44void Stream::Play() {
@@ -66,15 +66,6 @@ s64 Stream::GetBufferReleaseNS(const Buffer& buffer) const {
66 return ns.count(); 66 return ns.count();
67} 67}
68 68
69s64 Stream::GetBufferReleaseNSHostTiming(const Buffer& buffer) const {
70 const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
71 /// DSP signals before playing the last sample, in HLE we emulate this in this way
72 s64 base_samples = std::max<s64>(static_cast<s64>(num_samples) - 1, 0);
73 const auto ns =
74 std::chrono::nanoseconds((static_cast<u64>(base_samples) * 1000000000ULL) / sample_rate);
75 return ns.count();
76}
77
78static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) { 69static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
79 const float volume{std::clamp(Settings::Volume() - (1.0f - game_volume), 0.0f, 1.0f)}; 70 const float volume{std::clamp(Settings::Volume() - (1.0f - game_volume), 0.0f, 1.0f)};
80 71
@@ -89,7 +80,7 @@ static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
89 } 80 }
90} 81}
91 82
92void Stream::PlayNextBuffer() { 83void Stream::PlayNextBuffer(s64 cycles_late) {
93 if (!IsPlaying()) { 84 if (!IsPlaying()) {
94 // Ensure we are in playing state before playing the next buffer 85 // Ensure we are in playing state before playing the next buffer
95 sink_stream.Flush(); 86 sink_stream.Flush();
@@ -114,18 +105,17 @@ void Stream::PlayNextBuffer() {
114 105
115 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); 106 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
116 107
117 if (core_timing.IsHostTiming()) { 108 core_timing.ScheduleEvent(
118 core_timing.ScheduleEvent(GetBufferReleaseNSHostTiming(*active_buffer), release_event, {}); 109 GetBufferReleaseNS(*active_buffer) -
119 } else { 110 (Settings::values.enable_audio_stretching.GetValue() ? 0 : cycles_late),
120 core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer), release_event, {}); 111 release_event, {});
121 }
122} 112}
123 113
124void Stream::ReleaseActiveBuffer() { 114void Stream::ReleaseActiveBuffer(s64 cycles_late) {
125 ASSERT(active_buffer); 115 ASSERT(active_buffer);
126 released_buffers.push(std::move(active_buffer)); 116 released_buffers.push(std::move(active_buffer));
127 release_callback(); 117 release_callback();
128 PlayNextBuffer(); 118 PlayNextBuffer(cycles_late);
129} 119}
130 120
131bool Stream::QueueBuffer(BufferPtr&& buffer) { 121bool Stream::QueueBuffer(BufferPtr&& buffer) {
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index e309d60fe..524376257 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -90,10 +90,10 @@ public:
90 90
91private: 91private:
92 /// Plays the next queued buffer in the audio stream, starting playback if necessary 92 /// Plays the next queued buffer in the audio stream, starting playback if necessary
93 void PlayNextBuffer(); 93 void PlayNextBuffer(s64 cycles_late = 0);
94 94
95 /// Releases the actively playing buffer, signalling that it has been completed 95 /// Releases the actively playing buffer, signalling that it has been completed
96 void ReleaseActiveBuffer(); 96 void ReleaseActiveBuffer(s64 cycles_late = 0);
97 97
98 /// Gets the number of core cycles when the specified buffer will be released 98 /// Gets the number of core cycles when the specified buffer will be released
99 s64 GetBufferReleaseNS(const Buffer& buffer) const; 99 s64 GetBufferReleaseNS(const Buffer& buffer) const;
diff --git a/src/common/alignment.h b/src/common/alignment.h
index f8c49e079..b37044bb6 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -11,7 +11,9 @@ namespace Common {
11template <typename T> 11template <typename T>
12constexpr T AlignUp(T value, std::size_t size) { 12constexpr T AlignUp(T value, std::size_t size) {
13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); 13 static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
14 return static_cast<T>(value + (size - value % size) % size); 14 auto mod{static_cast<T>(value % size)};
15 value -= mod;
16 return static_cast<T>(mod == T{0} ? value : value + size);
15} 17}
16 18
17template <typename T> 19template <typename T>
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 0d4ab95b7..443ca72eb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -142,10 +142,32 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
142 // Timing 142 // Timing
143 config.wall_clock_cntpct = uses_wall_clock; 143 config.wall_clock_cntpct = uses_wall_clock;
144 144
145 // Optimizations 145 // Safe optimizations
146 if (Settings::values.disable_cpu_opt) { 146 if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
147 config.enable_optimizations = false; 147 if (!Settings::values.cpuopt_page_tables) {
148 config.enable_fast_dispatch = false; 148 config.page_table = nullptr;
149 }
150 if (!Settings::values.cpuopt_block_linking) {
151 config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
152 }
153 if (!Settings::values.cpuopt_return_stack_buffer) {
154 config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer;
155 }
156 if (!Settings::values.cpuopt_fast_dispatcher) {
157 config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch;
158 }
159 if (!Settings::values.cpuopt_context_elimination) {
160 config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination;
161 }
162 if (!Settings::values.cpuopt_const_prop) {
163 config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp;
164 }
165 if (!Settings::values.cpuopt_misc_ir) {
166 config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt;
167 }
168 if (!Settings::values.cpuopt_reduce_misalign_checks) {
169 config.only_detect_misalignment_via_page_table_on_page_boundary = false;
170 }
149 } 171 }
150 172
151 return std::make_unique<Dynarmic::A32::Jit>(config); 173 return std::make_unique<Dynarmic::A32::Jit>(config);
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 790981034..a63a04a25 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -191,15 +191,37 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
191 // Unpredictable instructions 191 // Unpredictable instructions
192 config.define_unpredictable_behaviour = true; 192 config.define_unpredictable_behaviour = true;
193 193
194 // Optimizations
195 if (Settings::values.disable_cpu_opt) {
196 config.enable_optimizations = false;
197 config.enable_fast_dispatch = false;
198 }
199
200 // Timing 194 // Timing
201 config.wall_clock_cntpct = uses_wall_clock; 195 config.wall_clock_cntpct = uses_wall_clock;
202 196
197 // Safe optimizations
198 if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
199 if (!Settings::values.cpuopt_page_tables) {
200 config.page_table = nullptr;
201 }
202 if (!Settings::values.cpuopt_block_linking) {
203 config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
204 }
205 if (!Settings::values.cpuopt_return_stack_buffer) {
206 config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer;
207 }
208 if (!Settings::values.cpuopt_fast_dispatcher) {
209 config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch;
210 }
211 if (!Settings::values.cpuopt_context_elimination) {
212 config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination;
213 }
214 if (!Settings::values.cpuopt_const_prop) {
215 config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp;
216 }
217 if (!Settings::values.cpuopt_misc_ir) {
218 config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt;
219 }
220 if (!Settings::values.cpuopt_reduce_misalign_checks) {
221 config.only_detect_misalignment_via_page_table_on_page_boundary = false;
222 }
223 }
224
203 return std::make_shared<Dynarmic::A64::Jit>(config); 225 return std::make_shared<Dynarmic::A64::Jit>(config);
204} 226}
205 227
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 1a243c515..69a1aa0a5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -147,8 +147,8 @@ struct System::Impl {
147 147
148 device_memory = std::make_unique<Core::DeviceMemory>(system); 148 device_memory = std::make_unique<Core::DeviceMemory>(system);
149 149
150 is_multicore = Settings::values.use_multi_core; 150 is_multicore = Settings::values.use_multi_core.GetValue();
151 is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation; 151 is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue();
152 152
153 kernel.SetMulticore(is_multicore); 153 kernel.SetMulticore(is_multicore);
154 cpu_manager.SetMulticore(is_multicore); 154 cpu_manager.SetMulticore(is_multicore);
@@ -162,7 +162,7 @@ struct System::Impl {
162 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 162 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
163 std::chrono::system_clock::now().time_since_epoch()); 163 std::chrono::system_clock::now().time_since_epoch());
164 Settings::values.custom_rtc_differential = 164 Settings::values.custom_rtc_differential =
165 Settings::values.custom_rtc.value_or(current_time) - current_time; 165 Settings::values.custom_rtc.GetValue().value_or(current_time) - current_time;
166 166
167 // Create a default fs if one doesn't already exist. 167 // Create a default fs if one doesn't already exist.
168 if (virtual_filesystem == nullptr) 168 if (virtual_filesystem == nullptr)
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 5c83c41a4..a63e60461 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -172,7 +172,7 @@ void CoreTiming::ClearPendingEvents() {
172} 172}
173 173
174void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { 174void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
175 basic_lock.lock(); 175 std::scoped_lock lock{basic_lock};
176 176
177 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { 177 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
178 return e.type.lock().get() == event_type.get(); 178 return e.type.lock().get() == event_type.get();
@@ -183,12 +183,10 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
183 event_queue.erase(itr, event_queue.end()); 183 event_queue.erase(itr, event_queue.end());
184 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 184 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
185 } 185 }
186 basic_lock.unlock();
187} 186}
188 187
189std::optional<s64> CoreTiming::Advance() { 188std::optional<s64> CoreTiming::Advance() {
190 std::scoped_lock advance_scope{advance_lock}; 189 std::scoped_lock lock{advance_lock, basic_lock};
191 std::scoped_lock basic_scope{basic_lock};
192 global_timer = GetGlobalTimeNs().count(); 190 global_timer = GetGlobalTimeNs().count();
193 191
194 while (!event_queue.empty() && event_queue.front().time <= global_timer) { 192 while (!event_queue.empty() && event_queue.front().time <= global_timer) {
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 8997c7082..f87fe0abc 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -695,8 +695,9 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
695} 695}
696 696
697void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { 697void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
698 if (s128_keys.find({id, field1, field2}) != s128_keys.end()) 698 if (s128_keys.find({id, field1, field2}) != s128_keys.end() || key == Key128{}) {
699 return; 699 return;
700 }
700 if (id == S128KeyType::Titlekey) { 701 if (id == S128KeyType::Titlekey) {
701 Key128 rights_id; 702 Key128 rights_id;
702 std::memcpy(rights_id.data(), &field2, sizeof(u64)); 703 std::memcpy(rights_id.data(), &field2, sizeof(u64));
@@ -716,8 +717,9 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
716 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == 717 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
717 std::tie(id, field1, field2); 718 std::tie(id, field1, field2);
718 }); 719 });
719 if (iter2 != s128_file_id.end()) 720 if (iter2 != s128_file_id.end()) {
720 WriteKeyToFile(category, iter2->first, key); 721 WriteKeyToFile(category, iter2->first, key);
722 }
721 723
722 // Variable cases 724 // Variable cases
723 if (id == S128KeyType::KeyArea) { 725 if (id == S128KeyType::KeyArea) {
@@ -745,16 +747,18 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
745} 747}
746 748
747void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { 749void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
748 if (s256_keys.find({id, field1, field2}) != s256_keys.end()) 750 if (s256_keys.find({id, field1, field2}) != s256_keys.end() || key == Key256{}) {
749 return; 751 return;
752 }
750 const auto iter = std::find_if( 753 const auto iter = std::find_if(
751 s256_file_id.begin(), s256_file_id.end(), 754 s256_file_id.begin(), s256_file_id.end(),
752 [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) { 755 [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) {
753 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == 756 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
754 std::tie(id, field1, field2); 757 std::tie(id, field1, field2);
755 }); 758 });
756 if (iter != s256_file_id.end()) 759 if (iter != s256_file_id.end()) {
757 WriteKeyToFile(KeyCategory::Standard, iter->first, key); 760 WriteKeyToFile(KeyCategory::Standard, iter->first, key);
761 }
758 s256_keys[{id, field1, field2}] = key; 762 s256_keys[{id, field1, field2}] = key;
759} 763}
760 764
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 8935a62c3..285277ef8 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -12,6 +12,10 @@
12 12
13namespace FileSys { 13namespace FileSys {
14 14
15constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB
16constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB
17constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB
18
15BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_) 19BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
16 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), 20 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
17 dump_root(std::move(dump_root_)), 21 dump_root(std::move(dump_root_)),
@@ -110,30 +114,29 @@ VirtualDir BISFactory::GetImageDirectory() const {
110 114
111u64 BISFactory::GetSystemNANDFreeSpace() const { 115u64 BISFactory::GetSystemNANDFreeSpace() const {
112 const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system"); 116 const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
113 if (sys_dir == nullptr) 117 if (sys_dir == nullptr) {
114 return 0; 118 return GetSystemNANDTotalSpace();
119 }
115 120
116 return GetSystemNANDTotalSpace() - sys_dir->GetSize(); 121 return GetSystemNANDTotalSpace() - sys_dir->GetSize();
117} 122}
118 123
119u64 BISFactory::GetSystemNANDTotalSpace() const { 124u64 BISFactory::GetSystemNANDTotalSpace() const {
120 return static_cast<u64>(Settings::values.nand_system_size); 125 return NAND_SYSTEM_SIZE;
121} 126}
122 127
123u64 BISFactory::GetUserNANDFreeSpace() const { 128u64 BISFactory::GetUserNANDFreeSpace() const {
124 const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user"); 129 // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes.
125 if (usr_dir == nullptr) 130 // Set the free space to be 1 MiB less than the total as a workaround to this issue.
126 return 0; 131 return GetUserNANDTotalSpace() - 0x100000;
127
128 return GetUserNANDTotalSpace() - usr_dir->GetSize();
129} 132}
130 133
131u64 BISFactory::GetUserNANDTotalSpace() const { 134u64 BISFactory::GetUserNANDTotalSpace() const {
132 return static_cast<u64>(Settings::values.nand_user_size); 135 return NAND_USER_SIZE;
133} 136}
134 137
135u64 BISFactory::GetFullNANDTotalSpace() const { 138u64 BISFactory::GetFullNANDTotalSpace() const {
136 return static_cast<u64>(Settings::values.nand_total_size); 139 return NAND_TOTAL_SIZE;
137} 140}
138 141
139VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { 142VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const {
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index 5113a1ca6..6f732e4d8 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -10,6 +10,8 @@
10 10
11namespace FileSys { 11namespace FileSys {
12 12
13constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB
14
13SDMCFactory::SDMCFactory(VirtualDir dir_) 15SDMCFactory::SDMCFactory(VirtualDir dir_)
14 : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>( 16 : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>(
15 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), 17 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
@@ -46,7 +48,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const {
46} 48}
47 49
48u64 SDMCFactory::GetSDMCTotalSpace() const { 50u64 SDMCFactory::GetSDMCTotalSpace() const {
49 return static_cast<u64>(Settings::values.sdmc_size); 51 return SDMC_TOTAL_SIZE;
50} 52}
51 53
52} // namespace FileSys 54} // namespace FileSys
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index e21300a7c..96ce5957c 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -112,19 +112,26 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
112 const auto new_path = 112 const auto new_path =
113 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); 113 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
114 114
115 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
116 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
117 return nullptr;
118
119 if (cache.find(old_path) != cache.end()) { 115 if (cache.find(old_path) != cache.end()) {
120 auto cached = cache[old_path]; 116 auto file = cache[old_path].lock();
121 if (!cached.expired()) { 117
122 auto file = cached.lock(); 118 if (!cache[old_path].expired()) {
123 file->Open(new_path, "r+b"); 119 file->Close();
124 cache.erase(old_path); 120 }
125 cache[new_path] = file; 121
122 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
123 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) {
124 return nullptr;
126 } 125 }
126
127 cache.erase(old_path);
128 file->Open(new_path, "r+b");
129 cache[new_path] = file;
130 } else {
131 UNREACHABLE();
132 return nullptr;
127 } 133 }
134
128 return OpenFile(new_path, Mode::ReadWrite); 135 return OpenFile(new_path, Mode::ReadWrite);
129} 136}
130 137
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index d0c43447c..c1fbc235b 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -29,7 +29,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
29 29
30 const float window_aspect_ratio = static_cast<float>(height) / width; 30 const float window_aspect_ratio = static_cast<float>(height) / width;
31 const float emulation_aspect_ratio = EmulationAspectRatio( 31 const float emulation_aspect_ratio = EmulationAspectRatio(
32 static_cast<AspectRatio>(Settings::values.aspect_ratio), window_aspect_ratio); 32 static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio);
33 33
34 const Common::Rectangle<u32> screen_window_area{0, 0, width, height}; 34 const Common::Rectangle<u32> screen_window_area{0, 0, width, height};
35 Common::Rectangle<u32> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio); 35 Common::Rectangle<u32> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index f9d7c024d..c6fcb56ad 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -123,7 +123,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
123 : kernel.CreateNewUserProcessID(); 123 : kernel.CreateNewUserProcessID();
124 process->capabilities.InitializeForMetadatalessProcess(); 124 process->capabilities.InitializeForMetadatalessProcess();
125 125
126 std::mt19937 rng(Settings::values.rng_seed.value_or(0)); 126 std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0));
127 std::uniform_int_distribution<u64> distribution; 127 std::uniform_int_distribution<u64> distribution;
128 std::generate(process->random_entropy.begin(), process->random_entropy.end(), 128 std::generate(process->random_entropy.begin(), process->random_entropy.end(),
129 [&] { return distribution(rng); }); 129 [&] { return distribution(rng); });
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 2b12c0dbf..7b929781c 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -6,6 +6,7 @@
6// licensed under GPLv2 or later under exception provided by the author. 6// licensed under GPLv2 or later under exception provided by the author.
7 7
8#include <algorithm> 8#include <algorithm>
9#include <mutex>
9#include <set> 10#include <set>
10#include <unordered_set> 11#include <unordered_set>
11#include <utility> 12#include <utility>
@@ -31,22 +32,20 @@ GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {}
31GlobalScheduler::~GlobalScheduler() = default; 32GlobalScheduler::~GlobalScheduler() = default;
32 33
33void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) { 34void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) {
34 global_list_guard.lock(); 35 std::scoped_lock lock{global_list_guard};
35 thread_list.push_back(std::move(thread)); 36 thread_list.push_back(std::move(thread));
36 global_list_guard.unlock();
37} 37}
38 38
39void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) { 39void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) {
40 global_list_guard.lock(); 40 std::scoped_lock lock{global_list_guard};
41 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), 41 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
42 thread_list.end()); 42 thread_list.end());
43 global_list_guard.unlock();
44} 43}
45 44
46u32 GlobalScheduler::SelectThreads() { 45u32 GlobalScheduler::SelectThreads() {
47 ASSERT(is_locked); 46 ASSERT(is_locked);
48 const auto update_thread = [](Thread* thread, Scheduler& sched) { 47 const auto update_thread = [](Thread* thread, Scheduler& sched) {
49 sched.guard.lock(); 48 std::scoped_lock lock{sched.guard};
50 if (thread != sched.selected_thread_set.get()) { 49 if (thread != sched.selected_thread_set.get()) {
51 if (thread == nullptr) { 50 if (thread == nullptr) {
52 ++sched.idle_selection_count; 51 ++sched.idle_selection_count;
@@ -57,7 +56,6 @@ u32 GlobalScheduler::SelectThreads() {
57 sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread); 56 sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread);
58 sched.is_context_switch_pending = reschedule_pending; 57 sched.is_context_switch_pending = reschedule_pending;
59 std::atomic_thread_fence(std::memory_order_seq_cst); 58 std::atomic_thread_fence(std::memory_order_seq_cst);
60 sched.guard.unlock();
61 return reschedule_pending; 59 return reschedule_pending;
62 }; 60 };
63 if (!is_reselection_pending.load()) { 61 if (!is_reselection_pending.load()) {
@@ -757,11 +755,12 @@ void Scheduler::OnSwitch(void* this_scheduler) {
757 755
758void Scheduler::SwitchToCurrent() { 756void Scheduler::SwitchToCurrent() {
759 while (true) { 757 while (true) {
760 guard.lock(); 758 {
761 selected_thread = selected_thread_set; 759 std::scoped_lock lock{guard};
762 current_thread = selected_thread; 760 selected_thread = selected_thread_set;
763 is_context_switch_pending = false; 761 current_thread = selected_thread;
764 guard.unlock(); 762 is_context_switch_pending = false;
763 }
765 while (!is_context_switch_pending) { 764 while (!is_context_switch_pending) {
766 if (current_thread != nullptr && !current_thread->IsHLEThread()) { 765 if (current_thread != nullptr && !current_thread->IsHLEThread()) {
767 current_thread->context_guard.lock(); 766 current_thread->context_guard.lock();
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 24cfb370b..4e7a0bec9 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -272,7 +272,7 @@ ISelfController::ISelfController(Core::System& system,
272 {41, nullptr, "IsSystemBufferSharingEnabled"}, 272 {41, nullptr, "IsSystemBufferSharingEnabled"},
273 {42, nullptr, "GetSystemSharedLayerHandle"}, 273 {42, nullptr, "GetSystemSharedLayerHandle"},
274 {43, nullptr, "GetSystemSharedBufferHandle"}, 274 {43, nullptr, "GetSystemSharedBufferHandle"},
275 {44, nullptr, "CreateManagedDisplaySeparableLayer"}, 275 {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
276 {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, 276 {45, nullptr, "SetManagedDisplayLayerSeparationMode"},
277 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, 277 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
278 {51, nullptr, "ApproveToDisplay"}, 278 {51, nullptr, "ApproveToDisplay"},
@@ -462,6 +462,24 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
462 rb.Push(*layer_id); 462 rb.Push(*layer_id);
463} 463}
464 464
465void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestContext& ctx) {
466 LOG_WARNING(Service_AM, "(STUBBED) called");
467
468 // TODO(Subv): Find out how AM determines the display to use, for now just
469 // create the layer in the Default display.
470 // This calls nn::vi::CreateRecordingLayer() which creates another layer.
471 // Currently we do not support more than 1 layer per display, output 1 layer id for now.
472 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
473 // side effects.
474 // TODO: Support multiple layers
475 const auto display_id = nvflinger->OpenDisplay("Default");
476 const auto layer_id = nvflinger->CreateLayer(*display_id);
477
478 IPC::ResponseBuilder rb{ctx, 4};
479 rb.Push(RESULT_SUCCESS);
480 rb.Push(*layer_id);
481}
482
465void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { 483void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
466 LOG_WARNING(Service_AM, "(STUBBED) called"); 484 LOG_WARNING(Service_AM, "(STUBBED) called");
467 485
@@ -731,14 +749,14 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
731 749
732 if (Settings::values.use_docked_mode) { 750 if (Settings::values.use_docked_mode) {
733 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * 751 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
734 static_cast<u32>(Settings::values.resolution_factor)); 752 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
735 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * 753 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
736 static_cast<u32>(Settings::values.resolution_factor)); 754 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
737 } else { 755 } else {
738 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) * 756 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
739 static_cast<u32>(Settings::values.resolution_factor)); 757 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
740 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) * 758 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
741 static_cast<u32>(Settings::values.resolution_factor)); 759 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
742 } 760 }
743} 761}
744 762
@@ -1389,7 +1407,19 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1389 u32 supported_languages = 0; 1407 u32 supported_languages = 0;
1390 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; 1408 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
1391 1409
1392 const auto res = pm.GetControlMetadata(); 1410 const auto res = [this] {
1411 const auto title_id = system.CurrentProcess()->GetTitleID();
1412
1413 FileSys::PatchManager pm{title_id};
1414 auto res = pm.GetControlMetadata();
1415 if (res.first != nullptr) {
1416 return res;
1417 }
1418
1419 FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)};
1420 return pm_update.GetControlMetadata();
1421 }();
1422
1393 if (res.first != nullptr) { 1423 if (res.first != nullptr) {
1394 supported_languages = res.first->GetSupportedLanguages(); 1424 supported_languages = res.first->GetSupportedLanguages();
1395 } 1425 }
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 2f69466ec..6cfb11b48 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -140,6 +140,7 @@ private:
140 void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx); 140 void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx);
141 void SetAlbumImageOrientation(Kernel::HLERequestContext& ctx); 141 void SetAlbumImageOrientation(Kernel::HLERequestContext& ctx);
142 void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); 142 void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
143 void CreateManagedDisplaySeparableLayer(Kernel::HLERequestContext& ctx);
143 void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); 144 void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
144 void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); 145 void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
145 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); 146 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index f19affce7..11aa74828 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -121,11 +121,83 @@ public:
121 {39, nullptr, "PrepareShutdown"}, 121 {39, nullptr, "PrepareShutdown"},
122 {40, nullptr, "ListApplyDeltaTask"}, 122 {40, nullptr, "ListApplyDeltaTask"},
123 {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"}, 123 {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
124 {42, nullptr, "Unknown1"}, 124 {42, nullptr, "Unknown42"},
125 {43, nullptr, "Unknown2"}, 125 {43, nullptr, "Unknown43"},
126 {44, nullptr, "Unknown3"}, 126 {44, nullptr, "Unknown44"},
127 {45, nullptr, "Unknown4"}, 127 {45, nullptr, "Unknown45"},
128 {46, nullptr, "Unknown5"}, 128 {46, nullptr, "Unknown46"},
129 {47, nullptr, "Unknown47"},
130 {48, nullptr, "Unknown48"},
131 {49, nullptr, "Unknown49"},
132 {50, nullptr, "Unknown50"},
133 {51, nullptr, "Unknown51"},
134 {52, nullptr, "Unknown52"},
135 {53, nullptr, "Unknown53"},
136 {54, nullptr, "Unknown54"},
137 {55, nullptr, "Unknown55"},
138 {56, nullptr, "Unknown56"},
139 {57, nullptr, "Unknown57"},
140 {58, nullptr, "Unknown58"},
141 {59, nullptr, "Unknown59"},
142 {60, nullptr, "Unknown60"},
143 {61, nullptr, "Unknown61"},
144 {62, nullptr, "Unknown62"},
145 {63, nullptr, "Unknown63"},
146 {64, nullptr, "Unknown64"},
147 {65, nullptr, "Unknown65"},
148 {66, nullptr, "Unknown66"},
149 {67, nullptr, "Unknown67"},
150 {68, nullptr, "Unknown68"},
151 {69, nullptr, "Unknown69"},
152 {70, nullptr, "Unknown70"},
153 {71, nullptr, "Unknown71"},
154 {72, nullptr, "Unknown72"},
155 {73, nullptr, "Unknown73"},
156 {74, nullptr, "Unknown74"},
157 {75, nullptr, "Unknown75"},
158 {76, nullptr, "Unknown76"},
159 {77, nullptr, "Unknown77"},
160 {78, nullptr, "Unknown78"},
161 {79, nullptr, "Unknown79"},
162 {80, nullptr, "Unknown80"},
163 {81, nullptr, "Unknown81"},
164 {82, nullptr, "Unknown82"},
165 {83, nullptr, "Unknown83"},
166 {84, nullptr, "Unknown84"},
167 {85, nullptr, "Unknown85"},
168 {86, nullptr, "Unknown86"},
169 {87, nullptr, "Unknown87"},
170 {88, nullptr, "Unknown88"},
171 {89, nullptr, "Unknown89"},
172 {90, nullptr, "Unknown90"},
173 {91, nullptr, "Unknown91"},
174 {92, nullptr, "Unknown92"},
175 {93, nullptr, "Unknown93"},
176 {94, nullptr, "Unknown94"},
177 {95, nullptr, "Unknown95"},
178 {96, nullptr, "Unknown96"},
179 {97, nullptr, "Unknown97"},
180 {98, nullptr, "Unknown98"},
181 {99, nullptr, "Unknown99"},
182 {100, nullptr, "Unknown100"},
183 {101, nullptr, "Unknown101"},
184 {102, nullptr, "Unknown102"},
185 {103, nullptr, "Unknown103"},
186 {104, nullptr, "Unknown104"},
187 {105, nullptr, "Unknown105"},
188 {106, nullptr, "Unknown106"},
189 {107, nullptr, "Unknown107"},
190 {108, nullptr, "Unknown108"},
191 {109, nullptr, "Unknown109"},
192 {110, nullptr, "Unknown110"},
193 {111, nullptr, "Unknown111"},
194 {112, nullptr, "Unknown112"},
195 {113, nullptr, "Unknown113"},
196 {114, nullptr, "Unknown114"},
197 {115, nullptr, "Unknown115"},
198 {116, nullptr, "Unknown116"},
199 {117, nullptr, "Unknown117"},
200 {118, nullptr, "Unknown118"},
129 }; 201 };
130 // clang-format on 202 // clang-format on
131 203
@@ -142,6 +214,7 @@ public:
142 {1, nullptr, "RefreshDebugAvailability"}, 214 {1, nullptr, "RefreshDebugAvailability"},
143 {2, nullptr, "ClearDebugResponse"}, 215 {2, nullptr, "ClearDebugResponse"},
144 {3, nullptr, "RegisterDebugResponse"}, 216 {3, nullptr, "RegisterDebugResponse"},
217 {4, nullptr, "IsLargeResourceAvailable"},
145 }; 218 };
146 // clang-format on 219 // clang-format on
147 220
@@ -164,6 +237,8 @@ public:
164 static const FunctionInfo functions[] = { 237 static const FunctionInfo functions[] = {
165 {0, nullptr, "RequestDeviceAuthenticationToken"}, 238 {0, nullptr, "RequestDeviceAuthenticationToken"},
166 {1, nullptr, "RequestCachedDeviceAuthenticationToken"}, 239 {1, nullptr, "RequestCachedDeviceAuthenticationToken"},
240 {2, nullptr, "RequestEdgeToken"},
241 {3, nullptr, "RequestCachedEdgeToken"},
167 {100, nullptr, "RequestRegisterDeviceAccount"}, 242 {100, nullptr, "RequestRegisterDeviceAccount"},
168 {101, nullptr, "RequestUnregisterDeviceAccount"}, 243 {101, nullptr, "RequestUnregisterDeviceAccount"},
169 {102, nullptr, "RequestDeviceAccountStatus"}, 244 {102, nullptr, "RequestDeviceAccountStatus"},
@@ -181,7 +256,8 @@ public:
181 {305, nullptr, "RequestCreateVirtualAccount"}, 256 {305, nullptr, "RequestCreateVirtualAccount"},
182 {306, nullptr, "RequestDeviceLinkStatus"}, 257 {306, nullptr, "RequestDeviceLinkStatus"},
183 {400, nullptr, "GetAccountByVirtualAccount"}, 258 {400, nullptr, "GetAccountByVirtualAccount"},
184 {500, nullptr, "RequestSyncTicket"}, 259 {401, nullptr, "GetVirtualAccount"},
260 {500, nullptr, "RequestSyncTicketLegacy"},
185 {501, nullptr, "RequestDownloadTicket"}, 261 {501, nullptr, "RequestDownloadTicket"},
186 {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, 262 {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"},
187 {503, nullptr, "RequestSyncTicket"}, 263 {503, nullptr, "RequestSyncTicket"},
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index f38d01084..8fa16fb08 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -30,6 +30,7 @@ public:
30 {23, nullptr, "DestroyToken"}, 30 {23, nullptr, "DestroyToken"},
31 {24, nullptr, "DestroyTokenWithApplicationId"}, 31 {24, nullptr, "DestroyTokenWithApplicationId"},
32 {25, nullptr, "QueryIsTokenValid"}, 32 {25, nullptr, "QueryIsTokenValid"},
33 {26, nullptr, "ListenToMyApplicationId"},
33 {31, nullptr, "UploadTokenToBaaS"}, 34 {31, nullptr, "UploadTokenToBaaS"},
34 {32, nullptr, "DestroyTokenForBaaS"}, 35 {32, nullptr, "DestroyTokenForBaaS"},
35 {33, nullptr, "CreateTokenForBaaS"}, 36 {33, nullptr, "CreateTokenForBaaS"},
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 7e5ceccdb..886450be2 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -104,7 +104,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
104 {94, nullptr, "LaunchApplication"}, 104 {94, nullptr, "LaunchApplication"},
105 {95, nullptr, "GetApplicationLaunchInfo"}, 105 {95, nullptr, "GetApplicationLaunchInfo"},
106 {96, nullptr, "AcquireApplicationLaunchInfo"}, 106 {96, nullptr, "AcquireApplicationLaunchInfo"},
107 {97, nullptr, "GetMainApplicationProgramIndex2"}, 107 {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"},
108 {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, 108 {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
109 {99, nullptr, "LaunchDevMenu"}, 109 {99, nullptr, "LaunchDevMenu"},
110 {100, nullptr, "ResetToFactorySettings"}, 110 {100, nullptr, "ResetToFactorySettings"},
@@ -254,7 +254,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
254 {2170, nullptr, "GetRightsEnvironmentStatus"}, 254 {2170, nullptr, "GetRightsEnvironmentStatus"},
255 {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"}, 255 {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
256 {2180, nullptr, "RequestExtendRightsInRightsEnvironment"}, 256 {2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
257 {2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"}, 257 {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
258 {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"}, 258 {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
259 {2190, nullptr, "GetRightsEnvironmentHandleForApplication"}, 259 {2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
260 {2199, nullptr, "GetRightsEnvironmentCountForDebug"}, 260 {2199, nullptr, "GetRightsEnvironmentCountForDebug"},
@@ -366,7 +366,8 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
366 LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages); 366 LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
367 367
368 // Get language code from settings 368 // Get language code from settings
369 const auto language_code = Set::GetLanguageCodeFromIndex(Settings::values.language_index); 369 const auto language_code =
370 Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
370 371
371 // Convert to application language, get priority list 372 // Convert to application language, get priority list
372 const auto application_language = ConvertToApplicationLanguage(language_code); 373 const auto application_language = ConvertToApplicationLanguage(language_code);
@@ -445,8 +446,8 @@ IApplicationVersionInterface::IApplicationVersionInterface()
445 446
446IApplicationVersionInterface::~IApplicationVersionInterface() = default; 447IApplicationVersionInterface::~IApplicationVersionInterface() = default;
447 448
448IContentManagerInterface::IContentManagerInterface() 449IContentManagementInterface::IContentManagementInterface()
449 : ServiceFramework{"IContentManagerInterface"} { 450 : ServiceFramework{"IContentManagementInterface"} {
450 // clang-format off 451 // clang-format off
451 static const FunctionInfo functions[] = { 452 static const FunctionInfo functions[] = {
452 {11, nullptr, "CalculateApplicationOccupiedSize"}, 453 {11, nullptr, "CalculateApplicationOccupiedSize"},
@@ -463,7 +464,7 @@ IContentManagerInterface::IContentManagerInterface()
463 RegisterHandlers(functions); 464 RegisterHandlers(functions);
464} 465}
465 466
466IContentManagerInterface::~IContentManagerInterface() = default; 467IContentManagementInterface::~IContentManagementInterface() = default;
467 468
468IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} { 469IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
469 // clang-format off 470 // clang-format off
@@ -545,7 +546,7 @@ NS::NS(const char* name) : ServiceFramework{name} {
545 {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, 546 {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
546 {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, 547 {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
547 {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, 548 {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
548 {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"}, 549 {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"},
549 {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, 550 {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
550 }; 551 };
551 // clang-format on 552 // clang-format on
@@ -572,9 +573,9 @@ public:
572 {6, nullptr, "TerminateApplication"}, 573 {6, nullptr, "TerminateApplication"},
573 {7, nullptr, "PrepareLaunchProgramFromHost"}, 574 {7, nullptr, "PrepareLaunchProgramFromHost"},
574 {8, nullptr, "LaunchApplication"}, 575 {8, nullptr, "LaunchApplication"},
575 {9, nullptr, "LaunchApplicationWithStorageId"}, 576 {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
576 {10, nullptr, "TerminateApplication2"}, 577 {10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
577 {11, nullptr, "GetRunningApplicationProcessId"}, 578 {11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
578 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"}, 579 {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"},
579 {13, nullptr, "CreateApplicationResourceForDevelop"}, 580 {13, nullptr, "CreateApplicationResourceForDevelop"},
580 {14, nullptr, "IsPreomiaForDevelop"}, 581 {14, nullptr, "IsPreomiaForDevelop"},
@@ -636,6 +637,10 @@ public:
636 {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"}, 637 {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"},
637 {10, nullptr, "NotifySystemUpdateForContentDelivery"}, 638 {10, nullptr, "NotifySystemUpdateForContentDelivery"},
638 {11, nullptr, "PrepareShutdown"}, 639 {11, nullptr, "PrepareShutdown"},
640 {12, nullptr, "Unknown12"},
641 {13, nullptr, "Unknown13"},
642 {14, nullptr, "Unknown14"},
643 {15, nullptr, "Unknown15"},
639 {16, nullptr, "DestroySystemUpdateTask"}, 644 {16, nullptr, "DestroySystemUpdateTask"},
640 {17, nullptr, "RequestSendSystemUpdate"}, 645 {17, nullptr, "RequestSendSystemUpdate"},
641 {18, nullptr, "GetSendSystemUpdateProgress"}, 646 {18, nullptr, "GetSendSystemUpdateProgress"},
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index 13a64ad88..c2554b878 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -40,10 +40,10 @@ public:
40 ~IApplicationVersionInterface() override; 40 ~IApplicationVersionInterface() override;
41}; 41};
42 42
43class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> { 43class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> {
44public: 44public:
45 explicit IContentManagerInterface(); 45 explicit IContentManagementInterface();
46 ~IContentManagerInterface() override; 46 ~IContentManagementInterface() override;
47}; 47};
48 48
49class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { 49class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 6efdf1606..40838a225 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -163,7 +163,7 @@ PL_U::PL_U(Core::System& system)
163 {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, 163 {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
164 {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"}, 164 {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"},
165 {100, nullptr, "RequestApplicationFunctionAuthorization"}, 165 {100, nullptr, "RequestApplicationFunctionAuthorization"},
166 {101, nullptr, "RequestApplicationFunctionAuthorizationForSystem"}, 166 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
167 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, 167 {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
168 {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"}, 168 {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
169 {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"}, 169 {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"},
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index c8ea6c661..deaf0808b 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -144,7 +144,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
144 } 144 }
145} 145}
146 146
147void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { 147void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
148 IPC::RequestParser rp{ctx}; 148 IPC::RequestParser rp{ctx};
149 pid = rp.Pop<u64>(); 149 pid = rp.Pop<u64>();
150 LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); 150 LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
@@ -154,7 +154,7 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
154 rb.Push<u32>(0); 154 rb.Push<u32>(0);
155} 155}
156 156
157void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { 157void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
158 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 158 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
159 159
160 IPC::ResponseBuilder rb{ctx, 2}; 160 IPC::ResponseBuilder rb{ctx, 2};
@@ -187,13 +187,14 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
187 {4, &NVDRV::QueryEvent, "QueryEvent"}, 187 {4, &NVDRV::QueryEvent, "QueryEvent"},
188 {5, nullptr, "MapSharedMem"}, 188 {5, nullptr, "MapSharedMem"},
189 {6, &NVDRV::GetStatus, "GetStatus"}, 189 {6, &NVDRV::GetStatus, "GetStatus"},
190 {7, nullptr, "ForceSetClientPID"}, 190 {7, nullptr, "SetAruidForTest"},
191 {8, &NVDRV::SetClientPID, "SetClientPID"}, 191 {8, &NVDRV::SetAruid, "SetAruid"},
192 {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, 192 {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
193 {10, nullptr, "InitializeDevtools"}, 193 {10, nullptr, "InitializeDevtools"},
194 {11, &NVDRV::Ioctl2, "Ioctl2"}, 194 {11, &NVDRV::Ioctl2, "Ioctl2"},
195 {12, &NVDRV::Ioctl3, "Ioctl3"}, 195 {12, &NVDRV::Ioctl3, "Ioctl3"},
196 {13, &NVDRV::FinishInitialize, "FinishInitialize"}, 196 {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled,
197 "SetGraphicsFirmwareMemoryMarginEnabled"},
197 }; 198 };
198 RegisterHandlers(functions); 199 RegisterHandlers(functions);
199} 200}
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 9269ce00c..72e17a728 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -29,8 +29,8 @@ private:
29 void Close(Kernel::HLERequestContext& ctx); 29 void Close(Kernel::HLERequestContext& ctx);
30 void Initialize(Kernel::HLERequestContext& ctx); 30 void Initialize(Kernel::HLERequestContext& ctx);
31 void QueryEvent(Kernel::HLERequestContext& ctx); 31 void QueryEvent(Kernel::HLERequestContext& ctx);
32 void SetClientPID(Kernel::HLERequestContext& ctx); 32 void SetAruid(Kernel::HLERequestContext& ctx);
33 void FinishInitialize(Kernel::HLERequestContext& ctx); 33 void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
34 void GetStatus(Kernel::HLERequestContext& ctx); 34 void GetStatus(Kernel::HLERequestContext& ctx);
35 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); 35 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
36 void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); 36 void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version);
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
index b7b8b7a1b..73b37e805 100644
--- a/src/core/hle/service/nvdrv/nvmemp.cpp
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -10,19 +10,19 @@ namespace Service::Nvidia {
10 10
11NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { 11NVMEMP::NVMEMP() : ServiceFramework("nvmemp") {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &NVMEMP::Cmd0, "Cmd0"}, 13 {0, &NVMEMP::Open, "Open"},
14 {1, &NVMEMP::Cmd1, "Cmd1"}, 14 {1, &NVMEMP::GetAruid, "GetAruid"},
15 }; 15 };
16 RegisterHandlers(functions); 16 RegisterHandlers(functions);
17} 17}
18 18
19NVMEMP::~NVMEMP() = default; 19NVMEMP::~NVMEMP() = default;
20 20
21void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) { 21void NVMEMP::Open(Kernel::HLERequestContext& ctx) {
22 UNIMPLEMENTED(); 22 UNIMPLEMENTED();
23} 23}
24 24
25void NVMEMP::Cmd1(Kernel::HLERequestContext& ctx) { 25void NVMEMP::GetAruid(Kernel::HLERequestContext& ctx) {
26 UNIMPLEMENTED(); 26 UNIMPLEMENTED();
27} 27}
28 28
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h
index 6eafb1346..c453ee4db 100644
--- a/src/core/hle/service/nvdrv/nvmemp.h
+++ b/src/core/hle/service/nvdrv/nvmemp.h
@@ -14,8 +14,8 @@ public:
14 ~NVMEMP() override; 14 ~NVMEMP() override;
15 15
16private: 16private:
17 void Cmd0(Kernel::HLERequestContext& ctx); 17 void Open(Kernel::HLERequestContext& ctx);
18 void Cmd1(Kernel::HLERequestContext& ctx); 18 void GetAruid(Kernel::HLERequestContext& ctx);
19}; 19};
20 20
21} // namespace Service::Nvidia 21} // namespace Service::Nvidia
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
index 39cf05eba..c568a0adc 100644
--- a/src/core/hle/service/pcie/pcie.cpp
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -36,6 +36,9 @@ public:
36 {18, nullptr, "ReleaseIrq"}, 36 {18, nullptr, "ReleaseIrq"},
37 {19, nullptr, "SetIrqEnable"}, 37 {19, nullptr, "SetIrqEnable"},
38 {20, nullptr, "SetAspmEnable"}, 38 {20, nullptr, "SetAspmEnable"},
39 {21, nullptr, "SetResetUponResumeEnable"},
40 {22, nullptr, "Unknown22"},
41 {23, nullptr, "Unknown23"},
39 }; 42 };
40 // clang-format on 43 // clang-format on
41 44
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
index d6891a659..8bfc0276e 100644
--- a/src/core/hle/service/pcv/pcv.cpp
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -42,6 +42,9 @@ public:
42 {24, nullptr, "GetModuleStateTable"}, 42 {24, nullptr, "GetModuleStateTable"},
43 {25, nullptr, "GetPowerDomainStateTable"}, 43 {25, nullptr, "GetPowerDomainStateTable"},
44 {26, nullptr, "GetFuseInfo"}, 44 {26, nullptr, "GetFuseInfo"},
45 {27, nullptr, "GetDramId"},
46 {28, nullptr, "IsPoweredOn"},
47 {29, nullptr, "GetVoltage"},
45 }; 48 };
46 // clang-format on 49 // clang-format on
47 50
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 809eca0ab..f43122ad2 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -78,13 +78,13 @@ public:
78 : ServiceFramework{"pm:dmnt"}, kernel(kernel) { 78 : ServiceFramework{"pm:dmnt"}, kernel(kernel) {
79 // clang-format off 79 // clang-format off
80 static const FunctionInfo functions[] = { 80 static const FunctionInfo functions[] = {
81 {0, nullptr, "GetDebugProcesses"}, 81 {0, nullptr, "GetJitDebugProcessIdList"},
82 {1, nullptr, "StartDebugProcess"}, 82 {1, nullptr, "StartProcess"},
83 {2, &DebugMonitor::GetTitlePid, "GetTitlePid"}, 83 {2, &DebugMonitor::GetProcessId, "GetProcessId"},
84 {3, nullptr, "EnableDebugForTitleId"}, 84 {3, nullptr, "HookToCreateProcess"},
85 {4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"}, 85 {4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"},
86 {5, nullptr, "EnableDebugForApplication"}, 86 {5, nullptr, "HookToCreateApplicationProgress"},
87 {6, nullptr, "DisableDebug"}, 87 {6, nullptr, "ClearHook"},
88 }; 88 };
89 // clang-format on 89 // clang-format on
90 90
@@ -92,7 +92,7 @@ public:
92 } 92 }
93 93
94private: 94private:
95 void GetTitlePid(Kernel::HLERequestContext& ctx) { 95 void GetProcessId(Kernel::HLERequestContext& ctx) {
96 IPC::RequestParser rp{ctx}; 96 IPC::RequestParser rp{ctx};
97 const auto title_id = rp.PopRaw<u64>(); 97 const auto title_id = rp.PopRaw<u64>();
98 98
@@ -114,7 +114,7 @@ private:
114 rb.Push((*process)->GetProcessID()); 114 rb.Push((*process)->GetProcessID());
115 } 115 }
116 116
117 void GetApplicationPid(Kernel::HLERequestContext& ctx) { 117 void GetApplicationProcessId(Kernel::HLERequestContext& ctx) {
118 LOG_DEBUG(Service_PM, "called"); 118 LOG_DEBUG(Service_PM, "called");
119 GetApplicationPidGeneric(ctx, kernel.GetProcessList()); 119 GetApplicationPidGeneric(ctx, kernel.GetProcessList());
120 } 120 }
@@ -163,15 +163,15 @@ public:
163 : ServiceFramework{"pm:shell"}, kernel(kernel) { 163 : ServiceFramework{"pm:shell"}, kernel(kernel) {
164 // clang-format off 164 // clang-format off
165 static const FunctionInfo functions[] = { 165 static const FunctionInfo functions[] = {
166 {0, nullptr, "LaunchProcess"}, 166 {0, nullptr, "LaunchProgram"},
167 {1, nullptr, "TerminateProcessByPid"}, 167 {1, nullptr, "TerminateProcess"},
168 {2, nullptr, "TerminateProcessByTitleId"}, 168 {2, nullptr, "TerminateProgram"},
169 {3, nullptr, "GetProcessEventWaiter"}, 169 {3, nullptr, "GetProcessEventHandle"},
170 {4, nullptr, "GetProcessEventType"}, 170 {4, nullptr, "GetProcessEventInfo"},
171 {5, nullptr, "NotifyBootFinished"}, 171 {5, nullptr, "NotifyBootFinished"},
172 {6, &Shell::GetApplicationPid, "GetApplicationPid"}, 172 {6, &Shell::GetApplicationProcessIdForShell, "GetApplicationProcessIdForShell"},
173 {7, nullptr, "BoostSystemMemoryResourceLimit"}, 173 {7, nullptr, "BoostSystemMemoryResourceLimit"},
174 {8, nullptr, "EnableAdditionalSystemThreads"}, 174 {8, nullptr, "BoostApplicationThreadResourceLimit"},
175 {9, nullptr, "GetBootFinishedEventHandle"}, 175 {9, nullptr, "GetBootFinishedEventHandle"},
176 }; 176 };
177 // clang-format on 177 // clang-format on
@@ -180,7 +180,7 @@ public:
180 } 180 }
181 181
182private: 182private:
183 void GetApplicationPid(Kernel::HLERequestContext& ctx) { 183 void GetApplicationProcessIdForShell(Kernel::HLERequestContext& ctx) {
184 LOG_DEBUG(Service_PM, "called"); 184 LOG_DEBUG(Service_PM, "called");
185 GetApplicationPidGeneric(ctx, kernel.GetProcessList()); 185 GetApplicationPidGeneric(ctx, kernel.GetProcessList());
186 } 186 }
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 67833d9af..cde3312da 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -42,6 +42,11 @@ public:
42 {40101, nullptr, "SetUserAgreementCheckEnabled"}, 42 {40101, nullptr, "SetUserAgreementCheckEnabled"},
43 {50100, nullptr, "ReadAllApplicationReportFiles"}, 43 {50100, nullptr, "ReadAllApplicationReportFiles"},
44 {90100, nullptr, "ReadAllReportFiles"}, 44 {90100, nullptr, "ReadAllReportFiles"},
45 {90101, nullptr, "Unknown90101"},
46 {90102, nullptr, "Unknown90102"},
47 {90200, nullptr, "GetStatistics"},
48 {90201, nullptr, "GetThroughputHistory"},
49 {90300, nullptr, "GetLastUploadError"},
45 }; 50 };
46 // clang-format on 51 // clang-format on
47 52
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index 53ec6b031..99e1c9042 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -24,6 +24,8 @@ public:
24 {4, nullptr, "Cancel"}, 24 {4, nullptr, "Cancel"},
25 {5, nullptr, "PrintModuleInformation"}, 25 {5, nullptr, "PrintModuleInformation"},
26 {6, nullptr, "GetModuleInformation"}, 26 {6, nullptr, "GetModuleInformation"},
27 {10, nullptr, "Unknown10"},
28 {11, nullptr, "Unknown11"},
27 }; 29 };
28 // clang-format on 30 // clang-format on
29 31
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index 12d154ecf..6d9e6bd09 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -35,6 +35,7 @@ public:
35 {15, nullptr, "GetBatteryAgePercentage"}, 35 {15, nullptr, "GetBatteryAgePercentage"},
36 {16, nullptr, "GetBatteryChargeInfoEvent"}, 36 {16, nullptr, "GetBatteryChargeInfoEvent"},
37 {17, nullptr, "GetBatteryChargeInfoFields"}, 37 {17, nullptr, "GetBatteryChargeInfoFields"},
38 {18, nullptr, "GetBatteryChargeCalibratedEvent"},
38 }; 39 };
39 // clang-format on 40 // clang-format on
40 41
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index e5cfd2101..34fe2fd82 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -91,7 +91,7 @@ void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t m
91} 91}
92 92
93void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) { 93void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) {
94 const auto language_code = available_language_codes[Settings::values.language_index]; 94 const auto language_code = available_language_codes[Settings::values.language_index.GetValue()];
95 const auto key_code = 95 const auto key_code =
96 std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), 96 std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
97 [=](const auto& element) { return element.first == language_code; }); 97 [=](const auto& element) { return element.first == language_code; });
@@ -99,7 +99,7 @@ void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) {
99 if (key_code == language_to_layout.cend()) { 99 if (key_code == language_to_layout.cend()) {
100 LOG_ERROR(Service_SET, 100 LOG_ERROR(Service_SET,
101 "Could not find keyboard layout for language index {}, defaulting to English us", 101 "Could not find keyboard layout for language index {}, defaulting to English us",
102 Settings::values.language_index); 102 Settings::values.language_index.GetValue());
103 } else { 103 } else {
104 layout = key_code->second; 104 layout = key_code->second;
105 } 105 }
@@ -163,11 +163,11 @@ void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
163} 163}
164 164
165void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { 165void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
166 LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index); 166 LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index.GetValue());
167 167
168 IPC::ResponseBuilder rb{ctx, 4}; 168 IPC::ResponseBuilder rb{ctx, 4};
169 rb.Push(RESULT_SUCCESS); 169 rb.Push(RESULT_SUCCESS);
170 rb.PushEnum(available_language_codes[Settings::values.language_index]); 170 rb.PushEnum(available_language_codes[Settings::values.language_index.GetValue()]);
171} 171}
172 172
173void SET::GetRegionCode(Kernel::HLERequestContext& ctx) { 173void SET::GetRegionCode(Kernel::HLERequestContext& ctx) {
@@ -175,7 +175,7 @@ void SET::GetRegionCode(Kernel::HLERequestContext& ctx) {
175 175
176 IPC::ResponseBuilder rb{ctx, 3}; 176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(RESULT_SUCCESS); 177 rb.Push(RESULT_SUCCESS);
178 rb.Push(Settings::values.region_index); 178 rb.Push(Settings::values.region_index.GetValue());
179} 179}
180 180
181void SET::GetKeyCodeMap(Kernel::HLERequestContext& ctx) { 181void SET::GetKeyCodeMap(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 9cca84b31..972aaa6d9 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -12,7 +12,7 @@
12 12
13namespace Service::SM { 13namespace Service::SM {
14 14
15void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { 15void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); 16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
17 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); 17 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
18 ctx.Session()->ConvertToDomain(); 18 ctx.Session()->ConvertToDomain();
@@ -22,7 +22,7 @@ void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
22 rb.Push<u32>(1); // Converted sessions start with 1 request handler 22 rb.Push<u32>(1); // Converted sessions start with 1 request handler
23} 23}
24 24
25void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { 25void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
26 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong 26 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
27 // and that we probably want to actually make an entirely new Session, but we still need to 27 // and that we probably want to actually make an entirely new Session, but we still need to
28 // verify this on hardware. 28 // verify this on hardware.
@@ -33,10 +33,10 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
33 rb.PushMoveObjects(ctx.Session()->GetParent()->Client()); 33 rb.PushMoveObjects(ctx.Session()->GetParent()->Client());
34} 34}
35 35
36void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { 36void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
37 LOG_WARNING(Service, "(STUBBED) called, using DuplicateSession"); 37 LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject");
38 38
39 DuplicateSession(ctx); 39 CloneCurrentObject(ctx);
40} 40}
41 41
42void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { 42void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
@@ -47,13 +47,14 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
47 rb.Push<u16>(0x1000); 47 rb.Push<u16>(0x1000);
48} 48}
49 49
50// https://switchbrew.org/wiki/IPC_Marshalling
50Controller::Controller() : ServiceFramework("IpcController") { 51Controller::Controller() : ServiceFramework("IpcController") {
51 static const FunctionInfo functions[] = { 52 static const FunctionInfo functions[] = {
52 {0x00000000, &Controller::ConvertSessionToDomain, "ConvertSessionToDomain"}, 53 {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"},
53 {0x00000001, nullptr, "ConvertDomainToSession"}, 54 {1, nullptr, "CopyFromCurrentDomain"},
54 {0x00000002, &Controller::DuplicateSession, "DuplicateSession"}, 55 {2, &Controller::CloneCurrentObject, "CloneCurrentObject"},
55 {0x00000003, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"}, 56 {3, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"},
56 {0x00000004, &Controller::DuplicateSessionEx, "DuplicateSessionEx"}, 57 {4, &Controller::CloneCurrentObjectEx, "CloneCurrentObjectEx"},
57 }; 58 };
58 RegisterHandlers(functions); 59 RegisterHandlers(functions);
59} 60}
diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h
index dc66c9e37..180c6da50 100644
--- a/src/core/hle/service/sm/controller.h
+++ b/src/core/hle/service/sm/controller.h
@@ -14,9 +14,9 @@ public:
14 ~Controller() override; 14 ~Controller() override;
15 15
16private: 16private:
17 void ConvertSessionToDomain(Kernel::HLERequestContext& ctx); 17 void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx);
18 void DuplicateSession(Kernel::HLERequestContext& ctx); 18 void CloneCurrentObject(Kernel::HLERequestContext& ctx);
19 void DuplicateSessionEx(Kernel::HLERequestContext& ctx); 19 void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx);
20 void QueryPointerBufferSize(Kernel::HLERequestContext& ctx); 20 void QueryPointerBufferSize(Kernel::HLERequestContext& ctx);
21}; 21};
22 22
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index dc70fd6fe..40d781124 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -14,6 +14,7 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
14 {12, nullptr, "GetDeviceId"}, 14 {12, nullptr, "GetDeviceId"},
15 {13, nullptr, "DeleteSettings"}, 15 {13, nullptr, "DeleteSettings"},
16 {14, nullptr, "ImportSettings"}, 16 {14, nullptr, "ImportSettings"},
17 {15, nullptr, "SetChangeEnvironmentIdentifierDisabled"},
17 {20, nullptr, "Resolve"}, 18 {20, nullptr, "Resolve"},
18 {21, nullptr, "ResolveEx"}, 19 {21, nullptr, "ResolveEx"},
19 {30, nullptr, "GetNasServiceSetting"}, 20 {30, nullptr, "GetNasServiceSetting"},
@@ -28,6 +29,11 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
28 {60, nullptr, "ReadSaveDataFromFsForTest"}, 29 {60, nullptr, "ReadSaveDataFromFsForTest"},
29 {61, nullptr, "WriteSaveDataToFsForTest"}, 30 {61, nullptr, "WriteSaveDataToFsForTest"},
30 {62, nullptr, "DeleteSaveDataOfFsForTest"}, 31 {62, nullptr, "DeleteSaveDataOfFsForTest"},
32 {63, nullptr, "IsChangeEnvironmentIdentifierDisabled"},
33 {64, nullptr, "SetWithoutDomainExchangeFqdns"},
34 {100, nullptr, "GetApplicationServerEnvironmentType"},
35 {101, nullptr, "SetApplicationServerEnvironmentType"},
36 {102, nullptr, "DeleteApplicationServerEnvironmentType"},
31 }; 37 };
32 // clang-format on 38 // clang-format on
33 39
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 852e71e4b..e3017451f 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -7,7 +7,7 @@
7 7
8namespace Service::Sockets { 8namespace Service::Sockets {
9 9
10void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { 10void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
11 struct Parameters { 11 struct Parameters {
12 u8 use_nsd_resolve; 12 u8 use_nsd_resolve;
13 u32 unknown; 13 u32 unknown;
@@ -29,15 +29,20 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
29 static const FunctionInfo functions[] = { 29 static const FunctionInfo functions[] = {
30 {0, nullptr, "SetDnsAddressesPrivate"}, 30 {0, nullptr, "SetDnsAddressesPrivate"},
31 {1, nullptr, "GetDnsAddressPrivate"}, 31 {1, nullptr, "GetDnsAddressPrivate"},
32 {2, nullptr, "GetHostByName"}, 32 {2, nullptr, "GetHostByNameRequest"},
33 {3, nullptr, "GetHostByAddr"}, 33 {3, nullptr, "GetHostByAddrRequest"},
34 {4, nullptr, "GetHostStringError"}, 34 {4, nullptr, "GetHostStringErrorRequest"},
35 {5, nullptr, "GetGaiStringError"}, 35 {5, nullptr, "GetGaiStringErrorRequest"},
36 {6, &SFDNSRES::GetAddrInfo, "GetAddrInfo"}, 36 {6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"},
37 {7, nullptr, "GetNameInfo"}, 37 {7, nullptr, "GetNameInfoRequest"},
38 {8, nullptr, "RequestCancelHandle"}, 38 {8, nullptr, "RequestCancelHandleRequest"},
39 {9, nullptr, "CancelSocketCall"}, 39 {9, nullptr, "CancelRequest"},
40 {11, nullptr, "ClearDnsIpServerAddressArray"}, 40 {10, nullptr, "GetHostByNameRequestWithOptions"},
41 {11, nullptr, "GetHostByAddrRequestWithOptions"},
42 {12, nullptr, "GetAddrInfoRequestWithOptions"},
43 {13, nullptr, "GetNameInfoRequestWithOptions"},
44 {14, nullptr, "ResolverSetOptionRequest"},
45 {15, nullptr, "ResolverGetOptionRequest"},
41 }; 46 };
42 RegisterHandlers(functions); 47 RegisterHandlers(functions);
43} 48}
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index eda432903..acd3647bb 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -15,7 +15,7 @@ public:
15 ~SFDNSRES() override; 15 ~SFDNSRES() override;
16 16
17private: 17private:
18 void GetAddrInfo(Kernel::HLERequestContext& ctx); 18 void GetAddrInfoRequest(Kernel::HLERequestContext& ctx);
19}; 19};
20 20
21} // namespace Service::Sockets 21} // namespace Service::Sockets
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index e724d4ab8..865ed3b91 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -19,7 +19,7 @@ namespace Service::SPL {
19 19
20Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 20Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
21 : ServiceFramework(name), module(std::move(module)), 21 : ServiceFramework(name), module(std::move(module)),
22 rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {} 22 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {}
23 23
24Module::Interface::~Interface() = default; 24Module::Interface::~Interface() = default;
25 25
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp
index 70cb41905..773551464 100644
--- a/src/core/hle/service/spl/spl.cpp
+++ b/src/core/hle/service/spl/spl.cpp
@@ -9,35 +9,36 @@ namespace Service::SPL {
9SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") { 9SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") {
10 static const FunctionInfo functions[] = { 10 static const FunctionInfo functions[] = {
11 {0, nullptr, "GetConfig"}, 11 {0, nullptr, "GetConfig"},
12 {1, nullptr, "UserExpMod"}, 12 {1, nullptr, "ModularExponentiate"},
13 {2, nullptr, "GenerateAesKek"}, 13 {2, nullptr, "GenerateAesKek"},
14 {3, nullptr, "LoadAesKey"}, 14 {3, nullptr, "LoadAesKey"},
15 {4, nullptr, "GenerateAesKey"}, 15 {4, nullptr, "GenerateAesKey"},
16 {5, nullptr, "SetConfig"}, 16 {5, nullptr, "SetConfig"},
17 {7, &SPL::GetRandomBytes, "GetRandomBytes"}, 17 {7, &SPL::GetRandomBytes, "GetRandomBytes"},
18 {9, nullptr, "LoadSecureExpModKey"}, 18 {9, nullptr, "ImportLotusKey"},
19 {10, nullptr, "SecureExpMod"}, 19 {10, nullptr, "DecryptLotusMessage"},
20 {11, nullptr, "IsDevelopment"}, 20 {11, nullptr, "IsDevelopment"},
21 {12, nullptr, "GenerateSpecificAesKey"}, 21 {12, nullptr, "GenerateSpecificAesKey"},
22 {13, nullptr, "DecryptPrivk"}, 22 {13, nullptr, "DecryptDeviceUniqueData"},
23 {14, nullptr, "DecryptAesKey"}, 23 {14, nullptr, "DecryptAesKey"},
24 {15, nullptr, "DecryptAesCtr"}, 24 {15, nullptr, "CryptAesCtr"},
25 {16, nullptr, "ComputeCmac"}, 25 {16, nullptr, "ComputeCmac"},
26 {17, nullptr, "LoadRsaOaepKey"}, 26 {17, nullptr, "ImportEsKey"},
27 {18, nullptr, "UnwrapRsaOaepWrappedTitleKey"}, 27 {18, nullptr, "UnwrapTitleKey"},
28 {19, nullptr, "LoadTitleKey"}, 28 {19, nullptr, "LoadTitleKey"},
29 {20, nullptr, "UnwrapAesWrappedTitleKey"}, 29 {20, nullptr, "PrepareEsCommonKey"},
30 {21, nullptr, "LockAesEngine"}, 30 {21, nullptr, "AllocateAesKeyslot"},
31 {22, nullptr, "UnlockAesEngine"}, 31 {22, nullptr, "DeallocateAesKeySlot"},
32 {23, nullptr, "GetSplWaitEvent"}, 32 {23, nullptr, "GetAesKeyslotAvailableEvent"},
33 {24, nullptr, "SetSharedData"}, 33 {24, nullptr, "SetBootReason"},
34 {25, nullptr, "GetSharedData"}, 34 {25, nullptr, "GetBootReason"},
35 {26, nullptr, "ImportSslRsaKey"}, 35 {26, nullptr, "DecryptAndStoreSslClientCertKey"},
36 {27, nullptr, "SecureExpModWithSslKey"}, 36 {27, nullptr, "ModularExponentiateWithSslClientCertKey"},
37 {28, nullptr, "ImportEsRsaKey"}, 37 {28, nullptr, "DecryptAndStoreDrmDeviceCertKey"},
38 {29, nullptr, "SecureExpModWithEsKey"}, 38 {29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"},
39 {30, nullptr, "EncryptManuRsaKeyForImport"}, 39 {30, nullptr, "ReencryptDeviceUniqueData "},
40 {31, nullptr, "GetPackage2Hash"}, 40 {31, nullptr, "PrepareEsArchiveKey"}, // This is also GetPackage2Hash?
41 {32, nullptr, "LoadPreparedAesKey"},
41 }; 42 };
42 RegisterHandlers(functions); 43 RegisterHandlers(functions);
43} 44}
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 4cf58a61a..13e4b3818 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -90,6 +90,13 @@ public:
90 : ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} { 90 : ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} {
91 static const FunctionInfo functions[] = { 91 static const FunctionInfo functions[] = {
92 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, 92 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
93 {2, nullptr, "GetTestOffset"},
94 {3, nullptr, "SetTestOffset"},
95 {100, nullptr, "GetRtcValue"},
96 {101, nullptr, "IsRtcResetDetected"},
97 {102, nullptr, "GetSetupResultValue"},
98 {200, nullptr, "GetInternalOffset"},
99 {201, nullptr, "SetInternalOffset"},
93 }; 100 };
94 RegisterHandlers(functions); 101 RegisterHandlers(functions);
95 } 102 }
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index 58a9845fc..d033f8603 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -20,7 +20,7 @@ public:
20 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
21 {0, nullptr, "GetDsEndpoint"}, 21 {0, nullptr, "GetDsEndpoint"},
22 {1, nullptr, "GetSetupEvent"}, 22 {1, nullptr, "GetSetupEvent"},
23 {2, nullptr, "Unknown"}, 23 {2, nullptr, "Unknown2"},
24 {3, nullptr, "EnableInterface"}, 24 {3, nullptr, "EnableInterface"},
25 {4, nullptr, "DisableInterface"}, 25 {4, nullptr, "DisableInterface"},
26 {5, nullptr, "CtrlInPostBufferAsync"}, 26 {5, nullptr, "CtrlInPostBufferAsync"},
@@ -55,6 +55,7 @@ public:
55 {9, nullptr, "SetBinaryObjectStore"}, 55 {9, nullptr, "SetBinaryObjectStore"},
56 {10, nullptr, "Enable"}, 56 {10, nullptr, "Enable"},
57 {11, nullptr, "Disable"}, 57 {11, nullptr, "Disable"},
58 {12, nullptr, "Unknown12"},
58 }; 59 };
59 // clang-format on 60 // clang-format on
60 61
@@ -69,13 +70,13 @@ public:
69 static const FunctionInfo functions[] = { 70 static const FunctionInfo functions[] = {
70 {0, nullptr, "Open"}, 71 {0, nullptr, "Open"},
71 {1, nullptr, "Close"}, 72 {1, nullptr, "Close"},
72 {2, nullptr, "Unknown1"}, 73 {2, nullptr, "Unknown2"},
73 {3, nullptr, "Populate"}, 74 {3, nullptr, "Populate"},
74 {4, nullptr, "PostBufferAsync"}, 75 {4, nullptr, "PostBufferAsync"},
75 {5, nullptr, "GetXferReport"}, 76 {5, nullptr, "GetXferReport"},
76 {6, nullptr, "PostBufferMultiAsync"}, 77 {6, nullptr, "PostBufferMultiAsync"},
77 {7, nullptr, "Unknown3"}, 78 {7, nullptr, "Unknown7"},
78 {8, nullptr, "Unknown4"}, 79 {8, nullptr, "Unknown8"},
79 }; 80 };
80 // clang-format on 81 // clang-format on
81 82
@@ -88,13 +89,13 @@ public:
88 explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} { 89 explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} {
89 // clang-format off 90 // clang-format off
90 static const FunctionInfo functions[] = { 91 static const FunctionInfo functions[] = {
91 {0, nullptr, "Unknown1"}, 92 {0, nullptr, "Unknown0"},
92 {1, nullptr, "SetInterface"}, 93 {1, nullptr, "SetInterface"},
93 {2, nullptr, "GetInterface"}, 94 {2, nullptr, "GetInterface"},
94 {3, nullptr, "GetAlternateInterface"}, 95 {3, nullptr, "GetAlternateInterface"},
95 {4, nullptr, "GetCurrentFrame"}, 96 {4, nullptr, "GetCurrentFrame"},
96 {5, nullptr, "CtrlXferAsync"}, 97 {5, nullptr, "CtrlXferAsync"},
97 {6, nullptr, "Unknown2"}, 98 {6, nullptr, "Unknown6"},
98 {7, nullptr, "GetCtrlXferReport"}, 99 {7, nullptr, "GetCtrlXferReport"},
99 {8, nullptr, "ResetDevice"}, 100 {8, nullptr, "ResetDevice"},
100 {9, nullptr, "OpenUsbEp"}, 101 {9, nullptr, "OpenUsbEp"},
@@ -118,7 +119,7 @@ public:
118 {5, nullptr, "DestroyInterfaceAvailableEvent"}, 119 {5, nullptr, "DestroyInterfaceAvailableEvent"},
119 {6, nullptr, "GetInterfaceStateChangeEvent"}, 120 {6, nullptr, "GetInterfaceStateChangeEvent"},
120 {7, nullptr, "AcquireUsbIf"}, 121 {7, nullptr, "AcquireUsbIf"},
121 {8, nullptr, "Unknown1"}, 122 {8, nullptr, "Unknown8"},
122 }; 123 };
123 // clang-format on 124 // clang-format on
124 125
@@ -179,8 +180,8 @@ public:
179 {4, nullptr, "GetFwRevision"}, 180 {4, nullptr, "GetFwRevision"},
180 {5, nullptr, "GetManufacturerId"}, 181 {5, nullptr, "GetManufacturerId"},
181 {6, nullptr, "GetDeviceId"}, 182 {6, nullptr, "GetDeviceId"},
182 {7, nullptr, "Unknown1"}, 183 {7, nullptr, "Unknown7"},
183 {8, nullptr, "Unknown2"}, 184 {8, nullptr, "Unknown8"},
184 }; 185 };
185 // clang-format on 186 // clang-format on
186 187
@@ -215,12 +216,12 @@ public:
215 explicit USB_PM() : ServiceFramework{"usb:pm"} { 216 explicit USB_PM() : ServiceFramework{"usb:pm"} {
216 // clang-format off 217 // clang-format off
217 static const FunctionInfo functions[] = { 218 static const FunctionInfo functions[] = {
218 {0, nullptr, "Unknown1"}, 219 {0, nullptr, "Unknown0"},
219 {1, nullptr, "Unknown2"}, 220 {1, nullptr, "Unknown1"},
220 {2, nullptr, "Unknown3"}, 221 {2, nullptr, "Unknown2"},
221 {3, nullptr, "Unknown4"}, 222 {3, nullptr, "Unknown3"},
222 {4, nullptr, "Unknown5"}, 223 {4, nullptr, "Unknown4"},
223 {5, nullptr, "Unknown6"}, 224 {5, nullptr, "Unknown5"},
224 }; 225 };
225 // clang-format on 226 // clang-format on
226 227
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 157092074..ea7b4ae13 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -519,9 +519,9 @@ private:
519 IGBPConnectRequestParcel request{ctx.ReadBuffer()}; 519 IGBPConnectRequestParcel request{ctx.ReadBuffer()};
520 IGBPConnectResponseParcel response{ 520 IGBPConnectResponseParcel response{
521 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) * 521 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
522 Settings::values.resolution_factor), 522 Settings::values.resolution_factor.GetValue()),
523 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) * 523 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
524 Settings::values.resolution_factor)}; 524 Settings::values.resolution_factor.GetValue())};
525 ctx.WriteBuffer(response.Serialize()); 525 ctx.WriteBuffer(response.Serialize());
526 break; 526 break;
527 } 527 }
@@ -700,6 +700,7 @@ public:
700 {3215, nullptr, "SetDisplayGamma"}, 700 {3215, nullptr, "SetDisplayGamma"},
701 {3216, nullptr, "GetDisplayCmuLuma"}, 701 {3216, nullptr, "GetDisplayCmuLuma"},
702 {3217, nullptr, "SetDisplayCmuLuma"}, 702 {3217, nullptr, "SetDisplayCmuLuma"},
703 {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
703 {8225, nullptr, "GetSharedBufferMemoryHandleId"}, 704 {8225, nullptr, "GetSharedBufferMemoryHandleId"},
704 {8250, nullptr, "OpenSharedLayer"}, 705 {8250, nullptr, "OpenSharedLayer"},
705 {8251, nullptr, "CloseSharedLayer"}, 706 {8251, nullptr, "CloseSharedLayer"},
@@ -748,14 +749,14 @@ private:
748 749
749 if (Settings::values.use_docked_mode) { 750 if (Settings::values.use_docked_mode) {
750 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * 751 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
751 static_cast<u32>(Settings::values.resolution_factor)); 752 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
752 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * 753 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
753 static_cast<u32>(Settings::values.resolution_factor)); 754 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
754 } else { 755 } else {
755 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) * 756 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
756 static_cast<u32>(Settings::values.resolution_factor)); 757 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
757 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) * 758 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
758 static_cast<u32>(Settings::values.resolution_factor)); 759 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
759 } 760 }
760 761
761 rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games. 762 rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
@@ -785,6 +786,7 @@ public:
785 {2300, nullptr, "AcquireLayerTexturePresentingEvent"}, 786 {2300, nullptr, "AcquireLayerTexturePresentingEvent"},
786 {2301, nullptr, "ReleaseLayerTexturePresentingEvent"}, 787 {2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
787 {2302, nullptr, "GetDisplayHotplugEvent"}, 788 {2302, nullptr, "GetDisplayHotplugEvent"},
789 {2303, nullptr, "GetDisplayModeChangedEvent"},
788 {2402, nullptr, "GetDisplayHotplugState"}, 790 {2402, nullptr, "GetDisplayHotplugState"},
789 {2501, nullptr, "GetCompositorErrorInfo"}, 791 {2501, nullptr, "GetCompositorErrorInfo"},
790 {2601, nullptr, "GetDisplayErrorEvent"}, 792 {2601, nullptr, "GetDisplayErrorEvent"},
@@ -1029,9 +1031,9 @@ private:
1029 // between docked and undocked dimensions. We take the liberty of applying 1031 // between docked and undocked dimensions. We take the liberty of applying
1030 // the resolution scaling factor here. 1032 // the resolution scaling factor here.
1031 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) * 1033 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
1032 static_cast<u32>(Settings::values.resolution_factor)); 1034 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
1033 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) * 1035 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
1034 static_cast<u32>(Settings::values.resolution_factor)); 1036 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
1035 } 1037 }
1036 1038
1037 void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { 1039 void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
@@ -1064,8 +1066,8 @@ private:
1064 LOG_WARNING(Service_VI, "(STUBBED) called"); 1066 LOG_WARNING(Service_VI, "(STUBBED) called");
1065 1067
1066 DisplayInfo display_info; 1068 DisplayInfo display_info;
1067 display_info.width *= static_cast<u64>(Settings::values.resolution_factor); 1069 display_info.width *= static_cast<u64>(Settings::values.resolution_factor.GetValue());
1068 display_info.height *= static_cast<u64>(Settings::values.resolution_factor); 1070 display_info.height *= static_cast<u64>(Settings::values.resolution_factor.GetValue());
1069 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); 1071 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
1070 IPC::ResponseBuilder rb{ctx, 4}; 1072 IPC::ResponseBuilder rb{ctx, 4};
1071 rb.Push(RESULT_SUCCESS); 1073 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index 9d5ceb608..6b7329345 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -12,6 +12,7 @@ VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger)
12 : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { 12 : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} {
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, &VI_U::GetDisplayService, "GetDisplayService"}, 14 {0, &VI_U::GetDisplayService, "GetDisplayService"},
15 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
15 }; 16 };
16 RegisterHandlers(functions); 17 RegisterHandlers(functions);
17} 18}
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
index 2654594c1..0260d7dcf 100644
--- a/src/core/hle/service/wlan/wlan.cpp
+++ b/src/core/hle/service/wlan/wlan.cpp
@@ -15,34 +15,37 @@ public:
15 explicit WLANInfra() : ServiceFramework{"wlan:inf"} { 15 explicit WLANInfra() : ServiceFramework{"wlan:inf"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "Unknown1"}, 18 {0, nullptr, "OpenMode"},
19 {1, nullptr, "Unknown2"}, 19 {1, nullptr, "CloseMode"},
20 {2, nullptr, "GetMacAddress"}, 20 {2, nullptr, "GetMacAddress"},
21 {3, nullptr, "StartScan"}, 21 {3, nullptr, "StartScan"},
22 {4, nullptr, "StopScan"}, 22 {4, nullptr, "StopScan"},
23 {5, nullptr, "Connect"}, 23 {5, nullptr, "Connect"},
24 {6, nullptr, "CancelConnect"}, 24 {6, nullptr, "CancelConnect"},
25 {7, nullptr, "Disconnect"}, 25 {7, nullptr, "Disconnect"},
26 {8, nullptr, "Unknown3"}, 26 {8, nullptr, "GetConnectionEvent"},
27 {9, nullptr, "Unknown4"}, 27 {9, nullptr, "GetConnectionStatus"},
28 {10, nullptr, "GetState"}, 28 {10, nullptr, "GetState"},
29 {11, nullptr, "GetScanResult"}, 29 {11, nullptr, "GetScanResult"},
30 {12, nullptr, "GetRssi"}, 30 {12, nullptr, "GetRssi"},
31 {13, nullptr, "ChangeRxAntenna"}, 31 {13, nullptr, "ChangeRxAntenna"},
32 {14, nullptr, "Unknown5"}, 32 {14, nullptr, "GetFwVersion"},
33 {15, nullptr, "Unknown6"}, 33 {15, nullptr, "RequestSleep"},
34 {16, nullptr, "RequestWakeUp"}, 34 {16, nullptr, "RequestWakeUp"},
35 {17, nullptr, "RequestIfUpDown"}, 35 {17, nullptr, "RequestIfUpDown"},
36 {18, nullptr, "Unknown7"}, 36 {18, nullptr, "Unknown18"},
37 {19, nullptr, "Unknown8"}, 37 {19, nullptr, "Unknown19"},
38 {20, nullptr, "Unknown9"}, 38 {20, nullptr, "Unknown20"},
39 {21, nullptr, "Unknown10"}, 39 {21, nullptr, "Unknown21"},
40 {22, nullptr, "Unknown11"}, 40 {22, nullptr, "Unknown22"},
41 {23, nullptr, "Unknown12"}, 41 {23, nullptr, "Unknown23"},
42 {24, nullptr, "Unknown13"}, 42 {24, nullptr, "Unknown24"},
43 {25, nullptr, "Unknown14"}, 43 {25, nullptr, "Unknown25"},
44 {26, nullptr, "Unknown15"}, 44 {26, nullptr, "Unknown26"},
45 {27, nullptr, "Unknown16"}, 45 {27, nullptr, "Unknown27"},
46 {28, nullptr, "Unknown28"},
47 {29, nullptr, "Unknown29"},
48 {30, nullptr, "Unknown30"},
46 }; 49 };
47 // clang-format on 50 // clang-format on
48 51
@@ -55,12 +58,12 @@ public:
55 explicit WLANLocal() : ServiceFramework{"wlan:lcl"} { 58 explicit WLANLocal() : ServiceFramework{"wlan:lcl"} {
56 // clang-format off 59 // clang-format off
57 static const FunctionInfo functions[] = { 60 static const FunctionInfo functions[] = {
58 {0, nullptr, "Unknown1"}, 61 {0, nullptr, "Unknown0"},
59 {1, nullptr, "Unknown2"}, 62 {1, nullptr, "Unknown1"},
60 {2, nullptr, "Unknown3"}, 63 {2, nullptr, "Unknown2"},
61 {3, nullptr, "Unknown4"}, 64 {3, nullptr, "Unknown3"},
62 {4, nullptr, "Unknown5"}, 65 {4, nullptr, "Unknown4"},
63 {5, nullptr, "Unknown6"}, 66 {5, nullptr, "Unknown5"},
64 {6, nullptr, "GetMacAddress"}, 67 {6, nullptr, "GetMacAddress"},
65 {7, nullptr, "CreateBss"}, 68 {7, nullptr, "CreateBss"},
66 {8, nullptr, "DestroyBss"}, 69 {8, nullptr, "DestroyBss"},
@@ -72,38 +75,42 @@ public:
72 {14, nullptr, "CancelJoin"}, 75 {14, nullptr, "CancelJoin"},
73 {15, nullptr, "Disconnect"}, 76 {15, nullptr, "Disconnect"},
74 {16, nullptr, "SetBeaconLostCount"}, 77 {16, nullptr, "SetBeaconLostCount"},
75 {17, nullptr, "Unknown7"}, 78 {17, nullptr, "Unknown17"},
76 {18, nullptr, "Unknown8"}, 79 {18, nullptr, "Unknown18"},
77 {19, nullptr, "Unknown9"}, 80 {19, nullptr, "Unknown19"},
78 {20, nullptr, "GetBssIndicationEvent"}, 81 {20, nullptr, "GetBssIndicationEvent"},
79 {21, nullptr, "GetBssIndicationInfo"}, 82 {21, nullptr, "GetBssIndicationInfo"},
80 {22, nullptr, "GetState"}, 83 {22, nullptr, "GetState"},
81 {23, nullptr, "GetAllowedChannels"}, 84 {23, nullptr, "GetAllowedChannels"},
82 {24, nullptr, "AddIe"}, 85 {24, nullptr, "AddIe"},
83 {25, nullptr, "DeleteIe"}, 86 {25, nullptr, "DeleteIe"},
84 {26, nullptr, "Unknown10"}, 87 {26, nullptr, "Unknown26"},
85 {27, nullptr, "Unknown11"}, 88 {27, nullptr, "Unknown27"},
86 {28, nullptr, "CreateRxEntry"}, 89 {28, nullptr, "CreateRxEntry"},
87 {29, nullptr, "DeleteRxEntry"}, 90 {29, nullptr, "DeleteRxEntry"},
88 {30, nullptr, "Unknown12"}, 91 {30, nullptr, "Unknown30"},
89 {31, nullptr, "Unknown13"}, 92 {31, nullptr, "Unknown31"},
90 {32, nullptr, "AddMatchingDataToRxEntry"}, 93 {32, nullptr, "AddMatchingDataToRxEntry"},
91 {33, nullptr, "RemoveMatchingDataFromRxEntry"}, 94 {33, nullptr, "RemoveMatchingDataFromRxEntry"},
92 {34, nullptr, "GetScanResult"}, 95 {34, nullptr, "GetScanResult"},
93 {35, nullptr, "Unknown14"}, 96 {35, nullptr, "Unknown35"},
94 {36, nullptr, "SetActionFrameWithBeacon"}, 97 {36, nullptr, "SetActionFrameWithBeacon"},
95 {37, nullptr, "CancelActionFrameWithBeacon"}, 98 {37, nullptr, "CancelActionFrameWithBeacon"},
96 {38, nullptr, "CreateRxEntryForActionFrame"}, 99 {38, nullptr, "CreateRxEntryForActionFrame"},
97 {39, nullptr, "DeleteRxEntryForActionFrame"}, 100 {39, nullptr, "DeleteRxEntryForActionFrame"},
98 {40, nullptr, "Unknown15"}, 101 {40, nullptr, "Unknown40"},
99 {41, nullptr, "Unknown16"}, 102 {41, nullptr, "Unknown41"},
100 {42, nullptr, "CancelGetActionFrame"}, 103 {42, nullptr, "CancelGetActionFrame"},
101 {43, nullptr, "GetRssi"}, 104 {43, nullptr, "GetRssi"},
102 {44, nullptr, "Unknown17"}, 105 {44, nullptr, "Unknown44"},
103 {45, nullptr, "Unknown18"}, 106 {45, nullptr, "Unknown45"},
104 {46, nullptr, "Unknown19"}, 107 {46, nullptr, "Unknown46"},
105 {47, nullptr, "Unknown20"}, 108 {47, nullptr, "Unknown47"},
106 {48, nullptr, "Unknown21"}, 109 {48, nullptr, "Unknown48"},
110 {49, nullptr, "Unknown49"},
111 {50, nullptr, "Unknown50"},
112 {51, nullptr, "Unknown51"},
113 {52, nullptr, "Unknown52"},
107 }; 114 };
108 // clang-format on 115 // clang-format on
109 116
@@ -142,18 +149,19 @@ public:
142 explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} { 149 explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} {
143 // clang-format off 150 // clang-format off
144 static const FunctionInfo functions[] = { 151 static const FunctionInfo functions[] = {
145 {0, nullptr, "Unknown1"}, 152 {0, nullptr, "Unknown0"},
146 {1, nullptr, "Unknown2"}, 153 {1, nullptr, "Unknown1"},
147 {2, nullptr, "Unknown3"}, 154 {2, nullptr, "Unknown2"},
148 {3, nullptr, "Unknown4"}, 155 {3, nullptr, "Unknown3"},
149 {4, nullptr, "Unknown5"}, 156 {4, nullptr, "Unknown4"},
150 {5, nullptr, "Unknown6"}, 157 {5, nullptr, "Unknown5"},
151 {6, nullptr, "GetMacAddress"}, 158 {6, nullptr, "GetMacAddress"},
152 {7, nullptr, "SwitchTsfTimerFunction"}, 159 {7, nullptr, "SwitchTsfTimerFunction"},
153 {8, nullptr, "Unknown7"}, 160 {8, nullptr, "Unknown8"},
154 {9, nullptr, "Unknown8"}, 161 {9, nullptr, "Unknown9"},
155 {10, nullptr, "Unknown9"}, 162 {10, nullptr, "Unknown10"},
156 {11, nullptr, "Unknown10"}, 163 {11, nullptr, "Unknown11"},
164 {12, nullptr, "Unknown12"},
157 }; 165 };
158 // clang-format on 166 // clang-format on
159 167
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index 9f3a6b811..29339ead7 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -119,13 +119,14 @@ double PerfStats::GetLastFrameTimeScale() {
119} 119}
120 120
121void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) { 121void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
122 if (!Settings::values.use_frame_limit || Settings::values.use_multi_core) { 122 if (!Settings::values.use_frame_limit.GetValue() ||
123 Settings::values.use_multi_core.GetValue()) {
123 return; 124 return;
124 } 125 }
125 126
126 auto now = Clock::now(); 127 auto now = Clock::now();
127 128
128 const double sleep_scale = Settings::values.frame_limit / 100.0; 129 const double sleep_scale = Settings::values.frame_limit.GetValue() / 100.0;
129 130
130 // Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current 131 // Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
131 // speed percent or it will clamp too much and prevent this from properly limiting to that 132 // speed percent or it will clamp too much and prevent this from properly limiting to that
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 56df5e925..d3886c4ec 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -62,6 +62,7 @@ const std::array<const char*, NumMouseButtons> mapping = {{
62} 62}
63 63
64Values values = {}; 64Values values = {};
65bool configuring_global = true;
65 66
66std::string GetTimeZoneString() { 67std::string GetTimeZoneString() {
67 static constexpr std::array<const char*, 46> timezones{{ 68 static constexpr std::array<const char*, 46> timezones{{
@@ -73,9 +74,9 @@ std::string GetTimeZoneString() {
73 "UCT", "Universal", "UTC", "W-SU", "WET", "Zulu", 74 "UCT", "Universal", "UTC", "W-SU", "WET", "Zulu",
74 }}; 75 }};
75 76
76 ASSERT(Settings::values.time_zone_index < timezones.size()); 77 ASSERT(Settings::values.time_zone_index.GetValue() < timezones.size());
77 78
78 return timezones[Settings::values.time_zone_index]; 79 return timezones[Settings::values.time_zone_index.GetValue()];
79} 80}
80 81
81void Apply() { 82void Apply() {
@@ -97,25 +98,25 @@ void LogSetting(const std::string& name, const T& value) {
97 98
98void LogSettings() { 99void LogSettings() {
99 LOG_INFO(Config, "yuzu Configuration:"); 100 LOG_INFO(Config, "yuzu Configuration:");
100 LogSetting("System_UseDockedMode", Settings::values.use_docked_mode); 101 LogSetting("Controls_UseDockedMode", Settings::values.use_docked_mode);
101 LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0)); 102 LogSetting("System_RngSeed", Settings::values.rng_seed.GetValue().value_or(0));
102 LogSetting("System_CurrentUser", Settings::values.current_user); 103 LogSetting("System_CurrentUser", Settings::values.current_user);
103 LogSetting("System_LanguageIndex", Settings::values.language_index); 104 LogSetting("System_LanguageIndex", Settings::values.language_index.GetValue());
104 LogSetting("System_RegionIndex", Settings::values.region_index); 105 LogSetting("System_RegionIndex", Settings::values.region_index.GetValue());
105 LogSetting("System_TimeZoneIndex", Settings::values.time_zone_index); 106 LogSetting("System_TimeZoneIndex", Settings::values.time_zone_index.GetValue());
106 LogSetting("Core_UseMultiCore", Settings::values.use_multi_core); 107 LogSetting("Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
107 LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); 108 LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor.GetValue());
108 LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); 109 LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue());
109 LogSetting("Renderer_FrameLimit", Settings::values.frame_limit); 110 LogSetting("Renderer_FrameLimit", Settings::values.frame_limit.GetValue());
110 LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache); 111 LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache.GetValue());
111 LogSetting("Renderer_GPUAccuracyLevel", Settings::values.gpu_accuracy); 112 LogSetting("Renderer_GPUAccuracyLevel", Settings::values.gpu_accuracy.GetValue());
112 LogSetting("Renderer_UseAsynchronousGpuEmulation", 113 LogSetting("Renderer_UseAsynchronousGpuEmulation",
113 Settings::values.use_asynchronous_gpu_emulation); 114 Settings::values.use_asynchronous_gpu_emulation.GetValue());
114 LogSetting("Renderer_UseVsync", Settings::values.use_vsync); 115 LogSetting("Renderer_UseVsync", Settings::values.use_vsync.GetValue());
115 LogSetting("Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders); 116 LogSetting("Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders.GetValue());
116 LogSetting("Renderer_AnisotropicFilteringLevel", Settings::values.max_anisotropy); 117 LogSetting("Renderer_AnisotropicFilteringLevel", Settings::values.max_anisotropy.GetValue());
117 LogSetting("Audio_OutputEngine", Settings::values.sink_id); 118 LogSetting("Audio_OutputEngine", Settings::values.sink_id);
118 LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); 119 LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching.GetValue());
119 LogSetting("Audio_OutputDevice", Settings::values.audio_device_id); 120 LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);
120 LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd); 121 LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd);
121 LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)); 122 LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
@@ -131,15 +132,56 @@ float Volume() {
131 if (values.audio_muted) { 132 if (values.audio_muted) {
132 return 0.0f; 133 return 0.0f;
133 } 134 }
134 return values.volume; 135 return values.volume.GetValue();
135} 136}
136 137
137bool IsGPULevelExtreme() { 138bool IsGPULevelExtreme() {
138 return values.gpu_accuracy == GPUAccuracy::Extreme; 139 return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme;
139} 140}
140 141
141bool IsGPULevelHigh() { 142bool IsGPULevelHigh() {
142 return values.gpu_accuracy == GPUAccuracy::Extreme || values.gpu_accuracy == GPUAccuracy::High; 143 return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme ||
144 values.gpu_accuracy.GetValue() == GPUAccuracy::High;
145}
146
147void RestoreGlobalState() {
148 // If a game is running, DO NOT restore the global settings state
149 if (Core::System::GetInstance().IsPoweredOn()) {
150 return;
151 }
152
153 // Audio
154 values.enable_audio_stretching.SetGlobal(true);
155 values.volume.SetGlobal(true);
156
157 // Core
158 values.use_multi_core.SetGlobal(true);
159
160 // Renderer
161 values.renderer_backend.SetGlobal(true);
162 values.vulkan_device.SetGlobal(true);
163 values.aspect_ratio.SetGlobal(true);
164 values.max_anisotropy.SetGlobal(true);
165 values.use_frame_limit.SetGlobal(true);
166 values.frame_limit.SetGlobal(true);
167 values.use_disk_shader_cache.SetGlobal(true);
168 values.gpu_accuracy.SetGlobal(true);
169 values.use_asynchronous_gpu_emulation.SetGlobal(true);
170 values.use_vsync.SetGlobal(true);
171 values.use_assembly_shaders.SetGlobal(true);
172 values.use_fast_gpu_time.SetGlobal(true);
173 values.force_30fps_mode.SetGlobal(true);
174 values.bg_red.SetGlobal(true);
175 values.bg_green.SetGlobal(true);
176 values.bg_blue.SetGlobal(true);
177
178 // System
179 values.language_index.SetGlobal(true);
180 values.region_index.SetGlobal(true);
181 values.time_zone_index.SetGlobal(true);
182 values.rng_seed.SetGlobal(true);
183 values.custom_rtc.SetGlobal(true);
184 values.sound_index.SetGlobal(true);
143} 185}
144 186
145} // namespace Settings 187} // namespace Settings
diff --git a/src/core/settings.h b/src/core/settings.h
index a598ccbc1..3eb336f75 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -346,31 +346,6 @@ struct TouchscreenInput {
346 u32 rotation_angle; 346 u32 rotation_angle;
347}; 347};
348 348
349enum class NANDTotalSize : u64 {
350 S29_1GB = 0x747C00000ULL,
351};
352
353enum class NANDUserSize : u64 {
354 S26GB = 0x680000000ULL,
355};
356
357enum class NANDSystemSize : u64 {
358 S2_5GB = 0xA0000000,
359};
360
361enum class SDMCSize : u64 {
362 S1GB = 0x40000000,
363 S2GB = 0x80000000,
364 S4GB = 0x100000000ULL,
365 S8GB = 0x200000000ULL,
366 S16GB = 0x400000000ULL,
367 S32GB = 0x800000000ULL,
368 S64GB = 0x1000000000ULL,
369 S128GB = 0x2000000000ULL,
370 S256GB = 0x4000000000ULL,
371 S1TB = 0x10000000000ULL,
372};
373
374enum class RendererBackend { 349enum class RendererBackend {
375 OpenGL = 0, 350 OpenGL = 0,
376 Vulkan = 1, 351 Vulkan = 1,
@@ -382,20 +357,102 @@ enum class GPUAccuracy : u32 {
382 Extreme = 2, 357 Extreme = 2,
383}; 358};
384 359
360enum class CPUAccuracy {
361 Accurate = 0,
362 DebugMode = 1,
363};
364
365extern bool configuring_global;
366
367template <typename Type>
368class Setting final {
369public:
370 Setting() = default;
371 explicit Setting(Type val) : global{val} {}
372 ~Setting() = default;
373 void SetGlobal(bool to_global) {
374 use_global = to_global;
375 }
376 bool UsingGlobal() const {
377 return use_global;
378 }
379 Type GetValue(bool need_global = false) const {
380 if (use_global || need_global) {
381 return global;
382 }
383 return local;
384 }
385 void SetValue(const Type& value) {
386 if (use_global) {
387 global = value;
388 } else {
389 local = value;
390 }
391 }
392
393private:
394 bool use_global = true;
395 Type global{};
396 Type local{};
397};
398
385struct Values { 399struct Values {
400 // Audio
401 std::string audio_device_id;
402 std::string sink_id;
403 bool audio_muted;
404 Setting<bool> enable_audio_stretching;
405 Setting<float> volume;
406
407 // Core
408 Setting<bool> use_multi_core;
409
410 // Cpu
411 CPUAccuracy cpu_accuracy;
412
413 bool cpuopt_page_tables;
414 bool cpuopt_block_linking;
415 bool cpuopt_return_stack_buffer;
416 bool cpuopt_fast_dispatcher;
417 bool cpuopt_context_elimination;
418 bool cpuopt_const_prop;
419 bool cpuopt_misc_ir;
420 bool cpuopt_reduce_misalign_checks;
421
422 // Renderer
423 Setting<RendererBackend> renderer_backend;
424 bool renderer_debug;
425 Setting<int> vulkan_device;
426
427 Setting<u16> resolution_factor = Setting(static_cast<u16>(1));
428 Setting<int> aspect_ratio;
429 Setting<int> max_anisotropy;
430 Setting<bool> use_frame_limit;
431 Setting<u16> frame_limit;
432 Setting<bool> use_disk_shader_cache;
433 Setting<GPUAccuracy> gpu_accuracy;
434 Setting<bool> use_asynchronous_gpu_emulation;
435 Setting<bool> use_vsync;
436 Setting<bool> use_assembly_shaders;
437 Setting<bool> force_30fps_mode;
438 Setting<bool> use_fast_gpu_time;
439
440 Setting<float> bg_red;
441 Setting<float> bg_green;
442 Setting<float> bg_blue;
443
386 // System 444 // System
387 bool use_docked_mode; 445 Setting<std::optional<u32>> rng_seed;
388 std::optional<u32> rng_seed;
389 // Measured in seconds since epoch 446 // Measured in seconds since epoch
390 std::optional<std::chrono::seconds> custom_rtc; 447 Setting<std::optional<std::chrono::seconds>> custom_rtc;
391 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 448 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
392 std::chrono::seconds custom_rtc_differential; 449 std::chrono::seconds custom_rtc_differential;
393 450
394 s32 current_user; 451 s32 current_user;
395 s32 language_index; 452 Setting<s32> language_index;
396 s32 region_index; 453 Setting<s32> region_index;
397 s32 time_zone_index; 454 Setting<s32> time_zone_index;
398 s32 sound_index; 455 Setting<s32> sound_index;
399 456
400 // Controls 457 // Controls
401 std::array<PlayerInput, 10> players; 458 std::array<PlayerInput, 10> players;
@@ -419,51 +476,13 @@ struct Values {
419 u16 udp_input_port; 476 u16 udp_input_port;
420 u8 udp_pad_index; 477 u8 udp_pad_index;
421 478
422 // Core 479 bool use_docked_mode;
423 bool use_multi_core;
424 480
425 // Data Storage 481 // Data Storage
426 bool use_virtual_sd; 482 bool use_virtual_sd;
427 bool gamecard_inserted; 483 bool gamecard_inserted;
428 bool gamecard_current_game; 484 bool gamecard_current_game;
429 std::string gamecard_path; 485 std::string gamecard_path;
430 NANDTotalSize nand_total_size;
431 NANDSystemSize nand_system_size;
432 NANDUserSize nand_user_size;
433 SDMCSize sdmc_size;
434
435 // Renderer
436 RendererBackend renderer_backend;
437 bool renderer_debug;
438 int vulkan_device;
439
440 u16 resolution_factor{1};
441 int aspect_ratio;
442 int max_anisotropy;
443 bool use_frame_limit;
444 u16 frame_limit;
445 bool use_disk_shader_cache;
446 GPUAccuracy gpu_accuracy;
447 bool use_asynchronous_gpu_emulation;
448 bool use_vsync;
449 bool use_assembly_shaders;
450 bool force_30fps_mode;
451 bool use_fast_gpu_time;
452
453 float bg_red;
454 float bg_green;
455 float bg_blue;
456
457 std::string log_filter;
458
459 bool use_dev_keys;
460
461 // Audio
462 bool audio_muted;
463 std::string sink_id;
464 bool enable_audio_stretching;
465 std::string audio_device_id;
466 float volume;
467 486
468 // Debugging 487 // Debugging
469 bool record_frame_times; 488 bool record_frame_times;
@@ -474,10 +493,13 @@ struct Values {
474 bool dump_nso; 493 bool dump_nso;
475 bool reporting_services; 494 bool reporting_services;
476 bool quest_flag; 495 bool quest_flag;
477 bool disable_cpu_opt;
478 bool disable_macro_jit; 496 bool disable_macro_jit;
479 497
480 // BCAT 498 // Misceallaneous
499 std::string log_filter;
500 bool use_dev_keys;
501
502 // Services
481 std::string bcat_backend; 503 std::string bcat_backend;
482 bool bcat_boxcat_local; 504 bool bcat_boxcat_local;
483 505
@@ -501,4 +523,7 @@ std::string GetTimeZoneString();
501void Apply(); 523void Apply();
502void LogSettings(); 524void LogSettings();
503 525
526// Restore the global state of all applicable settings in the Values struct
527void RestoreGlobalState();
528
504} // namespace Settings 529} // namespace Settings
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index c781b3cfc..78915e6db 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -189,19 +189,24 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
189 // Log user configuration information 189 // Log user configuration information
190 constexpr auto field_type = Telemetry::FieldType::UserConfig; 190 constexpr auto field_type = Telemetry::FieldType::UserConfig;
191 AddField(field_type, "Audio_SinkId", Settings::values.sink_id); 191 AddField(field_type, "Audio_SinkId", Settings::values.sink_id);
192 AddField(field_type, "Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); 192 AddField(field_type, "Audio_EnableAudioStretching",
193 AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core); 193 Settings::values.enable_audio_stretching.GetValue());
194 AddField(field_type, "Renderer_Backend", TranslateRenderer(Settings::values.renderer_backend)); 194 AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
195 AddField(field_type, "Renderer_ResolutionFactor", Settings::values.resolution_factor); 195 AddField(field_type, "Renderer_Backend",
196 AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit); 196 TranslateRenderer(Settings::values.renderer_backend.GetValue()));
197 AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit); 197 AddField(field_type, "Renderer_ResolutionFactor",
198 AddField(field_type, "Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache); 198 Settings::values.resolution_factor.GetValue());
199 AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue());
200 AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit.GetValue());
201 AddField(field_type, "Renderer_UseDiskShaderCache",
202 Settings::values.use_disk_shader_cache.GetValue());
199 AddField(field_type, "Renderer_GPUAccuracyLevel", 203 AddField(field_type, "Renderer_GPUAccuracyLevel",
200 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy)); 204 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue()));
201 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", 205 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
202 Settings::values.use_asynchronous_gpu_emulation); 206 Settings::values.use_asynchronous_gpu_emulation.GetValue());
203 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync); 207 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
204 AddField(field_type, "Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders); 208 AddField(field_type, "Renderer_UseAssemblyShaders",
209 Settings::values.use_assembly_shaders.GetValue());
205 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); 210 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode);
206} 211}
207 212
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 3bd76dd23..317c25bad 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -30,7 +30,8 @@ if(SDL2_FOUND)
30 target_compile_definitions(input_common PRIVATE HAVE_SDL2) 30 target_compile_definitions(input_common PRIVATE HAVE_SDL2)
31endif() 31endif()
32 32
33target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES}) 33target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR})
34target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES})
34 35
35create_target_directory_groups(input_common) 36create_target_directory_groups(input_common)
36target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) 37target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost)
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index 05607e033..898a278a9 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -4,6 +4,7 @@
4 4
5#include <chrono> 5#include <chrono>
6#include <thread> 6#include <thread>
7#include <libusb.h>
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "input_common/gcadapter/gc_adapter.h" 9#include "input_common/gcadapter/gc_adapter.h"
9 10
@@ -34,7 +35,7 @@ Adapter::Adapter() {
34 } 35 }
35} 36}
36 37
37GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) { 38GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) {
38 GCPadStatus pad = {}; 39 GCPadStatus pad = {};
39 40
40 ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); 41 ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4);
@@ -205,7 +206,7 @@ void Adapter::StartScanThread() {
205 } 206 }
206 207
207 detect_thread_running = true; 208 detect_thread_running = true;
208 detect_thread = std::thread([=] { ScanThreadFunc(); }); 209 detect_thread = std::thread(&Adapter::ScanThreadFunc, this);
209} 210}
210 211
211void Adapter::StopScanThread() { 212void Adapter::StopScanThread() {
@@ -234,7 +235,7 @@ void Adapter::Setup() {
234 } 235 }
235 236
236 if (devices != nullptr) { 237 if (devices != nullptr) {
237 for (std::size_t index = 0; index < device_count; ++index) { 238 for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) {
238 if (CheckDeviceAccess(devices[index])) { 239 if (CheckDeviceAccess(devices[index])) {
239 // GC Adapter found and accessible, registering it 240 // GC Adapter found and accessible, registering it
240 GetGCEndpoint(devices[index]); 241 GetGCEndpoint(devices[index]);
@@ -368,11 +369,11 @@ void Adapter::Reset() {
368 } 369 }
369} 370}
370 371
371bool Adapter::DeviceConnected(int port) { 372bool Adapter::DeviceConnected(std::size_t port) {
372 return adapter_controllers_status[port] != ControllerTypes::None; 373 return adapter_controllers_status[port] != ControllerTypes::None;
373} 374}
374 375
375void Adapter::ResetDeviceType(int port) { 376void Adapter::ResetDeviceType(std::size_t port) {
376 adapter_controllers_status[port] = ControllerTypes::None; 377 adapter_controllers_status[port] = ControllerTypes::None;
377} 378}
378 379
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index a67485586..3586c8bda 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -8,10 +8,13 @@
8#include <mutex> 8#include <mutex>
9#include <thread> 9#include <thread>
10#include <unordered_map> 10#include <unordered_map>
11#include <libusb.h>
12#include "common/common_types.h" 11#include "common/common_types.h"
13#include "common/threadsafe_queue.h" 12#include "common/threadsafe_queue.h"
14 13
14struct libusb_context;
15struct libusb_device;
16struct libusb_device_handle;
17
15namespace GCAdapter { 18namespace GCAdapter {
16 19
17enum class PadButton { 20enum class PadButton {
@@ -91,6 +94,9 @@ public:
91 void BeginConfiguration(); 94 void BeginConfiguration();
92 void EndConfiguration(); 95 void EndConfiguration();
93 96
97 /// Returns true if there is a device connected to port
98 bool DeviceConnected(std::size_t port);
99
94 std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); 100 std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
95 const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; 101 const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
96 102
@@ -100,7 +106,7 @@ public:
100 int GetOriginValue(int port, int axis) const; 106 int GetOriginValue(int port, int axis) const;
101 107
102private: 108private:
103 GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload); 109 GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
104 110
105 void PadToState(const GCPadStatus& pad, GCState& state); 111 void PadToState(const GCPadStatus& pad, GCState& state);
106 112
@@ -112,11 +118,8 @@ private:
112 /// Stop scanning for the adapter 118 /// Stop scanning for the adapter
113 void StopScanThread(); 119 void StopScanThread();
114 120
115 /// Returns true if there is a device connected to port
116 bool DeviceConnected(int port);
117
118 /// Resets status of device connected to port 121 /// Resets status of device connected to port
119 void ResetDeviceType(int port); 122 void ResetDeviceType(std::size_t port);
120 123
121 /// Returns true if we successfully gain access to GC Adapter 124 /// Returns true if we successfully gain access to GC Adapter
122 bool CheckDeviceAccess(libusb_device* device); 125 bool CheckDeviceAccess(libusb_device* device);
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index ad321e933..96e22d3ad 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -6,6 +6,7 @@
6#include <list> 6#include <list>
7#include <mutex> 7#include <mutex>
8#include <utility> 8#include <utility>
9#include "common/assert.h"
9#include "common/threadsafe_queue.h" 10#include "common/threadsafe_queue.h"
10#include "input_common/gcadapter/gc_adapter.h" 11#include "input_common/gcadapter/gc_adapter.h"
11#include "input_common/gcadapter/gc_poller.h" 12#include "input_common/gcadapter/gc_poller.h"
@@ -20,7 +21,10 @@ public:
20 ~GCButton() override; 21 ~GCButton() override;
21 22
22 bool GetStatus() const override { 23 bool GetStatus() const override {
23 return gcadapter->GetPadState()[port].buttons.at(button); 24 if (gcadapter->DeviceConnected(port)) {
25 return gcadapter->GetPadState()[port].buttons.at(button);
26 }
27 return false;
24 } 28 }
25 29
26private: 30private:
@@ -37,14 +41,17 @@ public:
37 gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} 41 gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {}
38 42
39 bool GetStatus() const override { 43 bool GetStatus() const override {
40 const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis); 44 if (gcadapter->DeviceConnected(port)) {
41 const float axis_value = (current_axis_value - origin_value) / 128.0f; 45 const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis);
42 if (trigger_if_greater) { 46 const float axis_value = (current_axis_value - origin_value) / 128.0f;
43 // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently 47 if (trigger_if_greater) {
44 // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick 48 // TODO: Might be worthwile to set a slider for the trigger threshold. It is
45 return axis_value > threshold; 49 // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
50 return axis_value > threshold;
51 }
52 return axis_value < -threshold;
46 } 53 }
47 return axis_value < -threshold; 54 return false;
48 } 55 }
49 56
50private: 57private:
@@ -90,9 +97,12 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
90 return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, 97 return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater,
91 adapter.get()); 98 adapter.get());
92 } 99 }
100
101 UNREACHABLE();
102 return nullptr;
93} 103}
94 104
95Common::ParamPackage GCButtonFactory::GetNextInput() { 105Common::ParamPackage GCButtonFactory::GetNextInput() const {
96 Common::ParamPackage params; 106 Common::ParamPackage params;
97 GCAdapter::GCPadStatus pad; 107 GCAdapter::GCPadStatus pad;
98 auto& queue = adapter->GetPadQueue(); 108 auto& queue = adapter->GetPadQueue();
@@ -145,12 +155,15 @@ public:
145 origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} 155 origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {}
146 156
147 float GetAxis(int axis) const { 157 float GetAxis(int axis) const {
148 std::lock_guard lock{mutex}; 158 if (gcadapter->DeviceConnected(port)) {
149 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; 159 std::lock_guard lock{mutex};
150 // division is not by a perfect 128 to account for some variance in center location 160 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
151 // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range 161 // division is not by a perfect 128 to account for some variance in center location
152 // [20-230] 162 // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
153 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f; 163 // [20-230]
164 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
165 }
166 return 0.0f;
154 } 167 }
155 168
156 std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { 169 std::pair<float, float> GetAnalog(int axis_x, int axis_y) const {
@@ -250,7 +263,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
250 const u8 axis = static_cast<u8>(pad.axis); 263 const u8 axis = static_cast<u8>(pad.axis);
251 if (analog_x_axis == -1) { 264 if (analog_x_axis == -1) {
252 analog_x_axis = axis; 265 analog_x_axis = axis;
253 controller_number = port; 266 controller_number = static_cast<int>(port);
254 } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) { 267 } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) {
255 analog_y_axis = axis; 268 analog_y_axis = axis;
256 } 269 }
diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h
index e96af7d51..0527f328f 100644
--- a/src/input_common/gcadapter/gc_poller.h
+++ b/src/input_common/gcadapter/gc_poller.h
@@ -25,7 +25,7 @@ public:
25 */ 25 */
26 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; 26 std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override;
27 27
28 Common::ParamPackage GetNextInput(); 28 Common::ParamPackage GetNextInput() const;
29 29
30 /// For device input configuration/polling 30 /// For device input configuration/polling
31 void BeginConfiguration(); 31 void BeginConfiguration();
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index fd0af1019..b9d5d0ec3 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -4,7 +4,6 @@
4 4
5#include <memory> 5#include <memory>
6#include <thread> 6#include <thread>
7#include <libusb.h>
8#include "common/param_package.h" 7#include "common/param_package.h"
9#include "input_common/analog_from_button.h" 8#include "input_common/analog_from_button.h"
10#include "input_common/gcadapter/gc_adapter.h" 9#include "input_common/gcadapter/gc_adapter.h"
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index da5227058..e63c73c4f 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -234,7 +234,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
234 std::function<void(Status)> status_callback, 234 std::function<void(Status)> status_callback,
235 std::function<void(u16, u16, u16, u16)> data_callback) { 235 std::function<void(u16, u16, u16, u16)> data_callback) {
236 236
237 std::thread([=] { 237 std::thread([=, this] {
238 constexpr u16 CALIBRATION_THRESHOLD = 100; 238 constexpr u16 CALIBRATION_THRESHOLD = 100;
239 239
240 u16 min_x{UINT16_MAX}; 240 u16 min_x{UINT16_MAX};
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index c6479af9f..dd7ce8c99 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -96,7 +96,8 @@ public:
96 } 96 }
97 if (is_written) { 97 if (is_written) {
98 map->MarkAsModified(true, GetModifiedTicks()); 98 map->MarkAsModified(true, GetModifiedTicks());
99 if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { 99 if (Settings::IsGPULevelHigh() &&
100 Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
100 MarkForAsyncFlush(map); 101 MarkForAsyncFlush(map);
101 } 102 }
102 if (!map->is_written) { 103 if (!map->is_written) {
@@ -369,7 +370,8 @@ private:
369 } 370 }
370 if (modified_inheritance) { 371 if (modified_inheritance) {
371 map->MarkAsModified(true, GetModifiedTicks()); 372 map->MarkAsModified(true, GetModifiedTicks());
372 if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { 373 if (Settings::IsGPULevelHigh() &&
374 Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
373 MarkForAsyncFlush(map); 375 MarkForAsyncFlush(map);
374 } 376 }
375 } 377 }
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 482e49711..758bfe148 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -157,7 +157,7 @@ u64 GPU::GetTicks() const {
157 constexpr u64 gpu_ticks_den = 625; 157 constexpr u64 gpu_ticks_den = 625;
158 158
159 u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count(); 159 u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count();
160 if (Settings::values.use_fast_gpu_time) { 160 if (Settings::values.use_fast_gpu_time.GetValue()) {
161 nanoseconds /= 256; 161 nanoseconds /= 256;
162 } 162 }
163 const u64 nanoseconds_num = nanoseconds / gpu_ticks_den; 163 const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index e12dab899..0d3a88765 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -132,7 +132,7 @@ public:
132 } 132 }
133 133
134 query->BindCounter(Stream(type).Current(), timestamp); 134 query->BindCounter(Stream(type).Current(), timestamp);
135 if (Settings::values.use_asynchronous_gpu_emulation) { 135 if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
136 AsyncFlushQuery(cpu_addr); 136 AsyncFlushQuery(cpu_addr);
137 } 137 }
138 } 138 }
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index 919d1f2d4..dfb06e87e 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -18,7 +18,7 @@ RendererBase::~RendererBase() = default;
18void RendererBase::RefreshBaseSettings() { 18void RendererBase::RefreshBaseSettings() {
19 UpdateCurrentFramebufferLayout(); 19 UpdateCurrentFramebufferLayout();
20 20
21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit; 21 renderer_settings.use_framelimiter = Settings::values.use_frame_limit.GetValue();
22 renderer_settings.set_background_color = true; 22 renderer_settings.set_background_color = true;
23} 23}
24 24
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 208fc6167..c1f20f0ab 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -229,15 +229,15 @@ Device::Device()
229 // uniform buffers as "push constants" 229 // uniform buffers as "push constants"
230 has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data; 230 has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
231 231
232 use_assembly_shaders = Settings::values.use_assembly_shaders && GLAD_GL_NV_gpu_program5 && 232 use_assembly_shaders = Settings::values.use_assembly_shaders.GetValue() &&
233 GLAD_GL_NV_compute_program5 && GLAD_GL_NV_transform_feedback && 233 GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
234 GLAD_GL_NV_transform_feedback2; 234 GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
235 235
236 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi); 236 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
237 LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug); 237 LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
238 LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug); 238 LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
239 239
240 if (Settings::values.use_assembly_shaders && !use_assembly_shaders) { 240 if (Settings::values.use_assembly_shaders.GetValue() && !use_assembly_shaders) {
241 LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported"); 241 LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
242 } 242 }
243} 243}
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 653c3f2f9..2dcc2b0eb 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -213,7 +213,7 @@ ShaderDiskCacheOpenGL::~ShaderDiskCacheOpenGL() = default;
213std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTransferable() { 213std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTransferable() {
214 // Skip games without title id 214 // Skip games without title id
215 const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0; 215 const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0;
216 if (!Settings::values.use_disk_shader_cache || !has_title_id) { 216 if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) {
217 return {}; 217 return {};
218 } 218 }
219 219
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index c40adb6e7..e66cdc083 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -455,8 +455,8 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color
455void RendererOpenGL::InitOpenGLObjects() { 455void RendererOpenGL::InitOpenGLObjects() {
456 frame_mailbox = std::make_unique<FrameMailbox>(); 456 frame_mailbox = std::make_unique<FrameMailbox>();
457 457
458 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 458 glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
459 0.0f); 459 Settings::values.bg_blue.GetValue(), 0.0f);
460 460
461 // Create shader programs 461 // Create shader programs
462 OGLShader vertex_shader; 462 OGLShader vertex_shader;
@@ -561,8 +561,8 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
561void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { 561void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
562 if (renderer_settings.set_background_color) { 562 if (renderer_settings.set_background_color) {
563 // Update background color before drawing 563 // Update background color before drawing
564 glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 564 glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
565 0.0f); 565 Settings::values.bg_blue.GetValue(), 0.0f);
566 } 566 }
567 567
568 // Set projection matrix 568 // Set projection matrix
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 2d9b18ed9..2258479f5 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -409,7 +409,7 @@ bool RendererVulkan::PickDevices() {
409 return false; 409 return false;
410 } 410 }
411 411
412 const s32 device_index = Settings::values.vulkan_device; 412 const s32 device_index = Settings::values.vulkan_device.GetValue();
413 if (device_index < 0 || device_index >= static_cast<s32>(devices->size())) { 413 if (device_index < 0 || device_index >= static_cast<s32>(devices->size())) {
414 LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); 414 LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
415 return false; 415 return false;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 380ed532b..7625871c2 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -332,23 +332,23 @@ private:
332 332
333 if constexpr (has_extended_dynamic_state) { 333 if constexpr (has_extended_dynamic_state) {
334 // With extended dynamic states we can specify the length and stride of a vertex buffer 334 // With extended dynamic states we can specify the length and stride of a vertex buffer
335 // std::array<VkDeviceSize, N> sizes; 335 std::array<VkDeviceSize, N> sizes;
336 std::array<u16, N> strides; 336 std::array<u16, N> strides;
337 // std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin()); 337 std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin());
338 std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin()); 338 std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin());
339 339
340 if constexpr (is_indexed) { 340 if constexpr (is_indexed) {
341 scheduler.Record( 341 scheduler.Record(
342 [buffers, offsets, strides, index = index](vk::CommandBuffer cmdbuf) { 342 [buffers, offsets, sizes, strides, index = index](vk::CommandBuffer cmdbuf) {
343 cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type); 343 cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type);
344 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), 344 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
345 offsets.data(), nullptr, 345 offsets.data(), sizes.data(),
346 ExpandStrides(strides).data()); 346 ExpandStrides(strides).data());
347 }); 347 });
348 } else { 348 } else {
349 scheduler.Record([buffers, offsets, strides](vk::CommandBuffer cmdbuf) { 349 scheduler.Record([buffers, offsets, sizes, strides](vk::CommandBuffer cmdbuf) {
350 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), 350 cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
351 offsets.data(), nullptr, 351 offsets.data(), sizes.data(),
352 ExpandStrides(strides).data()); 352 ExpandStrides(strides).data());
353 }); 353 });
354 } 354 }
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
index 868447af2..2d28a6c47 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -121,7 +121,7 @@ void VKStreamBuffer::CreateBuffers(VkBufferUsageFlags usage) {
121 121
122 // Substract from the preferred heap size some bytes to avoid getting out of memory. 122 // Substract from the preferred heap size some bytes to avoid getting out of memory.
123 const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; 123 const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size;
124 const VkDeviceSize allocable_size = heap_size - 4 * 1024 * 1024; 124 const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024;
125 125
126 VkBufferCreateInfo buffer_ci; 126 VkBufferCreateInfo buffer_ci;
127 buffer_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 127 buffer_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 6207d8dfe..cdcddb225 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -249,7 +249,7 @@ public:
249 auto& surface = render_targets[index].target; 249 auto& surface = render_targets[index].target;
250 surface->MarkAsRenderTarget(false, NO_RT); 250 surface->MarkAsRenderTarget(false, NO_RT);
251 const auto& cr_params = surface->GetSurfaceParams(); 251 const auto& cr_params = surface->GetSurfaceParams();
252 if (!cr_params.is_tiled && Settings::values.use_asynchronous_gpu_emulation) { 252 if (!cr_params.is_tiled && Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
253 AsyncFlushSurface(surface); 253 AsyncFlushSurface(surface);
254 } 254 }
255 } 255 }
diff --git a/src/video_core/textures/texture.cpp b/src/video_core/textures/texture.cpp
index d1939d744..4171e3ef2 100644
--- a/src/video_core/textures/texture.cpp
+++ b/src/video_core/textures/texture.cpp
@@ -48,7 +48,7 @@ constexpr std::array<float, 256> SRGB_CONVERSION_LUT = {
48}; 48};
49 49
50unsigned SettingsMinimumAnisotropy() noexcept { 50unsigned SettingsMinimumAnisotropy() noexcept {
51 switch (static_cast<Anisotropy>(Settings::values.max_anisotropy)) { 51 switch (static_cast<Anisotropy>(Settings::values.max_anisotropy.GetValue())) {
52 default: 52 default:
53 case Anisotropy::Default: 53 case Anisotropy::Default:
54 return 1U; 54 return 1U;
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index f60bdc60a..45f360bdd 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -19,7 +19,7 @@ namespace {
19std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, 19std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window,
20 Core::System& system, 20 Core::System& system,
21 Core::Frontend::GraphicsContext& context) { 21 Core::Frontend::GraphicsContext& context) {
22 switch (Settings::values.renderer_backend) { 22 switch (Settings::values.renderer_backend.GetValue()) {
23 case Settings::RendererBackend::OpenGL: 23 case Settings::RendererBackend::OpenGL:
24 return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context); 24 return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context);
25#ifdef HAS_VULKAN 25#ifdef HAS_VULKAN
@@ -42,7 +42,7 @@ std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor
42 return nullptr; 42 return nullptr;
43 } 43 }
44 44
45 if (Settings::values.use_asynchronous_gpu_emulation) { 45 if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
46 return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer), 46 return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer),
47 std::move(context)); 47 std::move(context));
48 } 48 }
@@ -51,8 +51,8 @@ std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor
51 51
52u16 GetResolutionScaleFactor(const RendererBase& renderer) { 52u16 GetResolutionScaleFactor(const RendererBase& renderer) {
53 return static_cast<u16>( 53 return static_cast<u16>(
54 Settings::values.resolution_factor != 0 54 Settings::values.resolution_factor.GetValue() != 0
55 ? Settings::values.resolution_factor 55 ? Settings::values.resolution_factor.GetValue()
56 : renderer.GetRenderWindow().GetFramebufferLayout().GetScalingRatio()); 56 : renderer.GetRenderWindow().GetFramebufferLayout().GetScalingRatio());
57} 57}
58 58
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 75c27e39e..a862b2610 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -24,10 +24,18 @@ add_executable(yuzu
24 compatibility_list.h 24 compatibility_list.h
25 configuration/config.cpp 25 configuration/config.cpp
26 configuration/config.h 26 configuration/config.h
27 configuration/configuration_shared.cpp
28 configuration/configuration_shared.h
27 configuration/configure.ui 29 configuration/configure.ui
28 configuration/configure_audio.cpp 30 configuration/configure_audio.cpp
29 configuration/configure_audio.h 31 configuration/configure_audio.h
30 configuration/configure_audio.ui 32 configuration/configure_audio.ui
33 configuration/configure_cpu.cpp
34 configuration/configure_cpu.h
35 configuration/configure_cpu.ui
36 configuration/configure_cpu_debug.cpp
37 configuration/configure_cpu_debug.h
38 configuration/configure_cpu_debug.ui
31 configuration/configure_debug.cpp 39 configuration/configure_debug.cpp
32 configuration/configure_debug.h 40 configuration/configure_debug.h
33 configuration/configure_debug.ui 41 configuration/configure_debug.ui
@@ -60,9 +68,12 @@ add_executable(yuzu
60 configuration/configure_mouse_advanced.cpp 68 configuration/configure_mouse_advanced.cpp
61 configuration/configure_mouse_advanced.h 69 configuration/configure_mouse_advanced.h
62 configuration/configure_mouse_advanced.ui 70 configuration/configure_mouse_advanced.ui
63 configuration/configure_per_general.cpp 71 configuration/configure_per_game.cpp
64 configuration/configure_per_general.h 72 configuration/configure_per_game.h
65 configuration/configure_per_general.ui 73 configuration/configure_per_game.ui
74 configuration/configure_per_game_addons.cpp
75 configuration/configure_per_game_addons.h
76 configuration/configure_per_game_addons.ui
66 configuration/configure_profile_manager.cpp 77 configuration/configure_profile_manager.cpp
67 configuration/configure_profile_manager.h 78 configuration/configure_profile_manager.h
68 configuration/configure_profile_manager.ui 79 configuration/configure_profile_manager.ui
@@ -93,11 +104,13 @@ add_executable(yuzu
93 game_list_p.h 104 game_list_p.h
94 game_list_worker.cpp 105 game_list_worker.cpp
95 game_list_worker.h 106 game_list_worker.h
107 hotkeys.cpp
108 hotkeys.h
109 install_dialog.cpp
110 install_dialog.h
96 loading_screen.cpp 111 loading_screen.cpp
97 loading_screen.h 112 loading_screen.h
98 loading_screen.ui 113 loading_screen.ui
99 hotkeys.cpp
100 hotkeys.h
101 main.cpp 114 main.cpp
102 main.h 115 main.h
103 main.ui 116 main.ui
@@ -147,7 +160,7 @@ endif()
147create_target_directory_groups(yuzu) 160create_target_directory_groups(yuzu)
148 161
149target_link_libraries(yuzu PRIVATE common core input_common video_core) 162target_link_libraries(yuzu PRIVATE common core input_common video_core)
150target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets) 163target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::Widgets)
151target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 164target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
152 165
153if (ENABLE_VULKAN AND NOT WIN32) 166if (ENABLE_VULKAN AND NOT WIN32)
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 4bfce48a4..5738787ac 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -145,7 +145,7 @@ public:
145 145
146 // disable vsync for any shared contexts 146 // disable vsync for any shared contexts
147 auto format = share_context->format(); 147 auto format = share_context->format();
148 format.setSwapInterval(main_surface ? Settings::values.use_vsync : 0); 148 format.setSwapInterval(main_surface ? Settings::values.use_vsync.GetValue() : 0);
149 149
150 context = std::make_unique<QOpenGLContext>(); 150 context = std::make_unique<QOpenGLContext>();
151 context->setShareContext(share_context); 151 context->setShareContext(share_context);
@@ -495,7 +495,7 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
495 495
496std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { 496std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
497#ifdef HAS_OPENGL 497#ifdef HAS_OPENGL
498 if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) { 498 if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL) {
499 auto c = static_cast<OpenGLSharedContext*>(main_context.get()); 499 auto c = static_cast<OpenGLSharedContext*>(main_context.get());
500 // Bind the shared contexts to the main surface in case the backend wants to take over 500 // Bind the shared contexts to the main surface in case the backend wants to take over
501 // presentation 501 // presentation
@@ -511,7 +511,7 @@ bool GRenderWindow::InitRenderTarget() {
511 511
512 first_frame = false; 512 first_frame = false;
513 513
514 switch (Settings::values.renderer_backend) { 514 switch (Settings::values.renderer_backend.GetValue()) {
515 case Settings::RendererBackend::OpenGL: 515 case Settings::RendererBackend::OpenGL:
516 if (!InitializeOpenGL()) { 516 if (!InitializeOpenGL()) {
517 return false; 517 return false;
@@ -538,7 +538,7 @@ bool GRenderWindow::InitRenderTarget() {
538 OnFramebufferSizeChanged(); 538 OnFramebufferSizeChanged();
539 BackupGeometry(); 539 BackupGeometry();
540 540
541 if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) { 541 if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL) {
542 if (!LoadOpenGL()) { 542 if (!LoadOpenGL()) {
543 return false; 543 return false;
544 } 544 }
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 5e0d0e7af..9e9b38214 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -13,17 +13,20 @@
13#include "input_common/udp/client.h" 13#include "input_common/udp/client.h"
14#include "yuzu/configuration/config.h" 14#include "yuzu/configuration/config.h"
15 15
16Config::Config() { 16Config::Config(const std::string& config_file, bool is_global) {
17 // TODO: Don't hardcode the path; let the frontend decide where to put the config files. 17 // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
18 qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini"; 18 qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + config_file;
19 FileUtil::CreateFullPath(qt_config_loc); 19 FileUtil::CreateFullPath(qt_config_loc);
20 qt_config = 20 qt_config =
21 std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat); 21 std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
22 global = is_global;
22 Reload(); 23 Reload();
23} 24}
24 25
25Config::~Config() { 26Config::~Config() {
26 Save(); 27 if (global) {
28 Save();
29 }
27} 30}
28 31
29const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { 32const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
@@ -402,16 +405,19 @@ void Config::ApplyDefaultProfileIfInputInvalid() {
402void Config::ReadAudioValues() { 405void Config::ReadAudioValues() {
403 qt_config->beginGroup(QStringLiteral("Audio")); 406 qt_config->beginGroup(QStringLiteral("Audio"));
404 407
405 Settings::values.sink_id = ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto")) 408 if (global) {
406 .toString() 409 Settings::values.sink_id =
407 .toStdString(); 410 ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto"))
408 Settings::values.enable_audio_stretching = 411 .toString()
409 ReadSetting(QStringLiteral("enable_audio_stretching"), true).toBool(); 412 .toStdString();
410 Settings::values.audio_device_id = 413 Settings::values.audio_device_id =
411 ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto")) 414 ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
412 .toString() 415 .toString()
413 .toStdString(); 416 .toStdString();
414 Settings::values.volume = ReadSetting(QStringLiteral("volume"), 1).toFloat(); 417 }
418 ReadSettingGlobal(Settings::values.enable_audio_stretching,
419 QStringLiteral("enable_audio_stretching"), true);
420 ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"), 1);
415 421
416 qt_config->endGroup(); 422 qt_config->endGroup();
417} 423}
@@ -440,6 +446,8 @@ void Config::ReadControlValues() {
440 .toInt()); 446 .toInt());
441 Settings::values.udp_pad_index = 447 Settings::values.udp_pad_index =
442 static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt()); 448 static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt());
449 Settings::values.use_docked_mode =
450 ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
443 451
444 qt_config->endGroup(); 452 qt_config->endGroup();
445} 453}
@@ -447,7 +455,7 @@ void Config::ReadControlValues() {
447void Config::ReadCoreValues() { 455void Config::ReadCoreValues() {
448 qt_config->beginGroup(QStringLiteral("Core")); 456 qt_config->beginGroup(QStringLiteral("Core"));
449 457
450 Settings::values.use_multi_core = ReadSetting(QStringLiteral("use_multi_core"), false).toBool(); 458 ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), false);
451 459
452 qt_config->endGroup(); 460 qt_config->endGroup();
453} 461}
@@ -497,22 +505,6 @@ void Config::ReadDataStorageValues() {
497 ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); 505 ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
498 Settings::values.gamecard_path = 506 Settings::values.gamecard_path =
499 ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); 507 ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString();
500 Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
501 ReadSetting(QStringLiteral("nand_total_size"),
502 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)))
503 .toULongLong());
504 Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
505 ReadSetting(QStringLiteral("nand_user_size"),
506 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)))
507 .toULongLong());
508 Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
509 ReadSetting(QStringLiteral("nand_system_size"),
510 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)))
511 .toULongLong());
512 Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
513 ReadSetting(QStringLiteral("sdmc_size"),
514 QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)))
515 .toULongLong());
516 508
517 qt_config->endGroup(); 509 qt_config->endGroup();
518} 510}
@@ -532,8 +524,6 @@ void Config::ReadDebuggingValues() {
532 Settings::values.reporting_services = 524 Settings::values.reporting_services =
533 ReadSetting(QStringLiteral("reporting_services"), false).toBool(); 525 ReadSetting(QStringLiteral("reporting_services"), false).toBool();
534 Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool(); 526 Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool();
535 Settings::values.disable_cpu_opt =
536 ReadSetting(QStringLiteral("disable_cpu_opt"), false).toBool();
537 Settings::values.disable_macro_jit = 527 Settings::values.disable_macro_jit =
538 ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); 528 ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
539 529
@@ -625,35 +615,59 @@ void Config::ReadPathValues() {
625 qt_config->endGroup(); 615 qt_config->endGroup();
626} 616}
627 617
618void Config::ReadCpuValues() {
619 qt_config->beginGroup(QStringLiteral("Cpu"));
620
621 if (global) {
622 Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>(
623 ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt());
624
625 Settings::values.cpuopt_page_tables =
626 ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
627 Settings::values.cpuopt_block_linking =
628 ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool();
629 Settings::values.cpuopt_return_stack_buffer =
630 ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool();
631 Settings::values.cpuopt_fast_dispatcher =
632 ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool();
633 Settings::values.cpuopt_context_elimination =
634 ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool();
635 Settings::values.cpuopt_const_prop =
636 ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool();
637 Settings::values.cpuopt_misc_ir =
638 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
639 Settings::values.cpuopt_reduce_misalign_checks =
640 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
641 }
642
643 qt_config->endGroup();
644}
645
628void Config::ReadRendererValues() { 646void Config::ReadRendererValues() {
629 qt_config->beginGroup(QStringLiteral("Renderer")); 647 qt_config->beginGroup(QStringLiteral("Renderer"));
630 648
631 Settings::values.renderer_backend = 649 ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
632 static_cast<Settings::RendererBackend>(ReadSetting(QStringLiteral("backend"), 0).toInt()); 650 ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
633 Settings::values.renderer_debug = ReadSetting(QStringLiteral("debug"), false).toBool(); 651 ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
634 Settings::values.vulkan_device = ReadSetting(QStringLiteral("vulkan_device"), 0).toInt(); 652 ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
635 Settings::values.aspect_ratio = ReadSetting(QStringLiteral("aspect_ratio"), 0).toInt(); 653 ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
636 Settings::values.max_anisotropy = ReadSetting(QStringLiteral("max_anisotropy"), 0).toInt(); 654 ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
637 Settings::values.use_frame_limit = 655 ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"), 100);
638 ReadSetting(QStringLiteral("use_frame_limit"), true).toBool(); 656 ReadSettingGlobal(Settings::values.use_disk_shader_cache,
639 Settings::values.frame_limit = ReadSetting(QStringLiteral("frame_limit"), 100).toUInt(); 657 QStringLiteral("use_disk_shader_cache"), true);
640 Settings::values.use_disk_shader_cache = 658 ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"), 0);
641 ReadSetting(QStringLiteral("use_disk_shader_cache"), true).toBool(); 659 ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation,
642 const int gpu_accuracy_level = ReadSetting(QStringLiteral("gpu_accuracy"), 0).toInt(); 660 QStringLiteral("use_asynchronous_gpu_emulation"), false);
643 Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(gpu_accuracy_level); 661 ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true);
644 Settings::values.use_asynchronous_gpu_emulation = 662 ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
645 ReadSetting(QStringLiteral("use_asynchronous_gpu_emulation"), false).toBool(); 663 false);
646 Settings::values.use_vsync = ReadSetting(QStringLiteral("use_vsync"), true).toBool(); 664 ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
647 Settings::values.use_assembly_shaders = 665 true);
648 ReadSetting(QStringLiteral("use_assembly_shaders"), false).toBool(); 666 ReadSettingGlobal(Settings::values.force_30fps_mode, QStringLiteral("force_30fps_mode"), false);
649 Settings::values.use_fast_gpu_time = 667
650 ReadSetting(QStringLiteral("use_fast_gpu_time"), true).toBool(); 668 ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0);
651 Settings::values.force_30fps_mode = 669 ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0);
652 ReadSetting(QStringLiteral("force_30fps_mode"), false).toBool(); 670 ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0);
653
654 Settings::values.bg_red = ReadSetting(QStringLiteral("bg_red"), 0.0).toFloat();
655 Settings::values.bg_green = ReadSetting(QStringLiteral("bg_green"), 0.0).toFloat();
656 Settings::values.bg_blue = ReadSetting(QStringLiteral("bg_blue"), 0.0).toFloat();
657 671
658 qt_config->endGroup(); 672 qt_config->endGroup();
659} 673}
@@ -682,35 +696,45 @@ void Config::ReadShortcutValues() {
682void Config::ReadSystemValues() { 696void Config::ReadSystemValues() {
683 qt_config->beginGroup(QStringLiteral("System")); 697 qt_config->beginGroup(QStringLiteral("System"));
684 698
685 Settings::values.use_docked_mode = 699 ReadSettingGlobal(Settings::values.current_user, QStringLiteral("current_user"), 0);
686 ReadSetting(QStringLiteral("use_docked_mode"), false).toBool(); 700 Settings::values.current_user =
687 701 std::clamp<int>(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1);
688 Settings::values.current_user = std::clamp<int>(
689 ReadSetting(QStringLiteral("current_user"), 0).toInt(), 0, Service::Account::MAX_USERS - 1);
690 702
691 Settings::values.language_index = ReadSetting(QStringLiteral("language_index"), 1).toInt(); 703 ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"), 1);
692 704
693 Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt(); 705 ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"), 1);
694 706
695 Settings::values.time_zone_index = ReadSetting(QStringLiteral("time_zone_index"), 0).toInt(); 707 ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"), 0);
696 708
697 const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool(); 709 bool rng_seed_enabled;
698 if (rng_seed_enabled) { 710 ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
699 Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong(); 711 bool rng_seed_global =
700 } else { 712 global || qt_config->value(QStringLiteral("rng_seed/use_global"), true).toBool();
701 Settings::values.rng_seed = std::nullopt; 713 Settings::values.rng_seed.SetGlobal(rng_seed_global);
714 if (global || !rng_seed_global) {
715 if (rng_seed_enabled) {
716 Settings::values.rng_seed.SetValue(
717 ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong());
718 } else {
719 Settings::values.rng_seed.SetValue(std::nullopt);
720 }
702 } 721 }
703 722
704 const auto custom_rtc_enabled = 723 bool custom_rtc_enabled;
705 ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool(); 724 ReadSettingGlobal(custom_rtc_enabled, QStringLiteral("custom_rtc_enabled"), false);
706 if (custom_rtc_enabled) { 725 bool custom_rtc_global =
707 Settings::values.custom_rtc = 726 global || qt_config->value(QStringLiteral("custom_rtc/use_global"), true).toBool();
708 std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong()); 727 Settings::values.custom_rtc.SetGlobal(custom_rtc_global);
709 } else { 728 if (global || !custom_rtc_global) {
710 Settings::values.custom_rtc = std::nullopt; 729 if (custom_rtc_enabled) {
730 Settings::values.custom_rtc.SetValue(
731 std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong()));
732 } else {
733 Settings::values.custom_rtc.SetValue(std::nullopt);
734 }
711 } 735 }
712 736
713 Settings::values.sound_index = ReadSetting(QStringLiteral("sound_index"), 1).toInt(); 737 ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"), 1);
714 738
715 qt_config->endGroup(); 739 qt_config->endGroup();
716} 740}
@@ -804,18 +828,21 @@ void Config::ReadWebServiceValues() {
804} 828}
805 829
806void Config::ReadValues() { 830void Config::ReadValues() {
807 ReadControlValues(); 831 if (global) {
832 ReadControlValues();
833 ReadDataStorageValues();
834 ReadDebuggingValues();
835 ReadDisabledAddOnValues();
836 ReadServiceValues();
837 ReadUIValues();
838 ReadWebServiceValues();
839 ReadMiscellaneousValues();
840 }
808 ReadCoreValues(); 841 ReadCoreValues();
842 ReadCpuValues();
809 ReadRendererValues(); 843 ReadRendererValues();
810 ReadAudioValues(); 844 ReadAudioValues();
811 ReadDataStorageValues();
812 ReadSystemValues(); 845 ReadSystemValues();
813 ReadMiscellaneousValues();
814 ReadDebuggingValues();
815 ReadWebServiceValues();
816 ReadServiceValues();
817 ReadDisabledAddOnValues();
818 ReadUIValues();
819} 846}
820 847
821void Config::SavePlayerValues() { 848void Config::SavePlayerValues() {
@@ -902,30 +929,36 @@ void Config::SaveTouchscreenValues() {
902} 929}
903 930
904void Config::SaveValues() { 931void Config::SaveValues() {
905 SaveControlValues(); 932 if (global) {
933 SaveControlValues();
934 SaveDataStorageValues();
935 SaveDebuggingValues();
936 SaveDisabledAddOnValues();
937 SaveServiceValues();
938 SaveUIValues();
939 SaveWebServiceValues();
940 SaveMiscellaneousValues();
941 }
906 SaveCoreValues(); 942 SaveCoreValues();
943 SaveCpuValues();
907 SaveRendererValues(); 944 SaveRendererValues();
908 SaveAudioValues(); 945 SaveAudioValues();
909 SaveDataStorageValues();
910 SaveSystemValues(); 946 SaveSystemValues();
911 SaveMiscellaneousValues();
912 SaveDebuggingValues();
913 SaveWebServiceValues();
914 SaveServiceValues();
915 SaveDisabledAddOnValues();
916 SaveUIValues();
917} 947}
918 948
919void Config::SaveAudioValues() { 949void Config::SaveAudioValues() {
920 qt_config->beginGroup(QStringLiteral("Audio")); 950 qt_config->beginGroup(QStringLiteral("Audio"));
921 951
922 WriteSetting(QStringLiteral("output_engine"), QString::fromStdString(Settings::values.sink_id), 952 if (global) {
923 QStringLiteral("auto")); 953 WriteSetting(QStringLiteral("output_engine"),
924 WriteSetting(QStringLiteral("enable_audio_stretching"), 954 QString::fromStdString(Settings::values.sink_id), QStringLiteral("auto"));
925 Settings::values.enable_audio_stretching, true); 955 WriteSetting(QStringLiteral("output_device"),
926 WriteSetting(QStringLiteral("output_device"), 956 QString::fromStdString(Settings::values.audio_device_id),
927 QString::fromStdString(Settings::values.audio_device_id), QStringLiteral("auto")); 957 QStringLiteral("auto"));
928 WriteSetting(QStringLiteral("volume"), Settings::values.volume, 1.0f); 958 }
959 WriteSettingGlobal(QStringLiteral("enable_audio_stretching"),
960 Settings::values.enable_audio_stretching, true);
961 WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume, 1.0f);
929 962
930 qt_config->endGroup(); 963 qt_config->endGroup();
931} 964}
@@ -948,6 +981,7 @@ void Config::SaveControlValues() {
948 WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port, 981 WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
949 InputCommon::CemuhookUDP::DEFAULT_PORT); 982 InputCommon::CemuhookUDP::DEFAULT_PORT);
950 WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0); 983 WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
984 WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
951 985
952 qt_config->endGroup(); 986 qt_config->endGroup();
953} 987}
@@ -955,7 +989,7 @@ void Config::SaveControlValues() {
955void Config::SaveCoreValues() { 989void Config::SaveCoreValues() {
956 qt_config->beginGroup(QStringLiteral("Core")); 990 qt_config->beginGroup(QStringLiteral("Core"));
957 991
958 WriteSetting(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, false); 992 WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, false);
959 993
960 qt_config->endGroup(); 994 qt_config->endGroup();
961} 995}
@@ -984,18 +1018,7 @@ void Config::SaveDataStorageValues() {
984 false); 1018 false);
985 WriteSetting(QStringLiteral("gamecard_path"), 1019 WriteSetting(QStringLiteral("gamecard_path"),
986 QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); 1020 QString::fromStdString(Settings::values.gamecard_path), QStringLiteral(""));
987 WriteSetting(QStringLiteral("nand_total_size"), 1021
988 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)),
989 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)));
990 WriteSetting(QStringLiteral("nand_user_size"),
991 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)),
992 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)));
993 WriteSetting(QStringLiteral("nand_system_size"),
994 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)),
995 QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)));
996 WriteSetting(QStringLiteral("sdmc_size"),
997 QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)),
998 QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)));
999 qt_config->endGroup(); 1022 qt_config->endGroup();
1000} 1023}
1001 1024
@@ -1011,7 +1034,6 @@ void Config::SaveDebuggingValues() {
1011 WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); 1034 WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
1012 WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); 1035 WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
1013 WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); 1036 WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
1014 WriteSetting(QStringLiteral("disable_cpu_opt"), Settings::values.disable_cpu_opt, false);
1015 WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false); 1037 WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
1016 1038
1017 qt_config->endGroup(); 1039 qt_config->endGroup();
@@ -1075,32 +1097,63 @@ void Config::SavePathValues() {
1075 qt_config->endGroup(); 1097 qt_config->endGroup();
1076} 1098}
1077 1099
1100void Config::SaveCpuValues() {
1101 qt_config->beginGroup(QStringLiteral("Cpu"));
1102
1103 if (global) {
1104 WriteSetting(QStringLiteral("cpu_accuracy"),
1105 static_cast<int>(Settings::values.cpu_accuracy), 0);
1106
1107 WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
1108 true);
1109 WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
1110 true);
1111 WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"),
1112 Settings::values.cpuopt_return_stack_buffer, true);
1113 WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"),
1114 Settings::values.cpuopt_fast_dispatcher, true);
1115 WriteSetting(QStringLiteral("cpuopt_context_elimination"),
1116 Settings::values.cpuopt_context_elimination, true);
1117 WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true);
1118 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
1119 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
1120 Settings::values.cpuopt_reduce_misalign_checks, true);
1121 }
1122
1123 qt_config->endGroup();
1124}
1125
1078void Config::SaveRendererValues() { 1126void Config::SaveRendererValues() {
1079 qt_config->beginGroup(QStringLiteral("Renderer")); 1127 qt_config->beginGroup(QStringLiteral("Renderer"));
1080 1128
1081 WriteSetting(QStringLiteral("backend"), static_cast<int>(Settings::values.renderer_backend), 0); 1129 WriteSettingGlobal(QStringLiteral("backend"),
1130 static_cast<int>(Settings::values.renderer_backend.GetValue(global)),
1131 Settings::values.renderer_backend.UsingGlobal(), 0);
1082 WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false); 1132 WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
1083 WriteSetting(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0); 1133 WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
1084 WriteSetting(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0); 1134 WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
1085 WriteSetting(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0); 1135 WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
1086 WriteSetting(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true); 1136 WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
1087 WriteSetting(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100); 1137 WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100);
1088 WriteSetting(QStringLiteral("use_disk_shader_cache"), Settings::values.use_disk_shader_cache, 1138 WriteSettingGlobal(QStringLiteral("use_disk_shader_cache"),
1089 true); 1139 Settings::values.use_disk_shader_cache, true);
1090 WriteSetting(QStringLiteral("gpu_accuracy"), static_cast<int>(Settings::values.gpu_accuracy), 1140 WriteSettingGlobal(QStringLiteral("gpu_accuracy"),
1091 0); 1141 static_cast<int>(Settings::values.gpu_accuracy.GetValue(global)),
1092 WriteSetting(QStringLiteral("use_asynchronous_gpu_emulation"), 1142 Settings::values.gpu_accuracy.UsingGlobal(), 0);
1093 Settings::values.use_asynchronous_gpu_emulation, false); 1143 WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"),
1094 WriteSetting(QStringLiteral("use_vsync"), Settings::values.use_vsync, true); 1144 Settings::values.use_asynchronous_gpu_emulation, false);
1095 WriteSetting(QStringLiteral("use_assembly_shaders"), Settings::values.use_assembly_shaders, 1145 WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
1096 false); 1146 WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
1097 WriteSetting(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time, true); 1147 Settings::values.use_assembly_shaders, false);
1098 WriteSetting(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode, false); 1148 WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
1149 true);
1150 WriteSettingGlobal(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode,
1151 false);
1099 1152
1100 // Cast to double because Qt's written float values are not human-readable 1153 // Cast to double because Qt's written float values are not human-readable
1101 WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0); 1154 WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0);
1102 WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0); 1155 WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0);
1103 WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0); 1156 WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue, 0.0);
1104 1157
1105 qt_config->endGroup(); 1158 qt_config->endGroup();
1106} 1159}
@@ -1128,23 +1181,28 @@ void Config::SaveShortcutValues() {
1128void Config::SaveSystemValues() { 1181void Config::SaveSystemValues() {
1129 qt_config->beginGroup(QStringLiteral("System")); 1182 qt_config->beginGroup(QStringLiteral("System"));
1130 1183
1131 WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
1132 WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0); 1184 WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0);
1133 WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1); 1185 WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index, 1);
1134 WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1); 1186 WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index, 1);
1135 WriteSetting(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0); 1187 WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
1136 1188
1137 WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false); 1189 WriteSettingGlobal(QStringLiteral("rng_seed_enabled"),
1138 WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0); 1190 Settings::values.rng_seed.GetValue(global).has_value(),
1139 1191 Settings::values.rng_seed.UsingGlobal(), false);
1140 WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(), 1192 WriteSettingGlobal(QStringLiteral("rng_seed"),
1141 false); 1193 Settings::values.rng_seed.GetValue(global).value_or(0),
1142 WriteSetting(QStringLiteral("custom_rtc"), 1194 Settings::values.rng_seed.UsingGlobal(), 0);
1143 QVariant::fromValue<long long>( 1195
1144 Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()), 1196 WriteSettingGlobal(QStringLiteral("custom_rtc_enabled"),
1145 0); 1197 Settings::values.custom_rtc.GetValue(global).has_value(),
1146 1198 Settings::values.custom_rtc.UsingGlobal(), false);
1147 WriteSetting(QStringLiteral("sound_index"), Settings::values.sound_index, 1); 1199 WriteSettingGlobal(
1200 QStringLiteral("custom_rtc"),
1201 QVariant::fromValue<long long>(
1202 Settings::values.custom_rtc.GetValue(global).value_or(std::chrono::seconds{}).count()),
1203 Settings::values.custom_rtc.UsingGlobal(), 0);
1204
1205 WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
1148 1206
1149 qt_config->endGroup(); 1207 qt_config->endGroup();
1150} 1208}
@@ -1236,6 +1294,34 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
1236 return result; 1294 return result;
1237} 1295}
1238 1296
1297template <typename Type>
1298void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name) {
1299 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
1300 setting.SetGlobal(use_global);
1301 if (global || !use_global) {
1302 setting.SetValue(ReadSetting(name).value<Type>());
1303 }
1304}
1305
1306template <typename Type>
1307void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
1308 const QVariant& default_value) {
1309 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
1310 setting.SetGlobal(use_global);
1311 if (global || !use_global) {
1312 setting.SetValue(ReadSetting(name, default_value).value<Type>());
1313 }
1314}
1315
1316template <typename Type>
1317void Config::ReadSettingGlobal(Type& setting, const QString& name,
1318 const QVariant& default_value) const {
1319 const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
1320 if (global || !use_global) {
1321 setting = ReadSetting(name, default_value).value<Type>();
1322 }
1323}
1324
1239void Config::WriteSetting(const QString& name, const QVariant& value) { 1325void Config::WriteSetting(const QString& name, const QVariant& value) {
1240 qt_config->setValue(name, value); 1326 qt_config->setValue(name, value);
1241} 1327}
@@ -1246,6 +1332,40 @@ void Config::WriteSetting(const QString& name, const QVariant& value,
1246 qt_config->setValue(name, value); 1332 qt_config->setValue(name, value);
1247} 1333}
1248 1334
1335template <typename Type>
1336void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting) {
1337 if (!global) {
1338 qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
1339 }
1340 if (global || !setting.UsingGlobal()) {
1341 qt_config->setValue(name, setting.GetValue(global));
1342 }
1343}
1344
1345template <typename Type>
1346void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
1347 const QVariant& default_value) {
1348 if (!global) {
1349 qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
1350 }
1351 if (global || !setting.UsingGlobal()) {
1352 qt_config->setValue(name + QStringLiteral("/default"),
1353 setting.GetValue(global) == default_value.value<Type>());
1354 qt_config->setValue(name, setting.GetValue(global));
1355 }
1356}
1357
1358void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
1359 const QVariant& default_value) {
1360 if (!global) {
1361 qt_config->setValue(name + QStringLiteral("/use_global"), use_global);
1362 }
1363 if (global || !use_global) {
1364 qt_config->setValue(name + QStringLiteral("/default"), value == default_value);
1365 qt_config->setValue(name, value);
1366 }
1367}
1368
1249void Config::Reload() { 1369void Config::Reload() {
1250 ReadValues(); 1370 ReadValues();
1251 // To apply default value changes 1371 // To apply default value changes
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 09316382c..8e815f829 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include <QMetaType>
10#include <QVariant> 11#include <QVariant>
11#include "core/settings.h" 12#include "core/settings.h"
12#include "yuzu/uisettings.h" 13#include "yuzu/uisettings.h"
@@ -15,7 +16,7 @@ class QSettings;
15 16
16class Config { 17class Config {
17public: 18public:
18 Config(); 19 explicit Config(const std::string& config_loc = "qt-config.ini", bool is_global = true);
19 ~Config(); 20 ~Config();
20 21
21 void Reload(); 22 void Reload();
@@ -48,6 +49,7 @@ private:
48 void ReadDisabledAddOnValues(); 49 void ReadDisabledAddOnValues();
49 void ReadMiscellaneousValues(); 50 void ReadMiscellaneousValues();
50 void ReadPathValues(); 51 void ReadPathValues();
52 void ReadCpuValues();
51 void ReadRendererValues(); 53 void ReadRendererValues();
52 void ReadShortcutValues(); 54 void ReadShortcutValues();
53 void ReadSystemValues(); 55 void ReadSystemValues();
@@ -72,6 +74,7 @@ private:
72 void SaveDisabledAddOnValues(); 74 void SaveDisabledAddOnValues();
73 void SaveMiscellaneousValues(); 75 void SaveMiscellaneousValues();
74 void SavePathValues(); 76 void SavePathValues();
77 void SaveCpuValues();
75 void SaveRendererValues(); 78 void SaveRendererValues();
76 void SaveShortcutValues(); 79 void SaveShortcutValues();
77 void SaveSystemValues(); 80 void SaveSystemValues();
@@ -82,9 +85,33 @@ private:
82 85
83 QVariant ReadSetting(const QString& name) const; 86 QVariant ReadSetting(const QString& name) const;
84 QVariant ReadSetting(const QString& name, const QVariant& default_value) const; 87 QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
88 // Templated ReadSettingGlobal functions will also look for the use_global setting and set
89 // both the value and the global state properly
90 template <typename Type>
91 void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name);
92 template <typename Type>
93 void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
94 const QVariant& default_value);
95 template <typename Type>
96 void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
97 // Templated WriteSettingGlobal functions will also write the global state if needed and will
98 // skip writing the actual setting if it defers to the global value
85 void WriteSetting(const QString& name, const QVariant& value); 99 void WriteSetting(const QString& name, const QVariant& value);
86 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); 100 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
101 template <typename Type>
102 void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting);
103 template <typename Type>
104 void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
105 const QVariant& default_value);
106 void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
107 const QVariant& default_value);
87 108
88 std::unique_ptr<QSettings> qt_config; 109 std::unique_ptr<QSettings> qt_config;
89 std::string qt_config_loc; 110 std::string qt_config_loc;
111
112 bool global;
90}; 113};
114
115// These metatype declarations cannot be in core/settings.h because core is devoid of QT
116Q_DECLARE_METATYPE(Settings::RendererBackend);
117Q_DECLARE_METATYPE(Settings::GPUAccuracy);
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
new file mode 100644
index 000000000..bb47c3933
--- /dev/null
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -0,0 +1,76 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QCheckBox>
6#include <QComboBox>
7#include "core/settings.h"
8#include "yuzu/configuration/configuration_shared.h"
9#include "yuzu/configuration/configure_per_game.h"
10
11void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
12 const QCheckBox* checkbox) {
13 if (checkbox->checkState() == Qt::PartiallyChecked) {
14 setting->SetGlobal(true);
15 } else {
16 setting->SetGlobal(false);
17 setting->SetValue(checkbox->checkState() == Qt::Checked);
18 }
19}
20
21void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting,
22 const QComboBox* combobox) {
23 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
24 setting->SetGlobal(true);
25 } else {
26 setting->SetGlobal(false);
27 setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
28 }
29}
30
31void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
32 const QComboBox* combobox) {
33 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
34 setting->SetGlobal(true);
35 } else {
36 setting->SetGlobal(false);
37 setting->SetValue(static_cast<Settings::RendererBackend>(
38 combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
39 }
40}
41
42void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
43 const Settings::Setting<bool>* setting) {
44 if (setting->UsingGlobal()) {
45 checkbox->setCheckState(Qt::PartiallyChecked);
46 } else {
47 checkbox->setCheckState(setting->GetValue() ? Qt::Checked : Qt::Unchecked);
48 }
49}
50
51void ConfigurationShared::SetPerGameSetting(QComboBox* combobox,
52 const Settings::Setting<int>* setting) {
53 combobox->setCurrentIndex(setting->UsingGlobal()
54 ? ConfigurationShared::USE_GLOBAL_INDEX
55 : setting->GetValue() + ConfigurationShared::USE_GLOBAL_OFFSET);
56}
57
58void ConfigurationShared::SetPerGameSetting(
59 QComboBox* combobox, const Settings::Setting<Settings::RendererBackend>* setting) {
60 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
61 : static_cast<int>(setting->GetValue()) +
62 ConfigurationShared::USE_GLOBAL_OFFSET);
63}
64
65void ConfigurationShared::SetPerGameSetting(
66 QComboBox* combobox, const Settings::Setting<Settings::GPUAccuracy>* setting) {
67 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
68 : static_cast<int>(setting->GetValue()) +
69 ConfigurationShared::USE_GLOBAL_OFFSET);
70}
71
72void ConfigurationShared::InsertGlobalItem(QComboBox* combobox) {
73 const QString use_global_text = ConfigurePerGame::tr("Use global configuration");
74 combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text);
75 combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX);
76}
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
new file mode 100644
index 000000000..b11b1b950
--- /dev/null
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -0,0 +1,36 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QCheckBox>
8#include <QComboBox>
9#include <QString>
10#include "core/settings.h"
11
12namespace ConfigurationShared {
13
14constexpr int USE_GLOBAL_INDEX = 0;
15constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
16constexpr int USE_GLOBAL_OFFSET = 2;
17
18// Global-aware apply and set functions
19
20void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox);
21void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox);
22void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
23 const QComboBox* combobox);
24void ApplyPerGameSetting(Settings::Setting<Settings::GPUAccuracy>* setting,
25 const QComboBox* combobox);
26
27void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
28void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<int>* setting);
29void SetPerGameSetting(QComboBox* combobox,
30 const Settings::Setting<Settings::RendererBackend>* setting);
31void SetPerGameSetting(QComboBox* combobox,
32 const Settings::Setting<Settings::GPUAccuracy>* setting);
33
34void InsertGlobalItem(QComboBox* combobox);
35
36} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 9aec1bd09..5f5d8e571 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -78,6 +78,16 @@
78 <string>Hotkeys</string> 78 <string>Hotkeys</string>
79 </attribute> 79 </attribute>
80 </widget> 80 </widget>
81 <widget class="ConfigureCpu" name="cpuTab">
82 <attribute name="title">
83 <string>CPU</string>
84 </attribute>
85 </widget>
86 <widget class="ConfigureCpuDebug" name="cpuDebugTab">
87 <attribute name="title">
88 <string>Debug</string>
89 </attribute>
90 </widget>
81 <widget class="ConfigureGraphics" name="graphicsTab"> 91 <widget class="ConfigureGraphics" name="graphicsTab">
82 <attribute name="title"> 92 <attribute name="title">
83 <string>Graphics</string> 93 <string>Graphics</string>
@@ -159,6 +169,18 @@
159 <container>1</container> 169 <container>1</container>
160 </customwidget> 170 </customwidget>
161 <customwidget> 171 <customwidget>
172 <class>ConfigureCpu</class>
173 <extends>QWidget</extends>
174 <header>configuration/configure_cpu.h</header>
175 <container>1</container>
176 </customwidget>
177 <customwidget>
178 <class>ConfigureCpuDebug</class>
179 <extends>QWidget</extends>
180 <header>configuration/configure_cpu_debug.h</header>
181 <container>1</container>
182 </customwidget>
183 <customwidget>
162 <class>ConfigureGraphics</class> 184 <class>ConfigureGraphics</class>
163 <extends>QWidget</extends> 185 <extends>QWidget</extends>
164 <header>configuration/configure_graphics.h</header> 186 <header>configuration/configure_graphics.h</header>
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index f370c690f..cc021beec 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -11,6 +11,7 @@
11#include "core/core.h" 11#include "core/core.h"
12#include "core/settings.h" 12#include "core/settings.h"
13#include "ui_configure_audio.h" 13#include "ui_configure_audio.h"
14#include "yuzu/configuration/configuration_shared.h"
14#include "yuzu/configuration/configure_audio.h" 15#include "yuzu/configuration/configure_audio.h"
15 16
16ConfigureAudio::ConfigureAudio(QWidget* parent) 17ConfigureAudio::ConfigureAudio(QWidget* parent)
@@ -24,6 +25,11 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
24 connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this, 25 connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
25 &ConfigureAudio::UpdateAudioDevices); 26 &ConfigureAudio::UpdateAudioDevices);
26 27
28 ui->volume_label->setVisible(Settings::configuring_global);
29 ui->volume_combo_box->setVisible(!Settings::configuring_global);
30
31 SetupPerGameUI();
32
27 SetConfiguration(); 33 SetConfiguration();
28 34
29 const bool is_powered_on = Core::System::GetInstance().IsPoweredOn(); 35 const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
@@ -41,8 +47,22 @@ void ConfigureAudio::SetConfiguration() {
41 47
42 SetAudioDeviceFromDeviceID(); 48 SetAudioDeviceFromDeviceID();
43 49
44 ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching); 50 ui->volume_slider->setValue(Settings::values.volume.GetValue() * ui->volume_slider->maximum());
45 ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum()); 51
52 if (Settings::configuring_global) {
53 ui->toggle_audio_stretching->setChecked(
54 Settings::values.enable_audio_stretching.GetValue());
55 } else {
56 ConfigurationShared::SetPerGameSetting(ui->toggle_audio_stretching,
57 &Settings::values.enable_audio_stretching);
58 if (Settings::values.volume.UsingGlobal()) {
59 ui->volume_combo_box->setCurrentIndex(0);
60 ui->volume_slider->setEnabled(false);
61 } else {
62 ui->volume_combo_box->setCurrentIndex(1);
63 ui->volume_slider->setEnabled(true);
64 }
65 }
46 SetVolumeIndicatorText(ui->volume_slider->sliderPosition()); 66 SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
47} 67}
48 68
@@ -80,15 +100,36 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
80} 100}
81 101
82void ConfigureAudio::ApplyConfiguration() { 102void ConfigureAudio::ApplyConfiguration() {
83 Settings::values.sink_id = 103 if (Settings::configuring_global) {
84 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) 104 Settings::values.sink_id =
85 .toStdString(); 105 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
86 Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked(); 106 .toStdString();
87 Settings::values.audio_device_id = 107 Settings::values.audio_device_id =
88 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex()) 108 ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
89 .toStdString(); 109 .toStdString();
90 Settings::values.volume = 110
91 static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum(); 111 // Guard if during game and set to game-specific value
112 if (Settings::values.enable_audio_stretching.UsingGlobal()) {
113 Settings::values.enable_audio_stretching.SetValue(
114 ui->toggle_audio_stretching->isChecked());
115 }
116 if (Settings::values.volume.UsingGlobal()) {
117 Settings::values.volume.SetValue(
118 static_cast<float>(ui->volume_slider->sliderPosition()) /
119 ui->volume_slider->maximum());
120 }
121 } else {
122 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
123 ui->toggle_audio_stretching);
124 if (ui->volume_combo_box->currentIndex() == 0) {
125 Settings::values.volume.SetGlobal(true);
126 } else {
127 Settings::values.volume.SetGlobal(false);
128 Settings::values.volume.SetValue(
129 static_cast<float>(ui->volume_slider->sliderPosition()) /
130 ui->volume_slider->maximum());
131 }
132 }
92} 133}
93 134
94void ConfigureAudio::changeEvent(QEvent* event) { 135void ConfigureAudio::changeEvent(QEvent* event) {
@@ -122,3 +163,22 @@ void ConfigureAudio::RetranslateUI() {
122 ui->retranslateUi(this); 163 ui->retranslateUi(this);
123 SetVolumeIndicatorText(ui->volume_slider->sliderPosition()); 164 SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
124} 165}
166
167void ConfigureAudio::SetupPerGameUI() {
168 if (Settings::configuring_global) {
169 ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal());
170 ui->toggle_audio_stretching->setEnabled(
171 Settings::values.enable_audio_stretching.UsingGlobal());
172
173 return;
174 }
175
176 ui->toggle_audio_stretching->setTristate(true);
177 connect(ui->volume_combo_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
178 this, [this](int index) { ui->volume_slider->setEnabled(index == 1); });
179
180 ui->output_sink_combo_box->setVisible(false);
181 ui->output_sink_label->setVisible(false);
182 ui->audio_device_combo_box->setVisible(false);
183 ui->audio_device_label->setVisible(false);
184}
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index ea83bd72d..d84f4a682 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -34,5 +34,7 @@ private:
34 void SetAudioDeviceFromDeviceID(); 34 void SetAudioDeviceFromDeviceID();
35 void SetVolumeIndicatorText(int percentage); 35 void SetVolumeIndicatorText(int percentage);
36 36
37 void SetupPerGameUI();
38
37 std::unique_ptr<Ui::ConfigureAudio> ui; 39 std::unique_ptr<Ui::ConfigureAudio> ui;
38}; 40};
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index a098b9acc..862ccb988 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -6,8 +6,8 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>188</width> 9 <width>367</width>
10 <height>246</height> 10 <height>368</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <layout class="QVBoxLayout"> 13 <layout class="QVBoxLayout">
@@ -18,9 +18,9 @@
18 </property> 18 </property>
19 <layout class="QVBoxLayout"> 19 <layout class="QVBoxLayout">
20 <item> 20 <item>
21 <layout class="QHBoxLayout"> 21 <layout class="QHBoxLayout" name="_3">
22 <item> 22 <item>
23 <widget class="QLabel" name="label_1"> 23 <widget class="QLabel" name="output_sink_label">
24 <property name="text"> 24 <property name="text">
25 <string>Output Engine:</string> 25 <string>Output Engine:</string>
26 </property> 26 </property>
@@ -31,20 +31,20 @@
31 </item> 31 </item>
32 </layout> 32 </layout>
33 </item> 33 </item>
34 <item>
35 <widget class="QCheckBox" name="toggle_audio_stretching">
36 <property name="toolTip">
37 <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
38 </property>
39 <property name="text">
40 <string>Enable audio stretching</string>
41 </property>
42 </widget>
43 </item>
44 <item> 34 <item>
45 <layout class="QHBoxLayout"> 35 <widget class="QCheckBox" name="toggle_audio_stretching">
36 <property name="toolTip">
37 <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
38 </property>
39 <property name="text">
40 <string>Enable audio stretching</string>
41 </property>
42 </widget>
43 </item>
44 <item>
45 <layout class="QHBoxLayout" name="_2">
46 <item> 46 <item>
47 <widget class="QLabel" name="label_2"> 47 <widget class="QLabel" name="audio_device_label">
48 <property name="text"> 48 <property name="text">
49 <string>Audio Device:</string> 49 <string>Audio Device:</string>
50 </property> 50 </property>
@@ -61,7 +61,21 @@
61 <number>0</number> 61 <number>0</number>
62 </property> 62 </property>
63 <item> 63 <item>
64 <widget class="QLabel" name="label_3"> 64 <widget class="QComboBox" name="volume_combo_box">
65 <item>
66 <property name="text">
67 <string>Use global volume</string>
68 </property>
69 </item>
70 <item>
71 <property name="text">
72 <string>Set volume:</string>
73 </property>
74 </item>
75 </widget>
76 </item>
77 <item>
78 <widget class="QLabel" name="volume_label">
65 <property name="text"> 79 <property name="text">
66 <string>Volume:</string> 80 <string>Volume:</string>
67 </property> 81 </property>
@@ -74,7 +88,7 @@
74 </property> 88 </property>
75 <property name="sizeHint" stdset="0"> 89 <property name="sizeHint" stdset="0">
76 <size> 90 <size>
77 <width>40</width> 91 <width>30</width>
78 <height>20</height> 92 <height>20</height>
79 </size> 93 </size>
80 </property> 94 </property>
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
new file mode 100644
index 000000000..7493e5ffb
--- /dev/null
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -0,0 +1,61 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QComboBox>
6#include <QMessageBox>
7
8#include "common/common_types.h"
9#include "common/logging/log.h"
10#include "core/core.h"
11#include "core/settings.h"
12#include "ui_configure_cpu.h"
13#include "yuzu/configuration/configure_cpu.h"
14
15ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) {
16 ui->setupUi(this);
17
18 SetConfiguration();
19
20 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
21 &ConfigureCpu::AccuracyUpdated);
22}
23
24ConfigureCpu::~ConfigureCpu() = default;
25
26void ConfigureCpu::SetConfiguration() {
27 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
28
29 ui->accuracy->setEnabled(runtime_lock);
30 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
31}
32
33void ConfigureCpu::AccuracyUpdated(int index) {
34 if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
35 const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
36 tr("CPU Debug Mode is only intended for developer "
37 "use. Are you sure you want to enable this?"),
38 QMessageBox::Yes | QMessageBox::No);
39 if (result == QMessageBox::No) {
40 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate));
41 return;
42 }
43 }
44}
45
46void ConfigureCpu::ApplyConfiguration() {
47 Settings::values.cpu_accuracy =
48 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex());
49}
50
51void ConfigureCpu::changeEvent(QEvent* event) {
52 if (event->type() == QEvent::LanguageChange) {
53 RetranslateUI();
54 }
55
56 QWidget::changeEvent(event);
57}
58
59void ConfigureCpu::RetranslateUI() {
60 ui->retranslateUi(this);
61}
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
new file mode 100644
index 000000000..e4741d3a4
--- /dev/null
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -0,0 +1,33 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9#include "core/settings.h"
10
11namespace Ui {
12class ConfigureCpu;
13}
14
15class ConfigureCpu : public QWidget {
16 Q_OBJECT
17
18public:
19 explicit ConfigureCpu(QWidget* parent = nullptr);
20 ~ConfigureCpu() override;
21
22 void ApplyConfiguration();
23
24private:
25 void changeEvent(QEvent* event) override;
26 void RetranslateUI();
27
28 void AccuracyUpdated(int index);
29
30 void SetConfiguration();
31
32 std::unique_ptr<Ui::ConfigureCpu> ui;
33};
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
new file mode 100644
index 000000000..bf6ea79bb
--- /dev/null
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -0,0 +1,92 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureCpu</class>
4 <widget class="QWidget" name="ConfigureCpu">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>321</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QVBoxLayout">
17 <item>
18 <layout class="QVBoxLayout">
19 <item>
20 <widget class="QGroupBox">
21 <property name="title">
22 <string>General</string>
23 </property>
24 <layout class="QVBoxLayout">
25 <item>
26 <layout class="QHBoxLayout">
27 <item>
28 <widget class="QLabel">
29 <property name="text">
30 <string>Accuracy:</string>
31 </property>
32 </widget>
33 </item>
34 <item>
35 <widget class="QComboBox" name="accuracy">
36 <item>
37 <property name="text">
38 <string>Accurate</string>
39 </property>
40 </item>
41 <item>
42 <property name="text">
43 <string>Enable Debug Mode</string>
44 </property>
45 </item>
46 </widget>
47 </item>
48 </layout>
49 </item>
50 <item>
51 <widget class="QLabel">
52 <property name="wordWrap">
53 <bool>1</bool>
54 </property>
55 <property name="text">
56 <string>We recommend setting accuracy to "Accurate".</string>
57 </property>
58 </widget>
59 </item>
60 </layout>
61 </widget>
62 </item>
63 </layout>
64 </item>
65 <item>
66 <spacer name="verticalSpacer">
67 <property name="orientation">
68 <enum>Qt::Vertical</enum>
69 </property>
70 <property name="sizeHint" stdset="0">
71 <size>
72 <width>20</width>
73 <height>40</height>
74 </size>
75 </property>
76 </spacer>
77 </item>
78 <item>
79 <widget class="QLabel" name="label_disable_info">
80 <property name="text">
81 <string>CPU settings are available only when game is not running.</string>
82 </property>
83 <property name="wordWrap">
84 <bool>true</bool>
85 </property>
86 </widget>
87 </item>
88 </layout>
89 </widget>
90 <resources/>
91 <connections/>
92</ui>
diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp
new file mode 100644
index 000000000..3385b2cf6
--- /dev/null
+++ b/src/yuzu/configuration/configure_cpu_debug.cpp
@@ -0,0 +1,65 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QComboBox>
6
7#include "common/common_types.h"
8#include "common/logging/log.h"
9#include "core/core.h"
10#include "core/settings.h"
11#include "ui_configure_cpu_debug.h"
12#include "yuzu/configuration/configure_cpu_debug.h"
13
14ConfigureCpuDebug::ConfigureCpuDebug(QWidget* parent)
15 : QWidget(parent), ui(new Ui::ConfigureCpuDebug) {
16 ui->setupUi(this);
17
18 SetConfiguration();
19}
20
21ConfigureCpuDebug::~ConfigureCpuDebug() = default;
22
23void ConfigureCpuDebug::SetConfiguration() {
24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
25
26 ui->cpuopt_page_tables->setEnabled(runtime_lock);
27 ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables);
28 ui->cpuopt_block_linking->setEnabled(runtime_lock);
29 ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking);
30 ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
31 ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer);
32 ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
33 ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher);
34 ui->cpuopt_context_elimination->setEnabled(runtime_lock);
35 ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination);
36 ui->cpuopt_const_prop->setEnabled(runtime_lock);
37 ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop);
38 ui->cpuopt_misc_ir->setEnabled(runtime_lock);
39 ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir);
40 ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
41 ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks);
42}
43
44void ConfigureCpuDebug::ApplyConfiguration() {
45 Settings::values.cpuopt_page_tables = ui->cpuopt_page_tables->isChecked();
46 Settings::values.cpuopt_block_linking = ui->cpuopt_block_linking->isChecked();
47 Settings::values.cpuopt_return_stack_buffer = ui->cpuopt_return_stack_buffer->isChecked();
48 Settings::values.cpuopt_fast_dispatcher = ui->cpuopt_fast_dispatcher->isChecked();
49 Settings::values.cpuopt_context_elimination = ui->cpuopt_context_elimination->isChecked();
50 Settings::values.cpuopt_const_prop = ui->cpuopt_const_prop->isChecked();
51 Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked();
52 Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked();
53}
54
55void ConfigureCpuDebug::changeEvent(QEvent* event) {
56 if (event->type() == QEvent::LanguageChange) {
57 RetranslateUI();
58 }
59
60 QWidget::changeEvent(event);
61}
62
63void ConfigureCpuDebug::RetranslateUI() {
64 ui->retranslateUi(this);
65}
diff --git a/src/yuzu/configuration/configure_cpu_debug.h b/src/yuzu/configuration/configure_cpu_debug.h
new file mode 100644
index 000000000..c9941ef3b
--- /dev/null
+++ b/src/yuzu/configuration/configure_cpu_debug.h
@@ -0,0 +1,31 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9#include "core/settings.h"
10
11namespace Ui {
12class ConfigureCpuDebug;
13}
14
15class ConfigureCpuDebug : public QWidget {
16 Q_OBJECT
17
18public:
19 explicit ConfigureCpuDebug(QWidget* parent = nullptr);
20 ~ConfigureCpuDebug() override;
21
22 void ApplyConfiguration();
23
24private:
25 void changeEvent(QEvent* event) override;
26 void RetranslateUI();
27
28 void SetConfiguration();
29
30 std::unique_ptr<Ui::ConfigureCpuDebug> ui;
31};
diff --git a/src/yuzu/configuration/configure_cpu_debug.ui b/src/yuzu/configuration/configure_cpu_debug.ui
new file mode 100644
index 000000000..a90dc64fe
--- /dev/null
+++ b/src/yuzu/configuration/configure_cpu_debug.ui
@@ -0,0 +1,174 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureCpuDebug</class>
4 <widget class="QWidget" name="ConfigureCpuDebug">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>321</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QVBoxLayout">
17 <item>
18 <layout class="QVBoxLayout">
19 <item>
20 <widget class="QGroupBox">
21 <property name="title">
22 <string>Toggle CPU Optimizations</string>
23 </property>
24 <layout class="QVBoxLayout">
25 <item>
26 <widget class="QLabel">
27 <property name="wordWrap">
28 <bool>1</bool>
29 </property>
30 <property name="text">
31 <string>
32 &lt;div&gt;
33 &lt;b&gt;For debugging only.&lt;/b&gt;
34 &lt;br&gt;
35 If you're not sure what these do, keep all of these enabled.
36 &lt;br&gt;
37 These settings only take effect when CPU Accuracy is "Debug Mode".
38 &lt;/div&gt;
39 </string>
40 </property>
41 </widget>
42 </item>
43 <item>
44 <widget class="QCheckBox" name="cpuopt_page_tables">
45 <property name="text">
46 <string>Enable inline page tables</string>
47 </property>
48 <property name="toolTip">
49 <string>
50 &lt;div style="white-space: nowrap"&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
51 &lt;div style="white-space: nowrap"&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
52 &lt;div style="white-space: nowrap"&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
53 </string>
54 </property>
55 </widget>
56 </item>
57 <item>
58 <widget class="QCheckBox" name="cpuopt_block_linking">
59 <property name="text">
60 <string>Enable block linking</string>
61 </property>
62 <property name="toolTip">
63 <string>
64 &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
65 </string>
66 </property>
67 </widget>
68 </item>
69 <item>
70 <widget class="QCheckBox" name="cpuopt_return_stack_buffer">
71 <property name="text">
72 <string>Enable return stack buffer</string>
73 </property>
74 <property name="toolTip">
75 <string>
76 &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
77 </string>
78 </property>
79 </widget>
80 </item>
81 <item>
82 <widget class="QCheckBox" name="cpuopt_fast_dispatcher">
83 <property name="text">
84 <string>Enable fast dispatcher</string>
85 </property>
86 <property name="toolTip">
87 <string>
88 &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
89 </string>
90 </property>
91 </widget>
92 </item>
93 <item>
94 <widget class="QCheckBox" name="cpuopt_context_elimination">
95 <property name="text">
96 <string>Enable context elimination</string>
97 </property>
98 <property name="toolTip">
99 <string>
100 &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
101 </string>
102 </property>
103 </widget>
104 </item>
105 <item>
106 <widget class="QCheckBox" name="cpuopt_const_prop">
107 <property name="text">
108 <string>Enable constant propagation</string>
109 </property>
110 <property name="toolTip">
111 <string>
112 &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
113 </string>
114 </property>
115 </widget>
116 </item>
117 <item>
118 <widget class="QCheckBox" name="cpuopt_misc_ir">
119 <property name="text">
120 <string>Enable miscellaneous optimizations</string>
121 </property>
122 <property name="toolTip">
123 <string>
124 &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
125 </string>
126 </property>
127 </widget>
128 </item>
129 <item>
130 <widget class="QCheckBox" name="cpuopt_reduce_misalign_checks">
131 <property name="text">
132 <string>Enable misalignment check reduction</string>
133 </property>
134 <property name="toolTip">
135 <string>
136 &lt;div style="white-space: nowrap"&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
137 &lt;div style="white-space: nowrap"&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
138 </string>
139 </property>
140 </widget>
141 </item>
142 </layout>
143 </widget>
144 </item>
145 </layout>
146 </item>
147 <item>
148 <spacer name="verticalSpacer">
149 <property name="orientation">
150 <enum>Qt::Vertical</enum>
151 </property>
152 <property name="sizeHint" stdset="0">
153 <size>
154 <width>20</width>
155 <height>40</height>
156 </size>
157 </property>
158 </spacer>
159 </item>
160 <item>
161 <widget class="QLabel" name="label_disable_info">
162 <property name="text">
163 <string>CPU settings are available only when game is not running.</string>
164 </property>
165 <property name="wordWrap">
166 <bool>true</bool>
167 </property>
168 </widget>
169 </item>
170 </layout>
171 </widget>
172 <resources/>
173 <connections/>
174</ui>
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 2c77441fd..d0e71dd60 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -36,7 +36,6 @@ void ConfigureDebug::SetConfiguration() {
36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); 36 ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
37 ui->reporting_services->setChecked(Settings::values.reporting_services); 37 ui->reporting_services->setChecked(Settings::values.reporting_services);
38 ui->quest_flag->setChecked(Settings::values.quest_flag); 38 ui->quest_flag->setChecked(Settings::values.quest_flag);
39 ui->disable_cpu_opt->setChecked(Settings::values.disable_cpu_opt);
40 ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 39 ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
41 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); 40 ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
42 ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 41 ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
@@ -51,7 +50,6 @@ void ConfigureDebug::ApplyConfiguration() {
51 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); 50 Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
52 Settings::values.reporting_services = ui->reporting_services->isChecked(); 51 Settings::values.reporting_services = ui->reporting_services->isChecked();
53 Settings::values.quest_flag = ui->quest_flag->isChecked(); 52 Settings::values.quest_flag = ui->quest_flag->isChecked();
54 Settings::values.disable_cpu_opt = ui->disable_cpu_opt->isChecked();
55 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); 53 Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
56 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); 54 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
57 Debugger::ToggleConsole(); 55 Debugger::ToggleConsole();
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 46f0208c6..272bdd6b8 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -228,13 +228,6 @@
228 </property> 228 </property>
229 </widget> 229 </widget>
230 </item> 230 </item>
231 <item>
232 <widget class="QCheckBox" name="disable_cpu_opt">
233 <property name="text">
234 <string>Disable CPU JIT optimizations</string>
235 </property>
236 </widget>
237 </item>
238 </layout> 231 </layout>
239 </widget> 232 </widget>
240 </item> 233 </item>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index df4473b46..a5afb354f 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -14,6 +14,8 @@
14 14
15ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) 15ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
16 : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) { 16 : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
17 Settings::configuring_global = true;
18
17 ui->setupUi(this); 19 ui->setupUi(this);
18 ui->hotkeysTab->Populate(registry); 20 ui->hotkeysTab->Populate(registry);
19 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); 21 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -40,6 +42,8 @@ void ConfigureDialog::ApplyConfiguration() {
40 ui->filesystemTab->applyConfiguration(); 42 ui->filesystemTab->applyConfiguration();
41 ui->inputTab->ApplyConfiguration(); 43 ui->inputTab->ApplyConfiguration();
42 ui->hotkeysTab->ApplyConfiguration(registry); 44 ui->hotkeysTab->ApplyConfiguration(registry);
45 ui->cpuTab->ApplyConfiguration();
46 ui->cpuDebugTab->ApplyConfiguration();
43 ui->graphicsTab->ApplyConfiguration(); 47 ui->graphicsTab->ApplyConfiguration();
44 ui->graphicsAdvancedTab->ApplyConfiguration(); 48 ui->graphicsAdvancedTab->ApplyConfiguration();
45 ui->audioTab->ApplyConfiguration(); 49 ui->audioTab->ApplyConfiguration();
@@ -74,9 +78,10 @@ void ConfigureDialog::RetranslateUI() {
74Q_DECLARE_METATYPE(QList<QWidget*>); 78Q_DECLARE_METATYPE(QList<QWidget*>);
75 79
76void ConfigureDialog::PopulateSelectionList() { 80void ConfigureDialog::PopulateSelectionList() {
77 const std::array<std::pair<QString, QList<QWidget*>>, 5> items{ 81 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
78 {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, 82 {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}},
79 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, 83 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
84 {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}},
80 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, 85 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
81 {tr("Audio"), {ui->audioTab}}, 86 {tr("Audio"), {ui->audioTab}},
82 {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, 87 {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
@@ -105,6 +110,8 @@ void ConfigureDialog::UpdateVisibleTabs() {
105 {ui->profileManagerTab, tr("Profiles")}, 110 {ui->profileManagerTab, tr("Profiles")},
106 {ui->inputTab, tr("Input")}, 111 {ui->inputTab, tr("Input")},
107 {ui->hotkeysTab, tr("Hotkeys")}, 112 {ui->hotkeysTab, tr("Hotkeys")},
113 {ui->cpuTab, tr("CPU")},
114 {ui->cpuDebugTab, tr("Debug")},
108 {ui->graphicsTab, tr("Graphics")}, 115 {ui->graphicsTab, tr("Graphics")},
109 {ui->graphicsAdvancedTab, tr("Advanced")}, 116 {ui->graphicsAdvancedTab, tr("Advanced")},
110 {ui->audioTab, tr("Audio")}, 117 {ui->audioTab, tr("Audio")},
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index 835ee821c..a089f5733 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -11,19 +11,6 @@
11#include "yuzu/configuration/configure_filesystem.h" 11#include "yuzu/configuration/configure_filesystem.h"
12#include "yuzu/uisettings.h" 12#include "yuzu/uisettings.h"
13 13
14namespace {
15
16template <typename T>
17void SetComboBoxFromData(QComboBox* combo_box, T data) {
18 const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data)));
19 if (index >= combo_box->count() || index < 0)
20 return;
21
22 combo_box->setCurrentIndex(index);
23}
24
25} // Anonymous namespace
26
27ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) 14ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
28 : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) { 15 : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) {
29 ui->setupUi(this); 16 ui->setupUi(this);
@@ -73,11 +60,6 @@ void ConfigureFilesystem::setConfiguration() {
73 60
74 ui->cache_game_list->setChecked(UISettings::values.cache_game_list); 61 ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
75 62
76 SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size);
77 SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size);
78 SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size);
79 SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size);
80
81 UpdateEnabledControls(); 63 UpdateEnabledControls();
82} 64}
83 65
@@ -98,15 +80,6 @@ void ConfigureFilesystem::applyConfiguration() {
98 Settings::values.dump_nso = ui->dump_nso->isChecked(); 80 Settings::values.dump_nso = ui->dump_nso->isChecked();
99 81
100 UISettings::values.cache_game_list = ui->cache_game_list->isChecked(); 82 UISettings::values.cache_game_list = ui->cache_game_list->isChecked();
101
102 Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
103 ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong());
104 Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
105 ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong());
106 Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
107 ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong());
108 Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
109 ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong());
110} 83}
111 84
112void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) { 85void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) {
diff --git a/src/yuzu/configuration/configure_filesystem.ui b/src/yuzu/configuration/configure_filesystem.ui
index 58cd07f52..84bea0600 100644
--- a/src/yuzu/configuration/configure_filesystem.ui
+++ b/src/yuzu/configuration/configure_filesystem.ui
@@ -116,127 +116,6 @@
116 </widget> 116 </widget>
117 </item> 117 </item>
118 <item> 118 <item>
119 <widget class="QGroupBox" name="groupBox_3">
120 <property name="title">
121 <string>Storage Sizes</string>
122 </property>
123 <layout class="QGridLayout" name="gridLayout_3">
124 <item row="3" column="0">
125 <widget class="QLabel" name="label_5">
126 <property name="text">
127 <string>SD Card</string>
128 </property>
129 </widget>
130 </item>
131 <item row="1" column="0">
132 <widget class="QLabel" name="label_4">
133 <property name="text">
134 <string>System NAND</string>
135 </property>
136 </widget>
137 </item>
138 <item row="1" column="1">
139 <widget class="QComboBox" name="sysnand_size">
140 <item>
141 <property name="text">
142 <string>2.5 GB</string>
143 </property>
144 </item>
145 </widget>
146 </item>
147 <item row="3" column="1">
148 <widget class="QComboBox" name="sdmc_size">
149 <property name="currentText">
150 <string>32 GB</string>
151 </property>
152 <item>
153 <property name="text">
154 <string>1 GB</string>
155 </property>
156 </item>
157 <item>
158 <property name="text">
159 <string>2 GB</string>
160 </property>
161 </item>
162 <item>
163 <property name="text">
164 <string>4 GB</string>
165 </property>
166 </item>
167 <item>
168 <property name="text">
169 <string>8 GB</string>
170 </property>
171 </item>
172 <item>
173 <property name="text">
174 <string>16 GB</string>
175 </property>
176 </item>
177 <item>
178 <property name="text">
179 <string>32 GB</string>
180 </property>
181 </item>
182 <item>
183 <property name="text">
184 <string>64 GB</string>
185 </property>
186 </item>
187 <item>
188 <property name="text">
189 <string>128 GB</string>
190 </property>
191 </item>
192 <item>
193 <property name="text">
194 <string>256 GB</string>
195 </property>
196 </item>
197 <item>
198 <property name="text">
199 <string>1 TB</string>
200 </property>
201 </item>
202 </widget>
203 </item>
204 <item row="2" column="1">
205 <widget class="QComboBox" name="usrnand_size">
206 <item>
207 <property name="text">
208 <string>26 GB</string>
209 </property>
210 </item>
211 </widget>
212 </item>
213 <item row="2" column="0">
214 <widget class="QLabel" name="label_6">
215 <property name="text">
216 <string>User NAND</string>
217 </property>
218 </widget>
219 </item>
220 <item row="0" column="0">
221 <widget class="QLabel" name="label_7">
222 <property name="text">
223 <string>NAND</string>
224 </property>
225 </widget>
226 </item>
227 <item row="0" column="1">
228 <widget class="QComboBox" name="nand_size">
229 <item>
230 <property name="text">
231 <string>29.1 GB</string>
232 </property>
233 </item>
234 </widget>
235 </item>
236 </layout>
237 </widget>
238 </item>
239 <item>
240 <widget class="QGroupBox" name="groupBox_4"> 119 <widget class="QGroupBox" name="groupBox_4">
241 <property name="title"> 120 <property name="title">
242 <string>Patch Manager</string> 121 <string>Patch Manager</string>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 74b2ad537..20316c9cc 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -7,17 +7,21 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "core/settings.h" 8#include "core/settings.h"
9#include "ui_configure_general.h" 9#include "ui_configure_general.h"
10#include "yuzu/configuration/configuration_shared.h"
10#include "yuzu/configuration/configure_general.h" 11#include "yuzu/configuration/configure_general.h"
11#include "yuzu/uisettings.h" 12#include "yuzu/uisettings.h"
12 13
13ConfigureGeneral::ConfigureGeneral(QWidget* parent) 14ConfigureGeneral::ConfigureGeneral(QWidget* parent)
14 : QWidget(parent), ui(new Ui::ConfigureGeneral) { 15 : QWidget(parent), ui(new Ui::ConfigureGeneral) {
15
16 ui->setupUi(this); 16 ui->setupUi(this);
17 17
18 SetupPerGameUI();
19
18 SetConfiguration(); 20 SetConfiguration();
19 21
20 connect(ui->toggle_frame_limit, &QCheckBox::toggled, ui->frame_limit, &QSpinBox::setEnabled); 22 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, [this]() {
23 ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked);
24 });
21} 25}
22 26
23ConfigureGeneral::~ConfigureGeneral() = default; 27ConfigureGeneral::~ConfigureGeneral() = default;
@@ -26,27 +30,58 @@ void ConfigureGeneral::SetConfiguration() {
26 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 30 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
27 31
28 ui->use_multi_core->setEnabled(runtime_lock); 32 ui->use_multi_core->setEnabled(runtime_lock);
29 ui->use_multi_core->setChecked(Settings::values.use_multi_core); 33 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
30 34
31 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); 35 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
32 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot); 36 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
33 ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background); 37 ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
34 ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse); 38 ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse);
35 39
36 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); 40 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
37 ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); 41 ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
38 ui->frame_limit->setValue(Settings::values.frame_limit); 42
43 if (!Settings::configuring_global) {
44 if (Settings::values.use_multi_core.UsingGlobal()) {
45 ui->use_multi_core->setCheckState(Qt::PartiallyChecked);
46 }
47 if (Settings::values.use_frame_limit.UsingGlobal()) {
48 ui->toggle_frame_limit->setCheckState(Qt::PartiallyChecked);
49 }
50 }
51
52 ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked &&
53 ui->toggle_frame_limit->isEnabled());
39} 54}
40 55
41void ConfigureGeneral::ApplyConfiguration() { 56void ConfigureGeneral::ApplyConfiguration() {
42 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 57 if (Settings::configuring_global) {
43 UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); 58 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
44 UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); 59 UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
45 UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); 60 UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
46 61 UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
47 Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); 62
48 Settings::values.frame_limit = ui->frame_limit->value(); 63 // Guard if during game and set to game-specific value
49 Settings::values.use_multi_core = ui->use_multi_core->isChecked(); 64 if (Settings::values.use_frame_limit.UsingGlobal()) {
65 Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
66 Qt::Checked);
67 Settings::values.frame_limit.SetValue(ui->frame_limit->value());
68 }
69 if (Settings::values.use_multi_core.UsingGlobal()) {
70 Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
71 }
72 } else {
73 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core,
74 ui->use_multi_core);
75
76 bool global_frame_limit = ui->toggle_frame_limit->checkState() == Qt::PartiallyChecked;
77 Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
78 Settings::values.frame_limit.SetGlobal(global_frame_limit);
79 if (!global_frame_limit) {
80 Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
81 Qt::Checked);
82 Settings::values.frame_limit.SetValue(ui->frame_limit->value());
83 }
84 }
50} 85}
51 86
52void ConfigureGeneral::changeEvent(QEvent* event) { 87void ConfigureGeneral::changeEvent(QEvent* event) {
@@ -60,3 +95,20 @@ void ConfigureGeneral::changeEvent(QEvent* event) {
60void ConfigureGeneral::RetranslateUI() { 95void ConfigureGeneral::RetranslateUI() {
61 ui->retranslateUi(this); 96 ui->retranslateUi(this);
62} 97}
98
99void ConfigureGeneral::SetupPerGameUI() {
100 if (Settings::configuring_global) {
101 ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal());
102 ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
103
104 return;
105 }
106
107 ui->toggle_check_exit->setVisible(false);
108 ui->toggle_user_on_boot->setVisible(false);
109 ui->toggle_background_pause->setVisible(false);
110 ui->toggle_hide_mouse->setVisible(false);
111
112 ui->toggle_frame_limit->setTristate(true);
113 ui->use_multi_core->setTristate(true);
114}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index ef05ce065..9c785c22e 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -28,5 +28,7 @@ private:
28 28
29 void SetConfiguration(); 29 void SetConfiguration();
30 30
31 void SetupPerGameUI();
32
31 std::unique_ptr<Ui::ConfigureGeneral> ui; 33 std::unique_ptr<Ui::ConfigureGeneral> ui;
32}; 34};
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 431f51d73..cb4706bd6 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -13,6 +13,7 @@
13#include "core/core.h" 13#include "core/core.h"
14#include "core/settings.h" 14#include "core/settings.h"
15#include "ui_configure_graphics.h" 15#include "ui_configure_graphics.h"
16#include "yuzu/configuration/configuration_shared.h"
16#include "yuzu/configuration/configure_graphics.h" 17#include "yuzu/configuration/configure_graphics.h"
17 18
18#ifdef HAS_VULKAN 19#ifdef HAS_VULKAN
@@ -21,11 +22,13 @@
21 22
22ConfigureGraphics::ConfigureGraphics(QWidget* parent) 23ConfigureGraphics::ConfigureGraphics(QWidget* parent)
23 : QWidget(parent), ui(new Ui::ConfigureGraphics) { 24 : QWidget(parent), ui(new Ui::ConfigureGraphics) {
24 vulkan_device = Settings::values.vulkan_device; 25 vulkan_device = Settings::values.vulkan_device.GetValue();
25 RetrieveVulkanDevices(); 26 RetrieveVulkanDevices();
26 27
27 ui->setupUi(this); 28 ui->setupUi(this);
28 29
30 SetupPerGameUI();
31
29 SetConfiguration(); 32 SetConfiguration();
30 33
31 connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, 34 connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this,
@@ -40,6 +43,9 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
40 } 43 }
41 UpdateBackgroundColorButton(new_bg_color); 44 UpdateBackgroundColorButton(new_bg_color);
42 }); 45 });
46
47 ui->bg_label->setVisible(Settings::configuring_global);
48 ui->bg_combobox->setVisible(!Settings::configuring_global);
43} 49}
44 50
45void ConfigureGraphics::UpdateDeviceSelection(int device) { 51void ConfigureGraphics::UpdateDeviceSelection(int device) {
@@ -57,27 +63,95 @@ void ConfigureGraphics::SetConfiguration() {
57 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 63 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
58 64
59 ui->api->setEnabled(runtime_lock); 65 ui->api->setEnabled(runtime_lock);
60 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend));
61 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio);
62 ui->use_disk_shader_cache->setEnabled(runtime_lock);
63 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
64 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock); 66 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
65 ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation); 67 ui->use_disk_shader_cache->setEnabled(runtime_lock);
66 UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green, 68
67 Settings::values.bg_blue)); 69 if (Settings::configuring_global) {
70 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
71 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
72 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
73 ui->use_asynchronous_gpu_emulation->setChecked(
74 Settings::values.use_asynchronous_gpu_emulation.GetValue());
75 } else {
76 ConfigurationShared::SetPerGameSetting(ui->use_disk_shader_cache,
77 &Settings::values.use_disk_shader_cache);
78 ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_gpu_emulation,
79 &Settings::values.use_asynchronous_gpu_emulation);
80
81 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
82 ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
83 &Settings::values.aspect_ratio);
84
85 ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
86 ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
87 }
88
89 UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(),
90 Settings::values.bg_green.GetValue(),
91 Settings::values.bg_blue.GetValue()));
68 UpdateDeviceComboBox(); 92 UpdateDeviceComboBox();
69} 93}
70 94
71void ConfigureGraphics::ApplyConfiguration() { 95void ConfigureGraphics::ApplyConfiguration() {
72 Settings::values.renderer_backend = GetCurrentGraphicsBackend(); 96 if (Settings::configuring_global) {
73 Settings::values.vulkan_device = vulkan_device; 97 // Guard if during game and set to game-specific value
74 Settings::values.aspect_ratio = ui->aspect_ratio_combobox->currentIndex(); 98 if (Settings::values.renderer_backend.UsingGlobal()) {
75 Settings::values.use_disk_shader_cache = ui->use_disk_shader_cache->isChecked(); 99 Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
76 Settings::values.use_asynchronous_gpu_emulation = 100 }
77 ui->use_asynchronous_gpu_emulation->isChecked(); 101 if (Settings::values.vulkan_device.UsingGlobal()) {
78 Settings::values.bg_red = static_cast<float>(bg_color.redF()); 102 Settings::values.vulkan_device.SetValue(vulkan_device);
79 Settings::values.bg_green = static_cast<float>(bg_color.greenF()); 103 }
80 Settings::values.bg_blue = static_cast<float>(bg_color.blueF()); 104 if (Settings::values.aspect_ratio.UsingGlobal()) {
105 Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
106 }
107 if (Settings::values.use_disk_shader_cache.UsingGlobal()) {
108 Settings::values.use_disk_shader_cache.SetValue(ui->use_disk_shader_cache->isChecked());
109 }
110 if (Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()) {
111 Settings::values.use_asynchronous_gpu_emulation.SetValue(
112 ui->use_asynchronous_gpu_emulation->isChecked());
113 }
114 if (Settings::values.bg_red.UsingGlobal()) {
115 Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
116 Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
117 Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
118 }
119 } else {
120 if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
121 Settings::values.renderer_backend.SetGlobal(true);
122 Settings::values.vulkan_device.SetGlobal(true);
123 } else {
124 Settings::values.renderer_backend.SetGlobal(false);
125 Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
126 if (GetCurrentGraphicsBackend() == Settings::RendererBackend::Vulkan) {
127 Settings::values.vulkan_device.SetGlobal(false);
128 Settings::values.vulkan_device.SetValue(vulkan_device);
129 } else {
130 Settings::values.vulkan_device.SetGlobal(true);
131 }
132 }
133
134 ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
135 ui->aspect_ratio_combobox);
136
137 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
138 ui->use_disk_shader_cache);
139 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
140 ui->use_asynchronous_gpu_emulation);
141
142 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
143 Settings::values.bg_red.SetGlobal(true);
144 Settings::values.bg_green.SetGlobal(true);
145 Settings::values.bg_blue.SetGlobal(true);
146 } else {
147 Settings::values.bg_red.SetGlobal(false);
148 Settings::values.bg_green.SetGlobal(false);
149 Settings::values.bg_blue.SetGlobal(false);
150 Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
151 Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
152 Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
153 }
154 }
81} 155}
82 156
83void ConfigureGraphics::changeEvent(QEvent* event) { 157void ConfigureGraphics::changeEvent(QEvent* event) {
@@ -106,6 +180,11 @@ void ConfigureGraphics::UpdateDeviceComboBox() {
106 ui->device->clear(); 180 ui->device->clear();
107 181
108 bool enabled = false; 182 bool enabled = false;
183
184 if (!Settings::configuring_global &&
185 ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
186 vulkan_device = Settings::values.vulkan_device.GetValue();
187 }
109 switch (GetCurrentGraphicsBackend()) { 188 switch (GetCurrentGraphicsBackend()) {
110 case Settings::RendererBackend::OpenGL: 189 case Settings::RendererBackend::OpenGL:
111 ui->device->addItem(tr("OpenGL Graphics Device")); 190 ui->device->addItem(tr("OpenGL Graphics Device"));
@@ -119,6 +198,9 @@ void ConfigureGraphics::UpdateDeviceComboBox() {
119 enabled = !vulkan_devices.empty(); 198 enabled = !vulkan_devices.empty();
120 break; 199 break;
121 } 200 }
201 // If in per-game config and use global is selected, don't enable.
202 enabled &= !(!Settings::configuring_global &&
203 ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX);
122 ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn()); 204 ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn());
123} 205}
124 206
@@ -132,5 +214,37 @@ void ConfigureGraphics::RetrieveVulkanDevices() {
132} 214}
133 215
134Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { 216Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
135 return static_cast<Settings::RendererBackend>(ui->api->currentIndex()); 217 if (Settings::configuring_global) {
218 return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
219 }
220
221 if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
222 Settings::values.renderer_backend.SetGlobal(true);
223 return Settings::values.renderer_backend.GetValue();
224 }
225 Settings::values.renderer_backend.SetGlobal(false);
226 return static_cast<Settings::RendererBackend>(ui->api->currentIndex() -
227 ConfigurationShared::USE_GLOBAL_OFFSET);
228}
229
230void ConfigureGraphics::SetupPerGameUI() {
231 if (Settings::configuring_global) {
232 ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
233 ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
234 ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
235 ui->use_asynchronous_gpu_emulation->setEnabled(
236 Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
237 ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
238 ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
239
240 return;
241 }
242
243 connect(ui->bg_combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this,
244 [this](int index) { ui->bg_button->setEnabled(index == 1); });
245
246 ui->use_disk_shader_cache->setTristate(true);
247 ui->use_asynchronous_gpu_emulation->setTristate(true);
248 ConfigurationShared::InsertGlobalItem(ui->aspect_ratio_combobox);
249 ConfigurationShared::InsertGlobalItem(ui->api);
136} 250}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 7e0596d9c..24f01c739 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -35,6 +35,8 @@ private:
35 35
36 void RetrieveVulkanDevices(); 36 void RetrieveVulkanDevices();
37 37
38 void SetupPerGameUI();
39
38 Settings::RendererBackend GetCurrentGraphicsBackend() const; 40 Settings::RendererBackend GetCurrentGraphicsBackend() const;
39 41
40 std::unique_ptr<Ui::ConfigureGraphics> ui; 42 std::unique_ptr<Ui::ConfigureGraphics> ui;
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 6e75447a5..62418fc14 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -122,6 +122,29 @@
122 <item> 122 <item>
123 <layout class="QHBoxLayout" name="horizontalLayout_3"> 123 <layout class="QHBoxLayout" name="horizontalLayout_3">
124 <item> 124 <item>
125 <widget class="QComboBox" name="bg_combobox">
126 <property name="currentText">
127 <string>Use global background color</string>
128 </property>
129 <property name="currentIndex">
130 <number>0</number>
131 </property>
132 <property name="maxVisibleItems">
133 <number>10</number>
134 </property>
135 <item>
136 <property name="text">
137 <string>Use global background color</string>
138 </property>
139 </item>
140 <item>
141 <property name="text">
142 <string>Set background color:</string>
143 </property>
144 </item>
145 </widget>
146 </item>
147 <item>
125 <widget class="QLabel" name="bg_label"> 148 <widget class="QLabel" name="bg_label">
126 <property name="text"> 149 <property name="text">
127 <string>Background Color:</string> 150 <string>Background Color:</string>
@@ -129,6 +152,19 @@
129 </widget> 152 </widget>
130 </item> 153 </item>
131 <item> 154 <item>
155 <spacer name="horizontalSpacer">
156 <property name="orientation">
157 <enum>Qt::Horizontal</enum>
158 </property>
159 <property name="sizeHint" stdset="0">
160 <size>
161 <width>40</width>
162 <height>20</height>
163 </size>
164 </property>
165 </spacer>
166 </item>
167 <item>
132 <widget class="QPushButton" name="bg_button"> 168 <widget class="QPushButton" name="bg_button">
133 <property name="maximumSize"> 169 <property name="maximumSize">
134 <size> 170 <size>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index be5006ad3..7c0fa7ec5 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/settings.h" 6#include "core/settings.h"
7#include "ui_configure_graphics_advanced.h" 7#include "ui_configure_graphics_advanced.h"
8#include "yuzu/configuration/configuration_shared.h"
8#include "yuzu/configuration/configure_graphics_advanced.h" 9#include "yuzu/configuration/configure_graphics_advanced.h"
9 10
10ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent) 11ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent)
@@ -12,6 +13,8 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent)
12 13
13 ui->setupUi(this); 14 ui->setupUi(this);
14 15
16 SetupPerGameUI();
17
15 SetConfiguration(); 18 SetConfiguration();
16} 19}
17 20
@@ -19,26 +22,81 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
19 22
20void ConfigureGraphicsAdvanced::SetConfiguration() { 23void ConfigureGraphicsAdvanced::SetConfiguration() {
21 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
22 ui->gpu_accuracy->setCurrentIndex(static_cast<int>(Settings::values.gpu_accuracy));
23 ui->use_vsync->setEnabled(runtime_lock); 25 ui->use_vsync->setEnabled(runtime_lock);
24 ui->use_vsync->setChecked(Settings::values.use_vsync);
25 ui->use_assembly_shaders->setEnabled(runtime_lock); 26 ui->use_assembly_shaders->setEnabled(runtime_lock);
26 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders);
27 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time);
28 ui->force_30fps_mode->setEnabled(runtime_lock); 27 ui->force_30fps_mode->setEnabled(runtime_lock);
29 ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode);
30 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); 28 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
31 ui->anisotropic_filtering_combobox->setCurrentIndex(Settings::values.max_anisotropy); 29
30 if (Settings::configuring_global) {
31 ui->gpu_accuracy->setCurrentIndex(
32 static_cast<int>(Settings::values.gpu_accuracy.GetValue()));
33 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
34 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
35 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
36 ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue());
37 ui->anisotropic_filtering_combobox->setCurrentIndex(
38 Settings::values.max_anisotropy.GetValue());
39 } else {
40 ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy);
41 ConfigurationShared::SetPerGameSetting(ui->use_vsync, &Settings::values.use_vsync);
42 ConfigurationShared::SetPerGameSetting(ui->use_assembly_shaders,
43 &Settings::values.use_assembly_shaders);
44 ConfigurationShared::SetPerGameSetting(ui->use_fast_gpu_time,
45 &Settings::values.use_fast_gpu_time);
46 ConfigurationShared::SetPerGameSetting(ui->force_30fps_mode,
47 &Settings::values.force_30fps_mode);
48 ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox,
49 &Settings::values.max_anisotropy);
50 }
32} 51}
33 52
34void ConfigureGraphicsAdvanced::ApplyConfiguration() { 53void ConfigureGraphicsAdvanced::ApplyConfiguration() {
35 auto gpu_accuracy = static_cast<Settings::GPUAccuracy>(ui->gpu_accuracy->currentIndex()); 54 // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots)
36 Settings::values.gpu_accuracy = gpu_accuracy; 55 const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>(
37 Settings::values.use_vsync = ui->use_vsync->isChecked(); 56 ui->gpu_accuracy->currentIndex() -
38 Settings::values.use_assembly_shaders = ui->use_assembly_shaders->isChecked(); 57 ((Settings::configuring_global) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
39 Settings::values.use_fast_gpu_time = ui->use_fast_gpu_time->isChecked(); 58
40 Settings::values.force_30fps_mode = ui->force_30fps_mode->isChecked(); 59 if (Settings::configuring_global) {
41 Settings::values.max_anisotropy = ui->anisotropic_filtering_combobox->currentIndex(); 60 // Must guard in case of a during-game configuration when set to be game-specific.
61 if (Settings::values.gpu_accuracy.UsingGlobal()) {
62 Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
63 }
64 if (Settings::values.use_vsync.UsingGlobal()) {
65 Settings::values.use_vsync.SetValue(ui->use_vsync->isChecked());
66 }
67 if (Settings::values.use_assembly_shaders.UsingGlobal()) {
68 Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked());
69 }
70 if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
71 Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
72 }
73 if (Settings::values.force_30fps_mode.UsingGlobal()) {
74 Settings::values.force_30fps_mode.SetValue(ui->force_30fps_mode->isChecked());
75 }
76 if (Settings::values.max_anisotropy.UsingGlobal()) {
77 Settings::values.max_anisotropy.SetValue(
78 ui->anisotropic_filtering_combobox->currentIndex());
79 }
80 } else {
81 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
82 ui->anisotropic_filtering_combobox);
83 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync);
84 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
85 ui->use_assembly_shaders);
86 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
87 ui->use_fast_gpu_time);
88 ConfigurationShared::ApplyPerGameSetting(&Settings::values.force_30fps_mode,
89 ui->force_30fps_mode);
90 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
91 ui->anisotropic_filtering_combobox);
92
93 if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
94 Settings::values.gpu_accuracy.SetGlobal(true);
95 } else {
96 Settings::values.gpu_accuracy.SetGlobal(false);
97 Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
98 }
99 }
42} 100}
43 101
44void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { 102void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
@@ -52,3 +110,25 @@ void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
52void ConfigureGraphicsAdvanced::RetranslateUI() { 110void ConfigureGraphicsAdvanced::RetranslateUI() {
53 ui->retranslateUi(this); 111 ui->retranslateUi(this);
54} 112}
113
114void ConfigureGraphicsAdvanced::SetupPerGameUI() {
115 // Disable if not global (only happens during game)
116 if (Settings::configuring_global) {
117 ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
118 ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
119 ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal());
120 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
121 ui->force_30fps_mode->setEnabled(Settings::values.force_30fps_mode.UsingGlobal());
122 ui->anisotropic_filtering_combobox->setEnabled(
123 Settings::values.max_anisotropy.UsingGlobal());
124
125 return;
126 }
127
128 ConfigurationShared::InsertGlobalItem(ui->gpu_accuracy);
129 ui->use_vsync->setTristate(true);
130 ui->use_assembly_shaders->setTristate(true);
131 ui->use_fast_gpu_time->setTristate(true);
132 ui->force_30fps_mode->setTristate(true);
133 ConfigurationShared::InsertGlobalItem(ui->anisotropic_filtering_combobox);
134}
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index bbc9d4355..c043588ff 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -26,5 +26,7 @@ private:
26 26
27 void SetConfiguration(); 27 void SetConfiguration();
28 28
29 void SetupPerGameUI();
30
29 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; 31 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
30}; 32};
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
new file mode 100644
index 000000000..1e49f0787
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -0,0 +1,140 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <memory>
7#include <utility>
8
9#include <QCheckBox>
10#include <QHeaderView>
11#include <QMenu>
12#include <QStandardItemModel>
13#include <QString>
14#include <QTimer>
15#include <QTreeView>
16
17#include "common/common_paths.h"
18#include "common/file_util.h"
19#include "core/file_sys/control_metadata.h"
20#include "core/file_sys/patch_manager.h"
21#include "core/file_sys/xts_archive.h"
22#include "core/loader/loader.h"
23#include "ui_configure_per_game.h"
24#include "yuzu/configuration/config.h"
25#include "yuzu/configuration/configure_input.h"
26#include "yuzu/configuration/configure_per_game.h"
27#include "yuzu/uisettings.h"
28#include "yuzu/util/util.h"
29
30ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id)
31 : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) {
32 game_config = std::make_unique<Config>(fmt::format("{:016X}.ini", title_id), false);
33
34 Settings::configuring_global = false;
35
36 ui->setupUi(this);
37 setFocusPolicy(Qt::ClickFocus);
38 setWindowTitle(tr("Properties"));
39
40 ui->addonsTab->SetTitleId(title_id);
41
42 scene = new QGraphicsScene;
43 ui->icon_view->setScene(scene);
44
45 LoadConfiguration();
46}
47
48ConfigurePerGame::~ConfigurePerGame() = default;
49
50void ConfigurePerGame::ApplyConfiguration() {
51 ui->addonsTab->ApplyConfiguration();
52 ui->generalTab->ApplyConfiguration();
53 ui->systemTab->ApplyConfiguration();
54 ui->graphicsTab->ApplyConfiguration();
55 ui->graphicsAdvancedTab->ApplyConfiguration();
56 ui->audioTab->ApplyConfiguration();
57
58 Settings::Apply();
59 Settings::LogSettings();
60
61 game_config->Save();
62}
63
64void ConfigurePerGame::changeEvent(QEvent* event) {
65 if (event->type() == QEvent::LanguageChange) {
66 RetranslateUI();
67 }
68
69 QDialog::changeEvent(event);
70}
71
72void ConfigurePerGame::RetranslateUI() {
73 ui->retranslateUi(this);
74}
75
76void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file) {
77 this->file = std::move(file);
78 LoadConfiguration();
79}
80
81void ConfigurePerGame::LoadConfiguration() {
82 if (file == nullptr) {
83 return;
84 }
85
86 ui->addonsTab->LoadFromFile(file);
87
88 ui->display_title_id->setText(
89 QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper());
90
91 FileSys::PatchManager pm{title_id};
92 const auto control = pm.GetControlMetadata();
93 const auto loader = Loader::GetLoader(file);
94
95 if (control.first != nullptr) {
96 ui->display_version->setText(QString::fromStdString(control.first->GetVersionString()));
97 ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName()));
98 ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName()));
99 } else {
100 std::string title;
101 if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
102 ui->display_name->setText(QString::fromStdString(title));
103
104 FileSys::NACP nacp;
105 if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success)
106 ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName()));
107
108 ui->display_version->setText(QStringLiteral("1.0.0"));
109 }
110
111 if (control.second != nullptr) {
112 scene->clear();
113
114 QPixmap map;
115 const auto bytes = control.second->ReadAllBytes();
116 map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
117
118 scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
119 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
120 } else {
121 std::vector<u8> bytes;
122 if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) {
123 scene->clear();
124
125 QPixmap map;
126 map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
127
128 scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
129 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
130 }
131 }
132
133 ui->display_filename->setText(QString::fromStdString(file->GetName()));
134
135 ui->display_format->setText(
136 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
137
138 const auto valueText = ReadableByteSize(file->GetSize());
139 ui->display_size->setText(valueText);
140}
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
new file mode 100644
index 000000000..5f9a08cef
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -0,0 +1,51 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <vector>
9
10#include <QDialog>
11#include <QList>
12
13#include "core/file_sys/vfs_types.h"
14#include "yuzu/configuration/config.h"
15
16class QGraphicsScene;
17class QStandardItem;
18class QStandardItemModel;
19class QTreeView;
20class QVBoxLayout;
21
22namespace Ui {
23class ConfigurePerGame;
24}
25
26class ConfigurePerGame : public QDialog {
27 Q_OBJECT
28
29public:
30 explicit ConfigurePerGame(QWidget* parent, u64 title_id);
31 ~ConfigurePerGame() override;
32
33 /// Save all button configurations to settings file
34 void ApplyConfiguration();
35
36 void LoadFromFile(FileSys::VirtualFile file);
37
38private:
39 void changeEvent(QEvent* event) override;
40 void RetranslateUI();
41
42 void LoadConfiguration();
43
44 std::unique_ptr<Ui::ConfigurePerGame> ui;
45 FileSys::VirtualFile file;
46 u64 title_id;
47
48 QGraphicsScene* scene;
49
50 std::unique_ptr<Config> game_config;
51};
diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui
new file mode 100644
index 000000000..d2057c4ab
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game.ui
@@ -0,0 +1,350 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigurePerGame</class>
4 <widget class="QDialog" name="ConfigurePerGame">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>800</width>
10 <height>600</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Dialog</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_3">
17 <item>
18 <layout class="QHBoxLayout" name="horizontalLayout">
19 <item>
20 <widget class="QGroupBox" name="groupBox">
21 <property name="sizePolicy">
22 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
23 <horstretch>0</horstretch>
24 <verstretch>0</verstretch>
25 </sizepolicy>
26 </property>
27 <property name="title">
28 <string>Info</string>
29 </property>
30 <layout class="QVBoxLayout" name="verticalLayout">
31 <item alignment="Qt::AlignHCenter">
32 <widget class="QGraphicsView" name="icon_view">
33 <property name="sizePolicy">
34 <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
35 <horstretch>0</horstretch>
36 <verstretch>0</verstretch>
37 </sizepolicy>
38 </property>
39 <property name="minimumSize">
40 <size>
41 <width>256</width>
42 <height>256</height>
43 </size>
44 </property>
45 <property name="maximumSize">
46 <size>
47 <width>256</width>
48 <height>256</height>
49 </size>
50 </property>
51 <property name="verticalScrollBarPolicy">
52 <enum>Qt::ScrollBarAlwaysOff</enum>
53 </property>
54 <property name="horizontalScrollBarPolicy">
55 <enum>Qt::ScrollBarAlwaysOff</enum>
56 </property>
57 <property name="interactive">
58 <bool>false</bool>
59 </property>
60 </widget>
61 </item>
62 <item>
63 <layout class="QGridLayout" name="gridLayout_2">
64 <item row="6" column="1">
65 <widget class="QLineEdit" name="display_size">
66 <property name="enabled">
67 <bool>true</bool>
68 </property>
69 <property name="readOnly">
70 <bool>true</bool>
71 </property>
72 </widget>
73 </item>
74 <item row="3" column="1">
75 <widget class="QLineEdit" name="display_version">
76 <property name="enabled">
77 <bool>true</bool>
78 </property>
79 <property name="readOnly">
80 <bool>true</bool>
81 </property>
82 </widget>
83 </item>
84 <item row="1" column="0">
85 <widget class="QLabel" name="label">
86 <property name="text">
87 <string>Name</string>
88 </property>
89 </widget>
90 </item>
91 <item row="4" column="0">
92 <widget class="QLabel" name="label_4">
93 <property name="text">
94 <string>Title ID</string>
95 </property>
96 </widget>
97 </item>
98 <item row="4" column="1">
99 <widget class="QLineEdit" name="display_title_id">
100 <property name="enabled">
101 <bool>true</bool>
102 </property>
103 <property name="readOnly">
104 <bool>true</bool>
105 </property>
106 </widget>
107 </item>
108 <item row="7" column="1">
109 <widget class="QLineEdit" name="display_filename">
110 <property name="enabled">
111 <bool>true</bool>
112 </property>
113 <property name="readOnly">
114 <bool>true</bool>
115 </property>
116 </widget>
117 </item>
118 <item row="5" column="1">
119 <widget class="QLineEdit" name="display_format">
120 <property name="enabled">
121 <bool>true</bool>
122 </property>
123 <property name="readOnly">
124 <bool>true</bool>
125 </property>
126 </widget>
127 </item>
128 <item row="7" column="0">
129 <widget class="QLabel" name="label_7">
130 <property name="text">
131 <string>Filename</string>
132 </property>
133 </widget>
134 </item>
135 <item row="1" column="1">
136 <widget class="QLineEdit" name="display_name">
137 <property name="enabled">
138 <bool>true</bool>
139 </property>
140 <property name="readOnly">
141 <bool>true</bool>
142 </property>
143 </widget>
144 </item>
145 <item row="2" column="1">
146 <widget class="QLineEdit" name="display_developer">
147 <property name="enabled">
148 <bool>true</bool>
149 </property>
150 <property name="readOnly">
151 <bool>true</bool>
152 </property>
153 </widget>
154 </item>
155 <item row="5" column="0">
156 <widget class="QLabel" name="label_5">
157 <property name="text">
158 <string>Format</string>
159 </property>
160 </widget>
161 </item>
162 <item row="3" column="0">
163 <widget class="QLabel" name="label_3">
164 <property name="text">
165 <string>Version</string>
166 </property>
167 </widget>
168 </item>
169 <item row="6" column="0">
170 <widget class="QLabel" name="label_6">
171 <property name="text">
172 <string>Size</string>
173 </property>
174 </widget>
175 </item>
176 <item row="2" column="0">
177 <widget class="QLabel" name="label_2">
178 <property name="text">
179 <string>Developer</string>
180 </property>
181 </widget>
182 </item>
183 </layout>
184 </item>
185 <item>
186 <spacer name="verticalSpacer">
187 <property name="orientation">
188 <enum>Qt::Vertical</enum>
189 </property>
190 <property name="sizeHint" stdset="0">
191 <size>
192 <width>20</width>
193 <height>40</height>
194 </size>
195 </property>
196 </spacer>
197 </item>
198 </layout>
199 </widget>
200 </item>
201 <item>
202 <layout class="QVBoxLayout" name="VerticalLayout">
203 <item>
204 <layout class="QVBoxLayout" name="verticalLayout_2"/>
205 </item>
206 <item>
207 <widget class="QTabWidget" name="tabWidget">
208 <property name="enabled">
209 <bool>true</bool>
210 </property>
211 <property name="currentIndex">
212 <number>0</number>
213 </property>
214 <property name="usesScrollButtons">
215 <bool>true</bool>
216 </property>
217 <property name="documentMode">
218 <bool>false</bool>
219 </property>
220 <property name="tabsClosable">
221 <bool>false</bool>
222 </property>
223 <widget class="ConfigurePerGameAddons" name="addonsTab">
224 <attribute name="title">
225 <string>Add-Ons</string>
226 </attribute>
227 </widget>
228 <widget class="ConfigureGeneral" name="generalTab">
229 <attribute name="title">
230 <string>General</string>
231 </attribute>
232 </widget>
233 <widget class="ConfigureSystem" name="systemTab">
234 <attribute name="title">
235 <string>System</string>
236 </attribute>
237 </widget>
238 <widget class="ConfigureGraphics" name="graphicsTab">
239 <attribute name="title">
240 <string>Graphics</string>
241 </attribute>
242 </widget>
243 <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
244 <attribute name="title">
245 <string>Adv. Graphics</string>
246 </attribute>
247 </widget>
248 <widget class="ConfigureAudio" name="audioTab">
249 <attribute name="title">
250 <string>Audio</string>
251 </attribute>
252 </widget>
253 </widget>
254 </item>
255 </layout>
256 </item>
257 </layout>
258 </item>
259 <item>
260 <widget class="QDialogButtonBox" name="buttonBox">
261 <property name="sizePolicy">
262 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
263 <horstretch>0</horstretch>
264 <verstretch>0</verstretch>
265 </sizepolicy>
266 </property>
267 <property name="orientation">
268 <enum>Qt::Horizontal</enum>
269 </property>
270 <property name="standardButtons">
271 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
272 </property>
273 </widget>
274 </item>
275 </layout>
276 </widget>
277 <customwidgets>
278 <customwidget>
279 <class>ConfigureGeneral</class>
280 <extends>QWidget</extends>
281 <header>configuration/configure_general.h</header>
282 <container>1</container>
283 </customwidget>
284 <customwidget>
285 <class>ConfigureSystem</class>
286 <extends>QWidget</extends>
287 <header>configuration/configure_system.h</header>
288 <container>1</container>
289 </customwidget>
290 <customwidget>
291 <class>ConfigureAudio</class>
292 <extends>QWidget</extends>
293 <header>configuration/configure_audio.h</header>
294 <container>1</container>
295 </customwidget>
296 <customwidget>
297 <class>ConfigureGraphics</class>
298 <extends>QWidget</extends>
299 <header>configuration/configure_graphics.h</header>
300 <container>1</container>
301 </customwidget>
302 <customwidget>
303 <class>ConfigureGraphicsAdvanced</class>
304 <extends>QWidget</extends>
305 <header>configuration/configure_graphics_advanced.h</header>
306 <container>1</container>
307 </customwidget>
308 <customwidget>
309 <class>ConfigurePerGameAddons</class>
310 <extends>QWidget</extends>
311 <header>configuration/configure_per_game_addons.h</header>
312 <container>1</container>
313 </customwidget>
314 </customwidgets>
315 <resources/>
316 <connections>
317 <connection>
318 <sender>buttonBox</sender>
319 <signal>accepted()</signal>
320 <receiver>ConfigurePerGame</receiver>
321 <slot>accept()</slot>
322 <hints>
323 <hint type="sourcelabel">
324 <x>248</x>
325 <y>254</y>
326 </hint>
327 <hint type="destinationlabel">
328 <x>157</x>
329 <y>274</y>
330 </hint>
331 </hints>
332 </connection>
333 <connection>
334 <sender>buttonBox</sender>
335 <signal>rejected()</signal>
336 <receiver>ConfigurePerGame</receiver>
337 <slot>reject()</slot>
338 <hints>
339 <hint type="sourcelabel">
340 <x>316</x>
341 <y>260</y>
342 </hint>
343 <hint type="destinationlabel">
344 <x>286</x>
345 <y>274</y>
346 </hint>
347 </hints>
348 </connection>
349 </connections>
350</ui>
diff --git a/src/yuzu/configuration/configure_per_general.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp
index d7f259f12..478d5d3a1 100644
--- a/src/yuzu/configuration/configure_per_general.cpp
+++ b/src/yuzu/configuration/configure_per_game_addons.cpp
@@ -15,23 +15,20 @@
15 15
16#include "common/common_paths.h" 16#include "common/common_paths.h"
17#include "common/file_util.h" 17#include "common/file_util.h"
18#include "core/file_sys/control_metadata.h" 18#include "core/core.h"
19#include "core/file_sys/patch_manager.h" 19#include "core/file_sys/patch_manager.h"
20#include "core/file_sys/xts_archive.h" 20#include "core/file_sys/xts_archive.h"
21#include "core/loader/loader.h" 21#include "core/loader/loader.h"
22#include "ui_configure_per_general.h" 22#include "ui_configure_per_game_addons.h"
23#include "yuzu/configuration/config.h" 23#include "yuzu/configuration/config.h"
24#include "yuzu/configuration/configure_input.h" 24#include "yuzu/configuration/configure_input.h"
25#include "yuzu/configuration/configure_per_general.h" 25#include "yuzu/configuration/configure_per_game_addons.h"
26#include "yuzu/uisettings.h" 26#include "yuzu/uisettings.h"
27#include "yuzu/util/util.h" 27#include "yuzu/util/util.h"
28 28
29ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id) 29ConfigurePerGameAddons::ConfigurePerGameAddons(QWidget* parent)
30 : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGameGeneral>()), title_id(title_id) { 30 : QWidget(parent), ui(new Ui::ConfigurePerGameAddons) {
31
32 ui->setupUi(this); 31 ui->setupUi(this);
33 setFocusPolicy(Qt::ClickFocus);
34 setWindowTitle(tr("Properties"));
35 32
36 layout = new QVBoxLayout; 33 layout = new QVBoxLayout;
37 tree_view = new QTreeView; 34 tree_view = new QTreeView;
@@ -52,7 +49,7 @@ ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
52 item_model->setHeaderData(1, Qt::Horizontal, tr("Version")); 49 item_model->setHeaderData(1, Qt::Horizontal, tr("Version"));
53 50
54 // We must register all custom types with the Qt Automoc system so that we are able to use it 51 // We must register all custom types with the Qt Automoc system so that we are able to use it
55 // with signals/slots. In this case, QList falls under the umbrells of custom types. 52 // with signals/slots. In this case, QList falls under the umbrella of custom types.
56 qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>"); 53 qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
57 54
58 layout->setContentsMargins(0, 0, 0, 0); 55 layout->setContentsMargins(0, 0, 0, 0);
@@ -61,18 +58,15 @@ ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
61 58
62 ui->scrollArea->setLayout(layout); 59 ui->scrollArea->setLayout(layout);
63 60
64 scene = new QGraphicsScene; 61 ui->scrollArea->setEnabled(!Core::System::GetInstance().IsPoweredOn());
65 ui->icon_view->setScene(scene);
66 62
67 connect(item_model, &QStandardItemModel::itemChanged, 63 connect(item_model, &QStandardItemModel::itemChanged,
68 [] { UISettings::values.is_game_list_reload_pending.exchange(true); }); 64 [] { UISettings::values.is_game_list_reload_pending.exchange(true); });
69
70 LoadConfiguration();
71} 65}
72 66
73ConfigurePerGameGeneral::~ConfigurePerGameGeneral() = default; 67ConfigurePerGameAddons::~ConfigurePerGameAddons() = default;
74 68
75void ConfigurePerGameGeneral::ApplyConfiguration() { 69void ConfigurePerGameAddons::ApplyConfiguration() {
76 std::vector<std::string> disabled_addons; 70 std::vector<std::string> disabled_addons;
77 71
78 for (const auto& item : list_items) { 72 for (const auto& item : list_items) {
@@ -92,72 +86,35 @@ void ConfigurePerGameGeneral::ApplyConfiguration() {
92 Settings::values.disabled_addons[title_id] = disabled_addons; 86 Settings::values.disabled_addons[title_id] = disabled_addons;
93} 87}
94 88
95void ConfigurePerGameGeneral::changeEvent(QEvent* event) { 89void ConfigurePerGameAddons::LoadFromFile(FileSys::VirtualFile file) {
90 this->file = std::move(file);
91 LoadConfiguration();
92}
93
94void ConfigurePerGameAddons::SetTitleId(u64 id) {
95 this->title_id = id;
96}
97
98void ConfigurePerGameAddons::changeEvent(QEvent* event) {
96 if (event->type() == QEvent::LanguageChange) { 99 if (event->type() == QEvent::LanguageChange) {
97 RetranslateUI(); 100 RetranslateUI();
98 } 101 }
99 102
100 QDialog::changeEvent(event); 103 QWidget::changeEvent(event);
101} 104}
102 105
103void ConfigurePerGameGeneral::RetranslateUI() { 106void ConfigurePerGameAddons::RetranslateUI() {
104 ui->retranslateUi(this); 107 ui->retranslateUi(this);
105} 108}
106 109
107void ConfigurePerGameGeneral::LoadFromFile(FileSys::VirtualFile file) { 110void ConfigurePerGameAddons::LoadConfiguration() {
108 this->file = std::move(file);
109 LoadConfiguration();
110}
111
112void ConfigurePerGameGeneral::LoadConfiguration() {
113 if (file == nullptr) { 111 if (file == nullptr) {
114 return; 112 return;
115 } 113 }
116 114
117 ui->display_title_id->setText(QString::fromStdString(fmt::format("{:016X}", title_id)));
118
119 FileSys::PatchManager pm{title_id}; 115 FileSys::PatchManager pm{title_id};
120 const auto control = pm.GetControlMetadata();
121 const auto loader = Loader::GetLoader(file); 116 const auto loader = Loader::GetLoader(file);
122 117
123 if (control.first != nullptr) {
124 ui->display_version->setText(QString::fromStdString(control.first->GetVersionString()));
125 ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName()));
126 ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName()));
127 } else {
128 std::string title;
129 if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
130 ui->display_name->setText(QString::fromStdString(title));
131
132 FileSys::NACP nacp;
133 if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success)
134 ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName()));
135
136 ui->display_version->setText(QStringLiteral("1.0.0"));
137 }
138
139 if (control.second != nullptr) {
140 scene->clear();
141
142 QPixmap map;
143 const auto bytes = control.second->ReadAllBytes();
144 map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
145
146 scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
147 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
148 } else {
149 std::vector<u8> bytes;
150 if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) {
151 scene->clear();
152
153 QPixmap map;
154 map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
155
156 scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
157 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
158 }
159 }
160
161 FileSys::VirtualFile update_raw; 118 FileSys::VirtualFile update_raw;
162 loader->ReadUpdateRaw(update_raw); 119 loader->ReadUpdateRaw(update_raw);
163 120
@@ -182,12 +139,4 @@ void ConfigurePerGameGeneral::LoadConfiguration() {
182 } 139 }
183 140
184 tree_view->setColumnWidth(0, 5 * tree_view->width() / 16); 141 tree_view->setColumnWidth(0, 5 * tree_view->width() / 16);
185
186 ui->display_filename->setText(QString::fromStdString(file->GetName()));
187
188 ui->display_format->setText(
189 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
190
191 const auto valueText = ReadableByteSize(file->GetSize());
192 ui->display_size->setText(valueText);
193} 142}
diff --git a/src/yuzu/configuration/configure_per_general.h b/src/yuzu/configuration/configure_per_game_addons.h
index a3b2cdeff..a00ec3539 100644
--- a/src/yuzu/configuration/configure_per_general.h
+++ b/src/yuzu/configuration/configure_per_game_addons.h
@@ -1,4 +1,4 @@
1// Copyright 2016 Citra Emulator Project 1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
@@ -7,7 +7,6 @@
7#include <memory> 7#include <memory>
8#include <vector> 8#include <vector>
9 9
10#include <QDialog>
11#include <QList> 10#include <QList>
12 11
13#include "core/file_sys/vfs_types.h" 12#include "core/file_sys/vfs_types.h"
@@ -19,35 +18,36 @@ class QTreeView;
19class QVBoxLayout; 18class QVBoxLayout;
20 19
21namespace Ui { 20namespace Ui {
22class ConfigurePerGameGeneral; 21class ConfigurePerGameAddons;
23} 22}
24 23
25class ConfigurePerGameGeneral : public QDialog { 24class ConfigurePerGameAddons : public QWidget {
26 Q_OBJECT 25 Q_OBJECT
27 26
28public: 27public:
29 explicit ConfigurePerGameGeneral(QWidget* parent, u64 title_id); 28 explicit ConfigurePerGameAddons(QWidget* parent = nullptr);
30 ~ConfigurePerGameGeneral() override; 29 ~ConfigurePerGameAddons() override;
31 30
32 /// Save all button configurations to settings file 31 /// Save all button configurations to settings file
33 void ApplyConfiguration(); 32 void ApplyConfiguration();
34 33
35 void LoadFromFile(FileSys::VirtualFile file); 34 void LoadFromFile(FileSys::VirtualFile file);
36 35
36 void SetTitleId(u64 id);
37
37private: 38private:
38 void changeEvent(QEvent* event) override; 39 void changeEvent(QEvent* event) override;
39 void RetranslateUI(); 40 void RetranslateUI();
40 41
41 void LoadConfiguration(); 42 void LoadConfiguration();
42 43
43 std::unique_ptr<Ui::ConfigurePerGameGeneral> ui; 44 std::unique_ptr<Ui::ConfigurePerGameAddons> ui;
44 FileSys::VirtualFile file; 45 FileSys::VirtualFile file;
45 u64 title_id; 46 u64 title_id;
46 47
47 QVBoxLayout* layout; 48 QVBoxLayout* layout;
48 QTreeView* tree_view; 49 QTreeView* tree_view;
49 QStandardItemModel* item_model; 50 QStandardItemModel* item_model;
50 QGraphicsScene* scene;
51 51
52 std::vector<QList<QStandardItem*>> list_items; 52 std::vector<QList<QStandardItem*>> list_items;
53}; 53};
diff --git a/src/yuzu/configuration/configure_per_game_addons.ui b/src/yuzu/configuration/configure_per_game_addons.ui
new file mode 100644
index 000000000..aefdebfcd
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game_addons.ui
@@ -0,0 +1,38 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigurePerGameAddons</class>
4 <widget class="QWidget" name="ConfigurePerGameAddons">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>300</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QGridLayout" name="gridLayout">
17 <item row="0" column="0">
18 <widget class="QScrollArea" name="scrollArea">
19 <property name="widgetResizable">
20 <bool>true</bool>
21 </property>
22 <widget class="QWidget" name="scrollAreaWidgetContents">
23 <property name="geometry">
24 <rect>
25 <x>0</x>
26 <y>0</y>
27 <width>380</width>
28 <height>280</height>
29 </rect>
30 </property>
31 </widget>
32 </widget>
33 </item>
34 </layout>
35 </widget>
36 <resources/>
37 <connections/>
38</ui>
diff --git a/src/yuzu/configuration/configure_per_general.ui b/src/yuzu/configuration/configure_per_general.ui
deleted file mode 100644
index 8fdd96fa4..000000000
--- a/src/yuzu/configuration/configure_per_general.ui
+++ /dev/null
@@ -1,276 +0,0 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigurePerGameGeneral</class>
4 <widget class="QDialog" name="ConfigurePerGameGeneral">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>520</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>ConfigurePerGameGeneral</string>
15 </property>
16 <layout class="QHBoxLayout" name="HorizontalLayout">
17 <item>
18 <layout class="QVBoxLayout" name="VerticalLayout">
19 <item>
20 <widget class="QGroupBox" name="GeneralGroupBox">
21 <property name="title">
22 <string>Info</string>
23 </property>
24 <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
25 <item>
26 <layout class="QGridLayout" name="gridLayout_2">
27 <item row="6" column="1" colspan="2">
28 <widget class="QLineEdit" name="display_filename">
29 <property name="enabled">
30 <bool>true</bool>
31 </property>
32 <property name="readOnly">
33 <bool>true</bool>
34 </property>
35 </widget>
36 </item>
37 <item row="0" column="1">
38 <widget class="QLineEdit" name="display_name">
39 <property name="enabled">
40 <bool>true</bool>
41 </property>
42 <property name="readOnly">
43 <bool>true</bool>
44 </property>
45 </widget>
46 </item>
47 <item row="1" column="0">
48 <widget class="QLabel" name="label_2">
49 <property name="text">
50 <string>Developer</string>
51 </property>
52 </widget>
53 </item>
54 <item row="5" column="1" colspan="2">
55 <widget class="QLineEdit" name="display_size">
56 <property name="enabled">
57 <bool>true</bool>
58 </property>
59 <property name="readOnly">
60 <bool>true</bool>
61 </property>
62 </widget>
63 </item>
64 <item row="0" column="0">
65 <widget class="QLabel" name="label">
66 <property name="text">
67 <string>Name</string>
68 </property>
69 </widget>
70 </item>
71 <item row="6" column="0">
72 <widget class="QLabel" name="label_7">
73 <property name="text">
74 <string>Filename</string>
75 </property>
76 </widget>
77 </item>
78 <item row="2" column="0">
79 <widget class="QLabel" name="label_3">
80 <property name="text">
81 <string>Version</string>
82 </property>
83 </widget>
84 </item>
85 <item row="4" column="0">
86 <widget class="QLabel" name="label_5">
87 <property name="text">
88 <string>Format</string>
89 </property>
90 </widget>
91 </item>
92 <item row="2" column="1">
93 <widget class="QLineEdit" name="display_version">
94 <property name="enabled">
95 <bool>true</bool>
96 </property>
97 <property name="readOnly">
98 <bool>true</bool>
99 </property>
100 </widget>
101 </item>
102 <item row="4" column="1">
103 <widget class="QLineEdit" name="display_format">
104 <property name="enabled">
105 <bool>true</bool>
106 </property>
107 <property name="readOnly">
108 <bool>true</bool>
109 </property>
110 </widget>
111 </item>
112 <item row="5" column="0">
113 <widget class="QLabel" name="label_6">
114 <property name="text">
115 <string>Size</string>
116 </property>
117 </widget>
118 </item>
119 <item row="1" column="1">
120 <widget class="QLineEdit" name="display_developer">
121 <property name="enabled">
122 <bool>true</bool>
123 </property>
124 <property name="readOnly">
125 <bool>true</bool>
126 </property>
127 </widget>
128 </item>
129 <item row="3" column="0">
130 <widget class="QLabel" name="label_4">
131 <property name="text">
132 <string>Title ID</string>
133 </property>
134 </widget>
135 </item>
136 <item row="3" column="1">
137 <widget class="QLineEdit" name="display_title_id">
138 <property name="enabled">
139 <bool>true</bool>
140 </property>
141 <property name="readOnly">
142 <bool>true</bool>
143 </property>
144 </widget>
145 </item>
146 <item row="0" column="2" rowspan="5">
147 <widget class="QGraphicsView" name="icon_view">
148 <property name="sizePolicy">
149 <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
150 <horstretch>0</horstretch>
151 <verstretch>0</verstretch>
152 </sizepolicy>
153 </property>
154 <property name="minimumSize">
155 <size>
156 <width>128</width>
157 <height>128</height>
158 </size>
159 </property>
160 <property name="maximumSize">
161 <size>
162 <width>128</width>
163 <height>128</height>
164 </size>
165 </property>
166 <property name="verticalScrollBarPolicy">
167 <enum>Qt::ScrollBarAlwaysOff</enum>
168 </property>
169 <property name="horizontalScrollBarPolicy">
170 <enum>Qt::ScrollBarAlwaysOff</enum>
171 </property>
172 <property name="sizeAdjustPolicy">
173 <enum>QAbstractScrollArea::AdjustToContents</enum>
174 </property>
175 <property name="interactive">
176 <bool>false</bool>
177 </property>
178 </widget>
179 </item>
180 </layout>
181 </item>
182 </layout>
183 </widget>
184 </item>
185 <item>
186 <widget class="QGroupBox" name="PerformanceGroupBox">
187 <property name="title">
188 <string>Add-Ons</string>
189 </property>
190 <layout class="QHBoxLayout" name="PerformanceHorizontalLayout">
191 <item>
192 <widget class="QScrollArea" name="scrollArea">
193 <property name="widgetResizable">
194 <bool>true</bool>
195 </property>
196 <widget class="QWidget" name="scrollAreaWidgetContents">
197 <property name="geometry">
198 <rect>
199 <x>0</x>
200 <y>0</y>
201 <width>350</width>
202 <height>169</height>
203 </rect>
204 </property>
205 </widget>
206 </widget>
207 </item>
208 <item>
209 <layout class="QVBoxLayout" name="PerformanceVerticalLayout"/>
210 </item>
211 </layout>
212 </widget>
213 </item>
214 <item>
215 <spacer name="verticalSpacer">
216 <property name="orientation">
217 <enum>Qt::Vertical</enum>
218 </property>
219 <property name="sizeType">
220 <enum>QSizePolicy::Fixed</enum>
221 </property>
222 <property name="sizeHint" stdset="0">
223 <size>
224 <width>20</width>
225 <height>40</height>
226 </size>
227 </property>
228 </spacer>
229 </item>
230 <item>
231 <widget class="QDialogButtonBox" name="buttonBox">
232 <property name="standardButtons">
233 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
234 </property>
235 </widget>
236 </item>
237 </layout>
238 </item>
239 </layout>
240 </widget>
241 <resources/>
242 <connections>
243 <connection>
244 <sender>buttonBox</sender>
245 <signal>accepted()</signal>
246 <receiver>ConfigurePerGameGeneral</receiver>
247 <slot>accept()</slot>
248 <hints>
249 <hint type="sourcelabel">
250 <x>269</x>
251 <y>567</y>
252 </hint>
253 <hint type="destinationlabel">
254 <x>269</x>
255 <y>294</y>
256 </hint>
257 </hints>
258 </connection>
259 <connection>
260 <sender>buttonBox</sender>
261 <signal>rejected()</signal>
262 <receiver>ConfigurePerGameGeneral</receiver>
263 <slot>reject()</slot>
264 <hints>
265 <hint type="sourcelabel">
266 <x>269</x>
267 <y>567</y>
268 </hint>
269 <hint type="destinationlabel">
270 <x>269</x>
271 <y>294</y>
272 </hint>
273 </hints>
274 </connection>
275 </connections>
276</ui>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 10315e7a6..68e02738b 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -14,6 +14,7 @@
14#include "core/core.h" 14#include "core/core.h"
15#include "core/settings.h" 15#include "core/settings.h"
16#include "ui_configure_system.h" 16#include "ui_configure_system.h"
17#include "yuzu/configuration/configuration_shared.h"
17#include "yuzu/configuration/configure_system.h" 18#include "yuzu/configuration/configure_system.h"
18 19
19ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) { 20ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) {
@@ -21,20 +22,25 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::
21 connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, 22 connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
22 &ConfigureSystem::RefreshConsoleID); 23 &ConfigureSystem::RefreshConsoleID);
23 24
24 connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) { 25 connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
25 ui->rng_seed_edit->setEnabled(checked); 26 ui->rng_seed_edit->setEnabled(state == Qt::Checked);
26 if (!checked) { 27 if (state != Qt::Checked) {
27 ui->rng_seed_edit->setText(QStringLiteral("00000000")); 28 ui->rng_seed_edit->setText(QStringLiteral("00000000"));
28 } 29 }
29 }); 30 });
30 31
31 connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) { 32 connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
32 ui->custom_rtc_edit->setEnabled(checked); 33 ui->custom_rtc_edit->setEnabled(state == Qt::Checked);
33 if (!checked) { 34 if (state != Qt::Checked) {
34 ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime()); 35 ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime());
35 } 36 }
36 }); 37 });
37 38
39 ui->label_console_id->setVisible(Settings::configuring_global);
40 ui->button_regenerate_console_id->setVisible(Settings::configuring_global);
41
42 SetupPerGameUI();
43
38 SetConfiguration(); 44 SetConfiguration();
39} 45}
40 46
@@ -54,26 +60,58 @@ void ConfigureSystem::RetranslateUI() {
54 60
55void ConfigureSystem::SetConfiguration() { 61void ConfigureSystem::SetConfiguration() {
56 enabled = !Core::System::GetInstance().IsPoweredOn(); 62 enabled = !Core::System::GetInstance().IsPoweredOn();
63 const auto rng_seed =
64 QStringLiteral("%1")
65 .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
66 .toUpper();
67 const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or(
68 std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
57 69
58 ui->combo_language->setCurrentIndex(Settings::values.language_index); 70 if (Settings::configuring_global) {
59 ui->combo_region->setCurrentIndex(Settings::values.region_index); 71 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
60 ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index); 72 ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue());
61 ui->combo_sound->setCurrentIndex(Settings::values.sound_index); 73 ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue());
62 74 ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue());
63 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value()); 75
64 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value()); 76 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
65 77 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
66 const auto rng_seed = QStringLiteral("%1") 78 Settings::values.rng_seed.UsingGlobal());
67 .arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}) 79 ui->rng_seed_edit->setText(rng_seed);
68 .toUpper(); 80
69 ui->rng_seed_edit->setText(rng_seed); 81 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value());
70 82 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() &&
71 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value()); 83 Settings::values.rng_seed.UsingGlobal());
72 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value()); 84 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
85 } else {
86 ConfigurationShared::SetPerGameSetting(ui->combo_language,
87 &Settings::values.language_index);
88 ConfigurationShared::SetPerGameSetting(ui->combo_region, &Settings::values.region_index);
89 ConfigurationShared::SetPerGameSetting(ui->combo_time_zone,
90 &Settings::values.time_zone_index);
91 ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index);
92
93 if (Settings::values.rng_seed.UsingGlobal()) {
94 ui->rng_seed_checkbox->setCheckState(Qt::PartiallyChecked);
95 } else {
96 ui->rng_seed_checkbox->setCheckState(
97 Settings::values.rng_seed.GetValue().has_value() ? Qt::Checked : Qt::Unchecked);
98 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value());
99 if (Settings::values.rng_seed.GetValue().has_value()) {
100 ui->rng_seed_edit->setText(rng_seed);
101 }
102 }
73 103
74 const auto rtc_time = Settings::values.custom_rtc.value_or( 104 if (Settings::values.custom_rtc.UsingGlobal()) {
75 std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); 105 ui->custom_rtc_checkbox->setCheckState(Qt::PartiallyChecked);
76 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); 106 } else {
107 ui->custom_rtc_checkbox->setCheckState(
108 Settings::values.custom_rtc.GetValue().has_value() ? Qt::Checked : Qt::Unchecked);
109 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value());
110 if (Settings::values.custom_rtc.GetValue().has_value()) {
111 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
112 }
113 }
114 }
77} 115}
78 116
79void ConfigureSystem::ReadSystemSettings() {} 117void ConfigureSystem::ReadSystemSettings() {}
@@ -83,22 +121,78 @@ void ConfigureSystem::ApplyConfiguration() {
83 return; 121 return;
84 } 122 }
85 123
86 Settings::values.language_index = ui->combo_language->currentIndex(); 124 if (Settings::configuring_global) {
87 Settings::values.region_index = ui->combo_region->currentIndex(); 125 // Guard if during game and set to game-specific value
88 Settings::values.time_zone_index = ui->combo_time_zone->currentIndex(); 126 if (Settings::values.language_index.UsingGlobal()) {
89 Settings::values.sound_index = ui->combo_sound->currentIndex(); 127 Settings::values.language_index.SetValue(ui->combo_language->currentIndex());
128 }
129 if (Settings::values.region_index.UsingGlobal()) {
130 Settings::values.region_index.SetValue(ui->combo_region->currentIndex());
131 }
132 if (Settings::values.time_zone_index.UsingGlobal()) {
133 Settings::values.time_zone_index.SetValue(ui->combo_time_zone->currentIndex());
134 }
135 if (Settings::values.sound_index.UsingGlobal()) {
136 Settings::values.sound_index.SetValue(ui->combo_sound->currentIndex());
137 }
138
139 if (Settings::values.rng_seed.UsingGlobal()) {
140 if (ui->rng_seed_checkbox->isChecked()) {
141 Settings::values.rng_seed.SetValue(
142 ui->rng_seed_edit->text().toULongLong(nullptr, 16));
143 } else {
144 Settings::values.rng_seed.SetValue(std::nullopt);
145 }
146 }
90 147
91 if (ui->rng_seed_checkbox->isChecked()) { 148 if (Settings::values.custom_rtc.UsingGlobal()) {
92 Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16); 149 if (ui->custom_rtc_checkbox->isChecked()) {
150 Settings::values.custom_rtc.SetValue(
151 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
152 } else {
153 Settings::values.custom_rtc.SetValue(std::nullopt);
154 }
155 }
93 } else { 156 } else {
94 Settings::values.rng_seed = std::nullopt; 157 ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
95 } 158 ui->combo_language);
159 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
160 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
161 ui->combo_time_zone);
162 ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
163
164 switch (ui->rng_seed_checkbox->checkState()) {
165 case Qt::Checked:
166 Settings::values.rng_seed.SetGlobal(false);
167 Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toULongLong(nullptr, 16));
168 break;
169 case Qt::Unchecked:
170 Settings::values.rng_seed.SetGlobal(false);
171 Settings::values.rng_seed.SetValue(std::nullopt);
172 break;
173 case Qt::PartiallyChecked:
174 Settings::values.rng_seed.SetGlobal(false);
175 Settings::values.rng_seed.SetValue(std::nullopt);
176 Settings::values.rng_seed.SetGlobal(true);
177 break;
178 }
96 179
97 if (ui->custom_rtc_checkbox->isChecked()) { 180 switch (ui->custom_rtc_checkbox->checkState()) {
98 Settings::values.custom_rtc = 181 case Qt::Checked:
99 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()); 182 Settings::values.custom_rtc.SetGlobal(false);
100 } else { 183 Settings::values.custom_rtc.SetValue(
101 Settings::values.custom_rtc = std::nullopt; 184 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
185 break;
186 case Qt::Unchecked:
187 Settings::values.custom_rtc.SetGlobal(false);
188 Settings::values.custom_rtc.SetValue(std::nullopt);
189 break;
190 case Qt::PartiallyChecked:
191 Settings::values.custom_rtc.SetGlobal(false);
192 Settings::values.custom_rtc.SetValue(std::nullopt);
193 Settings::values.custom_rtc.SetGlobal(true);
194 break;
195 }
102 } 196 }
103 197
104 Settings::Apply(); 198 Settings::Apply();
@@ -120,3 +214,25 @@ void ConfigureSystem::RefreshConsoleID() {
120 ui->label_console_id->setText( 214 ui->label_console_id->setText(
121 tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper())); 215 tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
122} 216}
217
218void ConfigureSystem::SetupPerGameUI() {
219 if (Settings::configuring_global) {
220 ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal());
221 ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal());
222 ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal());
223 ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
224 ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
225 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
226 ui->custom_rtc_checkbox->setEnabled(Settings::values.custom_rtc.UsingGlobal());
227 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.UsingGlobal());
228
229 return;
230 }
231
232 ConfigurationShared::InsertGlobalItem(ui->combo_language);
233 ConfigurationShared::InsertGlobalItem(ui->combo_region);
234 ConfigurationShared::InsertGlobalItem(ui->combo_time_zone);
235 ConfigurationShared::InsertGlobalItem(ui->combo_sound);
236 ui->rng_seed_checkbox->setTristate(true);
237 ui->custom_rtc_checkbox->setTristate(true);
238}
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index 26d42d5c5..f317ef8b5 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -32,6 +32,8 @@ private:
32 32
33 void RefreshConsoleID(); 33 void RefreshConsoleID();
34 34
35 void SetupPerGameUI();
36
35 std::unique_ptr<Ui::ConfigureSystem> ui; 37 std::unique_ptr<Ui::ConfigureSystem> ui;
36 bool enabled = false; 38 bool enabled = false;
37 39
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index bfb600df0..ab7fc7a24 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -531,8 +531,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
531 UISettings::GameDir& game_dir = 531 UISettings::GameDir& game_dir =
532 *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); 532 *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>();
533 533
534 QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up")); 534 QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up"));
535 QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down ")); 535 QAction* move_down = context_menu.addAction(tr("\u25bc Move Down"));
536 QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location")); 536 QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
537 537
538 const int row = selected.row(); 538 const int row = selected.row();
diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp
new file mode 100644
index 000000000..06b0b1874
--- /dev/null
+++ b/src/yuzu/install_dialog.cpp
@@ -0,0 +1,72 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QCheckBox>
6#include <QDialogButtonBox>
7#include <QFileInfo>
8#include <QHBoxLayout>
9#include <QLabel>
10#include <QListWidget>
11#include <QVBoxLayout>
12#include "yuzu/install_dialog.h"
13#include "yuzu/uisettings.h"
14
15InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) {
16 file_list = new QListWidget(this);
17
18 for (const QString& file : files) {
19 QListWidgetItem* item = new QListWidgetItem(QFileInfo(file).fileName(), file_list);
20 item->setData(Qt::UserRole, file);
21 item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
22 item->setCheckState(Qt::Checked);
23 }
24
25 file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 11) / 10);
26
27 vbox_layout = new QVBoxLayout;
28
29 hbox_layout = new QHBoxLayout;
30
31 description = new QLabel(tr("Please confirm these are the files you wish to install."));
32
33 update_description =
34 new QLabel(tr("Installing an Update or DLC will overwrite the previously installed one."));
35
36 buttons = new QDialogButtonBox;
37 buttons->addButton(QDialogButtonBox::Cancel);
38 buttons->addButton(tr("Install"), QDialogButtonBox::AcceptRole);
39
40 connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept);
41 connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject);
42
43 hbox_layout->addWidget(buttons);
44
45 vbox_layout->addWidget(description);
46 vbox_layout->addWidget(update_description);
47 vbox_layout->addWidget(file_list);
48 vbox_layout->addLayout(hbox_layout);
49
50 setLayout(vbox_layout);
51 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
52 setWindowTitle(tr("Install Files to NAND"));
53}
54
55InstallDialog::~InstallDialog() = default;
56
57QStringList InstallDialog::GetFiles() const {
58 QStringList files;
59
60 for (int i = 0; i < file_list->count(); ++i) {
61 const QListWidgetItem* item = file_list->item(i);
62 if (item->checkState() == Qt::Checked) {
63 files.append(item->data(Qt::UserRole).toString());
64 }
65 }
66
67 return files;
68}
69
70int InstallDialog::GetMinimumWidth() const {
71 return file_list->width();
72}
diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h
new file mode 100644
index 000000000..e4aba1b06
--- /dev/null
+++ b/src/yuzu/install_dialog.h
@@ -0,0 +1,36 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDialog>
8
9class QCheckBox;
10class QDialogButtonBox;
11class QHBoxLayout;
12class QLabel;
13class QListWidget;
14class QVBoxLayout;
15
16class InstallDialog : public QDialog {
17 Q_OBJECT
18
19public:
20 explicit InstallDialog(QWidget* parent, const QStringList& files);
21 ~InstallDialog() override;
22
23 QStringList GetFiles() const;
24 bool ShouldOverwriteFiles() const;
25 int GetMinimumWidth() const;
26
27private:
28 QListWidget* file_list;
29
30 QVBoxLayout* vbox_layout;
31 QHBoxLayout* hbox_layout;
32
33 QLabel* description;
34 QLabel* update_description;
35 QDialogButtonBox* buttons;
36};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9844e4764..432379705 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -16,7 +16,7 @@
16#include "applets/software_keyboard.h" 16#include "applets/software_keyboard.h"
17#include "applets/web_browser.h" 17#include "applets/web_browser.h"
18#include "configuration/configure_input.h" 18#include "configuration/configure_input.h"
19#include "configuration/configure_per_general.h" 19#include "configuration/configure_per_game.h"
20#include "core/file_sys/vfs.h" 20#include "core/file_sys/vfs.h"
21#include "core/file_sys/vfs_real.h" 21#include "core/file_sys/vfs_real.h"
22#include "core/frontend/applets/general_frontend.h" 22#include "core/frontend/applets/general_frontend.h"
@@ -107,6 +107,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
107#include "yuzu/game_list.h" 107#include "yuzu/game_list.h"
108#include "yuzu/game_list_p.h" 108#include "yuzu/game_list_p.h"
109#include "yuzu/hotkeys.h" 109#include "yuzu/hotkeys.h"
110#include "yuzu/install_dialog.h"
110#include "yuzu/loading_screen.h" 111#include "yuzu/loading_screen.h"
111#include "yuzu/main.h" 112#include "yuzu/main.h"
112#include "yuzu/uisettings.h" 113#include "yuzu/uisettings.h"
@@ -534,15 +535,15 @@ void GMainWindow::InitializeWidgets() {
534 if (emulation_running) { 535 if (emulation_running) {
535 return; 536 return;
536 } 537 }
537 bool is_async = 538 bool is_async = !Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
538 !Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; 539 Settings::values.use_multi_core.GetValue();
539 Settings::values.use_asynchronous_gpu_emulation = is_async; 540 Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);
540 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); 541 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
541 Settings::Apply(); 542 Settings::Apply();
542 }); 543 });
543 async_status_button->setText(tr("ASYNC")); 544 async_status_button->setText(tr("ASYNC"));
544 async_status_button->setCheckable(true); 545 async_status_button->setCheckable(true);
545 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); 546 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
546 547
547 // Setup Multicore button 548 // Setup Multicore button
548 multicore_status_button = new QPushButton(); 549 multicore_status_button = new QPushButton();
@@ -552,17 +553,17 @@ void GMainWindow::InitializeWidgets() {
552 if (emulation_running) { 553 if (emulation_running) {
553 return; 554 return;
554 } 555 }
555 Settings::values.use_multi_core = !Settings::values.use_multi_core; 556 Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue());
556 bool is_async = 557 bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
557 Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; 558 Settings::values.use_multi_core.GetValue();
558 Settings::values.use_asynchronous_gpu_emulation = is_async; 559 Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);
559 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); 560 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
560 multicore_status_button->setChecked(Settings::values.use_multi_core); 561 multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
561 Settings::Apply(); 562 Settings::Apply();
562 }); 563 });
563 multicore_status_button->setText(tr("MULTICORE")); 564 multicore_status_button->setText(tr("MULTICORE"));
564 multicore_status_button->setCheckable(true); 565 multicore_status_button->setCheckable(true);
565 multicore_status_button->setChecked(Settings::values.use_multi_core); 566 multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
566 statusBar()->insertPermanentWidget(0, multicore_status_button); 567 statusBar()->insertPermanentWidget(0, multicore_status_button);
567 statusBar()->insertPermanentWidget(0, async_status_button); 568 statusBar()->insertPermanentWidget(0, async_status_button);
568 569
@@ -581,16 +582,16 @@ void GMainWindow::InitializeWidgets() {
581 renderer_status_button->setCheckable(false); 582 renderer_status_button->setCheckable(false);
582 renderer_status_button->setDisabled(true); 583 renderer_status_button->setDisabled(true);
583#else 584#else
584 renderer_status_button->setChecked(Settings::values.renderer_backend == 585 renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
585 Settings::RendererBackend::Vulkan); 586 Settings::RendererBackend::Vulkan);
586 connect(renderer_status_button, &QPushButton::clicked, [=] { 587 connect(renderer_status_button, &QPushButton::clicked, [=] {
587 if (emulation_running) { 588 if (emulation_running) {
588 return; 589 return;
589 } 590 }
590 if (renderer_status_button->isChecked()) { 591 if (renderer_status_button->isChecked()) {
591 Settings::values.renderer_backend = Settings::RendererBackend::Vulkan; 592 Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan);
592 } else { 593 } else {
593 Settings::values.renderer_backend = Settings::RendererBackend::OpenGL; 594 Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);
594 } 595 }
595 596
596 Settings::Apply(); 597 Settings::Apply();
@@ -727,21 +728,24 @@ void GMainWindow::InitializeHotkeys() {
727 }); 728 });
728 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this), 729 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
729 &QShortcut::activated, this, [&] { 730 &QShortcut::activated, this, [&] {
730 Settings::values.use_frame_limit = !Settings::values.use_frame_limit; 731 Settings::values.use_frame_limit.SetValue(
732 !Settings::values.use_frame_limit.GetValue());
731 UpdateStatusBar(); 733 UpdateStatusBar();
732 }); 734 });
733 constexpr u16 SPEED_LIMIT_STEP = 5; 735 constexpr u16 SPEED_LIMIT_STEP = 5;
734 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this), 736 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
735 &QShortcut::activated, this, [&] { 737 &QShortcut::activated, this, [&] {
736 if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) { 738 if (Settings::values.frame_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
737 Settings::values.frame_limit += SPEED_LIMIT_STEP; 739 Settings::values.frame_limit.SetValue(SPEED_LIMIT_STEP +
740 Settings::values.frame_limit.GetValue());
738 UpdateStatusBar(); 741 UpdateStatusBar();
739 } 742 }
740 }); 743 });
741 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this), 744 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
742 &QShortcut::activated, this, [&] { 745 &QShortcut::activated, this, [&] {
743 if (Settings::values.frame_limit > SPEED_LIMIT_STEP) { 746 if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) {
744 Settings::values.frame_limit -= SPEED_LIMIT_STEP; 747 Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() -
748 SPEED_LIMIT_STEP);
745 UpdateStatusBar(); 749 UpdateStatusBar();
746 } 750 }
747 }); 751 });
@@ -844,6 +848,9 @@ void GMainWindow::ConnectWidgetEvents() {
844 connect(game_list, &GameList::OpenPerGameGeneralRequested, this, 848 connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
845 &GMainWindow::OnGameListOpenPerGameProperties); 849 &GMainWindow::OnGameListOpenPerGameProperties);
846 850
851 connect(this, &GMainWindow::UpdateInstallProgress, this,
852 &GMainWindow::IncrementInstallProgress);
853
847 connect(this, &GMainWindow::EmulationStarting, render_window, 854 connect(this, &GMainWindow::EmulationStarting, render_window,
848 &GRenderWindow::OnEmulationStarting); 855 &GRenderWindow::OnEmulationStarting);
849 connect(this, &GMainWindow::EmulationStopping, render_window, 856 connect(this, &GMainWindow::EmulationStopping, render_window,
@@ -1039,6 +1046,17 @@ void GMainWindow::BootGame(const QString& filename) {
1039 LOG_INFO(Frontend, "yuzu starting..."); 1046 LOG_INFO(Frontend, "yuzu starting...");
1040 StoreRecentFile(filename); // Put the filename on top of the list 1047 StoreRecentFile(filename); // Put the filename on top of the list
1041 1048
1049 u64 title_id{0};
1050
1051 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
1052 const auto loader = Loader::GetLoader(v_file);
1053 if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
1054 // Load per game settings
1055 Config per_game_config(fmt::format("{:016X}.ini", title_id), false);
1056 }
1057
1058 Settings::LogSettings();
1059
1042 if (UISettings::values.select_user_on_boot) { 1060 if (UISettings::values.select_user_on_boot) {
1043 SelectAndSetCurrentUser(); 1061 SelectAndSetCurrentUser();
1044 } 1062 }
@@ -1063,6 +1081,7 @@ void GMainWindow::BootGame(const QString& filename) {
1063 &LoadingScreen::OnLoadProgress, Qt::QueuedConnection); 1081 &LoadingScreen::OnLoadProgress, Qt::QueuedConnection);
1064 1082
1065 // Update the GUI 1083 // Update the GUI
1084 UpdateStatusButtons();
1066 if (ui.action_Single_Window_Mode->isChecked()) { 1085 if (ui.action_Single_Window_Mode->isChecked()) {
1067 game_list->hide(); 1086 game_list->hide();
1068 game_list_placeholder->hide(); 1087 game_list_placeholder->hide();
@@ -1078,8 +1097,6 @@ void GMainWindow::BootGame(const QString& filename) {
1078 ui.centralwidget->setMouseTracking(true); 1097 ui.centralwidget->setMouseTracking(true);
1079 } 1098 }
1080 1099
1081 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
1082
1083 std::string title_name; 1100 std::string title_name;
1084 std::string title_version; 1101 std::string title_version;
1085 const auto res = Core::System::GetInstance().GetGameName(title_name); 1102 const auto res = Core::System::GetInstance().GetGameName(title_name);
@@ -1521,7 +1538,7 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
1521 return; 1538 return;
1522 } 1539 }
1523 1540
1524 ConfigurePerGameGeneral dialog(this, title_id); 1541 ConfigurePerGame dialog(this, title_id);
1525 dialog.LoadFromFile(v_file); 1542 dialog.LoadFromFile(v_file);
1526 auto result = dialog.exec(); 1543 auto result = dialog.exec();
1527 if (result == QDialog::Accepted) { 1544 if (result == QDialog::Accepted) {
@@ -1532,7 +1549,14 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
1532 game_list->PopulateAsync(UISettings::values.game_dirs); 1549 game_list->PopulateAsync(UISettings::values.game_dirs);
1533 } 1550 }
1534 1551
1535 config->Save(); 1552 // Do not cause the global config to write local settings into the config file
1553 Settings::RestoreGlobalState();
1554
1555 if (!Core::System::GetInstance().IsPoweredOn()) {
1556 config->Save();
1557 }
1558 } else {
1559 Settings::RestoreGlobalState();
1536 } 1560 }
1537} 1561}
1538 1562
@@ -1573,187 +1597,255 @@ void GMainWindow::OnMenuLoadFolder() {
1573 } 1597 }
1574} 1598}
1575 1599
1600void GMainWindow::IncrementInstallProgress() {
1601 install_progress->setValue(install_progress->value() + 1);
1602}
1603
1576void GMainWindow::OnMenuInstallToNAND() { 1604void GMainWindow::OnMenuInstallToNAND() {
1577 const QString file_filter = 1605 const QString file_filter =
1578 tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " 1606 tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
1579 "(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge " 1607 "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge "
1580 "Image (*.xci)"); 1608 "Image (*.xci)");
1581 QString filename = QFileDialog::getOpenFileName(this, tr("Install File"),
1582 UISettings::values.roms_path, file_filter);
1583 1609
1584 if (filename.isEmpty()) { 1610 QStringList filenames = QFileDialog::getOpenFileNames(
1611 this, tr("Install Files"), UISettings::values.roms_path, file_filter);
1612
1613 if (filenames.isEmpty()) {
1614 return;
1615 }
1616
1617 InstallDialog installDialog(this, filenames);
1618 if (installDialog.exec() == QDialog::Rejected) {
1619 return;
1620 }
1621
1622 const QStringList files = installDialog.GetFiles();
1623
1624 if (files.isEmpty()) {
1625 return;
1626 }
1627
1628 int remaining = filenames.size();
1629
1630 // This would only overflow above 2^43 bytes (8.796 TB)
1631 int total_size = 0;
1632 for (const QString& file : files) {
1633 total_size += static_cast<int>(QFile(file).size() / 0x1000);
1634 }
1635 if (total_size < 0) {
1636 LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting.");
1585 return; 1637 return;
1586 } 1638 }
1587 1639
1640 QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
1641 QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
1642 QStringList failed_files{}; // Files that failed to install due to errors
1643
1644 ui.action_Install_File_NAND->setEnabled(false);
1645
1646 install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this);
1647 install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
1648 ~Qt::WindowMaximizeButtonHint);
1649 install_progress->setAttribute(Qt::WA_DeleteOnClose, true);
1650 install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40);
1651 install_progress->show();
1652
1653 for (const QString& file : files) {
1654 install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining));
1655 install_progress->setLabelText(
1656 tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
1657
1658 QFuture<InstallResult> future;
1659 InstallResult result;
1660
1661 if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
1662 file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1663
1664 future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); });
1665
1666 while (!future.isFinished()) {
1667 QCoreApplication::processEvents();
1668 }
1669
1670 result = future.result();
1671
1672 } else {
1673 result = InstallNCA(file);
1674 }
1675
1676 std::this_thread::sleep_for(std::chrono::milliseconds(10));
1677
1678 switch (result) {
1679 case InstallResult::Success:
1680 new_files.append(QFileInfo(file).fileName());
1681 break;
1682 case InstallResult::Overwrite:
1683 overwritten_files.append(QFileInfo(file).fileName());
1684 break;
1685 case InstallResult::Failure:
1686 failed_files.append(QFileInfo(file).fileName());
1687 break;
1688 }
1689
1690 --remaining;
1691 }
1692
1693 install_progress->close();
1694
1695 const QString install_results =
1696 (new_files.isEmpty() ? QStringLiteral("")
1697 : tr("%n file(s) were newly installed\n", "", new_files.size())) +
1698 (overwritten_files.isEmpty()
1699 ? QStringLiteral("")
1700 : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
1701 (failed_files.isEmpty() ? QStringLiteral("")
1702 : tr("%n file(s) failed to install\n", "", failed_files.size()));
1703
1704 QMessageBox::information(this, tr("Install Results"), install_results);
1705 game_list->PopulateAsync(UISettings::values.game_dirs);
1706 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
1707 "game_list");
1708 ui.action_Install_File_NAND->setEnabled(true);
1709}
1710
1711InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
1588 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, 1712 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
1589 const FileSys::VirtualFile& dest, std::size_t block_size) { 1713 const FileSys::VirtualFile& dest, std::size_t block_size) {
1590 if (src == nullptr || dest == nullptr) 1714 if (src == nullptr || dest == nullptr) {
1591 return false; 1715 return false;
1592 if (!dest->Resize(src->GetSize())) 1716 }
1717 if (!dest->Resize(src->GetSize())) {
1593 return false; 1718 return false;
1719 }
1594 1720
1595 std::array<u8, 0x1000> buffer{}; 1721 std::array<u8, 0x1000> buffer{};
1596 const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size());
1597
1598 QProgressDialog progress(
1599 tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())),
1600 tr("Cancel"), 0, progress_maximum, this);
1601 progress.setWindowModality(Qt::WindowModal);
1602 1722
1603 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { 1723 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
1604 if (progress.wasCanceled()) { 1724 if (install_progress->wasCanceled()) {
1605 dest->Resize(0); 1725 dest->Resize(0);
1606 return false; 1726 return false;
1607 } 1727 }
1608 1728
1609 const int progress_value = static_cast<int>(i / buffer.size()); 1729 emit UpdateInstallProgress();
1610 progress.setValue(progress_value);
1611 1730
1612 const auto read = src->Read(buffer.data(), buffer.size(), i); 1731 const auto read = src->Read(buffer.data(), buffer.size(), i);
1613 dest->Write(buffer.data(), read, i); 1732 dest->Write(buffer.data(), read, i);
1614 } 1733 }
1615
1616 return true; 1734 return true;
1617 }; 1735 };
1618 1736
1619 const auto success = [this]() { 1737 std::shared_ptr<FileSys::NSP> nsp;
1620 QMessageBox::information(this, tr("Successfully Installed"), 1738 if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1621 tr("The file was successfully installed.")); 1739 nsp = std::make_shared<FileSys::NSP>(
1622 game_list->PopulateAsync(UISettings::values.game_dirs); 1740 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1623 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + 1741 if (nsp->IsExtractedType()) {
1624 DIR_SEP + "game_list"); 1742 return InstallResult::Failure;
1625 };
1626
1627 const auto failed = [this]() {
1628 QMessageBox::warning(
1629 this, tr("Failed to Install"),
1630 tr("There was an error while attempting to install the provided file. It "
1631 "could have an incorrect format or be missing metadata. Please "
1632 "double-check your file and try again."));
1633 };
1634
1635 const auto overwrite = [this]() {
1636 return QMessageBox::question(this, tr("Failed to Install"),
1637 tr("The file you are attempting to install already exists "
1638 "in the cache. Would you like to overwrite it?")) ==
1639 QMessageBox::Yes;
1640 };
1641
1642 if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
1643 filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1644 std::shared_ptr<FileSys::NSP> nsp;
1645 if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1646 nsp = std::make_shared<FileSys::NSP>(
1647 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1648 if (nsp->IsExtractedType())
1649 failed();
1650 } else {
1651 const auto xci = std::make_shared<FileSys::XCI>(
1652 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1653 nsp = xci->GetSecurePartitionNSP();
1654 }
1655
1656 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
1657 failed();
1658 return;
1659 }
1660 const auto res = Core::System::GetInstance()
1661 .GetFileSystemController()
1662 .GetUserNANDContents()
1663 ->InstallEntry(*nsp, false, qt_raw_copy);
1664 if (res == FileSys::InstallResult::Success) {
1665 success();
1666 } else {
1667 if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1668 if (overwrite()) {
1669 const auto res2 = Core::System::GetInstance()
1670 .GetFileSystemController()
1671 .GetUserNANDContents()
1672 ->InstallEntry(*nsp, true, qt_raw_copy);
1673 if (res2 == FileSys::InstallResult::Success) {
1674 success();
1675 } else {
1676 failed();
1677 }
1678 }
1679 } else {
1680 failed();
1681 }
1682 } 1743 }
1683 } else { 1744 } else {
1684 const auto nca = std::make_shared<FileSys::NCA>( 1745 const auto xci = std::make_shared<FileSys::XCI>(
1685 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); 1746 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1686 const auto id = nca->GetStatus(); 1747 nsp = xci->GetSecurePartitionNSP();
1748 }
1687 1749
1688 // Game updates necessary are missing base RomFS 1750 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
1689 if (id != Loader::ResultStatus::Success && 1751 return InstallResult::Failure;
1690 id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { 1752 }
1691 failed(); 1753 const auto res =
1692 return; 1754 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
1693 } 1755 *nsp, true, qt_raw_copy);
1756 if (res == FileSys::InstallResult::Success) {
1757 return InstallResult::Success;
1758 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1759 return InstallResult::Overwrite;
1760 } else {
1761 return InstallResult::Failure;
1762 }
1763}
1694 1764
1695 const QStringList tt_options{tr("System Application"), 1765InstallResult GMainWindow::InstallNCA(const QString& filename) {
1696 tr("System Archive"), 1766 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
1697 tr("System Application Update"), 1767 const FileSys::VirtualFile& dest, std::size_t block_size) {
1698 tr("Firmware Package (Type A)"), 1768 if (src == nullptr || dest == nullptr) {
1699 tr("Firmware Package (Type B)"), 1769 return false;
1700 tr("Game"),
1701 tr("Game Update"),
1702 tr("Game DLC"),
1703 tr("Delta Title")};
1704 bool ok;
1705 const auto item = QInputDialog::getItem(
1706 this, tr("Select NCA Install Type..."),
1707 tr("Please select the type of title you would like to install this NCA as:\n(In "
1708 "most instances, the default 'Game' is fine.)"),
1709 tt_options, 5, false, &ok);
1710
1711 auto index = tt_options.indexOf(item);
1712 if (!ok || index == -1) {
1713 QMessageBox::warning(this, tr("Failed to Install"),
1714 tr("The title type you selected for the NCA is invalid."));
1715 return;
1716 } 1770 }
1717 1771 if (!dest->Resize(src->GetSize())) {
1718 // If index is equal to or past Game, add the jump in TitleType. 1772 return false;
1719 if (index >= 5) {
1720 index += static_cast<size_t>(FileSys::TitleType::Application) -
1721 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
1722 } 1773 }
1723 1774
1724 FileSys::InstallResult res; 1775 std::array<u8, 0x1000> buffer{};
1725 if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
1726 res = Core::System::GetInstance()
1727 .GetFileSystemController()
1728 .GetUserNANDContents()
1729 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
1730 qt_raw_copy);
1731 } else {
1732 res = Core::System::GetInstance()
1733 .GetFileSystemController()
1734 .GetSystemNANDContents()
1735 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
1736 qt_raw_copy);
1737 }
1738 1776
1739 if (res == FileSys::InstallResult::Success) { 1777 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
1740 success(); 1778 if (install_progress->wasCanceled()) {
1741 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { 1779 dest->Resize(0);
1742 if (overwrite()) { 1780 return false;
1743 const auto res2 = Core::System::GetInstance()
1744 .GetFileSystemController()
1745 .GetUserNANDContents()
1746 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index),
1747 true, qt_raw_copy);
1748 if (res2 == FileSys::InstallResult::Success) {
1749 success();
1750 } else {
1751 failed();
1752 }
1753 } 1781 }
1754 } else { 1782
1755 failed(); 1783 emit UpdateInstallProgress();
1784
1785 const auto read = src->Read(buffer.data(), buffer.size(), i);
1786 dest->Write(buffer.data(), read, i);
1756 } 1787 }
1788 return true;
1789 };
1790
1791 const auto nca =
1792 std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1793 const auto id = nca->GetStatus();
1794
1795 // Game updates necessary are missing base RomFS
1796 if (id != Loader::ResultStatus::Success &&
1797 id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
1798 return InstallResult::Failure;
1799 }
1800
1801 const QStringList tt_options{tr("System Application"),
1802 tr("System Archive"),
1803 tr("System Application Update"),
1804 tr("Firmware Package (Type A)"),
1805 tr("Firmware Package (Type B)"),
1806 tr("Game"),
1807 tr("Game Update"),
1808 tr("Game DLC"),
1809 tr("Delta Title")};
1810 bool ok;
1811 const auto item = QInputDialog::getItem(
1812 this, tr("Select NCA Install Type..."),
1813 tr("Please select the type of title you would like to install this NCA as:\n(In "
1814 "most instances, the default 'Game' is fine.)"),
1815 tt_options, 5, false, &ok);
1816
1817 auto index = tt_options.indexOf(item);
1818 if (!ok || index == -1) {
1819 QMessageBox::warning(this, tr("Failed to Install"),
1820 tr("The title type you selected for the NCA is invalid."));
1821 return InstallResult::Failure;
1822 }
1823
1824 // If index is equal to or past Game, add the jump in TitleType.
1825 if (index >= 5) {
1826 index += static_cast<size_t>(FileSys::TitleType::Application) -
1827 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
1828 }
1829
1830 FileSys::InstallResult res;
1831 if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
1832 res = Core::System::GetInstance()
1833 .GetFileSystemController()
1834 .GetUserNANDContents()
1835 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
1836 } else {
1837 res = Core::System::GetInstance()
1838 .GetFileSystemController()
1839 .GetSystemNANDContents()
1840 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
1841 }
1842
1843 if (res == FileSys::InstallResult::Success) {
1844 return InstallResult::Success;
1845 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1846 return InstallResult::Overwrite;
1847 } else {
1848 return InstallResult::Failure;
1757 } 1849 }
1758} 1850}
1759 1851
@@ -1819,6 +1911,9 @@ void GMainWindow::OnStopGame() {
1819 } 1911 }
1820 1912
1821 ShutdownGame(); 1913 ShutdownGame();
1914
1915 Settings::RestoreGlobalState();
1916 UpdateStatusButtons();
1822} 1917}
1823 1918
1824void GMainWindow::OnLoadComplete() { 1919void GMainWindow::OnLoadComplete() {
@@ -1926,7 +2021,7 @@ void GMainWindow::ToggleWindowMode() {
1926 2021
1927void GMainWindow::ResetWindowSize() { 2022void GMainWindow::ResetWindowSize() {
1928 const auto aspect_ratio = Layout::EmulationAspectRatio( 2023 const auto aspect_ratio = Layout::EmulationAspectRatio(
1929 static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio), 2024 static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()),
1930 static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width); 2025 static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width);
1931 if (!ui.action_Single_Window_Mode->isChecked()) { 2026 if (!ui.action_Single_Window_Mode->isChecked()) {
1932 render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio, 2027 render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio,
@@ -1974,16 +2069,7 @@ void GMainWindow::OnConfigure() {
1974 ui.centralwidget->setMouseTracking(false); 2069 ui.centralwidget->setMouseTracking(false);
1975 } 2070 }
1976 2071
1977 dock_status_button->setChecked(Settings::values.use_docked_mode); 2072 UpdateStatusButtons();
1978 multicore_status_button->setChecked(Settings::values.use_multi_core);
1979 Settings::values.use_asynchronous_gpu_emulation =
1980 Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core;
1981 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
1982
1983#ifdef HAS_VULKAN
1984 renderer_status_button->setChecked(Settings::values.renderer_backend ==
1985 Settings::RendererBackend::Vulkan);
1986#endif
1987} 2073}
1988 2074
1989void GMainWindow::OnLoadAmiibo() { 2075void GMainWindow::OnLoadAmiibo() {
@@ -2097,21 +2183,34 @@ void GMainWindow::UpdateStatusBar() {
2097 2183
2098 auto results = Core::System::GetInstance().GetAndResetPerfStats(); 2184 auto results = Core::System::GetInstance().GetAndResetPerfStats();
2099 2185
2100 if (Settings::values.use_frame_limit) { 2186 if (Settings::values.use_frame_limit.GetValue()) {
2101 emu_speed_label->setText(tr("Speed: %1% / %2%") 2187 emu_speed_label->setText(tr("Speed: %1% / %2%")
2102 .arg(results.emulation_speed * 100.0, 0, 'f', 0) 2188 .arg(results.emulation_speed * 100.0, 0, 'f', 0)
2103 .arg(Settings::values.frame_limit)); 2189 .arg(Settings::values.frame_limit.GetValue()));
2104 } else { 2190 } else {
2105 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); 2191 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
2106 } 2192 }
2107 game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0)); 2193 game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
2108 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); 2194 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
2109 2195
2110 emu_speed_label->setVisible(!Settings::values.use_multi_core); 2196 emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
2111 game_fps_label->setVisible(true); 2197 game_fps_label->setVisible(true);
2112 emu_frametime_label->setVisible(true); 2198 emu_frametime_label->setVisible(true);
2113} 2199}
2114 2200
2201void GMainWindow::UpdateStatusButtons() {
2202 dock_status_button->setChecked(Settings::values.use_docked_mode);
2203 multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
2204 Settings::values.use_asynchronous_gpu_emulation.SetValue(
2205 Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
2206 Settings::values.use_multi_core.GetValue());
2207 async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
2208#ifdef HAS_VULKAN
2209 renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
2210 Settings::RendererBackend::Vulkan);
2211#endif
2212}
2213
2115void GMainWindow::HideMouseCursor() { 2214void GMainWindow::HideMouseCursor() {
2116 if (emu_thread == nullptr || UISettings::values.hide_mouse == false) { 2215 if (emu_thread == nullptr || UISettings::values.hide_mouse == false) {
2117 mouse_hide_timer.stop(); 2216 mouse_hide_timer.stop();
@@ -2195,6 +2294,9 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
2195 if (answer == QMessageBox::Yes) { 2294 if (answer == QMessageBox::Yes) {
2196 if (emu_thread) { 2295 if (emu_thread) {
2197 ShutdownGame(); 2296 ShutdownGame();
2297
2298 Settings::RestoreGlobalState();
2299 UpdateStatusButtons();
2198 } 2300 }
2199 } else { 2301 } else {
2200 // Only show the message if the game is still running. 2302 // Only show the message if the game is still running.
@@ -2357,9 +2459,13 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
2357 hotkey_registry.SaveHotkeys(); 2459 hotkey_registry.SaveHotkeys();
2358 2460
2359 // Shutdown session if the emu thread is active... 2461 // Shutdown session if the emu thread is active...
2360 if (emu_thread != nullptr) 2462 if (emu_thread != nullptr) {
2361 ShutdownGame(); 2463 ShutdownGame();
2362 2464
2465 Settings::RestoreGlobalState();
2466 UpdateStatusButtons();
2467 }
2468
2363 render_window->close(); 2469 render_window->close();
2364 2470
2365 QWidget::closeEvent(event); 2471 QWidget::closeEvent(event);
@@ -2539,8 +2645,6 @@ int main(int argc, char* argv[]) {
2539 QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window, 2645 QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
2540 &GMainWindow::OnAppFocusStateChanged); 2646 &GMainWindow::OnAppFocusStateChanged);
2541 2647
2542 Settings::LogSettings();
2543
2544 int result = app.exec(); 2648 int result = app.exec();
2545 detached_tasks.WaitForAllTasks(); 2649 detached_tasks.WaitForAllTasks();
2546 return result; 2650 return result;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 66c84e5c0..adff65fb5 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -28,6 +28,7 @@ class MicroProfileDialog;
28class ProfilerWidget; 28class ProfilerWidget;
29class QLabel; 29class QLabel;
30class QPushButton; 30class QPushButton;
31class QProgressDialog;
31class WaitTreeWidget; 32class WaitTreeWidget;
32enum class GameListOpenTarget; 33enum class GameListOpenTarget;
33class GameListPlaceholder; 34class GameListPlaceholder;
@@ -47,6 +48,12 @@ enum class EmulatedDirectoryTarget {
47 SDMC, 48 SDMC,
48}; 49};
49 50
51enum class InstallResult {
52 Success,
53 Overwrite,
54 Failure,
55};
56
50enum class ReinitializeKeyBehavior { 57enum class ReinitializeKeyBehavior {
51 NoWarning, 58 NoWarning,
52 Warning, 59 Warning,
@@ -102,6 +109,8 @@ signals:
102 // Signal that tells widgets to update icons to use the current theme 109 // Signal that tells widgets to update icons to use the current theme
103 void UpdateThemedIcons(); 110 void UpdateThemedIcons();
104 111
112 void UpdateInstallProgress();
113
105 void ErrorDisplayFinished(); 114 void ErrorDisplayFinished();
106 115
107 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); 116 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
@@ -198,6 +207,7 @@ private slots:
198 void OnGameListOpenPerGameProperties(const std::string& file); 207 void OnGameListOpenPerGameProperties(const std::string& file);
199 void OnMenuLoadFile(); 208 void OnMenuLoadFile();
200 void OnMenuLoadFolder(); 209 void OnMenuLoadFolder();
210 void IncrementInstallProgress();
201 void OnMenuInstallToNAND(); 211 void OnMenuInstallToNAND();
202 void OnMenuRecentFile(); 212 void OnMenuRecentFile();
203 void OnConfigure(); 213 void OnConfigure();
@@ -218,9 +228,12 @@ private slots:
218 228
219private: 229private:
220 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); 230 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
231 InstallResult InstallNSPXCI(const QString& filename);
232 InstallResult InstallNCA(const QString& filename);
221 void UpdateWindowTitle(const std::string& title_name = {}, 233 void UpdateWindowTitle(const std::string& title_name = {},
222 const std::string& title_version = {}); 234 const std::string& title_version = {});
223 void UpdateStatusBar(); 235 void UpdateStatusBar();
236 void UpdateStatusButtons();
224 void HideMouseCursor(); 237 void HideMouseCursor();
225 void ShowMouseCursor(); 238 void ShowMouseCursor();
226 void OpenURL(const QUrl& url); 239 void OpenURL(const QUrl& url);
@@ -271,6 +284,9 @@ private:
271 284
272 HotkeyRegistry hotkey_registry; 285 HotkeyRegistry hotkey_registry;
273 286
287 // Install progress dialog
288 QProgressDialog* install_progress;
289
274protected: 290protected:
275 void dropEvent(QDropEvent* event) override; 291 void dropEvent(QDropEvent* event) override;
276 void dragEnterEvent(QDragEnterEvent* event) override; 292 void dragEnterEvent(QDragEnterEvent* event) override;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index bee6e107e..c3a1d715e 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -130,7 +130,7 @@
130 <bool>true</bool> 130 <bool>true</bool>
131 </property> 131 </property>
132 <property name="text"> 132 <property name="text">
133 <string>Install File to NAND...</string> 133 <string>Install Files to NAND...</string>
134 </property> 134 </property>
135 </action> 135 </action>
136 <action name="action_Load_File"> 136 <action name="action_Load_File">
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 659b9f701..7773228c8 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -335,15 +335,6 @@ void Config::ReadValues() {
335 Settings::values.gamecard_current_game = 335 Settings::values.gamecard_current_game =
336 sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false); 336 sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
337 Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", ""); 337 Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
338 Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger(
339 "Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB)));
340 Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger(
341 "Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB)));
342 Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
343 sdl2_config->GetInteger("Data Storage", "nand_system_size",
344 static_cast<long>(Settings::NANDSystemSize::S2_5GB)));
345 Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger(
346 "Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB)));
347 338
348 // System 339 // System
349 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); 340 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
@@ -354,63 +345,72 @@ void Config::ReadValues() {
354 345
355 const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); 346 const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
356 if (rng_seed_enabled) { 347 if (rng_seed_enabled) {
357 Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0); 348 Settings::values.rng_seed.SetValue(sdl2_config->GetInteger("System", "rng_seed", 0));
358 } else { 349 } else {
359 Settings::values.rng_seed = std::nullopt; 350 Settings::values.rng_seed.SetValue(std::nullopt);
360 } 351 }
361 352
362 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); 353 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
363 if (custom_rtc_enabled) { 354 if (custom_rtc_enabled) {
364 Settings::values.custom_rtc = 355 Settings::values.custom_rtc.SetValue(
365 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)); 356 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)));
366 } else { 357 } else {
367 Settings::values.custom_rtc = std::nullopt; 358 Settings::values.custom_rtc.SetValue(std::nullopt);
368 } 359 }
369 360
370 Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1); 361 Settings::values.language_index.SetValue(
371 Settings::values.time_zone_index = sdl2_config->GetInteger("System", "time_zone_index", 0); 362 sdl2_config->GetInteger("System", "language_index", 1));
363 Settings::values.time_zone_index.SetValue(
364 sdl2_config->GetInteger("System", "time_zone_index", 0));
372 365
373 // Core 366 // Core
374 Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); 367 Settings::values.use_multi_core.SetValue(
368 sdl2_config->GetBoolean("Core", "use_multi_core", false));
375 369
376 // Renderer 370 // Renderer
377 const int renderer_backend = sdl2_config->GetInteger( 371 const int renderer_backend = sdl2_config->GetInteger(
378 "Renderer", "backend", static_cast<int>(Settings::RendererBackend::OpenGL)); 372 "Renderer", "backend", static_cast<int>(Settings::RendererBackend::OpenGL));
379 Settings::values.renderer_backend = static_cast<Settings::RendererBackend>(renderer_backend); 373 Settings::values.renderer_backend.SetValue(
374 static_cast<Settings::RendererBackend>(renderer_backend));
380 Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false); 375 Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false);
381 Settings::values.vulkan_device = sdl2_config->GetInteger("Renderer", "vulkan_device", 0); 376 Settings::values.vulkan_device.SetValue(
382 377 sdl2_config->GetInteger("Renderer", "vulkan_device", 0));
383 Settings::values.aspect_ratio = 378
384 static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)); 379 Settings::values.aspect_ratio.SetValue(
385 Settings::values.max_anisotropy = 380 static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)));
386 static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)); 381 Settings::values.max_anisotropy.SetValue(
387 Settings::values.use_frame_limit = sdl2_config->GetBoolean("Renderer", "use_frame_limit", true); 382 static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)));
388 Settings::values.frame_limit = 383 Settings::values.use_frame_limit.SetValue(
389 static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)); 384 sdl2_config->GetBoolean("Renderer", "use_frame_limit", true));
390 Settings::values.use_disk_shader_cache = 385 Settings::values.frame_limit.SetValue(
391 sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false); 386 static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)));
387 Settings::values.use_disk_shader_cache.SetValue(
388 sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false));
392 const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0); 389 const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0);
393 Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(gpu_accuracy_level); 390 Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
394 Settings::values.use_asynchronous_gpu_emulation = 391 Settings::values.use_asynchronous_gpu_emulation.SetValue(
395 sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false); 392 sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false));
396 Settings::values.use_vsync = 393 Settings::values.use_vsync.SetValue(
397 static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)); 394 static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
398 Settings::values.use_assembly_shaders = 395 Settings::values.use_assembly_shaders.SetValue(
399 sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false); 396 sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false));
400 Settings::values.use_fast_gpu_time = 397 Settings::values.use_fast_gpu_time.SetValue(
401 sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true); 398 sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
402 399
403 Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)); 400 Settings::values.bg_red.SetValue(
404 Settings::values.bg_green = 401 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
405 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)); 402 Settings::values.bg_green.SetValue(
406 Settings::values.bg_blue = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)); 403 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
404 Settings::values.bg_blue.SetValue(
405 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
407 406
408 // Audio 407 // Audio
409 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); 408 Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
410 Settings::values.enable_audio_stretching = 409 Settings::values.enable_audio_stretching.SetValue(
411 sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true); 410 sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true));
412 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); 411 Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
413 Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)); 412 Settings::values.volume.SetValue(
413 static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)));
414 414
415 // Miscellaneous 415 // Miscellaneous
416 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); 416 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
@@ -428,8 +428,6 @@ void Config::ReadValues() {
428 Settings::values.reporting_services = 428 Settings::values.reporting_services =
429 sdl2_config->GetBoolean("Debugging", "reporting_services", false); 429 sdl2_config->GetBoolean("Debugging", "reporting_services", false);
430 Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false); 430 Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
431 Settings::values.disable_cpu_opt =
432 sdl2_config->GetBoolean("Debugging", "disable_cpu_opt", false);
433 Settings::values.disable_macro_jit = 431 Settings::values.disable_macro_jit =
434 sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false); 432 sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
435 433
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 45c07ed5d..5bed47fd7 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -97,6 +97,39 @@ udp_pad_index=
97# 0 (default): Disabled, 1: Enabled 97# 0 (default): Disabled, 1: Enabled
98use_multi_core= 98use_multi_core=
99 99
100[Cpu]
101# Enable inline page tables optimization (faster guest memory access)
102# 0: Disabled, 1 (default): Enabled
103cpuopt_page_tables =
104
105# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
106# 0: Disabled, 1 (default): Enabled
107cpuopt_block_linking =
108
109# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
110# 0: Disabled, 1 (default): Enabled
111cpuopt_return_stack_buffer =
112
113# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
114# 0: Disabled, 1 (default): Enabled
115cpuopt_fast_dispatcher =
116
117# Enable context elimination CPU Optimization (reduce host memory use for guest context)
118# 0: Disabled, 1 (default): Enabled
119cpuopt_context_elimination =
120
121# Enable constant propagation CPU optimization (basic IR optimization)
122# 0: Disabled, 1 (default): Enabled
123cpuopt_const_prop =
124
125# Enable miscellaneous CPU optimizations (basic IR optimization)
126# 0: Disabled, 1 (default): Enabled
127cpuopt_misc_ir =
128
129# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
130# 0: Disabled, 1 (default): Enabled
131cpuopt_reduce_misalign_checks =
132
100[Renderer] 133[Renderer]
101# Which backend API to use. 134# Which backend API to use.
102# 0 (default): OpenGL, 1: Vulkan 135# 0 (default): OpenGL, 1: Vulkan
@@ -283,9 +316,6 @@ dump_nso=false
283# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode 316# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
284# false: Retail/Normal Mode (default), true: Kiosk Mode 317# false: Retail/Normal Mode (default), true: Kiosk Mode
285quest_flag = 318quest_flag =
286# Determines whether or not JIT CPU optimizations are enabled
287# false: Optimizations Enabled, true: Optimizations Disabled
288disable_cpu_opt =
289# Enables/Disables the macro JIT compiler 319# Enables/Disables the macro JIT compiler
290disable_macro_jit=false 320disable_macro_jit=false
291 321
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index 09cc0a3b5..e78025737 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -165,7 +165,7 @@ std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateShared
165 165
166void EmuWindow_SDL2_GL::Present() { 166void EmuWindow_SDL2_GL::Present() {
167 SDL_GL_MakeCurrent(render_window, window_context); 167 SDL_GL_MakeCurrent(render_window, window_context);
168 SDL_GL_SetSwapInterval(Settings::values.use_vsync ? 1 : 0); 168 SDL_GL_SetSwapInterval(Settings::values.use_vsync.GetValue() ? 1 : 0);
169 while (IsOpen()) { 169 while (IsOpen()) {
170 system.Renderer().TryPresent(100); 170 system.Renderer().TryPresent(100);
171 SDL_GL_SwapWindow(render_window); 171 SDL_GL_SwapWindow(render_window);
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index e6c6a839d..512b060a7 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -181,7 +181,7 @@ int main(int argc, char** argv) {
181 Core::System& system{Core::System::GetInstance()}; 181 Core::System& system{Core::System::GetInstance()};
182 182
183 std::unique_ptr<EmuWindow_SDL2> emu_window; 183 std::unique_ptr<EmuWindow_SDL2> emu_window;
184 switch (Settings::values.renderer_backend) { 184 switch (Settings::values.renderer_backend.GetValue()) {
185 case Settings::RendererBackend::OpenGL: 185 case Settings::RendererBackend::OpenGL:
186 emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen); 186 emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen);
187 break; 187 break;
diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp
index 1566c2e3f..acb22885e 100644
--- a/src/yuzu_tester/config.cpp
+++ b/src/yuzu_tester/config.cpp
@@ -81,6 +81,9 @@ void Config::ReadValues() {
81 Settings::values.touchscreen.diameter_x = 15; 81 Settings::values.touchscreen.diameter_x = 15;
82 Settings::values.touchscreen.diameter_y = 15; 82 Settings::values.touchscreen.diameter_y = 15;
83 83
84 Settings::values.use_docked_mode =
85 sdl2_config->GetBoolean("Controls", "use_docked_mode", false);
86
84 // Data Storage 87 // Data Storage
85 Settings::values.use_virtual_sd = 88 Settings::values.use_virtual_sd =
86 sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); 89 sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
@@ -92,57 +95,59 @@ void Config::ReadValues() {
92 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); 95 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
93 96
94 // System 97 // System
95 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
96
97 Settings::values.current_user = std::clamp<int>( 98 Settings::values.current_user = std::clamp<int>(
98 sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); 99 sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1);
99 100
100 const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); 101 const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
101 if (rng_seed_enabled) { 102 if (rng_seed_enabled) {
102 Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0); 103 Settings::values.rng_seed.SetValue(sdl2_config->GetInteger("System", "rng_seed", 0));
103 } else { 104 } else {
104 Settings::values.rng_seed = std::nullopt; 105 Settings::values.rng_seed.SetValue(std::nullopt);
105 } 106 }
106 107
107 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); 108 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
108 if (custom_rtc_enabled) { 109 if (custom_rtc_enabled) {
109 Settings::values.custom_rtc = 110 Settings::values.custom_rtc.SetValue(
110 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)); 111 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)));
111 } else { 112 } else {
112 Settings::values.custom_rtc = std::nullopt; 113 Settings::values.custom_rtc.SetValue(std::nullopt);
113 } 114 }
114 115
115 // Core 116 // Core
116 Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); 117 Settings::values.use_multi_core.SetValue(
118 sdl2_config->GetBoolean("Core", "use_multi_core", false));
117 119
118 // Renderer 120 // Renderer
119 Settings::values.aspect_ratio = 121 Settings::values.aspect_ratio.SetValue(
120 static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)); 122 static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)));
121 Settings::values.max_anisotropy = 123 Settings::values.max_anisotropy.SetValue(
122 static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)); 124 static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)));
123 Settings::values.use_frame_limit = false; 125 Settings::values.use_frame_limit.SetValue(false);
124 Settings::values.frame_limit = 100; 126 Settings::values.frame_limit.SetValue(100);
125 Settings::values.use_disk_shader_cache = 127 Settings::values.use_disk_shader_cache.SetValue(
126 sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false); 128 sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false));
127 const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0); 129 const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0);
128 Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(gpu_accuracy_level); 130 Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
129 Settings::values.use_asynchronous_gpu_emulation = 131 Settings::values.use_asynchronous_gpu_emulation.SetValue(
130 sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false); 132 sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false));
131 Settings::values.use_fast_gpu_time = 133 Settings::values.use_fast_gpu_time.SetValue(
132 sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true); 134 sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
133 135
134 Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)); 136 Settings::values.bg_red.SetValue(
135 Settings::values.bg_green = 137 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
136 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)); 138 Settings::values.bg_green.SetValue(
137 Settings::values.bg_blue = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)); 139 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
140 Settings::values.bg_blue.SetValue(
141 static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
138 142
139 // Audio 143 // Audio
140 Settings::values.sink_id = "null"; 144 Settings::values.sink_id = "null";
141 Settings::values.enable_audio_stretching = false; 145 Settings::values.enable_audio_stretching.SetValue(false);
142 Settings::values.audio_device_id = "auto"; 146 Settings::values.audio_device_id = "auto";
143 Settings::values.volume = 0; 147 Settings::values.volume.SetValue(0);
144 148
145 Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1); 149 Settings::values.language_index.SetValue(
150 sdl2_config->GetInteger("System", "language_index", 1));
146 151
147 // Miscellaneous 152 // Miscellaneous
148 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); 153 Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
diff --git a/src/yuzu_tester/default_ini.h b/src/yuzu_tester/default_ini.h
index 41bbbbf60..3eb64e9d7 100644
--- a/src/yuzu_tester/default_ini.h
+++ b/src/yuzu_tester/default_ini.h
@@ -12,6 +12,39 @@ const char* sdl2_config_file = R"(
12# 0 (default): Disabled, 1: Enabled 12# 0 (default): Disabled, 1: Enabled
13use_multi_core= 13use_multi_core=
14 14
15[Cpu]
16# Enable inline page tables optimization (faster guest memory access)
17# 0: Disabled, 1 (default): Enabled
18cpuopt_page_tables =
19
20# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
21# 0: Disabled, 1 (default): Enabled
22cpuopt_block_linking =
23
24# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
25# 0: Disabled, 1 (default): Enabled
26cpuopt_return_stack_buffer =
27
28# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
29# 0: Disabled, 1 (default): Enabled
30cpuopt_fast_dispatcher =
31
32# Enable context elimination CPU Optimization (reduce host memory use for guest context)
33# 0: Disabled, 1 (default): Enabled
34cpuopt_context_elimination =
35
36# Enable constant propagation CPU optimization (basic IR optimization)
37# 0: Disabled, 1 (default): Enabled
38cpuopt_const_prop =
39
40# Enable miscellaneous CPU optimizations (basic IR optimization)
41# 0: Disabled, 1 (default): Enabled
42cpuopt_misc_ir =
43
44# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
45# 0: Disabled, 1 (default): Enabled
46cpuopt_reduce_misalign_checks =
47
15[Renderer] 48[Renderer]
16# Whether to use software or hardware rendering. 49# Whether to use software or hardware rendering.
17# 0: Software, 1 (default): Hardware 50# 0: Software, 1 (default): Hardware