summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAmeer <aj662@drexel.edu>2020-07-14 19:04:02 +0200
committerAmeer <aj662@drexel.edu>2020-07-14 19:04:02 +0200
commit93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3 (patch)
treec4ab9e3acff296733b00effd85371bf04db6491f /src
parentBreak out of scan loop if can't find adapter on first run (diff)
parentMerge pull request #4294 from MerryMage/cpu-opt-settings (diff)
downloadyuzu-93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3.tar
yuzu-93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3.tar.gz
yuzu-93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3.tar.bz2
yuzu-93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3.tar.lz
yuzu-93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3.tar.xz
yuzu-93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3.tar.zst
yuzu-93fe982a0c3a5bfb7fa5df97ebced0a7692ccaf3.zip
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
const std::size_t samples_to_write = num_channels * num_frames;
std::size_t samples_written;
- if (Settings::values.enable_audio_stretching) {
+ if (Settings::values.enable_audio_stretching.GetValue()) {
const std::vector<s16> in{impl->queue.Pop()};
const std::size_t num_in{in.size() / num_channels};
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
sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} {
release_event = Core::Timing::CreateEvent(
- name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(); });
+ name, [this](u64 userdata, s64 cycles_late) { ReleaseActiveBuffer(cycles_late); });
}
void Stream::Play() {
@@ -66,15 +66,6 @@ s64 Stream::GetBufferReleaseNS(const Buffer& buffer) const {
return ns.count();
}
-s64 Stream::GetBufferReleaseNSHostTiming(const Buffer& buffer) const {
- const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
- /// DSP signals before playing the last sample, in HLE we emulate this in this way
- s64 base_samples = std::max<s64>(static_cast<s64>(num_samples) - 1, 0);
- const auto ns =
- std::chrono::nanoseconds((static_cast<u64>(base_samples) * 1000000000ULL) / sample_rate);
- return ns.count();
-}
-
static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
const float volume{std::clamp(Settings::Volume() - (1.0f - game_volume), 0.0f, 1.0f)};
@@ -89,7 +80,7 @@ static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) {
}
}
-void Stream::PlayNextBuffer() {
+void Stream::PlayNextBuffer(s64 cycles_late) {
if (!IsPlaying()) {
// Ensure we are in playing state before playing the next buffer
sink_stream.Flush();
@@ -114,18 +105,17 @@ void Stream::PlayNextBuffer() {
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
- if (core_timing.IsHostTiming()) {
- core_timing.ScheduleEvent(GetBufferReleaseNSHostTiming(*active_buffer), release_event, {});
- } else {
- core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer), release_event, {});
- }
+ core_timing.ScheduleEvent(
+ GetBufferReleaseNS(*active_buffer) -
+ (Settings::values.enable_audio_stretching.GetValue() ? 0 : cycles_late),
+ release_event, {});
}
-void Stream::ReleaseActiveBuffer() {
+void Stream::ReleaseActiveBuffer(s64 cycles_late) {
ASSERT(active_buffer);
released_buffers.push(std::move(active_buffer));
release_callback();
- PlayNextBuffer();
+ PlayNextBuffer(cycles_late);
}
bool 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:
private:
/// Plays the next queued buffer in the audio stream, starting playback if necessary
- void PlayNextBuffer();
+ void PlayNextBuffer(s64 cycles_late = 0);
/// Releases the actively playing buffer, signalling that it has been completed
- void ReleaseActiveBuffer();
+ void ReleaseActiveBuffer(s64 cycles_late = 0);
/// Gets the number of core cycles when the specified buffer will be released
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 {
template <typename T>
constexpr T AlignUp(T value, std::size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
- return static_cast<T>(value + (size - value % size) % size);
+ auto mod{static_cast<T>(value % size)};
+ value -= mod;
+ return static_cast<T>(mod == T{0} ? value : value + size);
}
template <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&
// Timing
config.wall_clock_cntpct = uses_wall_clock;
- // Optimizations
- if (Settings::values.disable_cpu_opt) {
- config.enable_optimizations = false;
- config.enable_fast_dispatch = false;
+ // Safe optimizations
+ if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
+ if (!Settings::values.cpuopt_page_tables) {
+ config.page_table = nullptr;
+ }
+ if (!Settings::values.cpuopt_block_linking) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
+ }
+ if (!Settings::values.cpuopt_return_stack_buffer) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer;
+ }
+ if (!Settings::values.cpuopt_fast_dispatcher) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch;
+ }
+ if (!Settings::values.cpuopt_context_elimination) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination;
+ }
+ if (!Settings::values.cpuopt_const_prop) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp;
+ }
+ if (!Settings::values.cpuopt_misc_ir) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt;
+ }
+ if (!Settings::values.cpuopt_reduce_misalign_checks) {
+ config.only_detect_misalignment_via_page_table_on_page_boundary = false;
+ }
}
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&
// Unpredictable instructions
config.define_unpredictable_behaviour = true;
- // Optimizations
- if (Settings::values.disable_cpu_opt) {
- config.enable_optimizations = false;
- config.enable_fast_dispatch = false;
- }
-
// Timing
config.wall_clock_cntpct = uses_wall_clock;
+ // Safe optimizations
+ if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
+ if (!Settings::values.cpuopt_page_tables) {
+ config.page_table = nullptr;
+ }
+ if (!Settings::values.cpuopt_block_linking) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
+ }
+ if (!Settings::values.cpuopt_return_stack_buffer) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer;
+ }
+ if (!Settings::values.cpuopt_fast_dispatcher) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch;
+ }
+ if (!Settings::values.cpuopt_context_elimination) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination;
+ }
+ if (!Settings::values.cpuopt_const_prop) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp;
+ }
+ if (!Settings::values.cpuopt_misc_ir) {
+ config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt;
+ }
+ if (!Settings::values.cpuopt_reduce_misalign_checks) {
+ config.only_detect_misalignment_via_page_table_on_page_boundary = false;
+ }
+ }
+
return std::make_shared<Dynarmic::A64::Jit>(config);
}
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 {
device_memory = std::make_unique<Core::DeviceMemory>(system);
- is_multicore = Settings::values.use_multi_core;
- is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation;
+ is_multicore = Settings::values.use_multi_core.GetValue();
+ is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue();
kernel.SetMulticore(is_multicore);
cpu_manager.SetMulticore(is_multicore);
@@ -162,7 +162,7 @@ struct System::Impl {
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch());
Settings::values.custom_rtc_differential =
- Settings::values.custom_rtc.value_or(current_time) - current_time;
+ Settings::values.custom_rtc.GetValue().value_or(current_time) - current_time;
// Create a default fs if one doesn't already exist.
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() {
}
void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
- basic_lock.lock();
+ std::scoped_lock lock{basic_lock};
const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
return e.type.lock().get() == event_type.get();
@@ -183,12 +183,10 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
event_queue.erase(itr, event_queue.end());
std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
- basic_lock.unlock();
}
std::optional<s64> CoreTiming::Advance() {
- std::scoped_lock advance_scope{advance_lock};
- std::scoped_lock basic_scope{basic_lock};
+ std::scoped_lock lock{advance_lock, basic_lock};
global_timer = GetGlobalTimeNs().count();
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,
}
void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
- if (s128_keys.find({id, field1, field2}) != s128_keys.end())
+ if (s128_keys.find({id, field1, field2}) != s128_keys.end() || key == Key128{}) {
return;
+ }
if (id == S128KeyType::Titlekey) {
Key128 rights_id;
std::memcpy(rights_id.data(), &field2, sizeof(u64));
@@ -716,8 +717,9 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
std::tie(id, field1, field2);
});
- if (iter2 != s128_file_id.end())
+ if (iter2 != s128_file_id.end()) {
WriteKeyToFile(category, iter2->first, key);
+ }
// Variable cases
if (id == S128KeyType::KeyArea) {
@@ -745,16 +747,18 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
}
void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
- if (s256_keys.find({id, field1, field2}) != s256_keys.end())
+ if (s256_keys.find({id, field1, field2}) != s256_keys.end() || key == Key256{}) {
return;
+ }
const auto iter = std::find_if(
s256_file_id.begin(), s256_file_id.end(),
[&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) {
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
std::tie(id, field1, field2);
});
- if (iter != s256_file_id.end())
+ if (iter != s256_file_id.end()) {
WriteKeyToFile(KeyCategory::Standard, iter->first, key);
+ }
s256_keys[{id, field1, field2}] = key;
}
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 @@
namespace FileSys {
+constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB
+constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB
+constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB
+
BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_)
: nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
dump_root(std::move(dump_root_)),
@@ -110,30 +114,29 @@ VirtualDir BISFactory::GetImageDirectory() const {
u64 BISFactory::GetSystemNANDFreeSpace() const {
const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
- if (sys_dir == nullptr)
- return 0;
+ if (sys_dir == nullptr) {
+ return GetSystemNANDTotalSpace();
+ }
return GetSystemNANDTotalSpace() - sys_dir->GetSize();
}
u64 BISFactory::GetSystemNANDTotalSpace() const {
- return static_cast<u64>(Settings::values.nand_system_size);
+ return NAND_SYSTEM_SIZE;
}
u64 BISFactory::GetUserNANDFreeSpace() const {
- const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user");
- if (usr_dir == nullptr)
- return 0;
-
- return GetUserNANDTotalSpace() - usr_dir->GetSize();
+ // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes.
+ // Set the free space to be 1 MiB less than the total as a workaround to this issue.
+ return GetUserNANDTotalSpace() - 0x100000;
}
u64 BISFactory::GetUserNANDTotalSpace() const {
- return static_cast<u64>(Settings::values.nand_user_size);
+ return NAND_USER_SIZE;
}
u64 BISFactory::GetFullNANDTotalSpace() const {
- return static_cast<u64>(Settings::values.nand_total_size);
+ return NAND_TOTAL_SIZE;
}
VirtualDir 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 @@
namespace FileSys {
+constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB
+
SDMCFactory::SDMCFactory(VirtualDir dir_)
: dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
@@ -46,7 +48,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const {
}
u64 SDMCFactory::GetSDMCTotalSpace() const {
- return static_cast<u64>(Settings::values.sdmc_size);
+ return SDMC_TOTAL_SIZE;
}
} // 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_
const auto new_path =
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
- if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
- FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
- return nullptr;
-
if (cache.find(old_path) != cache.end()) {
- auto cached = cache[old_path];
- if (!cached.expired()) {
- auto file = cached.lock();
- file->Open(new_path, "r+b");
- cache.erase(old_path);
- cache[new_path] = file;
+ auto file = cache[old_path].lock();
+
+ if (!cache[old_path].expired()) {
+ file->Close();
+ }
+
+ if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
+ FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) {
+ return nullptr;
}
+
+ cache.erase(old_path);
+ file->Open(new_path, "r+b");
+ cache[new_path] = file;
+ } else {
+ UNREACHABLE();
+ return nullptr;
}
+
return OpenFile(new_path, Mode::ReadWrite);
}
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) {
const float window_aspect_ratio = static_cast<float>(height) / width;
const float emulation_aspect_ratio = EmulationAspectRatio(
- static_cast<AspectRatio>(Settings::values.aspect_ratio), window_aspect_ratio);
+ static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio);
const Common::Rectangle<u32> screen_window_area{0, 0, width, height};
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,
: kernel.CreateNewUserProcessID();
process->capabilities.InitializeForMetadatalessProcess();
- std::mt19937 rng(Settings::values.rng_seed.value_or(0));
+ std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0));
std::uniform_int_distribution<u64> distribution;
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
[&] { 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 @@
// licensed under GPLv2 or later under exception provided by the author.
#include <algorithm>
+#include <mutex>
#include <set>
#include <unordered_set>
#include <utility>
@@ -31,22 +32,20 @@ GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {}
GlobalScheduler::~GlobalScheduler() = default;
void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) {
- global_list_guard.lock();
+ std::scoped_lock lock{global_list_guard};
thread_list.push_back(std::move(thread));
- global_list_guard.unlock();
}
void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) {
- global_list_guard.lock();
+ std::scoped_lock lock{global_list_guard};
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
thread_list.end());
- global_list_guard.unlock();
}
u32 GlobalScheduler::SelectThreads() {
ASSERT(is_locked);
const auto update_thread = [](Thread* thread, Scheduler& sched) {
- sched.guard.lock();
+ std::scoped_lock lock{sched.guard};
if (thread != sched.selected_thread_set.get()) {
if (thread == nullptr) {
++sched.idle_selection_count;
@@ -57,7 +56,6 @@ u32 GlobalScheduler::SelectThreads() {
sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread);
sched.is_context_switch_pending = reschedule_pending;
std::atomic_thread_fence(std::memory_order_seq_cst);
- sched.guard.unlock();
return reschedule_pending;
};
if (!is_reselection_pending.load()) {
@@ -757,11 +755,12 @@ void Scheduler::OnSwitch(void* this_scheduler) {
void Scheduler::SwitchToCurrent() {
while (true) {
- guard.lock();
- selected_thread = selected_thread_set;
- current_thread = selected_thread;
- is_context_switch_pending = false;
- guard.unlock();
+ {
+ std::scoped_lock lock{guard};
+ selected_thread = selected_thread_set;
+ current_thread = selected_thread;
+ is_context_switch_pending = false;
+ }
while (!is_context_switch_pending) {
if (current_thread != nullptr && !current_thread->IsHLEThread()) {
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,
{41, nullptr, "IsSystemBufferSharingEnabled"},
{42, nullptr, "GetSystemSharedLayerHandle"},
{43, nullptr, "GetSystemSharedBufferHandle"},
- {44, nullptr, "CreateManagedDisplaySeparableLayer"},
+ {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
{51, nullptr, "ApproveToDisplay"},
@@ -462,6 +462,24 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
rb.Push(*layer_id);
}
+void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ // TODO(Subv): Find out how AM determines the display to use, for now just
+ // create the layer in the Default display.
+ // This calls nn::vi::CreateRecordingLayer() which creates another layer.
+ // Currently we do not support more than 1 layer per display, output 1 layer id for now.
+ // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
+ // side effects.
+ // TODO: Support multiple layers
+ const auto display_id = nvflinger->OpenDisplay("Default");
+ const auto layer_id = nvflinger->CreateLayer(*display_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(*layer_id);
+}
+
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
@@ -731,14 +749,14 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
if (Settings::values.use_docked_mode) {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
} else {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
}
}
@@ -1389,7 +1407,19 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
u32 supported_languages = 0;
FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
- const auto res = pm.GetControlMetadata();
+ const auto res = [this] {
+ const auto title_id = system.CurrentProcess()->GetTitleID();
+
+ FileSys::PatchManager pm{title_id};
+ auto res = pm.GetControlMetadata();
+ if (res.first != nullptr) {
+ return res;
+ }
+
+ FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)};
+ return pm_update.GetControlMetadata();
+ }();
+
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
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:
void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx);
void SetAlbumImageOrientation(Kernel::HLERequestContext& ctx);
void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
+ void CreateManagedDisplaySeparableLayer(Kernel::HLERequestContext& ctx);
void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
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:
{39, nullptr, "PrepareShutdown"},
{40, nullptr, "ListApplyDeltaTask"},
{41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
- {42, nullptr, "Unknown1"},
- {43, nullptr, "Unknown2"},
- {44, nullptr, "Unknown3"},
- {45, nullptr, "Unknown4"},
- {46, nullptr, "Unknown5"},
+ {42, nullptr, "Unknown42"},
+ {43, nullptr, "Unknown43"},
+ {44, nullptr, "Unknown44"},
+ {45, nullptr, "Unknown45"},
+ {46, nullptr, "Unknown46"},
+ {47, nullptr, "Unknown47"},
+ {48, nullptr, "Unknown48"},
+ {49, nullptr, "Unknown49"},
+ {50, nullptr, "Unknown50"},
+ {51, nullptr, "Unknown51"},
+ {52, nullptr, "Unknown52"},
+ {53, nullptr, "Unknown53"},
+ {54, nullptr, "Unknown54"},
+ {55, nullptr, "Unknown55"},
+ {56, nullptr, "Unknown56"},
+ {57, nullptr, "Unknown57"},
+ {58, nullptr, "Unknown58"},
+ {59, nullptr, "Unknown59"},
+ {60, nullptr, "Unknown60"},
+ {61, nullptr, "Unknown61"},
+ {62, nullptr, "Unknown62"},
+ {63, nullptr, "Unknown63"},
+ {64, nullptr, "Unknown64"},
+ {65, nullptr, "Unknown65"},
+ {66, nullptr, "Unknown66"},
+ {67, nullptr, "Unknown67"},
+ {68, nullptr, "Unknown68"},
+ {69, nullptr, "Unknown69"},
+ {70, nullptr, "Unknown70"},
+ {71, nullptr, "Unknown71"},
+ {72, nullptr, "Unknown72"},
+ {73, nullptr, "Unknown73"},
+ {74, nullptr, "Unknown74"},
+ {75, nullptr, "Unknown75"},
+ {76, nullptr, "Unknown76"},
+ {77, nullptr, "Unknown77"},
+ {78, nullptr, "Unknown78"},
+ {79, nullptr, "Unknown79"},
+ {80, nullptr, "Unknown80"},
+ {81, nullptr, "Unknown81"},
+ {82, nullptr, "Unknown82"},
+ {83, nullptr, "Unknown83"},
+ {84, nullptr, "Unknown84"},
+ {85, nullptr, "Unknown85"},
+ {86, nullptr, "Unknown86"},
+ {87, nullptr, "Unknown87"},
+ {88, nullptr, "Unknown88"},
+ {89, nullptr, "Unknown89"},
+ {90, nullptr, "Unknown90"},
+ {91, nullptr, "Unknown91"},
+ {92, nullptr, "Unknown92"},
+ {93, nullptr, "Unknown93"},
+ {94, nullptr, "Unknown94"},
+ {95, nullptr, "Unknown95"},
+ {96, nullptr, "Unknown96"},
+ {97, nullptr, "Unknown97"},
+ {98, nullptr, "Unknown98"},
+ {99, nullptr, "Unknown99"},
+ {100, nullptr, "Unknown100"},
+ {101, nullptr, "Unknown101"},
+ {102, nullptr, "Unknown102"},
+ {103, nullptr, "Unknown103"},
+ {104, nullptr, "Unknown104"},
+ {105, nullptr, "Unknown105"},
+ {106, nullptr, "Unknown106"},
+ {107, nullptr, "Unknown107"},
+ {108, nullptr, "Unknown108"},
+ {109, nullptr, "Unknown109"},
+ {110, nullptr, "Unknown110"},
+ {111, nullptr, "Unknown111"},
+ {112, nullptr, "Unknown112"},
+ {113, nullptr, "Unknown113"},
+ {114, nullptr, "Unknown114"},
+ {115, nullptr, "Unknown115"},
+ {116, nullptr, "Unknown116"},
+ {117, nullptr, "Unknown117"},
+ {118, nullptr, "Unknown118"},
};
// clang-format on
@@ -142,6 +214,7 @@ public:
{1, nullptr, "RefreshDebugAvailability"},
{2, nullptr, "ClearDebugResponse"},
{3, nullptr, "RegisterDebugResponse"},
+ {4, nullptr, "IsLargeResourceAvailable"},
};
// clang-format on
@@ -164,6 +237,8 @@ public:
static const FunctionInfo functions[] = {
{0, nullptr, "RequestDeviceAuthenticationToken"},
{1, nullptr, "RequestCachedDeviceAuthenticationToken"},
+ {2, nullptr, "RequestEdgeToken"},
+ {3, nullptr, "RequestCachedEdgeToken"},
{100, nullptr, "RequestRegisterDeviceAccount"},
{101, nullptr, "RequestUnregisterDeviceAccount"},
{102, nullptr, "RequestDeviceAccountStatus"},
@@ -181,7 +256,8 @@ public:
{305, nullptr, "RequestCreateVirtualAccount"},
{306, nullptr, "RequestDeviceLinkStatus"},
{400, nullptr, "GetAccountByVirtualAccount"},
- {500, nullptr, "RequestSyncTicket"},
+ {401, nullptr, "GetVirtualAccount"},
+ {500, nullptr, "RequestSyncTicketLegacy"},
{501, nullptr, "RequestDownloadTicket"},
{502, nullptr, "RequestDownloadTicketForPrepurchasedContents"},
{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:
{23, nullptr, "DestroyToken"},
{24, nullptr, "DestroyTokenWithApplicationId"},
{25, nullptr, "QueryIsTokenValid"},
+ {26, nullptr, "ListenToMyApplicationId"},
{31, nullptr, "UploadTokenToBaaS"},
{32, nullptr, "DestroyTokenForBaaS"},
{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()
{94, nullptr, "LaunchApplication"},
{95, nullptr, "GetApplicationLaunchInfo"},
{96, nullptr, "AcquireApplicationLaunchInfo"},
- {97, nullptr, "GetMainApplicationProgramIndex2"},
+ {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"},
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{99, nullptr, "LaunchDevMenu"},
{100, nullptr, "ResetToFactorySettings"},
@@ -254,7 +254,7 @@ IApplicationManagerInterface::IApplicationManagerInterface()
{2170, nullptr, "GetRightsEnvironmentStatus"},
{2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
- {2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"},
+ {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
@@ -366,7 +366,8 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
// Get language code from settings
- const auto language_code = Set::GetLanguageCodeFromIndex(Settings::values.language_index);
+ const auto language_code =
+ Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
// Convert to application language, get priority list
const auto application_language = ConvertToApplicationLanguage(language_code);
@@ -445,8 +446,8 @@ IApplicationVersionInterface::IApplicationVersionInterface()
IApplicationVersionInterface::~IApplicationVersionInterface() = default;
-IContentManagerInterface::IContentManagerInterface()
- : ServiceFramework{"IContentManagerInterface"} {
+IContentManagementInterface::IContentManagementInterface()
+ : ServiceFramework{"IContentManagementInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"},
@@ -463,7 +464,7 @@ IContentManagerInterface::IContentManagerInterface()
RegisterHandlers(functions);
}
-IContentManagerInterface::~IContentManagerInterface() = default;
+IContentManagementInterface::~IContentManagementInterface() = default;
IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
// clang-format off
@@ -545,7 +546,7 @@ NS::NS(const char* name) : ServiceFramework{name} {
{7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
{7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
{7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
- {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
+ {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"},
{7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
};
// clang-format on
@@ -572,9 +573,9 @@ public:
{6, nullptr, "TerminateApplication"},
{7, nullptr, "PrepareLaunchProgramFromHost"},
{8, nullptr, "LaunchApplication"},
- {9, nullptr, "LaunchApplicationWithStorageId"},
- {10, nullptr, "TerminateApplication2"},
- {11, nullptr, "GetRunningApplicationProcessId"},
+ {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
+ {10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
+ {11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
{12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"},
{13, nullptr, "CreateApplicationResourceForDevelop"},
{14, nullptr, "IsPreomiaForDevelop"},
@@ -636,6 +637,10 @@ public:
{9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"},
{10, nullptr, "NotifySystemUpdateForContentDelivery"},
{11, nullptr, "PrepareShutdown"},
+ {12, nullptr, "Unknown12"},
+ {13, nullptr, "Unknown13"},
+ {14, nullptr, "Unknown14"},
+ {15, nullptr, "Unknown15"},
{16, nullptr, "DestroySystemUpdateTask"},
{17, nullptr, "RequestSendSystemUpdate"},
{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:
~IApplicationVersionInterface() override;
};
-class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
+class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> {
public:
- explicit IContentManagerInterface();
- ~IContentManagerInterface() override;
+ explicit IContentManagementInterface();
+ ~IContentManagementInterface() override;
};
class 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)
{5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
{6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"},
{100, nullptr, "RequestApplicationFunctionAuthorization"},
- {101, nullptr, "RequestApplicationFunctionAuthorizationForSystem"},
+ {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
{102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
{1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
{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) {
}
}
-void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
+void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
pid = rp.Pop<u64>();
LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
@@ -154,7 +154,7 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0);
}
-void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) {
+void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -187,13 +187,14 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
{4, &NVDRV::QueryEvent, "QueryEvent"},
{5, nullptr, "MapSharedMem"},
{6, &NVDRV::GetStatus, "GetStatus"},
- {7, nullptr, "ForceSetClientPID"},
- {8, &NVDRV::SetClientPID, "SetClientPID"},
+ {7, nullptr, "SetAruidForTest"},
+ {8, &NVDRV::SetAruid, "SetAruid"},
{9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
{10, nullptr, "InitializeDevtools"},
{11, &NVDRV::Ioctl2, "Ioctl2"},
{12, &NVDRV::Ioctl3, "Ioctl3"},
- {13, &NVDRV::FinishInitialize, "FinishInitialize"},
+ {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled,
+ "SetGraphicsFirmwareMemoryMarginEnabled"},
};
RegisterHandlers(functions);
}
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:
void Close(Kernel::HLERequestContext& ctx);
void Initialize(Kernel::HLERequestContext& ctx);
void QueryEvent(Kernel::HLERequestContext& ctx);
- void SetClientPID(Kernel::HLERequestContext& ctx);
- void FinishInitialize(Kernel::HLERequestContext& ctx);
+ void SetAruid(Kernel::HLERequestContext& ctx);
+ void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
void GetStatus(Kernel::HLERequestContext& ctx);
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
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 {
NVMEMP::NVMEMP() : ServiceFramework("nvmemp") {
static const FunctionInfo functions[] = {
- {0, &NVMEMP::Cmd0, "Cmd0"},
- {1, &NVMEMP::Cmd1, "Cmd1"},
+ {0, &NVMEMP::Open, "Open"},
+ {1, &NVMEMP::GetAruid, "GetAruid"},
};
RegisterHandlers(functions);
}
NVMEMP::~NVMEMP() = default;
-void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) {
+void NVMEMP::Open(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED();
}
-void NVMEMP::Cmd1(Kernel::HLERequestContext& ctx) {
+void NVMEMP::GetAruid(Kernel::HLERequestContext& ctx) {
UNIMPLEMENTED();
}
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:
~NVMEMP() override;
private:
- void Cmd0(Kernel::HLERequestContext& ctx);
- void Cmd1(Kernel::HLERequestContext& ctx);
+ void Open(Kernel::HLERequestContext& ctx);
+ void GetAruid(Kernel::HLERequestContext& ctx);
};
} // 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:
{18, nullptr, "ReleaseIrq"},
{19, nullptr, "SetIrqEnable"},
{20, nullptr, "SetAspmEnable"},
+ {21, nullptr, "SetResetUponResumeEnable"},
+ {22, nullptr, "Unknown22"},
+ {23, nullptr, "Unknown23"},
};
// clang-format on
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:
{24, nullptr, "GetModuleStateTable"},
{25, nullptr, "GetPowerDomainStateTable"},
{26, nullptr, "GetFuseInfo"},
+ {27, nullptr, "GetDramId"},
+ {28, nullptr, "IsPoweredOn"},
+ {29, nullptr, "GetVoltage"},
};
// clang-format on
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:
: ServiceFramework{"pm:dmnt"}, kernel(kernel) {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "GetDebugProcesses"},
- {1, nullptr, "StartDebugProcess"},
- {2, &DebugMonitor::GetTitlePid, "GetTitlePid"},
- {3, nullptr, "EnableDebugForTitleId"},
- {4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"},
- {5, nullptr, "EnableDebugForApplication"},
- {6, nullptr, "DisableDebug"},
+ {0, nullptr, "GetJitDebugProcessIdList"},
+ {1, nullptr, "StartProcess"},
+ {2, &DebugMonitor::GetProcessId, "GetProcessId"},
+ {3, nullptr, "HookToCreateProcess"},
+ {4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"},
+ {5, nullptr, "HookToCreateApplicationProgress"},
+ {6, nullptr, "ClearHook"},
};
// clang-format on
@@ -92,7 +92,7 @@ public:
}
private:
- void GetTitlePid(Kernel::HLERequestContext& ctx) {
+ void GetProcessId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@@ -114,7 +114,7 @@ private:
rb.Push((*process)->GetProcessID());
}
- void GetApplicationPid(Kernel::HLERequestContext& ctx) {
+ void GetApplicationProcessId(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
}
@@ -163,15 +163,15 @@ public:
: ServiceFramework{"pm:shell"}, kernel(kernel) {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "LaunchProcess"},
- {1, nullptr, "TerminateProcessByPid"},
- {2, nullptr, "TerminateProcessByTitleId"},
- {3, nullptr, "GetProcessEventWaiter"},
- {4, nullptr, "GetProcessEventType"},
+ {0, nullptr, "LaunchProgram"},
+ {1, nullptr, "TerminateProcess"},
+ {2, nullptr, "TerminateProgram"},
+ {3, nullptr, "GetProcessEventHandle"},
+ {4, nullptr, "GetProcessEventInfo"},
{5, nullptr, "NotifyBootFinished"},
- {6, &Shell::GetApplicationPid, "GetApplicationPid"},
+ {6, &Shell::GetApplicationProcessIdForShell, "GetApplicationProcessIdForShell"},
{7, nullptr, "BoostSystemMemoryResourceLimit"},
- {8, nullptr, "EnableAdditionalSystemThreads"},
+ {8, nullptr, "BoostApplicationThreadResourceLimit"},
{9, nullptr, "GetBootFinishedEventHandle"},
};
// clang-format on
@@ -180,7 +180,7 @@ public:
}
private:
- void GetApplicationPid(Kernel::HLERequestContext& ctx) {
+ void GetApplicationProcessIdForShell(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
}
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:
{40101, nullptr, "SetUserAgreementCheckEnabled"},
{50100, nullptr, "ReadAllApplicationReportFiles"},
{90100, nullptr, "ReadAllReportFiles"},
+ {90101, nullptr, "Unknown90101"},
+ {90102, nullptr, "Unknown90102"},
+ {90200, nullptr, "GetStatistics"},
+ {90201, nullptr, "GetThroughputHistory"},
+ {90300, nullptr, "GetLastUploadError"},
};
// clang-format on
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:
{4, nullptr, "Cancel"},
{5, nullptr, "PrintModuleInformation"},
{6, nullptr, "GetModuleInformation"},
+ {10, nullptr, "Unknown10"},
+ {11, nullptr, "Unknown11"},
};
// clang-format on
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:
{15, nullptr, "GetBatteryAgePercentage"},
{16, nullptr, "GetBatteryChargeInfoEvent"},
{17, nullptr, "GetBatteryChargeInfoFields"},
+ {18, nullptr, "GetBatteryChargeCalibratedEvent"},
};
// clang-format on
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
}
void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) {
- const auto language_code = available_language_codes[Settings::values.language_index];
+ const auto language_code = available_language_codes[Settings::values.language_index.GetValue()];
const auto key_code =
std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
[=](const auto& element) { return element.first == language_code; });
@@ -99,7 +99,7 @@ void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) {
if (key_code == language_to_layout.cend()) {
LOG_ERROR(Service_SET,
"Could not find keyboard layout for language index {}, defaulting to English us",
- Settings::values.language_index);
+ Settings::values.language_index.GetValue());
} else {
layout = key_code->second;
}
@@ -163,11 +163,11 @@ void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
}
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
+ LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index.GetValue());
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.PushEnum(available_language_codes[Settings::values.language_index]);
+ rb.PushEnum(available_language_codes[Settings::values.language_index.GetValue()]);
}
void SET::GetRegionCode(Kernel::HLERequestContext& ctx) {
@@ -175,7 +175,7 @@ void SET::GetRegionCode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(Settings::values.region_index);
+ rb.Push(Settings::values.region_index.GetValue());
}
void 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 @@
namespace Service::SM {
-void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
+void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
ctx.Session()->ConvertToDomain();
@@ -22,7 +22,7 @@ void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(1); // Converted sessions start with 1 request handler
}
-void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
+void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
// and that we probably want to actually make an entirely new Session, but we still need to
// verify this on hardware.
@@ -33,10 +33,10 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
rb.PushMoveObjects(ctx.Session()->GetParent()->Client());
}
-void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called, using DuplicateSession");
+void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject");
- DuplicateSession(ctx);
+ CloneCurrentObject(ctx);
}
void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
@@ -47,13 +47,14 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push<u16>(0x1000);
}
+// https://switchbrew.org/wiki/IPC_Marshalling
Controller::Controller() : ServiceFramework("IpcController") {
static const FunctionInfo functions[] = {
- {0x00000000, &Controller::ConvertSessionToDomain, "ConvertSessionToDomain"},
- {0x00000001, nullptr, "ConvertDomainToSession"},
- {0x00000002, &Controller::DuplicateSession, "DuplicateSession"},
- {0x00000003, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"},
- {0x00000004, &Controller::DuplicateSessionEx, "DuplicateSessionEx"},
+ {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"},
+ {1, nullptr, "CopyFromCurrentDomain"},
+ {2, &Controller::CloneCurrentObject, "CloneCurrentObject"},
+ {3, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"},
+ {4, &Controller::CloneCurrentObjectEx, "CloneCurrentObjectEx"},
};
RegisterHandlers(functions);
}
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:
~Controller() override;
private:
- void ConvertSessionToDomain(Kernel::HLERequestContext& ctx);
- void DuplicateSession(Kernel::HLERequestContext& ctx);
- void DuplicateSessionEx(Kernel::HLERequestContext& ctx);
+ void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx);
+ void CloneCurrentObject(Kernel::HLERequestContext& ctx);
+ void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx);
void QueryPointerBufferSize(Kernel::HLERequestContext& ctx);
};
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) {
{12, nullptr, "GetDeviceId"},
{13, nullptr, "DeleteSettings"},
{14, nullptr, "ImportSettings"},
+ {15, nullptr, "SetChangeEnvironmentIdentifierDisabled"},
{20, nullptr, "Resolve"},
{21, nullptr, "ResolveEx"},
{30, nullptr, "GetNasServiceSetting"},
@@ -28,6 +29,11 @@ NSD::NSD(const char* name) : ServiceFramework(name) {
{60, nullptr, "ReadSaveDataFromFsForTest"},
{61, nullptr, "WriteSaveDataToFsForTest"},
{62, nullptr, "DeleteSaveDataOfFsForTest"},
+ {63, nullptr, "IsChangeEnvironmentIdentifierDisabled"},
+ {64, nullptr, "SetWithoutDomainExchangeFqdns"},
+ {100, nullptr, "GetApplicationServerEnvironmentType"},
+ {101, nullptr, "SetApplicationServerEnvironmentType"},
+ {102, nullptr, "DeleteApplicationServerEnvironmentType"},
};
// clang-format on
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 @@
namespace Service::Sockets {
-void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) {
+void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
struct Parameters {
u8 use_nsd_resolve;
u32 unknown;
@@ -29,15 +29,20 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
static const FunctionInfo functions[] = {
{0, nullptr, "SetDnsAddressesPrivate"},
{1, nullptr, "GetDnsAddressPrivate"},
- {2, nullptr, "GetHostByName"},
- {3, nullptr, "GetHostByAddr"},
- {4, nullptr, "GetHostStringError"},
- {5, nullptr, "GetGaiStringError"},
- {6, &SFDNSRES::GetAddrInfo, "GetAddrInfo"},
- {7, nullptr, "GetNameInfo"},
- {8, nullptr, "RequestCancelHandle"},
- {9, nullptr, "CancelSocketCall"},
- {11, nullptr, "ClearDnsIpServerAddressArray"},
+ {2, nullptr, "GetHostByNameRequest"},
+ {3, nullptr, "GetHostByAddrRequest"},
+ {4, nullptr, "GetHostStringErrorRequest"},
+ {5, nullptr, "GetGaiStringErrorRequest"},
+ {6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"},
+ {7, nullptr, "GetNameInfoRequest"},
+ {8, nullptr, "RequestCancelHandleRequest"},
+ {9, nullptr, "CancelRequest"},
+ {10, nullptr, "GetHostByNameRequestWithOptions"},
+ {11, nullptr, "GetHostByAddrRequestWithOptions"},
+ {12, nullptr, "GetAddrInfoRequestWithOptions"},
+ {13, nullptr, "GetNameInfoRequestWithOptions"},
+ {14, nullptr, "ResolverSetOptionRequest"},
+ {15, nullptr, "ResolverGetOptionRequest"},
};
RegisterHandlers(functions);
}
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:
~SFDNSRES() override;
private:
- void GetAddrInfo(Kernel::HLERequestContext& ctx);
+ void GetAddrInfoRequest(Kernel::HLERequestContext& ctx);
};
} // 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 {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)),
- rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {}
+ rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {}
Module::Interface::~Interface() = default;
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 {
SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") {
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
- {1, nullptr, "UserExpMod"},
+ {1, nullptr, "ModularExponentiate"},
{2, nullptr, "GenerateAesKek"},
{3, nullptr, "LoadAesKey"},
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GetRandomBytes"},
- {9, nullptr, "LoadSecureExpModKey"},
- {10, nullptr, "SecureExpMod"},
+ {9, nullptr, "ImportLotusKey"},
+ {10, nullptr, "DecryptLotusMessage"},
{11, nullptr, "IsDevelopment"},
{12, nullptr, "GenerateSpecificAesKey"},
- {13, nullptr, "DecryptPrivk"},
+ {13, nullptr, "DecryptDeviceUniqueData"},
{14, nullptr, "DecryptAesKey"},
- {15, nullptr, "DecryptAesCtr"},
+ {15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
- {17, nullptr, "LoadRsaOaepKey"},
- {18, nullptr, "UnwrapRsaOaepWrappedTitleKey"},
+ {17, nullptr, "ImportEsKey"},
+ {18, nullptr, "UnwrapTitleKey"},
{19, nullptr, "LoadTitleKey"},
- {20, nullptr, "UnwrapAesWrappedTitleKey"},
- {21, nullptr, "LockAesEngine"},
- {22, nullptr, "UnlockAesEngine"},
- {23, nullptr, "GetSplWaitEvent"},
- {24, nullptr, "SetSharedData"},
- {25, nullptr, "GetSharedData"},
- {26, nullptr, "ImportSslRsaKey"},
- {27, nullptr, "SecureExpModWithSslKey"},
- {28, nullptr, "ImportEsRsaKey"},
- {29, nullptr, "SecureExpModWithEsKey"},
- {30, nullptr, "EncryptManuRsaKeyForImport"},
- {31, nullptr, "GetPackage2Hash"},
+ {20, nullptr, "PrepareEsCommonKey"},
+ {21, nullptr, "AllocateAesKeyslot"},
+ {22, nullptr, "DeallocateAesKeySlot"},
+ {23, nullptr, "GetAesKeyslotAvailableEvent"},
+ {24, nullptr, "SetBootReason"},
+ {25, nullptr, "GetBootReason"},
+ {26, nullptr, "DecryptAndStoreSslClientCertKey"},
+ {27, nullptr, "ModularExponentiateWithSslClientCertKey"},
+ {28, nullptr, "DecryptAndStoreDrmDeviceCertKey"},
+ {29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"},
+ {30, nullptr, "ReencryptDeviceUniqueData "},
+ {31, nullptr, "PrepareEsArchiveKey"}, // This is also GetPackage2Hash?
+ {32, nullptr, "LoadPreparedAesKey"},
};
RegisterHandlers(functions);
}
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:
: ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} {
static const FunctionInfo functions[] = {
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
+ {2, nullptr, "GetTestOffset"},
+ {3, nullptr, "SetTestOffset"},
+ {100, nullptr, "GetRtcValue"},
+ {101, nullptr, "IsRtcResetDetected"},
+ {102, nullptr, "GetSetupResultValue"},
+ {200, nullptr, "GetInternalOffset"},
+ {201, nullptr, "SetInternalOffset"},
};
RegisterHandlers(functions);
}
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:
static const FunctionInfo functions[] = {
{0, nullptr, "GetDsEndpoint"},
{1, nullptr, "GetSetupEvent"},
- {2, nullptr, "Unknown"},
+ {2, nullptr, "Unknown2"},
{3, nullptr, "EnableInterface"},
{4, nullptr, "DisableInterface"},
{5, nullptr, "CtrlInPostBufferAsync"},
@@ -55,6 +55,7 @@ public:
{9, nullptr, "SetBinaryObjectStore"},
{10, nullptr, "Enable"},
{11, nullptr, "Disable"},
+ {12, nullptr, "Unknown12"},
};
// clang-format on
@@ -69,13 +70,13 @@ public:
static const FunctionInfo functions[] = {
{0, nullptr, "Open"},
{1, nullptr, "Close"},
- {2, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
{3, nullptr, "Populate"},
{4, nullptr, "PostBufferAsync"},
{5, nullptr, "GetXferReport"},
{6, nullptr, "PostBufferMultiAsync"},
- {7, nullptr, "Unknown3"},
- {8, nullptr, "Unknown4"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
};
// clang-format on
@@ -88,13 +89,13 @@ public:
explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown1"},
+ {0, nullptr, "Unknown0"},
{1, nullptr, "SetInterface"},
{2, nullptr, "GetInterface"},
{3, nullptr, "GetAlternateInterface"},
{4, nullptr, "GetCurrentFrame"},
{5, nullptr, "CtrlXferAsync"},
- {6, nullptr, "Unknown2"},
+ {6, nullptr, "Unknown6"},
{7, nullptr, "GetCtrlXferReport"},
{8, nullptr, "ResetDevice"},
{9, nullptr, "OpenUsbEp"},
@@ -118,7 +119,7 @@ public:
{5, nullptr, "DestroyInterfaceAvailableEvent"},
{6, nullptr, "GetInterfaceStateChangeEvent"},
{7, nullptr, "AcquireUsbIf"},
- {8, nullptr, "Unknown1"},
+ {8, nullptr, "Unknown8"},
};
// clang-format on
@@ -179,8 +180,8 @@ public:
{4, nullptr, "GetFwRevision"},
{5, nullptr, "GetManufacturerId"},
{6, nullptr, "GetDeviceId"},
- {7, nullptr, "Unknown1"},
- {8, nullptr, "Unknown2"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
};
// clang-format on
@@ -215,12 +216,12 @@ public:
explicit USB_PM() : ServiceFramework{"usb:pm"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown1"},
- {1, nullptr, "Unknown2"},
- {2, nullptr, "Unknown3"},
- {3, nullptr, "Unknown4"},
- {4, nullptr, "Unknown5"},
- {5, nullptr, "Unknown6"},
+ {0, nullptr, "Unknown0"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
};
// clang-format on
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:
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
IGBPConnectResponseParcel response{
static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
- Settings::values.resolution_factor),
+ Settings::values.resolution_factor.GetValue()),
static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
- Settings::values.resolution_factor)};
+ Settings::values.resolution_factor.GetValue())};
ctx.WriteBuffer(response.Serialize());
break;
}
@@ -700,6 +700,7 @@ public:
{3215, nullptr, "SetDisplayGamma"},
{3216, nullptr, "GetDisplayCmuLuma"},
{3217, nullptr, "SetDisplayCmuLuma"},
+ {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
{8225, nullptr, "GetSharedBufferMemoryHandleId"},
{8250, nullptr, "OpenSharedLayer"},
{8251, nullptr, "CloseSharedLayer"},
@@ -748,14 +749,14 @@ private:
if (Settings::values.use_docked_mode) {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
} else {
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
}
rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
@@ -785,6 +786,7 @@ public:
{2300, nullptr, "AcquireLayerTexturePresentingEvent"},
{2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
{2302, nullptr, "GetDisplayHotplugEvent"},
+ {2303, nullptr, "GetDisplayModeChangedEvent"},
{2402, nullptr, "GetDisplayHotplugState"},
{2501, nullptr, "GetCompositorErrorInfo"},
{2601, nullptr, "GetDisplayErrorEvent"},
@@ -1029,9 +1031,9 @@ private:
// between docked and undocked dimensions. We take the liberty of applying
// the resolution scaling factor here.
rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
- static_cast<u32>(Settings::values.resolution_factor));
+ static_cast<u32>(Settings::values.resolution_factor.GetValue()));
}
void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
@@ -1064,8 +1066,8 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called");
DisplayInfo display_info;
- display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
- display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
+ display_info.width *= static_cast<u64>(Settings::values.resolution_factor.GetValue());
+ display_info.height *= static_cast<u64>(Settings::values.resolution_factor.GetValue());
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
IPC::ResponseBuilder rb{ctx, 4};
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)
: ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} {
static const FunctionInfo functions[] = {
{0, &VI_U::GetDisplayService, "GetDisplayService"},
+ {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
};
RegisterHandlers(functions);
}
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:
explicit WLANInfra() : ServiceFramework{"wlan:inf"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown1"},
- {1, nullptr, "Unknown2"},
+ {0, nullptr, "OpenMode"},
+ {1, nullptr, "CloseMode"},
{2, nullptr, "GetMacAddress"},
{3, nullptr, "StartScan"},
{4, nullptr, "StopScan"},
{5, nullptr, "Connect"},
{6, nullptr, "CancelConnect"},
{7, nullptr, "Disconnect"},
- {8, nullptr, "Unknown3"},
- {9, nullptr, "Unknown4"},
+ {8, nullptr, "GetConnectionEvent"},
+ {9, nullptr, "GetConnectionStatus"},
{10, nullptr, "GetState"},
{11, nullptr, "GetScanResult"},
{12, nullptr, "GetRssi"},
{13, nullptr, "ChangeRxAntenna"},
- {14, nullptr, "Unknown5"},
- {15, nullptr, "Unknown6"},
+ {14, nullptr, "GetFwVersion"},
+ {15, nullptr, "RequestSleep"},
{16, nullptr, "RequestWakeUp"},
{17, nullptr, "RequestIfUpDown"},
- {18, nullptr, "Unknown7"},
- {19, nullptr, "Unknown8"},
- {20, nullptr, "Unknown9"},
- {21, nullptr, "Unknown10"},
- {22, nullptr, "Unknown11"},
- {23, nullptr, "Unknown12"},
- {24, nullptr, "Unknown13"},
- {25, nullptr, "Unknown14"},
- {26, nullptr, "Unknown15"},
- {27, nullptr, "Unknown16"},
+ {18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
+ {20, nullptr, "Unknown20"},
+ {21, nullptr, "Unknown21"},
+ {22, nullptr, "Unknown22"},
+ {23, nullptr, "Unknown23"},
+ {24, nullptr, "Unknown24"},
+ {25, nullptr, "Unknown25"},
+ {26, nullptr, "Unknown26"},
+ {27, nullptr, "Unknown27"},
+ {28, nullptr, "Unknown28"},
+ {29, nullptr, "Unknown29"},
+ {30, nullptr, "Unknown30"},
};
// clang-format on
@@ -55,12 +58,12 @@ public:
explicit WLANLocal() : ServiceFramework{"wlan:lcl"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown1"},
- {1, nullptr, "Unknown2"},
- {2, nullptr, "Unknown3"},
- {3, nullptr, "Unknown4"},
- {4, nullptr, "Unknown5"},
- {5, nullptr, "Unknown6"},
+ {0, nullptr, "Unknown0"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
{6, nullptr, "GetMacAddress"},
{7, nullptr, "CreateBss"},
{8, nullptr, "DestroyBss"},
@@ -72,38 +75,42 @@ public:
{14, nullptr, "CancelJoin"},
{15, nullptr, "Disconnect"},
{16, nullptr, "SetBeaconLostCount"},
- {17, nullptr, "Unknown7"},
- {18, nullptr, "Unknown8"},
- {19, nullptr, "Unknown9"},
+ {17, nullptr, "Unknown17"},
+ {18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
{20, nullptr, "GetBssIndicationEvent"},
{21, nullptr, "GetBssIndicationInfo"},
{22, nullptr, "GetState"},
{23, nullptr, "GetAllowedChannels"},
{24, nullptr, "AddIe"},
{25, nullptr, "DeleteIe"},
- {26, nullptr, "Unknown10"},
- {27, nullptr, "Unknown11"},
+ {26, nullptr, "Unknown26"},
+ {27, nullptr, "Unknown27"},
{28, nullptr, "CreateRxEntry"},
{29, nullptr, "DeleteRxEntry"},
- {30, nullptr, "Unknown12"},
- {31, nullptr, "Unknown13"},
+ {30, nullptr, "Unknown30"},
+ {31, nullptr, "Unknown31"},
{32, nullptr, "AddMatchingDataToRxEntry"},
{33, nullptr, "RemoveMatchingDataFromRxEntry"},
{34, nullptr, "GetScanResult"},
- {35, nullptr, "Unknown14"},
+ {35, nullptr, "Unknown35"},
{36, nullptr, "SetActionFrameWithBeacon"},
{37, nullptr, "CancelActionFrameWithBeacon"},
{38, nullptr, "CreateRxEntryForActionFrame"},
{39, nullptr, "DeleteRxEntryForActionFrame"},
- {40, nullptr, "Unknown15"},
- {41, nullptr, "Unknown16"},
+ {40, nullptr, "Unknown40"},
+ {41, nullptr, "Unknown41"},
{42, nullptr, "CancelGetActionFrame"},
{43, nullptr, "GetRssi"},
- {44, nullptr, "Unknown17"},
- {45, nullptr, "Unknown18"},
- {46, nullptr, "Unknown19"},
- {47, nullptr, "Unknown20"},
- {48, nullptr, "Unknown21"},
+ {44, nullptr, "Unknown44"},
+ {45, nullptr, "Unknown45"},
+ {46, nullptr, "Unknown46"},
+ {47, nullptr, "Unknown47"},
+ {48, nullptr, "Unknown48"},
+ {49, nullptr, "Unknown49"},
+ {50, nullptr, "Unknown50"},
+ {51, nullptr, "Unknown51"},
+ {52, nullptr, "Unknown52"},
};
// clang-format on
@@ -142,18 +149,19 @@ public:
explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown1"},
- {1, nullptr, "Unknown2"},
- {2, nullptr, "Unknown3"},
- {3, nullptr, "Unknown4"},
- {4, nullptr, "Unknown5"},
- {5, nullptr, "Unknown6"},
+ {0, nullptr, "Unknown0"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
{6, nullptr, "GetMacAddress"},
{7, nullptr, "SwitchTsfTimerFunction"},
- {8, nullptr, "Unknown7"},
- {9, nullptr, "Unknown8"},
- {10, nullptr, "Unknown9"},
- {11, nullptr, "Unknown10"},
+ {8, nullptr, "Unknown8"},
+ {9, nullptr, "Unknown9"},
+ {10, nullptr, "Unknown10"},
+ {11, nullptr, "Unknown11"},
+ {12, nullptr, "Unknown12"},
};
// clang-format on
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() {
}
void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
- if (!Settings::values.use_frame_limit || Settings::values.use_multi_core) {
+ if (!Settings::values.use_frame_limit.GetValue() ||
+ Settings::values.use_multi_core.GetValue()) {
return;
}
auto now = Clock::now();
- const double sleep_scale = Settings::values.frame_limit / 100.0;
+ const double sleep_scale = Settings::values.frame_limit.GetValue() / 100.0;
// Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
// 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 = {{
}
Values values = {};
+bool configuring_global = true;
std::string GetTimeZoneString() {
static constexpr std::array<const char*, 46> timezones{{
@@ -73,9 +74,9 @@ std::string GetTimeZoneString() {
"UCT", "Universal", "UTC", "W-SU", "WET", "Zulu",
}};
- ASSERT(Settings::values.time_zone_index < timezones.size());
+ ASSERT(Settings::values.time_zone_index.GetValue() < timezones.size());
- return timezones[Settings::values.time_zone_index];
+ return timezones[Settings::values.time_zone_index.GetValue()];
}
void Apply() {
@@ -97,25 +98,25 @@ void LogSetting(const std::string& name, const T& value) {
void LogSettings() {
LOG_INFO(Config, "yuzu Configuration:");
- LogSetting("System_UseDockedMode", Settings::values.use_docked_mode);
- LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0));
+ LogSetting("Controls_UseDockedMode", Settings::values.use_docked_mode);
+ LogSetting("System_RngSeed", Settings::values.rng_seed.GetValue().value_or(0));
LogSetting("System_CurrentUser", Settings::values.current_user);
- LogSetting("System_LanguageIndex", Settings::values.language_index);
- LogSetting("System_RegionIndex", Settings::values.region_index);
- LogSetting("System_TimeZoneIndex", Settings::values.time_zone_index);
- LogSetting("Core_UseMultiCore", Settings::values.use_multi_core);
- LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);
- LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit);
- LogSetting("Renderer_FrameLimit", Settings::values.frame_limit);
- LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache);
- LogSetting("Renderer_GPUAccuracyLevel", Settings::values.gpu_accuracy);
+ LogSetting("System_LanguageIndex", Settings::values.language_index.GetValue());
+ LogSetting("System_RegionIndex", Settings::values.region_index.GetValue());
+ LogSetting("System_TimeZoneIndex", Settings::values.time_zone_index.GetValue());
+ LogSetting("Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
+ LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor.GetValue());
+ LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue());
+ LogSetting("Renderer_FrameLimit", Settings::values.frame_limit.GetValue());
+ LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache.GetValue());
+ LogSetting("Renderer_GPUAccuracyLevel", Settings::values.gpu_accuracy.GetValue());
LogSetting("Renderer_UseAsynchronousGpuEmulation",
- Settings::values.use_asynchronous_gpu_emulation);
- LogSetting("Renderer_UseVsync", Settings::values.use_vsync);
- LogSetting("Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders);
- LogSetting("Renderer_AnisotropicFilteringLevel", Settings::values.max_anisotropy);
+ Settings::values.use_asynchronous_gpu_emulation.GetValue());
+ LogSetting("Renderer_UseVsync", Settings::values.use_vsync.GetValue());
+ LogSetting("Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders.GetValue());
+ LogSetting("Renderer_AnisotropicFilteringLevel", Settings::values.max_anisotropy.GetValue());
LogSetting("Audio_OutputEngine", Settings::values.sink_id);
- LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
+ LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching.GetValue());
LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);
LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd);
LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
@@ -131,15 +132,56 @@ float Volume() {
if (values.audio_muted) {
return 0.0f;
}
- return values.volume;
+ return values.volume.GetValue();
}
bool IsGPULevelExtreme() {
- return values.gpu_accuracy == GPUAccuracy::Extreme;
+ return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme;
}
bool IsGPULevelHigh() {
- return values.gpu_accuracy == GPUAccuracy::Extreme || values.gpu_accuracy == GPUAccuracy::High;
+ return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme ||
+ values.gpu_accuracy.GetValue() == GPUAccuracy::High;
+}
+
+void RestoreGlobalState() {
+ // If a game is running, DO NOT restore the global settings state
+ if (Core::System::GetInstance().IsPoweredOn()) {
+ return;
+ }
+
+ // Audio
+ values.enable_audio_stretching.SetGlobal(true);
+ values.volume.SetGlobal(true);
+
+ // Core
+ values.use_multi_core.SetGlobal(true);
+
+ // Renderer
+ values.renderer_backend.SetGlobal(true);
+ values.vulkan_device.SetGlobal(true);
+ values.aspect_ratio.SetGlobal(true);
+ values.max_anisotropy.SetGlobal(true);
+ values.use_frame_limit.SetGlobal(true);
+ values.frame_limit.SetGlobal(true);
+ values.use_disk_shader_cache.SetGlobal(true);
+ values.gpu_accuracy.SetGlobal(true);
+ values.use_asynchronous_gpu_emulation.SetGlobal(true);
+ values.use_vsync.SetGlobal(true);
+ values.use_assembly_shaders.SetGlobal(true);
+ values.use_fast_gpu_time.SetGlobal(true);
+ values.force_30fps_mode.SetGlobal(true);
+ values.bg_red.SetGlobal(true);
+ values.bg_green.SetGlobal(true);
+ values.bg_blue.SetGlobal(true);
+
+ // System
+ values.language_index.SetGlobal(true);
+ values.region_index.SetGlobal(true);
+ values.time_zone_index.SetGlobal(true);
+ values.rng_seed.SetGlobal(true);
+ values.custom_rtc.SetGlobal(true);
+ values.sound_index.SetGlobal(true);
}
} // 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 {
u32 rotation_angle;
};
-enum class NANDTotalSize : u64 {
- S29_1GB = 0x747C00000ULL,
-};
-
-enum class NANDUserSize : u64 {
- S26GB = 0x680000000ULL,
-};
-
-enum class NANDSystemSize : u64 {
- S2_5GB = 0xA0000000,
-};
-
-enum class SDMCSize : u64 {
- S1GB = 0x40000000,
- S2GB = 0x80000000,
- S4GB = 0x100000000ULL,
- S8GB = 0x200000000ULL,
- S16GB = 0x400000000ULL,
- S32GB = 0x800000000ULL,
- S64GB = 0x1000000000ULL,
- S128GB = 0x2000000000ULL,
- S256GB = 0x4000000000ULL,
- S1TB = 0x10000000000ULL,
-};
-
enum class RendererBackend {
OpenGL = 0,
Vulkan = 1,
@@ -382,20 +357,102 @@ enum class GPUAccuracy : u32 {
Extreme = 2,
};
+enum class CPUAccuracy {
+ Accurate = 0,
+ DebugMode = 1,
+};
+
+extern bool configuring_global;
+
+template <typename Type>
+class Setting final {
+public:
+ Setting() = default;
+ explicit Setting(Type val) : global{val} {}
+ ~Setting() = default;
+ void SetGlobal(bool to_global) {
+ use_global = to_global;
+ }
+ bool UsingGlobal() const {
+ return use_global;
+ }
+ Type GetValue(bool need_global = false) const {
+ if (use_global || need_global) {
+ return global;
+ }
+ return local;
+ }
+ void SetValue(const Type& value) {
+ if (use_global) {
+ global = value;
+ } else {
+ local = value;
+ }
+ }
+
+private:
+ bool use_global = true;
+ Type global{};
+ Type local{};
+};
+
struct Values {
+ // Audio
+ std::string audio_device_id;
+ std::string sink_id;
+ bool audio_muted;
+ Setting<bool> enable_audio_stretching;
+ Setting<float> volume;
+
+ // Core
+ Setting<bool> use_multi_core;
+
+ // Cpu
+ CPUAccuracy cpu_accuracy;
+
+ bool cpuopt_page_tables;
+ bool cpuopt_block_linking;
+ bool cpuopt_return_stack_buffer;
+ bool cpuopt_fast_dispatcher;
+ bool cpuopt_context_elimination;
+ bool cpuopt_const_prop;
+ bool cpuopt_misc_ir;
+ bool cpuopt_reduce_misalign_checks;
+
+ // Renderer
+ Setting<RendererBackend> renderer_backend;
+ bool renderer_debug;
+ Setting<int> vulkan_device;
+
+ Setting<u16> resolution_factor = Setting(static_cast<u16>(1));
+ Setting<int> aspect_ratio;
+ Setting<int> max_anisotropy;
+ Setting<bool> use_frame_limit;
+ Setting<u16> frame_limit;
+ Setting<bool> use_disk_shader_cache;
+ Setting<GPUAccuracy> gpu_accuracy;
+ Setting<bool> use_asynchronous_gpu_emulation;
+ Setting<bool> use_vsync;
+ Setting<bool> use_assembly_shaders;
+ Setting<bool> force_30fps_mode;
+ Setting<bool> use_fast_gpu_time;
+
+ Setting<float> bg_red;
+ Setting<float> bg_green;
+ Setting<float> bg_blue;
+
// System
- bool use_docked_mode;
- std::optional<u32> rng_seed;
+ Setting<std::optional<u32>> rng_seed;
// Measured in seconds since epoch
- std::optional<std::chrono::seconds> custom_rtc;
+ Setting<std::optional<std::chrono::seconds>> custom_rtc;
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
std::chrono::seconds custom_rtc_differential;
s32 current_user;
- s32 language_index;
- s32 region_index;
- s32 time_zone_index;
- s32 sound_index;
+ Setting<s32> language_index;
+ Setting<s32> region_index;
+ Setting<s32> time_zone_index;
+ Setting<s32> sound_index;
// Controls
std::array<PlayerInput, 10> players;
@@ -419,51 +476,13 @@ struct Values {
u16 udp_input_port;
u8 udp_pad_index;
- // Core
- bool use_multi_core;
+ bool use_docked_mode;
// Data Storage
bool use_virtual_sd;
bool gamecard_inserted;
bool gamecard_current_game;
std::string gamecard_path;
- NANDTotalSize nand_total_size;
- NANDSystemSize nand_system_size;
- NANDUserSize nand_user_size;
- SDMCSize sdmc_size;
-
- // Renderer
- RendererBackend renderer_backend;
- bool renderer_debug;
- int vulkan_device;
-
- u16 resolution_factor{1};
- int aspect_ratio;
- int max_anisotropy;
- bool use_frame_limit;
- u16 frame_limit;
- bool use_disk_shader_cache;
- GPUAccuracy gpu_accuracy;
- bool use_asynchronous_gpu_emulation;
- bool use_vsync;
- bool use_assembly_shaders;
- bool force_30fps_mode;
- bool use_fast_gpu_time;
-
- float bg_red;
- float bg_green;
- float bg_blue;
-
- std::string log_filter;
-
- bool use_dev_keys;
-
- // Audio
- bool audio_muted;
- std::string sink_id;
- bool enable_audio_stretching;
- std::string audio_device_id;
- float volume;
// Debugging
bool record_frame_times;
@@ -474,10 +493,13 @@ struct Values {
bool dump_nso;
bool reporting_services;
bool quest_flag;
- bool disable_cpu_opt;
bool disable_macro_jit;
- // BCAT
+ // Misceallaneous
+ std::string log_filter;
+ bool use_dev_keys;
+
+ // Services
std::string bcat_backend;
bool bcat_boxcat_local;
@@ -501,4 +523,7 @@ std::string GetTimeZoneString();
void Apply();
void LogSettings();
+// Restore the global state of all applicable settings in the Values struct
+void RestoreGlobalState();
+
} // 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) {
// Log user configuration information
constexpr auto field_type = Telemetry::FieldType::UserConfig;
AddField(field_type, "Audio_SinkId", Settings::values.sink_id);
- AddField(field_type, "Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
- AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core);
- AddField(field_type, "Renderer_Backend", TranslateRenderer(Settings::values.renderer_backend));
- AddField(field_type, "Renderer_ResolutionFactor", Settings::values.resolution_factor);
- AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit);
- AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit);
- AddField(field_type, "Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache);
+ AddField(field_type, "Audio_EnableAudioStretching",
+ Settings::values.enable_audio_stretching.GetValue());
+ AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
+ AddField(field_type, "Renderer_Backend",
+ TranslateRenderer(Settings::values.renderer_backend.GetValue()));
+ AddField(field_type, "Renderer_ResolutionFactor",
+ Settings::values.resolution_factor.GetValue());
+ AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue());
+ AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit.GetValue());
+ AddField(field_type, "Renderer_UseDiskShaderCache",
+ Settings::values.use_disk_shader_cache.GetValue());
AddField(field_type, "Renderer_GPUAccuracyLevel",
- TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy));
+ TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue()));
AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
- Settings::values.use_asynchronous_gpu_emulation);
- AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync);
- AddField(field_type, "Renderer_UseAssemblyShaders", Settings::values.use_assembly_shaders);
+ Settings::values.use_asynchronous_gpu_emulation.GetValue());
+ AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
+ AddField(field_type, "Renderer_UseAssemblyShaders",
+ Settings::values.use_assembly_shaders.GetValue());
AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode);
}
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)
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
endif()
-target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES})
+target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR})
+target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES})
create_target_directory_groups(input_common)
target_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 @@
#include <chrono>
#include <thread>
+#include <libusb.h>
#include "common/logging/log.h"
#include "input_common/gcadapter/gc_adapter.h"
@@ -34,7 +35,7 @@ Adapter::Adapter() {
}
}
-GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) {
+GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) {
GCPadStatus pad = {};
ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4);
@@ -205,7 +206,7 @@ void Adapter::StartScanThread() {
}
detect_thread_running = true;
- detect_thread = std::thread([=] { ScanThreadFunc(); });
+ detect_thread = std::thread(&Adapter::ScanThreadFunc, this);
}
void Adapter::StopScanThread() {
@@ -234,7 +235,7 @@ void Adapter::Setup() {
}
if (devices != nullptr) {
- for (std::size_t index = 0; index < device_count; ++index) {
+ for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) {
if (CheckDeviceAccess(devices[index])) {
// GC Adapter found and accessible, registering it
GetGCEndpoint(devices[index]);
@@ -368,11 +369,11 @@ void Adapter::Reset() {
}
}
-bool Adapter::DeviceConnected(int port) {
+bool Adapter::DeviceConnected(std::size_t port) {
return adapter_controllers_status[port] != ControllerTypes::None;
}
-void Adapter::ResetDeviceType(int port) {
+void Adapter::ResetDeviceType(std::size_t port) {
adapter_controllers_status[port] = ControllerTypes::None;
}
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 @@
#include <mutex>
#include <thread>
#include <unordered_map>
-#include <libusb.h>
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
+struct libusb_context;
+struct libusb_device;
+struct libusb_device_handle;
+
namespace GCAdapter {
enum class PadButton {
@@ -91,6 +94,9 @@ public:
void BeginConfiguration();
void EndConfiguration();
+ /// Returns true if there is a device connected to port
+ bool DeviceConnected(std::size_t port);
+
std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
@@ -100,7 +106,7 @@ public:
int GetOriginValue(int port, int axis) const;
private:
- GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload);
+ GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload);
void PadToState(const GCPadStatus& pad, GCState& state);
@@ -112,11 +118,8 @@ private:
/// Stop scanning for the adapter
void StopScanThread();
- /// Returns true if there is a device connected to port
- bool DeviceConnected(int port);
-
/// Resets status of device connected to port
- void ResetDeviceType(int port);
+ void ResetDeviceType(std::size_t port);
/// Returns true if we successfully gain access to GC Adapter
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 @@
#include <list>
#include <mutex>
#include <utility>
+#include "common/assert.h"
#include "common/threadsafe_queue.h"
#include "input_common/gcadapter/gc_adapter.h"
#include "input_common/gcadapter/gc_poller.h"
@@ -20,7 +21,10 @@ public:
~GCButton() override;
bool GetStatus() const override {
- return gcadapter->GetPadState()[port].buttons.at(button);
+ if (gcadapter->DeviceConnected(port)) {
+ return gcadapter->GetPadState()[port].buttons.at(button);
+ }
+ return false;
}
private:
@@ -37,14 +41,17 @@ public:
gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {}
bool GetStatus() const override {
- const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis);
- const float axis_value = (current_axis_value - origin_value) / 128.0f;
- if (trigger_if_greater) {
- // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently
- // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
- return axis_value > threshold;
+ if (gcadapter->DeviceConnected(port)) {
+ const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis);
+ const float axis_value = (current_axis_value - origin_value) / 128.0f;
+ if (trigger_if_greater) {
+ // TODO: Might be worthwile to set a slider for the trigger threshold. It is
+ // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
+ return axis_value > threshold;
+ }
+ return axis_value < -threshold;
}
- return axis_value < -threshold;
+ return false;
}
private:
@@ -90,9 +97,12 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater,
adapter.get());
}
+
+ UNREACHABLE();
+ return nullptr;
}
-Common::ParamPackage GCButtonFactory::GetNextInput() {
+Common::ParamPackage GCButtonFactory::GetNextInput() const {
Common::ParamPackage params;
GCAdapter::GCPadStatus pad;
auto& queue = adapter->GetPadQueue();
@@ -145,12 +155,15 @@ public:
origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {}
float GetAxis(int axis) const {
- std::lock_guard lock{mutex};
- const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
- // division is not by a perfect 128 to account for some variance in center location
- // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
- // [20-230]
- return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
+ if (gcadapter->DeviceConnected(port)) {
+ std::lock_guard lock{mutex};
+ const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
+ // division is not by a perfect 128 to account for some variance in center location
+ // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
+ // [20-230]
+ return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
+ }
+ return 0.0f;
}
std::pair<float, float> GetAnalog(int axis_x, int axis_y) const {
@@ -250,7 +263,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
const u8 axis = static_cast<u8>(pad.axis);
if (analog_x_axis == -1) {
analog_x_axis = axis;
- controller_number = port;
+ controller_number = static_cast<int>(port);
} else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) {
analog_y_axis = axis;
}
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:
*/
std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override;
- Common::ParamPackage GetNextInput();
+ Common::ParamPackage GetNextInput() const;
/// For device input configuration/polling
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 @@
#include <memory>
#include <thread>
-#include <libusb.h>
#include "common/param_package.h"
#include "input_common/analog_from_button.h"
#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(
std::function<void(Status)> status_callback,
std::function<void(u16, u16, u16, u16)> data_callback) {
- std::thread([=] {
+ std::thread([=, this] {
constexpr u16 CALIBRATION_THRESHOLD = 100;
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:
}
if (is_written) {
map->MarkAsModified(true, GetModifiedTicks());
- if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) {
+ if (Settings::IsGPULevelHigh() &&
+ Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
MarkForAsyncFlush(map);
}
if (!map->is_written) {
@@ -369,7 +370,8 @@ private:
}
if (modified_inheritance) {
map->MarkAsModified(true, GetModifiedTicks());
- if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) {
+ if (Settings::IsGPULevelHigh() &&
+ Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
MarkForAsyncFlush(map);
}
}
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 {
constexpr u64 gpu_ticks_den = 625;
u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count();
- if (Settings::values.use_fast_gpu_time) {
+ if (Settings::values.use_fast_gpu_time.GetValue()) {
nanoseconds /= 256;
}
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:
}
query->BindCounter(Stream(type).Current(), timestamp);
- if (Settings::values.use_asynchronous_gpu_emulation) {
+ if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
AsyncFlushQuery(cpu_addr);
}
}
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;
void RendererBase::RefreshBaseSettings() {
UpdateCurrentFramebufferLayout();
- renderer_settings.use_framelimiter = Settings::values.use_frame_limit;
+ renderer_settings.use_framelimiter = Settings::values.use_frame_limit.GetValue();
renderer_settings.set_background_color = true;
}
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()
// uniform buffers as "push constants"
has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
- use_assembly_shaders = Settings::values.use_assembly_shaders && GLAD_GL_NV_gpu_program5 &&
- GLAD_GL_NV_compute_program5 && GLAD_GL_NV_transform_feedback &&
- GLAD_GL_NV_transform_feedback2;
+ use_assembly_shaders = Settings::values.use_assembly_shaders.GetValue() &&
+ GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
+ GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
- if (Settings::values.use_assembly_shaders && !use_assembly_shaders) {
+ if (Settings::values.use_assembly_shaders.GetValue() && !use_assembly_shaders) {
LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
}
}
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;
std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTransferable() {
// Skip games without title id
const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0;
- if (!Settings::values.use_disk_shader_cache || !has_title_id) {
+ if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) {
return {};
}
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
void RendererOpenGL::InitOpenGLObjects() {
frame_mailbox = std::make_unique<FrameMailbox>();
- glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
- 0.0f);
+ glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
+ Settings::values.bg_blue.GetValue(), 0.0f);
// Create shader programs
OGLShader vertex_shader;
@@ -561,8 +561,8 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
if (renderer_settings.set_background_color) {
// Update background color before drawing
- glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
- 0.0f);
+ glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
+ Settings::values.bg_blue.GetValue(), 0.0f);
}
// 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() {
return false;
}
- const s32 device_index = Settings::values.vulkan_device;
+ const s32 device_index = Settings::values.vulkan_device.GetValue();
if (device_index < 0 || device_index >= static_cast<s32>(devices->size())) {
LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
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:
if constexpr (has_extended_dynamic_state) {
// With extended dynamic states we can specify the length and stride of a vertex buffer
- // std::array<VkDeviceSize, N> sizes;
+ std::array<VkDeviceSize, N> sizes;
std::array<u16, N> strides;
- // std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin());
+ std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin());
std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin());
if constexpr (is_indexed) {
scheduler.Record(
- [buffers, offsets, strides, index = index](vk::CommandBuffer cmdbuf) {
+ [buffers, offsets, sizes, strides, index = index](vk::CommandBuffer cmdbuf) {
cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type);
cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
- offsets.data(), nullptr,
+ offsets.data(), sizes.data(),
ExpandStrides(strides).data());
});
} else {
- scheduler.Record([buffers, offsets, strides](vk::CommandBuffer cmdbuf) {
+ scheduler.Record([buffers, offsets, sizes, strides](vk::CommandBuffer cmdbuf) {
cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(),
- offsets.data(), nullptr,
+ offsets.data(), sizes.data(),
ExpandStrides(strides).data());
});
}
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) {
// Substract from the preferred heap size some bytes to avoid getting out of memory.
const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size;
- const VkDeviceSize allocable_size = heap_size - 4 * 1024 * 1024;
+ const VkDeviceSize allocable_size = heap_size - 9 * 1024 * 1024;
VkBufferCreateInfo buffer_ci;
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:
auto& surface = render_targets[index].target;
surface->MarkAsRenderTarget(false, NO_RT);
const auto& cr_params = surface->GetSurfaceParams();
- if (!cr_params.is_tiled && Settings::values.use_asynchronous_gpu_emulation) {
+ if (!cr_params.is_tiled && Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
AsyncFlushSurface(surface);
}
}
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 = {
};
unsigned SettingsMinimumAnisotropy() noexcept {
- switch (static_cast<Anisotropy>(Settings::values.max_anisotropy)) {
+ switch (static_cast<Anisotropy>(Settings::values.max_anisotropy.GetValue())) {
default:
case Anisotropy::Default:
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 {
std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window,
Core::System& system,
Core::Frontend::GraphicsContext& context) {
- switch (Settings::values.renderer_backend) {
+ switch (Settings::values.renderer_backend.GetValue()) {
case Settings::RendererBackend::OpenGL:
return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context);
#ifdef HAS_VULKAN
@@ -42,7 +42,7 @@ std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor
return nullptr;
}
- if (Settings::values.use_asynchronous_gpu_emulation) {
+ if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer),
std::move(context));
}
@@ -51,8 +51,8 @@ std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor
u16 GetResolutionScaleFactor(const RendererBase& renderer) {
return static_cast<u16>(
- Settings::values.resolution_factor != 0
- ? Settings::values.resolution_factor
+ Settings::values.resolution_factor.GetValue() != 0
+ ? Settings::values.resolution_factor.GetValue()
: renderer.GetRenderWindow().GetFramebufferLayout().GetScalingRatio());
}
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
compatibility_list.h
configuration/config.cpp
configuration/config.h
+ configuration/configuration_shared.cpp
+ configuration/configuration_shared.h
configuration/configure.ui
configuration/configure_audio.cpp
configuration/configure_audio.h
configuration/configure_audio.ui
+ configuration/configure_cpu.cpp
+ configuration/configure_cpu.h
+ configuration/configure_cpu.ui
+ configuration/configure_cpu_debug.cpp
+ configuration/configure_cpu_debug.h
+ configuration/configure_cpu_debug.ui
configuration/configure_debug.cpp
configuration/configure_debug.h
configuration/configure_debug.ui
@@ -60,9 +68,12 @@ add_executable(yuzu
configuration/configure_mouse_advanced.cpp
configuration/configure_mouse_advanced.h
configuration/configure_mouse_advanced.ui
- configuration/configure_per_general.cpp
- configuration/configure_per_general.h
- configuration/configure_per_general.ui
+ configuration/configure_per_game.cpp
+ configuration/configure_per_game.h
+ configuration/configure_per_game.ui
+ configuration/configure_per_game_addons.cpp
+ configuration/configure_per_game_addons.h
+ configuration/configure_per_game_addons.ui
configuration/configure_profile_manager.cpp
configuration/configure_profile_manager.h
configuration/configure_profile_manager.ui
@@ -93,11 +104,13 @@ add_executable(yuzu
game_list_p.h
game_list_worker.cpp
game_list_worker.h
+ hotkeys.cpp
+ hotkeys.h
+ install_dialog.cpp
+ install_dialog.h
loading_screen.cpp
loading_screen.h
loading_screen.ui
- hotkeys.cpp
- hotkeys.h
main.cpp
main.h
main.ui
@@ -147,7 +160,7 @@ endif()
create_target_directory_groups(yuzu)
target_link_libraries(yuzu PRIVATE common core input_common video_core)
-target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets)
+target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::Widgets)
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (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:
// disable vsync for any shared contexts
auto format = share_context->format();
- format.setSwapInterval(main_surface ? Settings::values.use_vsync : 0);
+ format.setSwapInterval(main_surface ? Settings::values.use_vsync.GetValue() : 0);
context = std::make_unique<QOpenGLContext>();
context->setShareContext(share_context);
@@ -495,7 +495,7 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
#ifdef HAS_OPENGL
- if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
+ if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL) {
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
// Bind the shared contexts to the main surface in case the backend wants to take over
// presentation
@@ -511,7 +511,7 @@ bool GRenderWindow::InitRenderTarget() {
first_frame = false;
- switch (Settings::values.renderer_backend) {
+ switch (Settings::values.renderer_backend.GetValue()) {
case Settings::RendererBackend::OpenGL:
if (!InitializeOpenGL()) {
return false;
@@ -538,7 +538,7 @@ bool GRenderWindow::InitRenderTarget() {
OnFramebufferSizeChanged();
BackupGeometry();
- if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
+ if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL) {
if (!LoadOpenGL()) {
return false;
}
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 @@
#include "input_common/udp/client.h"
#include "yuzu/configuration/config.h"
-Config::Config() {
+Config::Config(const std::string& config_file, bool is_global) {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
- qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini";
+ qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + config_file;
FileUtil::CreateFullPath(qt_config_loc);
qt_config =
std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
+ global = is_global;
Reload();
}
Config::~Config() {
- Save();
+ if (global) {
+ Save();
+ }
}
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
@@ -402,16 +405,19 @@ void Config::ApplyDefaultProfileIfInputInvalid() {
void Config::ReadAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
- Settings::values.sink_id = ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto"))
- .toString()
- .toStdString();
- Settings::values.enable_audio_stretching =
- ReadSetting(QStringLiteral("enable_audio_stretching"), true).toBool();
- Settings::values.audio_device_id =
- ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
- .toString()
- .toStdString();
- Settings::values.volume = ReadSetting(QStringLiteral("volume"), 1).toFloat();
+ if (global) {
+ Settings::values.sink_id =
+ ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto"))
+ .toString()
+ .toStdString();
+ Settings::values.audio_device_id =
+ ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
+ .toString()
+ .toStdString();
+ }
+ ReadSettingGlobal(Settings::values.enable_audio_stretching,
+ QStringLiteral("enable_audio_stretching"), true);
+ ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"), 1);
qt_config->endGroup();
}
@@ -440,6 +446,8 @@ void Config::ReadControlValues() {
.toInt());
Settings::values.udp_pad_index =
static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt());
+ Settings::values.use_docked_mode =
+ ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
qt_config->endGroup();
}
@@ -447,7 +455,7 @@ void Config::ReadControlValues() {
void Config::ReadCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- Settings::values.use_multi_core = ReadSetting(QStringLiteral("use_multi_core"), false).toBool();
+ ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), false);
qt_config->endGroup();
}
@@ -497,22 +505,6 @@ void Config::ReadDataStorageValues() {
ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
Settings::values.gamecard_path =
ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString();
- Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
- ReadSetting(QStringLiteral("nand_total_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)))
- .toULongLong());
- Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
- ReadSetting(QStringLiteral("nand_user_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)))
- .toULongLong());
- Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
- ReadSetting(QStringLiteral("nand_system_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)))
- .toULongLong());
- Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
- ReadSetting(QStringLiteral("sdmc_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)))
- .toULongLong());
qt_config->endGroup();
}
@@ -532,8 +524,6 @@ void Config::ReadDebuggingValues() {
Settings::values.reporting_services =
ReadSetting(QStringLiteral("reporting_services"), false).toBool();
Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool();
- Settings::values.disable_cpu_opt =
- ReadSetting(QStringLiteral("disable_cpu_opt"), false).toBool();
Settings::values.disable_macro_jit =
ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
@@ -625,35 +615,59 @@ void Config::ReadPathValues() {
qt_config->endGroup();
}
+void Config::ReadCpuValues() {
+ qt_config->beginGroup(QStringLiteral("Cpu"));
+
+ if (global) {
+ Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>(
+ ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt());
+
+ Settings::values.cpuopt_page_tables =
+ ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
+ Settings::values.cpuopt_block_linking =
+ ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool();
+ Settings::values.cpuopt_return_stack_buffer =
+ ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool();
+ Settings::values.cpuopt_fast_dispatcher =
+ ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool();
+ Settings::values.cpuopt_context_elimination =
+ ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool();
+ Settings::values.cpuopt_const_prop =
+ ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool();
+ Settings::values.cpuopt_misc_ir =
+ ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
+ Settings::values.cpuopt_reduce_misalign_checks =
+ ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
+ }
+
+ qt_config->endGroup();
+}
+
void Config::ReadRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
- Settings::values.renderer_backend =
- static_cast<Settings::RendererBackend>(ReadSetting(QStringLiteral("backend"), 0).toInt());
- Settings::values.renderer_debug = ReadSetting(QStringLiteral("debug"), false).toBool();
- Settings::values.vulkan_device = ReadSetting(QStringLiteral("vulkan_device"), 0).toInt();
- Settings::values.aspect_ratio = ReadSetting(QStringLiteral("aspect_ratio"), 0).toInt();
- Settings::values.max_anisotropy = ReadSetting(QStringLiteral("max_anisotropy"), 0).toInt();
- Settings::values.use_frame_limit =
- ReadSetting(QStringLiteral("use_frame_limit"), true).toBool();
- Settings::values.frame_limit = ReadSetting(QStringLiteral("frame_limit"), 100).toUInt();
- Settings::values.use_disk_shader_cache =
- ReadSetting(QStringLiteral("use_disk_shader_cache"), true).toBool();
- const int gpu_accuracy_level = ReadSetting(QStringLiteral("gpu_accuracy"), 0).toInt();
- Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(gpu_accuracy_level);
- Settings::values.use_asynchronous_gpu_emulation =
- ReadSetting(QStringLiteral("use_asynchronous_gpu_emulation"), false).toBool();
- Settings::values.use_vsync = ReadSetting(QStringLiteral("use_vsync"), true).toBool();
- Settings::values.use_assembly_shaders =
- ReadSetting(QStringLiteral("use_assembly_shaders"), false).toBool();
- Settings::values.use_fast_gpu_time =
- ReadSetting(QStringLiteral("use_fast_gpu_time"), true).toBool();
- Settings::values.force_30fps_mode =
- ReadSetting(QStringLiteral("force_30fps_mode"), false).toBool();
-
- Settings::values.bg_red = ReadSetting(QStringLiteral("bg_red"), 0.0).toFloat();
- Settings::values.bg_green = ReadSetting(QStringLiteral("bg_green"), 0.0).toFloat();
- Settings::values.bg_blue = ReadSetting(QStringLiteral("bg_blue"), 0.0).toFloat();
+ ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
+ ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
+ ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
+ ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
+ ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
+ ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
+ ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"), 100);
+ ReadSettingGlobal(Settings::values.use_disk_shader_cache,
+ QStringLiteral("use_disk_shader_cache"), true);
+ ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"), 0);
+ ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation,
+ QStringLiteral("use_asynchronous_gpu_emulation"), false);
+ ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true);
+ ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
+ false);
+ ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
+ true);
+ ReadSettingGlobal(Settings::values.force_30fps_mode, QStringLiteral("force_30fps_mode"), false);
+
+ ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0);
+ ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0);
+ ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0);
qt_config->endGroup();
}
@@ -682,35 +696,45 @@ void Config::ReadShortcutValues() {
void Config::ReadSystemValues() {
qt_config->beginGroup(QStringLiteral("System"));
- Settings::values.use_docked_mode =
- ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
-
- Settings::values.current_user = std::clamp<int>(
- ReadSetting(QStringLiteral("current_user"), 0).toInt(), 0, Service::Account::MAX_USERS - 1);
+ ReadSettingGlobal(Settings::values.current_user, QStringLiteral("current_user"), 0);
+ Settings::values.current_user =
+ std::clamp<int>(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1);
- Settings::values.language_index = ReadSetting(QStringLiteral("language_index"), 1).toInt();
+ ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"), 1);
- Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt();
+ ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"), 1);
- Settings::values.time_zone_index = ReadSetting(QStringLiteral("time_zone_index"), 0).toInt();
+ ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"), 0);
- const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool();
- if (rng_seed_enabled) {
- Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong();
- } else {
- Settings::values.rng_seed = std::nullopt;
+ bool rng_seed_enabled;
+ ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
+ bool rng_seed_global =
+ global || qt_config->value(QStringLiteral("rng_seed/use_global"), true).toBool();
+ Settings::values.rng_seed.SetGlobal(rng_seed_global);
+ if (global || !rng_seed_global) {
+ if (rng_seed_enabled) {
+ Settings::values.rng_seed.SetValue(
+ ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong());
+ } else {
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ }
}
- const auto custom_rtc_enabled =
- ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool();
- if (custom_rtc_enabled) {
- Settings::values.custom_rtc =
- std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong());
- } else {
- Settings::values.custom_rtc = std::nullopt;
+ bool custom_rtc_enabled;
+ ReadSettingGlobal(custom_rtc_enabled, QStringLiteral("custom_rtc_enabled"), false);
+ bool custom_rtc_global =
+ global || qt_config->value(QStringLiteral("custom_rtc/use_global"), true).toBool();
+ Settings::values.custom_rtc.SetGlobal(custom_rtc_global);
+ if (global || !custom_rtc_global) {
+ if (custom_rtc_enabled) {
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong()));
+ } else {
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ }
}
- Settings::values.sound_index = ReadSetting(QStringLiteral("sound_index"), 1).toInt();
+ ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"), 1);
qt_config->endGroup();
}
@@ -804,18 +828,21 @@ void Config::ReadWebServiceValues() {
}
void Config::ReadValues() {
- ReadControlValues();
+ if (global) {
+ ReadControlValues();
+ ReadDataStorageValues();
+ ReadDebuggingValues();
+ ReadDisabledAddOnValues();
+ ReadServiceValues();
+ ReadUIValues();
+ ReadWebServiceValues();
+ ReadMiscellaneousValues();
+ }
ReadCoreValues();
+ ReadCpuValues();
ReadRendererValues();
ReadAudioValues();
- ReadDataStorageValues();
ReadSystemValues();
- ReadMiscellaneousValues();
- ReadDebuggingValues();
- ReadWebServiceValues();
- ReadServiceValues();
- ReadDisabledAddOnValues();
- ReadUIValues();
}
void Config::SavePlayerValues() {
@@ -902,30 +929,36 @@ void Config::SaveTouchscreenValues() {
}
void Config::SaveValues() {
- SaveControlValues();
+ if (global) {
+ SaveControlValues();
+ SaveDataStorageValues();
+ SaveDebuggingValues();
+ SaveDisabledAddOnValues();
+ SaveServiceValues();
+ SaveUIValues();
+ SaveWebServiceValues();
+ SaveMiscellaneousValues();
+ }
SaveCoreValues();
+ SaveCpuValues();
SaveRendererValues();
SaveAudioValues();
- SaveDataStorageValues();
SaveSystemValues();
- SaveMiscellaneousValues();
- SaveDebuggingValues();
- SaveWebServiceValues();
- SaveServiceValues();
- SaveDisabledAddOnValues();
- SaveUIValues();
}
void Config::SaveAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
- WriteSetting(QStringLiteral("output_engine"), QString::fromStdString(Settings::values.sink_id),
- QStringLiteral("auto"));
- WriteSetting(QStringLiteral("enable_audio_stretching"),
- Settings::values.enable_audio_stretching, true);
- WriteSetting(QStringLiteral("output_device"),
- QString::fromStdString(Settings::values.audio_device_id), QStringLiteral("auto"));
- WriteSetting(QStringLiteral("volume"), Settings::values.volume, 1.0f);
+ if (global) {
+ WriteSetting(QStringLiteral("output_engine"),
+ QString::fromStdString(Settings::values.sink_id), QStringLiteral("auto"));
+ WriteSetting(QStringLiteral("output_device"),
+ QString::fromStdString(Settings::values.audio_device_id),
+ QStringLiteral("auto"));
+ }
+ WriteSettingGlobal(QStringLiteral("enable_audio_stretching"),
+ Settings::values.enable_audio_stretching, true);
+ WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume, 1.0f);
qt_config->endGroup();
}
@@ -948,6 +981,7 @@ void Config::SaveControlValues() {
WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
InputCommon::CemuhookUDP::DEFAULT_PORT);
WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
+ WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
qt_config->endGroup();
}
@@ -955,7 +989,7 @@ void Config::SaveControlValues() {
void Config::SaveCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- WriteSetting(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, false);
+ WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, false);
qt_config->endGroup();
}
@@ -984,18 +1018,7 @@ void Config::SaveDataStorageValues() {
false);
WriteSetting(QStringLiteral("gamecard_path"),
QString::fromStdString(Settings::values.gamecard_path), QStringLiteral(""));
- WriteSetting(QStringLiteral("nand_total_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)));
- WriteSetting(QStringLiteral("nand_user_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)));
- WriteSetting(QStringLiteral("nand_system_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)));
- WriteSetting(QStringLiteral("sdmc_size"),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)),
- QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)));
+
qt_config->endGroup();
}
@@ -1011,7 +1034,6 @@ void Config::SaveDebuggingValues() {
WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
- WriteSetting(QStringLiteral("disable_cpu_opt"), Settings::values.disable_cpu_opt, false);
WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false);
qt_config->endGroup();
@@ -1075,32 +1097,63 @@ void Config::SavePathValues() {
qt_config->endGroup();
}
+void Config::SaveCpuValues() {
+ qt_config->beginGroup(QStringLiteral("Cpu"));
+
+ if (global) {
+ WriteSetting(QStringLiteral("cpu_accuracy"),
+ static_cast<int>(Settings::values.cpu_accuracy), 0);
+
+ WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
+ true);
+ WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
+ true);
+ WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"),
+ Settings::values.cpuopt_return_stack_buffer, true);
+ WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"),
+ Settings::values.cpuopt_fast_dispatcher, true);
+ WriteSetting(QStringLiteral("cpuopt_context_elimination"),
+ Settings::values.cpuopt_context_elimination, true);
+ WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true);
+ WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
+ WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
+ Settings::values.cpuopt_reduce_misalign_checks, true);
+ }
+
+ qt_config->endGroup();
+}
+
void Config::SaveRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
- WriteSetting(QStringLiteral("backend"), static_cast<int>(Settings::values.renderer_backend), 0);
+ WriteSettingGlobal(QStringLiteral("backend"),
+ static_cast<int>(Settings::values.renderer_backend.GetValue(global)),
+ Settings::values.renderer_backend.UsingGlobal(), 0);
WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
- WriteSetting(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
- WriteSetting(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
- WriteSetting(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
- WriteSetting(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
- WriteSetting(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100);
- WriteSetting(QStringLiteral("use_disk_shader_cache"), Settings::values.use_disk_shader_cache,
- true);
- WriteSetting(QStringLiteral("gpu_accuracy"), static_cast<int>(Settings::values.gpu_accuracy),
- 0);
- WriteSetting(QStringLiteral("use_asynchronous_gpu_emulation"),
- Settings::values.use_asynchronous_gpu_emulation, false);
- WriteSetting(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
- WriteSetting(QStringLiteral("use_assembly_shaders"), Settings::values.use_assembly_shaders,
- false);
- WriteSetting(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time, true);
- WriteSetting(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode, false);
+ WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
+ WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
+ WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
+ WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
+ WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100);
+ WriteSettingGlobal(QStringLiteral("use_disk_shader_cache"),
+ Settings::values.use_disk_shader_cache, true);
+ WriteSettingGlobal(QStringLiteral("gpu_accuracy"),
+ static_cast<int>(Settings::values.gpu_accuracy.GetValue(global)),
+ Settings::values.gpu_accuracy.UsingGlobal(), 0);
+ WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"),
+ Settings::values.use_asynchronous_gpu_emulation, false);
+ WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
+ WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
+ Settings::values.use_assembly_shaders, false);
+ WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
+ true);
+ WriteSettingGlobal(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode,
+ false);
// Cast to double because Qt's written float values are not human-readable
- WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0);
- WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0);
- WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0);
+ WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0);
+ WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0);
+ WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue, 0.0);
qt_config->endGroup();
}
@@ -1128,23 +1181,28 @@ void Config::SaveShortcutValues() {
void Config::SaveSystemValues() {
qt_config->beginGroup(QStringLiteral("System"));
- WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0);
- WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1);
- WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1);
- WriteSetting(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
-
- WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false);
- WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0);
-
- WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
- false);
- WriteSetting(QStringLiteral("custom_rtc"),
- QVariant::fromValue<long long>(
- Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()),
- 0);
-
- WriteSetting(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
+ WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index, 1);
+ WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index, 1);
+ WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
+
+ WriteSettingGlobal(QStringLiteral("rng_seed_enabled"),
+ Settings::values.rng_seed.GetValue(global).has_value(),
+ Settings::values.rng_seed.UsingGlobal(), false);
+ WriteSettingGlobal(QStringLiteral("rng_seed"),
+ Settings::values.rng_seed.GetValue(global).value_or(0),
+ Settings::values.rng_seed.UsingGlobal(), 0);
+
+ WriteSettingGlobal(QStringLiteral("custom_rtc_enabled"),
+ Settings::values.custom_rtc.GetValue(global).has_value(),
+ Settings::values.custom_rtc.UsingGlobal(), false);
+ WriteSettingGlobal(
+ QStringLiteral("custom_rtc"),
+ QVariant::fromValue<long long>(
+ Settings::values.custom_rtc.GetValue(global).value_or(std::chrono::seconds{}).count()),
+ Settings::values.custom_rtc.UsingGlobal(), 0);
+
+ WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
qt_config->endGroup();
}
@@ -1236,6 +1294,34 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
return result;
}
+template <typename Type>
+void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name) {
+ const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
+ setting.SetGlobal(use_global);
+ if (global || !use_global) {
+ setting.SetValue(ReadSetting(name).value<Type>());
+ }
+}
+
+template <typename Type>
+void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
+ const QVariant& default_value) {
+ const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
+ setting.SetGlobal(use_global);
+ if (global || !use_global) {
+ setting.SetValue(ReadSetting(name, default_value).value<Type>());
+ }
+}
+
+template <typename Type>
+void Config::ReadSettingGlobal(Type& setting, const QString& name,
+ const QVariant& default_value) const {
+ const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
+ if (global || !use_global) {
+ setting = ReadSetting(name, default_value).value<Type>();
+ }
+}
+
void Config::WriteSetting(const QString& name, const QVariant& value) {
qt_config->setValue(name, value);
}
@@ -1246,6 +1332,40 @@ void Config::WriteSetting(const QString& name, const QVariant& value,
qt_config->setValue(name, value);
}
+template <typename Type>
+void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting) {
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+ }
+ if (global || !setting.UsingGlobal()) {
+ qt_config->setValue(name, setting.GetValue(global));
+ }
+}
+
+template <typename Type>
+void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
+ const QVariant& default_value) {
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+ }
+ if (global || !setting.UsingGlobal()) {
+ qt_config->setValue(name + QStringLiteral("/default"),
+ setting.GetValue(global) == default_value.value<Type>());
+ qt_config->setValue(name, setting.GetValue(global));
+ }
+}
+
+void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
+ const QVariant& default_value) {
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), use_global);
+ }
+ if (global || !use_global) {
+ qt_config->setValue(name + QStringLiteral("/default"), value == default_value);
+ qt_config->setValue(name, value);
+ }
+}
+
void Config::Reload() {
ReadValues();
// 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 @@
#include <array>
#include <memory>
#include <string>
+#include <QMetaType>
#include <QVariant>
#include "core/settings.h"
#include "yuzu/uisettings.h"
@@ -15,7 +16,7 @@ class QSettings;
class Config {
public:
- Config();
+ explicit Config(const std::string& config_loc = "qt-config.ini", bool is_global = true);
~Config();
void Reload();
@@ -48,6 +49,7 @@ private:
void ReadDisabledAddOnValues();
void ReadMiscellaneousValues();
void ReadPathValues();
+ void ReadCpuValues();
void ReadRendererValues();
void ReadShortcutValues();
void ReadSystemValues();
@@ -72,6 +74,7 @@ private:
void SaveDisabledAddOnValues();
void SaveMiscellaneousValues();
void SavePathValues();
+ void SaveCpuValues();
void SaveRendererValues();
void SaveShortcutValues();
void SaveSystemValues();
@@ -82,9 +85,33 @@ private:
QVariant ReadSetting(const QString& name) const;
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
+ // Templated ReadSettingGlobal functions will also look for the use_global setting and set
+ // both the value and the global state properly
+ template <typename Type>
+ void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name);
+ template <typename Type>
+ void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
+ const QVariant& default_value);
+ template <typename Type>
+ void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
+ // Templated WriteSettingGlobal functions will also write the global state if needed and will
+ // skip writing the actual setting if it defers to the global value
void WriteSetting(const QString& name, const QVariant& value);
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
+ template <typename Type>
+ void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting);
+ template <typename Type>
+ void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
+ const QVariant& default_value);
+ void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
+ const QVariant& default_value);
std::unique_ptr<QSettings> qt_config;
std::string qt_config_loc;
+
+ bool global;
};
+
+// These metatype declarations cannot be in core/settings.h because core is devoid of QT
+Q_DECLARE_METATYPE(Settings::RendererBackend);
+Q_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 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QCheckBox>
+#include <QComboBox>
+#include "core/settings.h"
+#include "yuzu/configuration/configuration_shared.h"
+#include "yuzu/configuration/configure_per_game.h"
+
+void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
+ const QCheckBox* checkbox) {
+ if (checkbox->checkState() == Qt::PartiallyChecked) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(checkbox->checkState() == Qt::Checked);
+ }
+}
+
+void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting,
+ const QComboBox* combobox) {
+ if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
+ }
+}
+
+void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
+ const QComboBox* combobox) {
+ if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(static_cast<Settings::RendererBackend>(
+ combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
+ }
+}
+
+void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
+ const Settings::Setting<bool>* setting) {
+ if (setting->UsingGlobal()) {
+ checkbox->setCheckState(Qt::PartiallyChecked);
+ } else {
+ checkbox->setCheckState(setting->GetValue() ? Qt::Checked : Qt::Unchecked);
+ }
+}
+
+void ConfigurationShared::SetPerGameSetting(QComboBox* combobox,
+ const Settings::Setting<int>* setting) {
+ combobox->setCurrentIndex(setting->UsingGlobal()
+ ? ConfigurationShared::USE_GLOBAL_INDEX
+ : setting->GetValue() + ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigurationShared::SetPerGameSetting(
+ QComboBox* combobox, const Settings::Setting<Settings::RendererBackend>* setting) {
+ combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
+ : static_cast<int>(setting->GetValue()) +
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigurationShared::SetPerGameSetting(
+ QComboBox* combobox, const Settings::Setting<Settings::GPUAccuracy>* setting) {
+ combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
+ : static_cast<int>(setting->GetValue()) +
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigurationShared::InsertGlobalItem(QComboBox* combobox) {
+ const QString use_global_text = ConfigurePerGame::tr("Use global configuration");
+ combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text);
+ combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX);
+}
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 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QString>
+#include "core/settings.h"
+
+namespace ConfigurationShared {
+
+constexpr int USE_GLOBAL_INDEX = 0;
+constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
+constexpr int USE_GLOBAL_OFFSET = 2;
+
+// Global-aware apply and set functions
+
+void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox);
+void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox);
+void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
+ const QComboBox* combobox);
+void ApplyPerGameSetting(Settings::Setting<Settings::GPUAccuracy>* setting,
+ const QComboBox* combobox);
+
+void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
+void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<int>* setting);
+void SetPerGameSetting(QComboBox* combobox,
+ const Settings::Setting<Settings::RendererBackend>* setting);
+void SetPerGameSetting(QComboBox* combobox,
+ const Settings::Setting<Settings::GPUAccuracy>* setting);
+
+void InsertGlobalItem(QComboBox* combobox);
+
+} // 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 @@
<string>Hotkeys</string>
</attribute>
</widget>
+ <widget class="ConfigureCpu" name="cpuTab">
+ <attribute name="title">
+ <string>CPU</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureCpuDebug" name="cpuDebugTab">
+ <attribute name="title">
+ <string>Debug</string>
+ </attribute>
+ </widget>
<widget class="ConfigureGraphics" name="graphicsTab">
<attribute name="title">
<string>Graphics</string>
@@ -159,6 +169,18 @@
<container>1</container>
</customwidget>
<customwidget>
+ <class>ConfigureCpu</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_cpu.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureCpuDebug</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_cpu_debug.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
<class>ConfigureGraphics</class>
<extends>QWidget</extends>
<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 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_audio.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_audio.h"
ConfigureAudio::ConfigureAudio(QWidget* parent)
@@ -24,6 +25,11 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::UpdateAudioDevices);
+ ui->volume_label->setVisible(Settings::configuring_global);
+ ui->volume_combo_box->setVisible(!Settings::configuring_global);
+
+ SetupPerGameUI();
+
SetConfiguration();
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
@@ -41,8 +47,22 @@ void ConfigureAudio::SetConfiguration() {
SetAudioDeviceFromDeviceID();
- ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
- ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
+ ui->volume_slider->setValue(Settings::values.volume.GetValue() * ui->volume_slider->maximum());
+
+ if (Settings::configuring_global) {
+ ui->toggle_audio_stretching->setChecked(
+ Settings::values.enable_audio_stretching.GetValue());
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->toggle_audio_stretching,
+ &Settings::values.enable_audio_stretching);
+ if (Settings::values.volume.UsingGlobal()) {
+ ui->volume_combo_box->setCurrentIndex(0);
+ ui->volume_slider->setEnabled(false);
+ } else {
+ ui->volume_combo_box->setCurrentIndex(1);
+ ui->volume_slider->setEnabled(true);
+ }
+ }
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
@@ -80,15 +100,36 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
}
void ConfigureAudio::ApplyConfiguration() {
- Settings::values.sink_id =
- ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
- .toStdString();
- Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
- Settings::values.audio_device_id =
- ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
- .toStdString();
- Settings::values.volume =
- static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
+ if (Settings::configuring_global) {
+ Settings::values.sink_id =
+ ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
+ .toStdString();
+ Settings::values.audio_device_id =
+ ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
+ .toStdString();
+
+ // Guard if during game and set to game-specific value
+ if (Settings::values.enable_audio_stretching.UsingGlobal()) {
+ Settings::values.enable_audio_stretching.SetValue(
+ ui->toggle_audio_stretching->isChecked());
+ }
+ if (Settings::values.volume.UsingGlobal()) {
+ Settings::values.volume.SetValue(
+ static_cast<float>(ui->volume_slider->sliderPosition()) /
+ ui->volume_slider->maximum());
+ }
+ } else {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
+ ui->toggle_audio_stretching);
+ if (ui->volume_combo_box->currentIndex() == 0) {
+ Settings::values.volume.SetGlobal(true);
+ } else {
+ Settings::values.volume.SetGlobal(false);
+ Settings::values.volume.SetValue(
+ static_cast<float>(ui->volume_slider->sliderPosition()) /
+ ui->volume_slider->maximum());
+ }
+ }
}
void ConfigureAudio::changeEvent(QEvent* event) {
@@ -122,3 +163,22 @@ void ConfigureAudio::RetranslateUI() {
ui->retranslateUi(this);
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
+
+void ConfigureAudio::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal());
+ ui->toggle_audio_stretching->setEnabled(
+ Settings::values.enable_audio_stretching.UsingGlobal());
+
+ return;
+ }
+
+ ui->toggle_audio_stretching->setTristate(true);
+ connect(ui->volume_combo_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
+ this, [this](int index) { ui->volume_slider->setEnabled(index == 1); });
+
+ ui->output_sink_combo_box->setVisible(false);
+ ui->output_sink_label->setVisible(false);
+ ui->audio_device_combo_box->setVisible(false);
+ ui->audio_device_label->setVisible(false);
+}
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:
void SetAudioDeviceFromDeviceID();
void SetVolumeIndicatorText(int percentage);
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureAudio> ui;
};
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 @@
<rect>
<x>0</x>
<y>0</y>
- <width>188</width>
- <height>246</height>
+ <width>367</width>
+ <height>368</height>
</rect>
</property>
<layout class="QVBoxLayout">
@@ -18,9 +18,9 @@
</property>
<layout class="QVBoxLayout">
<item>
- <layout class="QHBoxLayout">
+ <layout class="QHBoxLayout" name="_3">
<item>
- <widget class="QLabel" name="label_1">
+ <widget class="QLabel" name="output_sink_label">
<property name="text">
<string>Output Engine:</string>
</property>
@@ -31,20 +31,20 @@
</item>
</layout>
</item>
- <item>
- <widget class="QCheckBox" name="toggle_audio_stretching">
- <property name="toolTip">
- <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
- </property>
- <property name="text">
- <string>Enable audio stretching</string>
- </property>
- </widget>
- </item>
<item>
- <layout class="QHBoxLayout">
+ <widget class="QCheckBox" name="toggle_audio_stretching">
+ <property name="toolTip">
+ <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
+ </property>
+ <property name="text">
+ <string>Enable audio stretching</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="_2">
<item>
- <widget class="QLabel" name="label_2">
+ <widget class="QLabel" name="audio_device_label">
<property name="text">
<string>Audio Device:</string>
</property>
@@ -61,7 +61,21 @@
<number>0</number>
</property>
<item>
- <widget class="QLabel" name="label_3">
+ <widget class="QComboBox" name="volume_combo_box">
+ <item>
+ <property name="text">
+ <string>Use global volume</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Set volume:</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="volume_label">
<property name="text">
<string>Volume:</string>
</property>
@@ -74,7 +88,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>40</width>
+ <width>30</width>
<height>20</height>
</size>
</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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QComboBox>
+#include <QMessageBox>
+
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/settings.h"
+#include "ui_configure_cpu.h"
+#include "yuzu/configuration/configure_cpu.h"
+
+ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) {
+ ui->setupUi(this);
+
+ SetConfiguration();
+
+ connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
+ &ConfigureCpu::AccuracyUpdated);
+}
+
+ConfigureCpu::~ConfigureCpu() = default;
+
+void ConfigureCpu::SetConfiguration() {
+ const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
+
+ ui->accuracy->setEnabled(runtime_lock);
+ ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
+}
+
+void ConfigureCpu::AccuracyUpdated(int index) {
+ if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
+ const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
+ tr("CPU Debug Mode is only intended for developer "
+ "use. Are you sure you want to enable this?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (result == QMessageBox::No) {
+ ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate));
+ return;
+ }
+ }
+}
+
+void ConfigureCpu::ApplyConfiguration() {
+ Settings::values.cpu_accuracy =
+ static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex());
+}
+
+void ConfigureCpu::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QWidget::changeEvent(event);
+}
+
+void ConfigureCpu::RetranslateUI() {
+ ui->retranslateUi(this);
+}
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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QWidget>
+#include "core/settings.h"
+
+namespace Ui {
+class ConfigureCpu;
+}
+
+class ConfigureCpu : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureCpu(QWidget* parent = nullptr);
+ ~ConfigureCpu() override;
+
+ void ApplyConfiguration();
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+
+ void AccuracyUpdated(int index);
+
+ void SetConfiguration();
+
+ std::unique_ptr<Ui::ConfigureCpu> ui;
+};
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureCpu</class>
+ <widget class="QWidget" name="ConfigureCpu">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>321</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox">
+ <property name="title">
+ <string>General</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QHBoxLayout">
+ <item>
+ <widget class="QLabel">
+ <property name="text">
+ <string>Accuracy:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="accuracy">
+ <item>
+ <property name="text">
+ <string>Accurate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Enable Debug Mode</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel">
+ <property name="wordWrap">
+ <bool>1</bool>
+ </property>
+ <property name="text">
+ <string>We recommend setting accuracy to "Accurate".</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_disable_info">
+ <property name="text">
+ <string>CPU settings are available only when game is not running.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QComboBox>
+
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/settings.h"
+#include "ui_configure_cpu_debug.h"
+#include "yuzu/configuration/configure_cpu_debug.h"
+
+ConfigureCpuDebug::ConfigureCpuDebug(QWidget* parent)
+ : QWidget(parent), ui(new Ui::ConfigureCpuDebug) {
+ ui->setupUi(this);
+
+ SetConfiguration();
+}
+
+ConfigureCpuDebug::~ConfigureCpuDebug() = default;
+
+void ConfigureCpuDebug::SetConfiguration() {
+ const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
+
+ ui->cpuopt_page_tables->setEnabled(runtime_lock);
+ ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables);
+ ui->cpuopt_block_linking->setEnabled(runtime_lock);
+ ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking);
+ ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock);
+ ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer);
+ ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock);
+ ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher);
+ ui->cpuopt_context_elimination->setEnabled(runtime_lock);
+ ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination);
+ ui->cpuopt_const_prop->setEnabled(runtime_lock);
+ ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop);
+ ui->cpuopt_misc_ir->setEnabled(runtime_lock);
+ ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir);
+ ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
+ ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks);
+}
+
+void ConfigureCpuDebug::ApplyConfiguration() {
+ Settings::values.cpuopt_page_tables = ui->cpuopt_page_tables->isChecked();
+ Settings::values.cpuopt_block_linking = ui->cpuopt_block_linking->isChecked();
+ Settings::values.cpuopt_return_stack_buffer = ui->cpuopt_return_stack_buffer->isChecked();
+ Settings::values.cpuopt_fast_dispatcher = ui->cpuopt_fast_dispatcher->isChecked();
+ Settings::values.cpuopt_context_elimination = ui->cpuopt_context_elimination->isChecked();
+ Settings::values.cpuopt_const_prop = ui->cpuopt_const_prop->isChecked();
+ Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked();
+ Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked();
+}
+
+void ConfigureCpuDebug::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QWidget::changeEvent(event);
+}
+
+void ConfigureCpuDebug::RetranslateUI() {
+ ui->retranslateUi(this);
+}
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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QWidget>
+#include "core/settings.h"
+
+namespace Ui {
+class ConfigureCpuDebug;
+}
+
+class ConfigureCpuDebug : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureCpuDebug(QWidget* parent = nullptr);
+ ~ConfigureCpuDebug() override;
+
+ void ApplyConfiguration();
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+
+ void SetConfiguration();
+
+ std::unique_ptr<Ui::ConfigureCpuDebug> ui;
+};
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureCpuDebug</class>
+ <widget class="QWidget" name="ConfigureCpuDebug">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>321</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox">
+ <property name="title">
+ <string>Toggle CPU Optimizations</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QLabel">
+ <property name="wordWrap">
+ <bool>1</bool>
+ </property>
+ <property name="text">
+ <string>
+ &lt;div&gt;
+ &lt;b&gt;For debugging only.&lt;/b&gt;
+ &lt;br&gt;
+ If you're not sure what these do, keep all of these enabled.
+ &lt;br&gt;
+ These settings only take effect when CPU Accuracy is "Debug Mode".
+ &lt;/div&gt;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_page_tables">
+ <property name="text">
+ <string>Enable inline page tables</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &lt;div style="white-space: nowrap"&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+ &lt;div style="white-space: nowrap"&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
+ &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;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_block_linking">
+ <property name="text">
+ <string>Enable block linking</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &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;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_return_stack_buffer">
+ <property name="text">
+ <string>Enable return stack buffer</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &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;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_fast_dispatcher">
+ <property name="text">
+ <string>Enable fast dispatcher</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &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;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_context_elimination">
+ <property name="text">
+ <string>Enable context elimination</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_const_prop">
+ <property name="text">
+ <string>Enable constant propagation</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_misc_ir">
+ <property name="text">
+ <string>Enable miscellaneous optimizations</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
+ </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="cpuopt_reduce_misalign_checks">
+ <property name="text">
+ <string>Enable misalignment check reduction</string>
+ </property>
+ <property name="toolTip">
+ <string>
+ &lt;div style="white-space: nowrap"&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
+ &lt;div style="white-space: nowrap"&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
+ </string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_disable_info">
+ <property name="text">
+ <string>CPU settings are available only when game is not running.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</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() {
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
ui->reporting_services->setChecked(Settings::values.reporting_services);
ui->quest_flag->setChecked(Settings::values.quest_flag);
- ui->disable_cpu_opt->setChecked(Settings::values.disable_cpu_opt);
ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
@@ -51,7 +50,6 @@ void ConfigureDebug::ApplyConfiguration() {
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
Settings::values.reporting_services = ui->reporting_services->isChecked();
Settings::values.quest_flag = ui->quest_flag->isChecked();
- Settings::values.disable_cpu_opt = ui->disable_cpu_opt->isChecked();
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
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 @@
</property>
</widget>
</item>
- <item>
- <widget class="QCheckBox" name="disable_cpu_opt">
- <property name="text">
- <string>Disable CPU JIT optimizations</string>
- </property>
- </widget>
- </item>
</layout>
</widget>
</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 @@
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
: QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
+ Settings::configuring_global = true;
+
ui->setupUi(this);
ui->hotkeysTab->Populate(registry);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -40,6 +42,8 @@ void ConfigureDialog::ApplyConfiguration() {
ui->filesystemTab->applyConfiguration();
ui->inputTab->ApplyConfiguration();
ui->hotkeysTab->ApplyConfiguration(registry);
+ ui->cpuTab->ApplyConfiguration();
+ ui->cpuDebugTab->ApplyConfiguration();
ui->graphicsTab->ApplyConfiguration();
ui->graphicsAdvancedTab->ApplyConfiguration();
ui->audioTab->ApplyConfiguration();
@@ -74,9 +78,10 @@ void ConfigureDialog::RetranslateUI() {
Q_DECLARE_METATYPE(QList<QWidget*>);
void ConfigureDialog::PopulateSelectionList() {
- const std::array<std::pair<QString, QList<QWidget*>>, 5> items{
+ const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
{{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}},
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
+ {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}},
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
{tr("Audio"), {ui->audioTab}},
{tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
@@ -105,6 +110,8 @@ void ConfigureDialog::UpdateVisibleTabs() {
{ui->profileManagerTab, tr("Profiles")},
{ui->inputTab, tr("Input")},
{ui->hotkeysTab, tr("Hotkeys")},
+ {ui->cpuTab, tr("CPU")},
+ {ui->cpuDebugTab, tr("Debug")},
{ui->graphicsTab, tr("Graphics")},
{ui->graphicsAdvancedTab, tr("Advanced")},
{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 @@
#include "yuzu/configuration/configure_filesystem.h"
#include "yuzu/uisettings.h"
-namespace {
-
-template <typename T>
-void SetComboBoxFromData(QComboBox* combo_box, T data) {
- const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data)));
- if (index >= combo_box->count() || index < 0)
- return;
-
- combo_box->setCurrentIndex(index);
-}
-
-} // Anonymous namespace
-
ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) {
ui->setupUi(this);
@@ -73,11 +60,6 @@ void ConfigureFilesystem::setConfiguration() {
ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
- SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size);
- SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size);
- SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size);
- SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size);
-
UpdateEnabledControls();
}
@@ -98,15 +80,6 @@ void ConfigureFilesystem::applyConfiguration() {
Settings::values.dump_nso = ui->dump_nso->isChecked();
UISettings::values.cache_game_list = ui->cache_game_list->isChecked();
-
- Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
- ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong());
- Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
- ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong());
- Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
- ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong());
- Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
- ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong());
}
void 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 @@
</widget>
</item>
<item>
- <widget class="QGroupBox" name="groupBox_3">
- <property name="title">
- <string>Storage Sizes</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_3">
- <item row="3" column="0">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>SD Card</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>System NAND</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QComboBox" name="sysnand_size">
- <item>
- <property name="text">
- <string>2.5 GB</string>
- </property>
- </item>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QComboBox" name="sdmc_size">
- <property name="currentText">
- <string>32 GB</string>
- </property>
- <item>
- <property name="text">
- <string>1 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>2 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>4 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>8 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>16 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>32 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>64 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>128 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>256 GB</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>1 TB</string>
- </property>
- </item>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QComboBox" name="usrnand_size">
- <item>
- <property name="text">
- <string>26 GB</string>
- </property>
- </item>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>User NAND</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>NAND</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QComboBox" name="nand_size">
- <item>
- <property name="text">
- <string>29.1 GB</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<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 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_general.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_general.h"
#include "yuzu/uisettings.h"
ConfigureGeneral::ConfigureGeneral(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGeneral) {
-
ui->setupUi(this);
+ SetupPerGameUI();
+
SetConfiguration();
- connect(ui->toggle_frame_limit, &QCheckBox::toggled, ui->frame_limit, &QSpinBox::setEnabled);
+ connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, [this]() {
+ ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked);
+ });
}
ConfigureGeneral::~ConfigureGeneral() = default;
@@ -26,27 +30,58 @@ void ConfigureGeneral::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->use_multi_core->setEnabled(runtime_lock);
- ui->use_multi_core->setChecked(Settings::values.use_multi_core);
+ ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse);
- ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
- ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked());
- ui->frame_limit->setValue(Settings::values.frame_limit);
+ ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
+ ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
+
+ if (!Settings::configuring_global) {
+ if (Settings::values.use_multi_core.UsingGlobal()) {
+ ui->use_multi_core->setCheckState(Qt::PartiallyChecked);
+ }
+ if (Settings::values.use_frame_limit.UsingGlobal()) {
+ ui->toggle_frame_limit->setCheckState(Qt::PartiallyChecked);
+ }
+ }
+
+ ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked &&
+ ui->toggle_frame_limit->isEnabled());
}
void ConfigureGeneral::ApplyConfiguration() {
- UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
- UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
- UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
- UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
-
- Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
- Settings::values.frame_limit = ui->frame_limit->value();
- Settings::values.use_multi_core = ui->use_multi_core->isChecked();
+ if (Settings::configuring_global) {
+ UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
+ UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
+ UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
+ UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
+
+ // Guard if during game and set to game-specific value
+ if (Settings::values.use_frame_limit.UsingGlobal()) {
+ Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
+ Qt::Checked);
+ Settings::values.frame_limit.SetValue(ui->frame_limit->value());
+ }
+ if (Settings::values.use_multi_core.UsingGlobal()) {
+ Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
+ }
+ } else {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core,
+ ui->use_multi_core);
+
+ bool global_frame_limit = ui->toggle_frame_limit->checkState() == Qt::PartiallyChecked;
+ Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
+ Settings::values.frame_limit.SetGlobal(global_frame_limit);
+ if (!global_frame_limit) {
+ Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
+ Qt::Checked);
+ Settings::values.frame_limit.SetValue(ui->frame_limit->value());
+ }
+ }
}
void ConfigureGeneral::changeEvent(QEvent* event) {
@@ -60,3 +95,20 @@ void ConfigureGeneral::changeEvent(QEvent* event) {
void ConfigureGeneral::RetranslateUI() {
ui->retranslateUi(this);
}
+
+void ConfigureGeneral::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal());
+ ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
+
+ return;
+ }
+
+ ui->toggle_check_exit->setVisible(false);
+ ui->toggle_user_on_boot->setVisible(false);
+ ui->toggle_background_pause->setVisible(false);
+ ui->toggle_hide_mouse->setVisible(false);
+
+ ui->toggle_frame_limit->setTristate(true);
+ ui->use_multi_core->setTristate(true);
+}
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:
void SetConfiguration();
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureGeneral> ui;
};
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 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_graphics.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_graphics.h"
#ifdef HAS_VULKAN
@@ -21,11 +22,13 @@
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGraphics) {
- vulkan_device = Settings::values.vulkan_device;
+ vulkan_device = Settings::values.vulkan_device.GetValue();
RetrieveVulkanDevices();
ui->setupUi(this);
+ SetupPerGameUI();
+
SetConfiguration();
connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this,
@@ -40,6 +43,9 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
}
UpdateBackgroundColorButton(new_bg_color);
});
+
+ ui->bg_label->setVisible(Settings::configuring_global);
+ ui->bg_combobox->setVisible(!Settings::configuring_global);
}
void ConfigureGraphics::UpdateDeviceSelection(int device) {
@@ -57,27 +63,95 @@ void ConfigureGraphics::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->api->setEnabled(runtime_lock);
- ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend));
- ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio);
- ui->use_disk_shader_cache->setEnabled(runtime_lock);
- ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
- ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation);
- UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
- Settings::values.bg_blue));
+ ui->use_disk_shader_cache->setEnabled(runtime_lock);
+
+ if (Settings::configuring_global) {
+ ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
+ ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
+ ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
+ ui->use_asynchronous_gpu_emulation->setChecked(
+ Settings::values.use_asynchronous_gpu_emulation.GetValue());
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->use_disk_shader_cache,
+ &Settings::values.use_disk_shader_cache);
+ ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_gpu_emulation,
+ &Settings::values.use_asynchronous_gpu_emulation);
+
+ ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
+ ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
+ &Settings::values.aspect_ratio);
+
+ ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
+ ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
+ }
+
+ UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(),
+ Settings::values.bg_green.GetValue(),
+ Settings::values.bg_blue.GetValue()));
UpdateDeviceComboBox();
}
void ConfigureGraphics::ApplyConfiguration() {
- Settings::values.renderer_backend = GetCurrentGraphicsBackend();
- Settings::values.vulkan_device = vulkan_device;
- Settings::values.aspect_ratio = ui->aspect_ratio_combobox->currentIndex();
- Settings::values.use_disk_shader_cache = ui->use_disk_shader_cache->isChecked();
- Settings::values.use_asynchronous_gpu_emulation =
- ui->use_asynchronous_gpu_emulation->isChecked();
- Settings::values.bg_red = static_cast<float>(bg_color.redF());
- Settings::values.bg_green = static_cast<float>(bg_color.greenF());
- Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
+ if (Settings::configuring_global) {
+ // Guard if during game and set to game-specific value
+ if (Settings::values.renderer_backend.UsingGlobal()) {
+ Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
+ }
+ if (Settings::values.vulkan_device.UsingGlobal()) {
+ Settings::values.vulkan_device.SetValue(vulkan_device);
+ }
+ if (Settings::values.aspect_ratio.UsingGlobal()) {
+ Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
+ }
+ if (Settings::values.use_disk_shader_cache.UsingGlobal()) {
+ Settings::values.use_disk_shader_cache.SetValue(ui->use_disk_shader_cache->isChecked());
+ }
+ if (Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()) {
+ Settings::values.use_asynchronous_gpu_emulation.SetValue(
+ ui->use_asynchronous_gpu_emulation->isChecked());
+ }
+ if (Settings::values.bg_red.UsingGlobal()) {
+ Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
+ Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
+ Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
+ }
+ } else {
+ if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.renderer_backend.SetGlobal(true);
+ Settings::values.vulkan_device.SetGlobal(true);
+ } else {
+ Settings::values.renderer_backend.SetGlobal(false);
+ Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
+ if (GetCurrentGraphicsBackend() == Settings::RendererBackend::Vulkan) {
+ Settings::values.vulkan_device.SetGlobal(false);
+ Settings::values.vulkan_device.SetValue(vulkan_device);
+ } else {
+ Settings::values.vulkan_device.SetGlobal(true);
+ }
+ }
+
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
+ ui->aspect_ratio_combobox);
+
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
+ ui->use_disk_shader_cache);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
+ ui->use_asynchronous_gpu_emulation);
+
+ if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.bg_red.SetGlobal(true);
+ Settings::values.bg_green.SetGlobal(true);
+ Settings::values.bg_blue.SetGlobal(true);
+ } else {
+ Settings::values.bg_red.SetGlobal(false);
+ Settings::values.bg_green.SetGlobal(false);
+ Settings::values.bg_blue.SetGlobal(false);
+ Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
+ Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
+ Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
+ }
+ }
}
void ConfigureGraphics::changeEvent(QEvent* event) {
@@ -106,6 +180,11 @@ void ConfigureGraphics::UpdateDeviceComboBox() {
ui->device->clear();
bool enabled = false;
+
+ if (!Settings::configuring_global &&
+ ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ vulkan_device = Settings::values.vulkan_device.GetValue();
+ }
switch (GetCurrentGraphicsBackend()) {
case Settings::RendererBackend::OpenGL:
ui->device->addItem(tr("OpenGL Graphics Device"));
@@ -119,6 +198,9 @@ void ConfigureGraphics::UpdateDeviceComboBox() {
enabled = !vulkan_devices.empty();
break;
}
+ // If in per-game config and use global is selected, don't enable.
+ enabled &= !(!Settings::configuring_global &&
+ ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX);
ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn());
}
@@ -132,5 +214,37 @@ void ConfigureGraphics::RetrieveVulkanDevices() {
}
Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
- return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
+ if (Settings::configuring_global) {
+ return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
+ }
+
+ if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.renderer_backend.SetGlobal(true);
+ return Settings::values.renderer_backend.GetValue();
+ }
+ Settings::values.renderer_backend.SetGlobal(false);
+ return static_cast<Settings::RendererBackend>(ui->api->currentIndex() -
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigureGraphics::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
+ ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
+ ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
+ ui->use_asynchronous_gpu_emulation->setEnabled(
+ Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
+ ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
+ ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
+
+ return;
+ }
+
+ connect(ui->bg_combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this,
+ [this](int index) { ui->bg_button->setEnabled(index == 1); });
+
+ ui->use_disk_shader_cache->setTristate(true);
+ ui->use_asynchronous_gpu_emulation->setTristate(true);
+ ConfigurationShared::InsertGlobalItem(ui->aspect_ratio_combobox);
+ ConfigurationShared::InsertGlobalItem(ui->api);
}
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:
void RetrieveVulkanDevices();
+ void SetupPerGameUI();
+
Settings::RendererBackend GetCurrentGraphicsBackend() const;
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 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
+ <widget class="QComboBox" name="bg_combobox">
+ <property name="currentText">
+ <string>Use global background color</string>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="maxVisibleItems">
+ <number>10</number>
+ </property>
+ <item>
+ <property name="text">
+ <string>Use global background color</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Set background color:</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="bg_label">
<property name="text">
<string>Background Color:</string>
@@ -129,6 +152,19 @@
</widget>
</item>
<item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
<widget class="QPushButton" name="bg_button">
<property name="maximumSize">
<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 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_graphics_advanced.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_graphics_advanced.h"
ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent)
@@ -12,6 +13,8 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent)
ui->setupUi(this);
+ SetupPerGameUI();
+
SetConfiguration();
}
@@ -19,26 +22,81 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
void ConfigureGraphicsAdvanced::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
- ui->gpu_accuracy->setCurrentIndex(static_cast<int>(Settings::values.gpu_accuracy));
ui->use_vsync->setEnabled(runtime_lock);
- ui->use_vsync->setChecked(Settings::values.use_vsync);
ui->use_assembly_shaders->setEnabled(runtime_lock);
- ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders);
- ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time);
ui->force_30fps_mode->setEnabled(runtime_lock);
- ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode);
ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
- ui->anisotropic_filtering_combobox->setCurrentIndex(Settings::values.max_anisotropy);
+
+ if (Settings::configuring_global) {
+ ui->gpu_accuracy->setCurrentIndex(
+ static_cast<int>(Settings::values.gpu_accuracy.GetValue()));
+ ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
+ ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
+ ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
+ ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue());
+ ui->anisotropic_filtering_combobox->setCurrentIndex(
+ Settings::values.max_anisotropy.GetValue());
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy);
+ ConfigurationShared::SetPerGameSetting(ui->use_vsync, &Settings::values.use_vsync);
+ ConfigurationShared::SetPerGameSetting(ui->use_assembly_shaders,
+ &Settings::values.use_assembly_shaders);
+ ConfigurationShared::SetPerGameSetting(ui->use_fast_gpu_time,
+ &Settings::values.use_fast_gpu_time);
+ ConfigurationShared::SetPerGameSetting(ui->force_30fps_mode,
+ &Settings::values.force_30fps_mode);
+ ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox,
+ &Settings::values.max_anisotropy);
+ }
}
void ConfigureGraphicsAdvanced::ApplyConfiguration() {
- auto gpu_accuracy = static_cast<Settings::GPUAccuracy>(ui->gpu_accuracy->currentIndex());
- Settings::values.gpu_accuracy = gpu_accuracy;
- Settings::values.use_vsync = ui->use_vsync->isChecked();
- Settings::values.use_assembly_shaders = ui->use_assembly_shaders->isChecked();
- Settings::values.use_fast_gpu_time = ui->use_fast_gpu_time->isChecked();
- Settings::values.force_30fps_mode = ui->force_30fps_mode->isChecked();
- Settings::values.max_anisotropy = ui->anisotropic_filtering_combobox->currentIndex();
+ // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots)
+ const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>(
+ ui->gpu_accuracy->currentIndex() -
+ ((Settings::configuring_global) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
+
+ if (Settings::configuring_global) {
+ // Must guard in case of a during-game configuration when set to be game-specific.
+ if (Settings::values.gpu_accuracy.UsingGlobal()) {
+ Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
+ }
+ if (Settings::values.use_vsync.UsingGlobal()) {
+ Settings::values.use_vsync.SetValue(ui->use_vsync->isChecked());
+ }
+ if (Settings::values.use_assembly_shaders.UsingGlobal()) {
+ Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked());
+ }
+ if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
+ Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
+ }
+ if (Settings::values.force_30fps_mode.UsingGlobal()) {
+ Settings::values.force_30fps_mode.SetValue(ui->force_30fps_mode->isChecked());
+ }
+ if (Settings::values.max_anisotropy.UsingGlobal()) {
+ Settings::values.max_anisotropy.SetValue(
+ ui->anisotropic_filtering_combobox->currentIndex());
+ }
+ } else {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
+ ui->anisotropic_filtering_combobox);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
+ ui->use_assembly_shaders);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
+ ui->use_fast_gpu_time);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.force_30fps_mode,
+ ui->force_30fps_mode);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
+ ui->anisotropic_filtering_combobox);
+
+ if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.gpu_accuracy.SetGlobal(true);
+ } else {
+ Settings::values.gpu_accuracy.SetGlobal(false);
+ Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
+ }
+ }
}
void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
@@ -52,3 +110,25 @@ void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
void ConfigureGraphicsAdvanced::RetranslateUI() {
ui->retranslateUi(this);
}
+
+void ConfigureGraphicsAdvanced::SetupPerGameUI() {
+ // Disable if not global (only happens during game)
+ if (Settings::configuring_global) {
+ ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
+ ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
+ ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal());
+ ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
+ ui->force_30fps_mode->setEnabled(Settings::values.force_30fps_mode.UsingGlobal());
+ ui->anisotropic_filtering_combobox->setEnabled(
+ Settings::values.max_anisotropy.UsingGlobal());
+
+ return;
+ }
+
+ ConfigurationShared::InsertGlobalItem(ui->gpu_accuracy);
+ ui->use_vsync->setTristate(true);
+ ui->use_assembly_shaders->setTristate(true);
+ ui->use_fast_gpu_time->setTristate(true);
+ ui->force_30fps_mode->setTristate(true);
+ ConfigurationShared::InsertGlobalItem(ui->anisotropic_filtering_combobox);
+}
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:
void SetConfiguration();
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
};
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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include <QCheckBox>
+#include <QHeaderView>
+#include <QMenu>
+#include <QStandardItemModel>
+#include <QString>
+#include <QTimer>
+#include <QTreeView>
+
+#include "common/common_paths.h"
+#include "common/file_util.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/xts_archive.h"
+#include "core/loader/loader.h"
+#include "ui_configure_per_game.h"
+#include "yuzu/configuration/config.h"
+#include "yuzu/configuration/configure_input.h"
+#include "yuzu/configuration/configure_per_game.h"
+#include "yuzu/uisettings.h"
+#include "yuzu/util/util.h"
+
+ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) {
+ game_config = std::make_unique<Config>(fmt::format("{:016X}.ini", title_id), false);
+
+ Settings::configuring_global = false;
+
+ ui->setupUi(this);
+ setFocusPolicy(Qt::ClickFocus);
+ setWindowTitle(tr("Properties"));
+
+ ui->addonsTab->SetTitleId(title_id);
+
+ scene = new QGraphicsScene;
+ ui->icon_view->setScene(scene);
+
+ LoadConfiguration();
+}
+
+ConfigurePerGame::~ConfigurePerGame() = default;
+
+void ConfigurePerGame::ApplyConfiguration() {
+ ui->addonsTab->ApplyConfiguration();
+ ui->generalTab->ApplyConfiguration();
+ ui->systemTab->ApplyConfiguration();
+ ui->graphicsTab->ApplyConfiguration();
+ ui->graphicsAdvancedTab->ApplyConfiguration();
+ ui->audioTab->ApplyConfiguration();
+
+ Settings::Apply();
+ Settings::LogSettings();
+
+ game_config->Save();
+}
+
+void ConfigurePerGame::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QDialog::changeEvent(event);
+}
+
+void ConfigurePerGame::RetranslateUI() {
+ ui->retranslateUi(this);
+}
+
+void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file) {
+ this->file = std::move(file);
+ LoadConfiguration();
+}
+
+void ConfigurePerGame::LoadConfiguration() {
+ if (file == nullptr) {
+ return;
+ }
+
+ ui->addonsTab->LoadFromFile(file);
+
+ ui->display_title_id->setText(
+ QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper());
+
+ FileSys::PatchManager pm{title_id};
+ const auto control = pm.GetControlMetadata();
+ const auto loader = Loader::GetLoader(file);
+
+ if (control.first != nullptr) {
+ ui->display_version->setText(QString::fromStdString(control.first->GetVersionString()));
+ ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName()));
+ ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName()));
+ } else {
+ std::string title;
+ if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
+ ui->display_name->setText(QString::fromStdString(title));
+
+ FileSys::NACP nacp;
+ if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success)
+ ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName()));
+
+ ui->display_version->setText(QStringLiteral("1.0.0"));
+ }
+
+ if (control.second != nullptr) {
+ scene->clear();
+
+ QPixmap map;
+ const auto bytes = control.second->ReadAllBytes();
+ map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
+
+ scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+ } else {
+ std::vector<u8> bytes;
+ if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) {
+ scene->clear();
+
+ QPixmap map;
+ map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
+
+ scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+ }
+ }
+
+ ui->display_filename->setText(QString::fromStdString(file->GetName()));
+
+ ui->display_format->setText(
+ QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
+
+ const auto valueText = ReadableByteSize(file->GetSize());
+ ui->display_size->setText(valueText);
+}
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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <QDialog>
+#include <QList>
+
+#include "core/file_sys/vfs_types.h"
+#include "yuzu/configuration/config.h"
+
+class QGraphicsScene;
+class QStandardItem;
+class QStandardItemModel;
+class QTreeView;
+class QVBoxLayout;
+
+namespace Ui {
+class ConfigurePerGame;
+}
+
+class ConfigurePerGame : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigurePerGame(QWidget* parent, u64 title_id);
+ ~ConfigurePerGame() override;
+
+ /// Save all button configurations to settings file
+ void ApplyConfiguration();
+
+ void LoadFromFile(FileSys::VirtualFile file);
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+
+ void LoadConfiguration();
+
+ std::unique_ptr<Ui::ConfigurePerGame> ui;
+ FileSys::VirtualFile file;
+ u64 title_id;
+
+ QGraphicsScene* scene;
+
+ std::unique_ptr<Config> game_config;
+};
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigurePerGame</class>
+ <widget class="QDialog" name="ConfigurePerGame">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Info</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGraphicsView" name="icon_view">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>256</width>
+ <height>256</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>256</width>
+ <height>256</height>
+ </size>
+ </property>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="interactive">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="6" column="1">
+ <widget class="QLineEdit" name="display_size">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="display_version">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Title ID</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="display_title_id">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QLineEdit" name="display_filename">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="display_format">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Filename</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="display_name">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="display_developer">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Format</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Size</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Developer</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="VerticalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2"/>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="usesScrollButtons">
+ <bool>true</bool>
+ </property>
+ <property name="documentMode">
+ <bool>false</bool>
+ </property>
+ <property name="tabsClosable">
+ <bool>false</bool>
+ </property>
+ <widget class="ConfigurePerGameAddons" name="addonsTab">
+ <attribute name="title">
+ <string>Add-Ons</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureGeneral" name="generalTab">
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureSystem" name="systemTab">
+ <attribute name="title">
+ <string>System</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureGraphics" name="graphicsTab">
+ <attribute name="title">
+ <string>Graphics</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
+ <attribute name="title">
+ <string>Adv. Graphics</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureAudio" name="audioTab">
+ <attribute name="title">
+ <string>Audio</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ConfigureGeneral</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_general.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureSystem</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_system.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureAudio</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_audio.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureGraphics</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_graphics.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureGraphicsAdvanced</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_graphics_advanced.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigurePerGameAddons</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_per_game_addons.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigurePerGame</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ConfigurePerGame</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</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 @@
#include "common/common_paths.h"
#include "common/file_util.h"
-#include "core/file_sys/control_metadata.h"
+#include "core/core.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/xts_archive.h"
#include "core/loader/loader.h"
-#include "ui_configure_per_general.h"
+#include "ui_configure_per_game_addons.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_input.h"
-#include "yuzu/configuration/configure_per_general.h"
+#include "yuzu/configuration/configure_per_game_addons.h"
#include "yuzu/uisettings.h"
#include "yuzu/util/util.h"
-ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
- : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGameGeneral>()), title_id(title_id) {
-
+ConfigurePerGameAddons::ConfigurePerGameAddons(QWidget* parent)
+ : QWidget(parent), ui(new Ui::ConfigurePerGameAddons) {
ui->setupUi(this);
- setFocusPolicy(Qt::ClickFocus);
- setWindowTitle(tr("Properties"));
layout = new QVBoxLayout;
tree_view = new QTreeView;
@@ -52,7 +49,7 @@ ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
item_model->setHeaderData(1, Qt::Horizontal, tr("Version"));
// We must register all custom types with the Qt Automoc system so that we are able to use it
- // with signals/slots. In this case, QList falls under the umbrells of custom types.
+ // with signals/slots. In this case, QList falls under the umbrella of custom types.
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
layout->setContentsMargins(0, 0, 0, 0);
@@ -61,18 +58,15 @@ ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
ui->scrollArea->setLayout(layout);
- scene = new QGraphicsScene;
- ui->icon_view->setScene(scene);
+ ui->scrollArea->setEnabled(!Core::System::GetInstance().IsPoweredOn());
connect(item_model, &QStandardItemModel::itemChanged,
[] { UISettings::values.is_game_list_reload_pending.exchange(true); });
-
- LoadConfiguration();
}
-ConfigurePerGameGeneral::~ConfigurePerGameGeneral() = default;
+ConfigurePerGameAddons::~ConfigurePerGameAddons() = default;
-void ConfigurePerGameGeneral::ApplyConfiguration() {
+void ConfigurePerGameAddons::ApplyConfiguration() {
std::vector<std::string> disabled_addons;
for (const auto& item : list_items) {
@@ -92,72 +86,35 @@ void ConfigurePerGameGeneral::ApplyConfiguration() {
Settings::values.disabled_addons[title_id] = disabled_addons;
}
-void ConfigurePerGameGeneral::changeEvent(QEvent* event) {
+void ConfigurePerGameAddons::LoadFromFile(FileSys::VirtualFile file) {
+ this->file = std::move(file);
+ LoadConfiguration();
+}
+
+void ConfigurePerGameAddons::SetTitleId(u64 id) {
+ this->title_id = id;
+}
+
+void ConfigurePerGameAddons::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
- QDialog::changeEvent(event);
+ QWidget::changeEvent(event);
}
-void ConfigurePerGameGeneral::RetranslateUI() {
+void ConfigurePerGameAddons::RetranslateUI() {
ui->retranslateUi(this);
}
-void ConfigurePerGameGeneral::LoadFromFile(FileSys::VirtualFile file) {
- this->file = std::move(file);
- LoadConfiguration();
-}
-
-void ConfigurePerGameGeneral::LoadConfiguration() {
+void ConfigurePerGameAddons::LoadConfiguration() {
if (file == nullptr) {
return;
}
- ui->display_title_id->setText(QString::fromStdString(fmt::format("{:016X}", title_id)));
-
FileSys::PatchManager pm{title_id};
- const auto control = pm.GetControlMetadata();
const auto loader = Loader::GetLoader(file);
- if (control.first != nullptr) {
- ui->display_version->setText(QString::fromStdString(control.first->GetVersionString()));
- ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName()));
- ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName()));
- } else {
- std::string title;
- if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
- ui->display_name->setText(QString::fromStdString(title));
-
- FileSys::NACP nacp;
- if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success)
- ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName()));
-
- ui->display_version->setText(QStringLiteral("1.0.0"));
- }
-
- if (control.second != nullptr) {
- scene->clear();
-
- QPixmap map;
- const auto bytes = control.second->ReadAllBytes();
- map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
-
- scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
- Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
- } else {
- std::vector<u8> bytes;
- if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) {
- scene->clear();
-
- QPixmap map;
- map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
-
- scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
- Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
- }
- }
-
FileSys::VirtualFile update_raw;
loader->ReadUpdateRaw(update_raw);
@@ -182,12 +139,4 @@ void ConfigurePerGameGeneral::LoadConfiguration() {
}
tree_view->setColumnWidth(0, 5 * tree_view->width() / 16);
-
- ui->display_filename->setText(QString::fromStdString(file->GetName()));
-
- ui->display_format->setText(
- QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
-
- const auto valueText = ReadableByteSize(file->GetSize());
- ui->display_size->setText(valueText);
}
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 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,7 +7,6 @@
#include <memory>
#include <vector>
-#include <QDialog>
#include <QList>
#include "core/file_sys/vfs_types.h"
@@ -19,35 +18,36 @@ class QTreeView;
class QVBoxLayout;
namespace Ui {
-class ConfigurePerGameGeneral;
+class ConfigurePerGameAddons;
}
-class ConfigurePerGameGeneral : public QDialog {
+class ConfigurePerGameAddons : public QWidget {
Q_OBJECT
public:
- explicit ConfigurePerGameGeneral(QWidget* parent, u64 title_id);
- ~ConfigurePerGameGeneral() override;
+ explicit ConfigurePerGameAddons(QWidget* parent = nullptr);
+ ~ConfigurePerGameAddons() override;
/// Save all button configurations to settings file
void ApplyConfiguration();
void LoadFromFile(FileSys::VirtualFile file);
+ void SetTitleId(u64 id);
+
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void LoadConfiguration();
- std::unique_ptr<Ui::ConfigurePerGameGeneral> ui;
+ std::unique_ptr<Ui::ConfigurePerGameAddons> ui;
FileSys::VirtualFile file;
u64 title_id;
QVBoxLayout* layout;
QTreeView* tree_view;
QStandardItemModel* item_model;
- QGraphicsScene* scene;
std::vector<QList<QStandardItem*>> list_items;
};
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigurePerGameAddons</class>
+ <widget class="QWidget" name="ConfigurePerGameAddons">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>280</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</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 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ConfigurePerGameGeneral</class>
- <widget class="QDialog" name="ConfigurePerGameGeneral">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>520</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>ConfigurePerGameGeneral</string>
- </property>
- <layout class="QHBoxLayout" name="HorizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="VerticalLayout">
- <item>
- <widget class="QGroupBox" name="GeneralGroupBox">
- <property name="title">
- <string>Info</string>
- </property>
- <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="6" column="1" colspan="2">
- <widget class="QLineEdit" name="display_filename">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="display_name">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Developer</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1" colspan="2">
- <widget class="QLineEdit" name="display_size">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Name</string>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Filename</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Version</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>Format</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="display_version">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QLineEdit" name="display_format">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>Size</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="display_developer">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Title ID</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLineEdit" name="display_title_id">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="2" rowspan="5">
- <widget class="QGraphicsView" name="icon_view">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>128</width>
- <height>128</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>128</width>
- <height>128</height>
- </size>
- </property>
- <property name="verticalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="sizeAdjustPolicy">
- <enum>QAbstractScrollArea::AdjustToContents</enum>
- </property>
- <property name="interactive">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="PerformanceGroupBox">
- <property name="title">
- <string>Add-Ons</string>
- </property>
- <layout class="QHBoxLayout" name="PerformanceHorizontalLayout">
- <item>
- <widget class="QScrollArea" name="scrollArea">
- <property name="widgetResizable">
- <bool>true</bool>
- </property>
- <widget class="QWidget" name="scrollAreaWidgetContents">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>350</width>
- <height>169</height>
- </rect>
- </property>
- </widget>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="PerformanceVerticalLayout"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>ConfigurePerGameGeneral</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>269</x>
- <y>567</y>
- </hint>
- <hint type="destinationlabel">
- <x>269</x>
- <y>294</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>ConfigurePerGameGeneral</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>269</x>
- <y>567</y>
- </hint>
- <hint type="destinationlabel">
- <x>269</x>
- <y>294</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</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 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_system.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_system.h"
ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) {
@@ -21,20 +22,25 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
&ConfigureSystem::RefreshConsoleID);
- connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
- ui->rng_seed_edit->setEnabled(checked);
- if (!checked) {
+ connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
+ ui->rng_seed_edit->setEnabled(state == Qt::Checked);
+ if (state != Qt::Checked) {
ui->rng_seed_edit->setText(QStringLiteral("00000000"));
}
});
- connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
- ui->custom_rtc_edit->setEnabled(checked);
- if (!checked) {
+ connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
+ ui->custom_rtc_edit->setEnabled(state == Qt::Checked);
+ if (state != Qt::Checked) {
ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime());
}
});
+ ui->label_console_id->setVisible(Settings::configuring_global);
+ ui->button_regenerate_console_id->setVisible(Settings::configuring_global);
+
+ SetupPerGameUI();
+
SetConfiguration();
}
@@ -54,26 +60,58 @@ void ConfigureSystem::RetranslateUI() {
void ConfigureSystem::SetConfiguration() {
enabled = !Core::System::GetInstance().IsPoweredOn();
+ const auto rng_seed =
+ QStringLiteral("%1")
+ .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
+ .toUpper();
+ const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or(
+ std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
- ui->combo_language->setCurrentIndex(Settings::values.language_index);
- ui->combo_region->setCurrentIndex(Settings::values.region_index);
- ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index);
- ui->combo_sound->setCurrentIndex(Settings::values.sound_index);
-
- ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value());
- ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value());
-
- const auto rng_seed = QStringLiteral("%1")
- .arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'})
- .toUpper();
- ui->rng_seed_edit->setText(rng_seed);
-
- ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
- ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
+ if (Settings::configuring_global) {
+ ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
+ ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue());
+ ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue());
+ ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue());
+
+ ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
+ ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
+ Settings::values.rng_seed.UsingGlobal());
+ ui->rng_seed_edit->setText(rng_seed);
+
+ ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value());
+ ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() &&
+ Settings::values.rng_seed.UsingGlobal());
+ ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->combo_language,
+ &Settings::values.language_index);
+ ConfigurationShared::SetPerGameSetting(ui->combo_region, &Settings::values.region_index);
+ ConfigurationShared::SetPerGameSetting(ui->combo_time_zone,
+ &Settings::values.time_zone_index);
+ ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index);
+
+ if (Settings::values.rng_seed.UsingGlobal()) {
+ ui->rng_seed_checkbox->setCheckState(Qt::PartiallyChecked);
+ } else {
+ ui->rng_seed_checkbox->setCheckState(
+ Settings::values.rng_seed.GetValue().has_value() ? Qt::Checked : Qt::Unchecked);
+ ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value());
+ if (Settings::values.rng_seed.GetValue().has_value()) {
+ ui->rng_seed_edit->setText(rng_seed);
+ }
+ }
- const auto rtc_time = Settings::values.custom_rtc.value_or(
- std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
- ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
+ if (Settings::values.custom_rtc.UsingGlobal()) {
+ ui->custom_rtc_checkbox->setCheckState(Qt::PartiallyChecked);
+ } else {
+ ui->custom_rtc_checkbox->setCheckState(
+ Settings::values.custom_rtc.GetValue().has_value() ? Qt::Checked : Qt::Unchecked);
+ ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value());
+ if (Settings::values.custom_rtc.GetValue().has_value()) {
+ ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
+ }
+ }
+ }
}
void ConfigureSystem::ReadSystemSettings() {}
@@ -83,22 +121,78 @@ void ConfigureSystem::ApplyConfiguration() {
return;
}
- Settings::values.language_index = ui->combo_language->currentIndex();
- Settings::values.region_index = ui->combo_region->currentIndex();
- Settings::values.time_zone_index = ui->combo_time_zone->currentIndex();
- Settings::values.sound_index = ui->combo_sound->currentIndex();
+ if (Settings::configuring_global) {
+ // Guard if during game and set to game-specific value
+ if (Settings::values.language_index.UsingGlobal()) {
+ Settings::values.language_index.SetValue(ui->combo_language->currentIndex());
+ }
+ if (Settings::values.region_index.UsingGlobal()) {
+ Settings::values.region_index.SetValue(ui->combo_region->currentIndex());
+ }
+ if (Settings::values.time_zone_index.UsingGlobal()) {
+ Settings::values.time_zone_index.SetValue(ui->combo_time_zone->currentIndex());
+ }
+ if (Settings::values.sound_index.UsingGlobal()) {
+ Settings::values.sound_index.SetValue(ui->combo_sound->currentIndex());
+ }
+
+ if (Settings::values.rng_seed.UsingGlobal()) {
+ if (ui->rng_seed_checkbox->isChecked()) {
+ Settings::values.rng_seed.SetValue(
+ ui->rng_seed_edit->text().toULongLong(nullptr, 16));
+ } else {
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ }
+ }
- if (ui->rng_seed_checkbox->isChecked()) {
- Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16);
+ if (Settings::values.custom_rtc.UsingGlobal()) {
+ if (ui->custom_rtc_checkbox->isChecked()) {
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
+ } else {
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ }
+ }
} else {
- Settings::values.rng_seed = std::nullopt;
- }
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
+ ui->combo_language);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
+ ui->combo_time_zone);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
+
+ switch (ui->rng_seed_checkbox->checkState()) {
+ case Qt::Checked:
+ Settings::values.rng_seed.SetGlobal(false);
+ Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toULongLong(nullptr, 16));
+ break;
+ case Qt::Unchecked:
+ Settings::values.rng_seed.SetGlobal(false);
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ break;
+ case Qt::PartiallyChecked:
+ Settings::values.rng_seed.SetGlobal(false);
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ Settings::values.rng_seed.SetGlobal(true);
+ break;
+ }
- if (ui->custom_rtc_checkbox->isChecked()) {
- Settings::values.custom_rtc =
- std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch());
- } else {
- Settings::values.custom_rtc = std::nullopt;
+ switch (ui->custom_rtc_checkbox->checkState()) {
+ case Qt::Checked:
+ Settings::values.custom_rtc.SetGlobal(false);
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
+ break;
+ case Qt::Unchecked:
+ Settings::values.custom_rtc.SetGlobal(false);
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ break;
+ case Qt::PartiallyChecked:
+ Settings::values.custom_rtc.SetGlobal(false);
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ Settings::values.custom_rtc.SetGlobal(true);
+ break;
+ }
}
Settings::Apply();
@@ -120,3 +214,25 @@ void ConfigureSystem::RefreshConsoleID() {
ui->label_console_id->setText(
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
}
+
+void ConfigureSystem::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal());
+ ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal());
+ ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal());
+ ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
+ ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
+ ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
+ ui->custom_rtc_checkbox->setEnabled(Settings::values.custom_rtc.UsingGlobal());
+ ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.UsingGlobal());
+
+ return;
+ }
+
+ ConfigurationShared::InsertGlobalItem(ui->combo_language);
+ ConfigurationShared::InsertGlobalItem(ui->combo_region);
+ ConfigurationShared::InsertGlobalItem(ui->combo_time_zone);
+ ConfigurationShared::InsertGlobalItem(ui->combo_sound);
+ ui->rng_seed_checkbox->setTristate(true);
+ ui->custom_rtc_checkbox->setTristate(true);
+}
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:
void RefreshConsoleID();
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureSystem> ui;
bool enabled = false;
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) {
UISettings::GameDir& game_dir =
*selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>();
- QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up"));
- QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down "));
+ QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up"));
+ QAction* move_down = context_menu.addAction(tr("\u25bc Move Down"));
QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QCheckBox>
+#include <QDialogButtonBox>
+#include <QFileInfo>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QListWidget>
+#include <QVBoxLayout>
+#include "yuzu/install_dialog.h"
+#include "yuzu/uisettings.h"
+
+InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) {
+ file_list = new QListWidget(this);
+
+ for (const QString& file : files) {
+ QListWidgetItem* item = new QListWidgetItem(QFileInfo(file).fileName(), file_list);
+ item->setData(Qt::UserRole, file);
+ item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
+ item->setCheckState(Qt::Checked);
+ }
+
+ file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 11) / 10);
+
+ vbox_layout = new QVBoxLayout;
+
+ hbox_layout = new QHBoxLayout;
+
+ description = new QLabel(tr("Please confirm these are the files you wish to install."));
+
+ update_description =
+ new QLabel(tr("Installing an Update or DLC will overwrite the previously installed one."));
+
+ buttons = new QDialogButtonBox;
+ buttons->addButton(QDialogButtonBox::Cancel);
+ buttons->addButton(tr("Install"), QDialogButtonBox::AcceptRole);
+
+ connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept);
+ connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject);
+
+ hbox_layout->addWidget(buttons);
+
+ vbox_layout->addWidget(description);
+ vbox_layout->addWidget(update_description);
+ vbox_layout->addWidget(file_list);
+ vbox_layout->addLayout(hbox_layout);
+
+ setLayout(vbox_layout);
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowTitle(tr("Install Files to NAND"));
+}
+
+InstallDialog::~InstallDialog() = default;
+
+QStringList InstallDialog::GetFiles() const {
+ QStringList files;
+
+ for (int i = 0; i < file_list->count(); ++i) {
+ const QListWidgetItem* item = file_list->item(i);
+ if (item->checkState() == Qt::Checked) {
+ files.append(item->data(Qt::UserRole).toString());
+ }
+ }
+
+ return files;
+}
+
+int InstallDialog::GetMinimumWidth() const {
+ return file_list->width();
+}
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 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <QDialog>
+
+class QCheckBox;
+class QDialogButtonBox;
+class QHBoxLayout;
+class QLabel;
+class QListWidget;
+class QVBoxLayout;
+
+class InstallDialog : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit InstallDialog(QWidget* parent, const QStringList& files);
+ ~InstallDialog() override;
+
+ QStringList GetFiles() const;
+ bool ShouldOverwriteFiles() const;
+ int GetMinimumWidth() const;
+
+private:
+ QListWidget* file_list;
+
+ QVBoxLayout* vbox_layout;
+ QHBoxLayout* hbox_layout;
+
+ QLabel* description;
+ QLabel* update_description;
+ QDialogButtonBox* buttons;
+};
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 @@
#include "applets/software_keyboard.h"
#include "applets/web_browser.h"
#include "configuration/configure_input.h"
-#include "configuration/configure_per_general.h"
+#include "configuration/configure_per_game.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h"
#include "core/frontend/applets/general_frontend.h"
@@ -107,6 +107,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/game_list.h"
#include "yuzu/game_list_p.h"
#include "yuzu/hotkeys.h"
+#include "yuzu/install_dialog.h"
#include "yuzu/loading_screen.h"
#include "yuzu/main.h"
#include "yuzu/uisettings.h"
@@ -534,15 +535,15 @@ void GMainWindow::InitializeWidgets() {
if (emulation_running) {
return;
}
- bool is_async =
- !Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core;
- Settings::values.use_asynchronous_gpu_emulation = is_async;
- async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
+ bool is_async = !Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
+ Settings::values.use_multi_core.GetValue();
+ Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);
+ async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
Settings::Apply();
});
async_status_button->setText(tr("ASYNC"));
async_status_button->setCheckable(true);
- async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
+ async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
// Setup Multicore button
multicore_status_button = new QPushButton();
@@ -552,17 +553,17 @@ void GMainWindow::InitializeWidgets() {
if (emulation_running) {
return;
}
- Settings::values.use_multi_core = !Settings::values.use_multi_core;
- bool is_async =
- Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core;
- Settings::values.use_asynchronous_gpu_emulation = is_async;
- async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
- multicore_status_button->setChecked(Settings::values.use_multi_core);
+ Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue());
+ bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
+ Settings::values.use_multi_core.GetValue();
+ Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);
+ async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
+ multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
Settings::Apply();
});
multicore_status_button->setText(tr("MULTICORE"));
multicore_status_button->setCheckable(true);
- multicore_status_button->setChecked(Settings::values.use_multi_core);
+ multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
statusBar()->insertPermanentWidget(0, multicore_status_button);
statusBar()->insertPermanentWidget(0, async_status_button);
@@ -581,16 +582,16 @@ void GMainWindow::InitializeWidgets() {
renderer_status_button->setCheckable(false);
renderer_status_button->setDisabled(true);
#else
- renderer_status_button->setChecked(Settings::values.renderer_backend ==
+ renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
Settings::RendererBackend::Vulkan);
connect(renderer_status_button, &QPushButton::clicked, [=] {
if (emulation_running) {
return;
}
if (renderer_status_button->isChecked()) {
- Settings::values.renderer_backend = Settings::RendererBackend::Vulkan;
+ Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan);
} else {
- Settings::values.renderer_backend = Settings::RendererBackend::OpenGL;
+ Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);
}
Settings::Apply();
@@ -727,21 +728,24 @@ void GMainWindow::InitializeHotkeys() {
});
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
&QShortcut::activated, this, [&] {
- Settings::values.use_frame_limit = !Settings::values.use_frame_limit;
+ Settings::values.use_frame_limit.SetValue(
+ !Settings::values.use_frame_limit.GetValue());
UpdateStatusBar();
});
constexpr u16 SPEED_LIMIT_STEP = 5;
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
&QShortcut::activated, this, [&] {
- if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) {
- Settings::values.frame_limit += SPEED_LIMIT_STEP;
+ if (Settings::values.frame_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
+ Settings::values.frame_limit.SetValue(SPEED_LIMIT_STEP +
+ Settings::values.frame_limit.GetValue());
UpdateStatusBar();
}
});
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
&QShortcut::activated, this, [&] {
- if (Settings::values.frame_limit > SPEED_LIMIT_STEP) {
- Settings::values.frame_limit -= SPEED_LIMIT_STEP;
+ if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) {
+ Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() -
+ SPEED_LIMIT_STEP);
UpdateStatusBar();
}
});
@@ -844,6 +848,9 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
&GMainWindow::OnGameListOpenPerGameProperties);
+ connect(this, &GMainWindow::UpdateInstallProgress, this,
+ &GMainWindow::IncrementInstallProgress);
+
connect(this, &GMainWindow::EmulationStarting, render_window,
&GRenderWindow::OnEmulationStarting);
connect(this, &GMainWindow::EmulationStopping, render_window,
@@ -1039,6 +1046,17 @@ void GMainWindow::BootGame(const QString& filename) {
LOG_INFO(Frontend, "yuzu starting...");
StoreRecentFile(filename); // Put the filename on top of the list
+ u64 title_id{0};
+
+ const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
+ const auto loader = Loader::GetLoader(v_file);
+ if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
+ // Load per game settings
+ Config per_game_config(fmt::format("{:016X}.ini", title_id), false);
+ }
+
+ Settings::LogSettings();
+
if (UISettings::values.select_user_on_boot) {
SelectAndSetCurrentUser();
}
@@ -1063,6 +1081,7 @@ void GMainWindow::BootGame(const QString& filename) {
&LoadingScreen::OnLoadProgress, Qt::QueuedConnection);
// Update the GUI
+ UpdateStatusButtons();
if (ui.action_Single_Window_Mode->isChecked()) {
game_list->hide();
game_list_placeholder->hide();
@@ -1078,8 +1097,6 @@ void GMainWindow::BootGame(const QString& filename) {
ui.centralwidget->setMouseTracking(true);
}
- const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
-
std::string title_name;
std::string title_version;
const auto res = Core::System::GetInstance().GetGameName(title_name);
@@ -1521,7 +1538,7 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
return;
}
- ConfigurePerGameGeneral dialog(this, title_id);
+ ConfigurePerGame dialog(this, title_id);
dialog.LoadFromFile(v_file);
auto result = dialog.exec();
if (result == QDialog::Accepted) {
@@ -1532,7 +1549,14 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
game_list->PopulateAsync(UISettings::values.game_dirs);
}
- config->Save();
+ // Do not cause the global config to write local settings into the config file
+ Settings::RestoreGlobalState();
+
+ if (!Core::System::GetInstance().IsPoweredOn()) {
+ config->Save();
+ }
+ } else {
+ Settings::RestoreGlobalState();
}
}
@@ -1573,187 +1597,255 @@ void GMainWindow::OnMenuLoadFolder() {
}
}
+void GMainWindow::IncrementInstallProgress() {
+ install_progress->setValue(install_progress->value() + 1);
+}
+
void GMainWindow::OnMenuInstallToNAND() {
const QString file_filter =
tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
- "(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge "
+ "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge "
"Image (*.xci)");
- QString filename = QFileDialog::getOpenFileName(this, tr("Install File"),
- UISettings::values.roms_path, file_filter);
- if (filename.isEmpty()) {
+ QStringList filenames = QFileDialog::getOpenFileNames(
+ this, tr("Install Files"), UISettings::values.roms_path, file_filter);
+
+ if (filenames.isEmpty()) {
+ return;
+ }
+
+ InstallDialog installDialog(this, filenames);
+ if (installDialog.exec() == QDialog::Rejected) {
+ return;
+ }
+
+ const QStringList files = installDialog.GetFiles();
+
+ if (files.isEmpty()) {
+ return;
+ }
+
+ int remaining = filenames.size();
+
+ // This would only overflow above 2^43 bytes (8.796 TB)
+ int total_size = 0;
+ for (const QString& file : files) {
+ total_size += static_cast<int>(QFile(file).size() / 0x1000);
+ }
+ if (total_size < 0) {
+ LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting.");
return;
}
+ QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
+ QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
+ QStringList failed_files{}; // Files that failed to install due to errors
+
+ ui.action_Install_File_NAND->setEnabled(false);
+
+ install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this);
+ install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
+ ~Qt::WindowMaximizeButtonHint);
+ install_progress->setAttribute(Qt::WA_DeleteOnClose, true);
+ install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40);
+ install_progress->show();
+
+ for (const QString& file : files) {
+ install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining));
+ install_progress->setLabelText(
+ tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
+
+ QFuture<InstallResult> future;
+ InstallResult result;
+
+ if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
+ file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
+
+ future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); });
+
+ while (!future.isFinished()) {
+ QCoreApplication::processEvents();
+ }
+
+ result = future.result();
+
+ } else {
+ result = InstallNCA(file);
+ }
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+
+ switch (result) {
+ case InstallResult::Success:
+ new_files.append(QFileInfo(file).fileName());
+ break;
+ case InstallResult::Overwrite:
+ overwritten_files.append(QFileInfo(file).fileName());
+ break;
+ case InstallResult::Failure:
+ failed_files.append(QFileInfo(file).fileName());
+ break;
+ }
+
+ --remaining;
+ }
+
+ install_progress->close();
+
+ const QString install_results =
+ (new_files.isEmpty() ? QStringLiteral("")
+ : tr("%n file(s) were newly installed\n", "", new_files.size())) +
+ (overwritten_files.isEmpty()
+ ? QStringLiteral("")
+ : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
+ (failed_files.isEmpty() ? QStringLiteral("")
+ : tr("%n file(s) failed to install\n", "", failed_files.size()));
+
+ QMessageBox::information(this, tr("Install Results"), install_results);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
+ FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
+ "game_list");
+ ui.action_Install_File_NAND->setEnabled(true);
+}
+
+InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
const FileSys::VirtualFile& dest, std::size_t block_size) {
- if (src == nullptr || dest == nullptr)
+ if (src == nullptr || dest == nullptr) {
return false;
- if (!dest->Resize(src->GetSize()))
+ }
+ if (!dest->Resize(src->GetSize())) {
return false;
+ }
std::array<u8, 0x1000> buffer{};
- const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size());
-
- QProgressDialog progress(
- tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())),
- tr("Cancel"), 0, progress_maximum, this);
- progress.setWindowModality(Qt::WindowModal);
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
- if (progress.wasCanceled()) {
+ if (install_progress->wasCanceled()) {
dest->Resize(0);
return false;
}
- const int progress_value = static_cast<int>(i / buffer.size());
- progress.setValue(progress_value);
+ emit UpdateInstallProgress();
const auto read = src->Read(buffer.data(), buffer.size(), i);
dest->Write(buffer.data(), read, i);
}
-
return true;
};
- const auto success = [this]() {
- QMessageBox::information(this, tr("Successfully Installed"),
- tr("The file was successfully installed."));
- game_list->PopulateAsync(UISettings::values.game_dirs);
- FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
- DIR_SEP + "game_list");
- };
-
- const auto failed = [this]() {
- QMessageBox::warning(
- this, tr("Failed to Install"),
- tr("There was an error while attempting to install the provided file. It "
- "could have an incorrect format or be missing metadata. Please "
- "double-check your file and try again."));
- };
-
- const auto overwrite = [this]() {
- return QMessageBox::question(this, tr("Failed to Install"),
- tr("The file you are attempting to install already exists "
- "in the cache. Would you like to overwrite it?")) ==
- QMessageBox::Yes;
- };
-
- if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
- filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
- std::shared_ptr<FileSys::NSP> nsp;
- if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
- nsp = std::make_shared<FileSys::NSP>(
- vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
- if (nsp->IsExtractedType())
- failed();
- } else {
- const auto xci = std::make_shared<FileSys::XCI>(
- vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
- nsp = xci->GetSecurePartitionNSP();
- }
-
- if (nsp->GetStatus() != Loader::ResultStatus::Success) {
- failed();
- return;
- }
- const auto res = Core::System::GetInstance()
- .GetFileSystemController()
- .GetUserNANDContents()
- ->InstallEntry(*nsp, false, qt_raw_copy);
- if (res == FileSys::InstallResult::Success) {
- success();
- } else {
- if (res == FileSys::InstallResult::ErrorAlreadyExists) {
- if (overwrite()) {
- const auto res2 = Core::System::GetInstance()
- .GetFileSystemController()
- .GetUserNANDContents()
- ->InstallEntry(*nsp, true, qt_raw_copy);
- if (res2 == FileSys::InstallResult::Success) {
- success();
- } else {
- failed();
- }
- }
- } else {
- failed();
- }
+ std::shared_ptr<FileSys::NSP> nsp;
+ if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
+ nsp = std::make_shared<FileSys::NSP>(
+ vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
+ if (nsp->IsExtractedType()) {
+ return InstallResult::Failure;
}
} else {
- const auto nca = std::make_shared<FileSys::NCA>(
+ const auto xci = std::make_shared<FileSys::XCI>(
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
- const auto id = nca->GetStatus();
+ nsp = xci->GetSecurePartitionNSP();
+ }
- // Game updates necessary are missing base RomFS
- if (id != Loader::ResultStatus::Success &&
- id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
- failed();
- return;
- }
+ if (nsp->GetStatus() != Loader::ResultStatus::Success) {
+ return InstallResult::Failure;
+ }
+ const auto res =
+ Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
+ *nsp, true, qt_raw_copy);
+ if (res == FileSys::InstallResult::Success) {
+ return InstallResult::Success;
+ } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
+ return InstallResult::Overwrite;
+ } else {
+ return InstallResult::Failure;
+ }
+}
- const QStringList tt_options{tr("System Application"),
- tr("System Archive"),
- tr("System Application Update"),
- tr("Firmware Package (Type A)"),
- tr("Firmware Package (Type B)"),
- tr("Game"),
- tr("Game Update"),
- tr("Game DLC"),
- tr("Delta Title")};
- bool ok;
- const auto item = QInputDialog::getItem(
- this, tr("Select NCA Install Type..."),
- tr("Please select the type of title you would like to install this NCA as:\n(In "
- "most instances, the default 'Game' is fine.)"),
- tt_options, 5, false, &ok);
-
- auto index = tt_options.indexOf(item);
- if (!ok || index == -1) {
- QMessageBox::warning(this, tr("Failed to Install"),
- tr("The title type you selected for the NCA is invalid."));
- return;
+InstallResult GMainWindow::InstallNCA(const QString& filename) {
+ const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
+ const FileSys::VirtualFile& dest, std::size_t block_size) {
+ if (src == nullptr || dest == nullptr) {
+ return false;
}
-
- // If index is equal to or past Game, add the jump in TitleType.
- if (index >= 5) {
- index += static_cast<size_t>(FileSys::TitleType::Application) -
- static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
+ if (!dest->Resize(src->GetSize())) {
+ return false;
}
- FileSys::InstallResult res;
- if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
- res = Core::System::GetInstance()
- .GetFileSystemController()
- .GetUserNANDContents()
- ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
- qt_raw_copy);
- } else {
- res = Core::System::GetInstance()
- .GetFileSystemController()
- .GetSystemNANDContents()
- ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
- qt_raw_copy);
- }
+ std::array<u8, 0x1000> buffer{};
- if (res == FileSys::InstallResult::Success) {
- success();
- } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
- if (overwrite()) {
- const auto res2 = Core::System::GetInstance()
- .GetFileSystemController()
- .GetUserNANDContents()
- ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index),
- true, qt_raw_copy);
- if (res2 == FileSys::InstallResult::Success) {
- success();
- } else {
- failed();
- }
+ for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
+ if (install_progress->wasCanceled()) {
+ dest->Resize(0);
+ return false;
}
- } else {
- failed();
+
+ emit UpdateInstallProgress();
+
+ const auto read = src->Read(buffer.data(), buffer.size(), i);
+ dest->Write(buffer.data(), read, i);
}
+ return true;
+ };
+
+ const auto nca =
+ std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
+ const auto id = nca->GetStatus();
+
+ // Game updates necessary are missing base RomFS
+ if (id != Loader::ResultStatus::Success &&
+ id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
+ return InstallResult::Failure;
+ }
+
+ const QStringList tt_options{tr("System Application"),
+ tr("System Archive"),
+ tr("System Application Update"),
+ tr("Firmware Package (Type A)"),
+ tr("Firmware Package (Type B)"),
+ tr("Game"),
+ tr("Game Update"),
+ tr("Game DLC"),
+ tr("Delta Title")};
+ bool ok;
+ const auto item = QInputDialog::getItem(
+ this, tr("Select NCA Install Type..."),
+ tr("Please select the type of title you would like to install this NCA as:\n(In "
+ "most instances, the default 'Game' is fine.)"),
+ tt_options, 5, false, &ok);
+
+ auto index = tt_options.indexOf(item);
+ if (!ok || index == -1) {
+ QMessageBox::warning(this, tr("Failed to Install"),
+ tr("The title type you selected for the NCA is invalid."));
+ return InstallResult::Failure;
+ }
+
+ // If index is equal to or past Game, add the jump in TitleType.
+ if (index >= 5) {
+ index += static_cast<size_t>(FileSys::TitleType::Application) -
+ static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
+ }
+
+ FileSys::InstallResult res;
+ if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
+ res = Core::System::GetInstance()
+ .GetFileSystemController()
+ .GetUserNANDContents()
+ ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
+ } else {
+ res = Core::System::GetInstance()
+ .GetFileSystemController()
+ .GetSystemNANDContents()
+ ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
+ }
+
+ if (res == FileSys::InstallResult::Success) {
+ return InstallResult::Success;
+ } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
+ return InstallResult::Overwrite;
+ } else {
+ return InstallResult::Failure;
}
}
@@ -1819,6 +1911,9 @@ void GMainWindow::OnStopGame() {
}
ShutdownGame();
+
+ Settings::RestoreGlobalState();
+ UpdateStatusButtons();
}
void GMainWindow::OnLoadComplete() {
@@ -1926,7 +2021,7 @@ void GMainWindow::ToggleWindowMode() {
void GMainWindow::ResetWindowSize() {
const auto aspect_ratio = Layout::EmulationAspectRatio(
- static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio),
+ static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()),
static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width);
if (!ui.action_Single_Window_Mode->isChecked()) {
render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio,
@@ -1974,16 +2069,7 @@ void GMainWindow::OnConfigure() {
ui.centralwidget->setMouseTracking(false);
}
- dock_status_button->setChecked(Settings::values.use_docked_mode);
- multicore_status_button->setChecked(Settings::values.use_multi_core);
- Settings::values.use_asynchronous_gpu_emulation =
- Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core;
- async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation);
-
-#ifdef HAS_VULKAN
- renderer_status_button->setChecked(Settings::values.renderer_backend ==
- Settings::RendererBackend::Vulkan);
-#endif
+ UpdateStatusButtons();
}
void GMainWindow::OnLoadAmiibo() {
@@ -2097,21 +2183,34 @@ void GMainWindow::UpdateStatusBar() {
auto results = Core::System::GetInstance().GetAndResetPerfStats();
- if (Settings::values.use_frame_limit) {
+ if (Settings::values.use_frame_limit.GetValue()) {
emu_speed_label->setText(tr("Speed: %1% / %2%")
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
- .arg(Settings::values.frame_limit));
+ .arg(Settings::values.frame_limit.GetValue()));
} else {
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
}
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
- emu_speed_label->setVisible(!Settings::values.use_multi_core);
+ emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
game_fps_label->setVisible(true);
emu_frametime_label->setVisible(true);
}
+void GMainWindow::UpdateStatusButtons() {
+ dock_status_button->setChecked(Settings::values.use_docked_mode);
+ multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
+ Settings::values.use_asynchronous_gpu_emulation.SetValue(
+ Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
+ Settings::values.use_multi_core.GetValue());
+ async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
+#ifdef HAS_VULKAN
+ renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
+ Settings::RendererBackend::Vulkan);
+#endif
+}
+
void GMainWindow::HideMouseCursor() {
if (emu_thread == nullptr || UISettings::values.hide_mouse == false) {
mouse_hide_timer.stop();
@@ -2195,6 +2294,9 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
if (answer == QMessageBox::Yes) {
if (emu_thread) {
ShutdownGame();
+
+ Settings::RestoreGlobalState();
+ UpdateStatusButtons();
}
} else {
// Only show the message if the game is still running.
@@ -2357,9 +2459,13 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
hotkey_registry.SaveHotkeys();
// Shutdown session if the emu thread is active...
- if (emu_thread != nullptr)
+ if (emu_thread != nullptr) {
ShutdownGame();
+ Settings::RestoreGlobalState();
+ UpdateStatusButtons();
+ }
+
render_window->close();
QWidget::closeEvent(event);
@@ -2539,8 +2645,6 @@ int main(int argc, char* argv[]) {
QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
&GMainWindow::OnAppFocusStateChanged);
- Settings::LogSettings();
-
int result = app.exec();
detached_tasks.WaitForAllTasks();
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;
class ProfilerWidget;
class QLabel;
class QPushButton;
+class QProgressDialog;
class WaitTreeWidget;
enum class GameListOpenTarget;
class GameListPlaceholder;
@@ -47,6 +48,12 @@ enum class EmulatedDirectoryTarget {
SDMC,
};
+enum class InstallResult {
+ Success,
+ Overwrite,
+ Failure,
+};
+
enum class ReinitializeKeyBehavior {
NoWarning,
Warning,
@@ -102,6 +109,8 @@ signals:
// Signal that tells widgets to update icons to use the current theme
void UpdateThemedIcons();
+ void UpdateInstallProgress();
+
void ErrorDisplayFinished();
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
@@ -198,6 +207,7 @@ private slots:
void OnGameListOpenPerGameProperties(const std::string& file);
void OnMenuLoadFile();
void OnMenuLoadFolder();
+ void IncrementInstallProgress();
void OnMenuInstallToNAND();
void OnMenuRecentFile();
void OnConfigure();
@@ -218,9 +228,12 @@ private slots:
private:
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
+ InstallResult InstallNSPXCI(const QString& filename);
+ InstallResult InstallNCA(const QString& filename);
void UpdateWindowTitle(const std::string& title_name = {},
const std::string& title_version = {});
void UpdateStatusBar();
+ void UpdateStatusButtons();
void HideMouseCursor();
void ShowMouseCursor();
void OpenURL(const QUrl& url);
@@ -271,6 +284,9 @@ private:
HotkeyRegistry hotkey_registry;
+ // Install progress dialog
+ QProgressDialog* install_progress;
+
protected:
void dropEvent(QDropEvent* event) override;
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 @@
<bool>true</bool>
</property>
<property name="text">
- <string>Install File to NAND...</string>
+ <string>Install Files to NAND...</string>
</property>
</action>
<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() {
Settings::values.gamecard_current_game =
sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
- Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger(
- "Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB)));
- Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger(
- "Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB)));
- Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
- sdl2_config->GetInteger("Data Storage", "nand_system_size",
- static_cast<long>(Settings::NANDSystemSize::S2_5GB)));
- Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger(
- "Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB)));
// System
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
@@ -354,63 +345,72 @@ void Config::ReadValues() {
const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
if (rng_seed_enabled) {
- Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0);
+ Settings::values.rng_seed.SetValue(sdl2_config->GetInteger("System", "rng_seed", 0));
} else {
- Settings::values.rng_seed = std::nullopt;
+ Settings::values.rng_seed.SetValue(std::nullopt);
}
const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
if (custom_rtc_enabled) {
- Settings::values.custom_rtc =
- std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0));
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)));
} else {
- Settings::values.custom_rtc = std::nullopt;
+ Settings::values.custom_rtc.SetValue(std::nullopt);
}
- Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1);
- Settings::values.time_zone_index = sdl2_config->GetInteger("System", "time_zone_index", 0);
+ Settings::values.language_index.SetValue(
+ sdl2_config->GetInteger("System", "language_index", 1));
+ Settings::values.time_zone_index.SetValue(
+ sdl2_config->GetInteger("System", "time_zone_index", 0));
// Core
- Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false);
+ Settings::values.use_multi_core.SetValue(
+ sdl2_config->GetBoolean("Core", "use_multi_core", false));
// Renderer
const int renderer_backend = sdl2_config->GetInteger(
"Renderer", "backend", static_cast<int>(Settings::RendererBackend::OpenGL));
- Settings::values.renderer_backend = static_cast<Settings::RendererBackend>(renderer_backend);
+ Settings::values.renderer_backend.SetValue(
+ static_cast<Settings::RendererBackend>(renderer_backend));
Settings::values.renderer_debug = sdl2_config->GetBoolean("Renderer", "debug", false);
- Settings::values.vulkan_device = sdl2_config->GetInteger("Renderer", "vulkan_device", 0);
-
- Settings::values.aspect_ratio =
- static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0));
- Settings::values.max_anisotropy =
- static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0));
- Settings::values.use_frame_limit = sdl2_config->GetBoolean("Renderer", "use_frame_limit", true);
- Settings::values.frame_limit =
- static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100));
- Settings::values.use_disk_shader_cache =
- sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false);
+ Settings::values.vulkan_device.SetValue(
+ sdl2_config->GetInteger("Renderer", "vulkan_device", 0));
+
+ Settings::values.aspect_ratio.SetValue(
+ static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)));
+ Settings::values.max_anisotropy.SetValue(
+ static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)));
+ Settings::values.use_frame_limit.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_frame_limit", true));
+ Settings::values.frame_limit.SetValue(
+ static_cast<u16>(sdl2_config->GetInteger("Renderer", "frame_limit", 100)));
+ Settings::values.use_disk_shader_cache.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false));
const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0);
- Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(gpu_accuracy_level);
- Settings::values.use_asynchronous_gpu_emulation =
- sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false);
- Settings::values.use_vsync =
- static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1));
- Settings::values.use_assembly_shaders =
- sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false);
- Settings::values.use_fast_gpu_time =
- sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true);
-
- Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0));
- Settings::values.bg_green =
- static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0));
- Settings::values.bg_blue = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0));
+ Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
+ Settings::values.use_asynchronous_gpu_emulation.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false));
+ Settings::values.use_vsync.SetValue(
+ static_cast<u16>(sdl2_config->GetInteger("Renderer", "use_vsync", 1)));
+ Settings::values.use_assembly_shaders.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_assembly_shaders", false));
+ Settings::values.use_fast_gpu_time.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
+
+ Settings::values.bg_red.SetValue(
+ static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
+ Settings::values.bg_green.SetValue(
+ static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
+ Settings::values.bg_blue.SetValue(
+ static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
// Audio
Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
- Settings::values.enable_audio_stretching =
- sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);
+ Settings::values.enable_audio_stretching.SetValue(
+ sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true));
Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto");
- Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1));
+ Settings::values.volume.SetValue(
+ static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)));
// Miscellaneous
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
@@ -428,8 +428,6 @@ void Config::ReadValues() {
Settings::values.reporting_services =
sdl2_config->GetBoolean("Debugging", "reporting_services", false);
Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false);
- Settings::values.disable_cpu_opt =
- sdl2_config->GetBoolean("Debugging", "disable_cpu_opt", false);
Settings::values.disable_macro_jit =
sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false);
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=
# 0 (default): Disabled, 1: Enabled
use_multi_core=
+[Cpu]
+# Enable inline page tables optimization (faster guest memory access)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_page_tables =
+
+# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_block_linking =
+
+# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_return_stack_buffer =
+
+# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_fast_dispatcher =
+
+# Enable context elimination CPU Optimization (reduce host memory use for guest context)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_context_elimination =
+
+# Enable constant propagation CPU optimization (basic IR optimization)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_const_prop =
+
+# Enable miscellaneous CPU optimizations (basic IR optimization)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_misc_ir =
+
+# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_reduce_misalign_checks =
+
[Renderer]
# Which backend API to use.
# 0 (default): OpenGL, 1: Vulkan
@@ -283,9 +316,6 @@ dump_nso=false
# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
# false: Retail/Normal Mode (default), true: Kiosk Mode
quest_flag =
-# Determines whether or not JIT CPU optimizations are enabled
-# false: Optimizations Enabled, true: Optimizations Disabled
-disable_cpu_opt =
# Enables/Disables the macro JIT compiler
disable_macro_jit=false
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
void EmuWindow_SDL2_GL::Present() {
SDL_GL_MakeCurrent(render_window, window_context);
- SDL_GL_SetSwapInterval(Settings::values.use_vsync ? 1 : 0);
+ SDL_GL_SetSwapInterval(Settings::values.use_vsync.GetValue() ? 1 : 0);
while (IsOpen()) {
system.Renderer().TryPresent(100);
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) {
Core::System& system{Core::System::GetInstance()};
std::unique_ptr<EmuWindow_SDL2> emu_window;
- switch (Settings::values.renderer_backend) {
+ switch (Settings::values.renderer_backend.GetValue()) {
case Settings::RendererBackend::OpenGL:
emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen);
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() {
Settings::values.touchscreen.diameter_x = 15;
Settings::values.touchscreen.diameter_y = 15;
+ Settings::values.use_docked_mode =
+ sdl2_config->GetBoolean("Controls", "use_docked_mode", false);
+
// Data Storage
Settings::values.use_virtual_sd =
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
@@ -92,57 +95,59 @@ void Config::ReadValues() {
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
// System
- Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
-
Settings::values.current_user = std::clamp<int>(
sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1);
const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
if (rng_seed_enabled) {
- Settings::values.rng_seed = sdl2_config->GetInteger("System", "rng_seed", 0);
+ Settings::values.rng_seed.SetValue(sdl2_config->GetInteger("System", "rng_seed", 0));
} else {
- Settings::values.rng_seed = std::nullopt;
+ Settings::values.rng_seed.SetValue(std::nullopt);
}
const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
if (custom_rtc_enabled) {
- Settings::values.custom_rtc =
- std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0));
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)));
} else {
- Settings::values.custom_rtc = std::nullopt;
+ Settings::values.custom_rtc.SetValue(std::nullopt);
}
// Core
- Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false);
+ Settings::values.use_multi_core.SetValue(
+ sdl2_config->GetBoolean("Core", "use_multi_core", false));
// Renderer
- Settings::values.aspect_ratio =
- static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0));
- Settings::values.max_anisotropy =
- static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0));
- Settings::values.use_frame_limit = false;
- Settings::values.frame_limit = 100;
- Settings::values.use_disk_shader_cache =
- sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false);
+ Settings::values.aspect_ratio.SetValue(
+ static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0)));
+ Settings::values.max_anisotropy.SetValue(
+ static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0)));
+ Settings::values.use_frame_limit.SetValue(false);
+ Settings::values.frame_limit.SetValue(100);
+ Settings::values.use_disk_shader_cache.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false));
const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0);
- Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(gpu_accuracy_level);
- Settings::values.use_asynchronous_gpu_emulation =
- sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false);
- Settings::values.use_fast_gpu_time =
- sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true);
-
- Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0));
- Settings::values.bg_green =
- static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0));
- Settings::values.bg_blue = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0));
+ Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level));
+ Settings::values.use_asynchronous_gpu_emulation.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false));
+ Settings::values.use_fast_gpu_time.SetValue(
+ sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true));
+
+ Settings::values.bg_red.SetValue(
+ static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0)));
+ Settings::values.bg_green.SetValue(
+ static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0)));
+ Settings::values.bg_blue.SetValue(
+ static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)));
// Audio
Settings::values.sink_id = "null";
- Settings::values.enable_audio_stretching = false;
+ Settings::values.enable_audio_stretching.SetValue(false);
Settings::values.audio_device_id = "auto";
- Settings::values.volume = 0;
+ Settings::values.volume.SetValue(0);
- Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1);
+ Settings::values.language_index.SetValue(
+ sdl2_config->GetInteger("System", "language_index", 1));
// Miscellaneous
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"(
# 0 (default): Disabled, 1: Enabled
use_multi_core=
+[Cpu]
+# Enable inline page tables optimization (faster guest memory access)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_page_tables =
+
+# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_block_linking =
+
+# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_return_stack_buffer =
+
+# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_fast_dispatcher =
+
+# Enable context elimination CPU Optimization (reduce host memory use for guest context)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_context_elimination =
+
+# Enable constant propagation CPU optimization (basic IR optimization)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_const_prop =
+
+# Enable miscellaneous CPU optimizations (basic IR optimization)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_misc_ir =
+
+# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_reduce_misalign_checks =
+
[Renderer]
# Whether to use software or hardware rendering.
# 0: Software, 1 (default): Hardware