summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/command_generator.cpp3
-rw-r--r--src/audio_core/mix_context.cpp2
-rw-r--r--src/audio_core/voice_context.cpp2
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/alignment.h28
-rw-r--r--src/common/div_ceil.h8
-rw-r--r--src/common/fs/path_util.cpp27
-rw-r--r--src/common/host_memory.cpp2
-rw-r--r--src/common/intrusive_red_black_tree.h17
-rw-r--r--src/common/logging/backend.cpp3
-rw-r--r--src/common/logging/log.h6
-rw-r--r--src/common/logging/log_entry.h28
-rw-r--r--src/common/logging/text_formatter.cpp1
-rw-r--r--src/common/logging/types.h17
-rw-r--r--src/common/param_package.cpp1
-rw-r--r--src/common/settings.cpp2
-rw-r--r--src/common/settings.h7
-rw-r--r--src/common/string_util.cpp12
-rw-r--r--src/common/string_util.h2
-rw-r--r--src/common/uuid.h7
-rw-r--r--src/common/vector_math.h4
-rw-r--r--src/core/CMakeLists.txt17
-rw-r--r--src/core/core.cpp115
-rw-r--r--src/core/core.h73
-rw-r--r--src/core/file_sys/program_metadata.cpp2
-rw-r--r--src/core/file_sys/vfs_libzip.cpp88
-rw-r--r--src/core/file_sys/vfs_libzip.h13
-rw-r--r--src/core/frontend/applets/profile_select.cpp3
-rw-r--r--src/core/hle/ipc_helpers.h3
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp1
-rw-r--r--src/core/hle/kernel/hle_ipc.h2
-rw-r--r--src/core/hle/kernel/k_auto_object_container.cpp2
-rw-r--r--src/core/hle/kernel/k_handle_table.cpp2
-rw-r--r--src/core/hle/kernel/k_page_table.cpp2
-rw-r--r--src/core/hle/kernel/k_priority_queue.h27
-rw-r--r--src/core/hle/kernel/k_process.cpp54
-rw-r--r--src/core/hle/kernel/k_process.h4
-rw-r--r--src/core/hle/kernel/k_scheduler.h2
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h15
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h2
-rw-r--r--src/core/hle/kernel/k_shared_memory_info.h46
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/core/hle/kernel/svc.cpp14
-rw-r--r--src/core/hle/service/acc/acc.cpp3
-rw-r--r--src/core/hle/service/acc/async_context.cpp17
-rw-r--r--src/core/hle/service/acc/async_context.h7
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp9
-rw-r--r--src/core/hle/service/am/am.cpp123
-rw-r--r--src/core/hle/service/am/am.h32
-rw-r--r--src/core/hle/service/am/applet_ae.h2
-rw-r--r--src/core/hle/service/am/applet_oe.h2
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.cpp2
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.cpp10
-rw-r--r--src/core/hle/service/am/applets/applets.cpp41
-rw-r--r--src/core/hle/service/am/applets/applets.h10
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp31
-rw-r--r--src/core/hle/service/aoc/aoc_u.h6
-rw-r--r--src/core/hle/service/audio/audctl.cpp8
-rw-r--r--src/core/hle/service/audio/audin_u.cpp81
-rw-r--r--src/core/hle/service/audio/audin_u.h16
-rw-r--r--src/core/hle/service/audio/audout_u.cpp33
-rw-r--r--src/core/hle/service/audio/audren_u.cpp45
-rw-r--r--src/core/hle/service/audio/audren_u.h6
-rw-r--r--src/core/hle/service/audio/hwopus.cpp1
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp22
-rw-r--r--src/core/hle/service/bcat/backend/backend.h10
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp548
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.h64
-rw-r--r--src/core/hle/service/bcat/bcat_module.cpp11
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp22
-rw-r--r--src/core/hle/service/btm/btm.cpp43
-rw-r--r--src/core/hle/service/caps/caps.h3
-rw-r--r--src/core/hle/service/caps/caps_ss.cpp1
-rw-r--r--src/core/hle/service/es/es.cpp6
-rw-r--r--src/core/hle/service/fgm/fgm.cpp1
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.cpp1
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.cpp1
-rw-r--r--src/core/hle/service/friend/friend.cpp26
-rw-r--r--src/core/hle/service/glue/arp.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/npad.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp15
-rw-r--r--src/core/hle/service/lbl/lbl.cpp2
-rw-r--r--src/core/hle/service/mii/mii.cpp1
-rw-r--r--src/core/hle/service/nfc/nfc.cpp1
-rw-r--r--src/core/hle/service/nfp/nfp.cpp49
-rw-r--r--src/core/hle/service/nfp/nfp.h11
-rw-r--r--src/core/hle/service/nifm/nifm.cpp32
-rw-r--r--src/core/hle/service/nim/nim.cpp25
-rw-r--r--src/core/hle/service/npns/npns.cpp1
-rw-r--r--src/core/hle/service/ns/ns.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp13
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h2
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp29
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h11
-rw-r--r--src/core/hle/service/olsc/olsc.cpp1
-rw-r--r--src/core/hle/service/ptm/psm.cpp24
-rw-r--r--src/core/hle/service/set/set_sys.cpp1
-rw-r--r--src/core/hle/service/sockets/bsd.cpp14
-rw-r--r--src/core/hle/service/sockets/bsd.h3
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h1
-rw-r--r--src/core/hle/service/sockets/sockets.h6
-rw-r--r--src/core/hle/service/spl/spl_module.cpp2
-rw-r--r--src/core/hle/service/ssl/ssl.cpp1
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.cpp14
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h7
-rw-r--r--src/core/hle/service/time/system_clock_context_update_callback.h1
-rw-r--r--src/core/hle/service/time/system_clock_core.cpp2
-rw-r--r--src/core/hle/service/time/system_clock_core.h2
-rw-r--r--src/core/hle/service/time/time.cpp2
-rw-r--r--src/core/hle/service/time/time.h1
-rw-r--r--src/core/hle/service/time/time_manager.cpp13
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp4
-rw-r--r--src/core/hle/service/usb/usb.cpp7
-rw-r--r--src/core/hle/service/vi/vi.cpp13
-rw-r--r--src/core/hle/service/vi/vi.h1
-rw-r--r--src/core/memory.cpp6
-rw-r--r--src/core/network/network.cpp2
-rw-r--r--src/input_common/main.cpp4
-rw-r--r--src/input_common/sdl/sdl_impl.cpp25
-rw-r--r--src/input_common/udp/client.cpp74
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp4
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp3
-rw-r--r--src/shader_recompiler/object_pool.h6
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h7
-rw-r--r--src/video_core/cdma_pusher.cpp1
-rw-r--r--src/video_core/cdma_pusher.h2
-rw-r--r--src/video_core/command_classes/codecs/h264.cpp7
-rw-r--r--src/video_core/command_classes/vic.cpp259
-rw-r--r--src/video_core/command_classes/vic.h20
-rw-r--r--src/video_core/engines/maxwell_3d.h1
-rw-r--r--src/video_core/engines/maxwell_dma.cpp64
-rw-r--r--src/video_core/engines/maxwell_dma.h2
-rw-r--r--src/video_core/framebuffer_config.h20
-rw-r--r--src/video_core/gpu.cpp1215
-rw-r--r--src/video_core/gpu.h227
-rw-r--r--src/video_core/gpu_thread.h3
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt1
-rw-r--r--src/video_core/host_shaders/opengl_copy_bgra.comp15
-rw-r--r--src/video_core/query_cache.h9
-rw-r--r--src/video_core/rasterizer_accelerated.h2
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp38
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h23
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h4
-rw-r--r--src/video_core/renderer_opengl/util_shaders.cpp76
-rw-r--r--src/video_core/renderer_opengl/util_shaders.h22
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp13
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp16
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.h17
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h2
-rw-r--r--src/video_core/shader_environment.cpp1
-rw-r--r--src/video_core/shader_environment.h4
-rw-r--r--src/video_core/texture_cache/image_view_info.cpp1
-rw-r--r--src/video_core/texture_cache/slot_vector.h4
-rw-r--r--src/video_core/texture_cache/texture_cache.h5
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h8
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp25
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h6
-rw-r--r--src/yuzu/CMakeLists.txt4
-rw-r--r--src/yuzu/about_dialog.cpp3
-rw-r--r--src/yuzu/applets/qt_controller.cpp26
-rw-r--r--src/yuzu/applets/qt_controller.h6
-rw-r--r--src/yuzu/applets/qt_web_browser.cpp4
-rw-r--r--src/yuzu/bootmanager.cpp23
-rw-r--r--src/yuzu/bootmanager.h23
-rw-r--r--src/yuzu/compatdb.cpp14
-rw-r--r--src/yuzu/compatdb.h5
-rw-r--r--src/yuzu/configuration/config.cpp20
-rw-r--r--src/yuzu/configuration/config.h8
-rw-r--r--src/yuzu/configuration/configure.ui200
-rw-r--r--src/yuzu/configuration/configure_audio.cpp6
-rw-r--r--src/yuzu/configuration/configure_audio.h10
-rw-r--r--src/yuzu/configuration/configure_audio.ui3
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp5
-rw-r--r--src/yuzu/configuration/configure_cpu.h11
-rw-r--r--src/yuzu/configuration/configure_cpu.ui5
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.cpp6
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.h8
-rw-r--r--src/yuzu/configuration/configure_cpu_debug.ui3
-rw-r--r--src/yuzu/configuration/configure_debug.cpp5
-rw-r--r--src/yuzu/configuration/configure_debug.h8
-rw-r--r--src/yuzu/configuration/configure_debug.ui181
-rw-r--r--src/yuzu/configuration/configure_debug_controller.cpp5
-rw-r--r--src/yuzu/configuration/configure_debug_controller.h6
-rw-r--r--src/yuzu/configuration/configure_debug_tab.cpp16
-rw-r--r--src/yuzu/configuration/configure_debug_tab.h12
-rw-r--r--src/yuzu/configuration/configure_debug_tab.ui29
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp109
-rw-r--r--src/yuzu/configuration/configure_dialog.h38
-rw-r--r--src/yuzu/configuration/configure_filesystem.ui3
-rw-r--r--src/yuzu/configuration/configure_general.cpp6
-rw-r--r--src/yuzu/configuration/configure_general.h11
-rw-r--r--src/yuzu/configuration/configure_general.ui3
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp6
-rw-r--r--src/yuzu/configuration/configure_graphics.h11
-rw-r--r--src/yuzu/configuration/configure_graphics.ui11
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp6
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h11
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui3
-rw-r--r--src/yuzu/configuration/configure_hotkeys.ui3
-rw-r--r--src/yuzu/configuration/configure_input.cpp44
-rw-r--r--src/yuzu/configuration/configure_input.h10
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp4
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp18
-rw-r--r--src/yuzu/configuration/configure_input_player.h9
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp4
-rw-r--r--src/yuzu/configuration/configure_input_profile_dialog.cpp7
-rw-r--r--src/yuzu/configuration/configure_input_profile_dialog.h6
-rw-r--r--src/yuzu/configuration/configure_network.cpp123
-rw-r--r--src/yuzu/configuration/configure_network.h9
-rw-r--r--src/yuzu/configuration/configure_network.ui89
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp66
-rw-r--r--src/yuzu/configuration/configure_per_game.h25
-rw-r--r--src/yuzu/configuration/configure_per_game.ui104
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.cpp7
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.h8
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.ui3
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp10
-rw-r--r--src/yuzu/configuration/configure_profile_manager.h8
-rw-r--r--src/yuzu/configuration/configure_profile_manager.ui5
-rw-r--r--src/yuzu/configuration/configure_system.cpp21
-rw-r--r--src/yuzu/configuration/configure_system.h11
-rw-r--r--src/yuzu/configuration/configure_system.ui3
-rw-r--r--src/yuzu/configuration/configure_tas.cpp1
-rw-r--r--src/yuzu/configuration/configure_tas.ui355
-rw-r--r--src/yuzu/configuration/configure_ui.cpp5
-rw-r--r--src/yuzu/configuration/configure_ui.h8
-rw-r--r--src/yuzu/configuration/configure_ui.ui5
-rw-r--r--src/yuzu/configuration/configure_web.ui36
-rw-r--r--src/yuzu/configuration/input_profiles.cpp9
-rw-r--r--src/yuzu/configuration/input_profiles.h8
-rw-r--r--src/yuzu/debugger/profiler.cpp12
-rw-r--r--src/yuzu/debugger/wait_tree.cpp79
-rw-r--r--src/yuzu/debugger/wait_tree.h47
-rw-r--r--src/yuzu/discord_impl.cpp9
-rw-r--r--src/yuzu/discord_impl.h8
-rw-r--r--src/yuzu/game_list.cpp10
-rw-r--r--src/yuzu/game_list.h5
-rw-r--r--src/yuzu/game_list_worker.cpp10
-rw-r--r--src/yuzu/game_list_worker.h8
-rw-r--r--src/yuzu/main.cpp530
-rw-r--r--src/yuzu/main.h21
-rw-r--r--src/yuzu/main.ui48
-rw-r--r--src/yuzu/uisettings.h2
-rw-r--r--src/yuzu_cmd/config.cpp8
-rw-r--r--src/yuzu_cmd/default_ini.h9
-rw-r--r--src/yuzu_cmd/yuzu.cpp21
253 files changed, 3487 insertions, 3773 deletions
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index 45b2eef52..830af46ad 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -2,13 +2,16 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <cmath> 6#include <cmath>
6#include <numbers> 7#include <numbers>
8
7#include "audio_core/algorithm/interpolate.h" 9#include "audio_core/algorithm/interpolate.h"
8#include "audio_core/command_generator.h" 10#include "audio_core/command_generator.h"
9#include "audio_core/effect_context.h" 11#include "audio_core/effect_context.h"
10#include "audio_core/mix_context.h" 12#include "audio_core/mix_context.h"
11#include "audio_core/voice_context.h" 13#include "audio_core/voice_context.h"
14#include "common/common_types.h"
12#include "core/memory.h" 15#include "core/memory.h"
13 16
14namespace AudioCore { 17namespace AudioCore {
diff --git a/src/audio_core/mix_context.cpp b/src/audio_core/mix_context.cpp
index 4bca72eb0..057aab5ad 100644
--- a/src/audio_core/mix_context.cpp
+++ b/src/audio_core/mix_context.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6
5#include "audio_core/behavior_info.h" 7#include "audio_core/behavior_info.h"
6#include "audio_core/common.h" 8#include "audio_core/common.h"
7#include "audio_core/effect_context.h" 9#include "audio_core/effect_context.h"
diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp
index d8c954b60..75012a887 100644
--- a/src/audio_core/voice_context.cpp
+++ b/src/audio_core/voice_context.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6
5#include "audio_core/behavior_info.h" 7#include "audio_core/behavior_info.h"
6#include "audio_core/voice_context.h" 8#include "audio_core/voice_context.h"
7#include "core/memory.h" 9#include "core/memory.h"
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index b18a2a2f5..cb5c0f326 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -79,6 +79,7 @@ add_library(common STATIC
79 logging/filter.cpp 79 logging/filter.cpp
80 logging/filter.h 80 logging/filter.h
81 logging/log.h 81 logging/log.h
82 logging/log_entry.h
82 logging/text_formatter.cpp 83 logging/text_formatter.cpp
83 logging/text_formatter.h 84 logging/text_formatter.h
84 logging/types.h 85 logging/types.h
diff --git a/src/common/alignment.h b/src/common/alignment.h
index 32d796ffa..8570c7d3c 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -9,41 +9,48 @@
9namespace Common { 9namespace Common {
10 10
11template <typename T> 11template <typename T>
12requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUp(T value, size_t size) { 12requires std::is_unsigned_v<T>
13[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
13 auto mod{static_cast<T>(value % size)}; 14 auto mod{static_cast<T>(value % size)};
14 value -= mod; 15 value -= mod;
15 return static_cast<T>(mod == T{0} ? value : value + size); 16 return static_cast<T>(mod == T{0} ? value : value + size);
16} 17}
17 18
18template <typename T> 19template <typename T>
19requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) { 20requires std::is_unsigned_v<T>
21[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
20 return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2); 22 return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
21} 23}
22 24
23template <typename T> 25template <typename T>
24requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignDown(T value, size_t size) { 26requires std::is_unsigned_v<T>
27[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
25 return static_cast<T>(value - value % size); 28 return static_cast<T>(value - value % size);
26} 29}
27 30
28template <typename T> 31template <typename T>
29requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool Is4KBAligned(T value) { 32requires std::is_unsigned_v<T>
33[[nodiscard]] constexpr bool Is4KBAligned(T value) {
30 return (value & 0xFFF) == 0; 34 return (value & 0xFFF) == 0;
31} 35}
32 36
33template <typename T> 37template <typename T>
34requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool IsWordAligned(T value) { 38requires std::is_unsigned_v<T>
39[[nodiscard]] constexpr bool IsWordAligned(T value) {
35 return (value & 0b11) == 0; 40 return (value & 0b11) == 0;
36} 41}
37 42
38template <typename T> 43template <typename T>
39requires std::is_integral_v<T>[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) { 44requires std::is_integral_v<T>
45[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
40 using U = typename std::make_unsigned_t<T>; 46 using U = typename std::make_unsigned_t<T>;
41 const U mask = static_cast<U>(alignment - 1); 47 const U mask = static_cast<U>(alignment - 1);
42 return (value & mask) == 0; 48 return (value & mask) == 0;
43} 49}
44 50
45template <typename T, typename U> 51template <typename T, typename U>
46requires std::is_integral_v<T>[[nodiscard]] constexpr T DivideUp(T x, U y) { 52requires std::is_integral_v<T>
53[[nodiscard]] constexpr T DivideUp(T x, U y) {
47 return (x + (y - 1)) / y; 54 return (x + (y - 1)) / y;
48} 55}
49 56
@@ -57,7 +64,7 @@ public:
57 using propagate_on_container_copy_assignment = std::true_type; 64 using propagate_on_container_copy_assignment = std::true_type;
58 using propagate_on_container_move_assignment = std::true_type; 65 using propagate_on_container_move_assignment = std::true_type;
59 using propagate_on_container_swap = std::true_type; 66 using propagate_on_container_swap = std::true_type;
60 using is_always_equal = std::true_type; 67 using is_always_equal = std::false_type;
61 68
62 constexpr AlignmentAllocator() noexcept = default; 69 constexpr AlignmentAllocator() noexcept = default;
63 70
@@ -76,6 +83,11 @@ public:
76 struct rebind { 83 struct rebind {
77 using other = AlignmentAllocator<T2, Align>; 84 using other = AlignmentAllocator<T2, Align>;
78 }; 85 };
86
87 template <typename T2, size_t Align2>
88 constexpr bool operator==(const AlignmentAllocator<T2, Align2>&) const noexcept {
89 return std::is_same_v<T, T2> && Align == Align2;
90 }
79}; 91};
80 92
81} // namespace Common 93} // namespace Common
diff --git a/src/common/div_ceil.h b/src/common/div_ceil.h
index 95e1489a9..e1db35464 100644
--- a/src/common/div_ceil.h
+++ b/src/common/div_ceil.h
@@ -11,15 +11,15 @@ namespace Common {
11 11
12/// Ceiled integer division. 12/// Ceiled integer division.
13template <typename N, typename D> 13template <typename N, typename D>
14requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeil(N number, 14requires std::is_integral_v<N> && std::is_unsigned_v<D>
15 D divisor) { 15[[nodiscard]] constexpr N DivCeil(N number, D divisor) {
16 return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor); 16 return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
17} 17}
18 18
19/// Ceiled integer division with logarithmic divisor in base 2 19/// Ceiled integer division with logarithmic divisor in base 2
20template <typename N, typename D> 20template <typename N, typename D>
21requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeilLog2( 21requires std::is_integral_v<N> && std::is_unsigned_v<D>
22 N value, D alignment_log2) { 22[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
23 return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2); 23 return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
24} 24}
25 25
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index 43b79bd6d..1bcb897b5 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -82,32 +82,35 @@ public:
82 82
83private: 83private:
84 PathManagerImpl() { 84 PathManagerImpl() {
85 fs::path yuzu_path;
86 fs::path yuzu_path_cache;
87 fs::path yuzu_path_config;
88
85#ifdef _WIN32 89#ifdef _WIN32
86 auto yuzu_path = GetExeDirectory() / PORTABLE_DIR; 90 yuzu_path = GetExeDirectory() / PORTABLE_DIR;
87 91
88 if (!IsDir(yuzu_path)) { 92 if (!IsDir(yuzu_path)) {
89 yuzu_path = GetAppDataRoamingDirectory() / YUZU_DIR; 93 yuzu_path = GetAppDataRoamingDirectory() / YUZU_DIR;
90 } 94 }
91 95
92 GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path); 96 yuzu_path_cache = yuzu_path / CACHE_DIR;
93 GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path / CACHE_DIR); 97 yuzu_path_config = yuzu_path / CONFIG_DIR;
94 GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path / CONFIG_DIR);
95#else 98#else
96 auto yuzu_path = GetCurrentDir() / PORTABLE_DIR; 99 yuzu_path = GetCurrentDir() / PORTABLE_DIR;
97 100
98 if (Exists(yuzu_path) && IsDir(yuzu_path)) { 101 if (Exists(yuzu_path) && IsDir(yuzu_path)) {
99 GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path); 102 yuzu_path_cache = yuzu_path / CACHE_DIR;
100 GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path / CACHE_DIR); 103 yuzu_path_config = yuzu_path / CONFIG_DIR;
101 GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path / CONFIG_DIR);
102 } else { 104 } else {
103 yuzu_path = GetDataDirectory("XDG_DATA_HOME") / YUZU_DIR; 105 yuzu_path = GetDataDirectory("XDG_DATA_HOME") / YUZU_DIR;
104 106 yuzu_path_cache = GetDataDirectory("XDG_CACHE_HOME") / YUZU_DIR;
105 GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path); 107 yuzu_path_config = GetDataDirectory("XDG_CONFIG_HOME") / YUZU_DIR;
106 GenerateYuzuPath(YuzuPath::CacheDir, GetDataDirectory("XDG_CACHE_HOME") / YUZU_DIR);
107 GenerateYuzuPath(YuzuPath::ConfigDir, GetDataDirectory("XDG_CONFIG_HOME") / YUZU_DIR);
108 } 108 }
109#endif 109#endif
110 110
111 GenerateYuzuPath(YuzuPath::YuzuDir, yuzu_path);
112 GenerateYuzuPath(YuzuPath::CacheDir, yuzu_path_cache);
113 GenerateYuzuPath(YuzuPath::ConfigDir, yuzu_path_config);
111 GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR); 114 GenerateYuzuPath(YuzuPath::DumpDir, yuzu_path / DUMP_DIR);
112 GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR); 115 GenerateYuzuPath(YuzuPath::KeysDir, yuzu_path / KEYS_DIR);
113 GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR); 116 GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 6661244cf..b44a44949 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -314,8 +314,8 @@ private:
314 } 314 }
315 315
316 void UntrackPlaceholder(boost::icl::separate_interval_set<size_t>::iterator it) { 316 void UntrackPlaceholder(boost::icl::separate_interval_set<size_t>::iterator it) {
317 placeholders.erase(it);
318 placeholder_host_pointers.erase(it->lower()); 317 placeholder_host_pointers.erase(it->lower());
318 placeholders.erase(it);
319 } 319 }
320 320
321 /// Return true when a given memory region is a "nieche" and the placeholders don't have to be 321 /// Return true when a given memory region is a "nieche" and the placeholders don't have to be
diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h
index 1f696fe80..3173cc449 100644
--- a/src/common/intrusive_red_black_tree.h
+++ b/src/common/intrusive_red_black_tree.h
@@ -235,20 +235,19 @@ public:
235 235
236template <typename T> 236template <typename T>
237concept HasLightCompareType = requires { 237concept HasLightCompareType = requires {
238 { std::is_same<typename T::LightCompareType, void>::value } 238 { std::is_same<typename T::LightCompareType, void>::value } -> std::convertible_to<bool>;
239 ->std::convertible_to<bool>;
240}; 239};
241 240
242namespace impl { 241namespace impl {
243 242
244template <typename T, typename Default> 243 template <typename T, typename Default>
245consteval auto* GetLightCompareType() { 244 consteval auto* GetLightCompareType() {
246 if constexpr (HasLightCompareType<T>) { 245 if constexpr (HasLightCompareType<T>) {
247 return static_cast<typename T::LightCompareType*>(nullptr); 246 return static_cast<typename T::LightCompareType*>(nullptr);
248 } else { 247 } else {
249 return static_cast<Default*>(nullptr); 248 return static_cast<Default*>(nullptr);
249 }
250 } 250 }
251}
252 251
253} // namespace impl 252} // namespace impl
254 253
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index e40d117d6..0e85a9c1d 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -9,6 +9,8 @@
9#include <thread> 9#include <thread>
10#include <vector> 10#include <vector>
11 11
12#include <fmt/format.h>
13
12#ifdef _WIN32 14#ifdef _WIN32
13#include <windows.h> // For OutputDebugStringW 15#include <windows.h> // For OutputDebugStringW
14#endif 16#endif
@@ -22,6 +24,7 @@
22 24
23#include "common/logging/backend.h" 25#include "common/logging/backend.h"
24#include "common/logging/log.h" 26#include "common/logging/log.h"
27#include "common/logging/log_entry.h"
25#include "common/logging/text_formatter.h" 28#include "common/logging/text_formatter.h"
26#include "common/settings.h" 29#include "common/settings.h"
27#ifdef _WIN32 30#ifdef _WIN32
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 8d43eddc7..c186d55ef 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -4,7 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <fmt/format.h> 7#include <algorithm>
8#include <string_view>
9
10#include <fmt/core.h>
11
8#include "common/logging/types.h" 12#include "common/logging/types.h"
9 13
10namespace Common::Log { 14namespace Common::Log {
diff --git a/src/common/logging/log_entry.h b/src/common/logging/log_entry.h
new file mode 100644
index 000000000..dd6f44841
--- /dev/null
+++ b/src/common/logging/log_entry.h
@@ -0,0 +1,28 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <chrono>
8
9#include "common/logging/types.h"
10
11namespace Common::Log {
12
13/**
14 * A log entry. Log entries are store in a structured format to permit more varied output
15 * formatting on different frontends, as well as facilitating filtering and aggregation.
16 */
17struct Entry {
18 std::chrono::microseconds timestamp;
19 Class log_class{};
20 Level log_level{};
21 const char* filename = nullptr;
22 unsigned int line_num = 0;
23 std::string function;
24 std::string message;
25 bool final_entry = false;
26};
27
28} // namespace Common::Log
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
index cfc0d5846..10b2281db 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -13,6 +13,7 @@
13#include "common/common_funcs.h" 13#include "common/common_funcs.h"
14#include "common/logging/filter.h" 14#include "common/logging/filter.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/logging/log_entry.h"
16#include "common/logging/text_formatter.h" 17#include "common/logging/text_formatter.h"
17#include "common/string_util.h" 18#include "common/string_util.h"
18 19
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index ddf9d27ca..2d21fc483 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -4,8 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <chrono>
8
9#include "common/common_types.h" 7#include "common/common_types.h"
10 8
11namespace Common::Log { 9namespace Common::Log {
@@ -131,19 +129,4 @@ enum class Class : u8 {
131 Count ///< Total number of logging classes 129 Count ///< Total number of logging classes
132}; 130};
133 131
134/**
135 * A log entry. Log entries are store in a structured format to permit more varied output
136 * formatting on different frontends, as well as facilitating filtering and aggregation.
137 */
138struct Entry {
139 std::chrono::microseconds timestamp;
140 Class log_class{};
141 Level log_level{};
142 const char* filename = nullptr;
143 unsigned int line_num = 0;
144 std::string function;
145 std::string message;
146 bool final_entry = false;
147};
148
149} // namespace Common::Log 132} // namespace Common::Log
diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp
index b916b4866..bbf20f5eb 100644
--- a/src/common/param_package.cpp
+++ b/src/common/param_package.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array> 5#include <array>
6#include <stdexcept>
6#include <utility> 7#include <utility>
7#include <vector> 8#include <vector>
8 9
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 69f0bd8c0..9dd5e3efb 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -69,8 +69,6 @@ void LogSettings() {
69 log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir)); 69 log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
70 log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir)); 70 log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
71 log_setting("Debugging_ProgramArgs", values.program_args.GetValue()); 71 log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
72 log_setting("Services_BCATBackend", values.bcat_backend.GetValue());
73 log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local.GetValue());
74 log_setting("Input_EnableMotion", values.motion_enabled.GetValue()); 72 log_setting("Input_EnableMotion", values.motion_enabled.GetValue());
75 log_setting("Input_EnableVibration", values.vibration_enabled.GetValue()); 73 log_setting("Input_EnableVibration", values.vibration_enabled.GetValue());
76 log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue()); 74 log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue());
diff --git a/src/common/settings.h b/src/common/settings.h
index c53d5acc3..9ff4cf85d 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -7,7 +7,6 @@
7#include <algorithm> 7#include <algorithm>
8#include <array> 8#include <array>
9#include <atomic> 9#include <atomic>
10#include <chrono>
11#include <map> 10#include <map>
12#include <optional> 11#include <optional>
13#include <string> 12#include <string>
@@ -487,9 +486,9 @@ struct Values {
487 // System 486 // System
488 Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"}; 487 Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
489 // Measured in seconds since epoch 488 // Measured in seconds since epoch
490 std::optional<std::chrono::seconds> custom_rtc; 489 std::optional<s64> custom_rtc;
491 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 490 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
492 std::chrono::seconds custom_rtc_differential; 491 s64 custom_rtc_differential;
493 492
494 BasicSetting<s32> current_user{0, "current_user"}; 493 BasicSetting<s32> current_user{0, "current_user"};
495 RangedSetting<s32> language_index{1, 0, 17, "language_index"}; 494 RangedSetting<s32> language_index{1, 0, 17, "language_index"};
@@ -568,8 +567,6 @@ struct Values {
568 BasicSetting<bool> use_dev_keys{false, "use_dev_keys"}; 567 BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
569 568
570 // Network 569 // Network
571 BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
572 BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
573 BasicSetting<std::string> network_interface{std::string(), "network_interface"}; 570 BasicSetting<std::string> network_interface{std::string(), "network_interface"};
574 571
575 // WebService 572 // WebService
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index e6344fd41..662171138 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -180,20 +180,20 @@ std::wstring UTF8ToUTF16W(const std::string& input) {
180 180
181#endif 181#endif
182 182
183std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len) { 183std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len) {
184 std::size_t len = 0; 184 std::size_t len = 0;
185 while (len < max_len && buffer[len] != '\0') 185 while (len < buffer.length() && len < max_len && buffer[len] != '\0') {
186 ++len; 186 ++len;
187 187 }
188 return std::string(buffer, len); 188 return std::string(buffer.begin(), buffer.begin() + len);
189} 189}
190 190
191std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, 191std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
192 std::size_t max_len) { 192 std::size_t max_len) {
193 std::size_t len = 0; 193 std::size_t len = 0;
194 while (len < max_len && buffer[len] != '\0') 194 while (len < buffer.length() && len < max_len && buffer[len] != '\0') {
195 ++len; 195 ++len;
196 196 }
197 return std::u16string(buffer.begin(), buffer.begin() + len); 197 return std::u16string(buffer.begin(), buffer.begin() + len);
198} 198}
199 199
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 7e90a9ca5..f0dd632ee 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -63,7 +63,7 @@ template <typename InIt>
63 * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't 63 * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
64 * NUL-terminated then the string ends at max_len characters. 64 * NUL-terminated then the string ends at max_len characters.
65 */ 65 */
66[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, 66[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer,
67 std::size_t max_len); 67 std::size_t max_len);
68 68
69/** 69/**
diff --git a/src/common/uuid.h b/src/common/uuid.h
index 2353179d8..8ea01f8da 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -58,6 +58,13 @@ struct UUID {
58 uuid = INVALID_UUID; 58 uuid = INVALID_UUID;
59 } 59 }
60 60
61 [[nodiscard]] constexpr bool IsInvalid() const {
62 return uuid == INVALID_UUID;
63 }
64 [[nodiscard]] constexpr bool IsValid() const {
65 return !IsInvalid();
66 }
67
61 // TODO(ogniK): Properly generate a Nintendo ID 68 // TODO(ogniK): Properly generate a Nintendo ID
62 [[nodiscard]] constexpr u64 GetNintendoID() const { 69 [[nodiscard]] constexpr u64 GetNintendoID() const {
63 return uuid[0]; 70 return uuid[0];
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 22dba3c2d..ba7c363c1 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -667,8 +667,8 @@ template <typename T>
667 667
668// linear interpolation via float: 0.0=begin, 1.0=end 668// linear interpolation via float: 0.0=begin, 1.0=end
669template <typename X> 669template <typename X>
670[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, 670[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{})
671 const float t) { 671 Lerp(const X& begin, const X& end, const float t) {
672 return begin * (1.f - t) + end * t; 672 return begin * (1.f - t) + end * t;
673} 673}
674 674
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7140d0db8..9f0fbba2d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -106,8 +106,6 @@ add_library(core STATIC
106 file_sys/vfs_concat.h 106 file_sys/vfs_concat.h
107 file_sys/vfs_layered.cpp 107 file_sys/vfs_layered.cpp
108 file_sys/vfs_layered.h 108 file_sys/vfs_layered.h
109 file_sys/vfs_libzip.cpp
110 file_sys/vfs_libzip.h
111 file_sys/vfs_offset.cpp 109 file_sys/vfs_offset.cpp
112 file_sys/vfs_offset.h 110 file_sys/vfs_offset.h
113 file_sys/vfs_real.cpp 111 file_sys/vfs_real.cpp
@@ -218,6 +216,7 @@ add_library(core STATIC
218 hle/kernel/k_session.h 216 hle/kernel/k_session.h
219 hle/kernel/k_shared_memory.cpp 217 hle/kernel/k_shared_memory.cpp
220 hle/kernel/k_shared_memory.h 218 hle/kernel/k_shared_memory.h
219 hle/kernel/k_shared_memory_info.h
221 hle/kernel/k_slab_heap.h 220 hle/kernel/k_slab_heap.h
222 hle/kernel/k_spin_lock.cpp 221 hle/kernel/k_spin_lock.cpp
223 hle/kernel/k_spin_lock.h 222 hle/kernel/k_spin_lock.h
@@ -653,13 +652,6 @@ add_library(core STATIC
653 tools/freezer.h 652 tools/freezer.h
654) 653)
655 654
656if (YUZU_ENABLE_BOXCAT)
657 target_sources(core PRIVATE
658 hle/service/bcat/backend/boxcat.cpp
659 hle/service/bcat/backend/boxcat.h
660 )
661endif()
662
663if (MSVC) 655if (MSVC)
664 target_compile_options(core PRIVATE 656 target_compile_options(core PRIVATE
665 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data 657 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
@@ -690,12 +682,7 @@ endif()
690create_target_directory_groups(core) 682create_target_directory_groups(core)
691 683
692target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 684target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
693target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus zip) 685target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus)
694
695if (YUZU_ENABLE_BOXCAT)
696 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
697 target_link_libraries(core PRIVATE httplib nlohmann_json::nlohmann_json)
698endif()
699 686
700if (ENABLE_WEB_SERVICE) 687if (ENABLE_WEB_SERVICE)
701 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) 688 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 54ebed2c1..3c75f42ae 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -139,27 +139,47 @@ struct System::Impl {
139 : kernel{system}, fs_controller{system}, memory{system}, 139 : kernel{system}, fs_controller{system}, memory{system},
140 cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} 140 cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
141 141
142 ResultStatus Run() { 142 SystemResultStatus Run() {
143 status = ResultStatus::Success; 143 std::unique_lock<std::mutex> lk(suspend_guard);
144 status = SystemResultStatus::Success;
144 145
145 kernel.Suspend(false); 146 kernel.Suspend(false);
146 core_timing.SyncPause(false); 147 core_timing.SyncPause(false);
147 cpu_manager.Pause(false); 148 cpu_manager.Pause(false);
149 is_paused = false;
148 150
149 return status; 151 return status;
150 } 152 }
151 153
152 ResultStatus Pause() { 154 SystemResultStatus Pause() {
153 status = ResultStatus::Success; 155 std::unique_lock<std::mutex> lk(suspend_guard);
156 status = SystemResultStatus::Success;
154 157
155 core_timing.SyncPause(true); 158 core_timing.SyncPause(true);
156 kernel.Suspend(true); 159 kernel.Suspend(true);
157 cpu_manager.Pause(true); 160 cpu_manager.Pause(true);
161 is_paused = true;
158 162
159 return status; 163 return status;
160 } 164 }
161 165
162 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { 166 std::unique_lock<std::mutex> StallCPU() {
167 std::unique_lock<std::mutex> lk(suspend_guard);
168 kernel.Suspend(true);
169 core_timing.SyncPause(true);
170 cpu_manager.Pause(true);
171 return lk;
172 }
173
174 void UnstallCPU() {
175 if (!is_paused) {
176 core_timing.SyncPause(false);
177 kernel.Suspend(false);
178 cpu_manager.Pause(false);
179 }
180 }
181
182 SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
163 LOG_DEBUG(Core, "initialized OK"); 183 LOG_DEBUG(Core, "initialized OK");
164 184
165 device_memory = std::make_unique<Core::DeviceMemory>(); 185 device_memory = std::make_unique<Core::DeviceMemory>();
@@ -176,8 +196,9 @@ struct System::Impl {
176 cpu_manager.Initialize(); 196 cpu_manager.Initialize();
177 core_timing.Initialize([&system]() { system.RegisterHostThread(); }); 197 core_timing.Initialize([&system]() { system.RegisterHostThread(); });
178 198
179 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 199 const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
180 std::chrono::system_clock::now().time_since_epoch()); 200 const auto current_time =
201 std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
181 Settings::values.custom_rtc_differential = 202 Settings::values.custom_rtc_differential =
182 Settings::values.custom_rtc.value_or(current_time) - current_time; 203 Settings::values.custom_rtc.value_or(current_time) - current_time;
183 204
@@ -197,7 +218,7 @@ struct System::Impl {
197 218
198 gpu_core = VideoCore::CreateGPU(emu_window, system); 219 gpu_core = VideoCore::CreateGPU(emu_window, system);
199 if (!gpu_core) { 220 if (!gpu_core) {
200 return ResultStatus::ErrorVideoCore; 221 return SystemResultStatus::ErrorVideoCore;
201 } 222 }
202 223
203 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); 224 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
@@ -217,21 +238,22 @@ struct System::Impl {
217 238
218 LOG_DEBUG(Core, "Initialized OK"); 239 LOG_DEBUG(Core, "Initialized OK");
219 240
220 return ResultStatus::Success; 241 return SystemResultStatus::Success;
221 } 242 }
222 243
223 ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, 244 SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
224 u64 program_id, std::size_t program_index) { 245 const std::string& filepath, u64 program_id,
246 std::size_t program_index) {
225 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), 247 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
226 program_id, program_index); 248 program_id, program_index);
227 249
228 if (!app_loader) { 250 if (!app_loader) {
229 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); 251 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
230 return ResultStatus::ErrorGetLoader; 252 return SystemResultStatus::ErrorGetLoader;
231 } 253 }
232 254
233 ResultStatus init_result{Init(system, emu_window)}; 255 SystemResultStatus init_result{Init(system, emu_window)};
234 if (init_result != ResultStatus::Success) { 256 if (init_result != SystemResultStatus::Success) {
235 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", 257 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
236 static_cast<int>(init_result)); 258 static_cast<int>(init_result));
237 Shutdown(); 259 Shutdown();
@@ -249,8 +271,8 @@ struct System::Impl {
249 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); 271 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
250 Shutdown(); 272 Shutdown();
251 273
252 return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + 274 return static_cast<SystemResultStatus>(
253 static_cast<u32>(load_result)); 275 static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
254 } 276 }
255 AddGlueRegistrationForProcess(*app_loader, *main_process); 277 AddGlueRegistrationForProcess(*app_loader, *main_process);
256 kernel.MakeCurrentProcess(main_process.get()); 278 kernel.MakeCurrentProcess(main_process.get());
@@ -282,7 +304,7 @@ struct System::Impl {
282 GetAndResetPerfStats(); 304 GetAndResetPerfStats();
283 perf_stats->BeginSystemFrame(); 305 perf_stats->BeginSystemFrame();
284 306
285 status = ResultStatus::Success; 307 status = SystemResultStatus::Success;
286 return status; 308 return status;
287 } 309 }
288 310
@@ -305,7 +327,6 @@ struct System::Impl {
305 is_powered_on = false; 327 is_powered_on = false;
306 exit_lock = false; 328 exit_lock = false;
307 329
308 gpu_core.reset();
309 services.reset(); 330 services.reset();
310 service_manager.reset(); 331 service_manager.reset();
311 cheat_engine.reset(); 332 cheat_engine.reset();
@@ -315,6 +336,7 @@ struct System::Impl {
315 core_timing.Shutdown(); 336 core_timing.Shutdown();
316 app_loader.reset(); 337 app_loader.reset();
317 perf_stats.reset(); 338 perf_stats.reset();
339 gpu_core.reset();
318 kernel.Shutdown(); 340 kernel.Shutdown();
319 memory.Reset(); 341 memory.Reset();
320 applet_manager.ClearAll(); 342 applet_manager.ClearAll();
@@ -355,7 +377,7 @@ struct System::Impl {
355 arp_manager.Register(launch.title_id, launch, std::move(nacp_data)); 377 arp_manager.Register(launch.title_id, launch, std::move(nacp_data));
356 } 378 }
357 379
358 void SetStatus(ResultStatus new_status, const char* details = nullptr) { 380 void SetStatus(SystemResultStatus new_status, const char* details = nullptr) {
359 status = new_status; 381 status = new_status;
360 if (details) { 382 if (details) {
361 status_details = details; 383 status_details = details;
@@ -366,6 +388,9 @@ struct System::Impl {
366 return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs()); 388 return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs());
367 } 389 }
368 390
391 std::mutex suspend_guard;
392 bool is_paused{};
393
369 Timing::CoreTiming core_timing; 394 Timing::CoreTiming core_timing;
370 Kernel::KernelCore kernel; 395 Kernel::KernelCore kernel;
371 /// RealVfsFilesystem instance 396 /// RealVfsFilesystem instance
@@ -411,7 +436,7 @@ struct System::Impl {
411 /// Network instance 436 /// Network instance
412 Network::NetworkInstance network_instance; 437 Network::NetworkInstance network_instance;
413 438
414 ResultStatus status = ResultStatus::Success; 439 SystemResultStatus status = SystemResultStatus::Success;
415 std::string status_details = ""; 440 std::string status_details = "";
416 441
417 std::unique_ptr<Core::PerfStats> perf_stats; 442 std::unique_ptr<Core::PerfStats> perf_stats;
@@ -421,27 +446,15 @@ struct System::Impl {
421 bool is_async_gpu{}; 446 bool is_async_gpu{};
422 447
423 ExecuteProgramCallback execute_program_callback; 448 ExecuteProgramCallback execute_program_callback;
449 ExitCallback exit_callback;
424 450
425 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; 451 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
426 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; 452 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
427}; 453};
428 454
429System::System() : impl{std::make_unique<Impl>(*this)} {} 455System::System() : impl{std::make_unique<Impl>(*this)} {}
430System::~System() = default;
431
432System& System::GetInstance() {
433 if (!s_instance) {
434 throw std::runtime_error("Using System instance before its initialization");
435 }
436 return *s_instance;
437}
438 456
439void System::InitializeGlobalInstance() { 457System::~System() = default;
440 if (s_instance) {
441 throw std::runtime_error("Reinitializing Global System instance.");
442 }
443 s_instance = std::unique_ptr<System>(new System);
444}
445 458
446CpuManager& System::GetCpuManager() { 459CpuManager& System::GetCpuManager() {
447 return impl->cpu_manager; 460 return impl->cpu_manager;
@@ -451,16 +464,16 @@ const CpuManager& System::GetCpuManager() const {
451 return impl->cpu_manager; 464 return impl->cpu_manager;
452} 465}
453 466
454System::ResultStatus System::Run() { 467SystemResultStatus System::Run() {
455 return impl->Run(); 468 return impl->Run();
456} 469}
457 470
458System::ResultStatus System::Pause() { 471SystemResultStatus System::Pause() {
459 return impl->Pause(); 472 return impl->Pause();
460} 473}
461 474
462System::ResultStatus System::SingleStep() { 475SystemResultStatus System::SingleStep() {
463 return ResultStatus::Success; 476 return SystemResultStatus::Success;
464} 477}
465 478
466void System::InvalidateCpuInstructionCaches() { 479void System::InvalidateCpuInstructionCaches() {
@@ -475,8 +488,16 @@ void System::Shutdown() {
475 impl->Shutdown(); 488 impl->Shutdown();
476} 489}
477 490
478System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, 491std::unique_lock<std::mutex> System::StallCPU() {
479 u64 program_id, std::size_t program_index) { 492 return impl->StallCPU();
493}
494
495void System::UnstallCPU() {
496 impl->UnstallCPU();
497}
498
499SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
500 u64 program_id, std::size_t program_index) {
480 return impl->Load(*this, emu_window, filepath, program_id, program_index); 501 return impl->Load(*this, emu_window, filepath, program_id, program_index);
481} 502}
482 503
@@ -636,7 +657,7 @@ Loader::ResultStatus System::GetGameName(std::string& out) const {
636 return impl->GetGameName(out); 657 return impl->GetGameName(out);
637} 658}
638 659
639void System::SetStatus(ResultStatus new_status, const char* details) { 660void System::SetStatus(SystemResultStatus new_status, const char* details) {
640 impl->SetStatus(new_status, details); 661 impl->SetStatus(new_status, details);
641} 662}
642 663
@@ -798,6 +819,18 @@ void System::ExecuteProgram(std::size_t program_index) {
798 } 819 }
799} 820}
800 821
822void System::RegisterExitCallback(ExitCallback&& callback) {
823 impl->exit_callback = std::move(callback);
824}
825
826void System::Exit() {
827 if (impl->exit_callback) {
828 impl->exit_callback();
829 } else {
830 LOG_CRITICAL(Core, "exit_callback must be initialized by the frontend");
831 }
832}
833
801void System::ApplySettings() { 834void System::ApplySettings() {
802 if (IsPoweredOn()) { 835 if (IsPoweredOn()) {
803 Renderer().RefreshBaseSettings(); 836 Renderer().RefreshBaseSettings();
diff --git a/src/core/core.h b/src/core/core.h
index 715ab88e7..1cfe1bba6 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -7,6 +7,7 @@
7#include <cstddef> 7#include <cstddef>
8#include <functional> 8#include <functional>
9#include <memory> 9#include <memory>
10#include <mutex>
10#include <string> 11#include <string>
11#include <vector> 12#include <vector>
12 13
@@ -104,55 +105,49 @@ struct PerfStatsResults;
104FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, 105FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
105 const std::string& path); 106 const std::string& path);
106 107
108/// Enumeration representing the return values of the System Initialize and Load process.
109enum class SystemResultStatus : u32 {
110 Success, ///< Succeeded
111 ErrorNotInitialized, ///< Error trying to use core prior to initialization
112 ErrorGetLoader, ///< Error finding the correct application loader
113 ErrorSystemFiles, ///< Error in finding system files
114 ErrorSharedFont, ///< Error in finding shared font
115 ErrorVideoCore, ///< Error in the video core
116 ErrorUnknown, ///< Any other error
117 ErrorLoader, ///< The base for loader errors (too many to repeat)
118};
119
107class System { 120class System {
108public: 121public:
109 using CurrentBuildProcessID = std::array<u8, 0x20>; 122 using CurrentBuildProcessID = std::array<u8, 0x20>;
110 123
124 explicit System();
125
126 ~System();
127
111 System(const System&) = delete; 128 System(const System&) = delete;
112 System& operator=(const System&) = delete; 129 System& operator=(const System&) = delete;
113 130
114 System(System&&) = delete; 131 System(System&&) = delete;
115 System& operator=(System&&) = delete; 132 System& operator=(System&&) = delete;
116 133
117 ~System();
118
119 /**
120 * Gets the instance of the System singleton class.
121 * @returns Reference to the instance of the System singleton class.
122 */
123 [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance();
124
125 static void InitializeGlobalInstance();
126
127 /// Enumeration representing the return values of the System Initialize and Load process.
128 enum class ResultStatus : u32 {
129 Success, ///< Succeeded
130 ErrorNotInitialized, ///< Error trying to use core prior to initialization
131 ErrorGetLoader, ///< Error finding the correct application loader
132 ErrorSystemFiles, ///< Error in finding system files
133 ErrorSharedFont, ///< Error in finding shared font
134 ErrorVideoCore, ///< Error in the video core
135 ErrorUnknown, ///< Any other error
136 ErrorLoader, ///< The base for loader errors (too many to repeat)
137 };
138
139 /** 134 /**
140 * Run the OS and Application 135 * Run the OS and Application
141 * This function will start emulation and run the relevant devices 136 * This function will start emulation and run the relevant devices
142 */ 137 */
143 [[nodiscard]] ResultStatus Run(); 138 [[nodiscard]] SystemResultStatus Run();
144 139
145 /** 140 /**
146 * Pause the OS and Application 141 * Pause the OS and Application
147 * This function will pause emulation and stop the relevant devices 142 * This function will pause emulation and stop the relevant devices
148 */ 143 */
149 [[nodiscard]] ResultStatus Pause(); 144 [[nodiscard]] SystemResultStatus Pause();
150 145
151 /** 146 /**
152 * Step the CPU one instruction 147 * Step the CPU one instruction
153 * @return Result status, indicating whether or not the operation succeeded. 148 * @return Result status, indicating whether or not the operation succeeded.
154 */ 149 */
155 [[nodiscard]] ResultStatus SingleStep(); 150 [[nodiscard]] SystemResultStatus SingleStep();
156 151
157 /** 152 /**
158 * Invalidate the CPU instruction caches 153 * Invalidate the CPU instruction caches
@@ -166,16 +161,20 @@ public:
166 /// Shutdown the emulated system. 161 /// Shutdown the emulated system.
167 void Shutdown(); 162 void Shutdown();
168 163
164 std::unique_lock<std::mutex> StallCPU();
165 void UnstallCPU();
166
169 /** 167 /**
170 * Load an executable application. 168 * Load an executable application.
171 * @param emu_window Reference to the host-system window used for video output and keyboard 169 * @param emu_window Reference to the host-system window used for video output and keyboard
172 * input. 170 * input.
173 * @param filepath String path to the executable application to load on the host file system. 171 * @param filepath String path to the executable application to load on the host file system.
174 * @param program_index Specifies the index within the container of the program to launch. 172 * @param program_index Specifies the index within the container of the program to launch.
175 * @returns ResultStatus code, indicating if the operation succeeded. 173 * @returns SystemResultStatus code, indicating if the operation succeeded.
176 */ 174 */
177 [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath, 175 [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window,
178 u64 program_id = 0, std::size_t program_index = 0); 176 const std::string& filepath, u64 program_id = 0,
177 std::size_t program_index = 0);
179 178
180 /** 179 /**
181 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an 180 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@@ -301,7 +300,7 @@ public:
301 /// Gets the name of the current game 300 /// Gets the name of the current game
302 [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const; 301 [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
303 302
304 void SetStatus(ResultStatus new_status, const char* details); 303 void SetStatus(SystemResultStatus new_status, const char* details);
305 304
306 [[nodiscard]] const std::string& GetStatusDetails() const; 305 [[nodiscard]] const std::string& GetStatusDetails() const;
307 306
@@ -387,16 +386,24 @@ public:
387 */ 386 */
388 void ExecuteProgram(std::size_t program_index); 387 void ExecuteProgram(std::size_t program_index);
389 388
389 /// Type used for the frontend to designate a callback for System to exit the application.
390 using ExitCallback = std::function<void()>;
391
392 /**
393 * Registers a callback from the frontend for System to exit the application.
394 * @param callback Callback from the frontend to exit the application.
395 */
396 void RegisterExitCallback(ExitCallback&& callback);
397
398 /// Instructs the frontend to exit the application.
399 void Exit();
400
390 /// Applies any changes to settings to this core instance. 401 /// Applies any changes to settings to this core instance.
391 void ApplySettings(); 402 void ApplySettings();
392 403
393private: 404private:
394 System();
395
396 struct Impl; 405 struct Impl;
397 std::unique_ptr<Impl> impl; 406 std::unique_ptr<Impl> impl;
398
399 inline static std::unique_ptr<System> s_instance{};
400}; 407};
401 408
402} // namespace Core 409} // namespace Core
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 01ae1a567..35a53d36c 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -77,7 +77,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address
77 aci_header.title_id = title_id; 77 aci_header.title_id = title_id;
78 aci_file_access.permissions = filesystem_permissions; 78 aci_file_access.permissions = filesystem_permissions;
79 npdm_header.system_resource_size = system_resource_size; 79 npdm_header.system_resource_size = system_resource_size;
80 aci_kernel_capabilities = std ::move(capabilities); 80 aci_kernel_capabilities = std::move(capabilities);
81} 81}
82 82
83bool ProgramMetadata::Is64BitProgram() const { 83bool ProgramMetadata::Is64BitProgram() const {
diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp
deleted file mode 100644
index 00e256779..000000000
--- a/src/core/file_sys/vfs_libzip.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6
7#ifdef __GNUC__
8#pragma GCC diagnostic push
9#pragma GCC diagnostic ignored "-Wshadow"
10#endif
11#include <zip.h>
12#ifdef __GNUC__
13#pragma GCC diagnostic pop
14#endif
15
16#include "common/fs/path_util.h"
17#include "core/file_sys/vfs.h"
18#include "core/file_sys/vfs_libzip.h"
19#include "core/file_sys/vfs_vector.h"
20
21namespace FileSys {
22
23VirtualDir ExtractZIP(VirtualFile file) {
24 zip_error_t error{};
25
26 const auto data = file->ReadAllBytes();
27 std::unique_ptr<zip_source_t, decltype(&zip_source_close)> src{
28 zip_source_buffer_create(data.data(), data.size(), 0, &error), zip_source_close};
29 if (src == nullptr)
30 return nullptr;
31
32 std::unique_ptr<zip_t, decltype(&zip_close)> zip{zip_open_from_source(src.get(), 0, &error),
33 zip_close};
34 if (zip == nullptr)
35 return nullptr;
36
37 std::shared_ptr<VectorVfsDirectory> out = std::make_shared<VectorVfsDirectory>();
38
39 const auto num_entries = static_cast<std::size_t>(zip_get_num_entries(zip.get(), 0));
40
41 zip_stat_t stat{};
42 zip_stat_init(&stat);
43
44 for (std::size_t i = 0; i < num_entries; ++i) {
45 const auto stat_res = zip_stat_index(zip.get(), i, 0, &stat);
46 if (stat_res == -1)
47 return nullptr;
48
49 const std::string name(stat.name);
50 if (name.empty())
51 continue;
52
53 if (name.back() != '/') {
54 std::unique_ptr<zip_file_t, decltype(&zip_fclose)> file2{
55 zip_fopen_index(zip.get(), i, 0), zip_fclose};
56
57 std::vector<u8> buf(stat.size);
58 if (zip_fread(file2.get(), buf.data(), buf.size()) != s64(buf.size()))
59 return nullptr;
60
61 const auto parts = Common::FS::SplitPathComponents(stat.name);
62 const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back());
63
64 std::shared_ptr<VectorVfsDirectory> dtrv = out;
65 for (std::size_t j = 0; j < parts.size() - 1; ++j) {
66 if (dtrv == nullptr)
67 return nullptr;
68 const auto subdir = dtrv->GetSubdirectory(parts[j]);
69 if (subdir == nullptr) {
70 const auto temp = std::make_shared<VectorVfsDirectory>(
71 std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parts[j]);
72 dtrv->AddDirectory(temp);
73 dtrv = temp;
74 } else {
75 dtrv = std::dynamic_pointer_cast<VectorVfsDirectory>(subdir);
76 }
77 }
78
79 if (dtrv == nullptr)
80 return nullptr;
81 dtrv->AddFile(new_file);
82 }
83 }
84
85 return out;
86}
87
88} // namespace FileSys
diff --git a/src/core/file_sys/vfs_libzip.h b/src/core/file_sys/vfs_libzip.h
deleted file mode 100644
index f68af576a..000000000
--- a/src/core/file_sys/vfs_libzip.h
+++ /dev/null
@@ -1,13 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/file_sys/vfs_types.h"
8
9namespace FileSys {
10
11VirtualDir ExtractZIP(VirtualFile zip);
12
13} // namespace FileSys
diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp
index 4c58c310f..3e4f90be2 100644
--- a/src/core/frontend/applets/profile_select.cpp
+++ b/src/core/frontend/applets/profile_select.cpp
@@ -13,7 +13,8 @@ ProfileSelectApplet::~ProfileSelectApplet() = default;
13void DefaultProfileSelectApplet::SelectProfile( 13void DefaultProfileSelectApplet::SelectProfile(
14 std::function<void(std::optional<Common::UUID>)> callback) const { 14 std::function<void(std::optional<Common::UUID>)> callback) const {
15 Service::Account::ProfileManager manager; 15 Service::Account::ProfileManager manager;
16 callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{})); 16 callback(manager.GetUser(Settings::values.current_user.GetValue())
17 .value_or(Common::UUID{Common::INVALID_UUID}));
17 LOG_INFO(Service_ACC, "called, selecting current user instead of prompting..."); 18 LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
18} 19}
19 20
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index ceff2532d..cf204f570 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -4,17 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <cstring> 7#include <cstring>
9#include <memory> 8#include <memory>
10#include <tuple>
11#include <type_traits> 9#include <type_traits>
12#include <utility> 10#include <utility>
13#include "common/assert.h" 11#include "common/assert.h"
14#include "common/common_types.h" 12#include "common/common_types.h"
15#include "core/hle/ipc.h" 13#include "core/hle/ipc.h"
16#include "core/hle/kernel/hle_ipc.h" 14#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/k_client_port.h"
18#include "core/hle/kernel/k_process.h" 15#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_resource_limit.h" 16#include "core/hle/kernel/k_resource_limit.h"
20#include "core/hle/kernel/k_session.h" 17#include "core/hle/kernel/k_session.h"
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index ca68fc325..cee96dd9b 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -15,6 +15,7 @@
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "core/hle/ipc_helpers.h" 16#include "core/hle/ipc_helpers.h"
17#include "core/hle/kernel/hle_ipc.h" 17#include "core/hle/kernel/hle_ipc.h"
18#include "core/hle/kernel/k_auto_object.h"
18#include "core/hle/kernel/k_handle_table.h" 19#include "core/hle/kernel/k_handle_table.h"
19#include "core/hle/kernel/k_process.h" 20#include "core/hle/kernel/k_process.h"
20#include "core/hle/kernel/k_readable_event.h" 21#include "core/hle/kernel/k_readable_event.h"
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index a61870f8b..55e6fb9f7 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -17,7 +17,6 @@
17#include "common/concepts.h" 17#include "common/concepts.h"
18#include "common/swap.h" 18#include "common/swap.h"
19#include "core/hle/ipc.h" 19#include "core/hle/ipc.h"
20#include "core/hle/kernel/k_auto_object.h"
21#include "core/hle/kernel/svc_common.h" 20#include "core/hle/kernel/svc_common.h"
22 21
23union ResultCode; 22union ResultCode;
@@ -38,6 +37,7 @@ namespace Kernel {
38 37
39class Domain; 38class Domain;
40class HLERequestContext; 39class HLERequestContext;
40class KAutoObject;
41class KernelCore; 41class KernelCore;
42class KHandleTable; 42class KHandleTable;
43class KProcess; 43class KProcess;
diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp
index 010006bb7..d5f80d5b2 100644
--- a/src/core/hle/kernel/k_auto_object_container.cpp
+++ b/src/core/hle/kernel/k_auto_object_container.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6
5#include "core/hle/kernel/k_auto_object_container.h" 7#include "core/hle/kernel/k_auto_object_container.h"
6 8
7namespace Kernel { 9namespace Kernel {
diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp
index 6a420d5b0..44d13169f 100644
--- a/src/core/hle/kernel/k_handle_table.cpp
+++ b/src/core/hle/kernel/k_handle_table.cpp
@@ -7,7 +7,7 @@
7namespace Kernel { 7namespace Kernel {
8 8
9KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {} 9KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
10KHandleTable ::~KHandleTable() = default; 10KHandleTable::~KHandleTable() = default;
11 11
12ResultCode KHandleTable::Finalize() { 12ResultCode KHandleTable::Finalize() {
13 // Get the table and clear our record of it. 13 // Get the table and clear our record of it.
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 701268545..5e0b620c2 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -363,6 +363,8 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st
363 block_manager->Update(src_addr, num_pages, KMemoryState::Normal, 363 block_manager->Update(src_addr, num_pages, KMemoryState::Normal,
364 KMemoryPermission::ReadAndWrite); 364 KMemoryPermission::ReadAndWrite);
365 365
366 system.InvalidateCpuInstructionCacheRange(dst_addr, size);
367
366 return ResultSuccess; 368 return ResultSuccess;
367} 369}
368 370
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h
index 4aa669d95..f4d71ad7e 100644
--- a/src/core/hle/kernel/k_priority_queue.h
+++ b/src/core/hle/kernel/k_priority_queue.h
@@ -22,12 +22,10 @@ class KThread;
22 22
23template <typename T> 23template <typename T>
24concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) { 24concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
25 { t.GetAffinityMask() } 25 { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
26 ->Common::ConvertibleTo<u64>;
27 {t.SetAffinityMask(0)}; 26 {t.SetAffinityMask(0)};
28 27
29 { t.GetAffinity(0) } 28 { t.GetAffinity(0) } -> std::same_as<bool>;
30 ->std::same_as<bool>;
31 {t.SetAffinity(0, false)}; 29 {t.SetAffinity(0, false)};
32 {t.SetAll()}; 30 {t.SetAll()};
33}; 31};
@@ -38,25 +36,20 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
38 {(typename T::QueueEntry()).Initialize()}; 36 {(typename T::QueueEntry()).Initialize()};
39 {(typename T::QueueEntry()).SetPrev(std::addressof(t))}; 37 {(typename T::QueueEntry()).SetPrev(std::addressof(t))};
40 {(typename T::QueueEntry()).SetNext(std::addressof(t))}; 38 {(typename T::QueueEntry()).SetNext(std::addressof(t))};
41 { (typename T::QueueEntry()).GetNext() } 39 { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
42 ->std::same_as<T*>; 40 { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
43 { (typename T::QueueEntry()).GetPrev() } 41 { t.GetPriorityQueueEntry(0) } -> std::same_as<typename T::QueueEntry&>;
44 ->std::same_as<T*>;
45 { t.GetPriorityQueueEntry(0) }
46 ->std::same_as<typename T::QueueEntry&>;
47 42
48 {t.GetAffinityMask()}; 43 {t.GetAffinityMask()};
49 { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } 44 { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } -> KPriorityQueueAffinityMask;
50 ->KPriorityQueueAffinityMask;
51 45
52 { t.GetActiveCore() } 46 { t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
53 ->Common::ConvertibleTo<s32>; 47 { t.GetPriority() } -> Common::ConvertibleTo<s32>;
54 { t.GetPriority() }
55 ->Common::ConvertibleTo<s32>;
56}; 48};
57 49
58template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> 50template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
59requires KPriorityQueueMember<Member> class KPriorityQueue { 51requires KPriorityQueueMember<Member>
52class KPriorityQueue {
60public: 53public:
61 using AffinityMaskType = std::remove_cv_t< 54 using AffinityMaskType = std::remove_cv_t<
62 std::remove_reference_t<decltype(std::declval<Member>().GetAffinityMask())>>; 55 std::remove_reference_t<decltype(std::declval<Member>().GetAffinityMask())>>;
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 8ead1a769..211157ccc 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -23,6 +23,7 @@
23#include "core/hle/kernel/k_scheduler.h" 23#include "core/hle/kernel/k_scheduler.h"
24#include "core/hle/kernel/k_scoped_resource_reservation.h" 24#include "core/hle/kernel/k_scoped_resource_reservation.h"
25#include "core/hle/kernel/k_shared_memory.h" 25#include "core/hle/kernel/k_shared_memory.h"
26#include "core/hle/kernel/k_shared_memory_info.h"
26#include "core/hle/kernel/k_slab_heap.h" 27#include "core/hle/kernel/k_slab_heap.h"
27#include "core/hle/kernel/k_thread.h" 28#include "core/hle/kernel/k_thread.h"
28#include "core/hle/kernel/kernel.h" 29#include "core/hle/kernel/kernel.h"
@@ -254,10 +255,26 @@ ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAdd
254 // Lock ourselves, to prevent concurrent access. 255 // Lock ourselves, to prevent concurrent access.
255 KScopedLightLock lk(state_lock); 256 KScopedLightLock lk(state_lock);
256 257
257 // TODO(bunnei): Manage KSharedMemoryInfo list here. 258 // Try to find an existing info for the memory.
259 KSharedMemoryInfo* shemen_info = nullptr;
260 const auto iter = std::find_if(
261 shared_memory_list.begin(), shared_memory_list.end(),
262 [shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
263 if (iter != shared_memory_list.end()) {
264 shemen_info = *iter;
265 }
266
267 if (shemen_info == nullptr) {
268 shemen_info = KSharedMemoryInfo::Allocate(kernel);
269 R_UNLESS(shemen_info != nullptr, ResultOutOfMemory);
270
271 shemen_info->Initialize(shmem);
272 shared_memory_list.push_back(shemen_info);
273 }
258 274
259 // Open a reference to the shared memory. 275 // Open a reference to the shared memory and its info.
260 shmem->Open(); 276 shmem->Open();
277 shemen_info->Open();
261 278
262 return ResultSuccess; 279 return ResultSuccess;
263} 280}
@@ -267,7 +284,20 @@ void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr a
267 // Lock ourselves, to prevent concurrent access. 284 // Lock ourselves, to prevent concurrent access.
268 KScopedLightLock lk(state_lock); 285 KScopedLightLock lk(state_lock);
269 286
270 // TODO(bunnei): Manage KSharedMemoryInfo list here. 287 KSharedMemoryInfo* shemen_info = nullptr;
288 const auto iter = std::find_if(
289 shared_memory_list.begin(), shared_memory_list.end(),
290 [shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
291 if (iter != shared_memory_list.end()) {
292 shemen_info = *iter;
293 }
294
295 ASSERT(shemen_info != nullptr);
296
297 if (shemen_info->Close()) {
298 shared_memory_list.erase(iter);
299 KSharedMemoryInfo::Free(kernel, shemen_info);
300 }
271 301
272 // Close a reference to the shared memory. 302 // Close a reference to the shared memory.
273 shmem->Close(); 303 shmem->Close();
@@ -412,6 +442,24 @@ void KProcess::Finalize() {
412 // Finalize the handle table and close any open handles. 442 // Finalize the handle table and close any open handles.
413 handle_table.Finalize(); 443 handle_table.Finalize();
414 444
445 // Free all shared memory infos.
446 {
447 auto it = shared_memory_list.begin();
448 while (it != shared_memory_list.end()) {
449 KSharedMemoryInfo* info = *it;
450 KSharedMemory* shmem = info->GetSharedMemory();
451
452 while (!info->Close()) {
453 shmem->Close();
454 }
455
456 shmem->Close();
457
458 it = shared_memory_list.erase(it);
459 KSharedMemoryInfo::Free(kernel, info);
460 }
461 }
462
415 // Perform inherited finalization. 463 // Perform inherited finalization.
416 KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); 464 KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
417} 465}
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index a03c074fb..1a53e2be7 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -34,6 +34,7 @@ class KernelCore;
34class KPageTable; 34class KPageTable;
35class KResourceLimit; 35class KResourceLimit;
36class KThread; 36class KThread;
37class KSharedMemoryInfo;
37class TLSPage; 38class TLSPage;
38 39
39struct CodeSet; 40struct CodeSet;
@@ -448,6 +449,9 @@ private:
448 /// List of threads that are running with this process as their owner. 449 /// List of threads that are running with this process as their owner.
449 std::list<const KThread*> thread_list; 450 std::list<const KThread*> thread_list;
450 451
452 /// List of shared memory that are running with this process as their owner.
453 std::list<KSharedMemoryInfo*> shared_memory_list;
454
451 /// Address of the top of the main thread's stack 455 /// Address of the top of the main thread's stack
452 VAddr main_thread_stack_top{}; 456 VAddr main_thread_stack_top{};
453 457
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 12cfae919..c8ccc1ae4 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -197,7 +197,7 @@ private:
197 197
198class [[nodiscard]] KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> { 198class [[nodiscard]] KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
199public: 199public:
200 explicit KScopedSchedulerLock(KernelCore & kernel); 200 explicit KScopedSchedulerLock(KernelCore& kernel);
201 ~KScopedSchedulerLock(); 201 ~KScopedSchedulerLock();
202}; 202};
203 203
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
index 72c3b0252..4fb180fc6 100644
--- a/src/core/hle/kernel/k_scoped_lock.h
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -13,19 +13,18 @@ namespace Kernel {
13 13
14template <typename T> 14template <typename T>
15concept KLockable = !std::is_reference_v<T> && requires(T & t) { 15concept KLockable = !std::is_reference_v<T> && requires(T & t) {
16 { t.Lock() } 16 { t.Lock() } -> std::same_as<void>;
17 ->std::same_as<void>; 17 { t.Unlock() } -> std::same_as<void>;
18 { t.Unlock() }
19 ->std::same_as<void>;
20}; 18};
21 19
22template <typename T> 20template <typename T>
23requires KLockable<T> class [[nodiscard]] KScopedLock { 21requires KLockable<T>
22class [[nodiscard]] KScopedLock {
24public: 23public:
25 explicit KScopedLock(T * l) : lock_ptr(l) { 24 explicit KScopedLock(T* l) : lock_ptr(l) {
26 this->lock_ptr->Lock(); 25 this->lock_ptr->Lock();
27 } 26 }
28 explicit KScopedLock(T & l) : KScopedLock(std::addressof(l)) {} 27 explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) {}
29 28
30 ~KScopedLock() { 29 ~KScopedLock() {
31 this->lock_ptr->Unlock(); 30 this->lock_ptr->Unlock();
@@ -34,7 +33,7 @@ public:
34 KScopedLock(const KScopedLock&) = delete; 33 KScopedLock(const KScopedLock&) = delete;
35 KScopedLock& operator=(const KScopedLock&) = delete; 34 KScopedLock& operator=(const KScopedLock&) = delete;
36 35
37 KScopedLock(KScopedLock &&) = delete; 36 KScopedLock(KScopedLock&&) = delete;
38 KScopedLock& operator=(KScopedLock&&) = delete; 37 KScopedLock& operator=(KScopedLock&&) = delete;
39 38
40private: 39private:
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
index a86af56dd..f6c75f2d9 100644
--- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -17,7 +17,7 @@ namespace Kernel {
17 17
18class [[nodiscard]] KScopedSchedulerLockAndSleep { 18class [[nodiscard]] KScopedSchedulerLockAndSleep {
19public: 19public:
20 explicit KScopedSchedulerLockAndSleep(KernelCore & kernel_, KThread * t, s64 timeout) 20 explicit KScopedSchedulerLockAndSleep(KernelCore& kernel_, KThread* t, s64 timeout)
21 : kernel(kernel_), thread(t), timeout_tick(timeout) { 21 : kernel(kernel_), thread(t), timeout_tick(timeout) {
22 // Lock the scheduler. 22 // Lock the scheduler.
23 kernel.GlobalSchedulerContext().scheduler_lock.Lock(); 23 kernel.GlobalSchedulerContext().scheduler_lock.Lock();
diff --git a/src/core/hle/kernel/k_shared_memory_info.h b/src/core/hle/kernel/k_shared_memory_info.h
new file mode 100644
index 000000000..bf97a0184
--- /dev/null
+++ b/src/core/hle/kernel/k_shared_memory_info.h
@@ -0,0 +1,46 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10#include <boost/intrusive/list.hpp>
11
12#include "common/assert.h"
13#include "core/hle/kernel/slab_helpers.h"
14
15namespace Kernel {
16
17class KSharedMemory;
18
19class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>,
20 public boost::intrusive::list_base_hook<> {
21
22public:
23 explicit KSharedMemoryInfo() = default;
24
25 constexpr void Initialize(KSharedMemory* shmem) {
26 shared_memory = shmem;
27 }
28
29 constexpr KSharedMemory* GetSharedMemory() const {
30 return shared_memory;
31 }
32
33 constexpr void Open() {
34 ++reference_count;
35 }
36
37 constexpr bool Close() {
38 return (--reference_count) == 0;
39 }
40
41private:
42 KSharedMemory* shared_memory{};
43 size_t reference_count{};
44};
45
46} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 901d43da9..b6658b437 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -49,6 +49,7 @@ class KScheduler;
49class KServerSession; 49class KServerSession;
50class KSession; 50class KSession;
51class KSharedMemory; 51class KSharedMemory;
52class KSharedMemoryInfo;
52class KThread; 53class KThread;
53class KTransferMemory; 54class KTransferMemory;
54class KWritableEvent; 55class KWritableEvent;
@@ -309,6 +310,8 @@ public:
309 return slab_heap_container->session; 310 return slab_heap_container->session;
310 } else if constexpr (std::is_same_v<T, KSharedMemory>) { 311 } else if constexpr (std::is_same_v<T, KSharedMemory>) {
311 return slab_heap_container->shared_memory; 312 return slab_heap_container->shared_memory;
313 } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) {
314 return slab_heap_container->shared_memory_info;
312 } else if constexpr (std::is_same_v<T, KThread>) { 315 } else if constexpr (std::is_same_v<T, KThread>) {
313 return slab_heap_container->thread; 316 return slab_heap_container->thread;
314 } else if constexpr (std::is_same_v<T, KTransferMemory>) { 317 } else if constexpr (std::is_same_v<T, KTransferMemory>) {
@@ -362,6 +365,7 @@ private:
362 KSlabHeap<KResourceLimit> resource_limit; 365 KSlabHeap<KResourceLimit> resource_limit;
363 KSlabHeap<KSession> session; 366 KSlabHeap<KSession> session;
364 KSlabHeap<KSharedMemory> shared_memory; 367 KSlabHeap<KSharedMemory> shared_memory;
368 KSlabHeap<KSharedMemoryInfo> shared_memory_info;
365 KSlabHeap<KThread> thread; 369 KSlabHeap<KThread> thread;
366 KSlabHeap<KTransferMemory> transfer_memory; 370 KSlabHeap<KTransferMemory> transfer_memory;
367 KSlabHeap<KWritableEvent> writeable_event; 371 KSlabHeap<KWritableEvent> writeable_event;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 62fb06c45..f98f24a60 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -320,17 +320,19 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
320 320
321 auto& kernel = system.Kernel(); 321 auto& kernel = system.Kernel();
322 322
323 KScopedAutoObject session =
324 kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
325 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
326 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
327
328 auto thread = kernel.CurrentScheduler()->GetCurrentThread(); 323 auto thread = kernel.CurrentScheduler()->GetCurrentThread();
329 { 324 {
330 KScopedSchedulerLock lock(kernel); 325 KScopedSchedulerLock lock(kernel);
331 thread->SetState(ThreadState::Waiting); 326 thread->SetState(ThreadState::Waiting);
332 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); 327 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
333 session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); 328
329 {
330 KScopedAutoObject session =
331 kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
332 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
333 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
334 session->SendSyncRequest(thread, system.Memory(), system.CoreTiming());
335 }
334 } 336 }
335 337
336 KSynchronizationObject* dummy{}; 338 KSynchronizationObject* dummy{};
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 6d9ec0a8a..689b36056 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -929,8 +929,7 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
929 } 929 }
930 930
931 const auto user_list = profile_manager->GetAllUsers(); 931 const auto user_list = profile_manager->GetAllUsers();
932 if (std::all_of(user_list.begin(), user_list.end(), 932 if (std::ranges::all_of(user_list, [](const auto& user) { return user.IsInvalid(); })) {
933 [](const auto& user) { return user.uuid == Common::INVALID_UUID; })) {
934 rb.Push(ResultUnknown); // TODO(ogniK): Find the correct error code 933 rb.Push(ResultUnknown); // TODO(ogniK): Find the correct error code
935 rb.PushRaw<u128>(Common::INVALID_UUID); 934 rb.PushRaw<u128>(Common::INVALID_UUID);
936 return; 935 return;
diff --git a/src/core/hle/service/acc/async_context.cpp b/src/core/hle/service/acc/async_context.cpp
index 459323132..a49dfdec7 100644
--- a/src/core/hle/service/acc/async_context.cpp
+++ b/src/core/hle/service/acc/async_context.cpp
@@ -4,15 +4,12 @@
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/acc/async_context.h" 8#include "core/hle/service/acc/async_context.h"
8 9
9namespace Service::Account { 10namespace Service::Account {
10IAsyncContext::IAsyncContext(Core::System& system_) 11IAsyncContext::IAsyncContext(Core::System& system_)
11 : ServiceFramework{system_, "IAsyncContext"}, compeletion_event{system_.Kernel()} { 12 : ServiceFramework{system_, "IAsyncContext"}, service_context{system_, "IAsyncContext"} {
12
13 Kernel::KAutoObject::Create(std::addressof(compeletion_event));
14 compeletion_event.Initialize("IAsyncContext:CompletionEvent");
15
16 // clang-format off 13 // clang-format off
17 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
18 {0, &IAsyncContext::GetSystemEvent, "GetSystemEvent"}, 15 {0, &IAsyncContext::GetSystemEvent, "GetSystemEvent"},
@@ -23,6 +20,12 @@ IAsyncContext::IAsyncContext(Core::System& system_)
23 // clang-format on 20 // clang-format on
24 21
25 RegisterHandlers(functions); 22 RegisterHandlers(functions);
23
24 completion_event = service_context.CreateEvent("IAsyncContext:CompletionEvent");
25}
26
27IAsyncContext::~IAsyncContext() {
28 service_context.CloseEvent(completion_event);
26} 29}
27 30
28void IAsyncContext::GetSystemEvent(Kernel::HLERequestContext& ctx) { 31void IAsyncContext::GetSystemEvent(Kernel::HLERequestContext& ctx) {
@@ -30,7 +33,7 @@ void IAsyncContext::GetSystemEvent(Kernel::HLERequestContext& ctx) {
30 33
31 IPC::ResponseBuilder rb{ctx, 2, 1}; 34 IPC::ResponseBuilder rb{ctx, 2, 1};
32 rb.Push(ResultSuccess); 35 rb.Push(ResultSuccess);
33 rb.PushCopyObjects(compeletion_event.GetReadableEvent()); 36 rb.PushCopyObjects(completion_event->GetReadableEvent());
34} 37}
35 38
36void IAsyncContext::Cancel(Kernel::HLERequestContext& ctx) { 39void IAsyncContext::Cancel(Kernel::HLERequestContext& ctx) {
@@ -62,7 +65,7 @@ void IAsyncContext::GetResult(Kernel::HLERequestContext& ctx) {
62 65
63void IAsyncContext::MarkComplete() { 66void IAsyncContext::MarkComplete() {
64 is_complete.store(true); 67 is_complete.store(true);
65 compeletion_event.GetWritableEvent().Signal(); 68 completion_event->GetWritableEvent().Signal();
66} 69}
67 70
68} // namespace Service::Account 71} // namespace Service::Account
diff --git a/src/core/hle/service/acc/async_context.h b/src/core/hle/service/acc/async_context.h
index c694b4946..cc3a0a9fe 100644
--- a/src/core/hle/service/acc/async_context.h
+++ b/src/core/hle/service/acc/async_context.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <atomic> 7#include <atomic>
8#include "core/hle/kernel/k_event.h" 8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10 10
11namespace Core { 11namespace Core {
@@ -17,6 +17,7 @@ namespace Service::Account {
17class IAsyncContext : public ServiceFramework<IAsyncContext> { 17class IAsyncContext : public ServiceFramework<IAsyncContext> {
18public: 18public:
19 explicit IAsyncContext(Core::System& system_); 19 explicit IAsyncContext(Core::System& system_);
20 ~IAsyncContext() override;
20 21
21 void GetSystemEvent(Kernel::HLERequestContext& ctx); 22 void GetSystemEvent(Kernel::HLERequestContext& ctx);
22 void Cancel(Kernel::HLERequestContext& ctx); 23 void Cancel(Kernel::HLERequestContext& ctx);
@@ -30,8 +31,10 @@ protected:
30 31
31 void MarkComplete(); 32 void MarkComplete();
32 33
34 KernelHelpers::ServiceContext service_context;
35
33 std::atomic<bool> is_complete{false}; 36 std::atomic<bool> is_complete{false};
34 Kernel::KEvent compeletion_event; 37 Kernel::KEvent* completion_event;
35}; 38};
36 39
37} // namespace Service::Account 40} // namespace Service::Account
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 24a1c9157..568303ced 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -208,9 +208,10 @@ bool ProfileManager::UserExists(UUID uuid) const {
208} 208}
209 209
210bool ProfileManager::UserExistsIndex(std::size_t index) const { 210bool ProfileManager::UserExistsIndex(std::size_t index) const {
211 if (index >= MAX_USERS) 211 if (index >= MAX_USERS) {
212 return false; 212 return false;
213 return profiles[index].user_uuid.uuid != Common::INVALID_UUID; 213 }
214 return profiles[index].user_uuid.IsValid();
214} 215}
215 216
216/// Opens a specific user 217/// Opens a specific user
@@ -304,7 +305,7 @@ bool ProfileManager::RemoveUser(UUID uuid) {
304 305
305bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { 306bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) {
306 const auto index = GetUserIndex(uuid); 307 const auto index = GetUserIndex(uuid);
307 if (!index || profile_new.user_uuid == UUID(Common::INVALID_UUID)) { 308 if (!index || profile_new.user_uuid.IsInvalid()) {
308 return false; 309 return false;
309 } 310 }
310 311
@@ -346,7 +347,7 @@ void ProfileManager::ParseUserSaveFile() {
346 } 347 }
347 348
348 for (const auto& user : data.users) { 349 for (const auto& user : data.users) {
349 if (user.uuid == UUID(Common::INVALID_UUID)) { 350 if (user.uuid.IsInvalid()) {
350 continue; 351 continue;
351 } 352 }
352 353
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index c3ac73131..eccdcc20d 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -16,9 +16,7 @@
16#include "core/hle/ipc_helpers.h" 16#include "core/hle/ipc_helpers.h"
17#include "core/hle/kernel/k_event.h" 17#include "core/hle/kernel/k_event.h"
18#include "core/hle/kernel/k_process.h" 18#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_readable_event.h"
20#include "core/hle/kernel/k_transfer_memory.h" 19#include "core/hle/kernel/k_transfer_memory.h"
21#include "core/hle/kernel/k_writable_event.h"
22#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/kernel.h"
23#include "core/hle/service/acc/profile_manager.h" 21#include "core/hle/service/acc/profile_manager.h"
24#include "core/hle/service/am/am.h" 22#include "core/hle/service/am/am.h"
@@ -254,8 +252,9 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
254IDebugFunctions::~IDebugFunctions() = default; 252IDebugFunctions::~IDebugFunctions() = default;
255 253
256ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_) 254ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_)
257 : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_}, 255 : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_}, service_context{
258 launchable_event{system.Kernel()}, accumulated_suspended_tick_changed_event{system.Kernel()} { 256 system,
257 "ISelfController"} {
259 // clang-format off 258 // clang-format off
260 static const FunctionInfo functions[] = { 259 static const FunctionInfo functions[] = {
261 {0, &ISelfController::Exit, "Exit"}, 260 {0, &ISelfController::Exit, "Exit"},
@@ -275,12 +274,14 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
275 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, 274 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
276 {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, 275 {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
277 {20, nullptr, "SetDesirableKeyboardLayout"}, 276 {20, nullptr, "SetDesirableKeyboardLayout"},
277 {21, nullptr, "GetScreenShotProgramId"},
278 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, 278 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
279 {41, nullptr, "IsSystemBufferSharingEnabled"}, 279 {41, nullptr, "IsSystemBufferSharingEnabled"},
280 {42, nullptr, "GetSystemSharedLayerHandle"}, 280 {42, nullptr, "GetSystemSharedLayerHandle"},
281 {43, nullptr, "GetSystemSharedBufferHandle"}, 281 {43, nullptr, "GetSystemSharedBufferHandle"},
282 {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"}, 282 {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
283 {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, 283 {45, nullptr, "SetManagedDisplayLayerSeparationMode"},
284 {46, nullptr, "SetRecordingLayerCompositionEnabled"},
284 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, 285 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
285 {51, nullptr, "ApproveToDisplay"}, 286 {51, nullptr, "ApproveToDisplay"},
286 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, 287 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
@@ -302,15 +303,14 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
302 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, 303 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
303 {110, nullptr, "SetApplicationAlbumUserData"}, 304 {110, nullptr, "SetApplicationAlbumUserData"},
304 {120, nullptr, "SaveCurrentScreenshot"}, 305 {120, nullptr, "SaveCurrentScreenshot"},
306 {130, nullptr, "SetRecordVolumeMuted"},
305 {1000, nullptr, "GetDebugStorageChannel"}, 307 {1000, nullptr, "GetDebugStorageChannel"},
306 }; 308 };
307 // clang-format on 309 // clang-format on
308 310
309 RegisterHandlers(functions); 311 RegisterHandlers(functions);
310 312
311 Kernel::KAutoObject::Create(std::addressof(launchable_event)); 313 launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent");
312
313 launchable_event.Initialize("ISelfController:LaunchableEvent");
314 314
315 // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is 315 // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
316 // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple 316 // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
@@ -318,21 +318,23 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
318 // suspended if the event has previously been created by a call to 318 // suspended if the event has previously been created by a call to
319 // GetAccumulatedSuspendedTickChangedEvent. 319 // GetAccumulatedSuspendedTickChangedEvent.
320 320
321 Kernel::KAutoObject::Create(std::addressof(accumulated_suspended_tick_changed_event)); 321 accumulated_suspended_tick_changed_event =
322 accumulated_suspended_tick_changed_event.Initialize( 322 service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent");
323 "ISelfController:AccumulatedSuspendedTickChangedEvent"); 323 accumulated_suspended_tick_changed_event->GetWritableEvent().Signal();
324 accumulated_suspended_tick_changed_event.GetWritableEvent().Signal();
325} 324}
326 325
327ISelfController::~ISelfController() = default; 326ISelfController::~ISelfController() {
327 service_context.CloseEvent(launchable_event);
328 service_context.CloseEvent(accumulated_suspended_tick_changed_event);
329}
328 330
329void ISelfController::Exit(Kernel::HLERequestContext& ctx) { 331void ISelfController::Exit(Kernel::HLERequestContext& ctx) {
330 LOG_DEBUG(Service_AM, "called"); 332 LOG_DEBUG(Service_AM, "called");
331 333
332 system.Shutdown();
333
334 IPC::ResponseBuilder rb{ctx, 2}; 334 IPC::ResponseBuilder rb{ctx, 2};
335 rb.Push(ResultSuccess); 335 rb.Push(ResultSuccess);
336
337 system.Exit();
336} 338}
337 339
338void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { 340void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
@@ -380,11 +382,11 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
380void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { 382void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
381 LOG_WARNING(Service_AM, "(STUBBED) called"); 383 LOG_WARNING(Service_AM, "(STUBBED) called");
382 384
383 launchable_event.GetWritableEvent().Signal(); 385 launchable_event->GetWritableEvent().Signal();
384 386
385 IPC::ResponseBuilder rb{ctx, 2, 1}; 387 IPC::ResponseBuilder rb{ctx, 2, 1};
386 rb.Push(ResultSuccess); 388 rb.Push(ResultSuccess);
387 rb.PushCopyObjects(launchable_event.GetReadableEvent()); 389 rb.PushCopyObjects(launchable_event->GetReadableEvent());
388} 390}
389 391
390void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 392void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
@@ -563,7 +565,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
563 565
564 IPC::ResponseBuilder rb{ctx, 2, 1}; 566 IPC::ResponseBuilder rb{ctx, 2, 1};
565 rb.Push(ResultSuccess); 567 rb.Push(ResultSuccess);
566 rb.PushCopyObjects(accumulated_suspended_tick_changed_event.GetReadableEvent()); 568 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
567} 569}
568 570
569void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) { 571void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
@@ -581,40 +583,39 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo
581 rb.Push(ResultSuccess); 583 rb.Push(ResultSuccess);
582} 584}
583 585
584AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) 586AppletMessageQueue::AppletMessageQueue(Core::System& system)
585 : on_new_message{kernel}, on_operation_mode_changed{kernel} { 587 : service_context{system, "AppletMessageQueue"} {
586 588 on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
587 Kernel::KAutoObject::Create(std::addressof(on_new_message)); 589 on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
588 Kernel::KAutoObject::Create(std::addressof(on_operation_mode_changed));
589
590 on_new_message.Initialize("AMMessageQueue:OnMessageReceived");
591 on_operation_mode_changed.Initialize("AMMessageQueue:OperationModeChanged");
592} 590}
593 591
594AppletMessageQueue::~AppletMessageQueue() = default; 592AppletMessageQueue::~AppletMessageQueue() {
593 service_context.CloseEvent(on_new_message);
594 service_context.CloseEvent(on_operation_mode_changed);
595}
595 596
596Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() { 597Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
597 return on_new_message.GetReadableEvent(); 598 return on_new_message->GetReadableEvent();
598} 599}
599 600
600Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { 601Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
601 return on_operation_mode_changed.GetReadableEvent(); 602 return on_operation_mode_changed->GetReadableEvent();
602} 603}
603 604
604void AppletMessageQueue::PushMessage(AppletMessage msg) { 605void AppletMessageQueue::PushMessage(AppletMessage msg) {
605 messages.push(msg); 606 messages.push(msg);
606 on_new_message.GetWritableEvent().Signal(); 607 on_new_message->GetWritableEvent().Signal();
607} 608}
608 609
609AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { 610AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
610 if (messages.empty()) { 611 if (messages.empty()) {
611 on_new_message.GetWritableEvent().Clear(); 612 on_new_message->GetWritableEvent().Clear();
612 return AppletMessage::NoMessage; 613 return AppletMessage::NoMessage;
613 } 614 }
614 auto msg = messages.front(); 615 auto msg = messages.front();
615 messages.pop(); 616 messages.pop();
616 if (messages.empty()) { 617 if (messages.empty()) {
617 on_new_message.GetWritableEvent().Clear(); 618 on_new_message->GetWritableEvent().Clear();
618 } 619 }
619 return msg; 620 return msg;
620} 621}
@@ -634,7 +635,7 @@ void AppletMessageQueue::FocusStateChanged() {
634void AppletMessageQueue::OperationModeChanged() { 635void AppletMessageQueue::OperationModeChanged() {
635 PushMessage(AppletMessage::OperationModeChanged); 636 PushMessage(AppletMessage::OperationModeChanged);
636 PushMessage(AppletMessage::PerformanceModeChanged); 637 PushMessage(AppletMessage::PerformanceModeChanged);
637 on_operation_mode_changed.GetWritableEvent().Signal(); 638 on_operation_mode_changed->GetWritableEvent().Signal();
638} 639}
639 640
640ICommonStateGetter::ICommonStateGetter(Core::System& system_, 641ICommonStateGetter::ICommonStateGetter(Core::System& system_,
@@ -683,6 +684,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
683 {91, nullptr, "GetCurrentPerformanceConfiguration"}, 684 {91, nullptr, "GetCurrentPerformanceConfiguration"},
684 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, 685 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
685 {110, nullptr, "OpenMyGpuErrorHandler"}, 686 {110, nullptr, "OpenMyGpuErrorHandler"},
687 {120, nullptr, "GetAppletLaunchedHistory"},
686 {200, nullptr, "GetOperationModeSystemInfo"}, 688 {200, nullptr, "GetOperationModeSystemInfo"},
687 {300, nullptr, "GetSettingsPlatformRegion"}, 689 {300, nullptr, "GetSettingsPlatformRegion"},
688 {400, nullptr, "ActivateMigrationService"}, 690 {400, nullptr, "ActivateMigrationService"},
@@ -1268,10 +1270,8 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
1268} 1270}
1269 1271
1270IApplicationFunctions::IApplicationFunctions(Core::System& system_) 1272IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1271 : ServiceFramework{system_, "IApplicationFunctions"}, gpu_error_detected_event{system.Kernel()}, 1273 : ServiceFramework{system_, "IApplicationFunctions"}, service_context{system,
1272 friend_invitation_storage_channel_event{system.Kernel()}, 1274 "IApplicationFunctions"} {
1273 notification_storage_channel_event{system.Kernel()}, health_warning_disappeared_system_event{
1274 system.Kernel()} {
1275 // clang-format off 1275 // clang-format off
1276 static const FunctionInfo functions[] = { 1276 static const FunctionInfo functions[] = {
1277 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, 1277 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
@@ -1339,21 +1339,22 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1339 1339
1340 RegisterHandlers(functions); 1340 RegisterHandlers(functions);
1341 1341
1342 Kernel::KAutoObject::Create(std::addressof(gpu_error_detected_event)); 1342 gpu_error_detected_event =
1343 Kernel::KAutoObject::Create(std::addressof(friend_invitation_storage_channel_event)); 1343 service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent");
1344 Kernel::KAutoObject::Create(std::addressof(notification_storage_channel_event)); 1344 friend_invitation_storage_channel_event =
1345 Kernel::KAutoObject::Create(std::addressof(health_warning_disappeared_system_event)); 1345 service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent");
1346 1346 notification_storage_channel_event =
1347 gpu_error_detected_event.Initialize("IApplicationFunctions:GpuErrorDetectedSystemEvent"); 1347 service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent");
1348 friend_invitation_storage_channel_event.Initialize( 1348 health_warning_disappeared_system_event =
1349 "IApplicationFunctions:FriendInvitationStorageChannelEvent"); 1349 service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent");
1350 notification_storage_channel_event.Initialize(
1351 "IApplicationFunctions:NotificationStorageChannelEvent");
1352 health_warning_disappeared_system_event.Initialize(
1353 "IApplicationFunctions:HealthWarningDisappearedSystemEvent");
1354} 1350}
1355 1351
1356IApplicationFunctions::~IApplicationFunctions() = default; 1352IApplicationFunctions::~IApplicationFunctions() {
1353 service_context.CloseEvent(gpu_error_detected_event);
1354 service_context.CloseEvent(friend_invitation_storage_channel_event);
1355 service_context.CloseEvent(notification_storage_channel_event);
1356 service_context.CloseEvent(health_warning_disappeared_system_event);
1357}
1357 1358
1358void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) { 1359void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
1359 LOG_WARNING(Service_AM, "(STUBBED) called"); 1360 LOG_WARNING(Service_AM, "(STUBBED) called");
@@ -1747,7 +1748,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
1747 1748
1748 IPC::ResponseBuilder rb{ctx, 2, 1}; 1749 IPC::ResponseBuilder rb{ctx, 2, 1};
1749 rb.Push(ResultSuccess); 1750 rb.Push(ResultSuccess);
1750 rb.PushCopyObjects(gpu_error_detected_event.GetReadableEvent()); 1751 rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent());
1751} 1752}
1752 1753
1753void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) { 1754void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) {
@@ -1755,7 +1756,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe
1755 1756
1756 IPC::ResponseBuilder rb{ctx, 2, 1}; 1757 IPC::ResponseBuilder rb{ctx, 2, 1};
1757 rb.Push(ResultSuccess); 1758 rb.Push(ResultSuccess);
1758 rb.PushCopyObjects(friend_invitation_storage_channel_event.GetReadableEvent()); 1759 rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent());
1759} 1760}
1760 1761
1761void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel( 1762void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
@@ -1771,7 +1772,7 @@ void IApplicationFunctions::GetNotificationStorageChannelEvent(Kernel::HLEReques
1771 1772
1772 IPC::ResponseBuilder rb{ctx, 2, 1}; 1773 IPC::ResponseBuilder rb{ctx, 2, 1};
1773 rb.Push(ResultSuccess); 1774 rb.Push(ResultSuccess);
1774 rb.PushCopyObjects(notification_storage_channel_event.GetReadableEvent()); 1775 rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent());
1775} 1776}
1776 1777
1777void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx) { 1778void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx) {
@@ -1779,12 +1780,12 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe
1779 1780
1780 IPC::ResponseBuilder rb{ctx, 2, 1}; 1781 IPC::ResponseBuilder rb{ctx, 2, 1};
1781 rb.Push(ResultSuccess); 1782 rb.Push(ResultSuccess);
1782 rb.PushCopyObjects(health_warning_disappeared_system_event.GetReadableEvent()); 1783 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
1783} 1784}
1784 1785
1785void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, 1786void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
1786 Core::System& system) { 1787 Core::System& system) {
1787 auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); 1788 auto message_queue = std::make_shared<AppletMessageQueue>(system);
1788 // Needed on game boot 1789 // Needed on game boot
1789 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); 1790 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
1790 1791
@@ -1797,8 +1798,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
1797} 1798}
1798 1799
1799IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) 1800IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
1800 : ServiceFramework{system_, "IHomeMenuFunctions"}, pop_from_general_channel_event{ 1801 : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system,
1801 system.Kernel()} { 1802 "IHomeMenuFunctions"} {
1802 // clang-format off 1803 // clang-format off
1803 static const FunctionInfo functions[] = { 1804 static const FunctionInfo functions[] = {
1804 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, 1805 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
@@ -1819,11 +1820,13 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
1819 1820
1820 RegisterHandlers(functions); 1821 RegisterHandlers(functions);
1821 1822
1822 Kernel::KAutoObject::Create(std::addressof(pop_from_general_channel_event)); 1823 pop_from_general_channel_event =
1823 pop_from_general_channel_event.Initialize("IHomeMenuFunctions:PopFromGeneralChannelEvent"); 1824 service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent");
1824} 1825}
1825 1826
1826IHomeMenuFunctions::~IHomeMenuFunctions() = default; 1827IHomeMenuFunctions::~IHomeMenuFunctions() {
1828 service_context.CloseEvent(pop_from_general_channel_event);
1829}
1827 1830
1828void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { 1831void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
1829 LOG_WARNING(Service_AM, "(STUBBED) called"); 1832 LOG_WARNING(Service_AM, "(STUBBED) called");
@@ -1837,7 +1840,7 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext
1837 1840
1838 IPC::ResponseBuilder rb{ctx, 2, 1}; 1841 IPC::ResponseBuilder rb{ctx, 2, 1};
1839 rb.Push(ResultSuccess); 1842 rb.Push(ResultSuccess);
1840 rb.PushCopyObjects(pop_from_general_channel_event.GetReadableEvent()); 1843 rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
1841} 1844}
1842 1845
1843IGlobalStateController::IGlobalStateController(Core::System& system_) 1846IGlobalStateController::IGlobalStateController(Core::System& system_)
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index c13aa5787..202d20757 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -8,7 +8,7 @@
8#include <memory> 8#include <memory>
9#include <queue> 9#include <queue>
10 10
11#include "core/hle/kernel/k_event.h" 11#include "core/hle/service/kernel_helpers.h"
12#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
13 13
14namespace Kernel { 14namespace Kernel {
@@ -53,7 +53,7 @@ public:
53 PerformanceModeChanged = 31, 53 PerformanceModeChanged = 31,
54 }; 54 };
55 55
56 explicit AppletMessageQueue(Kernel::KernelCore& kernel); 56 explicit AppletMessageQueue(Core::System& system);
57 ~AppletMessageQueue(); 57 ~AppletMessageQueue();
58 58
59 Kernel::KReadableEvent& GetMessageReceiveEvent(); 59 Kernel::KReadableEvent& GetMessageReceiveEvent();
@@ -66,9 +66,12 @@ public:
66 void OperationModeChanged(); 66 void OperationModeChanged();
67 67
68private: 68private:
69 KernelHelpers::ServiceContext service_context;
70
71 Kernel::KEvent* on_new_message;
72 Kernel::KEvent* on_operation_mode_changed;
73
69 std::queue<AppletMessage> messages; 74 std::queue<AppletMessage> messages;
70 Kernel::KEvent on_new_message;
71 Kernel::KEvent on_operation_mode_changed;
72}; 75};
73 76
74class IWindowController final : public ServiceFramework<IWindowController> { 77class IWindowController final : public ServiceFramework<IWindowController> {
@@ -156,8 +159,11 @@ private:
156 }; 159 };
157 160
158 NVFlinger::NVFlinger& nvflinger; 161 NVFlinger::NVFlinger& nvflinger;
159 Kernel::KEvent launchable_event; 162
160 Kernel::KEvent accumulated_suspended_tick_changed_event; 163 KernelHelpers::ServiceContext service_context;
164
165 Kernel::KEvent* launchable_event;
166 Kernel::KEvent* accumulated_suspended_tick_changed_event;
161 167
162 u32 idle_time_detection_extension = 0; 168 u32 idle_time_detection_extension = 0;
163 u64 num_fatal_sections_entered = 0; 169 u64 num_fatal_sections_entered = 0;
@@ -298,13 +304,15 @@ private:
298 void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx); 304 void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx);
299 void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx); 305 void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx);
300 306
307 KernelHelpers::ServiceContext service_context;
308
301 bool launch_popped_application_specific = false; 309 bool launch_popped_application_specific = false;
302 bool launch_popped_account_preselect = false; 310 bool launch_popped_account_preselect = false;
303 s32 previous_program_index{-1}; 311 s32 previous_program_index{-1};
304 Kernel::KEvent gpu_error_detected_event; 312 Kernel::KEvent* gpu_error_detected_event;
305 Kernel::KEvent friend_invitation_storage_channel_event; 313 Kernel::KEvent* friend_invitation_storage_channel_event;
306 Kernel::KEvent notification_storage_channel_event; 314 Kernel::KEvent* notification_storage_channel_event;
307 Kernel::KEvent health_warning_disappeared_system_event; 315 Kernel::KEvent* health_warning_disappeared_system_event;
308}; 316};
309 317
310class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 318class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
@@ -316,7 +324,9 @@ private:
316 void RequestToGetForeground(Kernel::HLERequestContext& ctx); 324 void RequestToGetForeground(Kernel::HLERequestContext& ctx);
317 void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); 325 void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx);
318 326
319 Kernel::KEvent pop_from_general_channel_event; 327 KernelHelpers::ServiceContext service_context;
328
329 Kernel::KEvent* pop_from_general_channel_event;
320}; 330};
321 331
322class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { 332class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index adb207349..f89f65649 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/hle/kernel/hle_ipc.h" 8
9#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10 10
11namespace Service { 11namespace Service {
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 6c1aa255a..64b874ead 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/hle/kernel/hle_ipc.h" 8
9#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10 10
11namespace Service { 11namespace Service {
diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp
index bdc21778e..a6e891944 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.cpp
+++ b/src/core/hle/service/am/applets/applet_profile_select.cpp
@@ -60,7 +60,7 @@ void ProfileSelect::Execute() {
60void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { 60void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
61 UserSelectionOutput output{}; 61 UserSelectionOutput output{};
62 62
63 if (uuid.has_value() && uuid->uuid != Common::INVALID_UUID) { 63 if (uuid.has_value() && uuid->IsValid()) {
64 output.result = 0; 64 output.result = 0;
65 output.uuid_selected = uuid->uuid; 65 output.uuid_selected = uuid->uuid;
66 } else { 66 } else {
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp
index 35f194961..927eeefff 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.cpp
+++ b/src/core/hle/service/am/applets/applet_web_browser.cpp
@@ -24,6 +24,7 @@
24#include "core/hle/service/am/applets/applet_web_browser.h" 24#include "core/hle/service/am/applets/applet_web_browser.h"
25#include "core/hle/service/filesystem/filesystem.h" 25#include "core/hle/service/filesystem/filesystem.h"
26#include "core/hle/service/ns/pl_u.h" 26#include "core/hle/service/ns/pl_u.h"
27#include "core/loader/loader.h"
27 28
28namespace Service::AM::Applets { 29namespace Service::AM::Applets {
29 30
@@ -122,6 +123,15 @@ FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
122 const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type); 123 const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type);
123 124
124 if (nca == nullptr) { 125 if (nca == nullptr) {
126 if (nca_type == FileSys::ContentRecordType::HtmlDocument) {
127 LOG_WARNING(Service_AM, "Falling back to AppLoader to get the RomFS.");
128 FileSys::VirtualFile romfs;
129 system.GetAppLoader().ReadManualRomFS(romfs);
130 if (romfs != nullptr) {
131 return romfs;
132 }
133 }
134
125 LOG_ERROR(Service_AM, 135 LOG_ERROR(Service_AM,
126 "NCA of type={} with title_id={:016X} is not found in the ContentProvider!", 136 "NCA of type={} with title_id={:016X} is not found in the ContentProvider!",
127 nca_type, title_id); 137 nca_type, title_id);
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 2b7685d42..7320b1c0f 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -12,8 +12,7 @@
12#include "core/frontend/applets/profile_select.h" 12#include "core/frontend/applets/profile_select.h"
13#include "core/frontend/applets/software_keyboard.h" 13#include "core/frontend/applets/software_keyboard.h"
14#include "core/frontend/applets/web_browser.h" 14#include "core/frontend/applets/web_browser.h"
15#include "core/hle/kernel/k_readable_event.h" 15#include "core/hle/kernel/k_event.h"
16#include "core/hle/kernel/k_writable_event.h"
17#include "core/hle/service/am/am.h" 16#include "core/hle/service/am/am.h"
18#include "core/hle/service/am/applet_ae.h" 17#include "core/hle/service/am/applet_ae.h"
19#include "core/hle/service/am/applet_oe.h" 18#include "core/hle/service/am/applet_oe.h"
@@ -29,19 +28,19 @@
29namespace Service::AM::Applets { 28namespace Service::AM::Applets {
30 29
31AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) 30AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_)
32 : system{system_}, applet_mode{applet_mode_}, state_changed_event{system.Kernel()}, 31 : system{system_}, applet_mode{applet_mode_}, service_context{system,
33 pop_out_data_event{system.Kernel()}, pop_interactive_out_data_event{system.Kernel()} { 32 "ILibraryAppletAccessor"} {
34 33 state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent");
35 Kernel::KAutoObject::Create(std::addressof(state_changed_event)); 34 pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent");
36 Kernel::KAutoObject::Create(std::addressof(pop_out_data_event)); 35 pop_interactive_out_data_event =
37 Kernel::KAutoObject::Create(std::addressof(pop_interactive_out_data_event)); 36 service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
38
39 state_changed_event.Initialize("ILibraryAppletAccessor:StateChangedEvent");
40 pop_out_data_event.Initialize("ILibraryAppletAccessor:PopDataOutEvent");
41 pop_interactive_out_data_event.Initialize("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
42} 37}
43 38
44AppletDataBroker::~AppletDataBroker() = default; 39AppletDataBroker::~AppletDataBroker() {
40 service_context.CloseEvent(state_changed_event);
41 service_context.CloseEvent(pop_out_data_event);
42 service_context.CloseEvent(pop_interactive_out_data_event);
43}
45 44
46AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const { 45AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
47 std::vector<std::vector<u8>> out_normal; 46 std::vector<std::vector<u8>> out_normal;
@@ -65,7 +64,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
65 64
66 auto out = std::move(out_channel.front()); 65 auto out = std::move(out_channel.front());
67 out_channel.pop_front(); 66 out_channel.pop_front();
68 pop_out_data_event.GetWritableEvent().Clear(); 67 pop_out_data_event->GetWritableEvent().Clear();
69 return out; 68 return out;
70} 69}
71 70
@@ -84,7 +83,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
84 83
85 auto out = std::move(out_interactive_channel.front()); 84 auto out = std::move(out_interactive_channel.front());
86 out_interactive_channel.pop_front(); 85 out_interactive_channel.pop_front();
87 pop_interactive_out_data_event.GetWritableEvent().Clear(); 86 pop_interactive_out_data_event->GetWritableEvent().Clear();
88 return out; 87 return out;
89} 88}
90 89
@@ -103,7 +102,7 @@ void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storag
103 102
104void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { 103void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
105 out_channel.emplace_back(std::move(storage)); 104 out_channel.emplace_back(std::move(storage));
106 pop_out_data_event.GetWritableEvent().Signal(); 105 pop_out_data_event->GetWritableEvent().Signal();
107} 106}
108 107
109void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { 108void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
@@ -112,11 +111,11 @@ void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& s
112 111
113void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { 112void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
114 out_interactive_channel.emplace_back(std::move(storage)); 113 out_interactive_channel.emplace_back(std::move(storage));
115 pop_interactive_out_data_event.GetWritableEvent().Signal(); 114 pop_interactive_out_data_event->GetWritableEvent().Signal();
116} 115}
117 116
118void AppletDataBroker::SignalStateChanged() { 117void AppletDataBroker::SignalStateChanged() {
119 state_changed_event.GetWritableEvent().Signal(); 118 state_changed_event->GetWritableEvent().Signal();
120 119
121 switch (applet_mode) { 120 switch (applet_mode) {
122 case LibraryAppletMode::AllForeground: 121 case LibraryAppletMode::AllForeground:
@@ -141,15 +140,15 @@ void AppletDataBroker::SignalStateChanged() {
141} 140}
142 141
143Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() { 142Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() {
144 return pop_out_data_event.GetReadableEvent(); 143 return pop_out_data_event->GetReadableEvent();
145} 144}
146 145
147Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() { 146Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() {
148 return pop_interactive_out_data_event.GetReadableEvent(); 147 return pop_interactive_out_data_event->GetReadableEvent();
149} 148}
150 149
151Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() { 150Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() {
152 return state_changed_event.GetReadableEvent(); 151 return state_changed_event->GetReadableEvent();
153} 152}
154 153
155Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_) 154Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_)
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 5c0b4b459..15eeb4ee1 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -8,7 +8,7 @@
8#include <queue> 8#include <queue>
9 9
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/hle/kernel/k_event.h" 11#include "core/hle/service/kernel_helpers.h"
12 12
13union ResultCode; 13union ResultCode;
14 14
@@ -105,6 +105,8 @@ private:
105 Core::System& system; 105 Core::System& system;
106 LibraryAppletMode applet_mode; 106 LibraryAppletMode applet_mode;
107 107
108 KernelHelpers::ServiceContext service_context;
109
108 // Queues are named from applet's perspective 110 // Queues are named from applet's perspective
109 111
110 // PopNormalDataToApplet and PushNormalDataFromGame 112 // PopNormalDataToApplet and PushNormalDataFromGame
@@ -119,13 +121,13 @@ private:
119 // PopInteractiveDataToGame and PushInteractiveDataFromApplet 121 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
120 std::deque<std::shared_ptr<IStorage>> out_interactive_channel; 122 std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
121 123
122 Kernel::KEvent state_changed_event; 124 Kernel::KEvent* state_changed_event;
123 125
124 // Signaled on PushNormalDataFromApplet 126 // Signaled on PushNormalDataFromApplet
125 Kernel::KEvent pop_out_data_event; 127 Kernel::KEvent* pop_out_data_event;
126 128
127 // Signaled on PushInteractiveDataFromApplet 129 // Signaled on PushInteractiveDataFromApplet
128 Kernel::KEvent pop_interactive_out_data_event; 130 Kernel::KEvent* pop_interactive_out_data_event;
129}; 131};
130 132
131class Applet { 133class Applet {
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index dd945e058..4c54066c6 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -16,8 +16,8 @@
16#include "core/file_sys/patch_manager.h" 16#include "core/file_sys/patch_manager.h"
17#include "core/file_sys/registered_cache.h" 17#include "core/file_sys/registered_cache.h"
18#include "core/hle/ipc_helpers.h" 18#include "core/hle/ipc_helpers.h"
19#include "core/hle/kernel/k_event.h"
19#include "core/hle/kernel/k_process.h" 20#include "core/hle/kernel/k_process.h"
20#include "core/hle/kernel/k_readable_event.h"
21#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
22#include "core/hle/service/aoc/aoc_u.h" 22#include "core/hle/service/aoc/aoc_u.h"
23#include "core/loader/loader.h" 23#include "core/loader/loader.h"
@@ -49,7 +49,8 @@ static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
49class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> { 49class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
50public: 50public:
51 explicit IPurchaseEventManager(Core::System& system_) 51 explicit IPurchaseEventManager(Core::System& system_)
52 : ServiceFramework{system_, "IPurchaseEventManager"}, purchased_event{system.Kernel()} { 52 : ServiceFramework{system_, "IPurchaseEventManager"}, service_context{
53 system, "IPurchaseEventManager"} {
53 // clang-format off 54 // clang-format off
54 static const FunctionInfo functions[] = { 55 static const FunctionInfo functions[] = {
55 {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"}, 56 {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"},
@@ -62,8 +63,11 @@ public:
62 63
63 RegisterHandlers(functions); 64 RegisterHandlers(functions);
64 65
65 Kernel::KAutoObject::Create(std::addressof(purchased_event)); 66 purchased_event = service_context.CreateEvent("IPurchaseEventManager:PurchasedEvent");
66 purchased_event.Initialize("IPurchaseEventManager:PurchasedEvent"); 67 }
68
69 ~IPurchaseEventManager() override {
70 service_context.CloseEvent(purchased_event);
67 } 71 }
68 72
69private: 73private:
@@ -96,15 +100,17 @@ private:
96 100
97 IPC::ResponseBuilder rb{ctx, 2, 1}; 101 IPC::ResponseBuilder rb{ctx, 2, 1};
98 rb.Push(ResultSuccess); 102 rb.Push(ResultSuccess);
99 rb.PushCopyObjects(purchased_event.GetReadableEvent()); 103 rb.PushCopyObjects(purchased_event->GetReadableEvent());
100 } 104 }
101 105
102 Kernel::KEvent purchased_event; 106 KernelHelpers::ServiceContext service_context;
107
108 Kernel::KEvent* purchased_event;
103}; 109};
104 110
105AOC_U::AOC_U(Core::System& system_) 111AOC_U::AOC_U(Core::System& system_)
106 : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)}, 112 : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
107 aoc_change_event{system.Kernel()} { 113 service_context{system_, "aoc:u"} {
108 // clang-format off 114 // clang-format off
109 static const FunctionInfo functions[] = { 115 static const FunctionInfo functions[] = {
110 {0, nullptr, "CountAddOnContentByApplicationId"}, 116 {0, nullptr, "CountAddOnContentByApplicationId"},
@@ -126,11 +132,12 @@ AOC_U::AOC_U(Core::System& system_)
126 132
127 RegisterHandlers(functions); 133 RegisterHandlers(functions);
128 134
129 Kernel::KAutoObject::Create(std::addressof(aoc_change_event)); 135 aoc_change_event = service_context.CreateEvent("GetAddOnContentListChanged:Event");
130 aoc_change_event.Initialize("GetAddOnContentListChanged:Event");
131} 136}
132 137
133AOC_U::~AOC_U() = default; 138AOC_U::~AOC_U() {
139 service_context.CloseEvent(aoc_change_event);
140}
134 141
135void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { 142void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
136 struct Parameters { 143 struct Parameters {
@@ -254,7 +261,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
254 261
255 IPC::ResponseBuilder rb{ctx, 2, 1}; 262 IPC::ResponseBuilder rb{ctx, 2, 1};
256 rb.Push(ResultSuccess); 263 rb.Push(ResultSuccess);
257 rb.PushCopyObjects(aoc_change_event.GetReadableEvent()); 264 rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
258} 265}
259 266
260void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx) { 267void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx) {
@@ -262,7 +269,7 @@ void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestConte
262 269
263 IPC::ResponseBuilder rb{ctx, 2, 1}; 270 IPC::ResponseBuilder rb{ctx, 2, 1};
264 rb.Push(ResultSuccess); 271 rb.Push(ResultSuccess);
265 rb.PushCopyObjects(aoc_change_event.GetReadableEvent()); 272 rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
266} 273}
267 274
268void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { 275void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index bb6ffb8eb..31d645be8 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_event.h" 7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Core { 10namespace Core {
@@ -33,7 +33,9 @@ private:
33 void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx); 33 void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
34 34
35 std::vector<u64> add_on_content; 35 std::vector<u64> add_on_content;
36 Kernel::KEvent aoc_change_event; 36 KernelHelpers::ServiceContext service_context;
37
38 Kernel::KEvent* aoc_change_event;
37}; 39};
38 40
39/// Registers all AOC services with the specified service manager. 41/// Registers all AOC services with the specified service manager.
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
index 8c4c49b85..2e46e7161 100644
--- a/src/core/hle/service/audio/audctl.cpp
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -41,6 +41,14 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
41 {27, nullptr, "SetVolumeMappingTableForDev"}, 41 {27, nullptr, "SetVolumeMappingTableForDev"},
42 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, 42 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
43 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, 43 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
44 {30, nullptr, "Unknown30"},
45 {31, nullptr, "Unknown31"},
46 {32, nullptr, "Unknown32"},
47 {33, nullptr, "Unknown33"},
48 {34, nullptr, "Unknown34"},
49 {10000, nullptr, "Unknown10000"},
50 {10001, nullptr, "Unknown10001"},
51 {10002, nullptr, "Unknown10002"},
44 }; 52 };
45 // clang-format on 53 // clang-format on
46 54
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 3e7fd6024..34cc659ed 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -3,38 +3,65 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h" 8#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/audio/audin_u.h" 9#include "core/hle/service/audio/audin_u.h"
9 10
10namespace Service::Audio { 11namespace Service::Audio {
11 12
12class IAudioIn final : public ServiceFramework<IAudioIn> { 13IAudioIn::IAudioIn(Core::System& system_)
13public: 14 : ServiceFramework{system_, "IAudioIn"}, service_context{system_, "IAudioIn"} {
14 explicit IAudioIn(Core::System& system_) : ServiceFramework{system_, "IAudioIn"} { 15 // clang-format off
15 // clang-format off 16 static const FunctionInfo functions[] = {
16 static const FunctionInfo functions[] = { 17 {0, nullptr, "GetAudioInState"},
17 {0, nullptr, "GetAudioInState"}, 18 {1, &IAudioIn::Start, "Start"},
18 {1, nullptr, "Start"}, 19 {2, nullptr, "Stop"},
19 {2, nullptr, "Stop"}, 20 {3, nullptr, "AppendAudioInBuffer"},
20 {3, nullptr, "AppendAudioInBuffer"}, 21 {4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"},
21 {4, nullptr, "RegisterBufferEvent"}, 22 {5, nullptr, "GetReleasedAudioInBuffer"},
22 {5, nullptr, "GetReleasedAudioInBuffer"}, 23 {6, nullptr, "ContainsAudioInBuffer"},
23 {6, nullptr, "ContainsAudioInBuffer"}, 24 {7, nullptr, "AppendUacInBuffer"},
24 {7, nullptr, "AppendUacInBuffer"}, 25 {8, &IAudioIn::AppendAudioInBufferAuto, "AppendAudioInBufferAuto"},
25 {8, nullptr, "AppendAudioInBufferAuto"}, 26 {9, nullptr, "GetReleasedAudioInBuffersAuto"},
26 {9, nullptr, "GetReleasedAudioInBuffersAuto"}, 27 {10, nullptr, "AppendUacInBufferAuto"},
27 {10, nullptr, "AppendUacInBufferAuto"}, 28 {11, nullptr, "GetAudioInBufferCount"},
28 {11, nullptr, "GetAudioInBufferCount"}, 29 {12, nullptr, "SetDeviceGain"},
29 {12, nullptr, "SetDeviceGain"}, 30 {13, nullptr, "GetDeviceGain"},
30 {13, nullptr, "GetDeviceGain"}, 31 {14, nullptr, "FlushAudioInBuffers"},
31 {14, nullptr, "FlushAudioInBuffers"}, 32 };
32 }; 33 // clang-format on
33 // clang-format on 34
34 35 RegisterHandlers(functions);
35 RegisterHandlers(functions); 36
36 } 37 buffer_event = service_context.CreateEvent("IAudioIn:BufferEvent");
37}; 38}
39
40IAudioIn::~IAudioIn() {
41 service_context.CloseEvent(buffer_event);
42}
43
44void IAudioIn::Start(Kernel::HLERequestContext& ctx) {
45 LOG_WARNING(Service_Audio, "(STUBBED) called");
46
47 IPC::ResponseBuilder rb{ctx, 2};
48 rb.Push(ResultSuccess);
49}
50
51void IAudioIn::RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
52 LOG_WARNING(Service_Audio, "(STUBBED) called");
53
54 IPC::ResponseBuilder rb{ctx, 2, 1};
55 rb.Push(ResultSuccess);
56 rb.PushCopyObjects(buffer_event->GetReadableEvent());
57}
58
59void IAudioIn::AppendAudioInBufferAuto(Kernel::HLERequestContext& ctx) {
60 LOG_WARNING(Service_Audio, "(STUBBED) called");
61
62 IPC::ResponseBuilder rb{ctx, 2};
63 rb.Push(ResultSuccess);
64}
38 65
39AudInU::AudInU(Core::System& system_) : ServiceFramework{system_, "audin:u"} { 66AudInU::AudInU(Core::System& system_) : ServiceFramework{system_, "audin:u"} {
40 // clang-format off 67 // clang-format off
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
index 0d75ae5ac..bf3418613 100644
--- a/src/core/hle/service/audio/audin_u.h
+++ b/src/core/hle/service/audio/audin_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Core { 10namespace Core {
@@ -16,6 +17,21 @@ class HLERequestContext;
16 17
17namespace Service::Audio { 18namespace Service::Audio {
18 19
20class IAudioIn final : public ServiceFramework<IAudioIn> {
21public:
22 explicit IAudioIn(Core::System& system_);
23 ~IAudioIn() override;
24
25private:
26 void Start(Kernel::HLERequestContext& ctx);
27 void RegisterBufferEvent(Kernel::HLERequestContext& ctx);
28 void AppendAudioInBufferAuto(Kernel::HLERequestContext& ctx);
29
30 KernelHelpers::ServiceContext service_context;
31
32 Kernel::KEvent* buffer_event;
33};
34
19class AudInU final : public ServiceFramework<AudInU> { 35class AudInU final : public ServiceFramework<AudInU> {
20public: 36public:
21 explicit AudInU(Core::System& system_); 37 explicit AudInU(Core::System& system_);
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 92d4510b1..81adbfe09 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -13,13 +13,11 @@
13#include "common/swap.h" 13#include "common/swap.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/k_event.h" 16#include "core/hle/kernel/k_event.h"
18#include "core/hle/kernel/k_readable_event.h"
19#include "core/hle/kernel/k_writable_event.h"
20#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
21#include "core/hle/service/audio/audout_u.h" 18#include "core/hle/service/audio/audout_u.h"
22#include "core/hle/service/audio/errors.h" 19#include "core/hle/service/audio/errors.h"
20#include "core/hle/service/kernel_helpers.h"
23#include "core/memory.h" 21#include "core/memory.h"
24 22
25namespace Service::Audio { 23namespace Service::Audio {
@@ -41,11 +39,12 @@ enum class AudioState : u32 {
41 39
42class IAudioOut final : public ServiceFramework<IAudioOut> { 40class IAudioOut final : public ServiceFramework<IAudioOut> {
43public: 41public:
44 IAudioOut(Core::System& system_, AudoutParams audio_params_, AudioCore::AudioOut& audio_core_, 42 explicit IAudioOut(Core::System& system_, AudoutParams audio_params_,
45 std::string&& device_name_, std::string&& unique_name) 43 AudioCore::AudioOut& audio_core_, std::string&& device_name_,
46 : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, device_name{std::move( 44 std::string&& unique_name)
47 device_name_)}, 45 : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_},
48 audio_params{audio_params_}, buffer_event{system.Kernel()}, main_memory{system.Memory()} { 46 device_name{std::move(device_name_)}, audio_params{audio_params_},
47 main_memory{system.Memory()}, service_context{system_, "IAudioOut"} {
49 // clang-format off 48 // clang-format off
50 static const FunctionInfo functions[] = { 49 static const FunctionInfo functions[] = {
51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 50 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -67,16 +66,19 @@ public:
67 RegisterHandlers(functions); 66 RegisterHandlers(functions);
68 67
69 // This is the event handle used to check if the audio buffer was released 68 // This is the event handle used to check if the audio buffer was released
70 Kernel::KAutoObject::Create(std::addressof(buffer_event)); 69 buffer_event = service_context.CreateEvent("IAudioOutBufferReleased");
71 buffer_event.Initialize("IAudioOutBufferReleased");
72 70
73 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, 71 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
74 audio_params.channel_count, std::move(unique_name), [this] { 72 audio_params.channel_count, std::move(unique_name), [this] {
75 const auto guard = LockService(); 73 const auto guard = LockService();
76 buffer_event.GetWritableEvent().Signal(); 74 buffer_event->GetWritableEvent().Signal();
77 }); 75 });
78 } 76 }
79 77
78 ~IAudioOut() override {
79 service_context.CloseEvent(buffer_event);
80 }
81
80private: 82private:
81 struct AudioBuffer { 83 struct AudioBuffer {
82 u64_le next; 84 u64_le next;
@@ -126,7 +128,7 @@ private:
126 128
127 IPC::ResponseBuilder rb{ctx, 2, 1}; 129 IPC::ResponseBuilder rb{ctx, 2, 1};
128 rb.Push(ResultSuccess); 130 rb.Push(ResultSuccess);
129 rb.PushCopyObjects(buffer_event.GetReadableEvent()); 131 rb.PushCopyObjects(buffer_event->GetReadableEvent());
130 } 132 }
131 133
132 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 134 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -227,9 +229,12 @@ private:
227 229
228 [[maybe_unused]] AudoutParams audio_params{}; 230 [[maybe_unused]] AudoutParams audio_params{};
229 231
230 /// This is the event handle used to check if the audio buffer was released
231 Kernel::KEvent buffer_event;
232 Core::Memory::Memory& main_memory; 232 Core::Memory::Memory& main_memory;
233
234 KernelHelpers::ServiceContext service_context;
235
236 /// This is the event handle used to check if the audio buffer was released
237 Kernel::KEvent* buffer_event;
233}; 238};
234 239
235AudOutU::AudOutU(Core::System& system_) : ServiceFramework{system_, "audout:u"} { 240AudOutU::AudOutU(Core::System& system_) : ServiceFramework{system_, "audout:u"} {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index b769fe959..cdb2a9521 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -15,10 +15,7 @@
15#include "common/string_util.h" 15#include "common/string_util.h"
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/ipc_helpers.h" 17#include "core/hle/ipc_helpers.h"
18#include "core/hle/kernel/hle_ipc.h"
19#include "core/hle/kernel/k_event.h" 18#include "core/hle/kernel/k_event.h"
20#include "core/hle/kernel/k_readable_event.h"
21#include "core/hle/kernel/k_writable_event.h"
22#include "core/hle/kernel/kernel.h" 19#include "core/hle/kernel/kernel.h"
23#include "core/hle/service/audio/audren_u.h" 20#include "core/hle/service/audio/audren_u.h"
24#include "core/hle/service/audio/errors.h" 21#include "core/hle/service/audio/errors.h"
@@ -30,7 +27,7 @@ public:
30 explicit IAudioRenderer(Core::System& system_, 27 explicit IAudioRenderer(Core::System& system_,
31 const AudioCommon::AudioRendererParameter& audren_params, 28 const AudioCommon::AudioRendererParameter& audren_params,
32 const std::size_t instance_number) 29 const std::size_t instance_number)
33 : ServiceFramework{system_, "IAudioRenderer"}, system_event{system.Kernel()} { 30 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"} {
34 // clang-format off 31 // clang-format off
35 static const FunctionInfo functions[] = { 32 static const FunctionInfo functions[] = {
36 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, 33 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
@@ -49,17 +46,20 @@ public:
49 // clang-format on 46 // clang-format on
50 RegisterHandlers(functions); 47 RegisterHandlers(functions);
51 48
52 Kernel::KAutoObject::Create(std::addressof(system_event)); 49 system_event = service_context.CreateEvent("IAudioRenderer:SystemEvent");
53 system_event.Initialize("IAudioRenderer:SystemEvent");
54 renderer = std::make_unique<AudioCore::AudioRenderer>( 50 renderer = std::make_unique<AudioCore::AudioRenderer>(
55 system.CoreTiming(), system.Memory(), audren_params, 51 system.CoreTiming(), system.Memory(), audren_params,
56 [this]() { 52 [this]() {
57 const auto guard = LockService(); 53 const auto guard = LockService();
58 system_event.GetWritableEvent().Signal(); 54 system_event->GetWritableEvent().Signal();
59 }, 55 },
60 instance_number); 56 instance_number);
61 } 57 }
62 58
59 ~IAudioRenderer() override {
60 service_context.CloseEvent(system_event);
61 }
62
63private: 63private:
64 void GetSampleRate(Kernel::HLERequestContext& ctx) { 64 void GetSampleRate(Kernel::HLERequestContext& ctx) {
65 LOG_DEBUG(Service_Audio, "called"); 65 LOG_DEBUG(Service_Audio, "called");
@@ -130,7 +130,7 @@ private:
130 130
131 IPC::ResponseBuilder rb{ctx, 2, 1}; 131 IPC::ResponseBuilder rb{ctx, 2, 1};
132 rb.Push(ResultSuccess); 132 rb.Push(ResultSuccess);
133 rb.PushCopyObjects(system_event.GetReadableEvent()); 133 rb.PushCopyObjects(system_event->GetReadableEvent());
134 } 134 }
135 135
136 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { 136 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
@@ -164,14 +164,16 @@ private:
164 rb.Push(ERR_NOT_SUPPORTED); 164 rb.Push(ERR_NOT_SUPPORTED);
165 } 165 }
166 166
167 Kernel::KEvent system_event; 167 KernelHelpers::ServiceContext service_context;
168
169 Kernel::KEvent* system_event;
168 std::unique_ptr<AudioCore::AudioRenderer> renderer; 170 std::unique_ptr<AudioCore::AudioRenderer> renderer;
169 u32 rendering_time_limit_percent = 100; 171 u32 rendering_time_limit_percent = 100;
170}; 172};
171 173
172class IAudioDevice final : public ServiceFramework<IAudioDevice> { 174class IAudioDevice final : public ServiceFramework<IAudioDevice> {
173public: 175public:
174 explicit IAudioDevice(Core::System& system_, Kernel::KEvent& buffer_event_, u32_le revision_) 176 explicit IAudioDevice(Core::System& system_, Kernel::KEvent* buffer_event_, u32_le revision_)
175 : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{ 177 : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{
176 revision_} { 178 revision_} {
177 static const FunctionInfo functions[] = { 179 static const FunctionInfo functions[] = {
@@ -187,7 +189,8 @@ public:
187 {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"}, 189 {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
188 {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"}, 190 {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
189 {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"}, 191 {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
190 {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, 192 {13, nullptr, "GetActiveAudioOutputDeviceName"},
193 {14, nullptr, "ListAudioOutputDeviceName"},
191 }; 194 };
192 RegisterHandlers(functions); 195 RegisterHandlers(functions);
193 } 196 }
@@ -278,11 +281,11 @@ private:
278 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { 281 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
279 LOG_WARNING(Service_Audio, "(STUBBED) called"); 282 LOG_WARNING(Service_Audio, "(STUBBED) called");
280 283
281 buffer_event.GetWritableEvent().Signal(); 284 buffer_event->GetWritableEvent().Signal();
282 285
283 IPC::ResponseBuilder rb{ctx, 2, 1}; 286 IPC::ResponseBuilder rb{ctx, 2, 1};
284 rb.Push(ResultSuccess); 287 rb.Push(ResultSuccess);
285 rb.PushCopyObjects(buffer_event.GetReadableEvent()); 288 rb.PushCopyObjects(buffer_event->GetReadableEvent());
286 } 289 }
287 290
288 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { 291 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
@@ -299,7 +302,7 @@ private:
299 302
300 IPC::ResponseBuilder rb{ctx, 2, 1}; 303 IPC::ResponseBuilder rb{ctx, 2, 1};
301 rb.Push(ResultSuccess); 304 rb.Push(ResultSuccess);
302 rb.PushCopyObjects(buffer_event.GetReadableEvent()); 305 rb.PushCopyObjects(buffer_event->GetReadableEvent());
303 } 306 }
304 307
305 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { 308 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
@@ -307,16 +310,15 @@ private:
307 310
308 IPC::ResponseBuilder rb{ctx, 2, 1}; 311 IPC::ResponseBuilder rb{ctx, 2, 1};
309 rb.Push(ResultSuccess); 312 rb.Push(ResultSuccess);
310 rb.PushCopyObjects(buffer_event.GetReadableEvent()); 313 rb.PushCopyObjects(buffer_event->GetReadableEvent());
311 } 314 }
312 315
313 Kernel::KEvent& buffer_event; 316 Kernel::KEvent* buffer_event;
314 u32_le revision = 0; 317 u32_le revision = 0;
315}; 318};
316 319
317AudRenU::AudRenU(Core::System& system_) 320AudRenU::AudRenU(Core::System& system_)
318 : ServiceFramework{system_, "audren:u"}, buffer_event{system.Kernel()} { 321 : ServiceFramework{system_, "audren:u"}, service_context{system_, "audren:u"} {
319
320 // clang-format off 322 // clang-format off
321 static const FunctionInfo functions[] = { 323 static const FunctionInfo functions[] = {
322 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 324 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
@@ -329,11 +331,12 @@ AudRenU::AudRenU(Core::System& system_)
329 331
330 RegisterHandlers(functions); 332 RegisterHandlers(functions);
331 333
332 Kernel::KAutoObject::Create(std::addressof(buffer_event)); 334 buffer_event = service_context.CreateEvent("IAudioOutBufferReleasedEvent");
333 buffer_event.Initialize("IAudioOutBufferReleasedEvent");
334} 335}
335 336
336AudRenU::~AudRenU() = default; 337AudRenU::~AudRenU() {
338 service_context.CloseEvent(buffer_event);
339}
337 340
338void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 341void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
339 LOG_DEBUG(Service_Audio, "called"); 342 LOG_DEBUG(Service_Audio, "called");
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 0ee6f9542..5922b4b27 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_event.h" 7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Core { 10namespace Core {
@@ -31,8 +31,10 @@ private:
31 31
32 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); 32 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
33 33
34 KernelHelpers::ServiceContext service_context;
35
34 std::size_t audren_instance_count = 0; 36 std::size_t audren_instance_count = 0;
35 Kernel::KEvent buffer_event; 37 Kernel::KEvent* buffer_event;
36}; 38};
37 39
38// Describes a particular audio feature that may be supported in a particular revision. 40// Describes a particular audio feature that may be supported in a particular revision.
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 33a6dbbb6..7da1f2969 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -13,7 +13,6 @@
13#include "common/assert.h" 13#include "common/assert.h"
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/service/audio/hwopus.h" 16#include "core/hle/service/audio/hwopus.h"
18 17
19namespace Service::Audio { 18namespace Service::Audio {
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index a78544c88..4c7d3bb6e 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -5,22 +5,24 @@
5#include "common/hex_util.h" 5#include "common/hex_util.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/kernel/k_readable_event.h" 8#include "core/hle/kernel/k_event.h"
9#include "core/hle/kernel/k_writable_event.h"
10#include "core/hle/lock.h" 9#include "core/hle/lock.h"
11#include "core/hle/service/bcat/backend/backend.h" 10#include "core/hle/service/bcat/backend/backend.h"
12 11
13namespace Service::BCAT { 12namespace Service::BCAT {
14 13
15ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel, 14ProgressServiceBackend::ProgressServiceBackend(Core::System& system, std::string_view event_name)
16 std::string_view event_name) 15 : service_context{system, "ProgressServiceBackend"} {
17 : update_event{kernel} { 16 update_event = service_context.CreateEvent("ProgressServiceBackend:UpdateEvent:" +
18 Kernel::KAutoObject::Create(std::addressof(update_event)); 17 std::string(event_name));
19 update_event.Initialize("ProgressServiceBackend:UpdateEvent:" + std::string(event_name)); 18}
19
20ProgressServiceBackend::~ProgressServiceBackend() {
21 service_context.CloseEvent(update_event);
20} 22}
21 23
22Kernel::KReadableEvent& ProgressServiceBackend::GetEvent() { 24Kernel::KReadableEvent& ProgressServiceBackend::GetEvent() {
23 return update_event.GetReadableEvent(); 25 return update_event->GetReadableEvent();
24} 26}
25 27
26DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { 28DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
@@ -88,9 +90,9 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
88void ProgressServiceBackend::SignalUpdate() { 90void ProgressServiceBackend::SignalUpdate() {
89 if (need_hle_lock) { 91 if (need_hle_lock) {
90 std::lock_guard lock(HLE::g_hle_lock); 92 std::lock_guard lock(HLE::g_hle_lock);
91 update_event.GetWritableEvent().Signal(); 93 update_event->GetWritableEvent().Signal();
92 } else { 94 } else {
93 update_event.GetWritableEvent().Signal(); 95 update_event->GetWritableEvent().Signal();
94 } 96 }
95} 97}
96 98
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h
index e79a9c2ad..749e046c7 100644
--- a/src/core/hle/service/bcat/backend/backend.h
+++ b/src/core/hle/service/bcat/backend/backend.h
@@ -11,8 +11,8 @@
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/file_sys/vfs_types.h" 13#include "core/file_sys/vfs_types.h"
14#include "core/hle/kernel/k_event.h"
15#include "core/hle/result.h" 14#include "core/hle/result.h"
15#include "core/hle/service/kernel_helpers.h"
16 16
17namespace Core { 17namespace Core {
18class System; 18class System;
@@ -70,6 +70,8 @@ class ProgressServiceBackend {
70 friend class IBcatService; 70 friend class IBcatService;
71 71
72public: 72public:
73 ~ProgressServiceBackend();
74
73 // Clients should call this with true if any of the functions are going to be called from a 75 // Clients should call this with true if any of the functions are going to be called from a
74 // non-HLE thread and this class need to lock the hle mutex. (default is false) 76 // non-HLE thread and this class need to lock the hle mutex. (default is false)
75 void SetNeedHLELock(bool need); 77 void SetNeedHLELock(bool need);
@@ -97,15 +99,17 @@ public:
97 void FinishDownload(ResultCode result); 99 void FinishDownload(ResultCode result);
98 100
99private: 101private:
100 explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name); 102 explicit ProgressServiceBackend(Core::System& system, std::string_view event_name);
101 103
102 Kernel::KReadableEvent& GetEvent(); 104 Kernel::KReadableEvent& GetEvent();
103 DeliveryCacheProgressImpl& GetImpl(); 105 DeliveryCacheProgressImpl& GetImpl();
104 106
105 void SignalUpdate(); 107 void SignalUpdate();
106 108
109 KernelHelpers::ServiceContext service_context;
110
107 DeliveryCacheProgressImpl impl{}; 111 DeliveryCacheProgressImpl impl{};
108 Kernel::KEvent update_event; 112 Kernel::KEvent* update_event;
109 bool need_hle_lock = false; 113 bool need_hle_lock = false;
110}; 114};
111 115
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
deleted file mode 100644
index 7ca7f2aac..000000000
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ /dev/null
@@ -1,548 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <fmt/ostream.h>
6
7#ifdef __GNUC__
8#pragma GCC diagnostic push
9#pragma GCC diagnostic ignored "-Wshadow"
10#ifndef __clang__
11#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
12#endif
13#endif
14#include <httplib.h>
15#include <mbedtls/sha256.h>
16#include <nlohmann/json.hpp>
17#ifdef __GNUC__
18#pragma GCC diagnostic pop
19#endif
20
21#include "common/fs/file.h"
22#include "common/fs/fs.h"
23#include "common/fs/path_util.h"
24#include "common/hex_util.h"
25#include "common/logging/log.h"
26#include "common/settings.h"
27#include "core/core.h"
28#include "core/file_sys/vfs.h"
29#include "core/file_sys/vfs_libzip.h"
30#include "core/file_sys/vfs_vector.h"
31#include "core/frontend/applets/error.h"
32#include "core/hle/service/am/applets/applets.h"
33#include "core/hle/service/bcat/backend/boxcat.h"
34
35namespace Service::BCAT {
36namespace {
37
38// Prevents conflicts with windows macro called CreateFile
39FileSys::VirtualFile VfsCreateFileWrap(FileSys::VirtualDir dir, std::string_view name) {
40 return dir->CreateFile(name);
41}
42
43// Prevents conflicts with windows macro called DeleteFile
44bool VfsDeleteFileWrap(FileSys::VirtualDir dir, std::string_view name) {
45 return dir->DeleteFile(name);
46}
47
48constexpr ResultCode ERROR_GENERAL_BCAT_FAILURE{ErrorModule::BCAT, 1};
49
50constexpr char BOXCAT_HOSTNAME[] = "api.yuzu-emu.org";
51
52// Formatted using fmt with arg[0] = hex title id
53constexpr char BOXCAT_PATHNAME_DATA[] = "/game-assets/{:016X}/boxcat";
54constexpr char BOXCAT_PATHNAME_LAUNCHPARAM[] = "/game-assets/{:016X}/launchparam";
55
56constexpr char BOXCAT_PATHNAME_EVENTS[] = "/game-assets/boxcat/events";
57
58constexpr char BOXCAT_API_VERSION[] = "1";
59constexpr char BOXCAT_CLIENT_TYPE[] = "yuzu";
60
61// HTTP status codes for Boxcat
62enum class ResponseStatus {
63 Ok = 200, ///< Operation completed successfully.
64 BadClientVersion = 301, ///< The Boxcat-Client-Version doesn't match the server.
65 NoUpdate = 304, ///< The digest provided would match the new data, no need to update.
66 NoMatchTitleId = 404, ///< The title ID provided doesn't have a boxcat implementation.
67 NoMatchBuildId = 406, ///< The build ID provided is blacklisted (potentially because of format
68 ///< issues or whatnot) and has no data.
69};
70
71enum class DownloadResult {
72 Success = 0,
73 NoResponse,
74 GeneralWebError,
75 NoMatchTitleId,
76 NoMatchBuildId,
77 InvalidContentType,
78 GeneralFSError,
79 BadClientVersion,
80};
81
82constexpr std::array<const char*, 8> DOWNLOAD_RESULT_LOG_MESSAGES{
83 "Success",
84 "There was no response from the server.",
85 "There was a general web error code returned from the server.",
86 "The title ID of the current game doesn't have a boxcat implementation. If you believe an "
87 "implementation should be added, contact yuzu support.",
88 "The build ID of the current version of the game is marked as incompatible with the current "
89 "BCAT distribution. Try upgrading or downgrading your game version or contacting yuzu support.",
90 "The content type of the web response was invalid.",
91 "There was a general filesystem error while saving the zip file.",
92 "The server is either too new or too old to serve the request. Try using the latest version of "
93 "an official release of yuzu.",
94};
95
96std::ostream& operator<<(std::ostream& os, DownloadResult result) {
97 return os << DOWNLOAD_RESULT_LOG_MESSAGES.at(static_cast<std::size_t>(result));
98}
99
100constexpr u32 PORT = 443;
101constexpr u32 TIMEOUT_SECONDS = 30;
102[[maybe_unused]] constexpr u64 VFS_COPY_BLOCK_SIZE = 1ULL << 24; // 4MB
103
104std::filesystem::path GetBINFilePath(u64 title_id) {
105 return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" /
106 fmt::format("{:016X}/launchparam.bin", title_id);
107}
108
109std::filesystem::path GetZIPFilePath(u64 title_id) {
110 return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" /
111 fmt::format("{:016X}/data.zip", title_id);
112}
113
114// If the error is something the user should know about (build ID mismatch, bad client version),
115// display an error.
116void HandleDownloadDisplayResult(const AM::Applets::AppletManager& applet_manager,
117 DownloadResult res) {
118 if (res == DownloadResult::Success || res == DownloadResult::NoResponse ||
119 res == DownloadResult::GeneralWebError || res == DownloadResult::GeneralFSError ||
120 res == DownloadResult::NoMatchTitleId || res == DownloadResult::InvalidContentType) {
121 return;
122 }
123
124 const auto& frontend{applet_manager.GetAppletFrontendSet()};
125 frontend.error->ShowCustomErrorText(
126 ResultUnknown, "There was an error while attempting to use Boxcat.",
127 DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {});
128}
129
130bool VfsRawCopyProgress(FileSys::VirtualFile src, FileSys::VirtualFile dest,
131 std::string_view dir_name, ProgressServiceBackend& progress,
132 std::size_t block_size = 0x1000) {
133 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
134 return false;
135 if (!dest->Resize(src->GetSize()))
136 return false;
137
138 progress.StartDownloadingFile(dir_name, src->GetName(), src->GetSize());
139
140 std::vector<u8> temp(std::min(block_size, src->GetSize()));
141 for (std::size_t i = 0; i < src->GetSize(); i += block_size) {
142 const auto read = std::min(block_size, src->GetSize() - i);
143
144 if (src->Read(temp.data(), read, i) != read) {
145 return false;
146 }
147
148 if (dest->Write(temp.data(), read, i) != read) {
149 return false;
150 }
151
152 progress.UpdateFileProgress(i);
153 }
154
155 progress.FinishDownloadingFile();
156
157 return true;
158}
159
160bool VfsRawCopyDProgressSingle(FileSys::VirtualDir src, FileSys::VirtualDir dest,
161 ProgressServiceBackend& progress, std::size_t block_size = 0x1000) {
162 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
163 return false;
164
165 for (const auto& file : src->GetFiles()) {
166 const auto out_file = VfsCreateFileWrap(dest, file->GetName());
167 if (!VfsRawCopyProgress(file, out_file, src->GetName(), progress, block_size)) {
168 return false;
169 }
170 }
171 progress.CommitDirectory(src->GetName());
172
173 return true;
174}
175
176bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest,
177 ProgressServiceBackend& progress, std::size_t block_size = 0x1000) {
178 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
179 return false;
180
181 for (const auto& dir : src->GetSubdirectories()) {
182 const auto out = dest->CreateSubdirectory(dir->GetName());
183 if (!VfsRawCopyDProgressSingle(dir, out, progress, block_size)) {
184 return false;
185 }
186 }
187
188 return true;
189}
190
191} // Anonymous namespace
192
193class Boxcat::Client {
194public:
195 Client(std::filesystem::path path_, u64 title_id_, u64 build_id_)
196 : path(std::move(path_)), title_id(title_id_), build_id(build_id_) {}
197
198 DownloadResult DownloadDataZip() {
199 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS,
200 "application/zip");
201 }
202
203 DownloadResult DownloadLaunchParam() {
204 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_LAUNCHPARAM, title_id),
205 TIMEOUT_SECONDS / 3, "application/octet-stream");
206 }
207
208private:
209 DownloadResult DownloadInternal(const std::string& resolved_path, u32 timeout_seconds,
210 const std::string& content_type_name) {
211 if (client == nullptr) {
212 client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT);
213 client->set_connection_timeout(timeout_seconds);
214 client->set_read_timeout(timeout_seconds);
215 client->set_write_timeout(timeout_seconds);
216 }
217
218 httplib::Headers headers{
219 {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
220 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
221 {std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)},
222 };
223
224 if (Common::FS::Exists(path)) {
225 Common::FS::IOFile file{path, Common::FS::FileAccessMode::Read,
226 Common::FS::FileType::BinaryFile};
227 if (file.IsOpen()) {
228 std::vector<u8> bytes(file.GetSize());
229 void(file.Read(bytes));
230 const auto digest = DigestFile(bytes);
231 headers.insert({std::string("If-None-Match"), Common::HexToString(digest, false)});
232 }
233 }
234
235 const auto response = client->Get(resolved_path.c_str(), headers);
236 if (response == nullptr)
237 return DownloadResult::NoResponse;
238
239 if (response->status == static_cast<int>(ResponseStatus::NoUpdate))
240 return DownloadResult::Success;
241 if (response->status == static_cast<int>(ResponseStatus::BadClientVersion))
242 return DownloadResult::BadClientVersion;
243 if (response->status == static_cast<int>(ResponseStatus::NoMatchTitleId))
244 return DownloadResult::NoMatchTitleId;
245 if (response->status == static_cast<int>(ResponseStatus::NoMatchBuildId))
246 return DownloadResult::NoMatchBuildId;
247 if (response->status != static_cast<int>(ResponseStatus::Ok))
248 return DownloadResult::GeneralWebError;
249
250 const auto content_type = response->headers.find("content-type");
251 if (content_type == response->headers.end() ||
252 content_type->second.find(content_type_name) == std::string::npos) {
253 return DownloadResult::InvalidContentType;
254 }
255
256 if (!Common::FS::CreateDirs(path)) {
257 return DownloadResult::GeneralFSError;
258 }
259
260 Common::FS::IOFile file{path, Common::FS::FileAccessMode::Append,
261 Common::FS::FileType::BinaryFile};
262 if (!file.IsOpen()) {
263 return DownloadResult::GeneralFSError;
264 }
265
266 if (!file.SetSize(response->body.size())) {
267 return DownloadResult::GeneralFSError;
268 }
269
270 if (file.Write(response->body) != response->body.size()) {
271 return DownloadResult::GeneralFSError;
272 }
273
274 return DownloadResult::Success;
275 }
276
277 using Digest = std::array<u8, 0x20>;
278 static Digest DigestFile(std::vector<u8> bytes) {
279 Digest out{};
280 mbedtls_sha256_ret(bytes.data(), bytes.size(), out.data(), 0);
281 return out;
282 }
283
284 std::unique_ptr<httplib::SSLClient> client;
285 std::filesystem::path path;
286 u64 title_id;
287 u64 build_id;
288};
289
290Boxcat::Boxcat(AM::Applets::AppletManager& applet_manager_, DirectoryGetter getter)
291 : Backend(std::move(getter)), applet_manager{applet_manager_} {}
292
293Boxcat::~Boxcat() = default;
294
295void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGetter dir_getter,
296 TitleIDVersion title, ProgressServiceBackend& progress,
297 std::optional<std::string> dir_name = {}) {
298 progress.SetNeedHLELock(true);
299
300 if (Settings::values.bcat_boxcat_local) {
301 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download.");
302 const auto dir = dir_getter(title.title_id);
303 if (dir)
304 progress.SetTotalSize(dir->GetSize());
305 progress.FinishDownload(ResultSuccess);
306 return;
307 }
308
309 const auto zip_path = GetZIPFilePath(title.title_id);
310 Boxcat::Client client{zip_path, title.title_id, title.build_id};
311
312 progress.StartConnecting();
313
314 const auto res = client.DownloadDataZip();
315 if (res != DownloadResult::Success) {
316 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
317
318 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
319 Common::FS::RemoveFile(zip_path);
320 }
321
322 HandleDownloadDisplayResult(applet_manager, res);
323 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
324 return;
325 }
326
327 progress.StartProcessingDataList();
328
329 Common::FS::IOFile zip{zip_path, Common::FS::FileAccessMode::Read,
330 Common::FS::FileType::BinaryFile};
331 const auto size = zip.GetSize();
332 std::vector<u8> bytes(size);
333 if (!zip.IsOpen() || size == 0 || zip.Read(bytes) != bytes.size()) {
334 LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!",
335 Common::FS::PathToUTF8String(zip_path));
336 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
337 return;
338 }
339
340 const auto extracted = FileSys::ExtractZIP(std::make_shared<FileSys::VectorVfsFile>(bytes));
341 if (extracted == nullptr) {
342 LOG_ERROR(Service_BCAT, "Boxcat failed to extract ZIP file!");
343 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
344 return;
345 }
346
347 if (dir_name == std::nullopt) {
348 progress.SetTotalSize(extracted->GetSize());
349
350 const auto target_dir = dir_getter(title.title_id);
351 if (target_dir == nullptr || !VfsRawCopyDProgress(extracted, target_dir, progress)) {
352 LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!");
353 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
354 return;
355 }
356 } else {
357 const auto target_dir = dir_getter(title.title_id);
358 if (target_dir == nullptr) {
359 LOG_ERROR(Service_BCAT, "Boxcat failed to get directory for title ID!");
360 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
361 return;
362 }
363
364 const auto target_sub = target_dir->GetSubdirectory(*dir_name);
365 const auto source_sub = extracted->GetSubdirectory(*dir_name);
366
367 progress.SetTotalSize(source_sub->GetSize());
368
369 std::vector<std::string> filenames;
370 {
371 const auto files = target_sub->GetFiles();
372 std::transform(files.begin(), files.end(), std::back_inserter(filenames),
373 [](const auto& vfile) { return vfile->GetName(); });
374 }
375
376 for (const auto& filename : filenames) {
377 VfsDeleteFileWrap(target_sub, filename);
378 }
379
380 if (target_sub == nullptr || source_sub == nullptr ||
381 !VfsRawCopyDProgressSingle(source_sub, target_sub, progress)) {
382 LOG_ERROR(Service_BCAT, "Boxcat failed to copy extracted ZIP to target directory!");
383 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
384 return;
385 }
386 }
387
388 progress.FinishDownload(ResultSuccess);
389}
390
391bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) {
392 is_syncing.exchange(true);
393
394 std::thread([this, title, &progress] {
395 SynchronizeInternal(applet_manager, dir_getter, title, progress);
396 }).detach();
397
398 return true;
399}
400
401bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name,
402 ProgressServiceBackend& progress) {
403 is_syncing.exchange(true);
404
405 std::thread([this, title, name, &progress] {
406 SynchronizeInternal(applet_manager, dir_getter, title, progress, name);
407 }).detach();
408
409 return true;
410}
411
412bool Boxcat::Clear(u64 title_id) {
413 if (Settings::values.bcat_boxcat_local) {
414 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping clear.");
415 return true;
416 }
417
418 const auto dir = dir_getter(title_id);
419
420 std::vector<std::string> dirnames;
421
422 for (const auto& subdir : dir->GetSubdirectories())
423 dirnames.push_back(subdir->GetName());
424
425 for (const auto& subdir : dirnames) {
426 if (!dir->DeleteSubdirectoryRecursive(subdir))
427 return false;
428 }
429
430 return true;
431}
432
433void Boxcat::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
434 LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
435 Common::HexToString(passphrase));
436}
437
438std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) {
439 const auto bin_file_path = GetBINFilePath(title.title_id);
440
441 if (Settings::values.bcat_boxcat_local) {
442 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download.");
443 } else {
444 Client launch_client{bin_file_path, title.title_id, title.build_id};
445
446 const auto res = launch_client.DownloadLaunchParam();
447 if (res != DownloadResult::Success) {
448 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
449
450 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
451 Common::FS::RemoveFile(bin_file_path);
452 }
453
454 HandleDownloadDisplayResult(applet_manager, res);
455 return std::nullopt;
456 }
457 }
458
459 Common::FS::IOFile bin{bin_file_path, Common::FS::FileAccessMode::Read,
460 Common::FS::FileType::BinaryFile};
461 const auto size = bin.GetSize();
462 std::vector<u8> bytes(size);
463 if (!bin.IsOpen() || size == 0 || bin.Read(bytes) != bytes.size()) {
464 LOG_ERROR(Service_BCAT, "Boxcat failed to read launch parameter binary at path '{}'!",
465 Common::FS::PathToUTF8String(bin_file_path));
466 return std::nullopt;
467 }
468
469 return bytes;
470}
471
472Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
473 std::map<std::string, EventStatus>& games) {
474 httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)};
475 client.set_connection_timeout(static_cast<int>(TIMEOUT_SECONDS));
476 client.set_read_timeout(static_cast<int>(TIMEOUT_SECONDS));
477 client.set_write_timeout(static_cast<int>(TIMEOUT_SECONDS));
478
479 httplib::Headers headers{
480 {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
481 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
482 };
483
484 if (!client.is_valid()) {
485 LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
486 return StatusResult::Offline;
487 }
488
489 if (!client.is_socket_open()) {
490 LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
491 return StatusResult::Offline;
492 }
493
494 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
495 if (response == nullptr)
496 return StatusResult::Offline;
497
498 if (response->status == static_cast<int>(ResponseStatus::BadClientVersion))
499 return StatusResult::BadClientVersion;
500
501 try {
502 nlohmann::json json = nlohmann::json::parse(response->body);
503
504 if (!json["online"].get<bool>())
505 return StatusResult::Offline;
506
507 if (json["global"].is_null())
508 global = std::nullopt;
509 else
510 global = json["global"].get<std::string>();
511
512 if (json["games"].is_array()) {
513 for (const auto& object : json["games"]) {
514 if (object.is_object() && object.find("name") != object.end()) {
515 EventStatus detail{};
516 if (object["header"].is_string()) {
517 detail.header = object["header"].get<std::string>();
518 } else {
519 detail.header = std::nullopt;
520 }
521
522 if (object["footer"].is_string()) {
523 detail.footer = object["footer"].get<std::string>();
524 } else {
525 detail.footer = std::nullopt;
526 }
527
528 if (object["events"].is_array()) {
529 for (const auto& event : object["events"]) {
530 if (!event.is_string())
531 continue;
532 detail.events.push_back(event.get<std::string>());
533 }
534 }
535
536 games.insert_or_assign(object["name"], std::move(detail));
537 }
538 }
539 }
540
541 return StatusResult::Success;
542 } catch (const nlohmann::json::parse_error& error) {
543 LOG_ERROR(Service_BCAT, "{}", error.what());
544 return StatusResult::ParseError;
545 }
546}
547
548} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/backend/boxcat.h b/src/core/hle/service/bcat/backend/boxcat.h
deleted file mode 100644
index d65b42e58..000000000
--- a/src/core/hle/service/bcat/backend/boxcat.h
+++ /dev/null
@@ -1,64 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <map>
9#include <optional>
10#include "core/hle/service/bcat/backend/backend.h"
11
12namespace Service::AM::Applets {
13class AppletManager;
14}
15
16namespace Service::BCAT {
17
18struct EventStatus {
19 std::optional<std::string> header;
20 std::optional<std::string> footer;
21 std::vector<std::string> events;
22};
23
24/// Boxcat is yuzu's custom backend implementation of Nintendo's BCAT service. It is free to use and
25/// doesn't require a switch or nintendo account. The content is controlled by the yuzu team.
26class Boxcat final : public Backend {
27 friend void SynchronizeInternal(AM::Applets::AppletManager& applet_manager,
28 DirectoryGetter dir_getter, TitleIDVersion title,
29 ProgressServiceBackend& progress,
30 std::optional<std::string> dir_name);
31
32public:
33 explicit Boxcat(AM::Applets::AppletManager& applet_manager_, DirectoryGetter getter);
34 ~Boxcat() override;
35
36 bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override;
37 bool SynchronizeDirectory(TitleIDVersion title, std::string name,
38 ProgressServiceBackend& progress) override;
39
40 bool Clear(u64 title_id) override;
41
42 void SetPassphrase(u64 title_id, const Passphrase& passphrase) override;
43
44 std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override;
45
46 enum class StatusResult {
47 Success,
48 Offline,
49 ParseError,
50 BadClientVersion,
51 };
52
53 static StatusResult GetStatus(std::optional<std::string>& global,
54 std::map<std::string, EventStatus>& games);
55
56private:
57 std::atomic_bool is_syncing{false};
58
59 class Client;
60 std::unique_ptr<Client> client;
61 AM::Applets::AppletManager& applet_manager;
62};
63
64} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp
index 72294eb2e..27e9b8df8 100644
--- a/src/core/hle/service/bcat/bcat_module.cpp
+++ b/src/core/hle/service/bcat/bcat_module.cpp
@@ -4,7 +4,6 @@
4 4
5#include <cctype> 5#include <cctype>
6#include <mbedtls/md5.h> 6#include <mbedtls/md5.h>
7#include "backend/boxcat.h"
8#include "common/hex_util.h" 7#include "common/hex_util.h"
9#include "common/logging/log.h" 8#include "common/logging/log.h"
10#include "common/settings.h" 9#include "common/settings.h"
@@ -128,8 +127,8 @@ public:
128 explicit IBcatService(Core::System& system_, Backend& backend_) 127 explicit IBcatService(Core::System& system_, Backend& backend_)
129 : ServiceFramework{system_, "IBcatService"}, backend{backend_}, 128 : ServiceFramework{system_, "IBcatService"}, backend{backend_},
130 progress{{ 129 progress{{
131 ProgressServiceBackend{system_.Kernel(), "Normal"}, 130 ProgressServiceBackend{system_, "Normal"},
132 ProgressServiceBackend{system_.Kernel(), "Directory"}, 131 ProgressServiceBackend{system_, "Directory"},
133 }} { 132 }} {
134 // clang-format off 133 // clang-format off
135 static const FunctionInfo functions[] = { 134 static const FunctionInfo functions[] = {
@@ -578,12 +577,6 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
578 577
579std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system, 578std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
580 DirectoryGetter getter) { 579 DirectoryGetter getter) {
581#ifdef YUZU_ENABLE_BOXCAT
582 if (Settings::values.bcat_backend.GetValue() == "boxcat") {
583 return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
584 }
585#endif
586
587 return std::make_unique<NullBackend>(std::move(getter)); 580 return std::make_unique<NullBackend>(std::move(getter));
588} 581}
589 582
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 46da438ef..088a1a18a 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -5,11 +5,10 @@
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/hle_ipc.h"
9#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_readable_event.h"
11#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
12#include "core/hle/service/btdrv/btdrv.h" 10#include "core/hle/service/btdrv/btdrv.h"
11#include "core/hle/service/kernel_helpers.h"
13#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
14#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
15 14
@@ -18,7 +17,7 @@ namespace Service::BtDrv {
18class Bt final : public ServiceFramework<Bt> { 17class Bt final : public ServiceFramework<Bt> {
19public: 18public:
20 explicit Bt(Core::System& system_) 19 explicit Bt(Core::System& system_)
21 : ServiceFramework{system_, "bt"}, register_event{system.Kernel()} { 20 : ServiceFramework{system_, "bt"}, service_context{system_, "bt"} {
22 // clang-format off 21 // clang-format off
23 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
24 {0, nullptr, "LeClientReadCharacteristic"}, 23 {0, nullptr, "LeClientReadCharacteristic"},
@@ -35,8 +34,11 @@ public:
35 // clang-format on 34 // clang-format on
36 RegisterHandlers(functions); 35 RegisterHandlers(functions);
37 36
38 Kernel::KAutoObject::Create(std::addressof(register_event)); 37 register_event = service_context.CreateEvent("BT:RegisterEvent");
39 register_event.Initialize("BT:RegisterEvent"); 38 }
39
40 ~Bt() override {
41 service_context.CloseEvent(register_event);
40 } 42 }
41 43
42private: 44private:
@@ -45,10 +47,12 @@ private:
45 47
46 IPC::ResponseBuilder rb{ctx, 2, 1}; 48 IPC::ResponseBuilder rb{ctx, 2, 1};
47 rb.Push(ResultSuccess); 49 rb.Push(ResultSuccess);
48 rb.PushCopyObjects(register_event.GetReadableEvent()); 50 rb.PushCopyObjects(register_event->GetReadableEvent());
49 } 51 }
50 52
51 Kernel::KEvent register_event; 53 KernelHelpers::ServiceContext service_context;
54
55 Kernel::KEvent* register_event;
52}; 56};
53 57
54class BtDrv final : public ServiceFramework<BtDrv> { 58class BtDrv final : public ServiceFramework<BtDrv> {
@@ -175,6 +179,10 @@ public:
175 {143, nullptr, "GetAudioControlInputState"}, 179 {143, nullptr, "GetAudioControlInputState"},
176 {144, nullptr, "AcquireAudioConnectionStateChangedEvent"}, 180 {144, nullptr, "AcquireAudioConnectionStateChangedEvent"},
177 {145, nullptr, "GetConnectedAudioDevice"}, 181 {145, nullptr, "GetConnectedAudioDevice"},
182 {146, nullptr, "CloseAudioControlInput"},
183 {147, nullptr, "RegisterAudioControlNotification"},
184 {148, nullptr, "SendAudioControlPassthroughCommand"},
185 {149, nullptr, "SendAudioControlSetAbsoluteVolumeCommand"},
178 {256, nullptr, "IsManufacturingMode"}, 186 {256, nullptr, "IsManufacturingMode"},
179 {257, nullptr, "EmulateBluetoothCrash"}, 187 {257, nullptr, "EmulateBluetoothCrash"},
180 {258, nullptr, "GetBleChannelMap"}, 188 {258, nullptr, "GetBleChannelMap"},
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 3ab29036a..7aabacc19 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -7,11 +7,10 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/hle_ipc.h"
11#include "core/hle/kernel/k_event.h" 10#include "core/hle/kernel/k_event.h"
12#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/btm/btm.h" 12#include "core/hle/service/btm/btm.h"
13#include "core/hle/service/kernel_helpers.h"
15#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
16 15
17namespace Service::BTM { 16namespace Service::BTM {
@@ -19,9 +18,7 @@ namespace Service::BTM {
19class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { 18class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
20public: 19public:
21 explicit IBtmUserCore(Core::System& system_) 20 explicit IBtmUserCore(Core::System& system_)
22 : ServiceFramework{system_, "IBtmUserCore"}, scan_event{system.Kernel()}, 21 : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
23 connection_event{system.Kernel()}, service_discovery{system.Kernel()},
24 config_event{system.Kernel()} {
25 // clang-format off 22 // clang-format off
26 static const FunctionInfo functions[] = { 23 static const FunctionInfo functions[] = {
27 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, 24 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
@@ -60,15 +57,17 @@ public:
60 // clang-format on 57 // clang-format on
61 RegisterHandlers(functions); 58 RegisterHandlers(functions);
62 59
63 Kernel::KAutoObject::Create(std::addressof(scan_event)); 60 scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
64 Kernel::KAutoObject::Create(std::addressof(connection_event)); 61 connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
65 Kernel::KAutoObject::Create(std::addressof(service_discovery)); 62 service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
66 Kernel::KAutoObject::Create(std::addressof(config_event)); 63 config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
64 }
67 65
68 scan_event.Initialize("IBtmUserCore:ScanEvent"); 66 ~IBtmUserCore() override {
69 connection_event.Initialize("IBtmUserCore:ConnectionEvent"); 67 service_context.CloseEvent(scan_event);
70 service_discovery.Initialize("IBtmUserCore:Discovery"); 68 service_context.CloseEvent(connection_event);
71 config_event.Initialize("IBtmUserCore:ConfigEvent"); 69 service_context.CloseEvent(service_discovery_event);
70 service_context.CloseEvent(config_event);
72 } 71 }
73 72
74private: 73private:
@@ -77,7 +76,7 @@ private:
77 76
78 IPC::ResponseBuilder rb{ctx, 2, 1}; 77 IPC::ResponseBuilder rb{ctx, 2, 1};
79 rb.Push(ResultSuccess); 78 rb.Push(ResultSuccess);
80 rb.PushCopyObjects(scan_event.GetReadableEvent()); 79 rb.PushCopyObjects(scan_event->GetReadableEvent());
81 } 80 }
82 81
83 void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) { 82 void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) {
@@ -85,7 +84,7 @@ private:
85 84
86 IPC::ResponseBuilder rb{ctx, 2, 1}; 85 IPC::ResponseBuilder rb{ctx, 2, 1};
87 rb.Push(ResultSuccess); 86 rb.Push(ResultSuccess);
88 rb.PushCopyObjects(connection_event.GetReadableEvent()); 87 rb.PushCopyObjects(connection_event->GetReadableEvent());
89 } 88 }
90 89
91 void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) { 90 void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) {
@@ -93,7 +92,7 @@ private:
93 92
94 IPC::ResponseBuilder rb{ctx, 2, 1}; 93 IPC::ResponseBuilder rb{ctx, 2, 1};
95 rb.Push(ResultSuccess); 94 rb.Push(ResultSuccess);
96 rb.PushCopyObjects(service_discovery.GetReadableEvent()); 95 rb.PushCopyObjects(service_discovery_event->GetReadableEvent());
97 } 96 }
98 97
99 void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) { 98 void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) {
@@ -101,13 +100,15 @@ private:
101 100
102 IPC::ResponseBuilder rb{ctx, 2, 1}; 101 IPC::ResponseBuilder rb{ctx, 2, 1};
103 rb.Push(ResultSuccess); 102 rb.Push(ResultSuccess);
104 rb.PushCopyObjects(config_event.GetReadableEvent()); 103 rb.PushCopyObjects(config_event->GetReadableEvent());
105 } 104 }
106 105
107 Kernel::KEvent scan_event; 106 KernelHelpers::ServiceContext service_context;
108 Kernel::KEvent connection_event; 107
109 Kernel::KEvent service_discovery; 108 Kernel::KEvent* scan_event;
110 Kernel::KEvent config_event; 109 Kernel::KEvent* connection_event;
110 Kernel::KEvent* service_discovery_event;
111 Kernel::KEvent* config_event;
111}; 112};
112 113
113class BTM_USR final : public ServiceFramework<BTM_USR> { 114class BTM_USR final : public ServiceFramework<BTM_USR> {
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h
index 3c4290c88..b18adcb9d 100644
--- a/src/core/hle/service/caps/caps.h
+++ b/src/core/hle/service/caps/caps.h
@@ -4,7 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h" 7#include "common/common_funcs.h"
8#include "common/common_types.h"
8 9
9namespace Core { 10namespace Core {
10class System; 11class System;
diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp
index 2b5314691..33a976ddf 100644
--- a/src/core/hle/service/caps/caps_ss.cpp
+++ b/src/core/hle/service/caps/caps_ss.cpp
@@ -15,6 +15,7 @@ CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
15 {204, nullptr, "SaveEditedScreenShotEx0"}, 15 {204, nullptr, "SaveEditedScreenShotEx0"},
16 {206, nullptr, "Unknown206"}, 16 {206, nullptr, "Unknown206"},
17 {208, nullptr, "SaveScreenShotOfMovieEx1"}, 17 {208, nullptr, "SaveScreenShotOfMovieEx1"},
18 {1000, nullptr, "Unknown1000"},
18 }; 19 };
19 // clang-format on 20 // clang-format on
20 21
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index 110c7cb1c..f6184acc9 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -55,6 +55,8 @@ public:
55 {36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"}, 55 {36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"},
56 {37, nullptr, "OwnTicket2"}, 56 {37, nullptr, "OwnTicket2"},
57 {38, nullptr, "OwnTicket3"}, 57 {38, nullptr, "OwnTicket3"},
58 {39, nullptr, "DeleteAllInactivePersonalizedTicket"},
59 {40, nullptr, "DeletePrepurchaseRecordByNintendoAccountId"},
58 {501, nullptr, "Unknown501"}, 60 {501, nullptr, "Unknown501"},
59 {502, nullptr, "Unknown502"}, 61 {502, nullptr, "Unknown502"},
60 {503, nullptr, "GetTitleKey"}, 62 {503, nullptr, "GetTitleKey"},
@@ -88,11 +90,15 @@ public:
88 {1503, nullptr, "Unknown1503"}, 90 {1503, nullptr, "Unknown1503"},
89 {1504, nullptr, "Unknown1504"}, 91 {1504, nullptr, "Unknown1504"},
90 {1505, nullptr, "Unknown1505"}, 92 {1505, nullptr, "Unknown1505"},
93 {1506, nullptr, "Unknown1506"},
91 {2000, nullptr, "Unknown2000"}, 94 {2000, nullptr, "Unknown2000"},
92 {2001, nullptr, "Unknown2001"}, 95 {2001, nullptr, "Unknown2001"},
96 {2002, nullptr, "Unknown2002"},
97 {2003, nullptr, "Unknown2003"},
93 {2100, nullptr, "Unknown2100"}, 98 {2100, nullptr, "Unknown2100"},
94 {2501, nullptr, "Unknown2501"}, 99 {2501, nullptr, "Unknown2501"},
95 {2502, nullptr, "Unknown2502"}, 100 {2502, nullptr, "Unknown2502"},
101 {2601, nullptr, "Unknown2601"},
96 {3001, nullptr, "Unknown3001"}, 102 {3001, nullptr, "Unknown3001"},
97 {3002, nullptr, "Unknown3002"}, 103 {3002, nullptr, "Unknown3002"},
98 }; 104 };
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
index 25c6c0194..d7a638f96 100644
--- a/src/core/hle/service/fgm/fgm.cpp
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -5,7 +5,6 @@
5#include <memory> 5#include <memory>
6 6
7#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/hle_ipc.h"
9#include "core/hle/service/fgm/fgm.h" 8#include "core/hle/service/fgm/fgm.h"
10#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h" 10#include "core/hle/service/sm/sm.h"
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp
index 1f6c17ba5..f112ae9d0 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.cpp
+++ b/src/core/hle/service/filesystem/fsp_ldr.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/service/filesystem/fsp_ldr.h" 5#include "core/hle/service/filesystem/fsp_ldr.h"
6#include "core/hle/service/service.h"
7 6
8namespace Service::FileSystem { 7namespace Service::FileSystem {
9 8
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp
index 00e4d1662..9b7f7d861 100644
--- a/src/core/hle/service/filesystem/fsp_pr.cpp
+++ b/src/core/hle/service/filesystem/fsp_pr.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/service/filesystem/fsp_pr.h" 5#include "core/hle/service/filesystem/fsp_pr.h"
6#include "core/hle/service/service.h"
7 6
8namespace Service::FileSystem { 7namespace Service::FileSystem {
9 8
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index b58c152ce..68c9240ae 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -8,11 +8,10 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/k_event.h" 10#include "core/hle/kernel/k_event.h"
11#include "core/hle/kernel/k_readable_event.h"
12#include "core/hle/kernel/k_writable_event.h"
13#include "core/hle/service/friend/errors.h" 11#include "core/hle/service/friend/errors.h"
14#include "core/hle/service/friend/friend.h" 12#include "core/hle/service/friend/friend.h"
15#include "core/hle/service/friend/friend_interface.h" 13#include "core/hle/service/friend/friend_interface.h"
14#include "core/hle/service/kernel_helpers.h"
16 15
17namespace Service::Friend { 16namespace Service::Friend {
18 17
@@ -184,9 +183,9 @@ private:
184 183
185class INotificationService final : public ServiceFramework<INotificationService> { 184class INotificationService final : public ServiceFramework<INotificationService> {
186public: 185public:
187 explicit INotificationService(Common::UUID uuid_, Core::System& system_) 186 explicit INotificationService(Core::System& system_, Common::UUID uuid_)
188 : ServiceFramework{system_, "INotificationService"}, uuid{uuid_}, notification_event{ 187 : ServiceFramework{system_, "INotificationService"}, uuid{uuid_},
189 system.Kernel()} { 188 service_context{system_, "INotificationService"} {
190 // clang-format off 189 // clang-format off
191 static const FunctionInfo functions[] = { 190 static const FunctionInfo functions[] = {
192 {0, &INotificationService::GetEvent, "GetEvent"}, 191 {0, &INotificationService::GetEvent, "GetEvent"},
@@ -197,8 +196,11 @@ public:
197 196
198 RegisterHandlers(functions); 197 RegisterHandlers(functions);
199 198
200 Kernel::KAutoObject::Create(std::addressof(notification_event)); 199 notification_event = service_context.CreateEvent("INotificationService:NotifyEvent");
201 notification_event.Initialize("INotificationService:NotifyEvent"); 200 }
201
202 ~INotificationService() override {
203 service_context.CloseEvent(notification_event);
202 } 204 }
203 205
204private: 206private:
@@ -207,7 +209,7 @@ private:
207 209
208 IPC::ResponseBuilder rb{ctx, 2, 1}; 210 IPC::ResponseBuilder rb{ctx, 2, 1};
209 rb.Push(ResultSuccess); 211 rb.Push(ResultSuccess);
210 rb.PushCopyObjects(notification_event.GetReadableEvent()); 212 rb.PushCopyObjects(notification_event->GetReadableEvent());
211 } 213 }
212 214
213 void Clear(Kernel::HLERequestContext& ctx) { 215 void Clear(Kernel::HLERequestContext& ctx) {
@@ -272,8 +274,10 @@ private:
272 bool has_received_friend_request; 274 bool has_received_friend_request;
273 }; 275 };
274 276
275 Common::UUID uuid{Common::INVALID_UUID}; 277 Common::UUID uuid;
276 Kernel::KEvent notification_event; 278 KernelHelpers::ServiceContext service_context;
279
280 Kernel::KEvent* notification_event;
277 std::queue<SizedNotificationInfo> notifications; 281 std::queue<SizedNotificationInfo> notifications;
278 States states{}; 282 States states{};
279}; 283};
@@ -293,7 +297,7 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx
293 297
294 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 298 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
295 rb.Push(ResultSuccess); 299 rb.Push(ResultSuccess);
296 rb.PushIpcInterface<INotificationService>(uuid, system); 300 rb.PushIpcInterface<INotificationService>(system, uuid);
297} 301}
298 302
299Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, 303Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index 5a3b54cc1..70cd63c6b 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -8,13 +8,11 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/file_sys/control_metadata.h" 9#include "core/file_sys/control_metadata.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/hle_ipc.h"
12#include "core/hle/kernel/k_process.h" 11#include "core/hle/kernel/k_process.h"
13#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/glue/arp.h" 13#include "core/hle/service/glue/arp.h"
15#include "core/hle/service/glue/errors.h" 14#include "core/hle/service/glue/errors.h"
16#include "core/hle/service/glue/glue_manager.h" 15#include "core/hle/service/glue/glue_manager.h"
17#include "core/hle/service/service.h"
18 16
19namespace Service::Glue { 17namespace Service::Glue {
20 18
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 4fcc6f93a..9ee146caf 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -507,6 +507,7 @@ private:
507 LarkNesRight = 18, 507 LarkNesRight = 18,
508 Lucia = 19, 508 Lucia = 19,
509 Verification = 20, 509 Verification = 20,
510 Lagon = 21,
510 }; 511 };
511 512
512 struct NPadEntry { 513 struct NPadEntry {
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a1707a72a..043320d50 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -8,12 +8,9 @@
8#include "common/settings.h" 8#include "common/settings.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/core_timing.h" 10#include "core/core_timing.h"
11#include "core/core_timing_util.h"
12#include "core/frontend/emu_window.h" 11#include "core/frontend/emu_window.h"
13#include "core/frontend/input.h" 12#include "core/frontend/input.h"
14#include "core/hardware_properties.h"
15#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/k_client_port.h"
17#include "core/hle/kernel/k_readable_event.h" 14#include "core/hle/kernel/k_readable_event.h"
18#include "core/hle/kernel/k_shared_memory.h" 15#include "core/hle/kernel/k_shared_memory.h"
19#include "core/hle/kernel/k_transfer_memory.h" 16#include "core/hle/kernel/k_transfer_memory.h"
@@ -23,7 +20,6 @@
23#include "core/hle/service/hid/hid.h" 20#include "core/hle/service/hid/hid.h"
24#include "core/hle/service/hid/irs.h" 21#include "core/hle/service/hid/irs.h"
25#include "core/hle/service/hid/xcd.h" 22#include "core/hle/service/hid/xcd.h"
26#include "core/hle/service/service.h"
27#include "core/memory.h" 23#include "core/memory.h"
28 24
29#include "core/hle/service/hid/controllers/console_sixaxis.h" 25#include "core/hle/service/hid/controllers/console_sixaxis.h"
@@ -106,7 +102,7 @@ void IAppletResource::DeactivateController(HidController controller) {
106 controllers[static_cast<size_t>(controller)]->DeactivateController(); 102 controllers[static_cast<size_t>(controller)]->DeactivateController();
107} 103}
108 104
109IAppletResource ::~IAppletResource() { 105IAppletResource::~IAppletResource() {
110 system.CoreTiming().UnscheduleEvent(pad_update_event, 0); 106 system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
111 system.CoreTiming().UnscheduleEvent(motion_update_event, 0); 107 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
112} 108}
@@ -239,6 +235,12 @@ Hid::Hid(Core::System& system_)
239 {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"}, 235 {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"},
240 {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, 236 {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
241 {83, &Hid::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"}, 237 {83, &Hid::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"},
238 {84, nullptr, "EnableSixAxisSensorUnalteredPassthrough"},
239 {85, nullptr, "IsSixAxisSensorUnalteredPassthroughEnabled"},
240 {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
241 {87, nullptr, "LoadSixAxisSensorCalibrationParameter"},
242 {88, nullptr, "GetSixAxisSensorIcInformation"},
243 {89, nullptr, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
242 {91, &Hid::ActivateGesture, "ActivateGesture"}, 244 {91, &Hid::ActivateGesture, "ActivateGesture"},
243 {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, 245 {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
244 {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, 246 {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
@@ -1656,6 +1658,9 @@ public:
1656 {12, nullptr, "UnsetTouchScreenAutoPilotState"}, 1658 {12, nullptr, "UnsetTouchScreenAutoPilotState"},
1657 {13, nullptr, "GetTouchScreenConfiguration"}, 1659 {13, nullptr, "GetTouchScreenConfiguration"},
1658 {14, nullptr, "ProcessTouchScreenAutoTune"}, 1660 {14, nullptr, "ProcessTouchScreenAutoTune"},
1661 {15, nullptr, "ForceStopTouchScreenManagement"},
1662 {16, nullptr, "ForceRestartTouchScreenManagement"},
1663 {17, nullptr, "IsTouchScreenManaged"},
1659 {20, nullptr, "DeactivateMouse"}, 1664 {20, nullptr, "DeactivateMouse"},
1660 {21, nullptr, "SetMouseAutoPilotState"}, 1665 {21, nullptr, "SetMouseAutoPilotState"},
1661 {22, nullptr, "UnsetMouseAutoPilotState"}, 1666 {22, nullptr, "UnsetMouseAutoPilotState"},
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 24890c830..5c8ae029c 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -2,11 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cmath>
5#include <memory> 6#include <memory>
6 7
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/lbl/lbl.h" 10#include "core/hle/service/lbl/lbl.h"
11#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h" 12#include "core/hle/service/sm/sm.h"
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 9d863486a..0b907824d 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -6,7 +6,6 @@
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/mii/mii.h" 9#include "core/hle/service/mii/mii.h"
11#include "core/hle/service/mii/mii_manager.h" 10#include "core/hle/service/mii/mii_manager.h"
12#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index b014ea826..f77037842 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -7,7 +7,6 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/settings.h" 8#include "common/settings.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/hle_ipc.h"
11#include "core/hle/service/nfc/nfc.h" 10#include "core/hle/service/nfc/nfc.h"
12#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
13#include "core/hle/service/sm/sm.h" 12#include "core/hle/service/sm/sm.h"
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 5f1ca029d..6791f20a5 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -8,9 +8,8 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/k_readable_event.h" 11#include "core/hle/kernel/k_event.h"
12#include "core/hle/kernel/k_thread.h" 12#include "core/hle/kernel/k_thread.h"
13#include "core/hle/kernel/k_writable_event.h"
14#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
15#include "core/hle/lock.h" 14#include "core/hle/lock.h"
16#include "core/hle/service/nfp/nfp.h" 15#include "core/hle/service/nfp/nfp.h"
@@ -23,18 +22,21 @@ constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
23 22
24Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, 23Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
25 const char* name) 24 const char* name)
26 : ServiceFramework{system_, name}, nfc_tag_load{system.Kernel()}, module{std::move(module_)} { 25 : ServiceFramework{system_, name}, module{std::move(module_)}, service_context{system_,
27 Kernel::KAutoObject::Create(std::addressof(nfc_tag_load)); 26 "NFP::IUser"} {
28 nfc_tag_load.Initialize("IUser:NFCTagDetected"); 27 nfc_tag_load = service_context.CreateEvent("NFP::IUser:NFCTagDetected");
29} 28}
30 29
31Module::Interface::~Interface() = default; 30Module::Interface::~Interface() {
31 service_context.CloseEvent(nfc_tag_load);
32}
32 33
33class IUser final : public ServiceFramework<IUser> { 34class IUser final : public ServiceFramework<IUser> {
34public: 35public:
35 explicit IUser(Module::Interface& nfp_interface_, Core::System& system_) 36 explicit IUser(Module::Interface& nfp_interface_, Core::System& system_,
37 KernelHelpers::ServiceContext& service_context_)
36 : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_}, 38 : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_},
37 deactivate_event{system.Kernel()}, availability_change_event{system.Kernel()} { 39 service_context{service_context_} {
38 static const FunctionInfo functions[] = { 40 static const FunctionInfo functions[] = {
39 {0, &IUser::Initialize, "Initialize"}, 41 {0, &IUser::Initialize, "Initialize"},
40 {1, &IUser::Finalize, "Finalize"}, 42 {1, &IUser::Finalize, "Finalize"},
@@ -64,11 +66,14 @@ public:
64 }; 66 };
65 RegisterHandlers(functions); 67 RegisterHandlers(functions);
66 68
67 Kernel::KAutoObject::Create(std::addressof(deactivate_event)); 69 deactivate_event = service_context.CreateEvent("NFP::IUser:DeactivateEvent");
68 Kernel::KAutoObject::Create(std::addressof(availability_change_event)); 70 availability_change_event =
71 service_context.CreateEvent("NFP::IUser:AvailabilityChangeEvent");
72 }
69 73
70 deactivate_event.Initialize("IUser:DeactivateEvent"); 74 ~IUser() override {
71 availability_change_event.Initialize("IUser:AvailabilityChangeEvent"); 75 service_context.CloseEvent(deactivate_event);
76 service_context.CloseEvent(availability_change_event);
72 } 77 }
73 78
74private: 79private:
@@ -166,7 +171,7 @@ private:
166 171
167 IPC::ResponseBuilder rb{ctx, 2, 1}; 172 IPC::ResponseBuilder rb{ctx, 2, 1};
168 rb.Push(ResultSuccess); 173 rb.Push(ResultSuccess);
169 rb.PushCopyObjects(deactivate_event.GetReadableEvent()); 174 rb.PushCopyObjects(deactivate_event->GetReadableEvent());
170 } 175 }
171 176
172 void StopDetection(Kernel::HLERequestContext& ctx) { 177 void StopDetection(Kernel::HLERequestContext& ctx) {
@@ -175,7 +180,7 @@ private:
175 switch (device_state) { 180 switch (device_state) {
176 case DeviceState::TagFound: 181 case DeviceState::TagFound:
177 case DeviceState::TagNearby: 182 case DeviceState::TagNearby:
178 deactivate_event.GetWritableEvent().Signal(); 183 deactivate_event->GetWritableEvent().Signal();
179 device_state = DeviceState::Initialized; 184 device_state = DeviceState::Initialized;
180 break; 185 break;
181 case DeviceState::SearchingForTag: 186 case DeviceState::SearchingForTag:
@@ -264,7 +269,7 @@ private:
264 269
265 IPC::ResponseBuilder rb{ctx, 2, 1}; 270 IPC::ResponseBuilder rb{ctx, 2, 1};
266 rb.Push(ResultSuccess); 271 rb.Push(ResultSuccess);
267 rb.PushCopyObjects(availability_change_event.GetReadableEvent()); 272 rb.PushCopyObjects(availability_change_event->GetReadableEvent());
268 } 273 }
269 274
270 void GetRegisterInfo(Kernel::HLERequestContext& ctx) { 275 void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -313,14 +318,16 @@ private:
313 rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub 318 rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
314 } 319 }
315 320
321 Module::Interface& nfp_interface;
322 KernelHelpers::ServiceContext& service_context;
323
316 bool has_attached_handle{}; 324 bool has_attached_handle{};
317 const u64 device_handle{0}; // Npad device 1 325 const u64 device_handle{0}; // Npad device 1
318 const u32 npad_id{0}; // Player 1 controller 326 const u32 npad_id{0}; // Player 1 controller
319 State state{State::NonInitialized}; 327 State state{State::NonInitialized};
320 DeviceState device_state{DeviceState::Initialized}; 328 DeviceState device_state{DeviceState::Initialized};
321 Module::Interface& nfp_interface; 329 Kernel::KEvent* deactivate_event;
322 Kernel::KEvent deactivate_event; 330 Kernel::KEvent* availability_change_event;
323 Kernel::KEvent availability_change_event;
324}; 331};
325 332
326void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 333void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
@@ -328,7 +335,7 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
328 335
329 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 336 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
330 rb.Push(ResultSuccess); 337 rb.Push(ResultSuccess);
331 rb.PushIpcInterface<IUser>(*this, system); 338 rb.PushIpcInterface<IUser>(*this, system, service_context);
332} 339}
333 340
334bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { 341bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
@@ -338,12 +345,12 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
338 } 345 }
339 346
340 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); 347 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
341 nfc_tag_load.GetWritableEvent().Signal(); 348 nfc_tag_load->GetWritableEvent().Signal();
342 return true; 349 return true;
343} 350}
344 351
345Kernel::KReadableEvent& Module::Interface::GetNFCEvent() { 352Kernel::KReadableEvent& Module::Interface::GetNFCEvent() {
346 return nfc_tag_load.GetReadableEvent(); 353 return nfc_tag_load->GetReadableEvent();
347} 354}
348 355
349const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { 356const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 5e4e49bc6..95c127efb 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -7,7 +7,7 @@
7#include <array> 7#include <array>
8#include <vector> 8#include <vector>
9 9
10#include "core/hle/kernel/k_event.h" 10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12 12
13namespace Kernel { 13namespace Kernel {
@@ -42,12 +42,13 @@ public:
42 Kernel::KReadableEvent& GetNFCEvent(); 42 Kernel::KReadableEvent& GetNFCEvent();
43 const AmiiboFile& GetAmiiboBuffer() const; 43 const AmiiboFile& GetAmiiboBuffer() const;
44 44
45 private:
46 Kernel::KEvent nfc_tag_load;
47 AmiiboFile amiibo{};
48
49 protected: 45 protected:
50 std::shared_ptr<Module> module; 46 std::shared_ptr<Module> module;
47
48 private:
49 KernelHelpers::ServiceContext service_context;
50 Kernel::KEvent* nfc_tag_load;
51 AmiiboFile amiibo{};
51 }; 52 };
52}; 53};
53 54
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 9decb9290..f13dc8b0d 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -6,10 +6,21 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
9#include "core/hle/kernel/k_readable_event.h"
10#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/nifm/nifm.h" 11#include "core/hle/service/nifm/nifm.h"
12#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
13
14namespace {
15
16// Avoids name conflict with Windows' CreateEvent macro.
17[[nodiscard]] Kernel::KEvent* CreateKEvent(Service::KernelHelpers::ServiceContext& service_context,
18 std::string&& name) {
19 return service_context.CreateEvent(std::move(name));
20}
21
22} // Anonymous namespace
23
13#include "core/network/network.h" 24#include "core/network/network.h"
14#include "core/network/network_interface.h" 25#include "core/network/network_interface.h"
15 26
@@ -129,7 +140,7 @@ public:
129class IRequest final : public ServiceFramework<IRequest> { 140class IRequest final : public ServiceFramework<IRequest> {
130public: 141public:
131 explicit IRequest(Core::System& system_) 142 explicit IRequest(Core::System& system_)
132 : ServiceFramework{system_, "IRequest"}, event1{system.Kernel()}, event2{system.Kernel()} { 143 : ServiceFramework{system_, "IRequest"}, service_context{system_, "IRequest"} {
133 static const FunctionInfo functions[] = { 144 static const FunctionInfo functions[] = {
134 {0, &IRequest::GetRequestState, "GetRequestState"}, 145 {0, &IRequest::GetRequestState, "GetRequestState"},
135 {1, &IRequest::GetResult, "GetResult"}, 146 {1, &IRequest::GetResult, "GetResult"},
@@ -159,11 +170,13 @@ public:
159 }; 170 };
160 RegisterHandlers(functions); 171 RegisterHandlers(functions);
161 172
162 Kernel::KAutoObject::Create(std::addressof(event1)); 173 event1 = CreateKEvent(service_context, "IRequest:Event1");
163 Kernel::KAutoObject::Create(std::addressof(event2)); 174 event2 = CreateKEvent(service_context, "IRequest:Event2");
175 }
164 176
165 event1.Initialize("IRequest:Event1"); 177 ~IRequest() override {
166 event2.Initialize("IRequest:Event2"); 178 service_context.CloseEvent(event1);
179 service_context.CloseEvent(event2);
167 } 180 }
168 181
169private: 182private:
@@ -199,7 +212,7 @@ private:
199 212
200 IPC::ResponseBuilder rb{ctx, 2, 2}; 213 IPC::ResponseBuilder rb{ctx, 2, 2};
201 rb.Push(ResultSuccess); 214 rb.Push(ResultSuccess);
202 rb.PushCopyObjects(event1.GetReadableEvent(), event2.GetReadableEvent()); 215 rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent());
203 } 216 }
204 217
205 void Cancel(Kernel::HLERequestContext& ctx) { 218 void Cancel(Kernel::HLERequestContext& ctx) {
@@ -230,7 +243,10 @@ private:
230 rb.Push<u32>(0); 243 rb.Push<u32>(0);
231 } 244 }
232 245
233 Kernel::KEvent event1, event2; 246 KernelHelpers::ServiceContext service_context;
247
248 Kernel::KEvent* event1;
249 Kernel::KEvent* event2;
234}; 250};
235 251
236class INetworkProfile final : public ServiceFramework<INetworkProfile> { 252class INetworkProfile final : public ServiceFramework<INetworkProfile> {
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 7447cc38f..30fb060b8 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -7,9 +7,8 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/k_event.h" 9#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_readable_event.h"
11#include "core/hle/kernel/k_writable_event.h"
12#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/service/kernel_helpers.h"
13#include "core/hle/service/nim/nim.h" 12#include "core/hle/service/nim/nim.h"
14#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
15#include "core/hle/service/sm/sm.h" 14#include "core/hle/service/sm/sm.h"
@@ -301,7 +300,7 @@ class IEnsureNetworkClockAvailabilityService final
301public: 300public:
302 explicit IEnsureNetworkClockAvailabilityService(Core::System& system_) 301 explicit IEnsureNetworkClockAvailabilityService(Core::System& system_)
303 : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"}, 302 : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"},
304 finished_event{system.Kernel()} { 303 service_context{system_, "IEnsureNetworkClockAvailabilityService"} {
305 static const FunctionInfo functions[] = { 304 static const FunctionInfo functions[] = {
306 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, 305 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
307 {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent, 306 {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent,
@@ -313,17 +312,19 @@ public:
313 }; 312 };
314 RegisterHandlers(functions); 313 RegisterHandlers(functions);
315 314
316 Kernel::KAutoObject::Create(std::addressof(finished_event)); 315 finished_event =
317 finished_event.Initialize("IEnsureNetworkClockAvailabilityService:FinishEvent"); 316 service_context.CreateEvent("IEnsureNetworkClockAvailabilityService:FinishEvent");
318 } 317 }
319 318
320private: 319 ~IEnsureNetworkClockAvailabilityService() override {
321 Kernel::KEvent finished_event; 320 service_context.CloseEvent(finished_event);
321 }
322 322
323private:
323 void StartTask(Kernel::HLERequestContext& ctx) { 324 void StartTask(Kernel::HLERequestContext& ctx) {
324 // No need to connect to the internet, just finish the task straight away. 325 // No need to connect to the internet, just finish the task straight away.
325 LOG_DEBUG(Service_NIM, "called"); 326 LOG_DEBUG(Service_NIM, "called");
326 finished_event.GetWritableEvent().Signal(); 327 finished_event->GetWritableEvent().Signal();
327 IPC::ResponseBuilder rb{ctx, 2}; 328 IPC::ResponseBuilder rb{ctx, 2};
328 rb.Push(ResultSuccess); 329 rb.Push(ResultSuccess);
329 } 330 }
@@ -333,7 +334,7 @@ private:
333 334
334 IPC::ResponseBuilder rb{ctx, 2, 1}; 335 IPC::ResponseBuilder rb{ctx, 2, 1};
335 rb.Push(ResultSuccess); 336 rb.Push(ResultSuccess);
336 rb.PushCopyObjects(finished_event.GetReadableEvent()); 337 rb.PushCopyObjects(finished_event->GetReadableEvent());
337 } 338 }
338 339
339 void GetResult(Kernel::HLERequestContext& ctx) { 340 void GetResult(Kernel::HLERequestContext& ctx) {
@@ -345,7 +346,7 @@ private:
345 346
346 void Cancel(Kernel::HLERequestContext& ctx) { 347 void Cancel(Kernel::HLERequestContext& ctx) {
347 LOG_DEBUG(Service_NIM, "called"); 348 LOG_DEBUG(Service_NIM, "called");
348 finished_event.GetWritableEvent().Clear(); 349 finished_event->GetWritableEvent().Clear();
349 IPC::ResponseBuilder rb{ctx, 2}; 350 IPC::ResponseBuilder rb{ctx, 2};
350 rb.Push(ResultSuccess); 351 rb.Push(ResultSuccess);
351 } 352 }
@@ -368,6 +369,10 @@ private:
368 rb.Push(ResultSuccess); 369 rb.Push(ResultSuccess);
369 rb.PushRaw<s64>(server_time); 370 rb.PushRaw<s64>(server_time);
370 } 371 }
372
373 KernelHelpers::ServiceContext service_context;
374
375 Kernel::KEvent* finished_event;
371}; 376};
372 377
373class NTC final : public ServiceFramework<NTC> { 378class NTC final : public ServiceFramework<NTC> {
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index e4c703da4..32533cd94 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -31,6 +31,7 @@ public:
31 {24, nullptr, "DestroyTokenWithApplicationId"}, 31 {24, nullptr, "DestroyTokenWithApplicationId"},
32 {25, nullptr, "QueryIsTokenValid"}, 32 {25, nullptr, "QueryIsTokenValid"},
33 {26, nullptr, "ListenToMyApplicationId"}, 33 {26, nullptr, "ListenToMyApplicationId"},
34 {27, nullptr, "DestroyTokenAll"},
34 {31, nullptr, "UploadTokenToBaaS"}, 35 {31, nullptr, "UploadTokenToBaaS"},
35 {32, nullptr, "DestroyTokenForBaaS"}, 36 {32, nullptr, "DestroyTokenForBaaS"},
36 {33, nullptr, "CreateTokenForBaaS"}, 37 {33, nullptr, "CreateTokenForBaaS"},
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 8ce1f3296..931b48f72 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -9,7 +9,6 @@
9#include "core/file_sys/patch_manager.h" 9#include "core/file_sys/patch_manager.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs.h"
11#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/hle_ipc.h"
13#include "core/hle/service/ns/errors.h" 12#include "core/hle/service/ns/errors.h"
14#include "core/hle/service/ns/language.h" 13#include "core/hle/service/ns/language.h"
15#include "core/hle/service/ns/ns.h" 14#include "core/hle/service/ns/ns.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index a33e47d0b..4ee8c5733 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -16,7 +16,7 @@ namespace Service::Nvidia::Devices {
16 16
17nvdisp_disp0::nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_) 17nvdisp_disp0::nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_)
18 : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {} 18 : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {}
19nvdisp_disp0 ::~nvdisp_disp0() = default; 19nvdisp_disp0::~nvdisp_disp0() = default;
20 20
21NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 21NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
22 std::vector<u8>& output) { 22 std::vector<u8>& output) {
@@ -48,8 +48,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
48 addr, offset, width, height, stride, format); 48 addr, offset, width, height, stride, format);
49 49
50 const auto pixel_format = static_cast<Tegra::FramebufferConfig::PixelFormat>(format); 50 const auto pixel_format = static_cast<Tegra::FramebufferConfig::PixelFormat>(format);
51 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height, 51 const auto transform_flags = static_cast<Tegra::FramebufferConfig::TransformFlags>(transform);
52 stride, pixel_format, transform, crop_rect}; 52 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
53 stride, pixel_format, transform_flags, crop_rect};
53 54
54 system.GetPerfStats().EndSystemFrame(); 55 system.GetPerfStats().EndSystemFrame();
55 system.GPU().SwapBuffers(&framebuffer); 56 system.GPU().SwapBuffers(&framebuffer);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 775e76330..f9b82b504 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -92,6 +92,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
92 if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { 92 if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
93 params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id); 93 params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id);
94 std::memcpy(output.data(), &params, sizeof(params)); 94 std::memcpy(output.data(), &params, sizeof(params));
95 events_interface.failed[event_id] = false;
95 return NvResult::Success; 96 return NvResult::Success;
96 } 97 }
97 98
@@ -99,6 +100,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
99 syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) { 100 syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
100 params.value = new_value; 101 params.value = new_value;
101 std::memcpy(output.data(), &params, sizeof(params)); 102 std::memcpy(output.data(), &params, sizeof(params));
103 events_interface.failed[event_id] = false;
102 return NvResult::Success; 104 return NvResult::Success;
103 } 105 }
104 106
@@ -111,13 +113,13 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
111 event.event->GetWritableEvent().Signal(); 113 event.event->GetWritableEvent().Signal();
112 return NvResult::Success; 114 return NvResult::Success;
113 } 115 }
114 auto lock = gpu.LockSync();
115 const u32 current_syncpoint_value = event.fence.value; 116 const u32 current_syncpoint_value = event.fence.value;
116 const s32 diff = current_syncpoint_value - params.threshold; 117 const s32 diff = current_syncpoint_value - params.threshold;
117 if (diff >= 0) { 118 if (diff >= 0) {
118 event.event->GetWritableEvent().Signal(); 119 event.event->GetWritableEvent().Signal();
119 params.value = current_syncpoint_value; 120 params.value = current_syncpoint_value;
120 std::memcpy(output.data(), &params, sizeof(params)); 121 std::memcpy(output.data(), &params, sizeof(params));
122 events_interface.failed[event_id] = false;
121 return NvResult::Success; 123 return NvResult::Success;
122 } 124 }
123 const u32 target_value = current_syncpoint_value - diff; 125 const u32 target_value = current_syncpoint_value - diff;
@@ -132,23 +134,34 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
132 } 134 }
133 135
134 EventState status = events_interface.status[event_id]; 136 EventState status = events_interface.status[event_id];
135 if (event_id < MaxNvEvents || status == EventState::Free || status == EventState::Registered) { 137 const bool bad_parameter = status != EventState::Free && status != EventState::Registered;
136 events_interface.SetEventStatus(event_id, EventState::Waiting); 138 if (bad_parameter) {
137 events_interface.assigned_syncpt[event_id] = params.syncpt_id; 139 std::memcpy(output.data(), &params, sizeof(params));
138 events_interface.assigned_value[event_id] = target_value; 140 return NvResult::BadParameter;
139 if (is_async) { 141 }
140 params.value = params.syncpt_id << 4; 142 events_interface.SetEventStatus(event_id, EventState::Waiting);
141 } else { 143 events_interface.assigned_syncpt[event_id] = params.syncpt_id;
142 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; 144 events_interface.assigned_value[event_id] = target_value;
145 if (is_async) {
146 params.value = params.syncpt_id << 4;
147 } else {
148 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
149 }
150 params.value |= event_id;
151 event.event->GetWritableEvent().Clear();
152 if (events_interface.failed[event_id]) {
153 {
154 auto lk = system.StallCPU();
155 gpu.WaitFence(params.syncpt_id, target_value);
156 system.UnstallCPU();
143 } 157 }
144 params.value |= event_id;
145 event.event->GetWritableEvent().Clear();
146 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
147 std::memcpy(output.data(), &params, sizeof(params)); 158 std::memcpy(output.data(), &params, sizeof(params));
148 return NvResult::Timeout; 159 events_interface.failed[event_id] = false;
160 return NvResult::Success;
149 } 161 }
162 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
150 std::memcpy(output.data(), &params, sizeof(params)); 163 std::memcpy(output.data(), &params, sizeof(params));
151 return NvResult::BadParameter; 164 return NvResult::Timeout;
152} 165}
153 166
154NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { 167NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
@@ -201,6 +214,7 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::v
201 if (events_interface.status[event_id] == EventState::Waiting) { 214 if (events_interface.status[event_id] == EventState::Waiting) {
202 events_interface.LiberateEvent(event_id); 215 events_interface.LiberateEvent(event_id);
203 } 216 }
217 events_interface.failed[event_id] = true;
204 218
205 syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id); 219 syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);
206 220
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index c0a380088..54ac105d5 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -13,6 +13,14 @@
13#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
14 14
15namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
16namespace {
17Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoint_id) {
18 Tegra::GPU::FenceAction result{};
19 result.op.Assign(op);
20 result.syncpoint_id.Assign(syncpoint_id);
21 return {result.raw};
22}
23} // namespace
16 24
17nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_, 25nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
18 SyncpointManager& syncpoint_manager_) 26 SyncpointManager& syncpoint_manager_)
@@ -187,7 +195,7 @@ static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
187 {fence.value}, 195 {fence.value},
188 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, 196 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1,
189 Tegra::SubmissionMode::Increasing), 197 Tegra::SubmissionMode::Increasing),
190 Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Acquire, fence.id), 198 BuildFenceAction(Tegra::GPU::FenceOperation::Acquire, fence.id),
191 }; 199 };
192} 200}
193 201
@@ -200,8 +208,7 @@ static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence,
200 for (u32 count = 0; count < add_increment; ++count) { 208 for (u32 count = 0; count < add_increment; ++count) {
201 result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, 209 result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1,
202 Tegra::SubmissionMode::Increasing)); 210 Tegra::SubmissionMode::Increasing));
203 result.emplace_back( 211 result.emplace_back(BuildFenceAction(Tegra::GPU::FenceOperation::Increment, fence.id));
204 Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Increment, fence.id));
205 } 212 }
206 213
207 return result; 214 return result;
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index e2a1dde5b..a5af5b785 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -49,6 +49,8 @@ struct EventInterface {
49 std::array<EventState, MaxNvEvents> status{}; 49 std::array<EventState, MaxNvEvents> status{};
50 // Tells if an NVEvent is registered or not 50 // Tells if an NVEvent is registered or not
51 std::array<bool, MaxNvEvents> registered{}; 51 std::array<bool, MaxNvEvents> registered{};
52 // Tells the NVEvent that it has failed.
53 std::array<bool, MaxNvEvents> failed{};
52 // When an NVEvent is waiting on GPU interrupt, this is the sync_point 54 // When an NVEvent is waiting on GPU interrupt, this is the sync_point
53 // associated with it. 55 // associated with it.
54 std::array<u32, MaxNvEvents> assigned_syncpt{}; 56 std::array<u32, MaxNvEvents> assigned_syncpt{};
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 3ead813b0..a22811ec1 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -13,28 +13,20 @@
13#include "common/thread.h" 13#include "common/thread.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_timing.h" 15#include "core/core_timing.h"
16#include "core/core_timing_util.h"
17#include "core/hardware_properties.h"
18#include "core/hle/kernel/k_readable_event.h" 16#include "core/hle/kernel/k_readable_event.h"
19#include "core/hle/kernel/kernel.h"
20#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 17#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
21#include "core/hle/service/nvdrv/nvdrv.h" 18#include "core/hle/service/nvdrv/nvdrv.h"
22#include "core/hle/service/nvflinger/buffer_queue.h" 19#include "core/hle/service/nvflinger/buffer_queue.h"
23#include "core/hle/service/nvflinger/nvflinger.h" 20#include "core/hle/service/nvflinger/nvflinger.h"
24#include "core/hle/service/vi/display/vi_display.h" 21#include "core/hle/service/vi/display/vi_display.h"
25#include "core/hle/service/vi/layer/vi_layer.h" 22#include "core/hle/service/vi/layer/vi_layer.h"
26#include "core/perf_stats.h" 23#include "video_core/gpu.h"
27#include "video_core/renderer_base.h"
28 24
29namespace Service::NVFlinger { 25namespace Service::NVFlinger {
30 26
31constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60}; 27constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
32 28
33void NVFlinger::VSyncThread(NVFlinger& nv_flinger) { 29void NVFlinger::SplitVSync(std::stop_token stop_token) {
34 nv_flinger.SplitVSync();
35}
36
37void NVFlinger::SplitVSync() {
38 system.RegisterHostThread(); 30 system.RegisterHostThread();
39 std::string name = "yuzu:VSyncThread"; 31 std::string name = "yuzu:VSyncThread";
40 MicroProfileOnThreadCreate(name.c_str()); 32 MicroProfileOnThreadCreate(name.c_str());
@@ -45,7 +37,7 @@ void NVFlinger::SplitVSync() {
45 Common::SetCurrentThreadName(name.c_str()); 37 Common::SetCurrentThreadName(name.c_str());
46 Common::SetCurrentThreadPriority(Common::ThreadPriority::High); 38 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
47 s64 delay = 0; 39 s64 delay = 0;
48 while (is_running) { 40 while (!stop_token.stop_requested()) {
49 guard->lock(); 41 guard->lock();
50 const s64 time_start = system.CoreTiming().GetGlobalTimeNs().count(); 42 const s64 time_start = system.CoreTiming().GetGlobalTimeNs().count();
51 Compose(); 43 Compose();
@@ -55,7 +47,7 @@ void NVFlinger::SplitVSync() {
55 const s64 next_time = std::max<s64>(0, ticks - time_passed - delay); 47 const s64 next_time = std::max<s64>(0, ticks - time_passed - delay);
56 guard->unlock(); 48 guard->unlock();
57 if (next_time > 0) { 49 if (next_time > 0) {
58 wait_event->WaitFor(std::chrono::nanoseconds{next_time}); 50 std::this_thread::sleep_for(std::chrono::nanoseconds{next_time});
59 } 51 }
60 delay = (system.CoreTiming().GetGlobalTimeNs().count() - time_end) - next_time; 52 delay = (system.CoreTiming().GetGlobalTimeNs().count() - time_end) - next_time;
61 } 53 }
@@ -84,9 +76,7 @@ NVFlinger::NVFlinger(Core::System& system_)
84 }); 76 });
85 77
86 if (system.IsMulticore()) { 78 if (system.IsMulticore()) {
87 is_running = true; 79 vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
88 wait_event = std::make_unique<Common::Event>();
89 vsync_thread = std::make_unique<std::thread>(VSyncThread, std::ref(*this));
90 } else { 80 } else {
91 system.CoreTiming().ScheduleEvent(frame_ns, composition_event); 81 system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
92 } 82 }
@@ -96,14 +86,7 @@ NVFlinger::~NVFlinger() {
96 for (auto& buffer_queue : buffer_queues) { 86 for (auto& buffer_queue : buffer_queues) {
97 buffer_queue->Disconnect(); 87 buffer_queue->Disconnect();
98 } 88 }
99 89 if (!system.IsMulticore()) {
100 if (system.IsMulticore()) {
101 is_running = false;
102 wait_event->Set();
103 vsync_thread->join();
104 vsync_thread.reset();
105 wait_event.reset();
106 } else {
107 system.CoreTiming().UnscheduleEvent(composition_event, 0); 90 system.CoreTiming().UnscheduleEvent(composition_event, 0);
108 } 91 }
109} 92}
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 6d84cafb4..7935cf773 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -4,13 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
8#include <list> 7#include <list>
9#include <memory> 8#include <memory>
10#include <mutex> 9#include <mutex>
11#include <optional> 10#include <optional>
12#include <string>
13#include <string_view>
14#include <thread> 11#include <thread>
15#include <vector> 12#include <vector>
16 13
@@ -109,9 +106,7 @@ private:
109 /// Creates a layer with the specified layer ID in the desired display. 106 /// Creates a layer with the specified layer ID in the desired display.
110 void CreateLayerAtId(VI::Display& display, u64 layer_id); 107 void CreateLayerAtId(VI::Display& display, u64 layer_id);
111 108
112 static void VSyncThread(NVFlinger& nv_flinger); 109 void SplitVSync(std::stop_token stop_token);
113
114 void SplitVSync();
115 110
116 std::shared_ptr<Nvidia::Module> nvdrv; 111 std::shared_ptr<Nvidia::Module> nvdrv;
117 112
@@ -133,9 +128,7 @@ private:
133 128
134 Core::System& system; 129 Core::System& system;
135 130
136 std::unique_ptr<std::thread> vsync_thread; 131 std::jthread vsync_thread;
137 std::unique_ptr<Common::Event> wait_event;
138 std::atomic<bool> is_running{};
139 132
140 KernelHelpers::ServiceContext service_context; 133 KernelHelpers::ServiceContext service_context;
141}; 134};
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index 3bbe1bfe2..39a8031a5 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/ipc_helpers.h" 5#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/service/olsc/olsc.h" 6#include "core/hle/service/olsc/olsc.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h" 8#include "core/hle/service/sm/sm.h"
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index d9897c5c5..22ff5269c 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -8,9 +8,8 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/k_event.h" 10#include "core/hle/kernel/k_event.h"
11#include "core/hle/kernel/k_readable_event.h"
12#include "core/hle/kernel/k_writable_event.h"
13#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/service/kernel_helpers.h"
14#include "core/hle/service/ptm/psm.h" 13#include "core/hle/service/ptm/psm.h"
15#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
16#include "core/hle/service/sm/sm.h" 15#include "core/hle/service/sm/sm.h"
@@ -20,7 +19,7 @@ namespace Service::PSM {
20class IPsmSession final : public ServiceFramework<IPsmSession> { 19class IPsmSession final : public ServiceFramework<IPsmSession> {
21public: 20public:
22 explicit IPsmSession(Core::System& system_) 21 explicit IPsmSession(Core::System& system_)
23 : ServiceFramework{system_, "IPsmSession"}, state_change_event{system.Kernel()} { 22 : ServiceFramework{system_, "IPsmSession"}, service_context{system_, "IPsmSession"} {
24 // clang-format off 23 // clang-format off
25 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
26 {0, &IPsmSession::BindStateChangeEvent, "BindStateChangeEvent"}, 25 {0, &IPsmSession::BindStateChangeEvent, "BindStateChangeEvent"},
@@ -33,27 +32,28 @@ public:
33 32
34 RegisterHandlers(functions); 33 RegisterHandlers(functions);
35 34
36 Kernel::KAutoObject::Create(std::addressof(state_change_event)); 35 state_change_event = service_context.CreateEvent("IPsmSession::state_change_event");
37 state_change_event.Initialize("IPsmSession::state_change_event");
38 } 36 }
39 37
40 ~IPsmSession() override = default; 38 ~IPsmSession() override {
39 service_context.CloseEvent(state_change_event);
40 }
41 41
42 void SignalChargerTypeChanged() { 42 void SignalChargerTypeChanged() {
43 if (should_signal && should_signal_charger_type) { 43 if (should_signal && should_signal_charger_type) {
44 state_change_event.GetWritableEvent().Signal(); 44 state_change_event->GetWritableEvent().Signal();
45 } 45 }
46 } 46 }
47 47
48 void SignalPowerSupplyChanged() { 48 void SignalPowerSupplyChanged() {
49 if (should_signal && should_signal_power_supply) { 49 if (should_signal && should_signal_power_supply) {
50 state_change_event.GetWritableEvent().Signal(); 50 state_change_event->GetWritableEvent().Signal();
51 } 51 }
52 } 52 }
53 53
54 void SignalBatteryVoltageStateChanged() { 54 void SignalBatteryVoltageStateChanged() {
55 if (should_signal && should_signal_battery_voltage) { 55 if (should_signal && should_signal_battery_voltage) {
56 state_change_event.GetWritableEvent().Signal(); 56 state_change_event->GetWritableEvent().Signal();
57 } 57 }
58 } 58 }
59 59
@@ -65,7 +65,7 @@ private:
65 65
66 IPC::ResponseBuilder rb{ctx, 2, 1}; 66 IPC::ResponseBuilder rb{ctx, 2, 1};
67 rb.Push(ResultSuccess); 67 rb.Push(ResultSuccess);
68 rb.PushCopyObjects(state_change_event.GetReadableEvent()); 68 rb.PushCopyObjects(state_change_event->GetReadableEvent());
69 } 69 }
70 70
71 void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) { 71 void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) {
@@ -110,11 +110,13 @@ private:
110 rb.Push(ResultSuccess); 110 rb.Push(ResultSuccess);
111 } 111 }
112 112
113 KernelHelpers::ServiceContext service_context;
114
113 bool should_signal_charger_type{}; 115 bool should_signal_charger_type{};
114 bool should_signal_power_supply{}; 116 bool should_signal_power_supply{};
115 bool should_signal_battery_voltage{}; 117 bool should_signal_battery_voltage{};
116 bool should_signal{}; 118 bool should_signal{};
117 Kernel::KEvent state_change_event; 119 Kernel::KEvent* state_change_event;
118}; 120};
119 121
120class PSM final : public ServiceFramework<PSM> { 122class PSM final : public ServiceFramework<PSM> {
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 8299c6b68..286578b17 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -7,7 +7,6 @@
7#include "core/file_sys/errors.h" 7#include "core/file_sys/errors.h"
8#include "core/file_sys/system_archive/system_version.h" 8#include "core/file_sys/system_archive/system_version.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/k_client_port.h"
11#include "core/hle/service/filesystem/filesystem.h" 10#include "core/hle/service/filesystem/filesystem.h"
12#include "core/hle/service/set/set_sys.h" 11#include "core/hle/service/set/set_sys.h"
13 12
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 7d85ecb6a..b9e765f1d 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -415,6 +415,18 @@ void BSD::Write(Kernel::HLERequestContext& ctx) {
415 }); 415 });
416} 416}
417 417
418void BSD::Read(Kernel::HLERequestContext& ctx) {
419 IPC::RequestParser rp{ctx};
420 const s32 fd = rp.Pop<s32>();
421
422 LOG_WARNING(Service, "(STUBBED) called. fd={} len={}", fd, ctx.GetWriteBufferSize());
423
424 IPC::ResponseBuilder rb{ctx, 4};
425 rb.Push(ResultSuccess);
426 rb.Push<u32>(0); // ret
427 rb.Push<u32>(0); // bsd errno
428}
429
418void BSD::Close(Kernel::HLERequestContext& ctx) { 430void BSD::Close(Kernel::HLERequestContext& ctx) {
419 IPC::RequestParser rp{ctx}; 431 IPC::RequestParser rp{ctx};
420 const s32 fd = rp.Pop<s32>(); 432 const s32 fd = rp.Pop<s32>();
@@ -855,7 +867,7 @@ BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, na
855 {22, &BSD::Shutdown, "Shutdown"}, 867 {22, &BSD::Shutdown, "Shutdown"},
856 {23, nullptr, "ShutdownAllSockets"}, 868 {23, nullptr, "ShutdownAllSockets"},
857 {24, &BSD::Write, "Write"}, 869 {24, &BSD::Write, "Write"},
858 {25, nullptr, "Read"}, 870 {25, &BSD::Read, "Read"},
859 {26, &BSD::Close, "Close"}, 871 {26, &BSD::Close, "Close"},
860 {27, nullptr, "DuplicateSocket"}, 872 {27, nullptr, "DuplicateSocket"},
861 {28, nullptr, "GetResourceStatistics"}, 873 {28, nullptr, "GetResourceStatistics"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 1d2df9c61..a387e50df 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -5,11 +5,9 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <string_view>
9#include <vector> 8#include <vector>
10 9
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "core/hle/kernel/hle_ipc.h"
13#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
14#include "core/hle/service/sockets/sockets.h" 12#include "core/hle/service/sockets/sockets.h"
15 13
@@ -135,6 +133,7 @@ private:
135 void Send(Kernel::HLERequestContext& ctx); 133 void Send(Kernel::HLERequestContext& ctx);
136 void SendTo(Kernel::HLERequestContext& ctx); 134 void SendTo(Kernel::HLERequestContext& ctx);
137 void Write(Kernel::HLERequestContext& ctx); 135 void Write(Kernel::HLERequestContext& ctx);
136 void Read(Kernel::HLERequestContext& ctx);
138 void Close(Kernel::HLERequestContext& ctx); 137 void Close(Kernel::HLERequestContext& ctx);
139 void EventFd(Kernel::HLERequestContext& ctx); 138 void EventFd(Kernel::HLERequestContext& ctx);
140 139
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index faa6b7d0d..5d3b4dc2d 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
10namespace Core { 9namespace Core {
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index 5a65ed2a9..02dbbae40 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -4,13 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_funcs.h"
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "core/hle/service/service.h"
9 9
10namespace Core { 10namespace Core {
11class System; 11class System;
12} 12}
13 13
14namespace Service::SM {
15class ServiceManager;
16}
17
14namespace Service::Sockets { 18namespace Service::Sockets {
15 19
16enum class Errno : u32 { 20enum class Errno : u32 {
diff --git a/src/core/hle/service/spl/spl_module.cpp b/src/core/hle/service/spl/spl_module.cpp
index 918633af5..ed4c06260 100644
--- a/src/core/hle/service/spl/spl_module.cpp
+++ b/src/core/hle/service/spl/spl_module.cpp
@@ -3,10 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <chrono>
7#include <cstdlib> 6#include <cstdlib>
8#include <ctime> 7#include <ctime>
9#include <functional>
10#include <vector> 8#include <vector>
11#include "common/logging/log.h" 9#include "common/logging/log.h"
12#include "common/settings.h" 10#include "common/settings.h"
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 921f4d776..a81a595ea 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/ipc_helpers.h" 5#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/service/service.h" 6#include "core/hle/service/service.h"
8#include "core/hle/service/sm/sm.h" 7#include "core/hle/service/sm/sm.h"
9#include "core/hle/service/ssl/ssl.h" 8#include "core/hle/service/ssl/ssl.h"
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp
index ef79ab917..e94220a44 100644
--- a/src/core/hle/service/time/standard_user_system_clock_core.cpp
+++ b/src/core/hle/service/time/standard_user_system_clock_core.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/time/standard_local_system_clock_core.h" 8#include "core/hle/service/time/standard_local_system_clock_core.h"
8#include "core/hle/service/time/standard_network_system_clock_core.h" 9#include "core/hle/service/time/standard_network_system_clock_core.h"
9#include "core/hle/service/time/standard_user_system_clock_core.h" 10#include "core/hle/service/time/standard_user_system_clock_core.h"
@@ -16,10 +17,15 @@ StandardUserSystemClockCore::StandardUserSystemClockCore(
16 : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()), 17 : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()),
17 local_system_clock_core{local_system_clock_core_}, 18 local_system_clock_core{local_system_clock_core_},
18 network_system_clock_core{network_system_clock_core_}, 19 network_system_clock_core{network_system_clock_core_},
19 auto_correction_time{SteadyClockTimePoint::GetRandom()}, auto_correction_event{ 20 auto_correction_time{SteadyClockTimePoint::GetRandom()}, service_context{
20 system_.Kernel()} { 21 system_,
21 Kernel::KAutoObject::Create(std::addressof(auto_correction_event)); 22 "StandardUserSystemClockCore"} {
22 auto_correction_event.Initialize("StandardUserSystemClockCore:AutoCorrectionEvent"); 23 auto_correction_event =
24 service_context.CreateEvent("StandardUserSystemClockCore:AutoCorrectionEvent");
25}
26
27StandardUserSystemClockCore::~StandardUserSystemClockCore() {
28 service_context.CloseEvent(auto_correction_event);
23} 29}
24 30
25ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, 31ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system,
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h
index bf9ec5e42..b7cb2b045 100644
--- a/src/core/hle/service/time/standard_user_system_clock_core.h
+++ b/src/core/hle/service/time/standard_user_system_clock_core.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_event.h" 7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/time/clock_types.h" 8#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/system_clock_core.h" 9#include "core/hle/service/time/system_clock_core.h"
10 10
@@ -27,6 +27,8 @@ public:
27 StandardNetworkSystemClockCore& network_system_clock_core_, 27 StandardNetworkSystemClockCore& network_system_clock_core_,
28 Core::System& system_); 28 Core::System& system_);
29 29
30 ~StandardUserSystemClockCore() override;
31
30 ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value); 32 ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value);
31 33
32 ResultCode GetClockContext(Core::System& system, SystemClockContext& ctx) const override; 34 ResultCode GetClockContext(Core::System& system, SystemClockContext& ctx) const override;
@@ -55,7 +57,8 @@ private:
55 StandardNetworkSystemClockCore& network_system_clock_core; 57 StandardNetworkSystemClockCore& network_system_clock_core;
56 bool auto_correction_enabled{}; 58 bool auto_correction_enabled{};
57 SteadyClockTimePoint auto_correction_time; 59 SteadyClockTimePoint auto_correction_time;
58 Kernel::KEvent auto_correction_event; 60 KernelHelpers::ServiceContext service_context;
61 Kernel::KEvent* auto_correction_event;
59}; 62};
60 63
61} // namespace Service::Time::Clock 64} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.h b/src/core/hle/service/time/system_clock_context_update_callback.h
index 797954958..6936397a5 100644
--- a/src/core/hle/service/time/system_clock_context_update_callback.h
+++ b/src/core/hle/service/time/system_clock_context_update_callback.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
7#include <vector> 8#include <vector>
8 9
9#include "core/hle/service/time/clock_types.h" 10#include "core/hle/service/time/clock_types.h"
diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp
index bd334bbef..5c2354cdd 100644
--- a/src/core/hle/service/time/system_clock_core.cpp
+++ b/src/core/hle/service/time/system_clock_core.cpp
@@ -13,7 +13,7 @@ SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_)
13 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId(); 13 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
14} 14}
15 15
16SystemClockCore ::~SystemClockCore() = default; 16SystemClockCore::~SystemClockCore() = default;
17 17
18ResultCode SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const { 18ResultCode SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const {
19 posix_time = 0; 19 posix_time = 0;
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h
index 83d0e5d62..b9237ad28 100644
--- a/src/core/hle/service/time/system_clock_core.h
+++ b/src/core/hle/service/time/system_clock_core.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8#include "core/hle/service/time/clock_types.h" 10#include "core/hle/service/time/clock_types.h"
9 11
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 8fdd5076f..d84a111c2 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -8,11 +8,11 @@
8#include "core/core_timing_util.h" 8#include "core/core_timing_util.h"
9#include "core/hardware_properties.h" 9#include "core/hardware_properties.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/k_client_port.h"
12#include "core/hle/kernel/k_scheduler.h" 11#include "core/hle/kernel/k_scheduler.h"
13#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/time/time.h" 13#include "core/hle/service/time/time.h"
15#include "core/hle/service/time/time_interface.h" 14#include "core/hle/service/time/time_interface.h"
15#include "core/hle/service/time/time_manager.h"
16#include "core/hle/service/time/time_sharedmemory.h" 16#include "core/hle/service/time/time_sharedmemory.h"
17#include "core/hle/service/time/time_zone_service.h" 17#include "core/hle/service/time/time_zone_service.h"
18 18
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index ce9c479c6..30e2cd369 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -6,7 +6,6 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8#include "core/hle/service/time/clock_types.h" 8#include "core/hle/service/time/clock_types.h"
9#include "core/hle/service/time/time_manager.h"
10 9
11namespace Core { 10namespace Core {
12class System; 11class System;
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index 4bbc606a1..9c4c960ef 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -13,18 +13,19 @@
13#include "core/hle/service/time/time_manager.h" 13#include "core/hle/service/time/time_manager.h"
14 14
15namespace Service::Time { 15namespace Service::Time {
16 16namespace {
17constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL}; 17constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL};
18 18
19static std::chrono::seconds GetSecondsSinceEpoch() { 19s64 GetSecondsSinceEpoch() {
20 return std::chrono::duration_cast<std::chrono::seconds>( 20 const auto time_since_epoch = std::chrono::system_clock::now().time_since_epoch();
21 std::chrono::system_clock::now().time_since_epoch()) + 21 return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() +
22 Settings::values.custom_rtc_differential; 22 Settings::values.custom_rtc_differential;
23} 23}
24 24
25static s64 GetExternalRtcValue() { 25s64 GetExternalRtcValue() {
26 return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset(); 26 return GetSecondsSinceEpoch() + TimeManager::GetExternalTimeZoneOffset();
27} 27}
28} // Anonymous namespace
28 29
29struct TimeManager::Impl final { 30struct TimeManager::Impl final {
30 explicit Impl(Core::System& system) 31 explicit Impl(Core::System& system)
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index 5c3108768..3871e7316 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -10,8 +10,8 @@
10 10
11namespace Service::Time { 11namespace Service::Time {
12 12
13ITimeZoneService ::ITimeZoneService(Core::System& system_, 13ITimeZoneService::ITimeZoneService(Core::System& system_,
14 TimeZone::TimeZoneContentManager& time_zone_manager_) 14 TimeZone::TimeZoneContentManager& time_zone_manager_)
15 : ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} { 15 : ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} {
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, 17 {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index 7f436c3bb..502dfbb4a 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -6,7 +6,6 @@
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h" 10#include "core/hle/service/sm/sm.h"
12#include "core/hle/service/usb/usb.h" 11#include "core/hle/service/usb/usb.h"
@@ -97,7 +96,7 @@ public:
97 {3, nullptr, "GetAlternateInterface"}, 96 {3, nullptr, "GetAlternateInterface"},
98 {4, nullptr, "GetCurrentFrame"}, 97 {4, nullptr, "GetCurrentFrame"},
99 {5, nullptr, "CtrlXferAsync"}, 98 {5, nullptr, "CtrlXferAsync"},
100 {6, nullptr, "Unknown6"}, 99 {6, nullptr, "GetCtrlXferCompletionEvent"},
101 {7, nullptr, "GetCtrlXferReport"}, 100 {7, nullptr, "GetCtrlXferReport"},
102 {8, nullptr, "ResetDevice"}, 101 {8, nullptr, "ResetDevice"},
103 {9, nullptr, "OpenUsbEp"}, 102 {9, nullptr, "OpenUsbEp"},
@@ -183,8 +182,8 @@ public:
183 {4, nullptr, "GetHostPdcFirmwareRevision"}, 182 {4, nullptr, "GetHostPdcFirmwareRevision"},
184 {5, nullptr, "GetHostPdcManufactureId"}, 183 {5, nullptr, "GetHostPdcManufactureId"},
185 {6, nullptr, "GetHostPdcDeviceId"}, 184 {6, nullptr, "GetHostPdcDeviceId"},
186 {7, nullptr, "AwakeCradle"}, 185 {7, nullptr, "EnableCradleRecovery"},
187 {8, nullptr, "SleepCradle"}, 186 {8, nullptr, "DisableCradleRecovery"},
188 }; 187 };
189 // clang-format on 188 // clang-format on
190 189
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 8e8fc40ca..439e7e472 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -524,7 +524,9 @@ private:
524 Disconnect = 11, 524 Disconnect = 11,
525 525
526 AllocateBuffers = 13, 526 AllocateBuffers = 13,
527 SetPreallocatedBuffer = 14 527 SetPreallocatedBuffer = 14,
528
529 GetBufferHistory = 17
528 }; 530 };
529 531
530 void TransactParcel(Kernel::HLERequestContext& ctx) { 532 void TransactParcel(Kernel::HLERequestContext& ctx) {
@@ -641,6 +643,14 @@ private:
641 ctx.WriteBuffer(response.Serialize()); 643 ctx.WriteBuffer(response.Serialize());
642 break; 644 break;
643 } 645 }
646 case TransactionId::GetBufferHistory: {
647 LOG_WARNING(Service_VI, "(STUBBED) called, transaction=GetBufferHistory");
648 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
649
650 IGBPEmptyResponseParcel response{};
651 ctx.WriteBuffer(response.Serialize());
652 break;
653 }
644 default: 654 default:
645 ASSERT_MSG(false, "Unimplemented"); 655 ASSERT_MSG(false, "Unimplemented");
646 } 656 }
@@ -831,6 +841,7 @@ public:
831 {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"}, 841 {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"},
832 {6011, nullptr, "EnableLayerAutoClearTransitionBuffer"}, 842 {6011, nullptr, "EnableLayerAutoClearTransitionBuffer"},
833 {6012, nullptr, "DisableLayerAutoClearTransitionBuffer"}, 843 {6012, nullptr, "DisableLayerAutoClearTransitionBuffer"},
844 {6013, nullptr, "SetLayerOpacity"},
834 {7000, nullptr, "SetContentVisibility"}, 845 {7000, nullptr, "SetContentVisibility"},
835 {8000, nullptr, "SetConductorLayer"}, 846 {8000, nullptr, "SetConductorLayer"},
836 {8001, nullptr, "SetTimestampTracking"}, 847 {8001, nullptr, "SetTimestampTracking"},
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index eec531d54..2fd7f8e61 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include "common/common_types.h" 7#include "common/common_types.h"
9 8
10namespace Core { 9namespace Core {
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 51c4dea26..88d6ec908 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -587,7 +587,11 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
587bool Memory::IsValidVirtualAddress(const VAddr vaddr) const { 587bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
588 const Kernel::KProcess& process = *system.CurrentProcess(); 588 const Kernel::KProcess& process = *system.CurrentProcess();
589 const auto& page_table = process.PageTable().PageTableImpl(); 589 const auto& page_table = process.PageTable().PageTableImpl();
590 const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType(); 590 const size_t page = vaddr >> PAGE_BITS;
591 if (page >= page_table.pointers.size()) {
592 return false;
593 }
594 const auto [pointer, type] = page_table.pointers[page].PointerType();
591 return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory; 595 return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory;
592} 596}
593 597
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 72eea52f0..a3e0664b9 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -366,8 +366,6 @@ std::optional<IPv4Address> GetHostIPv4Address() {
366 if (res != network_interfaces.end()) { 366 if (res != network_interfaces.end()) {
367 char ip_addr[16] = {}; 367 char ip_addr[16] = {};
368 ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr); 368 ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr);
369 LOG_INFO(Network, "IP address: {}", ip_addr);
370
371 return TranslateIPv4(res->ip_address); 369 return TranslateIPv4(res->ip_address);
372 } else { 370 } else {
373 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); 371 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 18d7d8817..f3907c65a 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -346,8 +346,8 @@ void InputSubsystem::ReloadInputDevices() {
346 impl->udp->ReloadSockets(); 346 impl->udp->ReloadSockets();
347} 347}
348 348
349std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers([ 349std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
350 [maybe_unused]] Polling::DeviceType type) const { 350 [[maybe_unused]] Polling::DeviceType type) const {
351#ifdef HAVE_SDL2 351#ifdef HAVE_SDL2
352 return impl->sdl->GetPollers(type); 352 return impl->sdl->GetPollers(type);
353#else 353#else
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 03888b7cb..ecb00d428 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -170,7 +170,8 @@ public:
170 float GetAxis(int axis, float range, float offset) const { 170 float GetAxis(int axis, float range, float offset) const {
171 std::lock_guard lock{mutex}; 171 std::lock_guard lock{mutex};
172 const float value = static_cast<float>(state.axes.at(axis)) / 32767.0f; 172 const float value = static_cast<float>(state.axes.at(axis)) / 32767.0f;
173 return (value + offset) / range; 173 const float offset_scale = (value + offset) > 0.0f ? 1.0f + offset : 1.0f - offset;
174 return (value + offset) / range / offset_scale;
174 } 175 }
175 176
176 bool RumblePlay(u16 amp_low, u16 amp_high) { 177 bool RumblePlay(u16 amp_low, u16 amp_high) {
@@ -254,11 +255,25 @@ public:
254 } 255 }
255 256
256 bool IsJoyconLeft() const { 257 bool IsJoyconLeft() const {
257 return std::strstr(GetControllerName().c_str(), "Joy-Con Left") != nullptr; 258 const std::string controller_name = GetControllerName();
259 if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) {
260 return true;
261 }
262 if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) {
263 return true;
264 }
265 return false;
258 } 266 }
259 267
260 bool IsJoyconRight() const { 268 bool IsJoyconRight() const {
261 return std::strstr(GetControllerName().c_str(), "Joy-Con Right") != nullptr; 269 const std::string controller_name = GetControllerName();
270 if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) {
271 return true;
272 }
273 if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) {
274 return true;
275 }
276 return false;
262 } 277 }
263 278
264 std::string GetControllerName() const { 279 std::string GetControllerName() const {
@@ -775,8 +790,8 @@ public:
775 const std::string invert_y_value = params.Get("invert_y", "+"); 790 const std::string invert_y_value = params.Get("invert_y", "+");
776 const bool invert_x = invert_x_value == "-"; 791 const bool invert_x = invert_x_value == "-";
777 const bool invert_y = invert_y_value == "-"; 792 const bool invert_y = invert_y_value == "-";
778 const float offset_x = params.Get("offset_x", 0.0f); 793 const float offset_x = std::clamp(params.Get("offset_x", 0.0f), -0.99f, 0.99f);
779 const float offset_y = params.Get("offset_y", 0.0f); 794 const float offset_y = std::clamp(params.Get("offset_y", 0.0f), -0.99f, 0.99f);
780 auto joystick = state.GetSDLJoystickByGUID(guid, port); 795 auto joystick = state.GetSDLJoystickByGUID(guid, port);
781 796
782 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 797 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 9b0aec797..b9512aa2e 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -471,46 +471,42 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
471 std::function<void(u16, u16, u16, u16)> data_callback) { 471 std::function<void(u16, u16, u16, u16)> data_callback) {
472 472
473 std::thread([=, this] { 473 std::thread([=, this] {
474 constexpr u16 CALIBRATION_THRESHOLD = 100;
475
476 u16 min_x{UINT16_MAX};
477 u16 min_y{UINT16_MAX};
478 u16 max_x{};
479 u16 max_y{};
480
481 Status current_status{Status::Initialized}; 474 Status current_status{Status::Initialized};
482 SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, 475 SocketCallback callback{
483 [&](Response::PadData data) { 476 [](Response::Version) {}, [](Response::PortInfo) {},
484 if (current_status == Status::Initialized) { 477 [&](Response::PadData data) {
485 // Receiving data means the communication is ready now 478 static constexpr u16 CALIBRATION_THRESHOLD = 100;
486 current_status = Status::Ready; 479 static constexpr u16 MAX_VALUE = UINT16_MAX;
487 status_callback(current_status); 480
488 } 481 if (current_status == Status::Initialized) {
489 if (data.touch[0].is_active == 0) { 482 // Receiving data means the communication is ready now
490 return; 483 current_status = Status::Ready;
491 } 484 status_callback(current_status);
492 LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, 485 }
493 data.touch[0].y); 486 const auto& touchpad_0 = data.touch[0];
494 min_x = std::min(min_x, static_cast<u16>(data.touch[0].x)); 487 if (touchpad_0.is_active == 0) {
495 min_y = std::min(min_y, static_cast<u16>(data.touch[0].y)); 488 return;
496 if (current_status == Status::Ready) { 489 }
497 // First touch - min data (min_x/min_y) 490 LOG_DEBUG(Input, "Current touch: {} {}", touchpad_0.x, touchpad_0.y);
498 current_status = Status::Stage1Completed; 491 const u16 min_x = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.x));
499 status_callback(current_status); 492 const u16 min_y = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.y));
500 } 493 if (current_status == Status::Ready) {
501 if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && 494 // First touch - min data (min_x/min_y)
502 data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { 495 current_status = Status::Stage1Completed;
503 // Set the current position as max value and finishes 496 status_callback(current_status);
504 // configuration 497 }
505 max_x = data.touch[0].x; 498 if (touchpad_0.x - min_x > CALIBRATION_THRESHOLD &&
506 max_y = data.touch[0].y; 499 touchpad_0.y - min_y > CALIBRATION_THRESHOLD) {
507 current_status = Status::Completed; 500 // Set the current position as max value and finishes configuration
508 data_callback(min_x, min_y, max_x, max_y); 501 const u16 max_x = touchpad_0.x;
509 status_callback(current_status); 502 const u16 max_y = touchpad_0.y;
510 503 current_status = Status::Completed;
511 complete_event.Set(); 504 data_callback(min_x, min_y, max_x, max_y);
512 } 505 status_callback(current_status);
513 }}; 506
507 complete_event.Set();
508 }
509 }};
514 Socket socket{host, port, std::move(callback)}; 510 Socket socket{host, port, std::move(callback)};
515 std::thread worker_thread{SocketLoop, &socket}; 511 std::thread worker_thread{SocketLoop, &socket};
516 complete_event.Wait(); 512 complete_event.Wait();
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index 580063fa9..170db269a 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -58,8 +58,8 @@ void GetCbuf(EmitContext& ctx, std::string_view ret, const IR::Value& binding,
58 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())}; 58 const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())};
59 const auto cbuf_cast{fmt::format("{}({}[{}]{{}})", cast, cbuf, index)}; 59 const auto cbuf_cast{fmt::format("{}({}[{}]{{}})", cast, cbuf, index)};
60 const auto extraction{num_bits == 32 ? cbuf_cast 60 const auto extraction{num_bits == 32 ? cbuf_cast
61 : fmt ::format("bitfieldExtract({},int({}),{})", cbuf_cast, 61 : fmt::format("bitfieldExtract({},int({}),{})", cbuf_cast,
62 bit_offset, num_bits)}; 62 bit_offset, num_bits)};
63 if (!component_indexing_bug) { 63 if (!component_indexing_bug) {
64 const auto result{fmt::format(fmt::runtime(extraction), swizzle)}; 64 const auto result{fmt::format(fmt::runtime(extraction), swizzle)};
65 ctx.Add("{}={};", ret, result); 65 ctx.Add("{}={};", ret, result);
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index 44ad10d43..225c238fb 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -492,7 +492,8 @@ void TexturePass(Environment& env, IR::Program& program) {
492 const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)}; 492 const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
493 IR::IREmitter ir{*texture_inst.block, insert_point}; 493 IR::IREmitter ir{*texture_inst.block, insert_point};
494 const IR::U32 shift{ir.Imm32(std::countr_zero(DESCRIPTOR_SIZE))}; 494 const IR::U32 shift{ir.Imm32(std::countr_zero(DESCRIPTOR_SIZE))};
495 inst->SetArg(0, ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift)); 495 inst->SetArg(0, ir.SMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift),
496 ir.Imm32(DESCRIPTOR_SIZE - 1)));
496 } else { 497 } else {
497 inst->SetArg(0, IR::Value{}); 498 inst->SetArg(0, IR::Value{});
498 } 499 }
diff --git a/src/shader_recompiler/object_pool.h b/src/shader_recompiler/object_pool.h
index f3b12d04b..a12ddcc8f 100644
--- a/src/shader_recompiler/object_pool.h
+++ b/src/shader_recompiler/object_pool.h
@@ -11,14 +11,16 @@
11namespace Shader { 11namespace Shader {
12 12
13template <typename T> 13template <typename T>
14requires std::is_destructible_v<T> class ObjectPool { 14requires std::is_destructible_v<T>
15class ObjectPool {
15public: 16public:
16 explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} { 17 explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
17 node = &chunks.emplace_back(new_chunk_size); 18 node = &chunks.emplace_back(new_chunk_size);
18 } 19 }
19 20
20 template <typename... Args> 21 template <typename... Args>
21 requires std::is_constructible_v<T, Args...>[[nodiscard]] T* Create(Args&&... args) { 22 requires std::is_constructible_v<T, Args...>
23 [[nodiscard]] T* Create(Args&&... args) {
22 return std::construct_at(Memory(), std::forward<Args>(args)...); 24 return std::construct_at(Memory(), std::forward<Args>(args)...);
23 } 25 }
24 26
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 7bfd57369..d350c9b36 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -570,13 +570,12 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
570 ForEachWrittenRange(*cpu_src_address, amount, mirror); 570 ForEachWrittenRange(*cpu_src_address, amount, mirror);
571 // This subtraction in this order is important for overlapping copies. 571 // This subtraction in this order is important for overlapping copies.
572 common_ranges.subtract(subtract_interval); 572 common_ranges.subtract(subtract_interval);
573 bool atleast_1_download = tmp_intervals.size() != 0; 573 const bool has_new_downloads = tmp_intervals.size() != 0;
574 for (const IntervalType add_interval : tmp_intervals) { 574 for (const IntervalType& add_interval : tmp_intervals) {
575 common_ranges.add(add_interval); 575 common_ranges.add(add_interval);
576 } 576 }
577
578 runtime.CopyBuffer(dest_buffer, src_buffer, copies); 577 runtime.CopyBuffer(dest_buffer, src_buffer, copies);
579 if (atleast_1_download) { 578 if (has_new_downloads) {
580 dest_buffer.MarkRegionAsGpuModified(*cpu_dest_address, amount); 579 dest_buffer.MarkRegionAsGpuModified(*cpu_dest_address, amount);
581 } 580 }
582 std::vector<u8> tmp_buffer(amount); 581 std::vector<u8> tmp_buffer(amount);
diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp
index 8b86ad050..a8c4b4415 100644
--- a/src/video_core/cdma_pusher.cpp
+++ b/src/video_core/cdma_pusher.cpp
@@ -24,6 +24,7 @@
24#include "command_classes/vic.h" 24#include "command_classes/vic.h"
25#include "video_core/cdma_pusher.h" 25#include "video_core/cdma_pusher.h"
26#include "video_core/command_classes/nvdec_common.h" 26#include "video_core/command_classes/nvdec_common.h"
27#include "video_core/command_classes/sync_manager.h"
27#include "video_core/engines/maxwell_3d.h" 28#include "video_core/engines/maxwell_3d.h"
28#include "video_core/gpu.h" 29#include "video_core/gpu.h"
29#include "video_core/memory_manager.h" 30#include "video_core/memory_manager.h"
diff --git a/src/video_core/cdma_pusher.h b/src/video_core/cdma_pusher.h
index 1bada44dd..87b49d6ea 100644
--- a/src/video_core/cdma_pusher.h
+++ b/src/video_core/cdma_pusher.h
@@ -9,13 +9,13 @@
9 9
10#include "common/bit_field.h" 10#include "common/bit_field.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/command_classes/sync_manager.h"
13 12
14namespace Tegra { 13namespace Tegra {
15 14
16class GPU; 15class GPU;
17class Host1x; 16class Host1x;
18class Nvdec; 17class Nvdec;
18class SyncptIncrManager;
19class Vic; 19class Vic;
20 20
21enum class ChSubmissionMode : u32 { 21enum class ChSubmissionMode : u32 {
diff --git a/src/video_core/command_classes/codecs/h264.cpp b/src/video_core/command_classes/codecs/h264.cpp
index 51ee14c13..5519c4705 100644
--- a/src/video_core/command_classes/codecs/h264.cpp
+++ b/src/video_core/command_classes/codecs/h264.cpp
@@ -20,6 +20,8 @@
20 20
21#include <array> 21#include <array>
22#include <bit> 22#include <bit>
23
24#include "common/settings.h"
23#include "video_core/command_classes/codecs/h264.h" 25#include "video_core/command_classes/codecs/h264.h"
24#include "video_core/gpu.h" 26#include "video_core/gpu.h"
25#include "video_core/memory_manager.h" 27#include "video_core/memory_manager.h"
@@ -96,7 +98,10 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
96 (context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2); 98 (context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2);
97 99
98 // TODO (ameerj): Where do we get this number, it seems to be particular for each stream 100 // TODO (ameerj): Where do we get this number, it seems to be particular for each stream
99 writer.WriteUe(6); // Max number of reference frames 101 const auto nvdec_decoding = Settings::values.nvdec_emulation.GetValue();
102 const bool uses_gpu_decoding = nvdec_decoding == Settings::NvdecEmulation::GPU;
103 const u32 max_num_ref_frames = uses_gpu_decoding ? 6u : 16u;
104 writer.WriteUe(max_num_ref_frames);
100 writer.WriteBit(false); 105 writer.WriteBit(false);
101 writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1); 106 writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1);
102 writer.WriteUe(pic_height - 1); 107 writer.WriteUe(pic_height - 1);
diff --git a/src/video_core/command_classes/vic.cpp b/src/video_core/command_classes/vic.cpp
index 0ee07f398..051616124 100644
--- a/src/video_core/command_classes/vic.cpp
+++ b/src/video_core/command_classes/vic.cpp
@@ -16,6 +16,7 @@ extern "C" {
16} 16}
17 17
18#include "common/assert.h" 18#include "common/assert.h"
19#include "common/bit_field.h"
19#include "common/logging/log.h" 20#include "common/logging/log.h"
20 21
21#include "video_core/command_classes/nvdec.h" 22#include "video_core/command_classes/nvdec.h"
@@ -26,6 +27,25 @@ extern "C" {
26#include "video_core/textures/decoders.h" 27#include "video_core/textures/decoders.h"
27 28
28namespace Tegra { 29namespace Tegra {
30namespace {
31enum class VideoPixelFormat : u64_le {
32 RGBA8 = 0x1f,
33 BGRA8 = 0x20,
34 RGBX8 = 0x23,
35 YUV420 = 0x44,
36};
37} // Anonymous namespace
38
39union VicConfig {
40 u64_le raw{};
41 BitField<0, 7, VideoPixelFormat> pixel_format;
42 BitField<7, 2, u64_le> chroma_loc_horiz;
43 BitField<9, 2, u64_le> chroma_loc_vert;
44 BitField<11, 4, u64_le> block_linear_kind;
45 BitField<15, 4, u64_le> block_linear_height_log2;
46 BitField<32, 14, u64_le> surface_width_minus1;
47 BitField<46, 14, u64_le> surface_height_minus1;
48};
29 49
30Vic::Vic(GPU& gpu_, std::shared_ptr<Nvdec> nvdec_processor_) 50Vic::Vic(GPU& gpu_, std::shared_ptr<Nvdec> nvdec_processor_)
31 : gpu(gpu_), 51 : gpu(gpu_),
@@ -65,134 +85,155 @@ void Vic::Execute() {
65 if (!frame) { 85 if (!frame) {
66 return; 86 return;
67 } 87 }
68 const auto pixel_format = static_cast<VideoPixelFormat>(config.pixel_format.Value()); 88 const u64 surface_width = config.surface_width_minus1 + 1;
69 switch (pixel_format) { 89 const u64 surface_height = config.surface_height_minus1 + 1;
90 if (static_cast<u64>(frame->width) != surface_width ||
91 static_cast<u64>(frame->height) != surface_height) {
92 // TODO: Properly support multiple video streams with differing frame dimensions
93 LOG_WARNING(Service_NVDRV, "Frame dimensions {}x{} don't match surface dimensions {}x{}",
94 frame->width, frame->height, surface_width, surface_height);
95 }
96 switch (config.pixel_format) {
97 case VideoPixelFormat::RGBA8:
70 case VideoPixelFormat::BGRA8: 98 case VideoPixelFormat::BGRA8:
71 case VideoPixelFormat::RGBA8: { 99 case VideoPixelFormat::RGBX8:
72 LOG_TRACE(Service_NVDRV, "Writing RGB Frame"); 100 WriteRGBFrame(frame, config);
101 break;
102 case VideoPixelFormat::YUV420:
103 WriteYUVFrame(frame, config);
104 break;
105 default:
106 UNIMPLEMENTED_MSG("Unknown video pixel format {:X}", config.pixel_format.Value());
107 break;
108 }
109}
73 110
74 if (scaler_ctx == nullptr || frame->width != scaler_width || 111void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) {
75 frame->height != scaler_height) { 112 LOG_TRACE(Service_NVDRV, "Writing RGB Frame");
76 const AVPixelFormat target_format = 113
77 (pixel_format == VideoPixelFormat::RGBA8) ? AV_PIX_FMT_RGBA : AV_PIX_FMT_BGRA; 114 if (!scaler_ctx || frame->width != scaler_width || frame->height != scaler_height) {
115 const AVPixelFormat target_format = [pixel_format = config.pixel_format]() {
116 switch (pixel_format) {
117 case VideoPixelFormat::RGBA8:
118 return AV_PIX_FMT_RGBA;
119 case VideoPixelFormat::BGRA8:
120 return AV_PIX_FMT_BGRA;
121 case VideoPixelFormat::RGBX8:
122 return AV_PIX_FMT_RGB0;
123 default:
124 return AV_PIX_FMT_RGBA;
125 }
126 }();
127
128 sws_freeContext(scaler_ctx);
129 // Frames are decoded into either YUV420 or NV12 formats. Convert to desired RGB format
130 scaler_ctx = sws_getContext(frame->width, frame->height,
131 static_cast<AVPixelFormat>(frame->format), frame->width,
132 frame->height, target_format, 0, nullptr, nullptr, nullptr);
133 scaler_width = frame->width;
134 scaler_height = frame->height;
135 converted_frame_buffer.reset();
136 }
137 if (!converted_frame_buffer) {
138 const size_t frame_size = frame->width * frame->height * 4;
139 converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(frame_size)), av_free};
140 }
141 const std::array<int, 4> converted_stride{frame->width * 4, frame->height * 4, 0, 0};
142 u8* const converted_frame_buf_addr{converted_frame_buffer.get()};
143 sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height, &converted_frame_buf_addr,
144 converted_stride.data());
145
146 // Use the minimum of surface/frame dimensions to avoid buffer overflow.
147 const u32 surface_width = static_cast<u32>(config.surface_width_minus1) + 1;
148 const u32 surface_height = static_cast<u32>(config.surface_height_minus1) + 1;
149 const u32 width = std::min(surface_width, static_cast<u32>(frame->width));
150 const u32 height = std::min(surface_height, static_cast<u32>(frame->height));
151 const u32 blk_kind = static_cast<u32>(config.block_linear_kind);
152 if (blk_kind != 0) {
153 // swizzle pitch linear to block linear
154 const u32 block_height = static_cast<u32>(config.block_linear_height_log2);
155 const auto size = Texture::CalculateSize(true, 4, width, height, 1, block_height, 0);
156 luma_buffer.resize(size);
157 Texture::SwizzleSubrect(width, height, width * 4, width, 4, luma_buffer.data(),
158 converted_frame_buf_addr, block_height, 0, 0);
159
160 gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size);
161 } else {
162 // send pitch linear frame
163 const size_t linear_size = width * height * 4;
164 gpu.MemoryManager().WriteBlock(output_surface_luma_address, converted_frame_buf_addr,
165 linear_size);
166 }
167}
78 168
79 sws_freeContext(scaler_ctx); 169void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) {
80 scaler_ctx = nullptr; 170 LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame");
81 171
82 // Frames are decoded into either YUV420 or NV12 formats. Convert to desired format 172 const std::size_t surface_width = config.surface_width_minus1 + 1;
83 scaler_ctx = sws_getContext(frame->width, frame->height, 173 const std::size_t surface_height = config.surface_height_minus1 + 1;
84 static_cast<AVPixelFormat>(frame->format), frame->width, 174 const std::size_t aligned_width = (surface_width + 0xff) & ~0xffUL;
85 frame->height, target_format, 0, nullptr, nullptr, nullptr); 175 // Use the minimum of surface/frame dimensions to avoid buffer overflow.
176 const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->width));
177 const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->height));
86 178
87 scaler_width = frame->width; 179 const auto stride = static_cast<size_t>(frame->linesize[0]);
88 scaler_height = frame->height; 180
89 } 181 luma_buffer.resize(aligned_width * surface_height);
90 // Get Converted frame 182 chroma_buffer.resize(aligned_width * surface_height / 2);
91 const u32 width = static_cast<u32>(frame->width); 183
92 const u32 height = static_cast<u32>(frame->height); 184 // Populate luma buffer
93 const std::size_t linear_size = width * height * 4; 185 const u8* luma_src = frame->data[0];
94 186 for (std::size_t y = 0; y < frame_height; ++y) {
95 // Only allocate frame_buffer once per stream, as the size is not expected to change 187 const std::size_t src = y * stride;
96 if (!converted_frame_buffer) { 188 const std::size_t dst = y * aligned_width;
97 converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(linear_size)), av_free}; 189 for (std::size_t x = 0; x < frame_width; ++x) {
190 luma_buffer[dst + x] = luma_src[src + x];
98 } 191 }
99 const std::array<int, 4> converted_stride{frame->width * 4, frame->height * 4, 0, 0}; 192 }
100 u8* const converted_frame_buf_addr{converted_frame_buffer.get()}; 193 gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(),
101 194 luma_buffer.size());
102 sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height, 195
103 &converted_frame_buf_addr, converted_stride.data()); 196 // Chroma
104 197 const std::size_t half_height = frame_height / 2;
105 const u32 blk_kind = static_cast<u32>(config.block_linear_kind); 198 const auto half_stride = static_cast<size_t>(frame->linesize[1]);
106 if (blk_kind != 0) { 199
107 // swizzle pitch linear to block linear 200 switch (frame->format) {
108 const u32 block_height = static_cast<u32>(config.block_linear_height_log2); 201 case AV_PIX_FMT_YUV420P: {
109 const auto size = 202 // Frame from FFmpeg software
110 Tegra::Texture::CalculateSize(true, 4, width, height, 1, block_height, 0); 203 // Populate chroma buffer from both channels with interleaving.
111 luma_buffer.resize(size); 204 const std::size_t half_width = frame_width / 2;
112 Tegra::Texture::SwizzleSubrect(width, height, width * 4, width, 4, luma_buffer.data(), 205 const u8* chroma_b_src = frame->data[1];
113 converted_frame_buffer.get(), block_height, 0, 0); 206 const u8* chroma_r_src = frame->data[2];
114 207 for (std::size_t y = 0; y < half_height; ++y) {
115 gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size); 208 const std::size_t src = y * half_stride;
116 } else { 209 const std::size_t dst = y * aligned_width;
117 // send pitch linear frame 210
118 gpu.MemoryManager().WriteBlock(output_surface_luma_address, converted_frame_buf_addr, 211 for (std::size_t x = 0; x < half_width; ++x) {
119 linear_size); 212 chroma_buffer[dst + x * 2] = chroma_b_src[src + x];
213 chroma_buffer[dst + x * 2 + 1] = chroma_r_src[src + x];
214 }
120 } 215 }
121 break; 216 break;
122 } 217 }
123 case VideoPixelFormat::Yuv420: { 218 case AV_PIX_FMT_NV12: {
124 LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame"); 219 // Frame from VA-API hardware
125 220 // This is already interleaved so just copy
126 const std::size_t surface_width = config.surface_width_minus1 + 1; 221 const u8* chroma_src = frame->data[1];
127 const std::size_t surface_height = config.surface_height_minus1 + 1; 222 for (std::size_t y = 0; y < half_height; ++y) {
128 const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->width));
129 const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->height));
130 const std::size_t aligned_width = (surface_width + 0xff) & ~0xffUL;
131
132 const auto stride = static_cast<size_t>(frame->linesize[0]);
133
134 luma_buffer.resize(aligned_width * surface_height);
135 chroma_buffer.resize(aligned_width * surface_height / 2);
136
137 // Populate luma buffer
138 const u8* luma_src = frame->data[0];
139 for (std::size_t y = 0; y < frame_height; ++y) {
140 const std::size_t src = y * stride; 223 const std::size_t src = y * stride;
141 const std::size_t dst = y * aligned_width; 224 const std::size_t dst = y * aligned_width;
142 for (std::size_t x = 0; x < frame_width; ++x) { 225 for (std::size_t x = 0; x < frame_width; ++x) {
143 luma_buffer[dst + x] = luma_src[src + x]; 226 chroma_buffer[dst + x] = chroma_src[src + x];
144 }
145 }
146 gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(),
147 luma_buffer.size());
148
149 // Chroma
150 const std::size_t half_height = frame_height / 2;
151 const auto half_stride = static_cast<size_t>(frame->linesize[1]);
152
153 switch (frame->format) {
154 case AV_PIX_FMT_YUV420P: {
155 // Frame from FFmpeg software
156 // Populate chroma buffer from both channels with interleaving.
157 const std::size_t half_width = frame_width / 2;
158 const u8* chroma_b_src = frame->data[1];
159 const u8* chroma_r_src = frame->data[2];
160 for (std::size_t y = 0; y < half_height; ++y) {
161 const std::size_t src = y * half_stride;
162 const std::size_t dst = y * aligned_width;
163
164 for (std::size_t x = 0; x < half_width; ++x) {
165 chroma_buffer[dst + x * 2] = chroma_b_src[src + x];
166 chroma_buffer[dst + x * 2 + 1] = chroma_r_src[src + x];
167 }
168 } 227 }
169 break;
170 }
171 case AV_PIX_FMT_NV12: {
172 // Frame from VA-API hardware
173 // This is already interleaved so just copy
174 const u8* chroma_src = frame->data[1];
175 for (std::size_t y = 0; y < half_height; ++y) {
176 const std::size_t src = y * stride;
177 const std::size_t dst = y * aligned_width;
178 for (std::size_t x = 0; x < frame_width; ++x) {
179 chroma_buffer[dst + x] = chroma_src[src + x];
180 }
181 }
182 break;
183 }
184 default:
185 UNREACHABLE();
186 break;
187 } 228 }
188 gpu.MemoryManager().WriteBlock(output_surface_chroma_address, chroma_buffer.data(),
189 chroma_buffer.size());
190 break; 229 break;
191 } 230 }
192 default: 231 default:
193 UNIMPLEMENTED_MSG("Unknown video pixel format {}", config.pixel_format.Value()); 232 UNREACHABLE();
194 break; 233 break;
195 } 234 }
235 gpu.MemoryManager().WriteBlock(output_surface_chroma_address, chroma_buffer.data(),
236 chroma_buffer.size());
196} 237}
197 238
198} // namespace Tegra 239} // namespace Tegra
diff --git a/src/video_core/command_classes/vic.h b/src/video_core/command_classes/vic.h
index 74246e08c..6d4cdfd57 100644
--- a/src/video_core/command_classes/vic.h
+++ b/src/video_core/command_classes/vic.h
@@ -6,7 +6,6 @@
6 6
7#include <memory> 7#include <memory>
8#include <vector> 8#include <vector>
9#include "common/bit_field.h"
10#include "common/common_types.h" 9#include "common/common_types.h"
11 10
12struct SwsContext; 11struct SwsContext;
@@ -14,6 +13,7 @@ struct SwsContext;
14namespace Tegra { 13namespace Tegra {
15class GPU; 14class GPU;
16class Nvdec; 15class Nvdec;
16union VicConfig;
17 17
18class Vic { 18class Vic {
19public: 19public:
@@ -27,6 +27,7 @@ public:
27 }; 27 };
28 28
29 explicit Vic(GPU& gpu, std::shared_ptr<Nvdec> nvdec_processor); 29 explicit Vic(GPU& gpu, std::shared_ptr<Nvdec> nvdec_processor);
30
30 ~Vic(); 31 ~Vic();
31 32
32 /// Write to the device state. 33 /// Write to the device state.
@@ -35,22 +36,9 @@ public:
35private: 36private:
36 void Execute(); 37 void Execute();
37 38
38 enum class VideoPixelFormat : u64_le { 39 void WriteRGBFrame(const AVFrame* frame, const VicConfig& config);
39 RGBA8 = 0x1f,
40 BGRA8 = 0x20,
41 Yuv420 = 0x44,
42 };
43 40
44 union VicConfig { 41 void WriteYUVFrame(const AVFrame* frame, const VicConfig& config);
45 u64_le raw{};
46 BitField<0, 7, u64_le> pixel_format;
47 BitField<7, 2, u64_le> chroma_loc_horiz;
48 BitField<9, 2, u64_le> chroma_loc_vert;
49 BitField<11, 4, u64_le> block_linear_kind;
50 BitField<15, 4, u64_le> block_linear_height_log2;
51 BitField<32, 14, u64_le> surface_width_minus1;
52 BitField<46, 14, u64_le> surface_height_minus1;
53 };
54 42
55 GPU& gpu; 43 GPU& gpu;
56 std::shared_ptr<Tegra::Nvdec> nvdec_processor; 44 std::shared_ptr<Tegra::Nvdec> nvdec_processor;
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 7f4ca6282..f22342dfb 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <bitset> 8#include <bitset>
9#include <cmath>
9#include <limits> 10#include <limits>
10#include <optional> 11#include <optional>
11#include <type_traits> 12#include <type_traits>
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index c7ec1eac9..67388d980 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -82,41 +82,41 @@ void MaxwellDMA::Launch() {
82} 82}
83 83
84void MaxwellDMA::CopyPitchToPitch() { 84void MaxwellDMA::CopyPitchToPitch() {
85 // When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D 85 // When `multi_line_enable` bit is enabled we copy a 2D image of dimensions
86 // buffer of length `line_length_in`. 86 // (line_length_in, line_count).
87 // Otherwise we copy a 2D image of dimensions (line_length_in, line_count). 87 // Otherwise the copy is performed as if we were copying a 1D buffer of length line_length_in.
88 auto& accelerate = rasterizer->AccessAccelerateDMA(); 88 const bool remap_enabled = regs.launch_dma.remap_enable != 0;
89 if (!regs.launch_dma.multi_line_enable) { 89 if (regs.launch_dma.multi_line_enable) {
90 const bool is_buffer_clear = regs.launch_dma.remap_enable != 0 && 90 UNIMPLEMENTED_IF(remap_enabled);
91 regs.remap_const.dst_x == RemapConst::Swizzle::CONST_A; 91
92 // TODO: allow multisized components. 92 // Perform a line-by-line copy.
93 if (is_buffer_clear) { 93 // We're going to take a subrect of size (line_length_in, line_count) from the source
94 ASSERT(regs.remap_const.component_size_minus_one == 3); 94 // rectangle. There is no need to manually flush/invalidate the regions because CopyBlock
95 accelerate.BufferClear(regs.offset_out, regs.line_length_in, regs.remap_consta_value); 95 // does that for us.
96 std::vector<u32> tmp_buffer(regs.line_length_in, regs.remap_consta_value); 96 for (u32 line = 0; line < regs.line_count; ++line) {
97 memory_manager.WriteBlockUnsafe(regs.offset_out, 97 const GPUVAddr source_line = regs.offset_in + static_cast<size_t>(line) * regs.pitch_in;
98 reinterpret_cast<u8*>(tmp_buffer.data()), 98 const GPUVAddr dest_line = regs.offset_out + static_cast<size_t>(line) * regs.pitch_out;
99 regs.line_length_in * sizeof(u32)); 99 memory_manager.CopyBlock(dest_line, source_line, regs.line_length_in);
100 return;
101 }
102 UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0);
103 if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
104 std::vector<u8> tmp_buffer(regs.line_length_in);
105 memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), regs.line_length_in);
106 memory_manager.WriteBlock(regs.offset_out, tmp_buffer.data(), regs.line_length_in);
107 } 100 }
108 return; 101 return;
109 } 102 }
110 103 // TODO: allow multisized components.
111 UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0); 104 auto& accelerate = rasterizer->AccessAccelerateDMA();
112 105 const bool is_const_a_dst = regs.remap_const.dst_x == RemapConst::Swizzle::CONST_A;
113 // Perform a line-by-line copy. 106 const bool is_buffer_clear = remap_enabled && is_const_a_dst;
114 // We're going to take a subrect of size (line_length_in, line_count) from the source rectangle. 107 if (is_buffer_clear) {
115 // There is no need to manually flush/invalidate the regions because CopyBlock does that for us. 108 ASSERT(regs.remap_const.component_size_minus_one == 3);
116 for (u32 line = 0; line < regs.line_count; ++line) { 109 accelerate.BufferClear(regs.offset_out, regs.line_length_in, regs.remap_consta_value);
117 const GPUVAddr source_line = regs.offset_in + static_cast<size_t>(line) * regs.pitch_in; 110 std::vector<u32> tmp_buffer(regs.line_length_in, regs.remap_consta_value);
118 const GPUVAddr dest_line = regs.offset_out + static_cast<size_t>(line) * regs.pitch_out; 111 memory_manager.WriteBlockUnsafe(regs.offset_out, reinterpret_cast<u8*>(tmp_buffer.data()),
119 memory_manager.CopyBlock(dest_line, source_line, regs.line_length_in); 112 regs.line_length_in * sizeof(u32));
113 return;
114 }
115 UNIMPLEMENTED_IF(remap_enabled);
116 if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) {
117 std::vector<u8> tmp_buffer(regs.line_length_in);
118 memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), regs.line_length_in);
119 memory_manager.WriteBlock(regs.offset_out, tmp_buffer.data(), regs.line_length_in);
120 } 120 }
121} 121}
122 122
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index 9e457ae16..a04514425 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -175,7 +175,7 @@ public:
175 static_assert(sizeof(LaunchDMA) == 4); 175 static_assert(sizeof(LaunchDMA) == 4);
176 176
177 struct RemapConst { 177 struct RemapConst {
178 enum Swizzle : u32 { 178 enum class Swizzle : u32 {
179 SRC_X = 0, 179 SRC_X = 0,
180 SRC_Y = 1, 180 SRC_Y = 1,
181 SRC_Z = 2, 181 SRC_Z = 2,
diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h
index b86c3a757..b1d455e30 100644
--- a/src/video_core/framebuffer_config.h
+++ b/src/video_core/framebuffer_config.h
@@ -4,8 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Tegra { 7#include "common/common_types.h"
8#include "common/math_util.h"
8 9
10namespace Tegra {
9/** 11/**
10 * Struct describing framebuffer configuration 12 * Struct describing framebuffer configuration
11 */ 13 */
@@ -16,6 +18,21 @@ struct FramebufferConfig {
16 B8G8R8A8_UNORM = 5, 18 B8G8R8A8_UNORM = 5,
17 }; 19 };
18 20
21 enum class TransformFlags : u32 {
22 /// No transform flags are set
23 Unset = 0x00,
24 /// Flip source image horizontally (around the vertical axis)
25 FlipH = 0x01,
26 /// Flip source image vertically (around the horizontal axis)
27 FlipV = 0x02,
28 /// Rotate source image 90 degrees clockwise
29 Rotate90 = 0x04,
30 /// Rotate source image 180 degrees
31 Rotate180 = 0x03,
32 /// Rotate source image 270 degrees clockwise
33 Rotate270 = 0x07,
34 };
35
19 VAddr address{}; 36 VAddr address{};
20 u32 offset{}; 37 u32 offset{};
21 u32 width{}; 38 u32 width{};
@@ -23,7 +40,6 @@ struct FramebufferConfig {
23 u32 stride{}; 40 u32 stride{};
24 PixelFormat pixel_format{}; 41 PixelFormat pixel_format{};
25 42
26 using TransformFlags = Service::NVFlinger::BufferQueue::BufferTransformFlags;
27 TransformFlags transform_flags{}; 43 TransformFlags transform_flags{};
28 Common::Rectangle<int> crop_rect; 44 Common::Rectangle<int> crop_rect;
29}; 45};
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 2ae3639b5..ab7c21a49 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -2,540 +2,913 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
6#include <atomic>
5#include <chrono> 7#include <chrono>
8#include <condition_variable>
9#include <list>
10#include <memory>
6 11
7#include "common/assert.h" 12#include "common/assert.h"
8#include "common/microprofile.h" 13#include "common/microprofile.h"
9#include "common/settings.h" 14#include "common/settings.h"
10#include "core/core.h" 15#include "core/core.h"
11#include "core/core_timing.h" 16#include "core/core_timing.h"
12#include "core/core_timing_util.h"
13#include "core/frontend/emu_window.h" 17#include "core/frontend/emu_window.h"
14#include "core/hardware_interrupt_manager.h" 18#include "core/hardware_interrupt_manager.h"
15#include "core/memory.h" 19#include "core/hle/service/nvdrv/nvdata.h"
20#include "core/hle/service/nvflinger/buffer_queue.h"
16#include "core/perf_stats.h" 21#include "core/perf_stats.h"
22#include "video_core/cdma_pusher.h"
23#include "video_core/dma_pusher.h"
17#include "video_core/engines/fermi_2d.h" 24#include "video_core/engines/fermi_2d.h"
18#include "video_core/engines/kepler_compute.h" 25#include "video_core/engines/kepler_compute.h"
19#include "video_core/engines/kepler_memory.h" 26#include "video_core/engines/kepler_memory.h"
20#include "video_core/engines/maxwell_3d.h" 27#include "video_core/engines/maxwell_3d.h"
21#include "video_core/engines/maxwell_dma.h" 28#include "video_core/engines/maxwell_dma.h"
22#include "video_core/gpu.h" 29#include "video_core/gpu.h"
30#include "video_core/gpu_thread.h"
23#include "video_core/memory_manager.h" 31#include "video_core/memory_manager.h"
24#include "video_core/renderer_base.h" 32#include "video_core/renderer_base.h"
25#include "video_core/shader_notify.h" 33#include "video_core/shader_notify.h"
26#include "video_core/video_core.h"
27 34
28namespace Tegra { 35namespace Tegra {
29 36
30MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); 37MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
31 38
32GPU::GPU(Core::System& system_, bool is_async_, bool use_nvdec_) 39struct GPU::Impl {
33 : system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)}, 40 explicit Impl(GPU& gpu_, Core::System& system_, bool is_async_, bool use_nvdec_)
34 dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, use_nvdec{use_nvdec_}, 41 : gpu{gpu_}, system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(
35 maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)}, 42 system)},
36 fermi_2d{std::make_unique<Engines::Fermi2D>()}, 43 dma_pusher{std::make_unique<Tegra::DmaPusher>(system, gpu)}, use_nvdec{use_nvdec_},
37 kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)}, 44 maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
38 maxwell_dma{std::make_unique<Engines::MaxwellDMA>(system, *memory_manager)}, 45 fermi_2d{std::make_unique<Engines::Fermi2D>()},
39 kepler_memory{std::make_unique<Engines::KeplerMemory>(system, *memory_manager)}, 46 kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
40 shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_}, 47 maxwell_dma{std::make_unique<Engines::MaxwellDMA>(system, *memory_manager)},
41 gpu_thread{system_, is_async_} {} 48 kepler_memory{std::make_unique<Engines::KeplerMemory>(system, *memory_manager)},
49 shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_},
50 gpu_thread{system_, is_async_} {}
51
52 ~Impl() = default;
53
54 /// Binds a renderer to the GPU.
55 void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
56 renderer = std::move(renderer_);
57 rasterizer = renderer->ReadRasterizer();
58
59 memory_manager->BindRasterizer(rasterizer);
60 maxwell_3d->BindRasterizer(rasterizer);
61 fermi_2d->BindRasterizer(rasterizer);
62 kepler_compute->BindRasterizer(rasterizer);
63 maxwell_dma->BindRasterizer(rasterizer);
64 }
42 65
43GPU::~GPU() = default; 66 /// Calls a GPU method.
67 void CallMethod(const GPU::MethodCall& method_call) {
68 LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method,
69 method_call.subchannel);
70
71 ASSERT(method_call.subchannel < bound_engines.size());
72
73 if (ExecuteMethodOnEngine(method_call.method)) {
74 CallEngineMethod(method_call);
75 } else {
76 CallPullerMethod(method_call);
77 }
78 }
79
80 /// Calls a GPU multivalue method.
81 void CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
82 u32 methods_pending) {
83 LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method, subchannel);
44 84
45void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) { 85 ASSERT(subchannel < bound_engines.size());
46 renderer = std::move(renderer_); 86
47 rasterizer = renderer->ReadRasterizer(); 87 if (ExecuteMethodOnEngine(method)) {
88 CallEngineMultiMethod(method, subchannel, base_start, amount, methods_pending);
89 } else {
90 for (std::size_t i = 0; i < amount; i++) {
91 CallPullerMethod(GPU::MethodCall{
92 method,
93 base_start[i],
94 subchannel,
95 methods_pending - static_cast<u32>(i),
96 });
97 }
98 }
99 }
100
101 /// Flush all current written commands into the host GPU for execution.
102 void FlushCommands() {
103 rasterizer->FlushCommands();
104 }
105
106 /// Synchronizes CPU writes with Host GPU memory.
107 void SyncGuestHost() {
108 rasterizer->SyncGuestHost();
109 }
110
111 /// Signal the ending of command list.
112 void OnCommandListEnd() {
113 if (is_async) {
114 // This command only applies to asynchronous GPU mode
115 gpu_thread.OnCommandListEnd();
116 }
117 }
118
119 /// Request a host GPU memory flush from the CPU.
120 [[nodiscard]] u64 RequestFlush(VAddr addr, std::size_t size) {
121 std::unique_lock lck{flush_request_mutex};
122 const u64 fence = ++last_flush_fence;
123 flush_requests.emplace_back(fence, addr, size);
124 return fence;
125 }
126
127 /// Obtains current flush request fence id.
128 [[nodiscard]] u64 CurrentFlushRequestFence() const {
129 return current_flush_fence.load(std::memory_order_relaxed);
130 }
131
132 /// Tick pending requests within the GPU.
133 void TickWork() {
134 std::unique_lock lck{flush_request_mutex};
135 while (!flush_requests.empty()) {
136 auto& request = flush_requests.front();
137 const u64 fence = request.fence;
138 const VAddr addr = request.addr;
139 const std::size_t size = request.size;
140 flush_requests.pop_front();
141 flush_request_mutex.unlock();
142 rasterizer->FlushRegion(addr, size);
143 current_flush_fence.store(fence);
144 flush_request_mutex.lock();
145 }
146 }
147
148 /// Returns a reference to the Maxwell3D GPU engine.
149 [[nodiscard]] Engines::Maxwell3D& Maxwell3D() {
150 return *maxwell_3d;
151 }
152
153 /// Returns a const reference to the Maxwell3D GPU engine.
154 [[nodiscard]] const Engines::Maxwell3D& Maxwell3D() const {
155 return *maxwell_3d;
156 }
157
158 /// Returns a reference to the KeplerCompute GPU engine.
159 [[nodiscard]] Engines::KeplerCompute& KeplerCompute() {
160 return *kepler_compute;
161 }
162
163 /// Returns a reference to the KeplerCompute GPU engine.
164 [[nodiscard]] const Engines::KeplerCompute& KeplerCompute() const {
165 return *kepler_compute;
166 }
167
168 /// Returns a reference to the GPU memory manager.
169 [[nodiscard]] Tegra::MemoryManager& MemoryManager() {
170 return *memory_manager;
171 }
172
173 /// Returns a const reference to the GPU memory manager.
174 [[nodiscard]] const Tegra::MemoryManager& MemoryManager() const {
175 return *memory_manager;
176 }
177
178 /// Returns a reference to the GPU DMA pusher.
179 [[nodiscard]] Tegra::DmaPusher& DmaPusher() {
180 return *dma_pusher;
181 }
182
183 /// Returns a const reference to the GPU DMA pusher.
184 [[nodiscard]] const Tegra::DmaPusher& DmaPusher() const {
185 return *dma_pusher;
186 }
187
188 /// Returns a reference to the GPU CDMA pusher.
189 [[nodiscard]] Tegra::CDmaPusher& CDmaPusher() {
190 return *cdma_pusher;
191 }
192
193 /// Returns a const reference to the GPU CDMA pusher.
194 [[nodiscard]] const Tegra::CDmaPusher& CDmaPusher() const {
195 return *cdma_pusher;
196 }
197
198 /// Returns a reference to the underlying renderer.
199 [[nodiscard]] VideoCore::RendererBase& Renderer() {
200 return *renderer;
201 }
202
203 /// Returns a const reference to the underlying renderer.
204 [[nodiscard]] const VideoCore::RendererBase& Renderer() const {
205 return *renderer;
206 }
207
208 /// Returns a reference to the shader notifier.
209 [[nodiscard]] VideoCore::ShaderNotify& ShaderNotify() {
210 return *shader_notify;
211 }
212
213 /// Returns a const reference to the shader notifier.
214 [[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const {
215 return *shader_notify;
216 }
217
218 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
219 void WaitFence(u32 syncpoint_id, u32 value) {
220 // Synced GPU, is always in sync
221 if (!is_async) {
222 return;
223 }
224 if (syncpoint_id == UINT32_MAX) {
225 // TODO: Research what this does.
226 LOG_ERROR(HW_GPU, "Waiting for syncpoint -1 not implemented");
227 return;
228 }
229 MICROPROFILE_SCOPE(GPU_wait);
230 std::unique_lock lock{sync_mutex};
231 sync_cv.wait(lock, [=, this] {
232 if (shutting_down.load(std::memory_order_relaxed)) {
233 // We're shutting down, ensure no threads continue to wait for the next syncpoint
234 return true;
235 }
236 return syncpoints.at(syncpoint_id).load() >= value;
237 });
238 }
239
240 void IncrementSyncPoint(u32 syncpoint_id) {
241 auto& syncpoint = syncpoints.at(syncpoint_id);
242 syncpoint++;
243 std::lock_guard lock{sync_mutex};
244 sync_cv.notify_all();
245 auto& interrupt = syncpt_interrupts.at(syncpoint_id);
246 if (!interrupt.empty()) {
247 u32 value = syncpoint.load();
248 auto it = interrupt.begin();
249 while (it != interrupt.end()) {
250 if (value >= *it) {
251 TriggerCpuInterrupt(syncpoint_id, *it);
252 it = interrupt.erase(it);
253 continue;
254 }
255 it++;
256 }
257 }
258 }
259
260 [[nodiscard]] u32 GetSyncpointValue(u32 syncpoint_id) const {
261 return syncpoints.at(syncpoint_id).load();
262 }
263
264 void RegisterSyncptInterrupt(u32 syncpoint_id, u32 value) {
265 std::lock_guard lock{sync_mutex};
266 auto& interrupt = syncpt_interrupts.at(syncpoint_id);
267 bool contains = std::any_of(interrupt.begin(), interrupt.end(),
268 [value](u32 in_value) { return in_value == value; });
269 if (contains) {
270 return;
271 }
272 interrupt.emplace_back(value);
273 }
274
275 [[nodiscard]] bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value) {
276 std::lock_guard lock{sync_mutex};
277 auto& interrupt = syncpt_interrupts.at(syncpoint_id);
278 const auto iter =
279 std::find_if(interrupt.begin(), interrupt.end(),
280 [value](u32 interrupt_value) { return value == interrupt_value; });
281
282 if (iter == interrupt.end()) {
283 return false;
284 }
285 interrupt.erase(iter);
286 return true;
287 }
288
289 [[nodiscard]] u64 GetTicks() const {
290 // This values were reversed engineered by fincs from NVN
291 // The gpu clock is reported in units of 385/625 nanoseconds
292 constexpr u64 gpu_ticks_num = 384;
293 constexpr u64 gpu_ticks_den = 625;
294
295 u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count();
296 if (Settings::values.use_fast_gpu_time.GetValue()) {
297 nanoseconds /= 256;
298 }
299 const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
300 const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den;
301 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
302 }
303
304 [[nodiscard]] bool IsAsync() const {
305 return is_async;
306 }
307
308 [[nodiscard]] bool UseNvdec() const {
309 return use_nvdec;
310 }
311
312 void RendererFrameEndNotify() {
313 system.GetPerfStats().EndGameFrame();
314 }
315
316 /// Performs any additional setup necessary in order to begin GPU emulation.
317 /// This can be used to launch any necessary threads and register any necessary
318 /// core timing events.
319 void Start() {
320 gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher);
321 cpu_context = renderer->GetRenderWindow().CreateSharedContext();
322 cpu_context->MakeCurrent();
323 }
324
325 /// Obtain the CPU Context
326 void ObtainContext() {
327 cpu_context->MakeCurrent();
328 }
329
330 /// Release the CPU Context
331 void ReleaseContext() {
332 cpu_context->DoneCurrent();
333 }
334
335 /// Push GPU command entries to be processed
336 void PushGPUEntries(Tegra::CommandList&& entries) {
337 gpu_thread.SubmitList(std::move(entries));
338 }
339
340 /// Push GPU command buffer entries to be processed
341 void PushCommandBuffer(Tegra::ChCommandHeaderList& entries) {
342 if (!use_nvdec) {
343 return;
344 }
345
346 if (!cdma_pusher) {
347 cdma_pusher = std::make_unique<Tegra::CDmaPusher>(gpu);
348 }
349
350 // SubmitCommandBuffer would make the nvdec operations async, this is not currently working
351 // TODO(ameerj): RE proper async nvdec operation
352 // gpu_thread.SubmitCommandBuffer(std::move(entries));
353
354 cdma_pusher->ProcessEntries(std::move(entries));
355 }
356
357 /// Frees the CDMAPusher instance to free up resources
358 void ClearCdmaInstance() {
359 cdma_pusher.reset();
360 }
361
362 /// Swap buffers (render frame)
363 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
364 gpu_thread.SwapBuffers(framebuffer);
365 }
366
367 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
368 void FlushRegion(VAddr addr, u64 size) {
369 gpu_thread.FlushRegion(addr, size);
370 }
371
372 /// Notify rasterizer that any caches of the specified region should be invalidated
373 void InvalidateRegion(VAddr addr, u64 size) {
374 gpu_thread.InvalidateRegion(addr, size);
375 }
376
377 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
378 void FlushAndInvalidateRegion(VAddr addr, u64 size) {
379 gpu_thread.FlushAndInvalidateRegion(addr, size);
380 }
381
382 void TriggerCpuInterrupt(u32 syncpoint_id, u32 value) const {
383 auto& interrupt_manager = system.InterruptManager();
384 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
385 }
386
387 void ProcessBindMethod(const GPU::MethodCall& method_call) {
388 // Bind the current subchannel to the desired engine id.
389 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel,
390 method_call.argument);
391 const auto engine_id = static_cast<EngineID>(method_call.argument);
392 bound_engines[method_call.subchannel] = static_cast<EngineID>(engine_id);
393 switch (engine_id) {
394 case EngineID::FERMI_TWOD_A:
395 dma_pusher->BindSubchannel(fermi_2d.get(), method_call.subchannel);
396 break;
397 case EngineID::MAXWELL_B:
398 dma_pusher->BindSubchannel(maxwell_3d.get(), method_call.subchannel);
399 break;
400 case EngineID::KEPLER_COMPUTE_B:
401 dma_pusher->BindSubchannel(kepler_compute.get(), method_call.subchannel);
402 break;
403 case EngineID::MAXWELL_DMA_COPY_A:
404 dma_pusher->BindSubchannel(maxwell_dma.get(), method_call.subchannel);
405 break;
406 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
407 dma_pusher->BindSubchannel(kepler_memory.get(), method_call.subchannel);
408 break;
409 default:
410 UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id);
411 }
412 }
48 413
49 memory_manager->BindRasterizer(rasterizer); 414 void ProcessFenceActionMethod() {
50 maxwell_3d->BindRasterizer(rasterizer); 415 switch (regs.fence_action.op) {
51 fermi_2d->BindRasterizer(rasterizer); 416 case GPU::FenceOperation::Acquire:
52 kepler_compute->BindRasterizer(rasterizer); 417 WaitFence(regs.fence_action.syncpoint_id, regs.fence_value);
53 maxwell_dma->BindRasterizer(rasterizer); 418 break;
419 case GPU::FenceOperation::Increment:
420 IncrementSyncPoint(regs.fence_action.syncpoint_id);
421 break;
422 default:
423 UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value());
424 }
425 }
426
427 void ProcessWaitForInterruptMethod() {
428 // TODO(bunnei) ImplementMe
429 LOG_WARNING(HW_GPU, "(STUBBED) called");
430 }
431
432 void ProcessSemaphoreTriggerMethod() {
433 const auto semaphoreOperationMask = 0xF;
434 const auto op =
435 static_cast<GpuSemaphoreOperation>(regs.semaphore_trigger & semaphoreOperationMask);
436 if (op == GpuSemaphoreOperation::WriteLong) {
437 struct Block {
438 u32 sequence;
439 u32 zeros = 0;
440 u64 timestamp;
441 };
442
443 Block block{};
444 block.sequence = regs.semaphore_sequence;
445 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
446 // CoreTiming
447 block.timestamp = GetTicks();
448 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
449 sizeof(block));
450 } else {
451 const u32 word{memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress())};
452 if ((op == GpuSemaphoreOperation::AcquireEqual && word == regs.semaphore_sequence) ||
453 (op == GpuSemaphoreOperation::AcquireGequal &&
454 static_cast<s32>(word - regs.semaphore_sequence) > 0) ||
455 (op == GpuSemaphoreOperation::AcquireMask && (word & regs.semaphore_sequence))) {
456 // Nothing to do in this case
457 } else {
458 regs.acquire_source = true;
459 regs.acquire_value = regs.semaphore_sequence;
460 if (op == GpuSemaphoreOperation::AcquireEqual) {
461 regs.acquire_active = true;
462 regs.acquire_mode = false;
463 } else if (op == GpuSemaphoreOperation::AcquireGequal) {
464 regs.acquire_active = true;
465 regs.acquire_mode = true;
466 } else if (op == GpuSemaphoreOperation::AcquireMask) {
467 // TODO(kemathe) The acquire mask operation waits for a value that, ANDed with
468 // semaphore_sequence, gives a non-0 result
469 LOG_ERROR(HW_GPU, "Invalid semaphore operation AcquireMask not implemented");
470 } else {
471 LOG_ERROR(HW_GPU, "Invalid semaphore operation");
472 }
473 }
474 }
475 }
476
477 void ProcessSemaphoreRelease() {
478 memory_manager->Write<u32>(regs.semaphore_address.SemaphoreAddress(),
479 regs.semaphore_release);
480 }
481
482 void ProcessSemaphoreAcquire() {
483 const u32 word = memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress());
484 const auto value = regs.semaphore_acquire;
485 if (word != value) {
486 regs.acquire_active = true;
487 regs.acquire_value = value;
488 // TODO(kemathe73) figure out how to do the acquire_timeout
489 regs.acquire_mode = false;
490 regs.acquire_source = false;
491 }
492 }
493
494 /// Calls a GPU puller method.
495 void CallPullerMethod(const GPU::MethodCall& method_call) {
496 regs.reg_array[method_call.method] = method_call.argument;
497 const auto method = static_cast<BufferMethods>(method_call.method);
498
499 switch (method) {
500 case BufferMethods::BindObject: {
501 ProcessBindMethod(method_call);
502 break;
503 }
504 case BufferMethods::Nop:
505 case BufferMethods::SemaphoreAddressHigh:
506 case BufferMethods::SemaphoreAddressLow:
507 case BufferMethods::SemaphoreSequence:
508 case BufferMethods::UnkCacheFlush:
509 case BufferMethods::WrcacheFlush:
510 case BufferMethods::FenceValue:
511 break;
512 case BufferMethods::RefCnt:
513 rasterizer->SignalReference();
514 break;
515 case BufferMethods::FenceAction:
516 ProcessFenceActionMethod();
517 break;
518 case BufferMethods::WaitForInterrupt:
519 ProcessWaitForInterruptMethod();
520 break;
521 case BufferMethods::SemaphoreTrigger: {
522 ProcessSemaphoreTriggerMethod();
523 break;
524 }
525 case BufferMethods::NotifyIntr: {
526 // TODO(Kmather73): Research and implement this method.
527 LOG_ERROR(HW_GPU, "Special puller engine method NotifyIntr not implemented");
528 break;
529 }
530 case BufferMethods::Unk28: {
531 // TODO(Kmather73): Research and implement this method.
532 LOG_ERROR(HW_GPU, "Special puller engine method Unk28 not implemented");
533 break;
534 }
535 case BufferMethods::SemaphoreAcquire: {
536 ProcessSemaphoreAcquire();
537 break;
538 }
539 case BufferMethods::SemaphoreRelease: {
540 ProcessSemaphoreRelease();
541 break;
542 }
543 case BufferMethods::Yield: {
544 // TODO(Kmather73): Research and implement this method.
545 LOG_ERROR(HW_GPU, "Special puller engine method Yield not implemented");
546 break;
547 }
548 default:
549 LOG_ERROR(HW_GPU, "Special puller engine method {:X} not implemented", method);
550 break;
551 }
552 }
553
554 /// Calls a GPU engine method.
555 void CallEngineMethod(const GPU::MethodCall& method_call) {
556 const EngineID engine = bound_engines[method_call.subchannel];
557
558 switch (engine) {
559 case EngineID::FERMI_TWOD_A:
560 fermi_2d->CallMethod(method_call.method, method_call.argument,
561 method_call.IsLastCall());
562 break;
563 case EngineID::MAXWELL_B:
564 maxwell_3d->CallMethod(method_call.method, method_call.argument,
565 method_call.IsLastCall());
566 break;
567 case EngineID::KEPLER_COMPUTE_B:
568 kepler_compute->CallMethod(method_call.method, method_call.argument,
569 method_call.IsLastCall());
570 break;
571 case EngineID::MAXWELL_DMA_COPY_A:
572 maxwell_dma->CallMethod(method_call.method, method_call.argument,
573 method_call.IsLastCall());
574 break;
575 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
576 kepler_memory->CallMethod(method_call.method, method_call.argument,
577 method_call.IsLastCall());
578 break;
579 default:
580 UNIMPLEMENTED_MSG("Unimplemented engine");
581 }
582 }
583
584 /// Calls a GPU engine multivalue method.
585 void CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
586 u32 methods_pending) {
587 const EngineID engine = bound_engines[subchannel];
588
589 switch (engine) {
590 case EngineID::FERMI_TWOD_A:
591 fermi_2d->CallMultiMethod(method, base_start, amount, methods_pending);
592 break;
593 case EngineID::MAXWELL_B:
594 maxwell_3d->CallMultiMethod(method, base_start, amount, methods_pending);
595 break;
596 case EngineID::KEPLER_COMPUTE_B:
597 kepler_compute->CallMultiMethod(method, base_start, amount, methods_pending);
598 break;
599 case EngineID::MAXWELL_DMA_COPY_A:
600 maxwell_dma->CallMultiMethod(method, base_start, amount, methods_pending);
601 break;
602 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
603 kepler_memory->CallMultiMethod(method, base_start, amount, methods_pending);
604 break;
605 default:
606 UNIMPLEMENTED_MSG("Unimplemented engine");
607 }
608 }
609
610 /// Determines where the method should be executed.
611 [[nodiscard]] bool ExecuteMethodOnEngine(u32 method) {
612 const auto buffer_method = static_cast<BufferMethods>(method);
613 return buffer_method >= BufferMethods::NonPullerMethods;
614 }
615
616 struct Regs {
617 static constexpr size_t NUM_REGS = 0x40;
618
619 union {
620 struct {
621 INSERT_PADDING_WORDS_NOINIT(0x4);
622 struct {
623 u32 address_high;
624 u32 address_low;
625
626 [[nodiscard]] GPUVAddr SemaphoreAddress() const {
627 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
628 address_low);
629 }
630 } semaphore_address;
631
632 u32 semaphore_sequence;
633 u32 semaphore_trigger;
634 INSERT_PADDING_WORDS_NOINIT(0xC);
635
636 // The pusher and the puller share the reference counter, the pusher only has read
637 // access
638 u32 reference_count;
639 INSERT_PADDING_WORDS_NOINIT(0x5);
640
641 u32 semaphore_acquire;
642 u32 semaphore_release;
643 u32 fence_value;
644 GPU::FenceAction fence_action;
645 INSERT_PADDING_WORDS_NOINIT(0xE2);
646
647 // Puller state
648 u32 acquire_mode;
649 u32 acquire_source;
650 u32 acquire_active;
651 u32 acquire_timeout;
652 u32 acquire_value;
653 };
654 std::array<u32, NUM_REGS> reg_array;
655 };
656 } regs{};
657
658 GPU& gpu;
659 Core::System& system;
660 std::unique_ptr<Tegra::MemoryManager> memory_manager;
661 std::unique_ptr<Tegra::DmaPusher> dma_pusher;
662 std::unique_ptr<Tegra::CDmaPusher> cdma_pusher;
663 std::unique_ptr<VideoCore::RendererBase> renderer;
664 VideoCore::RasterizerInterface* rasterizer = nullptr;
665 const bool use_nvdec;
666
667 /// Mapping of command subchannels to their bound engine ids
668 std::array<EngineID, 8> bound_engines{};
669 /// 3D engine
670 std::unique_ptr<Engines::Maxwell3D> maxwell_3d;
671 /// 2D engine
672 std::unique_ptr<Engines::Fermi2D> fermi_2d;
673 /// Compute engine
674 std::unique_ptr<Engines::KeplerCompute> kepler_compute;
675 /// DMA engine
676 std::unique_ptr<Engines::MaxwellDMA> maxwell_dma;
677 /// Inline memory engine
678 std::unique_ptr<Engines::KeplerMemory> kepler_memory;
679 /// Shader build notifier
680 std::unique_ptr<VideoCore::ShaderNotify> shader_notify;
681 /// When true, we are about to shut down emulation session, so terminate outstanding tasks
682 std::atomic_bool shutting_down{};
683
684 std::array<std::atomic<u32>, Service::Nvidia::MaxSyncPoints> syncpoints{};
685
686 std::array<std::list<u32>, Service::Nvidia::MaxSyncPoints> syncpt_interrupts;
687
688 std::mutex sync_mutex;
689 std::mutex device_mutex;
690
691 std::condition_variable sync_cv;
692
693 struct FlushRequest {
694 explicit FlushRequest(u64 fence_, VAddr addr_, std::size_t size_)
695 : fence{fence_}, addr{addr_}, size{size_} {}
696 u64 fence;
697 VAddr addr;
698 std::size_t size;
699 };
700
701 std::list<FlushRequest> flush_requests;
702 std::atomic<u64> current_flush_fence{};
703 u64 last_flush_fence{};
704 std::mutex flush_request_mutex;
705
706 const bool is_async;
707
708 VideoCommon::GPUThread::ThreadManager gpu_thread;
709 std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context;
710
711#define ASSERT_REG_POSITION(field_name, position) \
712 static_assert(offsetof(Regs, field_name) == position * 4, \
713 "Field " #field_name " has invalid position")
714
715 ASSERT_REG_POSITION(semaphore_address, 0x4);
716 ASSERT_REG_POSITION(semaphore_sequence, 0x6);
717 ASSERT_REG_POSITION(semaphore_trigger, 0x7);
718 ASSERT_REG_POSITION(reference_count, 0x14);
719 ASSERT_REG_POSITION(semaphore_acquire, 0x1A);
720 ASSERT_REG_POSITION(semaphore_release, 0x1B);
721 ASSERT_REG_POSITION(fence_value, 0x1C);
722 ASSERT_REG_POSITION(fence_action, 0x1D);
723
724 ASSERT_REG_POSITION(acquire_mode, 0x100);
725 ASSERT_REG_POSITION(acquire_source, 0x101);
726 ASSERT_REG_POSITION(acquire_active, 0x102);
727 ASSERT_REG_POSITION(acquire_timeout, 0x103);
728 ASSERT_REG_POSITION(acquire_value, 0x104);
729
730#undef ASSERT_REG_POSITION
731
732 enum class GpuSemaphoreOperation {
733 AcquireEqual = 0x1,
734 WriteLong = 0x2,
735 AcquireGequal = 0x4,
736 AcquireMask = 0x8,
737 };
738};
739
740GPU::GPU(Core::System& system, bool is_async, bool use_nvdec)
741 : impl{std::make_unique<Impl>(*this, system, is_async, use_nvdec)} {}
742
743GPU::~GPU() = default;
744
745void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer) {
746 impl->BindRenderer(std::move(renderer));
54} 747}
55 748
56Engines::Maxwell3D& GPU::Maxwell3D() { 749void GPU::CallMethod(const MethodCall& method_call) {
57 return *maxwell_3d; 750 impl->CallMethod(method_call);
58} 751}
59 752
60const Engines::Maxwell3D& GPU::Maxwell3D() const { 753void GPU::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
61 return *maxwell_3d; 754 u32 methods_pending) {
755 impl->CallMultiMethod(method, subchannel, base_start, amount, methods_pending);
62} 756}
63 757
64Engines::KeplerCompute& GPU::KeplerCompute() { 758void GPU::FlushCommands() {
65 return *kepler_compute; 759 impl->FlushCommands();
66} 760}
67 761
68const Engines::KeplerCompute& GPU::KeplerCompute() const { 762void GPU::SyncGuestHost() {
69 return *kepler_compute; 763 impl->SyncGuestHost();
70} 764}
71 765
72MemoryManager& GPU::MemoryManager() { 766void GPU::OnCommandListEnd() {
73 return *memory_manager; 767 impl->OnCommandListEnd();
74} 768}
75 769
76const MemoryManager& GPU::MemoryManager() const { 770u64 GPU::RequestFlush(VAddr addr, std::size_t size) {
77 return *memory_manager; 771 return impl->RequestFlush(addr, size);
78} 772}
79 773
80DmaPusher& GPU::DmaPusher() { 774u64 GPU::CurrentFlushRequestFence() const {
81 return *dma_pusher; 775 return impl->CurrentFlushRequestFence();
82} 776}
83 777
84Tegra::CDmaPusher& GPU::CDmaPusher() { 778void GPU::TickWork() {
85 return *cdma_pusher; 779 impl->TickWork();
86} 780}
87 781
88const DmaPusher& GPU::DmaPusher() const { 782Engines::Maxwell3D& GPU::Maxwell3D() {
89 return *dma_pusher; 783 return impl->Maxwell3D();
90} 784}
91 785
92const Tegra::CDmaPusher& GPU::CDmaPusher() const { 786const Engines::Maxwell3D& GPU::Maxwell3D() const {
93 return *cdma_pusher; 787 return impl->Maxwell3D();
94} 788}
95 789
96void GPU::WaitFence(u32 syncpoint_id, u32 value) { 790Engines::KeplerCompute& GPU::KeplerCompute() {
97 // Synced GPU, is always in sync 791 return impl->KeplerCompute();
98 if (!is_async) {
99 return;
100 }
101 if (syncpoint_id == UINT32_MAX) {
102 // TODO: Research what this does.
103 LOG_ERROR(HW_GPU, "Waiting for syncpoint -1 not implemented");
104 return;
105 }
106 MICROPROFILE_SCOPE(GPU_wait);
107 std::unique_lock lock{sync_mutex};
108 sync_cv.wait(lock, [=, this] {
109 if (shutting_down.load(std::memory_order_relaxed)) {
110 // We're shutting down, ensure no threads continue to wait for the next syncpoint
111 return true;
112 }
113 return syncpoints.at(syncpoint_id).load() >= value;
114 });
115}
116
117void GPU::IncrementSyncPoint(const u32 syncpoint_id) {
118 auto& syncpoint = syncpoints.at(syncpoint_id);
119 syncpoint++;
120 std::lock_guard lock{sync_mutex};
121 sync_cv.notify_all();
122 auto& interrupt = syncpt_interrupts.at(syncpoint_id);
123 if (!interrupt.empty()) {
124 u32 value = syncpoint.load();
125 auto it = interrupt.begin();
126 while (it != interrupt.end()) {
127 if (value >= *it) {
128 TriggerCpuInterrupt(syncpoint_id, *it);
129 it = interrupt.erase(it);
130 continue;
131 }
132 it++;
133 }
134 }
135} 792}
136 793
137u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const { 794const Engines::KeplerCompute& GPU::KeplerCompute() const {
138 return syncpoints.at(syncpoint_id).load(); 795 return impl->KeplerCompute();
139} 796}
140 797
141void GPU::RegisterSyncptInterrupt(const u32 syncpoint_id, const u32 value) { 798Tegra::MemoryManager& GPU::MemoryManager() {
142 auto& interrupt = syncpt_interrupts.at(syncpoint_id); 799 return impl->MemoryManager();
143 bool contains = std::any_of(interrupt.begin(), interrupt.end(),
144 [value](u32 in_value) { return in_value == value; });
145 if (contains) {
146 return;
147 }
148 interrupt.emplace_back(value);
149} 800}
150 801
151bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) { 802const Tegra::MemoryManager& GPU::MemoryManager() const {
152 std::lock_guard lock{sync_mutex}; 803 return impl->MemoryManager();
153 auto& interrupt = syncpt_interrupts.at(syncpoint_id); 804}
154 const auto iter =
155 std::find_if(interrupt.begin(), interrupt.end(),
156 [value](u32 interrupt_value) { return value == interrupt_value; });
157 805
158 if (iter == interrupt.end()) { 806Tegra::DmaPusher& GPU::DmaPusher() {
159 return false; 807 return impl->DmaPusher();
160 }
161 interrupt.erase(iter);
162 return true;
163} 808}
164 809
165u64 GPU::RequestFlush(VAddr addr, std::size_t size) { 810const Tegra::DmaPusher& GPU::DmaPusher() const {
166 std::unique_lock lck{flush_request_mutex}; 811 return impl->DmaPusher();
167 const u64 fence = ++last_flush_fence;
168 flush_requests.emplace_back(fence, addr, size);
169 return fence;
170} 812}
171 813
172void GPU::TickWork() { 814Tegra::CDmaPusher& GPU::CDmaPusher() {
173 std::unique_lock lck{flush_request_mutex}; 815 return impl->CDmaPusher();
174 while (!flush_requests.empty()) {
175 auto& request = flush_requests.front();
176 const u64 fence = request.fence;
177 const VAddr addr = request.addr;
178 const std::size_t size = request.size;
179 flush_requests.pop_front();
180 flush_request_mutex.unlock();
181 rasterizer->FlushRegion(addr, size);
182 current_flush_fence.store(fence);
183 flush_request_mutex.lock();
184 }
185} 816}
186 817
187u64 GPU::GetTicks() const { 818const Tegra::CDmaPusher& GPU::CDmaPusher() const {
188 // This values were reversed engineered by fincs from NVN 819 return impl->CDmaPusher();
189 // The gpu clock is reported in units of 385/625 nanoseconds 820}
190 constexpr u64 gpu_ticks_num = 384;
191 constexpr u64 gpu_ticks_den = 625;
192 821
193 u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count(); 822VideoCore::RendererBase& GPU::Renderer() {
194 if (Settings::values.use_fast_gpu_time.GetValue()) { 823 return impl->Renderer();
195 nanoseconds /= 256;
196 }
197 const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
198 const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den;
199 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
200} 824}
201 825
202void GPU::RendererFrameEndNotify() { 826const VideoCore::RendererBase& GPU::Renderer() const {
203 system.GetPerfStats().EndGameFrame(); 827 return impl->Renderer();
204} 828}
205 829
206void GPU::FlushCommands() { 830VideoCore::ShaderNotify& GPU::ShaderNotify() {
207 rasterizer->FlushCommands(); 831 return impl->ShaderNotify();
208} 832}
209 833
210void GPU::SyncGuestHost() { 834const VideoCore::ShaderNotify& GPU::ShaderNotify() const {
211 rasterizer->SyncGuestHost(); 835 return impl->ShaderNotify();
212} 836}
213 837
214enum class GpuSemaphoreOperation { 838void GPU::WaitFence(u32 syncpoint_id, u32 value) {
215 AcquireEqual = 0x1, 839 impl->WaitFence(syncpoint_id, value);
216 WriteLong = 0x2, 840}
217 AcquireGequal = 0x4,
218 AcquireMask = 0x8,
219};
220 841
221void GPU::CallMethod(const MethodCall& method_call) { 842void GPU::IncrementSyncPoint(u32 syncpoint_id) {
222 LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method, 843 impl->IncrementSyncPoint(syncpoint_id);
223 method_call.subchannel); 844}
224 845
225 ASSERT(method_call.subchannel < bound_engines.size()); 846u32 GPU::GetSyncpointValue(u32 syncpoint_id) const {
847 return impl->GetSyncpointValue(syncpoint_id);
848}
226 849
227 if (ExecuteMethodOnEngine(method_call.method)) { 850void GPU::RegisterSyncptInterrupt(u32 syncpoint_id, u32 value) {
228 CallEngineMethod(method_call); 851 impl->RegisterSyncptInterrupt(syncpoint_id, value);
229 } else {
230 CallPullerMethod(method_call);
231 }
232} 852}
233 853
234void GPU::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount, 854bool GPU::CancelSyncptInterrupt(u32 syncpoint_id, u32 value) {
235 u32 methods_pending) { 855 return impl->CancelSyncptInterrupt(syncpoint_id, value);
236 LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method, subchannel);
237
238 ASSERT(subchannel < bound_engines.size());
239
240 if (ExecuteMethodOnEngine(method)) {
241 CallEngineMultiMethod(method, subchannel, base_start, amount, methods_pending);
242 } else {
243 for (std::size_t i = 0; i < amount; i++) {
244 CallPullerMethod(MethodCall{
245 method,
246 base_start[i],
247 subchannel,
248 methods_pending - static_cast<u32>(i),
249 });
250 }
251 }
252} 856}
253 857
254bool GPU::ExecuteMethodOnEngine(u32 method) { 858u64 GPU::GetTicks() const {
255 const auto buffer_method = static_cast<BufferMethods>(method); 859 return impl->GetTicks();
256 return buffer_method >= BufferMethods::NonPullerMethods; 860}
257}
258
259void GPU::CallPullerMethod(const MethodCall& method_call) {
260 regs.reg_array[method_call.method] = method_call.argument;
261 const auto method = static_cast<BufferMethods>(method_call.method);
262
263 switch (method) {
264 case BufferMethods::BindObject: {
265 ProcessBindMethod(method_call);
266 break;
267 }
268 case BufferMethods::Nop:
269 case BufferMethods::SemaphoreAddressHigh:
270 case BufferMethods::SemaphoreAddressLow:
271 case BufferMethods::SemaphoreSequence:
272 case BufferMethods::UnkCacheFlush:
273 case BufferMethods::WrcacheFlush:
274 case BufferMethods::FenceValue:
275 break;
276 case BufferMethods::RefCnt:
277 rasterizer->SignalReference();
278 break;
279 case BufferMethods::FenceAction:
280 ProcessFenceActionMethod();
281 break;
282 case BufferMethods::WaitForInterrupt:
283 ProcessWaitForInterruptMethod();
284 break;
285 case BufferMethods::SemaphoreTrigger: {
286 ProcessSemaphoreTriggerMethod();
287 break;
288 }
289 case BufferMethods::NotifyIntr: {
290 // TODO(Kmather73): Research and implement this method.
291 LOG_ERROR(HW_GPU, "Special puller engine method NotifyIntr not implemented");
292 break;
293 }
294 case BufferMethods::Unk28: {
295 // TODO(Kmather73): Research and implement this method.
296 LOG_ERROR(HW_GPU, "Special puller engine method Unk28 not implemented");
297 break;
298 }
299 case BufferMethods::SemaphoreAcquire: {
300 ProcessSemaphoreAcquire();
301 break;
302 }
303 case BufferMethods::SemaphoreRelease: {
304 ProcessSemaphoreRelease();
305 break;
306 }
307 case BufferMethods::Yield: {
308 // TODO(Kmather73): Research and implement this method.
309 LOG_ERROR(HW_GPU, "Special puller engine method Yield not implemented");
310 break;
311 }
312 default:
313 LOG_ERROR(HW_GPU, "Special puller engine method {:X} not implemented", method);
314 break;
315 }
316}
317
318void GPU::CallEngineMethod(const MethodCall& method_call) {
319 const EngineID engine = bound_engines[method_call.subchannel];
320
321 switch (engine) {
322 case EngineID::FERMI_TWOD_A:
323 fermi_2d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
324 break;
325 case EngineID::MAXWELL_B:
326 maxwell_3d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
327 break;
328 case EngineID::KEPLER_COMPUTE_B:
329 kepler_compute->CallMethod(method_call.method, method_call.argument,
330 method_call.IsLastCall());
331 break;
332 case EngineID::MAXWELL_DMA_COPY_A:
333 maxwell_dma->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
334 break;
335 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
336 kepler_memory->CallMethod(method_call.method, method_call.argument,
337 method_call.IsLastCall());
338 break;
339 default:
340 UNIMPLEMENTED_MSG("Unimplemented engine");
341 }
342}
343
344void GPU::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
345 u32 methods_pending) {
346 const EngineID engine = bound_engines[subchannel];
347
348 switch (engine) {
349 case EngineID::FERMI_TWOD_A:
350 fermi_2d->CallMultiMethod(method, base_start, amount, methods_pending);
351 break;
352 case EngineID::MAXWELL_B:
353 maxwell_3d->CallMultiMethod(method, base_start, amount, methods_pending);
354 break;
355 case EngineID::KEPLER_COMPUTE_B:
356 kepler_compute->CallMultiMethod(method, base_start, amount, methods_pending);
357 break;
358 case EngineID::MAXWELL_DMA_COPY_A:
359 maxwell_dma->CallMultiMethod(method, base_start, amount, methods_pending);
360 break;
361 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
362 kepler_memory->CallMultiMethod(method, base_start, amount, methods_pending);
363 break;
364 default:
365 UNIMPLEMENTED_MSG("Unimplemented engine");
366 }
367}
368
369void GPU::ProcessBindMethod(const MethodCall& method_call) {
370 // Bind the current subchannel to the desired engine id.
371 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel,
372 method_call.argument);
373 const auto engine_id = static_cast<EngineID>(method_call.argument);
374 bound_engines[method_call.subchannel] = static_cast<EngineID>(engine_id);
375 switch (engine_id) {
376 case EngineID::FERMI_TWOD_A:
377 dma_pusher->BindSubchannel(fermi_2d.get(), method_call.subchannel);
378 break;
379 case EngineID::MAXWELL_B:
380 dma_pusher->BindSubchannel(maxwell_3d.get(), method_call.subchannel);
381 break;
382 case EngineID::KEPLER_COMPUTE_B:
383 dma_pusher->BindSubchannel(kepler_compute.get(), method_call.subchannel);
384 break;
385 case EngineID::MAXWELL_DMA_COPY_A:
386 dma_pusher->BindSubchannel(maxwell_dma.get(), method_call.subchannel);
387 break;
388 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
389 dma_pusher->BindSubchannel(kepler_memory.get(), method_call.subchannel);
390 break;
391 default:
392 UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id);
393 }
394}
395
396void GPU::ProcessFenceActionMethod() {
397 switch (regs.fence_action.op) {
398 case FenceOperation::Acquire:
399 WaitFence(regs.fence_action.syncpoint_id, regs.fence_value);
400 break;
401 case FenceOperation::Increment:
402 IncrementSyncPoint(regs.fence_action.syncpoint_id);
403 break;
404 default:
405 UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value());
406 }
407}
408
409void GPU::ProcessWaitForInterruptMethod() {
410 // TODO(bunnei) ImplementMe
411 LOG_WARNING(HW_GPU, "(STUBBED) called");
412}
413
414void GPU::ProcessSemaphoreTriggerMethod() {
415 const auto semaphoreOperationMask = 0xF;
416 const auto op =
417 static_cast<GpuSemaphoreOperation>(regs.semaphore_trigger & semaphoreOperationMask);
418 if (op == GpuSemaphoreOperation::WriteLong) {
419 struct Block {
420 u32 sequence;
421 u32 zeros = 0;
422 u64 timestamp;
423 };
424 861
425 Block block{}; 862bool GPU::IsAsync() const {
426 block.sequence = regs.semaphore_sequence; 863 return impl->IsAsync();
427 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
428 // CoreTiming
429 block.timestamp = GetTicks();
430 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
431 sizeof(block));
432 } else {
433 const u32 word{memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress())};
434 if ((op == GpuSemaphoreOperation::AcquireEqual && word == regs.semaphore_sequence) ||
435 (op == GpuSemaphoreOperation::AcquireGequal &&
436 static_cast<s32>(word - regs.semaphore_sequence) > 0) ||
437 (op == GpuSemaphoreOperation::AcquireMask && (word & regs.semaphore_sequence))) {
438 // Nothing to do in this case
439 } else {
440 regs.acquire_source = true;
441 regs.acquire_value = regs.semaphore_sequence;
442 if (op == GpuSemaphoreOperation::AcquireEqual) {
443 regs.acquire_active = true;
444 regs.acquire_mode = false;
445 } else if (op == GpuSemaphoreOperation::AcquireGequal) {
446 regs.acquire_active = true;
447 regs.acquire_mode = true;
448 } else if (op == GpuSemaphoreOperation::AcquireMask) {
449 // TODO(kemathe) The acquire mask operation waits for a value that, ANDed with
450 // semaphore_sequence, gives a non-0 result
451 LOG_ERROR(HW_GPU, "Invalid semaphore operation AcquireMask not implemented");
452 } else {
453 LOG_ERROR(HW_GPU, "Invalid semaphore operation");
454 }
455 }
456 }
457} 864}
458 865
459void GPU::ProcessSemaphoreRelease() { 866bool GPU::UseNvdec() const {
460 memory_manager->Write<u32>(regs.semaphore_address.SemaphoreAddress(), regs.semaphore_release); 867 return impl->UseNvdec();
461} 868}
462 869
463void GPU::ProcessSemaphoreAcquire() { 870void GPU::RendererFrameEndNotify() {
464 const u32 word = memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress()); 871 impl->RendererFrameEndNotify();
465 const auto value = regs.semaphore_acquire;
466 if (word != value) {
467 regs.acquire_active = true;
468 regs.acquire_value = value;
469 // TODO(kemathe73) figure out how to do the acquire_timeout
470 regs.acquire_mode = false;
471 regs.acquire_source = false;
472 }
473} 872}
474 873
475void GPU::Start() { 874void GPU::Start() {
476 gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher); 875 impl->Start();
477 cpu_context = renderer->GetRenderWindow().CreateSharedContext();
478 cpu_context->MakeCurrent();
479} 876}
480 877
481void GPU::ObtainContext() { 878void GPU::ObtainContext() {
482 cpu_context->MakeCurrent(); 879 impl->ObtainContext();
483} 880}
484 881
485void GPU::ReleaseContext() { 882void GPU::ReleaseContext() {
486 cpu_context->DoneCurrent(); 883 impl->ReleaseContext();
487} 884}
488 885
489void GPU::PushGPUEntries(Tegra::CommandList&& entries) { 886void GPU::PushGPUEntries(Tegra::CommandList&& entries) {
490 gpu_thread.SubmitList(std::move(entries)); 887 impl->PushGPUEntries(std::move(entries));
491} 888}
492 889
493void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { 890void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) {
494 if (!use_nvdec) { 891 impl->PushCommandBuffer(entries);
495 return;
496 }
497
498 if (!cdma_pusher) {
499 cdma_pusher = std::make_unique<Tegra::CDmaPusher>(*this);
500 }
501
502 // SubmitCommandBuffer would make the nvdec operations async, this is not currently working
503 // TODO(ameerj): RE proper async nvdec operation
504 // gpu_thread.SubmitCommandBuffer(std::move(entries));
505
506 cdma_pusher->ProcessEntries(std::move(entries));
507} 892}
508 893
509void GPU::ClearCdmaInstance() { 894void GPU::ClearCdmaInstance() {
510 cdma_pusher.reset(); 895 impl->ClearCdmaInstance();
511} 896}
512 897
513void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { 898void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
514 gpu_thread.SwapBuffers(framebuffer); 899 impl->SwapBuffers(framebuffer);
515} 900}
516 901
517void GPU::FlushRegion(VAddr addr, u64 size) { 902void GPU::FlushRegion(VAddr addr, u64 size) {
518 gpu_thread.FlushRegion(addr, size); 903 impl->FlushRegion(addr, size);
519} 904}
520 905
521void GPU::InvalidateRegion(VAddr addr, u64 size) { 906void GPU::InvalidateRegion(VAddr addr, u64 size) {
522 gpu_thread.InvalidateRegion(addr, size); 907 impl->InvalidateRegion(addr, size);
523} 908}
524 909
525void GPU::FlushAndInvalidateRegion(VAddr addr, u64 size) { 910void GPU::FlushAndInvalidateRegion(VAddr addr, u64 size) {
526 gpu_thread.FlushAndInvalidateRegion(addr, size); 911 impl->FlushAndInvalidateRegion(addr, size);
527}
528
529void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
530 auto& interrupt_manager = system.InterruptManager();
531 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
532}
533
534void GPU::OnCommandListEnd() {
535 if (is_async) {
536 // This command only applies to asynchronous GPU mode
537 gpu_thread.OnCommandListEnd();
538 }
539} 912}
540 913
541} // namespace Tegra 914} // namespace Tegra
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index e6a02a71b..05e5c94f3 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -4,28 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <atomic>
9#include <condition_variable>
10#include <list>
11#include <memory> 7#include <memory>
12#include <mutex> 8
9#include "common/bit_field.h"
13#include "common/common_types.h" 10#include "common/common_types.h"
14#include "core/hle/service/nvdrv/nvdata.h"
15#include "core/hle/service/nvflinger/buffer_queue.h"
16#include "video_core/cdma_pusher.h" 11#include "video_core/cdma_pusher.h"
17#include "video_core/dma_pusher.h"
18#include "video_core/framebuffer_config.h" 12#include "video_core/framebuffer_config.h"
19#include "video_core/gpu_thread.h"
20
21using CacheAddr = std::uintptr_t;
22[[nodiscard]] inline CacheAddr ToCacheAddr(const void* host_ptr) {
23 return reinterpret_cast<CacheAddr>(host_ptr);
24}
25
26[[nodiscard]] inline u8* FromCacheAddr(CacheAddr cache_addr) {
27 return reinterpret_cast<u8*>(cache_addr);
28}
29 13
30namespace Core { 14namespace Core {
31namespace Frontend { 15namespace Frontend {
@@ -40,6 +24,9 @@ class ShaderNotify;
40} // namespace VideoCore 24} // namespace VideoCore
41 25
42namespace Tegra { 26namespace Tegra {
27class DmaPusher;
28class CDmaPusher;
29struct CommandList;
43 30
44enum class RenderTargetFormat : u32 { 31enum class RenderTargetFormat : u32 {
45 NONE = 0x0, 32 NONE = 0x0,
@@ -138,7 +125,18 @@ public:
138 } 125 }
139 }; 126 };
140 127
141 explicit GPU(Core::System& system_, bool is_async_, bool use_nvdec_); 128 enum class FenceOperation : u32 {
129 Acquire = 0,
130 Increment = 1,
131 };
132
133 union FenceAction {
134 u32 raw;
135 BitField<0, 1, FenceOperation> op;
136 BitField<8, 24, u32> syncpoint_id;
137 };
138
139 explicit GPU(Core::System& system, bool is_async, bool use_nvdec);
142 ~GPU(); 140 ~GPU();
143 141
144 /// Binds a renderer to the GPU. 142 /// Binds a renderer to the GPU.
@@ -162,9 +160,7 @@ public:
162 [[nodiscard]] u64 RequestFlush(VAddr addr, std::size_t size); 160 [[nodiscard]] u64 RequestFlush(VAddr addr, std::size_t size);
163 161
164 /// Obtains current flush request fence id. 162 /// Obtains current flush request fence id.
165 [[nodiscard]] u64 CurrentFlushRequestFence() const { 163 [[nodiscard]] u64 CurrentFlushRequestFence() const;
166 return current_flush_fence.load(std::memory_order_relaxed);
167 }
168 164
169 /// Tick pending requests within the GPU. 165 /// Tick pending requests within the GPU.
170 void TickWork(); 166 void TickWork();
@@ -200,24 +196,16 @@ public:
200 [[nodiscard]] const Tegra::CDmaPusher& CDmaPusher() const; 196 [[nodiscard]] const Tegra::CDmaPusher& CDmaPusher() const;
201 197
202 /// Returns a reference to the underlying renderer. 198 /// Returns a reference to the underlying renderer.
203 [[nodiscard]] VideoCore::RendererBase& Renderer() { 199 [[nodiscard]] VideoCore::RendererBase& Renderer();
204 return *renderer;
205 }
206 200
207 /// Returns a const reference to the underlying renderer. 201 /// Returns a const reference to the underlying renderer.
208 [[nodiscard]] const VideoCore::RendererBase& Renderer() const { 202 [[nodiscard]] const VideoCore::RendererBase& Renderer() const;
209 return *renderer;
210 }
211 203
212 /// Returns a reference to the shader notifier. 204 /// Returns a reference to the shader notifier.
213 [[nodiscard]] VideoCore::ShaderNotify& ShaderNotify() { 205 [[nodiscard]] VideoCore::ShaderNotify& ShaderNotify();
214 return *shader_notify;
215 }
216 206
217 /// Returns a const reference to the shader notifier. 207 /// Returns a const reference to the shader notifier.
218 [[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const { 208 [[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const;
219 return *shader_notify;
220 }
221 209
222 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame. 210 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
223 void WaitFence(u32 syncpoint_id, u32 value); 211 void WaitFence(u32 syncpoint_id, u32 value);
@@ -232,80 +220,12 @@ public:
232 220
233 [[nodiscard]] u64 GetTicks() const; 221 [[nodiscard]] u64 GetTicks() const;
234 222
235 [[nodiscard]] std::unique_lock<std::mutex> LockSync() { 223 [[nodiscard]] bool IsAsync() const;
236 return std::unique_lock{sync_mutex};
237 }
238
239 [[nodiscard]] bool IsAsync() const {
240 return is_async;
241 }
242 224
243 [[nodiscard]] bool UseNvdec() const { 225 [[nodiscard]] bool UseNvdec() const;
244 return use_nvdec;
245 }
246 226
247 void RendererFrameEndNotify(); 227 void RendererFrameEndNotify();
248 228
249 enum class FenceOperation : u32 {
250 Acquire = 0,
251 Increment = 1,
252 };
253
254 union FenceAction {
255 u32 raw;
256 BitField<0, 1, FenceOperation> op;
257 BitField<8, 24, u32> syncpoint_id;
258
259 [[nodiscard]] static CommandHeader Build(FenceOperation op, u32 syncpoint_id) {
260 FenceAction result{};
261 result.op.Assign(op);
262 result.syncpoint_id.Assign(syncpoint_id);
263 return {result.raw};
264 }
265 };
266
267 struct Regs {
268 static constexpr size_t NUM_REGS = 0x40;
269
270 union {
271 struct {
272 INSERT_PADDING_WORDS_NOINIT(0x4);
273 struct {
274 u32 address_high;
275 u32 address_low;
276
277 [[nodiscard]] GPUVAddr SemaphoreAddress() const {
278 return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) |
279 address_low);
280 }
281 } semaphore_address;
282
283 u32 semaphore_sequence;
284 u32 semaphore_trigger;
285 INSERT_PADDING_WORDS_NOINIT(0xC);
286
287 // The pusher and the puller share the reference counter, the pusher only has read
288 // access
289 u32 reference_count;
290 INSERT_PADDING_WORDS_NOINIT(0x5);
291
292 u32 semaphore_acquire;
293 u32 semaphore_release;
294 u32 fence_value;
295 FenceAction fence_action;
296 INSERT_PADDING_WORDS_NOINIT(0xE2);
297
298 // Puller state
299 u32 acquire_mode;
300 u32 acquire_source;
301 u32 acquire_active;
302 u32 acquire_timeout;
303 u32 acquire_value;
304 };
305 std::array<u32, NUM_REGS> reg_array;
306 };
307 } regs{};
308
309 /// Performs any additional setup necessary in order to begin GPU emulation. 229 /// Performs any additional setup necessary in order to begin GPU emulation.
310 /// This can be used to launch any necessary threads and register any necessary 230 /// This can be used to launch any necessary threads and register any necessary
311 /// core timing events. 231 /// core timing events.
@@ -338,104 +258,9 @@ public:
338 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 258 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
339 void FlushAndInvalidateRegion(VAddr addr, u64 size); 259 void FlushAndInvalidateRegion(VAddr addr, u64 size);
340 260
341protected:
342 void TriggerCpuInterrupt(u32 syncpoint_id, u32 value) const;
343
344private: 261private:
345 void ProcessBindMethod(const MethodCall& method_call); 262 struct Impl;
346 void ProcessFenceActionMethod(); 263 std::unique_ptr<Impl> impl;
347 void ProcessWaitForInterruptMethod();
348 void ProcessSemaphoreTriggerMethod();
349 void ProcessSemaphoreRelease();
350 void ProcessSemaphoreAcquire();
351
352 /// Calls a GPU puller method.
353 void CallPullerMethod(const MethodCall& method_call);
354
355 /// Calls a GPU engine method.
356 void CallEngineMethod(const MethodCall& method_call);
357
358 /// Calls a GPU engine multivalue method.
359 void CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
360 u32 methods_pending);
361
362 /// Determines where the method should be executed.
363 [[nodiscard]] bool ExecuteMethodOnEngine(u32 method);
364
365protected:
366 Core::System& system;
367 std::unique_ptr<Tegra::MemoryManager> memory_manager;
368 std::unique_ptr<Tegra::DmaPusher> dma_pusher;
369 std::unique_ptr<Tegra::CDmaPusher> cdma_pusher;
370 std::unique_ptr<VideoCore::RendererBase> renderer;
371 VideoCore::RasterizerInterface* rasterizer = nullptr;
372 const bool use_nvdec;
373
374private:
375 /// Mapping of command subchannels to their bound engine ids
376 std::array<EngineID, 8> bound_engines = {};
377 /// 3D engine
378 std::unique_ptr<Engines::Maxwell3D> maxwell_3d;
379 /// 2D engine
380 std::unique_ptr<Engines::Fermi2D> fermi_2d;
381 /// Compute engine
382 std::unique_ptr<Engines::KeplerCompute> kepler_compute;
383 /// DMA engine
384 std::unique_ptr<Engines::MaxwellDMA> maxwell_dma;
385 /// Inline memory engine
386 std::unique_ptr<Engines::KeplerMemory> kepler_memory;
387 /// Shader build notifier
388 std::unique_ptr<VideoCore::ShaderNotify> shader_notify;
389 /// When true, we are about to shut down emulation session, so terminate outstanding tasks
390 std::atomic_bool shutting_down{};
391
392 std::array<std::atomic<u32>, Service::Nvidia::MaxSyncPoints> syncpoints{};
393
394 std::array<std::list<u32>, Service::Nvidia::MaxSyncPoints> syncpt_interrupts;
395
396 std::mutex sync_mutex;
397 std::mutex device_mutex;
398
399 std::condition_variable sync_cv;
400
401 struct FlushRequest {
402 explicit FlushRequest(u64 fence_, VAddr addr_, std::size_t size_)
403 : fence{fence_}, addr{addr_}, size{size_} {}
404 u64 fence;
405 VAddr addr;
406 std::size_t size;
407 };
408
409 std::list<FlushRequest> flush_requests;
410 std::atomic<u64> current_flush_fence{};
411 u64 last_flush_fence{};
412 std::mutex flush_request_mutex;
413
414 const bool is_async;
415
416 VideoCommon::GPUThread::ThreadManager gpu_thread;
417 std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context;
418}; 264};
419 265
420#define ASSERT_REG_POSITION(field_name, position) \
421 static_assert(offsetof(GPU::Regs, field_name) == position * 4, \
422 "Field " #field_name " has invalid position")
423
424ASSERT_REG_POSITION(semaphore_address, 0x4);
425ASSERT_REG_POSITION(semaphore_sequence, 0x6);
426ASSERT_REG_POSITION(semaphore_trigger, 0x7);
427ASSERT_REG_POSITION(reference_count, 0x14);
428ASSERT_REG_POSITION(semaphore_acquire, 0x1A);
429ASSERT_REG_POSITION(semaphore_release, 0x1B);
430ASSERT_REG_POSITION(fence_value, 0x1C);
431ASSERT_REG_POSITION(fence_action, 0x1D);
432
433ASSERT_REG_POSITION(acquire_mode, 0x100);
434ASSERT_REG_POSITION(acquire_source, 0x101);
435ASSERT_REG_POSITION(acquire_active, 0x102);
436ASSERT_REG_POSITION(acquire_timeout, 0x103);
437ASSERT_REG_POSITION(acquire_value, 0x104);
438
439#undef ASSERT_REG_POSITION
440
441} // namespace Tegra 266} // namespace Tegra
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 91bada925..00984188e 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -130,9 +130,6 @@ public:
130 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 130 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
131 void FlushAndInvalidateRegion(VAddr addr, u64 size); 131 void FlushAndInvalidateRegion(VAddr addr, u64 size);
132 132
133 // Stops the GPU execution and waits for the GPU to finish working
134 void ShutDown();
135
136 void OnCommandListEnd(); 133 void OnCommandListEnd();
137 134
138private: 135private:
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index c9cff7450..20d748c12 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -6,7 +6,6 @@ set(SHADER_FILES
6 convert_float_to_depth.frag 6 convert_float_to_depth.frag
7 full_screen_triangle.vert 7 full_screen_triangle.vert
8 opengl_copy_bc4.comp 8 opengl_copy_bc4.comp
9 opengl_copy_bgra.comp
10 opengl_present.frag 9 opengl_present.frag
11 opengl_present.vert 10 opengl_present.vert
12 pitch_unswizzle.comp 11 pitch_unswizzle.comp
diff --git a/src/video_core/host_shaders/opengl_copy_bgra.comp b/src/video_core/host_shaders/opengl_copy_bgra.comp
deleted file mode 100644
index 2571a4abf..000000000
--- a/src/video_core/host_shaders/opengl_copy_bgra.comp
+++ /dev/null
@@ -1,15 +0,0 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#version 430 core
6
7layout (local_size_x = 4, local_size_y = 4) in;
8
9layout(binding = 0, rgba8) readonly uniform image2DArray bgr_input;
10layout(binding = 1, rgba8) writeonly uniform image2DArray bgr_output;
11
12void main() {
13 vec4 color = imageLoad(bgr_input, ivec3(gl_GlobalInvocationID));
14 imageStore(bgr_output, ivec3(gl_GlobalInvocationID), color.bgra);
15}
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index aac851253..392f82eb7 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -8,6 +8,7 @@
8#include <array> 8#include <array>
9#include <cstring> 9#include <cstring>
10#include <iterator> 10#include <iterator>
11#include <list>
11#include <memory> 12#include <memory>
12#include <mutex> 13#include <mutex>
13#include <optional> 14#include <optional>
@@ -257,9 +258,9 @@ private:
257 258
258 void AsyncFlushQuery(VAddr addr) { 259 void AsyncFlushQuery(VAddr addr) {
259 if (!uncommitted_flushes) { 260 if (!uncommitted_flushes) {
260 uncommitted_flushes = std::make_shared<std::unordered_set<VAddr>>(); 261 uncommitted_flushes = std::make_shared<std::vector<VAddr>>();
261 } 262 }
262 uncommitted_flushes->insert(addr); 263 uncommitted_flushes->push_back(addr);
263 } 264 }
264 265
265 static constexpr std::uintptr_t PAGE_SIZE = 4096; 266 static constexpr std::uintptr_t PAGE_SIZE = 4096;
@@ -275,8 +276,8 @@ private:
275 276
276 std::array<CounterStream, VideoCore::NumQueryTypes> streams; 277 std::array<CounterStream, VideoCore::NumQueryTypes> streams;
277 278
278 std::shared_ptr<std::unordered_set<VAddr>> uncommitted_flushes{}; 279 std::shared_ptr<std::vector<VAddr>> uncommitted_flushes{};
279 std::list<std::shared_ptr<std::unordered_set<VAddr>>> committed_flushes; 280 std::list<std::shared_ptr<std::vector<VAddr>>> committed_flushes;
280}; 281};
281 282
282template <class QueryCache, class HostCounter> 283template <class QueryCache, class HostCounter>
diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h
index ea879bfdd..249644e50 100644
--- a/src/video_core/rasterizer_accelerated.h
+++ b/src/video_core/rasterizer_accelerated.h
@@ -42,7 +42,7 @@ private:
42 }; 42 };
43 static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!"); 43 static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
44 44
45 std::array<CacheEntry, 0x1000000> cached_pages; 45 std::array<CacheEntry, 0x2000000> cached_pages;
46 Core::Memory::Memory& cpu_memory; 46 Core::Memory::Memory& cpu_memory;
47}; 47};
48 48
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index 07a995f7d..187a28e4d 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -147,8 +147,7 @@ void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer,
147 147
148void BufferCacheRuntime::ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value) { 148void BufferCacheRuntime::ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value) {
149 glClearNamedBufferSubData(dest_buffer.Handle(), GL_R32UI, static_cast<GLintptr>(offset), 149 glClearNamedBufferSubData(dest_buffer.Handle(), GL_R32UI, static_cast<GLintptr>(offset),
150 static_cast<GLsizeiptr>(size / sizeof(u32)), GL_RED, GL_UNSIGNED_INT, 150 static_cast<GLsizeiptr>(size), GL_RED, GL_UNSIGNED_INT, &value);
151 &value);
152} 151}
153 152
154void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) { 153void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) {
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 9692b8e94..1e1d1d020 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -10,6 +10,7 @@
10#include <limits> 10#include <limits>
11#include <optional> 11#include <optional>
12#include <span> 12#include <span>
13#include <stdexcept>
13#include <vector> 14#include <vector>
14 15
15#include <glad/glad.h> 16#include <glad/glad.h>
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index b0aee6cc1..8c3ca3d82 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -20,6 +20,7 @@
20#include "video_core/surface.h" 20#include "video_core/surface.h"
21#include "video_core/texture_cache/formatter.h" 21#include "video_core/texture_cache/formatter.h"
22#include "video_core/texture_cache/samples_helper.h" 22#include "video_core/texture_cache/samples_helper.h"
23#include "video_core/texture_cache/util.h"
23 24
24namespace OpenGL { 25namespace OpenGL {
25namespace { 26namespace {
@@ -461,7 +462,7 @@ bool TextureCacheRuntime::CanImageBeCopied(const Image& dst, const Image& src) {
461 if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) { 462 if (dst.info.type == ImageType::e3D && dst.info.format == PixelFormat::BC4_UNORM) {
462 return false; 463 return false;
463 } 464 }
464 if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { 465 if (IsPixelFormatBGR(dst.info.format) != IsPixelFormatBGR(src.info.format)) {
465 return false; 466 return false;
466 } 467 }
467 return true; 468 return true;
@@ -473,7 +474,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src,
473 ASSERT(src.info.type == ImageType::e3D); 474 ASSERT(src.info.type == ImageType::e3D);
474 util_shaders.CopyBC4(dst, src, copies); 475 util_shaders.CopyBC4(dst, src, copies);
475 } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) { 476 } else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) {
476 util_shaders.CopyBGR(dst, src, copies); 477 bgr_copy_pass.CopyBGR(dst, src, copies);
477 } else { 478 } else {
478 UNREACHABLE(); 479 UNREACHABLE();
479 } 480 }
@@ -1112,4 +1113,37 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
1112 framebuffer.handle = handle; 1113 framebuffer.handle = handle;
1113} 1114}
1114 1115
1116void BGRCopyPass::CopyBGR(Image& dst_image, Image& src_image,
1117 std::span<const VideoCommon::ImageCopy> copies) {
1118 static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0};
1119 const u32 requested_pbo_size =
1120 std::max(src_image.unswizzled_size_bytes, dst_image.unswizzled_size_bytes);
1121
1122 if (bgr_pbo_size < requested_pbo_size) {
1123 bgr_pbo.Create();
1124 bgr_pbo_size = requested_pbo_size;
1125 glNamedBufferData(bgr_pbo.handle, bgr_pbo_size, nullptr, GL_STREAM_COPY);
1126 }
1127 for (const ImageCopy& copy : copies) {
1128 ASSERT(copy.src_offset == zero_offset);
1129 ASSERT(copy.dst_offset == zero_offset);
1130
1131 // Copy from source to PBO
1132 glPixelStorei(GL_PACK_ALIGNMENT, 1);
1133 glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width);
1134 glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr_pbo.handle);
1135 glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height,
1136 copy.src_subresource.num_layers, src_image.GlFormat(),
1137 src_image.GlType(), static_cast<GLsizei>(bgr_pbo_size), nullptr);
1138
1139 // Copy from PBO to destination in desired GL format
1140 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1141 glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width);
1142 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bgr_pbo.handle);
1143 glTextureSubImage3D(dst_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height,
1144 copy.dst_subresource.num_layers, dst_image.GlFormat(),
1145 dst_image.GlType(), nullptr);
1146 }
1147}
1148
1115} // namespace OpenGL 1149} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 4a4f6301c..1ca2c90be 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -12,6 +12,7 @@
12#include "shader_recompiler/shader_info.h" 12#include "shader_recompiler/shader_info.h"
13#include "video_core/renderer_opengl/gl_resource_manager.h" 13#include "video_core/renderer_opengl/gl_resource_manager.h"
14#include "video_core/renderer_opengl/util_shaders.h" 14#include "video_core/renderer_opengl/util_shaders.h"
15#include "video_core/texture_cache/image_view_base.h"
15#include "video_core/texture_cache/texture_cache_base.h" 16#include "video_core/texture_cache/texture_cache_base.h"
16 17
17namespace OpenGL { 18namespace OpenGL {
@@ -47,6 +48,19 @@ struct FormatProperties {
47 bool is_compressed; 48 bool is_compressed;
48}; 49};
49 50
51class BGRCopyPass {
52public:
53 BGRCopyPass() = default;
54 ~BGRCopyPass() = default;
55
56 void CopyBGR(Image& dst_image, Image& src_image,
57 std::span<const VideoCommon::ImageCopy> copies);
58
59private:
60 OGLBuffer bgr_pbo;
61 size_t bgr_pbo_size{};
62};
63
50class TextureCacheRuntime { 64class TextureCacheRuntime {
51 friend Framebuffer; 65 friend Framebuffer;
52 friend Image; 66 friend Image;
@@ -118,6 +132,7 @@ private:
118 const Device& device; 132 const Device& device;
119 StateTracker& state_tracker; 133 StateTracker& state_tracker;
120 UtilShaders util_shaders; 134 UtilShaders util_shaders;
135 BGRCopyPass bgr_copy_pass;
121 136
122 std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties; 137 std::array<std::unordered_map<GLenum, FormatProperties>, 3> format_properties;
123 bool has_broken_texture_view_formats = false; 138 bool has_broken_texture_view_formats = false;
@@ -162,6 +177,14 @@ public:
162 return texture.handle; 177 return texture.handle;
163 } 178 }
164 179
180 GLuint GlFormat() const noexcept {
181 return gl_format;
182 }
183
184 GLuint GlType() const noexcept {
185 return gl_type;
186 }
187
165private: 188private:
166 void CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset); 189 void CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset);
167 190
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 672f94bfc..39158aa3e 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -52,7 +52,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
52 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT 52 {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT}, // BC6H_UFLOAT
53 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT 53 {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT}, // BC6H_SFLOAT
54 {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM 54 {GL_COMPRESSED_RGBA_ASTC_4x4_KHR}, // ASTC_2D_4X4_UNORM
55 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // B8G8R8A8_UNORM 55 {GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, // B8G8R8A8_UNORM
56 {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT 56 {GL_RGBA32F, GL_RGBA, GL_FLOAT}, // R32G32B32A32_FLOAT
57 {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT 57 {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT}, // R32G32B32A32_SINT
58 {GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT 58 {GL_RG32F, GL_RG, GL_FLOAT}, // R32G32_FLOAT
@@ -81,7 +81,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
81 {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM 81 {GL_COMPRESSED_RGBA_ASTC_8x8_KHR}, // ASTC_2D_8X8_UNORM
82 {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM 82 {GL_COMPRESSED_RGBA_ASTC_8x5_KHR}, // ASTC_2D_8X5_UNORM
83 {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM 83 {GL_COMPRESSED_RGBA_ASTC_5x4_KHR}, // ASTC_2D_5X4_UNORM
84 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE}, // B8G8R8A8_SRGB 84 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, // B8G8R8A8_SRGB
85 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB 85 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT}, // BC1_RGBA_SRGB
86 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB 86 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT}, // BC2_SRGB
87 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB 87 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}, // BC3_SRGB
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp
index 333f35a1c..897c380b3 100644
--- a/src/video_core/renderer_opengl/util_shaders.cpp
+++ b/src/video_core/renderer_opengl/util_shaders.cpp
@@ -14,7 +14,6 @@
14#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" 14#include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h"
15#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" 15#include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h"
16#include "video_core/host_shaders/opengl_copy_bc4_comp.h" 16#include "video_core/host_shaders/opengl_copy_bc4_comp.h"
17#include "video_core/host_shaders/opengl_copy_bgra_comp.h"
18#include "video_core/host_shaders/pitch_unswizzle_comp.h" 17#include "video_core/host_shaders/pitch_unswizzle_comp.h"
19#include "video_core/renderer_opengl/gl_shader_manager.h" 18#include "video_core/renderer_opengl/gl_shader_manager.h"
20#include "video_core/renderer_opengl/gl_shader_util.h" 19#include "video_core/renderer_opengl/gl_shader_util.h"
@@ -44,11 +43,6 @@ namespace {
44OGLProgram MakeProgram(std::string_view source) { 43OGLProgram MakeProgram(std::string_view source) {
45 return CreateProgram(source, GL_COMPUTE_SHADER); 44 return CreateProgram(source, GL_COMPUTE_SHADER);
46} 45}
47
48size_t NumPixelsInCopy(const VideoCommon::ImageCopy& copy) {
49 return static_cast<size_t>(copy.extent.width * copy.extent.height *
50 copy.src_subresource.num_layers);
51}
52} // Anonymous namespace 46} // Anonymous namespace
53 47
54UtilShaders::UtilShaders(ProgramManager& program_manager_) 48UtilShaders::UtilShaders(ProgramManager& program_manager_)
@@ -56,7 +50,6 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
56 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), 50 block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)),
57 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), 51 block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)),
58 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), 52 pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)),
59 copy_bgra_program(MakeProgram(OPENGL_COPY_BGRA_COMP)),
60 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { 53 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) {
61 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); 54 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
62 swizzle_table_buffer.Create(); 55 swizzle_table_buffer.Create();
@@ -255,43 +248,6 @@ void UtilShaders::CopyBC4(Image& dst_image, Image& src_image, std::span<const Im
255 program_manager.RestoreGuestCompute(); 248 program_manager.RestoreGuestCompute();
256} 249}
257 250
258void UtilShaders::CopyBGR(Image& dst_image, Image& src_image,
259 std::span<const VideoCommon::ImageCopy> copies) {
260 static constexpr GLuint BINDING_INPUT_IMAGE = 0;
261 static constexpr GLuint BINDING_OUTPUT_IMAGE = 1;
262 static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0};
263 const u32 bytes_per_block = BytesPerBlock(dst_image.info.format);
264 switch (bytes_per_block) {
265 case 2:
266 // BGR565 copy
267 for (const ImageCopy& copy : copies) {
268 ASSERT(copy.src_offset == zero_offset);
269 ASSERT(copy.dst_offset == zero_offset);
270 bgr_copy_pass.Execute(dst_image, src_image, copy);
271 }
272 break;
273 case 4: {
274 // BGRA8 copy
275 program_manager.BindComputeProgram(copy_bgra_program.handle);
276 constexpr GLenum FORMAT = GL_RGBA8;
277 for (const ImageCopy& copy : copies) {
278 ASSERT(copy.src_offset == zero_offset);
279 ASSERT(copy.dst_offset == zero_offset);
280 glBindImageTexture(BINDING_INPUT_IMAGE, src_image.StorageHandle(),
281 copy.src_subresource.base_level, GL_FALSE, 0, GL_READ_ONLY, FORMAT);
282 glBindImageTexture(BINDING_OUTPUT_IMAGE, dst_image.StorageHandle(),
283 copy.dst_subresource.base_level, GL_FALSE, 0, GL_WRITE_ONLY, FORMAT);
284 glDispatchCompute(copy.extent.width, copy.extent.height, copy.extent.depth);
285 }
286 program_manager.RestoreGuestCompute();
287 break;
288 }
289 default:
290 UNREACHABLE();
291 break;
292 }
293}
294
295GLenum StoreFormat(u32 bytes_per_block) { 251GLenum StoreFormat(u32 bytes_per_block) {
296 switch (bytes_per_block) { 252 switch (bytes_per_block) {
297 case 1: 253 case 1:
@@ -309,36 +265,4 @@ GLenum StoreFormat(u32 bytes_per_block) {
309 return GL_R8UI; 265 return GL_R8UI;
310} 266}
311 267
312void Bgr565CopyPass::Execute(const Image& dst_image, const Image& src_image,
313 const ImageCopy& copy) {
314 if (CopyBufferCreationNeeded(copy)) {
315 CreateNewCopyBuffer(copy, GL_TEXTURE_2D_ARRAY, GL_RGB565);
316 }
317 // Copy from source to PBO
318 glPixelStorei(GL_PACK_ALIGNMENT, 1);
319 glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width);
320 glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr16_pbo.handle);
321 glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height,
322 copy.src_subresource.num_layers, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
323 static_cast<GLsizei>(bgr16_pbo_size), nullptr);
324
325 // Copy from PBO to destination in reverse order
326 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
327 glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width);
328 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bgr16_pbo.handle);
329 glTextureSubImage3D(dst_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height,
330 copy.dst_subresource.num_layers, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV,
331 nullptr);
332}
333
334bool Bgr565CopyPass::CopyBufferCreationNeeded(const ImageCopy& copy) {
335 return bgr16_pbo_size < NumPixelsInCopy(copy) * sizeof(u16);
336}
337
338void Bgr565CopyPass::CreateNewCopyBuffer(const ImageCopy& copy, GLenum target, GLuint format) {
339 bgr16_pbo.Create();
340 bgr16_pbo_size = NumPixelsInCopy(copy) * sizeof(u16);
341 glNamedBufferData(bgr16_pbo.handle, bgr16_pbo_size, nullptr, GL_STREAM_COPY);
342}
343
344} // namespace OpenGL 268} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h
index ef881e35f..5de95ea7a 100644
--- a/src/video_core/renderer_opengl/util_shaders.h
+++ b/src/video_core/renderer_opengl/util_shaders.h
@@ -19,22 +19,6 @@ class ProgramManager;
19 19
20struct ImageBufferMap; 20struct ImageBufferMap;
21 21
22class Bgr565CopyPass {
23public:
24 Bgr565CopyPass() = default;
25 ~Bgr565CopyPass() = default;
26
27 void Execute(const Image& dst_image, const Image& src_image,
28 const VideoCommon::ImageCopy& copy);
29
30private:
31 [[nodiscard]] bool CopyBufferCreationNeeded(const VideoCommon::ImageCopy& copy);
32 void CreateNewCopyBuffer(const VideoCommon::ImageCopy& copy, GLenum target, GLuint format);
33
34 OGLBuffer bgr16_pbo;
35 size_t bgr16_pbo_size{};
36};
37
38class UtilShaders { 22class UtilShaders {
39public: 23public:
40 explicit UtilShaders(ProgramManager& program_manager); 24 explicit UtilShaders(ProgramManager& program_manager);
@@ -55,9 +39,6 @@ public:
55 void CopyBC4(Image& dst_image, Image& src_image, 39 void CopyBC4(Image& dst_image, Image& src_image,
56 std::span<const VideoCommon::ImageCopy> copies); 40 std::span<const VideoCommon::ImageCopy> copies);
57 41
58 void CopyBGR(Image& dst_image, Image& src_image,
59 std::span<const VideoCommon::ImageCopy> copies);
60
61private: 42private:
62 ProgramManager& program_manager; 43 ProgramManager& program_manager;
63 44
@@ -67,10 +48,7 @@ private:
67 OGLProgram block_linear_unswizzle_2d_program; 48 OGLProgram block_linear_unswizzle_2d_program;
68 OGLProgram block_linear_unswizzle_3d_program; 49 OGLProgram block_linear_unswizzle_3d_program;
69 OGLProgram pitch_unswizzle_program; 50 OGLProgram pitch_unswizzle_program;
70 OGLProgram copy_bgra_program;
71 OGLProgram copy_bc4_program; 51 OGLProgram copy_bc4_program;
72
73 Bgr565CopyPass bgr_copy_pass;
74}; 52};
75 53
76GLenum StoreFormat(u32 bytes_per_block); 54GLenum StoreFormat(u32 bytes_per_block);
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index adb6b7a3b..74822814d 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -97,19 +97,14 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
97 Core::Frontend::EmuWindow& emu_window, 97 Core::Frontend::EmuWindow& emu_window,
98 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, 98 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
99 std::unique_ptr<Core::Frontend::GraphicsContext> context_) try 99 std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
100 : RendererBase(emu_window, std::move(context_)), 100 : RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_),
101 telemetry_session(telemetry_session_), 101 cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary()),
102 cpu_memory(cpu_memory_),
103 gpu(gpu_),
104 library(OpenLibrary()),
105 instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, 102 instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
106 true, Settings::values.renderer_debug.GetValue())), 103 true, Settings::values.renderer_debug.GetValue())),
107 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 104 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
108 surface(CreateSurface(instance, render_window)), 105 surface(CreateSurface(instance, render_window)),
109 device(CreateDevice(instance, dld, *surface)), 106 device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false),
110 memory_allocator(device, false), 107 state_tracker(gpu), scheduler(device, state_tracker),
111 state_tracker(gpu),
112 scheduler(device, state_tracker),
113 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, 108 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
114 render_window.GetFramebufferLayout().height, false), 109 render_window.GetFramebufferLayout().height, false),
115 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler, 110 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler,
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 7c0f91007..8634c3316 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -507,8 +507,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
507 vertex_attributes.push_back({ 507 vertex_attributes.push_back({
508 .location = static_cast<u32>(index), 508 .location = static_cast<u32>(index),
509 .binding = 0, 509 .binding = 0,
510 .format = type == 1 ? VK_FORMAT_R32_SFLOAT 510 .format = type == 1 ? VK_FORMAT_R32_SFLOAT
511 : type == 2 ? VK_FORMAT_R32_SINT : VK_FORMAT_R32_UINT, 511 : type == 2 ? VK_FORMAT_R32_SINT
512 : VK_FORMAT_R32_UINT,
512 .offset = 0, 513 .offset = 0,
513 }); 514 });
514 } 515 }
@@ -567,12 +568,21 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
567 if (!vertex_binding_divisors.empty()) { 568 if (!vertex_binding_divisors.empty()) {
568 vertex_input_ci.pNext = &input_divisor_ci; 569 vertex_input_ci.pNext = &input_divisor_ci;
569 } 570 }
571 const bool has_tess_stages = spv_modules[1] || spv_modules[2];
570 auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, key.state.topology); 572 auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, key.state.topology);
571 if (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { 573 if (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
572 if (!spv_modules[1] && !spv_modules[2]) { 574 if (!has_tess_stages) {
573 LOG_WARNING(Render_Vulkan, "Patch topology used without tessellation, using points"); 575 LOG_WARNING(Render_Vulkan, "Patch topology used without tessellation, using points");
574 input_assembly_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; 576 input_assembly_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
575 } 577 }
578 } else {
579 if (has_tess_stages) {
580 // The Vulkan spec requires patch list IA topology be used with tessellation
581 // shader stages. Forcing it fixes a crash on some drivers
582 LOG_WARNING(Render_Vulkan,
583 "Patch topology not used with tessellation, using patch list");
584 input_assembly_topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
585 }
576 } 586 }
577 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ 587 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
578 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 588 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
index 4f8688118..0886b7da8 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.h
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -21,12 +21,12 @@ public:
21 21
22 /// Returns the current logical tick. 22 /// Returns the current logical tick.
23 [[nodiscard]] u64 CurrentTick() const noexcept { 23 [[nodiscard]] u64 CurrentTick() const noexcept {
24 return current_tick.load(std::memory_order_relaxed); 24 return current_tick.load(std::memory_order_acquire);
25 } 25 }
26 26
27 /// Returns the last known GPU tick. 27 /// Returns the last known GPU tick.
28 [[nodiscard]] u64 KnownGpuTick() const noexcept { 28 [[nodiscard]] u64 KnownGpuTick() const noexcept {
29 return gpu_tick.load(std::memory_order_relaxed); 29 return gpu_tick.load(std::memory_order_acquire);
30 } 30 }
31 31
32 /// Returns the timeline semaphore handle. 32 /// Returns the timeline semaphore handle.
@@ -41,12 +41,21 @@ public:
41 41
42 /// Advance to the logical tick and return the old one 42 /// Advance to the logical tick and return the old one
43 [[nodiscard]] u64 NextTick() noexcept { 43 [[nodiscard]] u64 NextTick() noexcept {
44 return current_tick.fetch_add(1, std::memory_order::relaxed); 44 return current_tick.fetch_add(1, std::memory_order_release);
45 } 45 }
46 46
47 /// Refresh the known GPU tick 47 /// Refresh the known GPU tick
48 void Refresh() { 48 void Refresh() {
49 gpu_tick.store(semaphore.GetCounter(), std::memory_order_relaxed); 49 u64 this_tick{};
50 u64 counter{};
51 do {
52 this_tick = gpu_tick.load(std::memory_order_acquire);
53 counter = semaphore.GetCounter();
54 if (counter < this_tick) {
55 return;
56 }
57 } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release,
58 std::memory_order_relaxed));
50 } 59 }
51 60
52 /// Waits for a tick to be hit on the GPU 61 /// Waits for a tick to be hit on the GPU
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index c9cb32d71..259cba156 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -117,7 +117,8 @@ u64 HostCounter::BlockingQuery() const {
117 cache.GetScheduler().Wait(tick); 117 cache.GetScheduler().Wait(tick);
118 u64 data; 118 u64 data;
119 const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults( 119 const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults(
120 query.first, query.second, 1, sizeof(data), &data, sizeof(data), VK_QUERY_RESULT_64_BIT); 120 query.first, query.second, 1, sizeof(data), &data, sizeof(data),
121 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
121 122
122 switch (query_result) { 123 switch (query_result) {
123 case VK_SUCCESS: 124 case VK_SUCCESS:
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index bd22e4e83..85fc1712f 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -212,7 +212,6 @@ private:
212 vk::CommandBuffer current_cmdbuf; 212 vk::CommandBuffer current_cmdbuf;
213 213
214 std::unique_ptr<CommandChunk> chunk; 214 std::unique_ptr<CommandChunk> chunk;
215 std::jthread worker_thread;
216 215
217 State state; 216 State state;
218 217
@@ -226,6 +225,7 @@ private:
226 std::mutex work_mutex; 225 std::mutex work_mutex;
227 std::condition_variable_any work_cv; 226 std::condition_variable_any work_cv;
228 std::condition_variable wait_cv; 227 std::condition_variable wait_cv;
228 std::jthread worker_thread;
229}; 229};
230 230
231} // namespace Vulkan 231} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index ff979a7ac..06c5fb867 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -21,6 +21,7 @@
21#include "video_core/renderer_vulkan/vk_texture_cache.h" 21#include "video_core/renderer_vulkan/vk_texture_cache.h"
22#include "video_core/texture_cache/formatter.h" 22#include "video_core/texture_cache/formatter.h"
23#include "video_core/texture_cache/samples_helper.h" 23#include "video_core/texture_cache/samples_helper.h"
24#include "video_core/texture_cache/util.h"
24#include "video_core/vulkan_common/vulkan_device.h" 25#include "video_core/vulkan_common/vulkan_device.h"
25#include "video_core/vulkan_common/vulkan_memory_allocator.h" 26#include "video_core/vulkan_common/vulkan_memory_allocator.h"
26#include "video_core/vulkan_common/vulkan_wrapper.h" 27#include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -127,7 +128,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
127 const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format); 128 const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format);
128 VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; 129 VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
129 if (info.type == ImageType::e2D && info.resources.layers >= 6 && 130 if (info.type == ImageType::e2D && info.resources.layers >= 6 &&
130 info.size.width == info.size.height) { 131 info.size.width == info.size.height && !device.HasBrokenCubeImageCompability()) {
131 flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 132 flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
132 } 133 }
133 if (info.type == ImageType::e3D) { 134 if (info.type == ImageType::e3D) {
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 6d5a68bfe..b09c468e4 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -4,11 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <compare>
8#include <span> 7#include <span>
9 8
10#include "shader_recompiler/shader_info.h" 9#include "shader_recompiler/shader_info.h"
11#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 10#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
11#include "video_core/texture_cache/image_view_base.h"
12#include "video_core/texture_cache/texture_cache_base.h" 12#include "video_core/texture_cache/texture_cache_base.h"
13#include "video_core/vulkan_common/vulkan_memory_allocator.h" 13#include "video_core/vulkan_common/vulkan_memory_allocator.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 81a878bb2..05850afd0 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -16,6 +16,7 @@
16#include "common/fs/fs.h" 16#include "common/fs/fs.h"
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18#include "shader_recompiler/environment.h" 18#include "shader_recompiler/environment.h"
19#include "video_core/engines/kepler_compute.h"
19#include "video_core/memory_manager.h" 20#include "video_core/memory_manager.h"
20#include "video_core/shader_environment.h" 21#include "video_core/shader_environment.h"
21#include "video_core/textures/texture.h" 22#include "video_core/textures/texture.h"
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h
index 2079979db..6640e53d0 100644
--- a/src/video_core/shader_environment.h
+++ b/src/video_core/shader_environment.h
@@ -5,13 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
9#include <filesystem> 8#include <filesystem>
10#include <iosfwd> 9#include <iosfwd>
11#include <limits> 10#include <limits>
12#include <memory> 11#include <memory>
13#include <optional> 12#include <optional>
14#include <span> 13#include <span>
14#include <stop_token>
15#include <type_traits> 15#include <type_traits>
16#include <unordered_map> 16#include <unordered_map>
17#include <vector> 17#include <vector>
@@ -19,9 +19,7 @@
19#include "common/common_types.h" 19#include "common/common_types.h"
20#include "common/unique_function.h" 20#include "common/unique_function.h"
21#include "shader_recompiler/environment.h" 21#include "shader_recompiler/environment.h"
22#include "video_core/engines/kepler_compute.h"
23#include "video_core/engines/maxwell_3d.h" 22#include "video_core/engines/maxwell_3d.h"
24#include "video_core/textures/texture.h"
25 23
26namespace Tegra { 24namespace Tegra {
27class Memorymanager; 25class Memorymanager;
diff --git a/src/video_core/texture_cache/image_view_info.cpp b/src/video_core/texture_cache/image_view_info.cpp
index 6527e14c8..e751f26c7 100644
--- a/src/video_core/texture_cache/image_view_info.cpp
+++ b/src/video_core/texture_cache/image_view_info.cpp
@@ -8,6 +8,7 @@
8#include "video_core/texture_cache/image_view_info.h" 8#include "video_core/texture_cache/image_view_info.h"
9#include "video_core/texture_cache/texture_cache_base.h" 9#include "video_core/texture_cache/texture_cache_base.h"
10#include "video_core/texture_cache/types.h" 10#include "video_core/texture_cache/types.h"
11#include "video_core/texture_cache/util.h"
11#include "video_core/textures/texture.h" 12#include "video_core/textures/texture.h"
12 13
13namespace VideoCommon { 14namespace VideoCommon {
diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h
index 74cd3c9d8..50df06409 100644
--- a/src/video_core/texture_cache/slot_vector.h
+++ b/src/video_core/texture_cache/slot_vector.h
@@ -31,8 +31,8 @@ struct SlotId {
31}; 31};
32 32
33template <class T> 33template <class T>
34requires std::is_nothrow_move_assignable_v<T>&& 34requires std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<T>
35 std::is_nothrow_move_constructible_v<T> class SlotVector { 35class SlotVector {
36public: 36public:
37 class Iterator { 37 class Iterator {
38 friend SlotVector<T>; 38 friend SlotVector<T>;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index c6e50bb5f..f70c1f764 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -4,10 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <unordered_set>
8
7#include "common/alignment.h" 9#include "common/alignment.h"
8#include "video_core/dirty_flags.h" 10#include "video_core/dirty_flags.h"
11#include "video_core/engines/kepler_compute.h"
12#include "video_core/texture_cache/image_view_base.h"
9#include "video_core/texture_cache/samples_helper.h" 13#include "video_core/texture_cache/samples_helper.h"
10#include "video_core/texture_cache/texture_cache_base.h" 14#include "video_core/texture_cache/texture_cache_base.h"
15#include "video_core/texture_cache/util.h"
11 16
12namespace VideoCommon { 17namespace VideoCommon {
13 18
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index d7528ed24..2d1893c1c 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -4,13 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <mutex> 7#include <mutex>
9#include <span> 8#include <span>
10#include <type_traits> 9#include <type_traits>
11#include <unordered_map> 10#include <unordered_map>
12#include <unordered_set>
13#include <vector> 11#include <vector>
12#include <queue>
14 13
15#include "common/common_types.h" 14#include "common/common_types.h"
16#include "common/literals.h" 15#include "common/literals.h"
@@ -18,10 +17,6 @@
18#include "video_core/compatible_formats.h" 17#include "video_core/compatible_formats.h"
19#include "video_core/delayed_destruction_ring.h" 18#include "video_core/delayed_destruction_ring.h"
20#include "video_core/engines/fermi_2d.h" 19#include "video_core/engines/fermi_2d.h"
21#include "video_core/engines/kepler_compute.h"
22#include "video_core/engines/maxwell_3d.h"
23#include "video_core/memory_manager.h"
24#include "video_core/rasterizer_interface.h"
25#include "video_core/surface.h" 20#include "video_core/surface.h"
26#include "video_core/texture_cache/descriptor_table.h" 21#include "video_core/texture_cache/descriptor_table.h"
27#include "video_core/texture_cache/image_base.h" 22#include "video_core/texture_cache/image_base.h"
@@ -30,7 +25,6 @@
30#include "video_core/texture_cache/render_targets.h" 25#include "video_core/texture_cache/render_targets.h"
31#include "video_core/texture_cache/slot_vector.h" 26#include "video_core/texture_cache/slot_vector.h"
32#include "video_core/texture_cache/types.h" 27#include "video_core/texture_cache/types.h"
33#include "video_core/texture_cache/util.h"
34#include "video_core/textures/texture.h" 28#include "video_core/textures/texture.h"
35 29
36namespace VideoCommon { 30namespace VideoCommon {
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 3a048900b..0f807990c 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -588,22 +588,27 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
588 ext_extended_dynamic_state = false; 588 ext_extended_dynamic_state = false;
589 } 589 }
590 } 590 }
591
592 sets_per_pool = 64; 591 sets_per_pool = 64;
593 if (driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE) { 592
593 const bool is_amd =
594 driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
595 if (is_amd) {
594 // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2. 596 // AMD drivers need a higher amount of Sets per Pool in certain circunstances like in XC2.
595 sets_per_pool = 96; 597 sets_per_pool = 96;
596 } 598 // Disable VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT on AMD GCN4 and lower as it is broken.
597
598 const bool is_amd = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY ||
599 driver_id == VK_DRIVER_ID_MESA_RADV ||
600 driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
601 if (ext_sampler_filter_minmax && is_amd) {
602 // Disable ext_sampler_filter_minmax on AMD GCN4 and lower as it is broken.
603 if (!is_float16_supported) { 599 if (!is_float16_supported) {
604 LOG_WARNING( 600 LOG_WARNING(
605 Render_Vulkan, 601 Render_Vulkan,
606 "Blacklisting AMD GCN4 and lower for VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME"); 602 "AMD GCN4 and earlier do not properly support VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT");
603 has_broken_cube_compatibility = true;
604 }
605 }
606 const bool is_amd_or_radv = is_amd || driver_id == VK_DRIVER_ID_MESA_RADV;
607 if (ext_sampler_filter_minmax && is_amd_or_radv) {
608 // Disable ext_sampler_filter_minmax on AMD GCN4 and lower as it is broken.
609 if (!is_float16_supported) {
610 LOG_WARNING(Render_Vulkan,
611 "Blacklisting AMD GCN4 and earlier for VK_EXT_sampler_filter_minmax");
607 ext_sampler_filter_minmax = false; 612 ext_sampler_filter_minmax = false;
608 } 613 }
609 } 614 }
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index f14e4001e..2d5daf6cd 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -309,6 +309,11 @@ public:
309 return has_renderdoc || has_nsight_graphics; 309 return has_renderdoc || has_nsight_graphics;
310 } 310 }
311 311
312 /// Returns true when the device does not properly support cube compatibility.
313 bool HasBrokenCubeImageCompability() const {
314 return has_broken_cube_compatibility;
315 }
316
312 /// Returns the vendor name reported from Vulkan. 317 /// Returns the vendor name reported from Vulkan.
313 std::string_view GetVendorName() const { 318 std::string_view GetVendorName() const {
314 return vendor_name; 319 return vendor_name;
@@ -421,6 +426,7 @@ private:
421 bool ext_conservative_rasterization{}; ///< Support for VK_EXT_conservative_rasterization. 426 bool ext_conservative_rasterization{}; ///< Support for VK_EXT_conservative_rasterization.
422 bool ext_provoking_vertex{}; ///< Support for VK_EXT_provoking_vertex. 427 bool ext_provoking_vertex{}; ///< Support for VK_EXT_provoking_vertex.
423 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. 428 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
429 bool has_broken_cube_compatibility{}; ///< Has broken cube compatiblity bit
424 bool has_renderdoc{}; ///< Has RenderDoc attached 430 bool has_renderdoc{}; ///< Has RenderDoc attached
425 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached 431 bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
426 bool supports_d24_depth{}; ///< Supports D24 depth buffers. 432 bool supports_d24_depth{}; ///< Supports D24 depth buffers.
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index b6dda283d..402be6a78 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -290,10 +290,6 @@ if (YUZU_USE_QT_WEB_ENGINE)
290 target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) 290 target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
291endif () 291endif ()
292 292
293if (YUZU_ENABLE_BOXCAT)
294 target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_BOXCAT)
295endif ()
296
297if(UNIX AND NOT APPLE) 293if(UNIX AND NOT APPLE)
298 install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 294 install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
299endif() 295endif()
diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp
index 6b0155a78..04ab4ae21 100644
--- a/src/yuzu/about_dialog.cpp
+++ b/src/yuzu/about_dialog.cpp
@@ -8,7 +8,8 @@
8#include "ui_aboutdialog.h" 8#include "ui_aboutdialog.h"
9#include "yuzu/about_dialog.h" 9#include "yuzu/about_dialog.h"
10 10
11AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { 11AboutDialog::AboutDialog(QWidget* parent)
12 : QDialog(parent), ui{std::make_unique<Ui::AboutDialog>()} {
12 const auto branch_name = std::string(Common::g_scm_branch); 13 const auto branch_name = std::string(Common::g_scm_branch);
13 const auto description = std::string(Common::g_scm_desc); 14 const auto description = std::string(Common::g_scm_desc);
14 const auto build_id = std::string(Common::g_build_id); 15 const auto build_id = std::string(Common::g_build_id);
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 97106d2cc..bf8445a89 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -37,17 +37,14 @@ constexpr std::array<std::array<bool, 4>, 8> led_patterns{{
37}}; 37}};
38 38
39void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, 39void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
40 bool connected) { 40 bool connected, Core::System& system) {
41 Core::System& system{Core::System::GetInstance()};
42
43 if (!system.IsPoweredOn()) { 41 if (!system.IsPoweredOn()) {
44 return; 42 return;
45 } 43 }
46 44
47 Service::SM::ServiceManager& sm = system.ServiceManager();
48
49 auto& npad = 45 auto& npad =
50 sm.GetService<Service::HID::Hid>("hid") 46 system.ServiceManager()
47 .GetService<Service::HID::Hid>("hid")
51 ->GetAppletResource() 48 ->GetAppletResource()
52 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); 49 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
53 50
@@ -79,10 +76,10 @@ bool IsControllerCompatible(Settings::ControllerType controller_type,
79 76
80QtControllerSelectorDialog::QtControllerSelectorDialog( 77QtControllerSelectorDialog::QtControllerSelectorDialog(
81 QWidget* parent, Core::Frontend::ControllerParameters parameters_, 78 QWidget* parent, Core::Frontend::ControllerParameters parameters_,
82 InputCommon::InputSubsystem* input_subsystem_) 79 InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
83 : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()), 80 : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
84 parameters(std::move(parameters_)), input_subsystem{input_subsystem_}, 81 parameters(std::move(parameters_)), input_subsystem{input_subsystem_},
85 input_profiles(std::make_unique<InputProfiles>()) { 82 input_profiles(std::make_unique<InputProfiles>(system_)), system{system_} {
86 ui->setupUi(this); 83 ui->setupUi(this);
87 84
88 player_widgets = { 85 player_widgets = {
@@ -245,7 +242,7 @@ int QtControllerSelectorDialog::exec() {
245void QtControllerSelectorDialog::ApplyConfiguration() { 242void QtControllerSelectorDialog::ApplyConfiguration() {
246 const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); 243 const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
247 Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked()); 244 Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
248 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue()); 245 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system);
249 246
250 Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); 247 Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
251 Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); 248 Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
@@ -293,7 +290,7 @@ void QtControllerSelectorDialog::CallConfigureMotionTouchDialog() {
293} 290}
294 291
295void QtControllerSelectorDialog::CallConfigureInputProfileDialog() { 292void QtControllerSelectorDialog::CallConfigureInputProfileDialog() {
296 ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get()); 293 ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get(), system);
297 294
298 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 295 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
299 Qt::WindowSystemMenuHint); 296 Qt::WindowSystemMenuHint);
@@ -533,7 +530,7 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index)
533 } 530 }
534 531
535 // Disconnect the controller first. 532 // Disconnect the controller first.
536 UpdateController(controller_type, player_index, false); 533 UpdateController(controller_type, player_index, false, system);
537 534
538 player.controller_type = controller_type; 535 player.controller_type = controller_type;
539 player.connected = player_connected; 536 player.connected = player_connected;
@@ -548,7 +545,7 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index)
548 } 545 }
549 handheld.connected = player_groupboxes[player_index]->isChecked() && 546 handheld.connected = player_groupboxes[player_index]->isChecked() &&
550 controller_type == Settings::ControllerType::Handheld; 547 controller_type == Settings::ControllerType::Handheld;
551 UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected); 548 UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected, system);
552 } 549 }
553 550
554 if (!player.connected) { 551 if (!player.connected) {
@@ -560,7 +557,7 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index)
560 using namespace std::chrono_literals; 557 using namespace std::chrono_literals;
561 std::this_thread::sleep_for(60ms); 558 std::this_thread::sleep_for(60ms);
562 559
563 UpdateController(controller_type, player_index, player_connected); 560 UpdateController(controller_type, player_index, player_connected, system);
564} 561}
565 562
566void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { 563void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
@@ -659,7 +656,8 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
659 for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { 656 for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
660 // Disconnect any unsupported players here and disable or hide them if applicable. 657 // Disconnect any unsupported players here and disable or hide them if applicable.
661 Settings::values.players.GetValue()[index].connected = false; 658 Settings::values.players.GetValue()[index].connected = false;
662 UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false); 659 UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false,
660 system);
663 // Hide the player widgets when max_supported_controllers is less than or equal to 4. 661 // Hide the player widgets when max_supported_controllers is less than or equal to 4.
664 if (max_supported_players <= 4) { 662 if (max_supported_players <= 4) {
665 player_widgets[index]->hide(); 663 player_widgets[index]->hide();
diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h
index 9b57aea1a..037325f50 100644
--- a/src/yuzu/applets/qt_controller.h
+++ b/src/yuzu/applets/qt_controller.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <QDialog> 9#include <QDialog>
10#include "core/core.h"
10#include "core/frontend/applets/controller.h" 11#include "core/frontend/applets/controller.h"
11 12
12class GMainWindow; 13class GMainWindow;
@@ -36,7 +37,8 @@ class QtControllerSelectorDialog final : public QDialog {
36public: 37public:
37 explicit QtControllerSelectorDialog(QWidget* parent, 38 explicit QtControllerSelectorDialog(QWidget* parent,
38 Core::Frontend::ControllerParameters parameters_, 39 Core::Frontend::ControllerParameters parameters_,
39 InputCommon::InputSubsystem* input_subsystem_); 40 InputCommon::InputSubsystem* input_subsystem_,
41 Core::System& system_);
40 ~QtControllerSelectorDialog() override; 42 ~QtControllerSelectorDialog() override;
41 43
42 int exec() override; 44 int exec() override;
@@ -103,6 +105,8 @@ private:
103 105
104 std::unique_ptr<InputProfiles> input_profiles; 106 std::unique_ptr<InputProfiles> input_profiles;
105 107
108 Core::System& system;
109
106 // This is true if and only if all parameters are met. Otherwise, this is false. 110 // This is true if and only if all parameters are met. Otherwise, this is false.
107 // This determines whether the "OK" button can be clicked to exit the applet. 111 // This determines whether the "OK" button can be clicked to exit the applet.
108 bool parameters_met{false}; 112 bool parameters_met{false};
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index 652d99570..da8c6882a 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#ifdef YUZU_USE_QT_WEB_ENGINE 5#ifdef YUZU_USE_QT_WEB_ENGINE
6#include <QApplication>
6#include <QKeyEvent> 7#include <QKeyEvent>
7 8
8#include <QWebEngineProfile> 9#include <QWebEngineProfile>
@@ -54,6 +55,9 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system,
54 input_interpreter(std::make_unique<InputInterpreter>(system)), 55 input_interpreter(std::make_unique<InputInterpreter>(system)),
55 default_profile{QWebEngineProfile::defaultProfile()}, 56 default_profile{QWebEngineProfile::defaultProfile()},
56 global_settings{QWebEngineSettings::globalSettings()} { 57 global_settings{QWebEngineSettings::globalSettings()} {
58 default_profile->setPersistentStoragePath(QString::fromStdString(Common::FS::PathToUTF8String(
59 Common::FS::GetYuzuPath(Common::FS::YuzuPath::YuzuDir) / "qtwebengine")));
60
57 QWebEngineScript gamepad; 61 QWebEngineScript gamepad;
58 QWebEngineScript window_nx; 62 QWebEngineScript window_nx;
59 63
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 1519a46ed..40fd47406 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -42,7 +42,7 @@
42#include "yuzu/bootmanager.h" 42#include "yuzu/bootmanager.h"
43#include "yuzu/main.h" 43#include "yuzu/main.h"
44 44
45EmuThread::EmuThread() = default; 45EmuThread::EmuThread(Core::System& system_) : system{system_} {}
46 46
47EmuThread::~EmuThread() = default; 47EmuThread::~EmuThread() = default;
48 48
@@ -51,7 +51,6 @@ void EmuThread::run() {
51 MicroProfileOnThreadCreate(name.c_str()); 51 MicroProfileOnThreadCreate(name.c_str());
52 Common::SetCurrentThreadName(name.c_str()); 52 Common::SetCurrentThreadName(name.c_str());
53 53
54 auto& system = Core::System::GetInstance();
55 auto& gpu = system.GPU(); 54 auto& gpu = system.GPU();
56 auto stop_token = stop_source.get_token(); 55 auto stop_token = stop_source.get_token();
57 56
@@ -87,15 +86,15 @@ void EmuThread::run() {
87 } 86 }
88 87
89 running_guard = true; 88 running_guard = true;
90 Core::System::ResultStatus result = system.Run(); 89 Core::SystemResultStatus result = system.Run();
91 if (result != Core::System::ResultStatus::Success) { 90 if (result != Core::SystemResultStatus::Success) {
92 running_guard = false; 91 running_guard = false;
93 this->SetRunning(false); 92 this->SetRunning(false);
94 emit ErrorThrown(result, system.GetStatusDetails()); 93 emit ErrorThrown(result, system.GetStatusDetails());
95 } 94 }
96 running_wait.Wait(); 95 running_wait.Wait();
97 result = system.Pause(); 96 result = system.Pause();
98 if (result != Core::System::ResultStatus::Success) { 97 if (result != Core::SystemResultStatus::Success) {
99 running_guard = false; 98 running_guard = false;
100 this->SetRunning(false); 99 this->SetRunning(false);
101 emit ErrorThrown(result, system.GetStatusDetails()); 100 emit ErrorThrown(result, system.GetStatusDetails());
@@ -285,8 +284,10 @@ static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow*
285} 284}
286 285
287GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, 286GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
288 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_) 287 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
289 : QWidget(parent), emu_thread(emu_thread_), input_subsystem{std::move(input_subsystem_)} { 288 Core::System& system_)
289 : QWidget(parent),
290 emu_thread(emu_thread_), input_subsystem{std::move(input_subsystem_)}, system{system_} {
290 setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") 291 setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")
291 .arg(QString::fromUtf8(Common::g_build_name), 292 .arg(QString::fromUtf8(Common::g_build_name),
292 QString::fromUtf8(Common::g_scm_branch), 293 QString::fromUtf8(Common::g_scm_branch),
@@ -302,12 +303,17 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
302 connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); 303 connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
303 connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, 304 connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
304 Qt::QueuedConnection); 305 Qt::QueuedConnection);
306 connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection);
305} 307}
306 308
307void GRenderWindow::ExecuteProgram(std::size_t program_index) { 309void GRenderWindow::ExecuteProgram(std::size_t program_index) {
308 emit ExecuteProgramSignal(program_index); 310 emit ExecuteProgramSignal(program_index);
309} 311}
310 312
313void GRenderWindow::Exit() {
314 emit ExitSignal();
315}
316
311GRenderWindow::~GRenderWindow() { 317GRenderWindow::~GRenderWindow() {
312 input_subsystem->Shutdown(); 318 input_subsystem->Shutdown();
313} 319}
@@ -624,8 +630,7 @@ void GRenderWindow::ReleaseRenderTarget() {
624} 630}
625 631
626void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) { 632void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
627 auto& renderer = Core::System::GetInstance().Renderer(); 633 VideoCore::RendererBase& renderer = system.Renderer();
628
629 if (res_scale == 0) { 634 if (res_scale == 0) {
630 res_scale = VideoCore::GetResolutionScaleFactor(renderer); 635 res_scale = VideoCore::GetResolutionScaleFactor(renderer);
631 } 636 }
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 402dd2ee1..e6a0666e9 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -16,7 +16,6 @@
16#include <QWindow> 16#include <QWindow>
17 17
18#include "common/thread.h" 18#include "common/thread.h"
19#include "core/core.h"
20#include "core/frontend/emu_window.h" 19#include "core/frontend/emu_window.h"
21 20
22class GRenderWindow; 21class GRenderWindow;
@@ -24,6 +23,11 @@ class GMainWindow;
24class QKeyEvent; 23class QKeyEvent;
25class QStringList; 24class QStringList;
26 25
26namespace Core {
27enum class SystemResultStatus : u32;
28class System;
29} // namespace Core
30
27namespace InputCommon { 31namespace InputCommon {
28class InputSubsystem; 32class InputSubsystem;
29} 33}
@@ -34,13 +38,14 @@ enum class MouseButton;
34 38
35namespace VideoCore { 39namespace VideoCore {
36enum class LoadCallbackStage; 40enum class LoadCallbackStage;
37} 41class RendererBase;
42} // namespace VideoCore
38 43
39class EmuThread final : public QThread { 44class EmuThread final : public QThread {
40 Q_OBJECT 45 Q_OBJECT
41 46
42public: 47public:
43 explicit EmuThread(); 48 explicit EmuThread(Core::System& system_);
44 ~EmuThread() override; 49 ~EmuThread() override;
45 50
46 /** 51 /**
@@ -101,6 +106,7 @@ private:
101 std::condition_variable_any running_cv; 106 std::condition_variable_any running_cv;
102 Common::Event running_wait{}; 107 Common::Event running_wait{};
103 std::atomic_bool running_guard{false}; 108 std::atomic_bool running_guard{false};
109 Core::System& system;
104 110
105signals: 111signals:
106 /** 112 /**
@@ -121,7 +127,7 @@ signals:
121 */ 127 */
122 void DebugModeLeft(); 128 void DebugModeLeft();
123 129
124 void ErrorThrown(Core::System::ResultStatus, std::string); 130 void ErrorThrown(Core::SystemResultStatus, std::string);
125 131
126 void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); 132 void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total);
127}; 133};
@@ -131,7 +137,8 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
131 137
132public: 138public:
133 explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, 139 explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
134 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_); 140 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
141 Core::System& system_);
135 ~GRenderWindow() override; 142 ~GRenderWindow() override;
136 143
137 // EmuWindow implementation. 144 // EmuWindow implementation.
@@ -181,6 +188,9 @@ public:
181 */ 188 */
182 void ExecuteProgram(std::size_t program_index); 189 void ExecuteProgram(std::size_t program_index);
183 190
191 /// Instructs the window to exit the application.
192 void Exit();
193
184public slots: 194public slots:
185 void OnEmulationStarting(EmuThread* emu_thread); 195 void OnEmulationStarting(EmuThread* emu_thread);
186 void OnEmulationStopping(); 196 void OnEmulationStopping();
@@ -191,6 +201,7 @@ signals:
191 void Closed(); 201 void Closed();
192 void FirstFrameDisplayed(); 202 void FirstFrameDisplayed();
193 void ExecuteProgramSignal(std::size_t program_index); 203 void ExecuteProgramSignal(std::size_t program_index);
204 void ExitSignal();
194 void MouseActivity(); 205 void MouseActivity();
195 206
196private: 207private:
@@ -228,6 +239,8 @@ private:
228 239
229 std::array<std::size_t, 16> touch_ids{}; 240 std::array<std::size_t, 16> touch_ids{};
230 241
242 Core::System& system;
243
231protected: 244protected:
232 void showEvent(QShowEvent* event) override; 245 void showEvent(QShowEvent* event) override;
233 bool eventFilter(QObject* object, QEvent* event) override; 246 bool eventFilter(QObject* object, QEvent* event) override;
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index a470056ef..2442bb3c3 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -8,14 +8,13 @@
8#include <QtConcurrent/qtconcurrentrun.h> 8#include <QtConcurrent/qtconcurrentrun.h>
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/telemetry.h" 10#include "common/telemetry.h"
11#include "core/core.h"
12#include "core/telemetry_session.h" 11#include "core/telemetry_session.h"
13#include "ui_compatdb.h" 12#include "ui_compatdb.h"
14#include "yuzu/compatdb.h" 13#include "yuzu/compatdb.h"
15 14
16CompatDB::CompatDB(QWidget* parent) 15CompatDB::CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent)
17 : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), 16 : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
18 ui{std::make_unique<Ui::CompatDB>()} { 17 ui{std::make_unique<Ui::CompatDB>()}, telemetry_session{telemetry_session_} {
19 ui->setupUi(this); 18 ui->setupUi(this);
20 connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext); 19 connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext);
21 connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext); 20 connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext);
@@ -53,16 +52,15 @@ void CompatDB::Submit() {
53 case CompatDBPage::Final: 52 case CompatDBPage::Final:
54 back(); 53 back();
55 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); 54 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
56 Core::System::GetInstance().TelemetrySession().AddField( 55 telemetry_session.AddField(Common::Telemetry::FieldType::UserFeedback, "Compatibility",
57 Common::Telemetry::FieldType::UserFeedback, "Compatibility", 56 compatibility->checkedId());
58 compatibility->checkedId());
59 57
60 button(NextButton)->setEnabled(false); 58 button(NextButton)->setEnabled(false);
61 button(NextButton)->setText(tr("Submitting")); 59 button(NextButton)->setText(tr("Submitting"));
62 button(CancelButton)->setVisible(false); 60 button(CancelButton)->setVisible(false);
63 61
64 testcase_watcher.setFuture(QtConcurrent::run( 62 testcase_watcher.setFuture(
65 [] { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); })); 63 QtConcurrent::run([this] { return telemetry_session.SubmitTestcase(); }));
66 break; 64 break;
67 default: 65 default:
68 LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); 66 LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h
index 5381f67f7..e2b2522bd 100644
--- a/src/yuzu/compatdb.h
+++ b/src/yuzu/compatdb.h
@@ -7,6 +7,7 @@
7#include <memory> 7#include <memory>
8#include <QFutureWatcher> 8#include <QFutureWatcher>
9#include <QWizard> 9#include <QWizard>
10#include "core/telemetry_session.h"
10 11
11namespace Ui { 12namespace Ui {
12class CompatDB; 13class CompatDB;
@@ -16,7 +17,7 @@ class CompatDB : public QWizard {
16 Q_OBJECT 17 Q_OBJECT
17 18
18public: 19public:
19 explicit CompatDB(QWidget* parent = nullptr); 20 explicit CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent = nullptr);
20 ~CompatDB(); 21 ~CompatDB();
21 22
22private: 23private:
@@ -27,4 +28,6 @@ private:
27 void Submit(); 28 void Submit();
28 void OnTestcaseSubmitted(); 29 void OnTestcaseSubmitted();
29 void EnableNext(); 30 void EnableNext();
31
32 Core::TelemetrySession& telemetry_session;
30}; 33};
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 27b67fd9e..faea5dda1 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -16,7 +16,8 @@
16 16
17namespace FS = Common::FS; 17namespace FS = Common::FS;
18 18
19Config::Config(const std::string& config_name, ConfigType config_type) : type(config_type) { 19Config::Config(Core::System& system_, const std::string& config_name, ConfigType config_type)
20 : type(config_type), system{system_} {
20 global = config_type == ConfigType::GlobalConfig; 21 global = config_type == ConfigType::GlobalConfig;
21 22
22 Initialize(config_name); 23 Initialize(config_name);
@@ -562,7 +563,11 @@ void Config::ReadControlValues() {
562 ReadTouchscreenValues(); 563 ReadTouchscreenValues();
563 ReadMotionTouchValues(); 564 ReadMotionTouchValues();
564 565
566#ifdef _WIN32
565 ReadBasicSetting(Settings::values.enable_raw_input); 567 ReadBasicSetting(Settings::values.enable_raw_input);
568#else
569 Settings::values.enable_raw_input = false;
570#endif
566 ReadBasicSetting(Settings::values.emulate_analog_keyboard); 571 ReadBasicSetting(Settings::values.emulate_analog_keyboard);
567 Settings::values.mouse_panning = false; 572 Settings::values.mouse_panning = false;
568 ReadBasicSetting(Settings::values.mouse_panning_sensitivity); 573 ReadBasicSetting(Settings::values.mouse_panning_sensitivity);
@@ -705,8 +710,6 @@ void Config::ReadDebuggingValues() {
705 710
706void Config::ReadServiceValues() { 711void Config::ReadServiceValues() {
707 qt_config->beginGroup(QStringLiteral("Services")); 712 qt_config->beginGroup(QStringLiteral("Services"));
708 ReadBasicSetting(Settings::values.bcat_backend);
709 ReadBasicSetting(Settings::values.bcat_boxcat_local);
710 ReadBasicSetting(Settings::values.network_interface); 713 ReadBasicSetting(Settings::values.network_interface);
711 qt_config->endGroup(); 714 qt_config->endGroup();
712} 715}
@@ -915,8 +918,7 @@ void Config::ReadSystemValues() {
915 const auto custom_rtc_enabled = 918 const auto custom_rtc_enabled =
916 ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool(); 919 ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool();
917 if (custom_rtc_enabled) { 920 if (custom_rtc_enabled) {
918 Settings::values.custom_rtc = 921 Settings::values.custom_rtc = ReadSetting(QStringLiteral("custom_rtc"), 0).toLongLong();
919 std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong());
920 } else { 922 } else {
921 Settings::values.custom_rtc = std::nullopt; 923 Settings::values.custom_rtc = std::nullopt;
922 } 924 }
@@ -1265,8 +1267,6 @@ void Config::SaveDebuggingValues() {
1265void Config::SaveNetworkValues() { 1267void Config::SaveNetworkValues() {
1266 qt_config->beginGroup(QStringLiteral("Services")); 1268 qt_config->beginGroup(QStringLiteral("Services"));
1267 1269
1268 WriteBasicSetting(Settings::values.bcat_backend);
1269 WriteBasicSetting(Settings::values.bcat_boxcat_local);
1270 WriteBasicSetting(Settings::values.network_interface); 1270 WriteBasicSetting(Settings::values.network_interface);
1271 1271
1272 qt_config->endGroup(); 1272 qt_config->endGroup();
@@ -1449,9 +1449,7 @@ void Config::SaveSystemValues() {
1449 WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(), 1449 WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
1450 false); 1450 false);
1451 WriteSetting(QStringLiteral("custom_rtc"), 1451 WriteSetting(QStringLiteral("custom_rtc"),
1452 QVariant::fromValue<long long>( 1452 QVariant::fromValue<long long>(Settings::values.custom_rtc.value_or(0)), 0);
1453 Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()),
1454 0);
1455 } 1453 }
1456 1454
1457 WriteGlobalSetting(Settings::values.sound_index); 1455 WriteGlobalSetting(Settings::values.sound_index);
@@ -1593,7 +1591,7 @@ void Config::Reload() {
1593 ReadValues(); 1591 ReadValues();
1594 // To apply default value changes 1592 // To apply default value changes
1595 SaveValues(); 1593 SaveValues();
1596 Core::System::GetInstance().ApplySettings(); 1594 system.ApplySettings();
1597} 1595}
1598 1596
1599void Config::Save() { 1597void Config::Save() {
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 3ee694e7c..a7f4a6720 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -14,6 +14,10 @@
14 14
15class QSettings; 15class QSettings;
16 16
17namespace Core {
18class System;
19}
20
17class Config { 21class Config {
18public: 22public:
19 enum class ConfigType { 23 enum class ConfigType {
@@ -22,7 +26,7 @@ public:
22 InputProfile, 26 InputProfile,
23 }; 27 };
24 28
25 explicit Config(const std::string& config_name = "qt-config", 29 explicit Config(Core::System& system_, const std::string& config_name = "qt-config",
26 ConfigType config_type = ConfigType::GlobalConfig); 30 ConfigType config_type = ConfigType::GlobalConfig);
27 ~Config(); 31 ~Config();
28 32
@@ -176,6 +180,8 @@ private:
176 std::unique_ptr<QSettings> qt_config; 180 std::unique_ptr<QSettings> qt_config;
177 std::string qt_config_loc; 181 std::string qt_config_loc;
178 bool global; 182 bool global;
183
184 Core::System& system;
179}; 185};
180 186
181// These metatype declarations cannot be in common/settings.h because core is devoid of QT 187// These metatype declarations cannot be in common/settings.h because core is devoid of QT
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 6258dcf20..eb8078467 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -41,120 +41,8 @@
41 <item> 41 <item>
42 <widget class="QTabWidget" name="tabWidget"> 42 <widget class="QTabWidget" name="tabWidget">
43 <property name="currentIndex"> 43 <property name="currentIndex">
44 <number>11</number> 44 <number>-1</number>
45 </property> 45 </property>
46 <widget class="ConfigureGeneral" name="generalTab">
47 <property name="accessibleName">
48 <string>General</string>
49 </property>
50 <attribute name="title">
51 <string>General</string>
52 </attribute>
53 </widget>
54 <widget class="ConfigureUi" name="uiTab">
55 <property name="accessibleName">
56 <string>UI</string>
57 </property>
58 <attribute name="title">
59 <string>Game List</string>
60 </attribute>
61 </widget>
62 <widget class="ConfigureSystem" name="systemTab">
63 <property name="accessibleName">
64 <string>System</string>
65 </property>
66 <attribute name="title">
67 <string>System</string>
68 </attribute>
69 </widget>
70 <widget class="ConfigureProfileManager" name="profileManagerTab">
71 <property name="accessibleName">
72 <string>Profiles</string>
73 </property>
74 <attribute name="title">
75 <string>Profiles</string>
76 </attribute>
77 </widget>
78 <widget class="ConfigureFilesystem" name="filesystemTab">
79 <property name="accessibleName">
80 <string>Filesystem</string>
81 </property>
82 <attribute name="title">
83 <string>Filesystem</string>
84 </attribute>
85 </widget>
86 <widget class="ConfigureInput" name="inputTab">
87 <property name="accessibleName">
88 <string>Controls</string>
89 </property>
90 <attribute name="title">
91 <string>Controls</string>
92 </attribute>
93 </widget>
94 <widget class="ConfigureHotkeys" name="hotkeysTab">
95 <property name="accessibleName">
96 <string>Hotkeys</string>
97 </property>
98 <attribute name="title">
99 <string>Hotkeys</string>
100 </attribute>
101 </widget>
102 <widget class="ConfigureCpu" name="cpuTab">
103 <property name="accessibleName">
104 <string>CPU</string>
105 </property>
106 <attribute name="title">
107 <string>CPU</string>
108 </attribute>
109 </widget>
110 <widget class="ConfigureGraphics" name="graphicsTab">
111 <property name="accessibleName">
112 <string>Graphics</string>
113 </property>
114 <attribute name="title">
115 <string>Graphics</string>
116 </attribute>
117 </widget>
118 <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
119 <property name="accessibleName">
120 <string>Advanced</string>
121 </property>
122 <attribute name="title">
123 <string>GraphicsAdvanced</string>
124 </attribute>
125 </widget>
126 <widget class="ConfigureAudio" name="audioTab">
127 <property name="accessibleName">
128 <string>Audio</string>
129 </property>
130 <attribute name="title">
131 <string>Audio</string>
132 </attribute>
133 </widget>
134 <widget class="ConfigureDebugTab" name="debugTab">
135 <property name="accessibleName">
136 <string>Debug</string>
137 </property>
138 <attribute name="title">
139 <string>Debug</string>
140 </attribute>
141 </widget>
142 <widget class="ConfigureWeb" name="webTab">
143 <property name="accessibleName">
144 <string>Web</string>
145 </property>
146 <attribute name="title">
147 <string>Web</string>
148 </attribute>
149 </widget>
150 <widget class="ConfigureNetwork" name="networkTab">
151 <property name="accessibleName">
152 <string>Network</string>
153 </property>
154 <attribute name="title">
155 <string>Network</string>
156 </attribute>
157 </widget>
158 </widget> 46 </widget>
159 </item> 47 </item>
160 </layout> 48 </layout>
@@ -168,92 +56,6 @@
168 </item> 56 </item>
169 </layout> 57 </layout>
170 </widget> 58 </widget>
171 <customwidgets>
172 <customwidget>
173 <class>ConfigureGeneral</class>
174 <extends>QWidget</extends>
175 <header>configuration/configure_general.h</header>
176 <container>1</container>
177 </customwidget>
178 <customwidget>
179 <class>ConfigureSystem</class>
180 <extends>QWidget</extends>
181 <header>configuration/configure_system.h</header>
182 <container>1</container>
183 </customwidget>
184 <customwidget>
185 <class>ConfigureProfileManager</class>
186 <extends>QWidget</extends>
187 <header>configuration/configure_profile_manager.h</header>
188 <container>1</container>
189 </customwidget>
190 <customwidget>
191 <class>ConfigureFilesystem</class>
192 <extends>QWidget</extends>
193 <header>configuration/configure_filesystem.h</header>
194 <container>1</container>
195 </customwidget>
196 <customwidget>
197 <class>ConfigureAudio</class>
198 <extends>QWidget</extends>
199 <header>configuration/configure_audio.h</header>
200 <container>1</container>
201 </customwidget>
202 <customwidget>
203 <class>ConfigureCpu</class>
204 <extends>QWidget</extends>
205 <header>configuration/configure_cpu.h</header>
206 <container>1</container>
207 </customwidget>
208 <customwidget>
209 <class>ConfigureGraphics</class>
210 <extends>QWidget</extends>
211 <header>configuration/configure_graphics.h</header>
212 <container>1</container>
213 </customwidget>
214 <customwidget>
215 <class>ConfigureGraphicsAdvanced</class>
216 <extends>QWidget</extends>
217 <header>configuration/configure_graphics_advanced.h</header>
218 <container>1</container>
219 </customwidget>
220 <customwidget>
221 <class>ConfigureWeb</class>
222 <extends>QWidget</extends>
223 <header>configuration/configure_web.h</header>
224 <container>1</container>
225 </customwidget>
226 <customwidget>
227 <class>ConfigureUi</class>
228 <extends>QWidget</extends>
229 <header>configuration/configure_ui.h</header>
230 <container>1</container>
231 </customwidget>
232 <customwidget>
233 <class>ConfigureInput</class>
234 <extends>QWidget</extends>
235 <header>configuration/configure_input.h</header>
236 <container>1</container>
237 </customwidget>
238 <customwidget>
239 <class>ConfigureHotkeys</class>
240 <extends>QWidget</extends>
241 <header>configuration/configure_hotkeys.h</header>
242 <container>1</container>
243 </customwidget>
244 <customwidget>
245 <class>ConfigureNetwork</class>
246 <extends>QWidget</extends>
247 <header>configuration/configure_network.h</header>
248 <container>1</container>
249 </customwidget>
250 <customwidget>
251 <class>ConfigureDebugTab</class>
252 <extends>QWidget</extends>
253 <header>configuration/configure_debug_tab.h</header>
254 <container>1</container>
255 </customwidget>
256 </customwidgets>
257 <resources/> 59 <resources/>
258 <connections> 60 <connections>
259 <connection> 61 <connection>
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index f437cb53d..c33488718 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -14,8 +14,8 @@
14#include "yuzu/configuration/configuration_shared.h" 14#include "yuzu/configuration/configuration_shared.h"
15#include "yuzu/configuration/configure_audio.h" 15#include "yuzu/configuration/configure_audio.h"
16 16
17ConfigureAudio::ConfigureAudio(QWidget* parent) 17ConfigureAudio::ConfigureAudio(const Core::System& system_, QWidget* parent)
18 : QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()) { 18 : QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_} {
19 ui->setupUi(this); 19 ui->setupUi(this);
20 20
21 InitializeAudioOutputSinkComboBox(); 21 InitializeAudioOutputSinkComboBox();
@@ -32,7 +32,7 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
32 32
33 SetConfiguration(); 33 SetConfiguration();
34 34
35 const bool is_powered_on = Core::System::GetInstance().IsPoweredOn(); 35 const bool is_powered_on = system_.IsPoweredOn();
36 ui->output_sink_combo_box->setEnabled(!is_powered_on); 36 ui->output_sink_combo_box->setEnabled(!is_powered_on);
37 ui->audio_device_combo_box->setEnabled(!is_powered_on); 37 ui->audio_device_combo_box->setEnabled(!is_powered_on);
38} 38}
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 5a01c8de7..5d2d05e47 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace Core {
11class System;
12}
13
10namespace ConfigurationShared { 14namespace ConfigurationShared {
11enum class CheckState; 15enum class CheckState;
12} 16}
@@ -19,10 +23,11 @@ class ConfigureAudio : public QWidget {
19 Q_OBJECT 23 Q_OBJECT
20 24
21public: 25public:
22 explicit ConfigureAudio(QWidget* parent = nullptr); 26 explicit ConfigureAudio(const Core::System& system_, QWidget* parent = nullptr);
23 ~ConfigureAudio() override; 27 ~ConfigureAudio() override;
24 28
25 void ApplyConfiguration(); 29 void ApplyConfiguration();
30 void SetConfiguration();
26 31
27private: 32private:
28 void changeEvent(QEvent* event) override; 33 void changeEvent(QEvent* event) override;
@@ -33,7 +38,6 @@ private:
33 38
34 void UpdateAudioDevices(int sink_index); 39 void UpdateAudioDevices(int sink_index);
35 40
36 void SetConfiguration();
37 void SetOutputSinkFromSinkID(); 41 void SetOutputSinkFromSinkID();
38 void SetAudioDeviceFromDeviceID(); 42 void SetAudioDeviceFromDeviceID();
39 void SetVolumeIndicatorText(int percentage); 43 void SetVolumeIndicatorText(int percentage);
@@ -41,4 +45,6 @@ private:
41 void SetupPerGameUI(); 45 void SetupPerGameUI();
42 46
43 std::unique_ptr<Ui::ConfigureAudio> ui; 47 std::unique_ptr<Ui::ConfigureAudio> ui;
48
49 const Core::System& system;
44}; 50};
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index bf736fc2c..d1ac8ad02 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -10,6 +10,9 @@
10 <height>368</height> 10 <height>368</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="accessibleName">
14 <string>Audio</string>
15 </property>
13 <layout class="QVBoxLayout"> 16 <layout class="QVBoxLayout">
14 <item> 17 <item>
15 <widget class="QGroupBox" name="groupBox"> 18 <widget class="QGroupBox" name="groupBox">
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 784b6484e..f66cab5d4 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -13,7 +13,8 @@
13#include "yuzu/configuration/configuration_shared.h" 13#include "yuzu/configuration/configuration_shared.h"
14#include "yuzu/configuration/configure_cpu.h" 14#include "yuzu/configuration/configure_cpu.h"
15 15
16ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) { 16ConfigureCpu::ConfigureCpu(const Core::System& system_, QWidget* parent)
17 : QWidget(parent), ui{std::make_unique<Ui::ConfigureCpu>()}, system{system_} {
17 ui->setupUi(this); 18 ui->setupUi(this);
18 19
19 SetupPerGameUI(); 20 SetupPerGameUI();
@@ -27,7 +28,7 @@ ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::Config
27ConfigureCpu::~ConfigureCpu() = default; 28ConfigureCpu::~ConfigureCpu() = default;
28 29
29void ConfigureCpu::SetConfiguration() { 30void ConfigureCpu::SetConfiguration() {
30 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 31 const bool runtime_lock = !system.IsPoweredOn();
31 32
32 ui->accuracy->setEnabled(runtime_lock); 33 ui->accuracy->setEnabled(runtime_lock);
33 ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock); 34 ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index 154931482..ed9af0e9f 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -8,6 +8,10 @@
8#include <QWidget> 8#include <QWidget>
9#include "common/settings.h" 9#include "common/settings.h"
10 10
11namespace Core {
12class System;
13}
14
11namespace ConfigurationShared { 15namespace ConfigurationShared {
12enum class CheckState; 16enum class CheckState;
13} 17}
@@ -20,10 +24,11 @@ class ConfigureCpu : public QWidget {
20 Q_OBJECT 24 Q_OBJECT
21 25
22public: 26public:
23 explicit ConfigureCpu(QWidget* parent = nullptr); 27 explicit ConfigureCpu(const Core::System& system_, QWidget* parent = nullptr);
24 ~ConfigureCpu() override; 28 ~ConfigureCpu() override;
25 29
26 void ApplyConfiguration(); 30 void ApplyConfiguration();
31 void SetConfiguration();
27 32
28private: 33private:
29 void changeEvent(QEvent* event) override; 34 void changeEvent(QEvent* event) override;
@@ -31,8 +36,6 @@ private:
31 36
32 void UpdateGroup(int index); 37 void UpdateGroup(int index);
33 38
34 void SetConfiguration();
35
36 void SetupPerGameUI(); 39 void SetupPerGameUI();
37 40
38 std::unique_ptr<Ui::ConfigureCpu> ui; 41 std::unique_ptr<Ui::ConfigureCpu> ui;
@@ -42,4 +45,6 @@ private:
42 ConfigurationShared::CheckState cpuopt_unsafe_ignore_standard_fpcr; 45 ConfigurationShared::CheckState cpuopt_unsafe_ignore_standard_fpcr;
43 ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan; 46 ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
44 ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check; 47 ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check;
48
49 const Core::System& system;
45}; 50};
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index 5b9457faf..d8064db24 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -7,12 +7,15 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>448</width> 9 <width>448</width>
10 <height>433</height> 10 <height>439</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>CPU</string>
18 </property>
16 <layout class="QVBoxLayout"> 19 <layout class="QVBoxLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout"> 21 <layout class="QVBoxLayout">
diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp
index 98e2d2be5..05a90963d 100644
--- a/src/yuzu/configuration/configure_cpu_debug.cpp
+++ b/src/yuzu/configuration/configure_cpu_debug.cpp
@@ -11,8 +11,8 @@
11#include "ui_configure_cpu_debug.h" 11#include "ui_configure_cpu_debug.h"
12#include "yuzu/configuration/configure_cpu_debug.h" 12#include "yuzu/configuration/configure_cpu_debug.h"
13 13
14ConfigureCpuDebug::ConfigureCpuDebug(QWidget* parent) 14ConfigureCpuDebug::ConfigureCpuDebug(const Core::System& system_, QWidget* parent)
15 : QWidget(parent), ui(new Ui::ConfigureCpuDebug) { 15 : QWidget(parent), ui{std::make_unique<Ui::ConfigureCpuDebug>()}, system{system_} {
16 ui->setupUi(this); 16 ui->setupUi(this);
17 17
18 SetConfiguration(); 18 SetConfiguration();
@@ -21,7 +21,7 @@ ConfigureCpuDebug::ConfigureCpuDebug(QWidget* parent)
21ConfigureCpuDebug::~ConfigureCpuDebug() = default; 21ConfigureCpuDebug::~ConfigureCpuDebug() = default;
22 22
23void ConfigureCpuDebug::SetConfiguration() { 23void ConfigureCpuDebug::SetConfiguration() {
24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 24 const bool runtime_lock = !system.IsPoweredOn();
25 25
26 ui->cpuopt_page_tables->setEnabled(runtime_lock); 26 ui->cpuopt_page_tables->setEnabled(runtime_lock);
27 ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables.GetValue()); 27 ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables.GetValue());
diff --git a/src/yuzu/configuration/configure_cpu_debug.h b/src/yuzu/configuration/configure_cpu_debug.h
index 1b0d8050c..d06c4c63f 100644
--- a/src/yuzu/configuration/configure_cpu_debug.h
+++ b/src/yuzu/configuration/configure_cpu_debug.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace Core {
11class System;
12}
13
10namespace Ui { 14namespace Ui {
11class ConfigureCpuDebug; 15class ConfigureCpuDebug;
12} 16}
@@ -15,7 +19,7 @@ class ConfigureCpuDebug : public QWidget {
15 Q_OBJECT 19 Q_OBJECT
16 20
17public: 21public:
18 explicit ConfigureCpuDebug(QWidget* parent = nullptr); 22 explicit ConfigureCpuDebug(const Core::System& system_, QWidget* parent = nullptr);
19 ~ConfigureCpuDebug() override; 23 ~ConfigureCpuDebug() override;
20 24
21 void ApplyConfiguration(); 25 void ApplyConfiguration();
@@ -27,4 +31,6 @@ private:
27 void SetConfiguration(); 31 void SetConfiguration();
28 32
29 std::unique_ptr<Ui::ConfigureCpuDebug> ui; 33 std::unique_ptr<Ui::ConfigureCpuDebug> ui;
34
35 const Core::System& system;
30}; 36};
diff --git a/src/yuzu/configuration/configure_cpu_debug.ui b/src/yuzu/configuration/configure_cpu_debug.ui
index abf469b55..6e635bb2f 100644
--- a/src/yuzu/configuration/configure_cpu_debug.ui
+++ b/src/yuzu/configuration/configure_cpu_debug.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>CPU</string>
18 </property>
16 <layout class="QVBoxLayout"> 19 <layout class="QVBoxLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout"> 21 <layout class="QVBoxLayout">
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index c0b240c1e..07bfa0360 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -14,7 +14,8 @@
14#include "yuzu/debugger/console.h" 14#include "yuzu/debugger/console.h"
15#include "yuzu/uisettings.h" 15#include "yuzu/uisettings.h"
16 16
17ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureDebug) { 17ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent)
18 : QWidget(parent), ui{std::make_unique<Ui::ConfigureDebug>()}, system{system_} {
18 ui->setupUi(this); 19 ui->setupUi(this);
19 SetConfiguration(); 20 SetConfiguration();
20 21
@@ -28,7 +29,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::Co
28ConfigureDebug::~ConfigureDebug() = default; 29ConfigureDebug::~ConfigureDebug() = default;
29 30
30void ConfigureDebug::SetConfiguration() { 31void ConfigureDebug::SetConfiguration() {
31 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 32 const bool runtime_lock = !system.IsPoweredOn();
32 33
33 ui->toggle_console->setEnabled(runtime_lock); 34 ui->toggle_console->setEnabled(runtime_lock);
34 ui->toggle_console->setChecked(UISettings::values.show_console.GetValue()); 35 ui->toggle_console->setChecked(UISettings::values.show_console.GetValue());
diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index f4805a1d8..73f71c9e3 100644
--- a/src/yuzu/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace Core {
11class System;
12}
13
10namespace Ui { 14namespace Ui {
11class ConfigureDebug; 15class ConfigureDebug;
12} 16}
@@ -15,7 +19,7 @@ class ConfigureDebug : public QWidget {
15 Q_OBJECT 19 Q_OBJECT
16 20
17public: 21public:
18 explicit ConfigureDebug(QWidget* parent = nullptr); 22 explicit ConfigureDebug(const Core::System& system_, QWidget* parent = nullptr);
19 ~ConfigureDebug() override; 23 ~ConfigureDebug() override;
20 24
21 void ApplyConfiguration(); 25 void ApplyConfiguration();
@@ -27,4 +31,6 @@ private:
27 void SetConfiguration(); 31 void SetConfiguration();
28 32
29 std::unique_ptr<Ui::ConfigureDebug> ui; 33 std::unique_ptr<Ui::ConfigureDebug> ui;
34
35 const Core::System& system;
30}; 36};
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 3fe9ff7de..b884a56b0 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -2,85 +2,55 @@
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureDebug</class> 3 <class>ConfigureDebug</class>
4 <widget class="QWidget" name="ConfigureDebug"> 4 <widget class="QWidget" name="ConfigureDebug">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>777</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Form</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_1"> 5 <layout class="QVBoxLayout" name="verticalLayout_1">
17 <item> 6 <item>
18 <widget class="QGroupBox" name="groupBox_2"> 7 <widget class="QGroupBox" name="groupBox_2">
19 <property name="title"> 8 <property name="title">
20 <string>Logging</string> 9 <string>Logging</string>
21 </property> 10 </property>
22 <layout class="QVBoxLayout" name="verticalLayout_4"> 11 <layout class="QGridLayout" name="gridLayout_1">
23 <item> 12 <item row="0" column="0" colspan="2">
24 <layout class="QHBoxLayout" name="horizontalLayout_2"> 13 <layout class="QHBoxLayout" name="horizontalLayout_1">
25 <item> 14 <item>
26 <widget class="QLabel" name="label_1"> 15 <widget class="QLabel" name="label_1">
27 <property name="text"> 16 <property name="text">
28 <string>Global Log Filter</string> 17 <string>Global Log Filter</string>
18 </property>
19 </widget>
20 </item>
21 <item>
22 <widget class="QLineEdit" name="log_filter_edit"/>
23 </item>
24 </layout>
25 </item>
26 <item row="1" column="0">
27 <widget class="QCheckBox" name="toggle_console">
28 <property name="text">
29 <string>Show Log in Console</string>
30 </property>
31 </widget>
32 </item>
33 <item row="1" column="1">
34 <widget class="QPushButton" name="open_log_button">
35 <property name="text">
36 <string>Open Log Location</string>
37 </property>
38 </widget>
39 </item>
40 <item row="2" column="0">
41 <widget class="QCheckBox" name="extended_logging">
42 <property name="enabled">
43 <bool>true</bool>
29 </property> 44 </property>
30 </widget> 45 <property name="toolTip">
31 </item> 46 <string>When checked, the max size of the log increases from 100 MB to 1 GB</string>
32 <item>
33 <widget class="QLineEdit" name="log_filter_edit"/>
34 </item>
35 </layout>
36 </item>
37 <item>
38 <layout class="QHBoxLayout" name="horizontalLayout_3">
39 <item>
40 <widget class="QCheckBox" name="toggle_console">
41 <property name="text">
42 <string>Show Log in Console</string>
43 </property> 47 </property>
44 </widget>
45 </item>
46 <item>
47 <widget class="QPushButton" name="open_log_button">
48 <property name="text"> 48 <property name="text">
49 <string>Open Log Location</string> 49 <string>Enable Extended Logging**</string>
50 </property> 50 </property>
51 </widget> 51 </widget>
52 </item> 52 </item>
53 </layout> 53 </layout>
54 </item>
55 <item>
56 <widget class="QCheckBox" name="extended_logging">
57 <property name="enabled">
58 <bool>true</bool>
59 </property>
60 <property name="toolTip">
61 <string>When checked, the max size of the log increases from 100 MB to 1 GB</string>
62 </property>
63 <property name="text">
64 <string>Enable Extended Logging</string>
65 </property>
66 </widget>
67 </item>
68 <item>
69 <widget class="QLabel" name="label_2">
70 <property name="font">
71 <font>
72 <italic>true</italic>
73 </font>
74 </property>
75 <property name="text">
76 <string>This will be reset automatically when yuzu closes.</string>
77 </property>
78 <property name="indent">
79 <number>20</number>
80 </property>
81 </widget>
82 </item>
83 </layout>
84 </widget> 54 </widget>
85 </item> 55 </item>
86 <item> 56 <item>
@@ -111,7 +81,7 @@
111 <property name="title"> 81 <property name="title">
112 <string>Graphics</string> 82 <string>Graphics</string>
113 </property> 83 </property>
114 <layout class="QGridLayout" name="gridLayout_3"> 84 <layout class="QGridLayout" name="gridLayout_2">
115 <item row="0" column="0"> 85 <item row="0" column="0">
116 <widget class="QCheckBox" name="enable_graphics_debugging"> 86 <widget class="QCheckBox" name="enable_graphics_debugging">
117 <property name="enabled"> 87 <property name="enabled">
@@ -176,33 +146,18 @@
176 <property name="title"> 146 <property name="title">
177 <string>Debugging</string> 147 <string>Debugging</string>
178 </property> 148 </property>
179 <layout class="QVBoxLayout" name="verticalLayout_7"> 149 <layout class="QGridLayout" name="gridLayout_3">
180 <item> 150 <item row="0" column="0">
181 <widget class="QCheckBox" name="fs_access_log"> 151 <widget class="QCheckBox" name="fs_access_log">
182 <property name="text"> 152 <property name="text">
183 <string>Enable FS Access Log</string> 153 <string>Enable FS Access Log</string>
184 </property> 154 </property>
185 </widget> 155 </widget>
186 </item> 156 </item>
187 <item> 157 <item row="1" column="0">
188 <widget class="QCheckBox" name="reporting_services"> 158 <widget class="QCheckBox" name="reporting_services">
189 <property name="text"> 159 <property name="text">
190 <string>Enable Verbose Reporting Services</string> 160 <string>Enable Verbose Reporting Services**</string>
191 </property>
192 </widget>
193 </item>
194 <item>
195 <widget class="QLabel" name="label_4">
196 <property name="font">
197 <font>
198 <italic>true</italic>
199 </font>
200 </property>
201 <property name="text">
202 <string>This will be reset automatically when yuzu closes.</string>
203 </property>
204 <property name="indent">
205 <number>20</number>
206 </property> 161 </property>
207 </widget> 162 </widget>
208 </item> 163 </item>
@@ -214,47 +169,32 @@
214 <property name="title"> 169 <property name="title">
215 <string>Advanced</string> 170 <string>Advanced</string>
216 </property> 171 </property>
217 <layout class="QVBoxLayout" name="verticalLayout_8"> 172 <layout class="QGridLayout" name="gridLayout_4">
218 <item> 173 <item> row="0" column="0">
219 <widget class="QCheckBox" name="quest_flag"> 174 <widget class="QCheckBox" name="quest_flag">
220 <property name="text"> 175 <property name="text">
221 <string>Kiosk (Quest) Mode</string> 176 <string>Kiosk (Quest) Mode</string>
222 </property> 177 </property>
223 </widget> 178 </widget>
224 </item> 179 </item>
225 <item> 180 <item row="1" column="0">
226 <widget class="QCheckBox" name="enable_cpu_debugging"> 181 <widget class="QCheckBox" name="enable_cpu_debugging">
227 <property name="text"> 182 <property name="text">
228 <string>Enable CPU Debugging</string> 183 <string>Enable CPU Debugging</string>
229 </property> 184 </property>
230 </widget> 185 </widget>
231 </item> 186 </item>
232 <item> 187 <item row="2" column="0">
233 <widget class="QCheckBox" name="use_debug_asserts"> 188 <widget class="QCheckBox" name="use_debug_asserts">
234 <property name="text"> 189 <property name="text">
235 <string>Enable Debug Asserts</string> 190 <string>Enable Debug Asserts</string>
236 </property> 191 </property>
237 </widget> 192 </widget>
238 </item> 193 </item>
239 <item> 194 <item row="0" column="1">
240 <widget class="QCheckBox" name="use_auto_stub"> 195 <widget class="QCheckBox" name="use_auto_stub">
241 <property name="text"> 196 <property name="text">
242 <string>Enable Auto-Stub</string> 197 <string>Enable Auto-Stub**</string>
243 </property>
244 </widget>
245 </item>
246 <item>
247 <widget class="QLabel" name="label_5">
248 <property name="font">
249 <font>
250 <italic>true</italic>
251 </font>
252 </property>
253 <property name="text">
254 <string>This will be reset automatically when yuzu closes.</string>
255 </property>
256 <property name="indent">
257 <number>20</number>
258 </property> 198 </property>
259 </widget> 199 </widget>
260 </item> 200 </item>
@@ -262,20 +202,19 @@
262 </widget> 202 </widget>
263 </item> 203 </item>
264 <item> 204 <item>
265 <spacer name="verticalSpacer"> 205 <widget class="QLabel" name="label_5">
266 <property name="orientation"> 206 <property name="font">
267 <enum>Qt::Vertical</enum> 207 <font>
208 <italic>true</italic>
209 </font>
268 </property> 210 </property>
269 <property name="sizeType"> 211 <property name="text">
270 <enum>QSizePolicy::Expanding</enum> 212 <string>**This will be reset automatically when yuzu closes.</string>
271 </property> 213 </property>
272 <property name="sizeHint" stdset="0"> 214 <property name="indent">
273 <size> 215 <number>20</number>
274 <width>20</width>
275 <height>40</height>
276 </size>
277 </property> 216 </property>
278 </spacer> 217 </widget>
279 </item> 218 </item>
280 </layout> 219 </layout>
281 </widget> 220 </widget>
diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp
index a878ef9c6..31ec48384 100644
--- a/src/yuzu/configuration/configure_debug_controller.cpp
+++ b/src/yuzu/configuration/configure_debug_controller.cpp
@@ -2,16 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
5#include "ui_configure_debug_controller.h" 6#include "ui_configure_debug_controller.h"
6#include "yuzu/configuration/configure_debug_controller.h" 7#include "yuzu/configuration/configure_debug_controller.h"
7#include "yuzu/configuration/configure_input_player.h" 8#include "yuzu/configuration/configure_input_player.h"
8 9
9ConfigureDebugController::ConfigureDebugController(QWidget* parent, 10ConfigureDebugController::ConfigureDebugController(QWidget* parent,
10 InputCommon::InputSubsystem* input_subsystem, 11 InputCommon::InputSubsystem* input_subsystem,
11 InputProfiles* profiles) 12 InputProfiles* profiles, Core::System& system)
12 : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()), 13 : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
13 debug_controller( 14 debug_controller(
14 new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, true)) { 15 new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, true)) {
15 ui->setupUi(this); 16 ui->setupUi(this);
16 17
17 ui->controllerLayout->addWidget(debug_controller); 18 ui->controllerLayout->addWidget(debug_controller);
diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h
index b4f53fad5..6e17c5aa0 100644
--- a/src/yuzu/configuration/configure_debug_controller.h
+++ b/src/yuzu/configuration/configure_debug_controller.h
@@ -13,6 +13,10 @@ class ConfigureInputPlayer;
13 13
14class InputProfiles; 14class InputProfiles;
15 15
16namespace Core {
17class System;
18}
19
16namespace InputCommon { 20namespace InputCommon {
17class InputSubsystem; 21class InputSubsystem;
18} 22}
@@ -26,7 +30,7 @@ class ConfigureDebugController : public QDialog {
26 30
27public: 31public:
28 explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem, 32 explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem,
29 InputProfiles* profiles); 33 InputProfiles* profiles, Core::System& system);
30 ~ConfigureDebugController() override; 34 ~ConfigureDebugController() override;
31 35
32 void ApplyConfiguration(); 36 void ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_debug_tab.cpp b/src/yuzu/configuration/configure_debug_tab.cpp
index 67d369249..e69cca1ef 100644
--- a/src/yuzu/configuration/configure_debug_tab.cpp
+++ b/src/yuzu/configuration/configure_debug_tab.cpp
@@ -2,21 +2,29 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory>
5#include "ui_configure_debug_tab.h" 6#include "ui_configure_debug_tab.h"
7#include "yuzu/configuration/configure_cpu_debug.h"
8#include "yuzu/configuration/configure_debug.h"
6#include "yuzu/configuration/configure_debug_tab.h" 9#include "yuzu/configuration/configure_debug_tab.h"
7 10
8ConfigureDebugTab::ConfigureDebugTab(QWidget* parent) 11ConfigureDebugTab::ConfigureDebugTab(const Core::System& system_, QWidget* parent)
9 : QWidget(parent), ui(new Ui::ConfigureDebugTab) { 12 : QWidget(parent), ui{std::make_unique<Ui::ConfigureDebugTab>()},
13 debug_tab{std::make_unique<ConfigureDebug>(system_, this)},
14 cpu_debug_tab{std::make_unique<ConfigureCpuDebug>(system_, this)} {
10 ui->setupUi(this); 15 ui->setupUi(this);
11 16
17 ui->tabWidget->addTab(debug_tab.get(), tr("Debug"));
18 ui->tabWidget->addTab(cpu_debug_tab.get(), tr("CPU"));
19
12 SetConfiguration(); 20 SetConfiguration();
13} 21}
14 22
15ConfigureDebugTab::~ConfigureDebugTab() = default; 23ConfigureDebugTab::~ConfigureDebugTab() = default;
16 24
17void ConfigureDebugTab::ApplyConfiguration() { 25void ConfigureDebugTab::ApplyConfiguration() {
18 ui->debugTab->ApplyConfiguration(); 26 debug_tab->ApplyConfiguration();
19 ui->cpuDebugTab->ApplyConfiguration(); 27 cpu_debug_tab->ApplyConfiguration();
20} 28}
21 29
22void ConfigureDebugTab::SetCurrentIndex(int index) { 30void ConfigureDebugTab::SetCurrentIndex(int index) {
diff --git a/src/yuzu/configuration/configure_debug_tab.h b/src/yuzu/configuration/configure_debug_tab.h
index 0a96d43d0..4f68260aa 100644
--- a/src/yuzu/configuration/configure_debug_tab.h
+++ b/src/yuzu/configuration/configure_debug_tab.h
@@ -7,6 +7,13 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10class ConfigureDebug;
11class ConfigureCpuDebug;
12
13namespace Core {
14class System;
15}
16
10namespace Ui { 17namespace Ui {
11class ConfigureDebugTab; 18class ConfigureDebugTab;
12} 19}
@@ -15,7 +22,7 @@ class ConfigureDebugTab : public QWidget {
15 Q_OBJECT 22 Q_OBJECT
16 23
17public: 24public:
18 explicit ConfigureDebugTab(QWidget* parent = nullptr); 25 explicit ConfigureDebugTab(const Core::System& system_, QWidget* parent = nullptr);
19 ~ConfigureDebugTab() override; 26 ~ConfigureDebugTab() override;
20 27
21 void ApplyConfiguration(); 28 void ApplyConfiguration();
@@ -29,4 +36,7 @@ private:
29 void SetConfiguration(); 36 void SetConfiguration();
30 37
31 std::unique_ptr<Ui::ConfigureDebugTab> ui; 38 std::unique_ptr<Ui::ConfigureDebugTab> ui;
39
40 std::unique_ptr<ConfigureDebug> debug_tab;
41 std::unique_ptr<ConfigureCpuDebug> cpu_debug_tab;
32}; 42};
diff --git a/src/yuzu/configuration/configure_debug_tab.ui b/src/yuzu/configuration/configure_debug_tab.ui
index 7dc6dd704..15ec74727 100644
--- a/src/yuzu/configuration/configure_debug_tab.ui
+++ b/src/yuzu/configuration/configure_debug_tab.ui
@@ -13,40 +13,19 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Debug</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout"> 19 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 20 <item>
18 <widget class="QTabWidget" name="tabWidget"> 21 <widget class="QTabWidget" name="tabWidget">
19 <property name="currentIndex"> 22 <property name="currentIndex">
20 <number>1</number> 23 <number>-1</number>
21 </property> 24 </property>
22 <widget class="ConfigureDebug" name="debugTab">
23 <attribute name="title">
24 <string>General</string>
25 </attribute>
26 </widget>
27 <widget class="ConfigureCpuDebug" name="cpuDebugTab">
28 <attribute name="title">
29 <string>CPU</string>
30 </attribute>
31 </widget>
32 </widget> 25 </widget>
33 </item> 26 </item>
34 </layout> 27 </layout>
35 </widget> 28 </widget>
36 <customwidgets>
37 <customwidget>
38 <class>ConfigureDebug</class>
39 <extends>QWidget</extends>
40 <header>configuration/configure_debug.h</header>
41 <container>1</container>
42 </customwidget>
43 <customwidget>
44 <class>ConfigureCpuDebug</class>
45 <extends>QWidget</extends>
46 <header>configuration/configure_cpu_debug.h</header>
47 <container>1</container>
48 </customwidget>
49 </customwidgets>
50 <resources/> 29 <resources/>
51 <connections/> 30 <connections/>
52</ui> 31</ui>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index fe4186157..4fa0c4a43 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory>
5#include <QAbstractButton> 6#include <QAbstractButton>
6#include <QDialogButtonBox> 7#include <QDialogButtonBox>
7#include <QHash> 8#include <QHash>
@@ -9,37 +10,84 @@
9#include <QPushButton> 10#include <QPushButton>
10#include <QSignalBlocker> 11#include <QSignalBlocker>
11#include <QTabWidget> 12#include <QTabWidget>
13#include "common/logging/log.h"
12#include "common/settings.h" 14#include "common/settings.h"
13#include "core/core.h" 15#include "core/core.h"
14#include "ui_configure.h" 16#include "ui_configure.h"
15#include "yuzu/configuration/config.h" 17#include "yuzu/configuration/config.h"
18#include "yuzu/configuration/configure_audio.h"
19#include "yuzu/configuration/configure_cpu.h"
20#include "yuzu/configuration/configure_debug_tab.h"
16#include "yuzu/configuration/configure_dialog.h" 21#include "yuzu/configuration/configure_dialog.h"
22#include "yuzu/configuration/configure_filesystem.h"
23#include "yuzu/configuration/configure_general.h"
24#include "yuzu/configuration/configure_graphics.h"
25#include "yuzu/configuration/configure_graphics_advanced.h"
26#include "yuzu/configuration/configure_hotkeys.h"
27#include "yuzu/configuration/configure_input.h"
17#include "yuzu/configuration/configure_input_player.h" 28#include "yuzu/configuration/configure_input_player.h"
29#include "yuzu/configuration/configure_network.h"
30#include "yuzu/configuration/configure_profile_manager.h"
31#include "yuzu/configuration/configure_system.h"
32#include "yuzu/configuration/configure_ui.h"
33#include "yuzu/configuration/configure_web.h"
18#include "yuzu/hotkeys.h" 34#include "yuzu/hotkeys.h"
19 35
20ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, 36ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
21 InputCommon::InputSubsystem* input_subsystem) 37 InputCommon::InputSubsystem* input_subsystem,
22 : QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) { 38 Core::System& system_)
39 : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()},
40 registry(registry), system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_,
41 this)},
42 cpu_tab{std::make_unique<ConfigureCpu>(system_, this)},
43 debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)},
44 filesystem_tab{std::make_unique<ConfigureFilesystem>(this)},
45 general_tab{std::make_unique<ConfigureGeneral>(system_, this)},
46 graphics_tab{std::make_unique<ConfigureGraphics>(system_, this)},
47 graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)},
48 hotkeys_tab{std::make_unique<ConfigureHotkeys>(this)},
49 input_tab{std::make_unique<ConfigureInput>(system_, this)},
50 network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
51 profile_tab{std::make_unique<ConfigureProfileManager>(system_, this)},
52 system_tab{std::make_unique<ConfigureSystem>(system_, this)},
53 ui_tab{std::make_unique<ConfigureUi>(system_, this)}, web_tab{std::make_unique<ConfigureWeb>(
54 this)} {
23 Settings::SetConfiguringGlobal(true); 55 Settings::SetConfiguringGlobal(true);
24 56
25 ui->setupUi(this); 57 ui->setupUi(this);
26 ui->hotkeysTab->Populate(registry); 58
59 ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));
60 ui->tabWidget->addTab(cpu_tab.get(), tr("CPU"));
61 ui->tabWidget->addTab(debug_tab_tab.get(), tr("Debug"));
62 ui->tabWidget->addTab(filesystem_tab.get(), tr("Filesystem"));
63 ui->tabWidget->addTab(general_tab.get(), tr("General"));
64 ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics"));
65 ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("GraphicsAdvanced"));
66 ui->tabWidget->addTab(hotkeys_tab.get(), tr("Hotkeys"));
67 ui->tabWidget->addTab(input_tab.get(), tr("Controls"));
68 ui->tabWidget->addTab(profile_tab.get(), tr("Profiles"));
69 ui->tabWidget->addTab(network_tab.get(), tr("Network"));
70 ui->tabWidget->addTab(system_tab.get(), tr("System"));
71 ui->tabWidget->addTab(ui_tab.get(), tr("Game List"));
72 ui->tabWidget->addTab(web_tab.get(), tr("Web"));
73
74 hotkeys_tab->Populate(registry);
27 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); 75 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
28 76
29 ui->inputTab->Initialize(input_subsystem); 77 input_tab->Initialize(input_subsystem);
30 78
31 ui->generalTab->SetResetCallback([&] { this->close(); }); 79 general_tab->SetResetCallback([&] { this->close(); });
32 80
33 SetConfiguration(); 81 SetConfiguration();
34 PopulateSelectionList(); 82 PopulateSelectionList();
35 83
36 connect(ui->tabWidget, &QTabWidget::currentChanged, this, 84 connect(ui->tabWidget, &QTabWidget::currentChanged, this,
37 [this]() { ui->debugTab->SetCurrentIndex(0); }); 85 [this]() { debug_tab_tab->SetCurrentIndex(0); });
38 connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged); 86 connect(ui_tab.get(), &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
39 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, 87 connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
40 &ConfigureDialog::UpdateVisibleTabs); 88 &ConfigureDialog::UpdateVisibleTabs);
41 89
42 if (Core::System::GetInstance().IsPoweredOn()) { 90 if (system.IsPoweredOn()) {
43 QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply); 91 QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply);
44 connect(apply_button, &QAbstractButton::clicked, this, 92 connect(apply_button, &QAbstractButton::clicked, this,
45 &ConfigureDialog::HandleApplyButtonClicked); 93 &ConfigureDialog::HandleApplyButtonClicked);
@@ -54,21 +102,21 @@ ConfigureDialog::~ConfigureDialog() = default;
54void ConfigureDialog::SetConfiguration() {} 102void ConfigureDialog::SetConfiguration() {}
55 103
56void ConfigureDialog::ApplyConfiguration() { 104void ConfigureDialog::ApplyConfiguration() {
57 ui->generalTab->ApplyConfiguration(); 105 general_tab->ApplyConfiguration();
58 ui->uiTab->ApplyConfiguration(); 106 ui_tab->ApplyConfiguration();
59 ui->systemTab->ApplyConfiguration(); 107 system_tab->ApplyConfiguration();
60 ui->profileManagerTab->ApplyConfiguration(); 108 profile_tab->ApplyConfiguration();
61 ui->filesystemTab->applyConfiguration(); 109 filesystem_tab->applyConfiguration();
62 ui->inputTab->ApplyConfiguration(); 110 input_tab->ApplyConfiguration();
63 ui->hotkeysTab->ApplyConfiguration(registry); 111 hotkeys_tab->ApplyConfiguration(registry);
64 ui->cpuTab->ApplyConfiguration(); 112 cpu_tab->ApplyConfiguration();
65 ui->graphicsTab->ApplyConfiguration(); 113 graphics_tab->ApplyConfiguration();
66 ui->graphicsAdvancedTab->ApplyConfiguration(); 114 graphics_advanced_tab->ApplyConfiguration();
67 ui->audioTab->ApplyConfiguration(); 115 audio_tab->ApplyConfiguration();
68 ui->debugTab->ApplyConfiguration(); 116 debug_tab_tab->ApplyConfiguration();
69 ui->webTab->ApplyConfiguration(); 117 web_tab->ApplyConfiguration();
70 ui->networkTab->ApplyConfiguration(); 118 network_tab->ApplyConfiguration();
71 Core::System::GetInstance().ApplySettings(); 119 system.ApplySettings();
72 Settings::LogSettings(); 120 Settings::LogSettings();
73} 121}
74 122
@@ -102,12 +150,14 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
102 150
103void ConfigureDialog::PopulateSelectionList() { 151void ConfigureDialog::PopulateSelectionList() {
104 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{ 152 const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
105 {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}}, 153 {{tr("General"),
106 {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->networkTab, ui->filesystemTab}}, 154 {general_tab.get(), hotkeys_tab.get(), ui_tab.get(), web_tab.get(), debug_tab_tab.get()}},
107 {tr("CPU"), {ui->cpuTab}}, 155 {tr("System"),
108 {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, 156 {system_tab.get(), profile_tab.get(), network_tab.get(), filesystem_tab.get()}},
109 {tr("Audio"), {ui->audioTab}}, 157 {tr("CPU"), {cpu_tab.get()}},
110 {tr("Controls"), ui->inputTab->GetSubTabs()}}, 158 {tr("Graphics"), {graphics_tab.get(), graphics_advanced_tab.get()}},
159 {tr("Audio"), {audio_tab.get()}},
160 {tr("Controls"), input_tab->GetSubTabs()}},
111 }; 161 };
112 162
113 [[maybe_unused]] const QSignalBlocker blocker(ui->selectorList); 163 [[maybe_unused]] const QSignalBlocker blocker(ui->selectorList);
@@ -142,6 +192,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
142 const auto tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole)); 192 const auto tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole));
143 193
144 for (auto* const tab : tabs) { 194 for (auto* const tab : tabs) {
195 LOG_DEBUG(Frontend, "{}", tab->accessibleName().toStdString());
145 ui->tabWidget->addTab(tab, tab->accessibleName()); 196 ui->tabWidget->addTab(tab, tab->accessibleName());
146 } 197 }
147} 198}
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index abe019635..32ddfd4e0 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -7,6 +7,25 @@
7#include <memory> 7#include <memory>
8#include <QDialog> 8#include <QDialog>
9 9
10namespace Core {
11class System;
12}
13
14class ConfigureAudio;
15class ConfigureCpu;
16class ConfigureDebugTab;
17class ConfigureFilesystem;
18class ConfigureGeneral;
19class ConfigureGraphics;
20class ConfigureGraphicsAdvanced;
21class ConfigureHotkeys;
22class ConfigureInput;
23class ConfigureProfileManager;
24class ConfigureSystem;
25class ConfigureNetwork;
26class ConfigureUi;
27class ConfigureWeb;
28
10class HotkeyRegistry; 29class HotkeyRegistry;
11 30
12namespace InputCommon { 31namespace InputCommon {
@@ -22,7 +41,7 @@ class ConfigureDialog : public QDialog {
22 41
23public: 42public:
24 explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, 43 explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
25 InputCommon::InputSubsystem* input_subsystem); 44 InputCommon::InputSubsystem* input_subsystem, Core::System& system_);
26 ~ConfigureDialog() override; 45 ~ConfigureDialog() override;
27 46
28 void ApplyConfiguration(); 47 void ApplyConfiguration();
@@ -45,4 +64,21 @@ private:
45 64
46 std::unique_ptr<Ui::ConfigureDialog> ui; 65 std::unique_ptr<Ui::ConfigureDialog> ui;
47 HotkeyRegistry& registry; 66 HotkeyRegistry& registry;
67
68 Core::System& system;
69
70 std::unique_ptr<ConfigureAudio> audio_tab;
71 std::unique_ptr<ConfigureCpu> cpu_tab;
72 std::unique_ptr<ConfigureDebugTab> debug_tab_tab;
73 std::unique_ptr<ConfigureFilesystem> filesystem_tab;
74 std::unique_ptr<ConfigureGeneral> general_tab;
75 std::unique_ptr<ConfigureGraphics> graphics_tab;
76 std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab;
77 std::unique_ptr<ConfigureHotkeys> hotkeys_tab;
78 std::unique_ptr<ConfigureInput> input_tab;
79 std::unique_ptr<ConfigureNetwork> network_tab;
80 std::unique_ptr<ConfigureProfileManager> profile_tab;
81 std::unique_ptr<ConfigureSystem> system_tab;
82 std::unique_ptr<ConfigureUi> ui_tab;
83 std::unique_ptr<ConfigureWeb> web_tab;
48}; 84};
diff --git a/src/yuzu/configuration/configure_filesystem.ui b/src/yuzu/configuration/configure_filesystem.ui
index 62b9abc7a..2f6030b5c 100644
--- a/src/yuzu/configuration/configure_filesystem.ui
+++ b/src/yuzu/configuration/configure_filesystem.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Filesystem</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout"> 19 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_3"> 21 <layout class="QVBoxLayout" name="verticalLayout_3">
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 1f647a0d1..7af3ea97e 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -15,8 +15,8 @@
15#include "yuzu/configuration/configure_general.h" 15#include "yuzu/configuration/configure_general.h"
16#include "yuzu/uisettings.h" 16#include "yuzu/uisettings.h"
17 17
18ConfigureGeneral::ConfigureGeneral(QWidget* parent) 18ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent)
19 : QWidget(parent), ui(new Ui::ConfigureGeneral) { 19 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGeneral>()}, system{system_} {
20 ui->setupUi(this); 20 ui->setupUi(this);
21 21
22 SetupPerGameUI(); 22 SetupPerGameUI();
@@ -35,7 +35,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
35ConfigureGeneral::~ConfigureGeneral() = default; 35ConfigureGeneral::~ConfigureGeneral() = default;
36 36
37void ConfigureGeneral::SetConfiguration() { 37void ConfigureGeneral::SetConfiguration() {
38 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 38 const bool runtime_lock = !system.IsPoweredOn();
39 39
40 ui->use_multi_core->setEnabled(runtime_lock); 40 ui->use_multi_core->setEnabled(runtime_lock);
41 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue()); 41 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index c9df37d73..85c1dd4a8 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -8,6 +8,10 @@
8#include <memory> 8#include <memory>
9#include <QWidget> 9#include <QWidget>
10 10
11namespace Core {
12class System;
13}
14
11class ConfigureDialog; 15class ConfigureDialog;
12 16
13namespace ConfigurationShared { 17namespace ConfigurationShared {
@@ -24,19 +28,18 @@ class ConfigureGeneral : public QWidget {
24 Q_OBJECT 28 Q_OBJECT
25 29
26public: 30public:
27 explicit ConfigureGeneral(QWidget* parent = nullptr); 31 explicit ConfigureGeneral(const Core::System& system_, QWidget* parent = nullptr);
28 ~ConfigureGeneral() override; 32 ~ConfigureGeneral() override;
29 33
30 void SetResetCallback(std::function<void()> callback); 34 void SetResetCallback(std::function<void()> callback);
31 void ResetDefaults(); 35 void ResetDefaults();
32 void ApplyConfiguration(); 36 void ApplyConfiguration();
37 void SetConfiguration();
33 38
34private: 39private:
35 void changeEvent(QEvent* event) override; 40 void changeEvent(QEvent* event) override;
36 void RetranslateUI(); 41 void RetranslateUI();
37 42
38 void SetConfiguration();
39
40 void SetupPerGameUI(); 43 void SetupPerGameUI();
41 44
42 std::function<void()> reset_callback; 45 std::function<void()> reset_callback;
@@ -45,4 +48,6 @@ private:
45 48
46 ConfigurationShared::CheckState use_speed_limit; 49 ConfigurationShared::CheckState use_speed_limit;
47 ConfigurationShared::CheckState use_multi_core; 50 ConfigurationShared::CheckState use_multi_core;
51
52 const Core::System& system;
48}; 53};
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 69b6c2d66..f9f0e3ebf 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>General</string>
18 </property>
16 <layout class="QHBoxLayout" name="HorizontalLayout"> 19 <layout class="QHBoxLayout" name="HorizontalLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="VerticalLayout"> 21 <layout class="QVBoxLayout" name="VerticalLayout">
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index c594164be..8e20cc6f3 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -19,8 +19,8 @@
19#include "yuzu/configuration/configuration_shared.h" 19#include "yuzu/configuration/configuration_shared.h"
20#include "yuzu/configuration/configure_graphics.h" 20#include "yuzu/configuration/configure_graphics.h"
21 21
22ConfigureGraphics::ConfigureGraphics(QWidget* parent) 22ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent)
23 : QWidget(parent), ui(new Ui::ConfigureGraphics) { 23 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} {
24 vulkan_device = Settings::values.vulkan_device.GetValue(); 24 vulkan_device = Settings::values.vulkan_device.GetValue();
25 RetrieveVulkanDevices(); 25 RetrieveVulkanDevices();
26 26
@@ -83,7 +83,7 @@ void ConfigureGraphics::UpdateShaderBackendSelection(int backend) {
83ConfigureGraphics::~ConfigureGraphics() = default; 83ConfigureGraphics::~ConfigureGraphics() = default;
84 84
85void ConfigureGraphics::SetConfiguration() { 85void ConfigureGraphics::SetConfiguration() {
86 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 86 const bool runtime_lock = !system.IsPoweredOn();
87 87
88 ui->api_widget->setEnabled(runtime_lock); 88 ui->api_widget->setEnabled(runtime_lock);
89 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock); 89 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 7d7ac329d..1b101c940 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -10,6 +10,10 @@
10#include <QWidget> 10#include <QWidget>
11#include "common/settings.h" 11#include "common/settings.h"
12 12
13namespace Core {
14class System;
15}
16
13namespace ConfigurationShared { 17namespace ConfigurationShared {
14enum class CheckState; 18enum class CheckState;
15} 19}
@@ -22,17 +26,16 @@ class ConfigureGraphics : public QWidget {
22 Q_OBJECT 26 Q_OBJECT
23 27
24public: 28public:
25 explicit ConfigureGraphics(QWidget* parent = nullptr); 29 explicit ConfigureGraphics(const Core::System& system_, QWidget* parent = nullptr);
26 ~ConfigureGraphics() override; 30 ~ConfigureGraphics() override;
27 31
28 void ApplyConfiguration(); 32 void ApplyConfiguration();
33 void SetConfiguration();
29 34
30private: 35private:
31 void changeEvent(QEvent* event) override; 36 void changeEvent(QEvent* event) override;
32 void RetranslateUI(); 37 void RetranslateUI();
33 38
34 void SetConfiguration();
35
36 void UpdateBackgroundColorButton(QColor color); 39 void UpdateBackgroundColorButton(QColor color);
37 void UpdateAPILayout(); 40 void UpdateAPILayout();
38 void UpdateDeviceSelection(int device); 41 void UpdateDeviceSelection(int device);
@@ -56,4 +59,6 @@ private:
56 std::vector<QString> vulkan_devices; 59 std::vector<QString> vulkan_devices;
57 u32 vulkan_device{}; 60 u32 vulkan_device{};
58 Settings::ShaderBackend shader_backend{}; 61 Settings::ShaderBackend shader_backend{};
62
63 const Core::System& system;
59}; 64};
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 1a12cfa4d..beae74344 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -7,12 +7,15 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>437</width> 9 <width>437</width>
10 <height>321</height> 10 <height>482</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Graphics</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_1"> 19 <layout class="QVBoxLayout" name="verticalLayout_1">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_2"> 21 <layout class="QVBoxLayout" name="verticalLayout_2">
@@ -200,17 +203,17 @@
200 <widget class="QComboBox" name="nvdec_emulation"> 203 <widget class="QComboBox" name="nvdec_emulation">
201 <item> 204 <item>
202 <property name="text"> 205 <property name="text">
203 <string>Disabled</string> 206 <string>No Video Output</string>
204 </property> 207 </property>
205 </item> 208 </item>
206 <item> 209 <item>
207 <property name="text"> 210 <property name="text">
208 <string>CPU Decoding</string> 211 <string>CPU Video Decoding</string>
209 </property> 212 </property>
210 </item> 213 </item>
211 <item> 214 <item>
212 <property name="text"> 215 <property name="text">
213 <string>GPU Decoding</string> 216 <string>GPU Video Decoding (Default)</string>
214 </property> 217 </property>
215 </item> 218 </item>
216 </widget> 219 </widget>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index bfd464061..30c5a3595 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -8,8 +8,8 @@
8#include "yuzu/configuration/configuration_shared.h" 8#include "yuzu/configuration/configuration_shared.h"
9#include "yuzu/configuration/configure_graphics_advanced.h" 9#include "yuzu/configuration/configure_graphics_advanced.h"
10 10
11ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent) 11ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(const Core::System& system_, QWidget* parent)
12 : QWidget(parent), ui(new Ui::ConfigureGraphicsAdvanced) { 12 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
13 13
14 ui->setupUi(this); 14 ui->setupUi(this);
15 15
@@ -21,7 +21,7 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent)
21ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; 21ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
22 22
23void ConfigureGraphicsAdvanced::SetConfiguration() { 23void ConfigureGraphicsAdvanced::SetConfiguration() {
24 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 24 const bool runtime_lock = !system.IsPoweredOn();
25 ui->use_vsync->setEnabled(runtime_lock); 25 ui->use_vsync->setEnabled(runtime_lock);
26 ui->use_asynchronous_shaders->setEnabled(runtime_lock); 26 ui->use_asynchronous_shaders->setEnabled(runtime_lock);
27 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); 27 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 13ba4ff6b..0a1724ce4 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace Core {
11class System;
12}
13
10namespace ConfigurationShared { 14namespace ConfigurationShared {
11enum class CheckState; 15enum class CheckState;
12} 16}
@@ -19,17 +23,16 @@ class ConfigureGraphicsAdvanced : public QWidget {
19 Q_OBJECT 23 Q_OBJECT
20 24
21public: 25public:
22 explicit ConfigureGraphicsAdvanced(QWidget* parent = nullptr); 26 explicit ConfigureGraphicsAdvanced(const Core::System& system_, QWidget* parent = nullptr);
23 ~ConfigureGraphicsAdvanced() override; 27 ~ConfigureGraphicsAdvanced() override;
24 28
25 void ApplyConfiguration(); 29 void ApplyConfiguration();
30 void SetConfiguration();
26 31
27private: 32private:
28 void changeEvent(QEvent* event) override; 33 void changeEvent(QEvent* event) override;
29 void RetranslateUI(); 34 void RetranslateUI();
30 35
31 void SetConfiguration();
32
33 void SetupPerGameUI(); 36 void SetupPerGameUI();
34 37
35 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; 38 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
@@ -37,4 +40,6 @@ private:
37 ConfigurationShared::CheckState use_vsync; 40 ConfigurationShared::CheckState use_vsync;
38 ConfigurationShared::CheckState use_asynchronous_shaders; 41 ConfigurationShared::CheckState use_asynchronous_shaders;
39 ConfigurationShared::CheckState use_fast_gpu_time; 42 ConfigurationShared::CheckState use_fast_gpu_time;
43
44 const Core::System& system;
40}; 45};
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index b91abc2f0..d06b45f17 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Advanced</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_1"> 19 <layout class="QVBoxLayout" name="verticalLayout_1">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_2"> 21 <layout class="QVBoxLayout" name="verticalLayout_2">
diff --git a/src/yuzu/configuration/configure_hotkeys.ui b/src/yuzu/configuration/configure_hotkeys.ui
index 6d9f861e3..a6902a5d8 100644
--- a/src/yuzu/configuration/configure_hotkeys.ui
+++ b/src/yuzu/configuration/configure_hotkeys.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Hotkey Settings</string> 14 <string>Hotkey Settings</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Hotkeys</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout"> 19 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 20 <item>
18 <layout class="QHBoxLayout" name="horizontalLayout"> 21 <layout class="QHBoxLayout" name="horizontalLayout">
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 422022d02..1599299db 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -39,12 +39,11 @@ void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
39} 39}
40} // Anonymous namespace 40} // Anonymous namespace
41 41
42void OnDockedModeChanged(bool last_state, bool new_state) { 42void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system) {
43 if (last_state == new_state) { 43 if (last_state == new_state) {
44 return; 44 return;
45 } 45 }
46 46
47 Core::System& system{Core::System::GetInstance()};
48 if (!system.IsPoweredOn()) { 47 if (!system.IsPoweredOn()) {
49 return; 48 return;
50 } 49 }
@@ -66,9 +65,9 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
66 } 65 }
67} 66}
68 67
69ConfigureInput::ConfigureInput(QWidget* parent) 68ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent)
70 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()), 69 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
71 profiles(std::make_unique<InputProfiles>()) { 70 profiles(std::make_unique<InputProfiles>(system_)), system{system_} {
72 ui->setupUi(this); 71 ui->setupUi(this);
73} 72}
74 73
@@ -77,22 +76,22 @@ ConfigureInput::~ConfigureInput() = default;
77void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, 76void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
78 std::size_t max_players) { 77 std::size_t max_players) {
79 player_controllers = { 78 player_controllers = {
80 new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, 79 new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, profiles.get(),
81 profiles.get()), 80 system),
82 new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem, 81 new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem, profiles.get(),
83 profiles.get()), 82 system),
84 new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem, 83 new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem, profiles.get(),
85 profiles.get()), 84 system),
86 new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem, 85 new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem, profiles.get(),
87 profiles.get()), 86 system),
88 new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem, 87 new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem, profiles.get(),
89 profiles.get()), 88 system),
90 new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem, 89 new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem, profiles.get(),
91 profiles.get()), 90 system),
92 new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem, 91 new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem, profiles.get(),
93 profiles.get()), 92 system),
94 new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem, 93 new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem, profiles.get(),
95 profiles.get()), 94 system),
96 }; 95 };
97 96
98 player_tabs = { 97 player_tabs = {
@@ -148,7 +147,8 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
148 ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); 147 ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
149 ui->tabAdvanced->layout()->addWidget(advanced); 148 ui->tabAdvanced->layout()->addWidget(advanced);
150 connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] { 149 connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] {
151 CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem, profiles.get()); 150 CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem, profiles.get(),
151 system);
152 }); 152 });
153 connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { 153 connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] {
154 CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem); 154 CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem);
@@ -204,7 +204,7 @@ void ConfigureInput::ApplyConfiguration() {
204 204
205 const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); 205 const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
206 Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked()); 206 Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
207 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue()); 207 OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system);
208 208
209 Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); 209 Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
210 Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); 210 Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index f4eb0d78b..4cafa3dab 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -11,6 +11,10 @@
11#include <QList> 11#include <QList>
12#include <QWidget> 12#include <QWidget>
13 13
14namespace Core {
15class System;
16}
17
14class QCheckBox; 18class QCheckBox;
15class QString; 19class QString;
16class QTimer; 20class QTimer;
@@ -28,13 +32,13 @@ namespace Ui {
28class ConfigureInput; 32class ConfigureInput;
29} 33}
30 34
31void OnDockedModeChanged(bool last_state, bool new_state); 35void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system);
32 36
33class ConfigureInput : public QWidget { 37class ConfigureInput : public QWidget {
34 Q_OBJECT 38 Q_OBJECT
35 39
36public: 40public:
37 explicit ConfigureInput(QWidget* parent = nullptr); 41 explicit ConfigureInput(Core::System& system_, QWidget* parent = nullptr);
38 ~ConfigureInput() override; 42 ~ConfigureInput() override;
39 43
40 /// Initializes the input dialog with the given input subsystem. 44 /// Initializes the input dialog with the given input subsystem.
@@ -69,4 +73,6 @@ private:
69 std::array<QWidget*, 8> player_tabs; 73 std::array<QWidget*, 8> player_tabs;
70 std::array<QCheckBox*, 8> player_connected; 74 std::array<QCheckBox*, 8> player_connected;
71 ConfigureInputAdvanced* advanced; 75 ConfigureInputAdvanced* advanced;
76
77 Core::System& system;
72}; 78};
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index d20fd86b6..b30f09013 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -88,6 +88,10 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
88 connect(ui->buttonMotionTouch, &QPushButton::clicked, this, 88 connect(ui->buttonMotionTouch, &QPushButton::clicked, this,
89 &ConfigureInputAdvanced::CallMotionTouchConfigDialog); 89 &ConfigureInputAdvanced::CallMotionTouchConfigDialog);
90 90
91#ifndef _WIN32
92 ui->enable_raw_input->setVisible(false);
93#endif
94
91 LoadConfiguration(); 95 LoadConfiguration();
92} 96}
93 97
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 88f4bf388..3aab5d5f8 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -44,8 +44,7 @@ namespace {
44constexpr std::size_t HANDHELD_INDEX = 8; 44constexpr std::size_t HANDHELD_INDEX = 8;
45 45
46void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, 46void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
47 bool connected) { 47 bool connected, Core::System& system) {
48 Core::System& system{Core::System::GetInstance()};
49 if (!system.IsPoweredOn()) { 48 if (!system.IsPoweredOn()) {
50 return; 49 return;
51 } 50 }
@@ -232,11 +231,12 @@ QString AnalogToText(const Common::ParamPackage& param, const std::string& dir)
232ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, 231ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index,
233 QWidget* bottom_row, 232 QWidget* bottom_row,
234 InputCommon::InputSubsystem* input_subsystem_, 233 InputCommon::InputSubsystem* input_subsystem_,
235 InputProfiles* profiles_, bool debug) 234 InputProfiles* profiles_, Core::System& system_,
235 bool debug)
236 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index), 236 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
237 debug(debug), input_subsystem{input_subsystem_}, profiles(profiles_), 237 debug(debug), input_subsystem{input_subsystem_}, profiles(profiles_),
238 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()), 238 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()),
239 bottom_row(bottom_row) { 239 bottom_row(bottom_row), system{system_} {
240 ui->setupUi(this); 240 ui->setupUi(this);
241 241
242 setFocusPolicy(Qt::ClickFocus); 242 setFocusPolicy(Qt::ClickFocus);
@@ -683,7 +683,7 @@ void ConfigureInputPlayer::TryConnectSelectedController() {
683 controller_type == Settings::ControllerType::Handheld; 683 controller_type == Settings::ControllerType::Handheld;
684 // Connect only if handheld is going from disconnected to connected 684 // Connect only if handheld is going from disconnected to connected
685 if (!handheld.connected && handheld_connected) { 685 if (!handheld.connected && handheld_connected) {
686 UpdateController(controller_type, HANDHELD_INDEX, true); 686 UpdateController(controller_type, HANDHELD_INDEX, true, system);
687 } 687 }
688 handheld.connected = handheld_connected; 688 handheld.connected = handheld_connected;
689 } 689 }
@@ -703,7 +703,7 @@ void ConfigureInputPlayer::TryConnectSelectedController() {
703 return; 703 return;
704 } 704 }
705 705
706 UpdateController(controller_type, player_index, true); 706 UpdateController(controller_type, player_index, true, system);
707} 707}
708 708
709void ConfigureInputPlayer::TryDisconnectSelectedController() { 709void ConfigureInputPlayer::TryDisconnectSelectedController() {
@@ -721,7 +721,7 @@ void ConfigureInputPlayer::TryDisconnectSelectedController() {
721 controller_type == Settings::ControllerType::Handheld; 721 controller_type == Settings::ControllerType::Handheld;
722 // Disconnect only if handheld is going from connected to disconnected 722 // Disconnect only if handheld is going from connected to disconnected
723 if (handheld.connected && !handheld_connected) { 723 if (handheld.connected && !handheld_connected) {
724 UpdateController(controller_type, HANDHELD_INDEX, false); 724 UpdateController(controller_type, HANDHELD_INDEX, false, system);
725 } 725 }
726 return; 726 return;
727 } 727 }
@@ -737,7 +737,7 @@ void ConfigureInputPlayer::TryDisconnectSelectedController() {
737 } 737 }
738 738
739 // Disconnect the controller first. 739 // Disconnect the controller first.
740 UpdateController(controller_type, player_index, false); 740 UpdateController(controller_type, player_index, false, system);
741} 741}
742 742
743void ConfigureInputPlayer::showEvent(QShowEvent* event) { 743void ConfigureInputPlayer::showEvent(QShowEvent* event) {
@@ -1017,8 +1017,6 @@ void ConfigureInputPlayer::SetConnectableControllers() {
1017 } 1017 }
1018 }; 1018 };
1019 1019
1020 Core::System& system{Core::System::GetInstance()};
1021
1022 if (!system.IsPoweredOn()) { 1020 if (!system.IsPoweredOn()) {
1023 add_controllers(true); 1021 add_controllers(true);
1024 return; 1022 return;
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index c7d101682..39b44b8a5 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -29,6 +29,10 @@ class QWidget;
29 29
30class InputProfiles; 30class InputProfiles;
31 31
32namespace Core {
33class System;
34}
35
32namespace InputCommon { 36namespace InputCommon {
33class InputSubsystem; 37class InputSubsystem;
34} 38}
@@ -48,7 +52,8 @@ class ConfigureInputPlayer : public QWidget {
48public: 52public:
49 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, 53 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
50 InputCommon::InputSubsystem* input_subsystem_, 54 InputCommon::InputSubsystem* input_subsystem_,
51 InputProfiles* profiles_, bool debug = false); 55 InputProfiles* profiles_, Core::System& system_,
56 bool debug = false);
52 ~ConfigureInputPlayer() override; 57 ~ConfigureInputPlayer() override;
53 58
54 /// Save all button configurations to settings file. 59 /// Save all button configurations to settings file.
@@ -233,4 +238,6 @@ private:
233 /// ConfigureInput widget. On show, add this widget to the main layout. This will change the 238 /// ConfigureInput widget. On show, add this widget to the main layout. This will change the
234 /// parent of the widget to this widget (but thats fine). 239 /// parent of the widget to this widget (but thats fine).
235 QWidget* bottom_row; 240 QWidget* bottom_row;
241
242 Core::System& system;
236}; 243};
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index da328d904..f31f86339 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -1837,7 +1837,7 @@ void PlayerControlPreview::DrawLeftBody(QPainter& p, const QPointF center) {
1837 const float led_size = 5.0f; 1837 const float led_size = 5.0f;
1838 const QPointF led_position = sideview_center + QPointF(0, -36); 1838 const QPointF led_position = sideview_center + QPointF(0, -36);
1839 int led_count = 0; 1839 int led_count = 0;
1840 for (const auto color : led_color) { 1840 for (const auto& color : led_color) {
1841 p.setBrush(color); 1841 p.setBrush(color);
1842 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); 1842 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1843 } 1843 }
@@ -1933,7 +1933,7 @@ void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) {
1933 const float led_size = 5.0f; 1933 const float led_size = 5.0f;
1934 const QPointF led_position = sideview_center + QPointF(0, -36); 1934 const QPointF led_position = sideview_center + QPointF(0, -36);
1935 int led_count = 0; 1935 int led_count = 0;
1936 for (const auto color : led_color) { 1936 for (const auto& color : led_color) {
1937 p.setBrush(color); 1937 p.setBrush(color);
1938 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); 1938 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1939 } 1939 }
diff --git a/src/yuzu/configuration/configure_input_profile_dialog.cpp b/src/yuzu/configuration/configure_input_profile_dialog.cpp
index 1f5cfa75b..cd5a88cea 100644
--- a/src/yuzu/configuration/configure_input_profile_dialog.cpp
+++ b/src/yuzu/configuration/configure_input_profile_dialog.cpp
@@ -2,14 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
5#include "ui_configure_input_profile_dialog.h" 6#include "ui_configure_input_profile_dialog.h"
6#include "yuzu/configuration/configure_input_player.h" 7#include "yuzu/configuration/configure_input_player.h"
7#include "yuzu/configuration/configure_input_profile_dialog.h" 8#include "yuzu/configuration/configure_input_profile_dialog.h"
8 9
9ConfigureInputProfileDialog::ConfigureInputProfileDialog( 10ConfigureInputProfileDialog::ConfigureInputProfileDialog(
10 QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles) 11 QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles,
12 Core::System& system)
11 : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputProfileDialog>()), 13 : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputProfileDialog>()),
12 profile_widget(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, false)) { 14 profile_widget(
15 new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, false)) {
13 ui->setupUi(this); 16 ui->setupUi(this);
14 17
15 ui->controllerLayout->addWidget(profile_widget); 18 ui->controllerLayout->addWidget(profile_widget);
diff --git a/src/yuzu/configuration/configure_input_profile_dialog.h b/src/yuzu/configuration/configure_input_profile_dialog.h
index e6386bdbb..84b1f6d1a 100644
--- a/src/yuzu/configuration/configure_input_profile_dialog.h
+++ b/src/yuzu/configuration/configure_input_profile_dialog.h
@@ -13,6 +13,10 @@ class ConfigureInputPlayer;
13 13
14class InputProfiles; 14class InputProfiles;
15 15
16namespace Core {
17class System;
18}
19
16namespace InputCommon { 20namespace InputCommon {
17class InputSubsystem; 21class InputSubsystem;
18} 22}
@@ -27,7 +31,7 @@ class ConfigureInputProfileDialog : public QDialog {
27public: 31public:
28 explicit ConfigureInputProfileDialog(QWidget* parent, 32 explicit ConfigureInputProfileDialog(QWidget* parent,
29 InputCommon::InputSubsystem* input_subsystem, 33 InputCommon::InputSubsystem* input_subsystem,
30 InputProfiles* profiles); 34 InputProfiles* profiles, Core::System& system);
31 ~ConfigureInputProfileDialog() override; 35 ~ConfigureInputProfileDialog() override;
32 36
33private: 37private:
diff --git a/src/yuzu/configuration/configure_network.cpp b/src/yuzu/configuration/configure_network.cpp
index ae22f1018..7020d2964 100644
--- a/src/yuzu/configuration/configure_network.cpp
+++ b/src/yuzu/configuration/configure_network.cpp
@@ -6,64 +6,25 @@
6#include <QtConcurrent/QtConcurrent> 6#include <QtConcurrent/QtConcurrent>
7#include "common/settings.h" 7#include "common/settings.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/service/bcat/backend/boxcat.h"
10#include "core/network/network_interface.h" 9#include "core/network/network_interface.h"
11#include "ui_configure_network.h" 10#include "ui_configure_network.h"
12#include "yuzu/configuration/configure_network.h" 11#include "yuzu/configuration/configure_network.h"
13 12
14#ifdef YUZU_ENABLE_BOXCAT 13ConfigureNetwork::ConfigureNetwork(const Core::System& system_, QWidget* parent)
15namespace { 14 : QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()), system{system_} {
16QString FormatEventStatusString(const Service::BCAT::EventStatus& status) {
17 QString out;
18
19 if (status.header.has_value()) {
20 out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.header));
21 }
22
23 if (status.events.size() == 1) {
24 out += QStringLiteral("%1<br>").arg(QString::fromStdString(status.events.front()));
25 } else {
26 for (const auto& event : status.events) {
27 out += QStringLiteral("- %1<br>").arg(QString::fromStdString(event));
28 }
29 }
30
31 if (status.footer.has_value()) {
32 out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.footer));
33 }
34
35 return out;
36}
37} // Anonymous namespace
38#endif
39
40ConfigureNetwork::ConfigureNetwork(QWidget* parent)
41 : QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()) {
42 ui->setupUi(this); 15 ui->setupUi(this);
43 16
44 ui->bcat_source->addItem(QStringLiteral("None"));
45 ui->bcat_empty_label->setHidden(true);
46 ui->bcat_empty_header->setHidden(true);
47
48#ifdef YUZU_ENABLE_BOXCAT
49 ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
50#endif
51
52 ui->network_interface->addItem(tr("None")); 17 ui->network_interface->addItem(tr("None"));
53 for (const auto& iface : Network::GetAvailableNetworkInterfaces()) { 18 for (const auto& iface : Network::GetAvailableNetworkInterfaces()) {
54 ui->network_interface->addItem(QString::fromStdString(iface.name)); 19 ui->network_interface->addItem(QString::fromStdString(iface.name));
55 } 20 }
56 21
57 connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
58 &ConfigureNetwork::OnBCATImplChanged);
59
60 this->SetConfiguration(); 22 this->SetConfiguration();
61} 23}
62 24
63ConfigureNetwork::~ConfigureNetwork() = default; 25ConfigureNetwork::~ConfigureNetwork() = default;
64 26
65void ConfigureNetwork::ApplyConfiguration() { 27void ConfigureNetwork::ApplyConfiguration() {
66 Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString();
67 Settings::values.network_interface = ui->network_interface->currentText().toStdString(); 28 Settings::values.network_interface = ui->network_interface->currentText().toStdString();
68} 29}
69 30
@@ -72,88 +33,10 @@ void ConfigureNetwork::RetranslateUi() {
72} 33}
73 34
74void ConfigureNetwork::SetConfiguration() { 35void ConfigureNetwork::SetConfiguration() {
75 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 36 const bool runtime_lock = !system.IsPoweredOn();
76
77 const int index =
78 ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
79 ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
80 37
81 const std::string& network_interface = Settings::values.network_interface.GetValue(); 38 const std::string& network_interface = Settings::values.network_interface.GetValue();
82 39
83 ui->network_interface->setCurrentText(QString::fromStdString(network_interface)); 40 ui->network_interface->setCurrentText(QString::fromStdString(network_interface));
84 ui->network_interface->setEnabled(runtime_lock); 41 ui->network_interface->setEnabled(runtime_lock);
85} 42}
86
87std::pair<QString, QString> ConfigureNetwork::BCATDownloadEvents() {
88#ifdef YUZU_ENABLE_BOXCAT
89 std::optional<std::string> global;
90 std::map<std::string, Service::BCAT::EventStatus> map;
91 const auto res = Service::BCAT::Boxcat::GetStatus(global, map);
92
93 switch (res) {
94 case Service::BCAT::Boxcat::StatusResult::Success:
95 break;
96 case Service::BCAT::Boxcat::StatusResult::Offline:
97 return {QString{},
98 tr("The boxcat service is offline or you are not connected to the internet.")};
99 case Service::BCAT::Boxcat::StatusResult::ParseError:
100 return {QString{},
101 tr("There was an error while processing the boxcat event data. Contact the yuzu "
102 "developers.")};
103 case Service::BCAT::Boxcat::StatusResult::BadClientVersion:
104 return {QString{},
105 tr("The version of yuzu you are using is either too new or too old for the server. "
106 "Try updating to the latest official release of yuzu.")};
107 }
108
109 if (map.empty()) {
110 return {QStringLiteral("Current Boxcat Events"),
111 tr("There are currently no events on boxcat.")};
112 }
113
114 QString out;
115
116 if (global.has_value()) {
117 out += QStringLiteral("%1<br>").arg(QString::fromStdString(*global));
118 }
119
120 for (const auto& [key, value] : map) {
121 out += QStringLiteral("%1<b>%2</b><br>%3")
122 .arg(out.isEmpty() ? QString{} : QStringLiteral("<br>"))
123 .arg(QString::fromStdString(key))
124 .arg(FormatEventStatusString(value));
125 }
126 return {tr("Current Boxcat Events"), std::move(out)};
127#else
128 return {tr("Current Boxcat Events"), tr("There are currently no events on boxcat.")};
129#endif
130}
131
132void ConfigureNetwork::OnBCATImplChanged() {
133#ifdef YUZU_ENABLE_BOXCAT
134 const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
135 ui->bcat_empty_header->setHidden(!boxcat);
136 ui->bcat_empty_label->setHidden(!boxcat);
137 ui->bcat_empty_header->setText(QString{});
138 ui->bcat_empty_label->setText(tr("Yuzu is retrieving the latest boxcat status..."));
139
140 if (!boxcat)
141 return;
142
143 const auto future = QtConcurrent::run([this] { return BCATDownloadEvents(); });
144
145 watcher.setFuture(future);
146 connect(&watcher, &QFutureWatcher<std::pair<QString, QString>>::finished, this,
147 [this] { OnUpdateBCATEmptyLabel(watcher.result()); });
148#endif
149}
150
151void ConfigureNetwork::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
152#ifdef YUZU_ENABLE_BOXCAT
153 const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
154 if (boxcat) {
155 ui->bcat_empty_header->setText(string.first);
156 ui->bcat_empty_label->setText(string.second);
157 }
158#endif
159}
diff --git a/src/yuzu/configuration/configure_network.h b/src/yuzu/configuration/configure_network.h
index 442b68e6b..8507c62eb 100644
--- a/src/yuzu/configuration/configure_network.h
+++ b/src/yuzu/configuration/configure_network.h
@@ -16,7 +16,7 @@ class ConfigureNetwork : public QWidget {
16 Q_OBJECT 16 Q_OBJECT
17 17
18public: 18public:
19 explicit ConfigureNetwork(QWidget* parent = nullptr); 19 explicit ConfigureNetwork(const Core::System& system_, QWidget* parent = nullptr);
20 ~ConfigureNetwork() override; 20 ~ConfigureNetwork() override;
21 21
22 void ApplyConfiguration(); 22 void ApplyConfiguration();
@@ -25,10 +25,7 @@ public:
25private: 25private:
26 void SetConfiguration(); 26 void SetConfiguration();
27 27
28 std::pair<QString, QString> BCATDownloadEvents();
29 void OnBCATImplChanged();
30 void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string);
31
32 std::unique_ptr<Ui::ConfigureNetwork> ui; 28 std::unique_ptr<Ui::ConfigureNetwork> ui;
33 QFutureWatcher<std::pair<QString, QString>> watcher{this}; 29
30 const Core::System& system;
34}; 31};
diff --git a/src/yuzu/configuration/configure_network.ui b/src/yuzu/configuration/configure_network.ui
index 5f9b7e97b..f10e973b1 100644
--- a/src/yuzu/configuration/configure_network.ui
+++ b/src/yuzu/configuration/configure_network.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Network</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout"> 19 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_3"> 21 <layout class="QVBoxLayout" name="verticalLayout_3">
@@ -35,92 +38,6 @@
35 </layout> 38 </layout>
36 </widget> 39 </widget>
37 </item> 40 </item>
38 <item>
39 <widget class="QGroupBox" name="groupBox">
40 <property name="title">
41 <string>BCAT</string>
42 </property>
43 <layout class="QGridLayout" name="gridLayout">
44 <item row="3" column="0">
45 <widget class="QLabel" name="bcat_empty_header">
46 <property name="text">
47 <string/>
48 </property>
49 <property name="alignment">
50 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
51 </property>
52 <property name="wordWrap">
53 <bool>true</bool>
54 </property>
55 </widget>
56 </item>
57 <item row="0" column="0">
58 <widget class="QLabel" name="label">
59 <property name="maximumSize">
60 <size>
61 <width>16777215</width>
62 <height>16777215</height>
63 </size>
64 </property>
65 <property name="text">
66 <string>BCAT Backend</string>
67 </property>
68 </widget>
69 </item>
70 <item row="1" column="1" colspan="2">
71 <widget class="QLabel" name="label_2">
72 <property name="maximumSize">
73 <size>
74 <width>260</width>
75 <height>16777215</height>
76 </size>
77 </property>
78 <property name="text">
79 <string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
80 </property>
81 <property name="wordWrap">
82 <bool>true</bool>
83 </property>
84 </widget>
85 </item>
86 <item row="2" column="1" colspan="2">
87 <widget class="QLabel" name="label_3">
88 <property name="text">
89 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
90 </property>
91 <property name="openExternalLinks">
92 <bool>true</bool>
93 </property>
94 </widget>
95 </item>
96 <item row="0" column="1" colspan="2">
97 <widget class="QComboBox" name="bcat_source"/>
98 </item>
99 <item row="3" column="1" colspan="2">
100 <widget class="QLabel" name="bcat_empty_label">
101 <property name="enabled">
102 <bool>true</bool>
103 </property>
104 <property name="maximumSize">
105 <size>
106 <width>260</width>
107 <height>16777215</height>
108 </size>
109 </property>
110 <property name="text">
111 <string/>
112 </property>
113 <property name="alignment">
114 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
115 </property>
116 <property name="wordWrap">
117 <bool>true</bool>
118 </property>
119 </widget>
120 </item>
121 </layout>
122 </widget>
123 </item>
124 </layout> 41 </layout>
125 </item> 42 </item>
126 <item> 43 <item>
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index 8c00eec59..1031399e1 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -30,32 +30,56 @@
30#include "core/loader/loader.h" 30#include "core/loader/loader.h"
31#include "ui_configure_per_game.h" 31#include "ui_configure_per_game.h"
32#include "yuzu/configuration/config.h" 32#include "yuzu/configuration/config.h"
33#include "yuzu/configuration/configure_audio.h"
34#include "yuzu/configuration/configure_cpu.h"
35#include "yuzu/configuration/configure_general.h"
36#include "yuzu/configuration/configure_graphics.h"
37#include "yuzu/configuration/configure_graphics_advanced.h"
33#include "yuzu/configuration/configure_input.h" 38#include "yuzu/configuration/configure_input.h"
34#include "yuzu/configuration/configure_per_game.h" 39#include "yuzu/configuration/configure_per_game.h"
40#include "yuzu/configuration/configure_per_game_addons.h"
41#include "yuzu/configuration/configure_system.h"
35#include "yuzu/uisettings.h" 42#include "yuzu/uisettings.h"
36#include "yuzu/util/util.h" 43#include "yuzu/util/util.h"
37 44
38ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, const std::string& file_name) 45ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, const std::string& file_name,
39 : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) { 46 Core::System& system_)
47 : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()),
48 title_id(title_id), system{system_}, addons_tab{std::make_unique<ConfigurePerGameAddons>(
49 system_, this)},
50 audio_tab{std::make_unique<ConfigureAudio>(system_, this)},
51 cpu_tab{std::make_unique<ConfigureCpu>(system_, this)},
52 general_tab{std::make_unique<ConfigureGeneral>(system_, this)},
53 graphics_tab{std::make_unique<ConfigureGraphics>(system_, this)},
54 graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)},
55 system_tab{std::make_unique<ConfigureSystem>(system_, this)} {
40 const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); 56 const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name));
41 const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) 57 const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename())
42 : fmt::format("{:016X}", title_id); 58 : fmt::format("{:016X}", title_id);
43 game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig); 59 game_config =
44 60 std::make_unique<Config>(system, config_file_name, Config::ConfigType::PerGameConfig);
45 Settings::SetConfiguringGlobal(false);
46 61
47 ui->setupUi(this); 62 ui->setupUi(this);
63
64 ui->tabWidget->addTab(addons_tab.get(), tr("Add-Ons"));
65 ui->tabWidget->addTab(general_tab.get(), tr("General"));
66 ui->tabWidget->addTab(system_tab.get(), tr("System"));
67 ui->tabWidget->addTab(cpu_tab.get(), tr("CPU"));
68 ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics"));
69 ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("GraphicsAdvanced"));
70 ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));
71
48 setFocusPolicy(Qt::ClickFocus); 72 setFocusPolicy(Qt::ClickFocus);
49 setWindowTitle(tr("Properties")); 73 setWindowTitle(tr("Properties"));
50 // remove Help question mark button from the title bar 74 // remove Help question mark button from the title bar
51 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); 75 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
52 76
53 ui->addonsTab->SetTitleId(title_id); 77 addons_tab->SetTitleId(title_id);
54 78
55 scene = new QGraphicsScene; 79 scene = new QGraphicsScene;
56 ui->icon_view->setScene(scene); 80 ui->icon_view->setScene(scene);
57 81
58 if (Core::System::GetInstance().IsPoweredOn()) { 82 if (system.IsPoweredOn()) {
59 QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply); 83 QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply);
60 connect(apply_button, &QAbstractButton::clicked, this, 84 connect(apply_button, &QAbstractButton::clicked, this,
61 &ConfigurePerGame::HandleApplyButtonClicked); 85 &ConfigurePerGame::HandleApplyButtonClicked);
@@ -67,15 +91,15 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, const std::str
67ConfigurePerGame::~ConfigurePerGame() = default; 91ConfigurePerGame::~ConfigurePerGame() = default;
68 92
69void ConfigurePerGame::ApplyConfiguration() { 93void ConfigurePerGame::ApplyConfiguration() {
70 ui->addonsTab->ApplyConfiguration(); 94 addons_tab->ApplyConfiguration();
71 ui->generalTab->ApplyConfiguration(); 95 general_tab->ApplyConfiguration();
72 ui->cpuTab->ApplyConfiguration(); 96 cpu_tab->ApplyConfiguration();
73 ui->systemTab->ApplyConfiguration(); 97 system_tab->ApplyConfiguration();
74 ui->graphicsTab->ApplyConfiguration(); 98 graphics_tab->ApplyConfiguration();
75 ui->graphicsAdvancedTab->ApplyConfiguration(); 99 graphics_advanced_tab->ApplyConfiguration();
76 ui->audioTab->ApplyConfiguration(); 100 audio_tab->ApplyConfiguration();
77 101
78 Core::System::GetInstance().ApplySettings(); 102 system.ApplySettings();
79 Settings::LogSettings(); 103 Settings::LogSettings();
80 104
81 game_config->Save(); 105 game_config->Save();
@@ -108,12 +132,11 @@ void ConfigurePerGame::LoadConfiguration() {
108 return; 132 return;
109 } 133 }
110 134
111 ui->addonsTab->LoadFromFile(file); 135 addons_tab->LoadFromFile(file);
112 136
113 ui->display_title_id->setText( 137 ui->display_title_id->setText(
114 QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper()); 138 QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper());
115 139
116 auto& system = Core::System::GetInstance();
117 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), 140 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
118 system.GetContentProvider()}; 141 system.GetContentProvider()};
119 const auto control = pm.GetControlMetadata(); 142 const auto control = pm.GetControlMetadata();
@@ -164,4 +187,11 @@ void ConfigurePerGame::LoadConfiguration() {
164 187
165 const auto valueText = ReadableByteSize(file->GetSize()); 188 const auto valueText = ReadableByteSize(file->GetSize());
166 ui->display_size->setText(valueText); 189 ui->display_size->setText(valueText);
190
191 general_tab->SetConfiguration();
192 cpu_tab->SetConfiguration();
193 system_tab->SetConfiguration();
194 graphics_tab->SetConfiguration();
195 graphics_advanced_tab->SetConfiguration();
196 audio_tab->SetConfiguration();
167} 197}
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index a2d0211a3..c1a57d87b 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -14,6 +14,18 @@
14#include "core/file_sys/vfs_types.h" 14#include "core/file_sys/vfs_types.h"
15#include "yuzu/configuration/config.h" 15#include "yuzu/configuration/config.h"
16 16
17namespace Core {
18class System;
19}
20
21class ConfigurePerGameAddons;
22class ConfigureAudio;
23class ConfigureCpu;
24class ConfigureGeneral;
25class ConfigureGraphics;
26class ConfigureGraphicsAdvanced;
27class ConfigureSystem;
28
17class QGraphicsScene; 29class QGraphicsScene;
18class QStandardItem; 30class QStandardItem;
19class QStandardItemModel; 31class QStandardItemModel;
@@ -29,7 +41,8 @@ class ConfigurePerGame : public QDialog {
29 41
30public: 42public:
31 // Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263 43 // Cannot use std::filesystem::path due to https://bugreports.qt.io/browse/QTBUG-73263
32 explicit ConfigurePerGame(QWidget* parent, u64 title_id, const std::string& file_name); 44 explicit ConfigurePerGame(QWidget* parent, u64 title_id, const std::string& file_name,
45 Core::System& system_);
33 ~ConfigurePerGame() override; 46 ~ConfigurePerGame() override;
34 47
35 /// Save all button configurations to settings file 48 /// Save all button configurations to settings file
@@ -52,4 +65,14 @@ private:
52 QGraphicsScene* scene; 65 QGraphicsScene* scene;
53 66
54 std::unique_ptr<Config> game_config; 67 std::unique_ptr<Config> game_config;
68
69 Core::System& system;
70
71 std::unique_ptr<ConfigurePerGameAddons> addons_tab;
72 std::unique_ptr<ConfigureAudio> audio_tab;
73 std::unique_ptr<ConfigureCpu> cpu_tab;
74 std::unique_ptr<ConfigureGeneral> general_tab;
75 std::unique_ptr<ConfigureGraphics> graphics_tab;
76 std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab;
77 std::unique_ptr<ConfigureSystem> system_tab;
55}; 78};
diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui
index 7da14146b..60efdbf21 100644
--- a/src/yuzu/configuration/configure_per_game.ui
+++ b/src/yuzu/configuration/configure_per_game.ui
@@ -7,12 +7,13 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>900</width> 9 <width>900</width>
10 <height>600</height> 10 <height>630</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="minimumSize"> 13 <property name="minimumSize">
14 <size> 14 <size>
15 <width>900</width> 15 <width>900</width>
16 <height>0</height>
16 </size> 17 </size>
17 </property> 18 </property>
18 <property name="windowTitle"> 19 <property name="windowTitle">
@@ -214,7 +215,7 @@
214 <bool>true</bool> 215 <bool>true</bool>
215 </property> 216 </property>
216 <property name="currentIndex"> 217 <property name="currentIndex">
217 <number>0</number> 218 <number>-1</number>
218 </property> 219 </property>
219 <property name="usesScrollButtons"> 220 <property name="usesScrollButtons">
220 <bool>true</bool> 221 <bool>true</bool>
@@ -225,41 +226,6 @@
225 <property name="tabsClosable"> 226 <property name="tabsClosable">
226 <bool>false</bool> 227 <bool>false</bool>
227 </property> 228 </property>
228 <widget class="ConfigurePerGameAddons" name="addonsTab">
229 <attribute name="title">
230 <string>Add-Ons</string>
231 </attribute>
232 </widget>
233 <widget class="ConfigureGeneral" name="generalTab">
234 <attribute name="title">
235 <string>General</string>
236 </attribute>
237 </widget>
238 <widget class="ConfigureSystem" name="systemTab">
239 <attribute name="title">
240 <string>System</string>
241 </attribute>
242 </widget>
243 <widget class="ConfigureCpu" name="cpuTab">
244 <attribute name="title">
245 <string>CPU</string>
246 </attribute>
247 </widget>
248 <widget class="ConfigureGraphics" name="graphicsTab">
249 <attribute name="title">
250 <string>Graphics</string>
251 </attribute>
252 </widget>
253 <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
254 <attribute name="title">
255 <string>Adv. Graphics</string>
256 </attribute>
257 </widget>
258 <widget class="ConfigureAudio" name="audioTab">
259 <attribute name="title">
260 <string>Audio</string>
261 </attribute>
262 </widget>
263 </widget> 229 </widget>
264 </item> 230 </item>
265 </layout> 231 </layout>
@@ -284,50 +250,6 @@
284 </item> 250 </item>
285 </layout> 251 </layout>
286 </widget> 252 </widget>
287 <customwidgets>
288 <customwidget>
289 <class>ConfigureGeneral</class>
290 <extends>QWidget</extends>
291 <header>configuration/configure_general.h</header>
292 <container>1</container>
293 </customwidget>
294 <customwidget>
295 <class>ConfigureSystem</class>
296 <extends>QWidget</extends>
297 <header>configuration/configure_system.h</header>
298 <container>1</container>
299 </customwidget>
300 <customwidget>
301 <class>ConfigureAudio</class>
302 <extends>QWidget</extends>
303 <header>configuration/configure_audio.h</header>
304 <container>1</container>
305 </customwidget>
306 <customwidget>
307 <class>ConfigureGraphics</class>
308 <extends>QWidget</extends>
309 <header>configuration/configure_graphics.h</header>
310 <container>1</container>
311 </customwidget>
312 <customwidget>
313 <class>ConfigureGraphicsAdvanced</class>
314 <extends>QWidget</extends>
315 <header>configuration/configure_graphics_advanced.h</header>
316 <container>1</container>
317 </customwidget>
318 <customwidget>
319 <class>ConfigurePerGameAddons</class>
320 <extends>QWidget</extends>
321 <header>configuration/configure_per_game_addons.h</header>
322 <container>1</container>
323 </customwidget>
324 <customwidget>
325 <class>ConfigureCpu</class>
326 <extends>QWidget</extends>
327 <header>configuration/configure_cpu.h</header>
328 <container>1</container>
329 </customwidget>
330 </customwidgets>
331 <resources/> 253 <resources/>
332 <connections> 254 <connections>
333 <connection> 255 <connection>
@@ -335,12 +257,32 @@
335 <signal>accepted()</signal> 257 <signal>accepted()</signal>
336 <receiver>ConfigurePerGame</receiver> 258 <receiver>ConfigurePerGame</receiver>
337 <slot>accept()</slot> 259 <slot>accept()</slot>
260 <hints>
261 <hint type="sourcelabel">
262 <x>20</x>
263 <y>20</y>
264 </hint>
265 <hint type="destinationlabel">
266 <x>20</x>
267 <y>20</y>
268 </hint>
269 </hints>
338 </connection> 270 </connection>
339 <connection> 271 <connection>
340 <sender>buttonBox</sender> 272 <sender>buttonBox</sender>
341 <signal>rejected()</signal> 273 <signal>rejected()</signal>
342 <receiver>ConfigurePerGame</receiver> 274 <receiver>ConfigurePerGame</receiver>
343 <slot>reject()</slot> 275 <slot>reject()</slot>
276 <hints>
277 <hint type="sourcelabel">
278 <x>20</x>
279 <y>20</y>
280 </hint>
281 <hint type="destinationlabel">
282 <x>20</x>
283 <y>20</y>
284 </hint>
285 </hints>
344 </connection> 286 </connection>
345 </connections> 287 </connections>
346</ui> 288</ui>
diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp
index ebb0f411c..65e615963 100644
--- a/src/yuzu/configuration/configure_per_game_addons.cpp
+++ b/src/yuzu/configuration/configure_per_game_addons.cpp
@@ -26,8 +26,8 @@
26#include "yuzu/uisettings.h" 26#include "yuzu/uisettings.h"
27#include "yuzu/util/util.h" 27#include "yuzu/util/util.h"
28 28
29ConfigurePerGameAddons::ConfigurePerGameAddons(QWidget* parent) 29ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* parent)
30 : QWidget(parent), ui(new Ui::ConfigurePerGameAddons) { 30 : QWidget(parent), ui{std::make_unique<Ui::ConfigurePerGameAddons>()}, system{system_} {
31 ui->setupUi(this); 31 ui->setupUi(this);
32 32
33 layout = new QVBoxLayout; 33 layout = new QVBoxLayout;
@@ -58,7 +58,7 @@ ConfigurePerGameAddons::ConfigurePerGameAddons(QWidget* parent)
58 58
59 ui->scrollArea->setLayout(layout); 59 ui->scrollArea->setLayout(layout);
60 60
61 ui->scrollArea->setEnabled(!Core::System::GetInstance().IsPoweredOn()); 61 ui->scrollArea->setEnabled(!system.IsPoweredOn());
62 62
63 connect(item_model, &QStandardItemModel::itemChanged, 63 connect(item_model, &QStandardItemModel::itemChanged,
64 [] { UISettings::values.is_game_list_reload_pending.exchange(true); }); 64 [] { UISettings::values.is_game_list_reload_pending.exchange(true); });
@@ -112,7 +112,6 @@ void ConfigurePerGameAddons::LoadConfiguration() {
112 return; 112 return;
113 } 113 }
114 114
115 auto& system = Core::System::GetInstance();
116 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), 115 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
117 system.GetContentProvider()}; 116 system.GetContentProvider()};
118 const auto loader = Loader::GetLoader(system, file); 117 const auto loader = Loader::GetLoader(system, file);
diff --git a/src/yuzu/configuration/configure_per_game_addons.h b/src/yuzu/configuration/configure_per_game_addons.h
index a00ec3539..24b017494 100644
--- a/src/yuzu/configuration/configure_per_game_addons.h
+++ b/src/yuzu/configuration/configure_per_game_addons.h
@@ -11,6 +11,10 @@
11 11
12#include "core/file_sys/vfs_types.h" 12#include "core/file_sys/vfs_types.h"
13 13
14namespace Core {
15class System;
16}
17
14class QGraphicsScene; 18class QGraphicsScene;
15class QStandardItem; 19class QStandardItem;
16class QStandardItemModel; 20class QStandardItemModel;
@@ -25,7 +29,7 @@ class ConfigurePerGameAddons : public QWidget {
25 Q_OBJECT 29 Q_OBJECT
26 30
27public: 31public:
28 explicit ConfigurePerGameAddons(QWidget* parent = nullptr); 32 explicit ConfigurePerGameAddons(Core::System& system_, QWidget* parent = nullptr);
29 ~ConfigurePerGameAddons() override; 33 ~ConfigurePerGameAddons() override;
30 34
31 /// Save all button configurations to settings file 35 /// Save all button configurations to settings file
@@ -50,4 +54,6 @@ private:
50 QStandardItemModel* item_model; 54 QStandardItemModel* item_model;
51 55
52 std::vector<QList<QStandardItem*>> list_items; 56 std::vector<QList<QStandardItem*>> list_items;
57
58 Core::System& system;
53}; 59};
diff --git a/src/yuzu/configuration/configure_per_game_addons.ui b/src/yuzu/configuration/configure_per_game_addons.ui
index aefdebfcd..f9cf6f2c3 100644
--- a/src/yuzu/configuration/configure_per_game_addons.ui
+++ b/src/yuzu/configuration/configure_per_game_addons.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleDescription">
17 <string>Add-Ons</string>
18 </property>
16 <layout class="QGridLayout" name="gridLayout"> 19 <layout class="QGridLayout" name="gridLayout">
17 <item row="0" column="0"> 20 <item row="0" column="0">
18 <widget class="QScrollArea" name="scrollArea"> 21 <widget class="QScrollArea" name="scrollArea">
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index ac849b01d..99d5f4686 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -76,9 +76,9 @@ QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_t
76} 76}
77} // Anonymous namespace 77} // Anonymous namespace
78 78
79ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent) 79ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QWidget* parent)
80 : QWidget(parent), ui(new Ui::ConfigureProfileManager), 80 : QWidget(parent), ui{std::make_unique<Ui::ConfigureProfileManager>()},
81 profile_manager(std::make_unique<Service::Account::ProfileManager>()) { 81 profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_} {
82 ui->setupUi(this); 82 ui->setupUi(this);
83 83
84 tree_view = new QTreeView; 84 tree_view = new QTreeView;
@@ -137,7 +137,7 @@ void ConfigureProfileManager::RetranslateUI() {
137} 137}
138 138
139void ConfigureProfileManager::SetConfiguration() { 139void ConfigureProfileManager::SetConfiguration() {
140 enabled = !Core::System::GetInstance().IsPoweredOn(); 140 enabled = !system.IsPoweredOn();
141 item_model->removeRows(0, item_model->rowCount()); 141 item_model->removeRows(0, item_model->rowCount());
142 list_items.clear(); 142 list_items.clear();
143 143
@@ -180,8 +180,6 @@ void ConfigureProfileManager::ApplyConfiguration() {
180 if (!enabled) { 180 if (!enabled) {
181 return; 181 return;
182 } 182 }
183
184 Core::System::GetInstance().ApplySettings();
185} 183}
186 184
187void ConfigureProfileManager::SelectUser(const QModelIndex& index) { 185void ConfigureProfileManager::SelectUser(const QModelIndex& index) {
diff --git a/src/yuzu/configuration/configure_profile_manager.h b/src/yuzu/configuration/configure_profile_manager.h
index 0a9bca2a6..575cb89d5 100644
--- a/src/yuzu/configuration/configure_profile_manager.h
+++ b/src/yuzu/configuration/configure_profile_manager.h
@@ -9,6 +9,10 @@
9#include <QList> 9#include <QList>
10#include <QWidget> 10#include <QWidget>
11 11
12namespace Core {
13class System;
14}
15
12class QGraphicsScene; 16class QGraphicsScene;
13class QStandardItem; 17class QStandardItem;
14class QStandardItemModel; 18class QStandardItemModel;
@@ -27,7 +31,7 @@ class ConfigureProfileManager : public QWidget {
27 Q_OBJECT 31 Q_OBJECT
28 32
29public: 33public:
30 explicit ConfigureProfileManager(QWidget* parent = nullptr); 34 explicit ConfigureProfileManager(const Core::System& system_, QWidget* parent = nullptr);
31 ~ConfigureProfileManager() override; 35 ~ConfigureProfileManager() override;
32 36
33 void ApplyConfiguration(); 37 void ApplyConfiguration();
@@ -58,4 +62,6 @@ private:
58 bool enabled = false; 62 bool enabled = false;
59 63
60 std::unique_ptr<Service::Account::ProfileManager> profile_manager; 64 std::unique_ptr<Service::Account::ProfileManager> profile_manager;
65
66 const Core::System& system;
61}; 67};
diff --git a/src/yuzu/configuration/configure_profile_manager.ui b/src/yuzu/configuration/configure_profile_manager.ui
index dedba4998..cfe7478c8 100644
--- a/src/yuzu/configuration/configure_profile_manager.ui
+++ b/src/yuzu/configuration/configure_profile_manager.ui
@@ -6,13 +6,16 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>366</width> 9 <width>390</width>
10 <height>483</height> 10 <height>483</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Profiles</string>
18 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout"> 19 <layout class="QHBoxLayout" name="horizontalLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="verticalLayout"> 21 <layout class="QVBoxLayout" name="verticalLayout">
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 99a5df241..56c762d64 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -12,12 +12,13 @@
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/settings.h" 13#include "common/settings.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/hle/service/time/time.h" 15#include "core/hle/service/time/time_manager.h"
16#include "ui_configure_system.h" 16#include "ui_configure_system.h"
17#include "yuzu/configuration/configuration_shared.h" 17#include "yuzu/configuration/configuration_shared.h"
18#include "yuzu/configuration/configure_system.h" 18#include "yuzu/configuration/configure_system.h"
19 19
20ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) { 20ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
21 : QWidget(parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} {
21 ui->setupUi(this); 22 ui->setupUi(this);
22 connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, 23 connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
23 &ConfigureSystem::RefreshConsoleID); 24 &ConfigureSystem::RefreshConsoleID);
@@ -59,13 +60,12 @@ void ConfigureSystem::RetranslateUI() {
59} 60}
60 61
61void ConfigureSystem::SetConfiguration() { 62void ConfigureSystem::SetConfiguration() {
62 enabled = !Core::System::GetInstance().IsPoweredOn(); 63 enabled = !system.IsPoweredOn();
63 const auto rng_seed = 64 const auto rng_seed =
64 QStringLiteral("%1") 65 QStringLiteral("%1")
65 .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'}) 66 .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
66 .toUpper(); 67 .toUpper();
67 const auto rtc_time = Settings::values.custom_rtc.value_or( 68 const auto rtc_time = Settings::values.custom_rtc.value_or(QDateTime::currentSecsSinceEpoch());
68 std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
69 69
70 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value()); 70 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
71 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() && 71 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
@@ -74,7 +74,7 @@ void ConfigureSystem::SetConfiguration() {
74 74
75 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value()); 75 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
76 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value()); 76 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
77 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); 77 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time));
78 78
79 if (Settings::IsConfiguringGlobal()) { 79 if (Settings::IsConfiguringGlobal()) {
80 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); 80 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
@@ -103,16 +103,13 @@ void ConfigureSystem::SetConfiguration() {
103void ConfigureSystem::ReadSystemSettings() {} 103void ConfigureSystem::ReadSystemSettings() {}
104 104
105void ConfigureSystem::ApplyConfiguration() { 105void ConfigureSystem::ApplyConfiguration() {
106 auto& system = Core::System::GetInstance();
107
108 // Allow setting custom RTC even if system is powered on, 106 // Allow setting custom RTC even if system is powered on,
109 // to allow in-game time to be fast forwarded 107 // to allow in-game time to be fast forwarded
110 if (Settings::IsConfiguringGlobal()) { 108 if (Settings::IsConfiguringGlobal()) {
111 if (ui->custom_rtc_checkbox->isChecked()) { 109 if (ui->custom_rtc_checkbox->isChecked()) {
112 Settings::values.custom_rtc = 110 Settings::values.custom_rtc = ui->custom_rtc_edit->dateTime().toSecsSinceEpoch();
113 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch());
114 if (system.IsPoweredOn()) { 111 if (system.IsPoweredOn()) {
115 const s64 posix_time{Settings::values.custom_rtc->count() + 112 const s64 posix_time{*Settings::values.custom_rtc +
116 Service::Time::TimeManager::GetExternalTimeZoneOffset()}; 113 Service::Time::TimeManager::GetExternalTimeZoneOffset()};
117 system.GetTimeManager().UpdateLocalSystemClockTime(posix_time); 114 system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
118 } 115 }
@@ -162,8 +159,6 @@ void ConfigureSystem::ApplyConfiguration() {
162 break; 159 break;
163 } 160 }
164 } 161 }
165
166 system.ApplySettings();
167} 162}
168 163
169void ConfigureSystem::RefreshConsoleID() { 164void ConfigureSystem::RefreshConsoleID() {
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index fc5cd2945..bb24c9ae7 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -9,6 +9,10 @@
9#include <QList> 9#include <QList>
10#include <QWidget> 10#include <QWidget>
11 11
12namespace Core {
13class System;
14}
15
12namespace ConfigurationShared { 16namespace ConfigurationShared {
13enum class CheckState; 17enum class CheckState;
14} 18}
@@ -21,17 +25,16 @@ class ConfigureSystem : public QWidget {
21 Q_OBJECT 25 Q_OBJECT
22 26
23public: 27public:
24 explicit ConfigureSystem(QWidget* parent = nullptr); 28 explicit ConfigureSystem(Core::System& system_, QWidget* parent = nullptr);
25 ~ConfigureSystem() override; 29 ~ConfigureSystem() override;
26 30
27 void ApplyConfiguration(); 31 void ApplyConfiguration();
32 void SetConfiguration();
28 33
29private: 34private:
30 void changeEvent(QEvent* event) override; 35 void changeEvent(QEvent* event) override;
31 void RetranslateUI(); 36 void RetranslateUI();
32 37
33 void SetConfiguration();
34
35 void ReadSystemSettings(); 38 void ReadSystemSettings();
36 39
37 void RefreshConsoleID(); 40 void RefreshConsoleID();
@@ -48,4 +51,6 @@ private:
48 51
49 ConfigurationShared::CheckState use_rng_seed; 52 ConfigurationShared::CheckState use_rng_seed;
50 ConfigurationShared::CheckState use_custom_rtc; 53 ConfigurationShared::CheckState use_custom_rtc;
54
55 Core::System& system;
51}; 56};
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 27f552f59..5b68dcb29 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>System</string>
18 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout"> 19 <layout class="QHBoxLayout" name="horizontalLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="verticalLayout"> 21 <layout class="QVBoxLayout" name="verticalLayout">
diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp
index b666b175a..8e5a4c72d 100644
--- a/src/yuzu/configuration/configure_tas.cpp
+++ b/src/yuzu/configuration/configure_tas.cpp
@@ -18,6 +18,7 @@ ConfigureTasDialog::ConfigureTasDialog(QWidget* parent)
18 18
19 setFocusPolicy(Qt::ClickFocus); 19 setFocusPolicy(Qt::ClickFocus);
20 setWindowTitle(tr("TAS Configuration")); 20 setWindowTitle(tr("TAS Configuration"));
21 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
21 22
22 connect(ui->tas_path_button, &QToolButton::pressed, this, 23 connect(ui->tas_path_button, &QToolButton::pressed, this,
23 [this] { SetDirectory(DirectoryTarget::TAS, ui->tas_path_edit); }); 24 [this] { SetDirectory(DirectoryTarget::TAS, ui->tas_path_edit); });
diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui
index 8a3ecb834..7d44895c4 100644
--- a/src/yuzu/configuration/configure_tas.ui
+++ b/src/yuzu/configuration/configure_tas.ui
@@ -1,183 +1,186 @@
1<?xml version="1.0" encoding="UTF-8"?> 1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0"> 2<ui version="4.0">
3 <class>ConfigureTas</class> 3 <class>ConfigureTas</class>
4 <widget class="QDialog" name="ConfigureTas"> 4 <widget class="QDialog" name="ConfigureTas">
5 <property name="geometry"> 5 <layout class="QVBoxLayout" name="verticalLayout_1">
6 <rect> 6 <item>
7 <x>0</x> 7 <layout class="QHBoxLayout" name="horizontalLayout_1">
8 <y>0</y> 8 <item>
9 <width>800</width> 9 <widget class="QGroupBox" name="groupBox_1">
10 <height>300</height> 10 <property name="title">
11 </rect> 11 <string>TAS</string>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <layout class="QGridLayout" name="gridLayout_1">
14 <string>Dialog</string> 14 <item row="0" column="0" colspan="4">
15 </property> 15 <widget class="QLabel" name="label_1">
16 <layout class="QVBoxLayout" name="verticalLayout_1"> 16 <property name="text">
17 <item> 17 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reads controller input from scripts in the same format as TAS-nx scripts.&lt;br/&gt;For a more detailed explanation, please consult the &lt;a href=&quot;https://yuzu-emu.org/help/feature/tas/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;help page&lt;/span&gt;&lt;/a&gt; on the yuzu website.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
18 <layout class="QHBoxLayout" name="horizontalLayout">
19 <item>
20 <widget class="QGroupBox" name="groupBox">
21 <property name="title">
22 <string>TAS</string>
23 </property>
24 <layout class="QGridLayout" name="gridLayout">
25 <item row="0" column="0" colspan="1">
26 <widget class="QLabel" name="label_1">
27 <property name="text">
28 <string>Reads controller input from scripts in the same format as TAS-nx scripts. For a more detailed explanation please consult the FAQ on the yuzu website.</string>
29 </property>
30 <property name="wordWrap">
31 <bool>true</bool>
32 </property>
33 </widget>
34 </item>
35 <item row="1" column="0" colspan="1">
36 <widget class="QLabel" name="label_2">
37 <property name="text">
38 <string>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (General -> Hotkeys).</string>
39 </property>
40 <property name="wordWrap">
41 <bool>true</bool>
42 </property>
43 </widget>
44 </item>
45 <item row="2" column="0" colspan="1">
46 <widget class="QLabel" name="label_2">
47 <property name="text">
48 <string>WARNING: This is an experimental feature. It will not play back scripts frame perfectly with the current, imperfect syncing method.</string>
49 </property>
50 <property name="wordWrap">
51 <bool>true</bool>
52 </property>
53 </widget>
54 </item>
55 </layout>
56 </widget>
57 </item>
58 </layout>
59 </item>
60 <item>
61 <layout class="QHBoxLayout" name="horizontalLayout">
62 <item>
63 <widget class="QGroupBox" name="groupBox">
64 <property name="title">
65 <string>Settings</string>
66 </property>
67 <layout class="QGridLayout" name="gridLayout">
68 <item row="0" column="0" colspan="4">
69 <widget class="QCheckBox" name="tas_enable">
70 <property name="text">
71 <string>Enable TAS features</string>
72 </property>
73 </widget>
74 </item>
75 <item row="1" column="0" colspan="4">
76 <widget class="QCheckBox" name="tas_control_swap">
77 <property name="text">
78 <string>Automatic controller profile swapping</string>
79 </property>
80 </widget>
81 </item>
82 <item row="2" column="0" colspan="4">
83 <widget class="QCheckBox" name="tas_loop_script">
84 <property name="text">
85 <string>Loop script</string>
86 </property>
87 </widget>
88 </item>
89 <item row="3" column="0" colspan="4">
90 <widget class="QCheckBox" name="tas_pause_on_load">
91 <property name="enabled">
92 <bool>false</bool>
93 </property>
94 <property name="text">
95 <string>Pause execution during loads</string>
96 </property>
97 </widget>
98 </item>
99 </layout>
100 </widget>
101 </item>
102 </layout>
103 </item>
104 <item>
105 <layout class="QHBoxLayout" name="horizontalLayout">
106 <item>
107 <widget class="QGroupBox" name="groupBox">
108 <property name="title">
109 <string>Script Directory</string>
110 </property>
111 <layout class="QGridLayout" name="gridLayout">
112 <item row="0" column="0">
113 <widget class="QLabel" name="label">
114 <property name="text">
115 <string>Path</string>
116 </property>
117 </widget>
118 </item>
119 <item row="0" column="3">
120 <widget class="QToolButton" name="tas_path_button">
121 <property name="text">
122 <string>...</string>
123 </property>
124 </widget>
125 </item>
126 <item row="0" column="2">
127 <widget class="QLineEdit" name="tas_path_edit"/>
128 </item>
129 <item row="0" column="1">
130 <spacer name="horizontalSpacer">
131 <property name="orientation">
132 <enum>Qt::Horizontal</enum>
133 </property>
134 <property name="sizeType">
135 <enum>QSizePolicy::Maximum</enum>
136 </property>
137 <property name="sizeHint" stdset="0">
138 <size>
139 <width>60</width>
140 <height>20</height>
141 </size>
142 </property>
143 </spacer>
144 </item>
145 </layout>
146 </widget>
147 </item>
148 </layout>
149 </item>
150 <item>
151 <widget class="QDialogButtonBox" name="buttonBox">
152 <property name="sizePolicy">
153 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
154 <horstretch>0</horstretch>
155 <verstretch>0</verstretch>
156 </sizepolicy>
157 </property> 18 </property>
158 <property name="orientation"> 19 </widget>
159 <enum>Qt::Horizontal</enum> 20 </item>
21 <item row="1" column="0" colspan="4">
22 <widget class="QLabel" name="label_2">
23 <property name="text">
24 <string>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -&gt; General -&gt; Hotkeys).</string>
160 </property> 25 </property>
161 <property name="standardButtons"> 26 <property name="wordWrap">
162 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> 27 <bool>true</bool>
163 </property> 28 </property>
164 </widget> 29 </widget>
165 </item> 30 </item>
31 <item row="2" column="0" colspan="4">
32 <widget class="QLabel" name="label_3">
33 <property name="text">
34 <string>WARNING: This is an experimental feature.&lt;br/&gt;It will not play back scripts frame perfectly with the current, imperfect syncing method.</string>
35 </property>
36 <property name="wordWrap">
37 <bool>true</bool>
38 </property>
39 </widget>
40 </item>
41 </layout>
42 </widget>
43 </item>
44 </layout>
45 </item>
46 <item>
47 <layout class="QHBoxLayout" name="horizontalLayout_2">
48 <item>
49 <widget class="QGroupBox" name="groupBox_2">
50 <property name="title">
51 <string>Settings</string>
52 </property>
53 <layout class="QGridLayout" name="gridLayout_2">
54 <item row="0" column="0" colspan="4">
55 <widget class="QCheckBox" name="tas_enable">
56 <property name="text">
57 <string>Enable TAS features</string>
58 </property>
59 </widget>
60 </item>
61 <item row="1" column="0" colspan="4">
62 <widget class="QCheckBox" name="tas_control_swap">
63 <property name="text">
64 <string>Automatic controller profile swapping</string>
65 </property>
66 </widget>
67 </item>
68 <item row="2" column="0" colspan="4">
69 <widget class="QCheckBox" name="tas_loop_script">
70 <property name="text">
71 <string>Loop script</string>
72 </property>
73 </widget>
74 </item>
75 <item row="3" column="0" colspan="4">
76 <widget class="QCheckBox" name="tas_pause_on_load">
77 <property name="enabled">
78 <bool>false</bool>
79 </property>
80 <property name="text">
81 <string>Pause execution during loads</string>
82 </property>
83 </widget>
84 </item>
85 </layout>
86 </widget>
87 </item>
88 </layout>
89 </item>
90 <item>
91 <layout class="QHBoxLayout" name="horizontalLayout_3">
92 <item>
93 <widget class="QGroupBox" name="groupBox_3">
94 <property name="title">
95 <string>Script Directory</string>
96 </property>
97 <layout class="QGridLayout" name="gridLayout_3">
98 <item row="0" column="0">
99 <widget class="QLabel" name="label_4">
100 <property name="text">
101 <string>Path</string>
102 </property>
103 </widget>
104 </item>
105 <item row="0" column="3">
106 <widget class="QToolButton" name="tas_path_button">
107 <property name="text">
108 <string>...</string>
109 </property>
110 </widget>
111 </item>
112 <item row="0" column="2">
113 <widget class="QLineEdit" name="tas_path_edit"/>
114 </item>
115 </layout>
116 </widget>
117 </item>
166 </layout> 118 </layout>
167 </widget> 119 </item>
168 <resources/> 120 <item>
169 <connections> 121 <spacer name="verticalSpacer">
170 <connection> 122 <property name="orientation">
171 <sender>buttonBox</sender> 123 <enum>Qt::Vertical</enum>
172 <signal>accepted()</signal> 124 </property>
173 <receiver>ConfigureTas</receiver> 125 <property name="sizeHint" stdset="0">
174 <slot>accept()</slot> 126 <size>
175 </connection> 127 <width>20</width>
176 <connection> 128 <height>40</height>
177 <sender>buttonBox</sender> 129 </size>
178 <signal>rejected()</signal> 130 </property>
179 <receiver>ConfigureTas</receiver> 131 </spacer>
180 <slot>reject()</slot> 132 </item>
181 </connection> 133 <item>
182 </connections> 134 <widget class="QDialogButtonBox" name="buttonBox">
135 <property name="sizePolicy">
136 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
137 <horstretch>0</horstretch>
138 <verstretch>0</verstretch>
139 </sizepolicy>
140 </property>
141 <property name="orientation">
142 <enum>Qt::Horizontal</enum>
143 </property>
144 <property name="standardButtons">
145 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
146 </property>
147 </widget>
148 </item>
149 </layout>
150 </widget>
151 <resources/>
152 <connections>
153 <connection>
154 <sender>buttonBox</sender>
155 <signal>accepted()</signal>
156 <receiver>ConfigureTas</receiver>
157 <slot>accept()</slot>
158 <hints>
159 <hint type="sourcelabel">
160 <x>20</x>
161 <y>20</y>
162 </hint>
163 <hint type="destinationlabel">
164 <x>20</x>
165 <y>20</y>
166 </hint>
167 </hints>
168 </connection>
169 <connection>
170 <sender>buttonBox</sender>
171 <signal>rejected()</signal>
172 <receiver>ConfigureTas</receiver>
173 <slot>reject()</slot>
174 <hints>
175 <hint type="sourcelabel">
176 <x>20</x>
177 <y>20</y>
178 </hint>
179 <hint type="destinationlabel">
180 <x>20</x>
181 <y>20</y>
182 </hint>
183 </hints>
184 </connection>
185 </connections>
183</ui> 186</ui>
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 9d7d51126..46e5409db 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -54,7 +54,8 @@ QString GetTranslatedRowTextName(size_t index) {
54} 54}
55} // Anonymous namespace 55} // Anonymous namespace
56 56
57ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) { 57ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
58 : QWidget(parent), ui{std::make_unique<Ui::ConfigureUi>()}, system{system_} {
58 ui->setupUi(this); 59 ui->setupUi(this);
59 60
60 InitializeLanguageComboBox(); 61 InitializeLanguageComboBox();
@@ -116,7 +117,7 @@ void ConfigureUi::ApplyConfiguration() {
116 UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked(); 117 UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();
117 Common::FS::SetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir, 118 Common::FS::SetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir,
118 ui->screenshot_path_edit->text().toStdString()); 119 ui->screenshot_path_edit->text().toStdString());
119 Core::System::GetInstance().ApplySettings(); 120 system.ApplySettings();
120} 121}
121 122
122void ConfigureUi::RequestGameListUpdate() { 123void ConfigureUi::RequestGameListUpdate() {
diff --git a/src/yuzu/configuration/configure_ui.h b/src/yuzu/configuration/configure_ui.h
index c30bcf6ff..48b6e6d82 100644
--- a/src/yuzu/configuration/configure_ui.h
+++ b/src/yuzu/configuration/configure_ui.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace Core {
11class System;
12}
13
10namespace Ui { 14namespace Ui {
11class ConfigureUi; 15class ConfigureUi;
12} 16}
@@ -15,7 +19,7 @@ class ConfigureUi : public QWidget {
15 Q_OBJECT 19 Q_OBJECT
16 20
17public: 21public:
18 explicit ConfigureUi(QWidget* parent = nullptr); 22 explicit ConfigureUi(Core::System& system_, QWidget* parent = nullptr);
19 ~ConfigureUi() override; 23 ~ConfigureUi() override;
20 24
21 void ApplyConfiguration(); 25 void ApplyConfiguration();
@@ -42,4 +46,6 @@ private:
42 void UpdateSecondRowComboBox(bool init = false); 46 void UpdateSecondRowComboBox(bool init = false);
43 47
44 std::unique_ptr<Ui::ConfigureUi> ui; 48 std::unique_ptr<Ui::ConfigureUi> ui;
49
50 Core::System& system;
45}; 51};
diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui
index 394f9fe04..a50df7f6f 100644
--- a/src/yuzu/configuration/configure_ui.ui
+++ b/src/yuzu/configuration/configure_ui.ui
@@ -7,12 +7,15 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>363</width> 9 <width>363</width>
10 <height>391</height> 10 <height>507</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>UI</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout"> 19 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 20 <item>
18 <widget class="QGroupBox" name="general_groupBox"> 21 <widget class="QGroupBox" name="general_groupBox">
diff --git a/src/yuzu/configuration/configure_web.ui b/src/yuzu/configuration/configure_web.ui
index 8c07d1165..35b4274b0 100644
--- a/src/yuzu/configuration/configure_web.ui
+++ b/src/yuzu/configuration/configure_web.ui
@@ -13,6 +13,9 @@
13 <property name="windowTitle"> 13 <property name="windowTitle">
14 <string>Form</string> 14 <string>Form</string>
15 </property> 15 </property>
16 <property name="accessibleName">
17 <string>Web</string>
18 </property>
16 <layout class="QVBoxLayout" name="verticalLayout"> 19 <layout class="QVBoxLayout" name="verticalLayout">
17 <item> 20 <item>
18 <layout class="QVBoxLayout" name="verticalLayout_3"> 21 <layout class="QVBoxLayout" name="verticalLayout_3">
@@ -55,7 +58,7 @@
55 </widget> 58 </widget>
56 </item> 59 </item>
57 <item row="0" column="1" colspan="3"> 60 <item row="0" column="1" colspan="3">
58 <widget class="QLabel" name="username" /> 61 <widget class="QLabel" name="username"/>
59 </item> 62 </item>
60 <item row="1" column="0"> 63 <item row="1" column="0">
61 <widget class="QLabel" name="label_token"> 64 <widget class="QLabel" name="label_token">
@@ -65,8 +68,7 @@
65 </widget> 68 </widget>
66 </item> 69 </item>
67 <item row="1" column="4"> 70 <item row="1" column="4">
68 <widget class="QLabel" name="label_token_verified"> 71 <widget class="QLabel" name="label_token_verified"/>
69 </widget>
70 </item> 72 </item>
71 <item row="0" column="0"> 73 <item row="0" column="0">
72 <widget class="QLabel" name="label_username"> 74 <widget class="QLabel" name="label_username">
@@ -163,20 +165,20 @@
163 </layout> 165 </layout>
164 </item> 166 </item>
165 <item> 167 <item>
166 <widget class="QGroupBox" name="discord_group"> 168 <widget class="QGroupBox" name="discord_group">
167 <property name="title"> 169 <property name="title">
168 <string>Discord Presence</string> 170 <string>Discord Presence</string>
169 </property> 171 </property>
170 <layout class="QVBoxLayout" name="verticalLayout_21"> 172 <layout class="QVBoxLayout" name="verticalLayout_21">
171 <item> 173 <item>
172 <widget class="QCheckBox" name="toggle_discordrpc"> 174 <widget class="QCheckBox" name="toggle_discordrpc">
173 <property name="text"> 175 <property name="text">
174 <string>Show Current Game in your Discord Status</string> 176 <string>Show Current Game in your Discord Status</string>
175 </property> 177 </property>
176 </widget> 178 </widget>
177 </item> 179 </item>
178 </layout> 180 </layout>
179 </widget> 181 </widget>
180 </item> 182 </item>
181 <item> 183 <item>
182 <spacer name="verticalSpacer"> 184 <spacer name="verticalSpacer">
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
index 333eeb84e..38ea6c772 100644
--- a/src/yuzu/configuration/input_profiles.cpp
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -28,7 +28,7 @@ std::filesystem::path GetNameWithoutExtension(std::filesystem::path filename) {
28 28
29} // namespace 29} // namespace
30 30
31InputProfiles::InputProfiles() { 31InputProfiles::InputProfiles(Core::System& system_) : system{system_} {
32 const auto input_profile_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "input"; 32 const auto input_profile_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "input";
33 33
34 if (!FS::IsDir(input_profile_loc)) { 34 if (!FS::IsDir(input_profile_loc)) {
@@ -44,8 +44,8 @@ InputProfiles::InputProfiles() {
44 44
45 if (IsINI(filename) && IsProfileNameValid(name_without_ext)) { 45 if (IsINI(filename) && IsProfileNameValid(name_without_ext)) {
46 map_profiles.insert_or_assign( 46 map_profiles.insert_or_assign(
47 name_without_ext, 47 name_without_ext, std::make_unique<Config>(system, name_without_ext,
48 std::make_unique<Config>(name_without_ext, Config::ConfigType::InputProfile)); 48 Config::ConfigType::InputProfile));
49 } 49 }
50 50
51 return true; 51 return true;
@@ -81,7 +81,8 @@ bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t p
81 } 81 }
82 82
83 map_profiles.insert_or_assign( 83 map_profiles.insert_or_assign(
84 profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile)); 84 profile_name,
85 std::make_unique<Config>(system, profile_name, Config::ConfigType::InputProfile));
85 86
86 return SaveProfile(profile_name, player_index); 87 return SaveProfile(profile_name, player_index);
87} 88}
diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h
index cb41fd9be..a567bd5a9 100644
--- a/src/yuzu/configuration/input_profiles.h
+++ b/src/yuzu/configuration/input_profiles.h
@@ -8,12 +8,16 @@
8#include <string_view> 8#include <string_view>
9#include <unordered_map> 9#include <unordered_map>
10 10
11namespace Core {
12class System;
13}
14
11class Config; 15class Config;
12 16
13class InputProfiles { 17class InputProfiles {
14 18
15public: 19public:
16 explicit InputProfiles(); 20 explicit InputProfiles(Core::System& system_);
17 virtual ~InputProfiles(); 21 virtual ~InputProfiles();
18 22
19 std::vector<std::string> GetInputProfileNames(); 23 std::vector<std::string> GetInputProfileNames();
@@ -29,4 +33,6 @@ private:
29 bool ProfileExistsInMap(const std::string& profile_name) const; 33 bool ProfileExistsInMap(const std::string& profile_name) const;
30 34
31 std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles; 35 std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles;
36
37 Core::System& system;
32}; 38};
diff --git a/src/yuzu/debugger/profiler.cpp b/src/yuzu/debugger/profiler.cpp
index 7a6f84d96..33110685a 100644
--- a/src/yuzu/debugger/profiler.cpp
+++ b/src/yuzu/debugger/profiler.cpp
@@ -143,24 +143,28 @@ void MicroProfileWidget::hideEvent(QHideEvent* ev) {
143} 143}
144 144
145void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) { 145void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) {
146 MicroProfileMousePosition(ev->pos().x() / x_scale, ev->pos().y() / y_scale, 0); 146 const auto mouse_position = ev->pos();
147 MicroProfileMousePosition(mouse_position.x() / x_scale, mouse_position.y() / y_scale, 0);
147 ev->accept(); 148 ev->accept();
148} 149}
149 150
150void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) { 151void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) {
151 MicroProfileMousePosition(ev->pos().x() / x_scale, ev->pos().y() / y_scale, 0); 152 const auto mouse_position = ev->pos();
153 MicroProfileMousePosition(mouse_position.x() / x_scale, mouse_position.y() / y_scale, 0);
152 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton); 154 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
153 ev->accept(); 155 ev->accept();
154} 156}
155 157
156void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) { 158void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) {
157 MicroProfileMousePosition(ev->pos().x() / x_scale, ev->pos().y() / y_scale, 0); 159 const auto mouse_position = ev->pos();
160 MicroProfileMousePosition(mouse_position.x() / x_scale, mouse_position.y() / y_scale, 0);
158 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton); 161 MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
159 ev->accept(); 162 ev->accept();
160} 163}
161 164
162void MicroProfileWidget::wheelEvent(QWheelEvent* ev) { 165void MicroProfileWidget::wheelEvent(QWheelEvent* ev) {
163 MicroProfileMousePosition(ev->pos().x() / x_scale, ev->pos().y() / y_scale, 166 const auto wheel_position = ev->position().toPoint();
167 MicroProfileMousePosition(wheel_position.x() / x_scale, wheel_position.y() / y_scale,
164 ev->angleDelta().y() / 120); 168 ev->angleDelta().y() / 120);
165 ev->accept(); 169 ev->accept();
166} 170}
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index bdfda6c54..1f41c46c4 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -89,20 +89,20 @@ std::size_t WaitTreeItem::Row() const {
89 return row; 89 return row;
90} 90}
91 91
92std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { 92std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList(
93 Core::System& system) {
93 std::vector<std::unique_ptr<WaitTreeThread>> item_list; 94 std::vector<std::unique_ptr<WaitTreeThread>> item_list;
94 std::size_t row = 0; 95 std::size_t row = 0;
95 auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { 96 auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) {
96 for (std::size_t i = 0; i < threads.size(); ++i) { 97 for (std::size_t i = 0; i < threads.size(); ++i) {
97 if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { 98 if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) {
98 item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i])); 99 item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system));
99 item_list.back()->row = row; 100 item_list.back()->row = row;
100 } 101 }
101 ++row; 102 ++row;
102 } 103 }
103 }; 104 };
104 105
105 const auto& system = Core::System::GetInstance();
106 add_threads(system.GlobalSchedulerContext().GetThreadList()); 106 add_threads(system.GlobalSchedulerContext().GetThreadList());
107 107
108 return item_list; 108 return item_list;
@@ -115,9 +115,10 @@ QString WaitTreeText::GetText() const {
115 return text; 115 return text;
116} 116}
117 117
118WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table) 118WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table,
119 : mutex_address(mutex_address) { 119 Core::System& system_)
120 mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address); 120 : mutex_address(mutex_address), system{system_} {
121 mutex_value = system.Memory().Read32(mutex_address);
121 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); 122 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
122 owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe(); 123 owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe();
123} 124}
@@ -136,12 +137,13 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() cons
136 list.push_back(std::make_unique<WaitTreeText>( 137 list.push_back(std::make_unique<WaitTreeText>(
137 tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char{'0'}))); 138 tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char{'0'})));
138 if (owner != nullptr) { 139 if (owner != nullptr) {
139 list.push_back(std::make_unique<WaitTreeThread>(*owner)); 140 list.push_back(std::make_unique<WaitTreeThread>(*owner, system));
140 } 141 }
141 return list; 142 return list;
142} 143}
143 144
144WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread) : thread(thread) {} 145WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread, Core::System& system_)
146 : thread(thread), system{system_} {}
145WaitTreeCallstack::~WaitTreeCallstack() = default; 147WaitTreeCallstack::~WaitTreeCallstack() = default;
146 148
147QString WaitTreeCallstack::GetText() const { 149QString WaitTreeCallstack::GetText() const {
@@ -159,8 +161,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
159 return list; 161 return list;
160 } 162 }
161 163
162 auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(Core::System::GetInstance(), 164 auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(system, thread.GetContext64());
163 thread.GetContext64());
164 165
165 for (auto& entry : backtrace) { 166 for (auto& entry : backtrace) {
166 std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, 167 std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
@@ -172,8 +173,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
172} 173}
173 174
174WaitTreeSynchronizationObject::WaitTreeSynchronizationObject( 175WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(
175 const Kernel::KSynchronizationObject& o) 176 const Kernel::KSynchronizationObject& o, Core::System& system_)
176 : object(o) {} 177 : object(o), system{system_} {}
177WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default; 178WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default;
178 179
179WaitTreeExpandableItem::WaitTreeExpandableItem() = default; 180WaitTreeExpandableItem::WaitTreeExpandableItem() = default;
@@ -191,16 +192,18 @@ QString WaitTreeSynchronizationObject::GetText() const {
191} 192}
192 193
193std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make( 194std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
194 const Kernel::KSynchronizationObject& object) { 195 const Kernel::KSynchronizationObject& object, Core::System& system) {
195 const auto type = 196 const auto type =
196 static_cast<Kernel::KClassTokenGenerator::ObjectType>(object.GetTypeObj().GetClassToken()); 197 static_cast<Kernel::KClassTokenGenerator::ObjectType>(object.GetTypeObj().GetClassToken());
197 switch (type) { 198 switch (type) {
198 case Kernel::KClassTokenGenerator::ObjectType::KReadableEvent: 199 case Kernel::KClassTokenGenerator::ObjectType::KReadableEvent:
199 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object)); 200 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object),
201 system);
200 case Kernel::KClassTokenGenerator::ObjectType::KThread: 202 case Kernel::KClassTokenGenerator::ObjectType::KThread:
201 return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object)); 203 return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object),
204 system);
202 default: 205 default:
203 return std::make_unique<WaitTreeSynchronizationObject>(object); 206 return std::make_unique<WaitTreeSynchronizationObject>(object, system);
204 } 207 }
205} 208}
206 209
@@ -211,15 +214,15 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChi
211 if (threads.empty()) { 214 if (threads.empty()) {
212 list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread"))); 215 list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread")));
213 } else { 216 } else {
214 list.push_back(std::make_unique<WaitTreeThreadList>(std::move(threads))); 217 list.push_back(std::make_unique<WaitTreeThreadList>(std::move(threads), system));
215 } 218 }
216 219
217 return list; 220 return list;
218} 221}
219 222
220WaitTreeObjectList::WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, 223WaitTreeObjectList::WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list,
221 bool w_all) 224 bool w_all, Core::System& system_)
222 : object_list(list), wait_all(w_all) {} 225 : object_list(list), wait_all(w_all), system{system_} {}
223 226
224WaitTreeObjectList::~WaitTreeObjectList() = default; 227WaitTreeObjectList::~WaitTreeObjectList() = default;
225 228
@@ -231,13 +234,14 @@ QString WaitTreeObjectList::GetText() const {
231 234
232std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const { 235std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const {
233 std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size()); 236 std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size());
234 std::transform(object_list.begin(), object_list.end(), list.begin(), 237 std::transform(object_list.begin(), object_list.end(), list.begin(), [this](const auto& t) {
235 [](const auto& t) { return WaitTreeSynchronizationObject::make(*t); }); 238 return WaitTreeSynchronizationObject::make(*t, system);
239 });
236 return list; 240 return list;
237} 241}
238 242
239WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread) 243WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread, Core::System& system_)
240 : WaitTreeSynchronizationObject(thread) {} 244 : WaitTreeSynchronizationObject(thread, system_), system{system_} {}
241WaitTreeThread::~WaitTreeThread() = default; 245WaitTreeThread::~WaitTreeThread() = default;
242 246
243QString WaitTreeThread::GetText() const { 247QString WaitTreeThread::GetText() const {
@@ -360,7 +364,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
360 const VAddr mutex_wait_address = thread.GetMutexWaitAddressForDebugging(); 364 const VAddr mutex_wait_address = thread.GetMutexWaitAddressForDebugging();
361 if (mutex_wait_address != 0) { 365 if (mutex_wait_address != 0) {
362 const auto& handle_table = thread.GetOwnerProcess()->GetHandleTable(); 366 const auto& handle_table = thread.GetOwnerProcess()->GetHandleTable();
363 list.push_back(std::make_unique<WaitTreeMutexInfo>(mutex_wait_address, handle_table)); 367 list.push_back(
368 std::make_unique<WaitTreeMutexInfo>(mutex_wait_address, handle_table, system));
364 } else { 369 } else {
365 list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); 370 list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex")));
366 } 371 }
@@ -369,20 +374,20 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
369 thread.GetWaitReasonForDebugging() == 374 thread.GetWaitReasonForDebugging() ==
370 Kernel::ThreadWaitReasonForDebugging::Synchronization) { 375 Kernel::ThreadWaitReasonForDebugging::Synchronization) {
371 list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(), 376 list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(),
372 thread.IsCancellable())); 377 thread.IsCancellable(), system));
373 } 378 }
374 379
375 list.push_back(std::make_unique<WaitTreeCallstack>(thread)); 380 list.push_back(std::make_unique<WaitTreeCallstack>(thread, system));
376 381
377 return list; 382 return list;
378} 383}
379 384
380WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object) 385WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object, Core::System& system_)
381 : WaitTreeSynchronizationObject(object) {} 386 : WaitTreeSynchronizationObject(object, system_) {}
382WaitTreeEvent::~WaitTreeEvent() = default; 387WaitTreeEvent::~WaitTreeEvent() = default;
383 388
384WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list) 389WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list, Core::System& system_)
385 : thread_list(std::move(list)) {} 390 : thread_list(std::move(list)), system{system_} {}
386WaitTreeThreadList::~WaitTreeThreadList() = default; 391WaitTreeThreadList::~WaitTreeThreadList() = default;
387 392
388QString WaitTreeThreadList::GetText() const { 393QString WaitTreeThreadList::GetText() const {
@@ -392,11 +397,12 @@ QString WaitTreeThreadList::GetText() const {
392std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThreadList::GetChildren() const { 397std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThreadList::GetChildren() const {
393 std::vector<std::unique_ptr<WaitTreeItem>> list(thread_list.size()); 398 std::vector<std::unique_ptr<WaitTreeItem>> list(thread_list.size());
394 std::transform(thread_list.begin(), thread_list.end(), list.begin(), 399 std::transform(thread_list.begin(), thread_list.end(), list.begin(),
395 [](const auto& t) { return std::make_unique<WaitTreeThread>(*t); }); 400 [this](const auto& t) { return std::make_unique<WaitTreeThread>(*t, system); });
396 return list; 401 return list;
397} 402}
398 403
399WaitTreeModel::WaitTreeModel(QObject* parent) : QAbstractItemModel(parent) {} 404WaitTreeModel::WaitTreeModel(Core::System& system_, QObject* parent)
405 : QAbstractItemModel(parent), system{system_} {}
400WaitTreeModel::~WaitTreeModel() = default; 406WaitTreeModel::~WaitTreeModel() = default;
401 407
402QModelIndex WaitTreeModel::index(int row, int column, const QModelIndex& parent) const { 408QModelIndex WaitTreeModel::index(int row, int column, const QModelIndex& parent) const {
@@ -455,10 +461,11 @@ void WaitTreeModel::ClearItems() {
455} 461}
456 462
457void WaitTreeModel::InitItems() { 463void WaitTreeModel::InitItems() {
458 thread_items = WaitTreeItem::MakeThreadItemList(); 464 thread_items = WaitTreeItem::MakeThreadItemList(system);
459} 465}
460 466
461WaitTreeWidget::WaitTreeWidget(QWidget* parent) : QDockWidget(tr("&Wait Tree"), parent) { 467WaitTreeWidget::WaitTreeWidget(Core::System& system_, QWidget* parent)
468 : QDockWidget(tr("&Wait Tree"), parent), system{system_} {
462 setObjectName(QStringLiteral("WaitTreeWidget")); 469 setObjectName(QStringLiteral("WaitTreeWidget"));
463 view = new QTreeView(this); 470 view = new QTreeView(this);
464 view->setHeaderHidden(true); 471 view->setHeaderHidden(true);
@@ -469,7 +476,7 @@ WaitTreeWidget::WaitTreeWidget(QWidget* parent) : QDockWidget(tr("&Wait Tree"),
469WaitTreeWidget::~WaitTreeWidget() = default; 476WaitTreeWidget::~WaitTreeWidget() = default;
470 477
471void WaitTreeWidget::OnDebugModeEntered() { 478void WaitTreeWidget::OnDebugModeEntered() {
472 if (!Core::System::GetInstance().IsPoweredOn()) 479 if (!system.IsPoweredOn())
473 return; 480 return;
474 model->InitItems(); 481 model->InitItems();
475 view->setModel(model); 482 view->setModel(model);
@@ -483,7 +490,7 @@ void WaitTreeWidget::OnDebugModeLeft() {
483} 490}
484 491
485void WaitTreeWidget::OnEmulationStarting(EmuThread* emu_thread) { 492void WaitTreeWidget::OnEmulationStarting(EmuThread* emu_thread) {
486 model = new WaitTreeModel(this); 493 model = new WaitTreeModel(system, this);
487 view->setModel(model); 494 view->setModel(model);
488 setEnabled(false); 495 setEnabled(false);
489} 496}
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index d450345df..ea4d2e299 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -18,6 +18,10 @@
18 18
19class EmuThread; 19class EmuThread;
20 20
21namespace Core {
22class System;
23}
24
21namespace Kernel { 25namespace Kernel {
22class KHandleTable; 26class KHandleTable;
23class KReadableEvent; 27class KReadableEvent;
@@ -42,7 +46,7 @@ public:
42 WaitTreeItem* Parent() const; 46 WaitTreeItem* Parent() const;
43 const std::vector<std::unique_ptr<WaitTreeItem>>& Children() const; 47 const std::vector<std::unique_ptr<WaitTreeItem>>& Children() const;
44 std::size_t Row() const; 48 std::size_t Row() const;
45 static std::vector<std::unique_ptr<WaitTreeThread>> MakeThreadItemList(); 49 static std::vector<std::unique_ptr<WaitTreeThread>> MakeThreadItemList(Core::System& system);
46 50
47private: 51private:
48 std::size_t row; 52 std::size_t row;
@@ -75,7 +79,8 @@ public:
75class WaitTreeMutexInfo : public WaitTreeExpandableItem { 79class WaitTreeMutexInfo : public WaitTreeExpandableItem {
76 Q_OBJECT 80 Q_OBJECT
77public: 81public:
78 explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table); 82 explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table,
83 Core::System& system_);
79 ~WaitTreeMutexInfo() override; 84 ~WaitTreeMutexInfo() override;
80 85
81 QString GetText() const override; 86 QString GetText() const override;
@@ -86,12 +91,14 @@ private:
86 u32 mutex_value{}; 91 u32 mutex_value{};
87 Kernel::Handle owner_handle{}; 92 Kernel::Handle owner_handle{};
88 Kernel::KThread* owner{}; 93 Kernel::KThread* owner{};
94
95 Core::System& system;
89}; 96};
90 97
91class WaitTreeCallstack : public WaitTreeExpandableItem { 98class WaitTreeCallstack : public WaitTreeExpandableItem {
92 Q_OBJECT 99 Q_OBJECT
93public: 100public:
94 explicit WaitTreeCallstack(const Kernel::KThread& thread); 101 explicit WaitTreeCallstack(const Kernel::KThread& thread, Core::System& system_);
95 ~WaitTreeCallstack() override; 102 ~WaitTreeCallstack() override;
96 103
97 QString GetText() const override; 104 QString GetText() const override;
@@ -99,27 +106,34 @@ public:
99 106
100private: 107private:
101 const Kernel::KThread& thread; 108 const Kernel::KThread& thread;
109
110 Core::System& system;
102}; 111};
103 112
104class WaitTreeSynchronizationObject : public WaitTreeExpandableItem { 113class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
105 Q_OBJECT 114 Q_OBJECT
106public: 115public:
107 explicit WaitTreeSynchronizationObject(const Kernel::KSynchronizationObject& object); 116 explicit WaitTreeSynchronizationObject(const Kernel::KSynchronizationObject& object,
117 Core::System& system_);
108 ~WaitTreeSynchronizationObject() override; 118 ~WaitTreeSynchronizationObject() override;
109 119
110 static std::unique_ptr<WaitTreeSynchronizationObject> make( 120 static std::unique_ptr<WaitTreeSynchronizationObject> make(
111 const Kernel::KSynchronizationObject& object); 121 const Kernel::KSynchronizationObject& object, Core::System& system);
112 QString GetText() const override; 122 QString GetText() const override;
113 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 123 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
114 124
115protected: 125protected:
116 const Kernel::KSynchronizationObject& object; 126 const Kernel::KSynchronizationObject& object;
127
128private:
129 Core::System& system;
117}; 130};
118 131
119class WaitTreeObjectList : public WaitTreeExpandableItem { 132class WaitTreeObjectList : public WaitTreeExpandableItem {
120 Q_OBJECT 133 Q_OBJECT
121public: 134public:
122 WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, bool wait_all); 135 WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, bool wait_all,
136 Core::System& system_);
123 ~WaitTreeObjectList() override; 137 ~WaitTreeObjectList() override;
124 138
125 QString GetText() const override; 139 QString GetText() const override;
@@ -128,30 +142,35 @@ public:
128private: 142private:
129 const std::vector<Kernel::KSynchronizationObject*>& object_list; 143 const std::vector<Kernel::KSynchronizationObject*>& object_list;
130 bool wait_all; 144 bool wait_all;
145
146 Core::System& system;
131}; 147};
132 148
133class WaitTreeThread : public WaitTreeSynchronizationObject { 149class WaitTreeThread : public WaitTreeSynchronizationObject {
134 Q_OBJECT 150 Q_OBJECT
135public: 151public:
136 explicit WaitTreeThread(const Kernel::KThread& thread); 152 explicit WaitTreeThread(const Kernel::KThread& thread, Core::System& system_);
137 ~WaitTreeThread() override; 153 ~WaitTreeThread() override;
138 154
139 QString GetText() const override; 155 QString GetText() const override;
140 QColor GetColor() const override; 156 QColor GetColor() const override;
141 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 157 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
158
159private:
160 Core::System& system;
142}; 161};
143 162
144class WaitTreeEvent : public WaitTreeSynchronizationObject { 163class WaitTreeEvent : public WaitTreeSynchronizationObject {
145 Q_OBJECT 164 Q_OBJECT
146public: 165public:
147 explicit WaitTreeEvent(const Kernel::KReadableEvent& object); 166 explicit WaitTreeEvent(const Kernel::KReadableEvent& object, Core::System& system_);
148 ~WaitTreeEvent() override; 167 ~WaitTreeEvent() override;
149}; 168};
150 169
151class WaitTreeThreadList : public WaitTreeExpandableItem { 170class WaitTreeThreadList : public WaitTreeExpandableItem {
152 Q_OBJECT 171 Q_OBJECT
153public: 172public:
154 explicit WaitTreeThreadList(std::vector<Kernel::KThread*>&& list); 173 explicit WaitTreeThreadList(std::vector<Kernel::KThread*>&& list, Core::System& system_);
155 ~WaitTreeThreadList() override; 174 ~WaitTreeThreadList() override;
156 175
157 QString GetText() const override; 176 QString GetText() const override;
@@ -159,13 +178,15 @@ public:
159 178
160private: 179private:
161 std::vector<Kernel::KThread*> thread_list; 180 std::vector<Kernel::KThread*> thread_list;
181
182 Core::System& system;
162}; 183};
163 184
164class WaitTreeModel : public QAbstractItemModel { 185class WaitTreeModel : public QAbstractItemModel {
165 Q_OBJECT 186 Q_OBJECT
166 187
167public: 188public:
168 explicit WaitTreeModel(QObject* parent = nullptr); 189 explicit WaitTreeModel(Core::System& system_, QObject* parent = nullptr);
169 ~WaitTreeModel() override; 190 ~WaitTreeModel() override;
170 191
171 QVariant data(const QModelIndex& index, int role) const override; 192 QVariant data(const QModelIndex& index, int role) const override;
@@ -179,13 +200,15 @@ public:
179 200
180private: 201private:
181 std::vector<std::unique_ptr<WaitTreeThread>> thread_items; 202 std::vector<std::unique_ptr<WaitTreeThread>> thread_items;
203
204 Core::System& system;
182}; 205};
183 206
184class WaitTreeWidget : public QDockWidget { 207class WaitTreeWidget : public QDockWidget {
185 Q_OBJECT 208 Q_OBJECT
186 209
187public: 210public:
188 explicit WaitTreeWidget(QWidget* parent = nullptr); 211 explicit WaitTreeWidget(Core::System& system_, QWidget* parent = nullptr);
189 ~WaitTreeWidget() override; 212 ~WaitTreeWidget() override;
190 213
191public slots: 214public slots:
@@ -198,4 +221,6 @@ public slots:
198private: 221private:
199 QTreeView* view; 222 QTreeView* view;
200 WaitTreeModel* model; 223 WaitTreeModel* model;
224
225 Core::System& system;
201}; 226};
diff --git a/src/yuzu/discord_impl.cpp b/src/yuzu/discord_impl.cpp
index a93733b26..66f928af6 100644
--- a/src/yuzu/discord_impl.cpp
+++ b/src/yuzu/discord_impl.cpp
@@ -13,7 +13,7 @@
13 13
14namespace DiscordRPC { 14namespace DiscordRPC {
15 15
16DiscordImpl::DiscordImpl() { 16DiscordImpl::DiscordImpl(Core::System& system_) : system{system_} {
17 DiscordEventHandlers handlers{}; 17 DiscordEventHandlers handlers{};
18 18
19 // The number is the client ID for yuzu, it's used for images and the 19 // The number is the client ID for yuzu, it's used for images and the
@@ -35,12 +35,13 @@ void DiscordImpl::Update() {
35 std::chrono::system_clock::now().time_since_epoch()) 35 std::chrono::system_clock::now().time_since_epoch())
36 .count(); 36 .count();
37 std::string title; 37 std::string title;
38 if (Core::System::GetInstance().IsPoweredOn()) 38 if (system.IsPoweredOn()) {
39 Core::System::GetInstance().GetAppLoader().ReadTitle(title); 39 system.GetAppLoader().ReadTitle(title);
40 }
40 DiscordRichPresence presence{}; 41 DiscordRichPresence presence{};
41 presence.largeImageKey = "yuzu_logo"; 42 presence.largeImageKey = "yuzu_logo";
42 presence.largeImageText = "yuzu is an emulator for the Nintendo Switch"; 43 presence.largeImageText = "yuzu is an emulator for the Nintendo Switch";
43 if (Core::System::GetInstance().IsPoweredOn()) { 44 if (system.IsPoweredOn()) {
44 presence.state = title.c_str(); 45 presence.state = title.c_str();
45 presence.details = "Currently in game"; 46 presence.details = "Currently in game";
46 } else { 47 } else {
diff --git a/src/yuzu/discord_impl.h b/src/yuzu/discord_impl.h
index 4bfda8cdf..03ad42681 100644
--- a/src/yuzu/discord_impl.h
+++ b/src/yuzu/discord_impl.h
@@ -6,15 +6,21 @@
6 6
7#include "yuzu/discord.h" 7#include "yuzu/discord.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace DiscordRPC { 13namespace DiscordRPC {
10 14
11class DiscordImpl : public DiscordInterface { 15class DiscordImpl : public DiscordInterface {
12public: 16public:
13 DiscordImpl(); 17 DiscordImpl(Core::System& system_);
14 ~DiscordImpl() override; 18 ~DiscordImpl() override;
15 19
16 void Pause() override; 20 void Pause() override;
17 void Update() override; 21 void Update() override;
22
23 Core::System& system;
18}; 24};
19 25
20} // namespace DiscordRPC 26} // namespace DiscordRPC
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index f9d949e75..6bd0f9ee9 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -159,8 +159,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
159 * @return true if the haystack contains all words of userinput 159 * @return true if the haystack contains all words of userinput
160 */ 160 */
161static bool ContainsAllWords(const QString& haystack, const QString& userinput) { 161static bool ContainsAllWords(const QString& haystack, const QString& userinput) {
162 const QStringList userinput_split = 162 const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
163 userinput.split(QLatin1Char{' '}, QString::SplitBehavior::SkipEmptyParts);
164 163
165 return std::all_of(userinput_split.begin(), userinput_split.end(), 164 return std::all_of(userinput_split.begin(), userinput_split.end(),
166 [&haystack](const QString& s) { return haystack.contains(s); }); 165 [&haystack](const QString& s) { return haystack.contains(s); });
@@ -305,8 +304,8 @@ void GameList::OnFilterCloseClicked() {
305} 304}
306 305
307GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvider* provider, 306GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvider* provider,
308 GMainWindow* parent) 307 Core::System& system_, GMainWindow* parent)
309 : QWidget{parent}, vfs(std::move(vfs)), provider(provider) { 308 : QWidget{parent}, vfs(std::move(vfs)), provider(provider), system{system_} {
310 watcher = new QFileSystemWatcher(this); 309 watcher = new QFileSystemWatcher(this);
311 connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); 310 connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory);
312 311
@@ -738,7 +737,8 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
738 737
739 emit ShouldCancelWorker(); 738 emit ShouldCancelWorker();
740 739
741 GameListWorker* worker = new GameListWorker(vfs, provider, game_dirs, compatibility_list); 740 GameListWorker* worker =
741 new GameListWorker(vfs, provider, game_dirs, compatibility_list, system);
742 742
743 connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); 743 connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
744 connect(worker, &GameListWorker::DirEntryReady, this, &GameList::AddDirEntry, 744 connect(worker, &GameListWorker::DirEntryReady, this, &GameList::AddDirEntry,
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 10339dcca..675469e66 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -72,7 +72,8 @@ public:
72 }; 72 };
73 73
74 explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, 74 explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs,
75 FileSys::ManualContentProvider* provider, GMainWindow* parent = nullptr); 75 FileSys::ManualContentProvider* provider, Core::System& system_,
76 GMainWindow* parent = nullptr);
76 ~GameList() override; 77 ~GameList() override;
77 78
78 QString GetLastFilterResultItem() const; 79 QString GetLastFilterResultItem() const;
@@ -145,6 +146,8 @@ private:
145 CompatibilityList compatibility_list; 146 CompatibilityList compatibility_list;
146 147
147 friend class GameListSearchField; 148 friend class GameListSearchField;
149
150 Core::System& system;
148}; 151};
149 152
150class GameListPlaceholder : public QWidget { 153class GameListPlaceholder : public QWidget {
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 2d5492157..fd92b36df 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -228,16 +228,15 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
228GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, 228GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs,
229 FileSys::ManualContentProvider* provider, 229 FileSys::ManualContentProvider* provider,
230 QVector<UISettings::GameDir>& game_dirs, 230 QVector<UISettings::GameDir>& game_dirs,
231 const CompatibilityList& compatibility_list) 231 const CompatibilityList& compatibility_list, Core::System& system_)
232 : vfs(std::move(vfs)), provider(provider), game_dirs(game_dirs), 232 : vfs(std::move(vfs)), provider(provider), game_dirs(game_dirs),
233 compatibility_list(compatibility_list) {} 233 compatibility_list(compatibility_list), system{system_} {}
234 234
235GameListWorker::~GameListWorker() = default; 235GameListWorker::~GameListWorker() = default;
236 236
237void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { 237void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
238 using namespace FileSys; 238 using namespace FileSys;
239 239
240 auto& system = Core::System::GetInstance();
241 const auto& cache = dynamic_cast<ContentProviderUnion&>(system.GetContentProvider()); 240 const auto& cache = dynamic_cast<ContentProviderUnion&>(system.GetContentProvider());
242 241
243 auto installed_games = cache.ListEntriesFilterOrigin(std::nullopt, TitleType::Application, 242 auto installed_games = cache.ListEntriesFilterOrigin(std::nullopt, TitleType::Application,
@@ -285,10 +284,7 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
285 284
286void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_path, bool deep_scan, 285void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_path, bool deep_scan,
287 GameListDir* parent_dir) { 286 GameListDir* parent_dir) {
288 auto& system = Core::System::GetInstance(); 287 const auto callback = [this, target, parent_dir](const std::filesystem::path& path) -> bool {
289
290 const auto callback = [this, target, parent_dir,
291 &system](const std::filesystem::path& path) -> bool {
292 if (stop_processing) { 288 if (stop_processing) {
293 // Breaks the callback loop. 289 // Breaks the callback loop.
294 return false; 290 return false;
diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h
index 396bb2623..1383e9fbc 100644
--- a/src/yuzu/game_list_worker.h
+++ b/src/yuzu/game_list_worker.h
@@ -19,6 +19,10 @@
19#include "common/common_types.h" 19#include "common/common_types.h"
20#include "yuzu/compatibility_list.h" 20#include "yuzu/compatibility_list.h"
21 21
22namespace Core {
23class System;
24}
25
22class QStandardItem; 26class QStandardItem;
23 27
24namespace FileSys { 28namespace FileSys {
@@ -37,7 +41,7 @@ public:
37 explicit GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs, 41 explicit GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs,
38 FileSys::ManualContentProvider* provider, 42 FileSys::ManualContentProvider* provider,
39 QVector<UISettings::GameDir>& game_dirs, 43 QVector<UISettings::GameDir>& game_dirs,
40 const CompatibilityList& compatibility_list); 44 const CompatibilityList& compatibility_list, Core::System& system_);
41 ~GameListWorker() override; 45 ~GameListWorker() override;
42 46
43 /// Starts the processing of directory tree information. 47 /// Starts the processing of directory tree information.
@@ -80,4 +84,6 @@ private:
80 84
81 QStringList watch_list; 85 QStringList watch_list;
82 std::atomic_bool stop_processing; 86 std::atomic_bool stop_processing;
87
88 Core::System& system;
83}; 89};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 3c2824362..2af582fe5 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -104,6 +104,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
104#include "core/telemetry_session.h" 104#include "core/telemetry_session.h"
105#include "input_common/main.h" 105#include "input_common/main.h"
106#include "input_common/tas/tas_input.h" 106#include "input_common/tas/tas_input.h"
107#include "ui_main.h"
107#include "util/overlay_dialog.h" 108#include "util/overlay_dialog.h"
108#include "video_core/gpu.h" 109#include "video_core/gpu.h"
109#include "video_core/renderer_base.h" 110#include "video_core/renderer_base.h"
@@ -171,7 +172,7 @@ void GMainWindow::ShowTelemetryCallout() {
171 "<br/><br/>Would you like to share your usage data with us?"); 172 "<br/><br/>Would you like to share your usage data with us?");
172 if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) { 173 if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) {
173 Settings::values.enable_telemetry = false; 174 Settings::values.enable_telemetry = false;
174 Core::System::GetInstance().ApplySettings(); 175 system->ApplySettings();
175 } 176 }
176} 177}
177 178
@@ -191,14 +192,16 @@ static void RemoveCachedContents() {
191} 192}
192 193
193GMainWindow::GMainWindow() 194GMainWindow::GMainWindow()
194 : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, 195 : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
195 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, 196 input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
197 config{std::make_unique<Config>(*system)},
198 vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
196 provider{std::make_unique<FileSys::ManualContentProvider>()} { 199 provider{std::make_unique<FileSys::ManualContentProvider>()} {
197 Common::Log::Initialize(); 200 Common::Log::Initialize();
198 LoadTranslation(); 201 LoadTranslation();
199 202
200 setAcceptDrops(true); 203 setAcceptDrops(true);
201 ui.setupUi(this); 204 ui->setupUi(this);
202 statusBar()->hide(); 205 statusBar()->hide();
203 206
204 default_theme_paths = QIcon::themeSearchPaths(); 207 default_theme_paths = QIcon::themeSearchPaths();
@@ -255,11 +258,10 @@ GMainWindow::GMainWindow()
255 258
256 show(); 259 show();
257 260
258 Core::System::GetInstance().SetContentProvider( 261 system->SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
259 std::make_unique<FileSys::ContentProviderUnion>()); 262 system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
260 Core::System::GetInstance().RegisterContentProvider( 263 provider.get());
261 FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); 264 system->GetFileSystemController().CreateFactories(*vfs);
262 Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
263 265
264 // Remove cached contents generated during the previous session 266 // Remove cached contents generated during the previous session
265 RemoveCachedContents(); 267 RemoveCachedContents();
@@ -274,16 +276,16 @@ GMainWindow::GMainWindow()
274 ShowTelemetryCallout(); 276 ShowTelemetryCallout();
275 277
276 // make sure menubar has the arrow cursor instead of inheriting from this 278 // make sure menubar has the arrow cursor instead of inheriting from this
277 ui.menubar->setCursor(QCursor()); 279 ui->menubar->setCursor(QCursor());
278 statusBar()->setCursor(QCursor()); 280 statusBar()->setCursor(QCursor());
279 281
280 mouse_hide_timer.setInterval(default_mouse_timeout); 282 mouse_hide_timer.setInterval(default_mouse_timeout);
281 connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor); 283 connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor);
282 connect(ui.menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor); 284 connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor);
283 285
284 MigrateConfigFiles(); 286 MigrateConfigFiles();
285 287
286 ui.action_Fullscreen->setChecked(false); 288 ui->action_Fullscreen->setChecked(false);
287 289
288 QStringList args = QApplication::arguments(); 290 QStringList args = QApplication::arguments();
289 291
@@ -302,7 +304,7 @@ GMainWindow::GMainWindow()
302 304
303 // Launch game in fullscreen mode 305 // Launch game in fullscreen mode
304 if (args[i] == QStringLiteral("-f")) { 306 if (args[i] == QStringLiteral("-f")) {
305 ui.action_Fullscreen->setChecked(true); 307 ui->action_Fullscreen->setChecked(true);
306 continue; 308 continue;
307 } 309 }
308 310
@@ -405,12 +407,12 @@ void GMainWindow::RegisterMetaTypes() {
405 qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason"); 407 qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
406 408
407 // Register loader types 409 // Register loader types
408 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); 410 qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
409} 411}
410 412
411void GMainWindow::ControllerSelectorReconfigureControllers( 413void GMainWindow::ControllerSelectorReconfigureControllers(
412 const Core::Frontend::ControllerParameters& parameters) { 414 const Core::Frontend::ControllerParameters& parameters) {
413 QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get()); 415 QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system);
414 416
415 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | 417 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
416 Qt::WindowTitleHint | Qt::WindowSystemMenuHint); 418 Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
@@ -420,7 +422,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
420 emit ControllerSelectorReconfigureFinished(); 422 emit ControllerSelectorReconfigureFinished();
421 423
422 // Don't forget to apply settings. 424 // Don't forget to apply settings.
423 Core::System::GetInstance().ApplySettings(); 425 system->ApplySettings();
424 config->Save(); 426 config->Save();
425 427
426 UpdateStatusButtons(); 428 UpdateStatusButtons();
@@ -454,8 +456,8 @@ void GMainWindow::SoftwareKeyboardInitialize(
454 return; 456 return;
455 } 457 }
456 458
457 software_keyboard = new QtSoftwareKeyboardDialog(render_window, Core::System::GetInstance(), 459 software_keyboard = new QtSoftwareKeyboardDialog(render_window, *system, is_inline,
458 is_inline, std::move(initialize_parameters)); 460 std::move(initialize_parameters));
459 461
460 if (is_inline) { 462 if (is_inline) {
461 connect( 463 connect(
@@ -566,11 +568,11 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
566 return; 568 return;
567 } 569 }
568 570
569 QtNXWebEngineView web_browser_view(this, Core::System::GetInstance(), input_subsystem.get()); 571 QtNXWebEngineView web_browser_view(this, *system, input_subsystem.get());
570 572
571 ui.action_Pause->setEnabled(false); 573 ui->action_Pause->setEnabled(false);
572 ui.action_Restart->setEnabled(false); 574 ui->action_Restart->setEnabled(false);
573 ui.action_Stop->setEnabled(false); 575 ui->action_Stop->setEnabled(false);
574 576
575 { 577 {
576 QProgressDialog loading_progress(this); 578 QProgressDialog loading_progress(this);
@@ -634,7 +636,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
634 web_browser_view.SetFinished(true); 636 web_browser_view.SetFinished(true);
635 } 637 }
636 }); 638 });
637 ui.menubar->addAction(exit_action); 639 ui->menubar->addAction(exit_action);
638 640
639 while (!web_browser_view.IsFinished()) { 641 while (!web_browser_view.IsFinished()) {
640 QCoreApplication::processEvents(); 642 QCoreApplication::processEvents();
@@ -676,11 +678,11 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
676 render_window->show(); 678 render_window->show();
677 } 679 }
678 680
679 ui.action_Pause->setEnabled(true); 681 ui->action_Pause->setEnabled(true);
680 ui.action_Restart->setEnabled(true); 682 ui->action_Restart->setEnabled(true);
681 ui.action_Stop->setEnabled(true); 683 ui->action_Stop->setEnabled(true);
682 684
683 ui.menubar->removeAction(exit_action); 685 ui->menubar->removeAction(exit_action);
684 686
685 QCoreApplication::processEvents(); 687 QCoreApplication::processEvents();
686 688
@@ -696,21 +698,21 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
696 698
697void GMainWindow::InitializeWidgets() { 699void GMainWindow::InitializeWidgets() {
698#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING 700#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
699 ui.action_Report_Compatibility->setVisible(true); 701 ui->action_Report_Compatibility->setVisible(true);
700#endif 702#endif
701 render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem); 703 render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *system);
702 render_window->hide(); 704 render_window->hide();
703 705
704 game_list = new GameList(vfs, provider.get(), this); 706 game_list = new GameList(vfs, provider.get(), *system, this);
705 ui.horizontalLayout->addWidget(game_list); 707 ui->horizontalLayout->addWidget(game_list);
706 708
707 game_list_placeholder = new GameListPlaceholder(this); 709 game_list_placeholder = new GameListPlaceholder(this);
708 ui.horizontalLayout->addWidget(game_list_placeholder); 710 ui->horizontalLayout->addWidget(game_list_placeholder);
709 game_list_placeholder->setVisible(false); 711 game_list_placeholder->setVisible(false);
710 712
711 loading_screen = new LoadingScreen(this); 713 loading_screen = new LoadingScreen(this);
712 loading_screen->hide(); 714 loading_screen->hide();
713 ui.horizontalLayout->addWidget(loading_screen); 715 ui->horizontalLayout->addWidget(loading_screen);
714 connect(loading_screen, &LoadingScreen::Hidden, [&] { 716 connect(loading_screen, &LoadingScreen::Hidden, [&] {
715 loading_screen->Clear(); 717 loading_screen->Clear();
716 if (emulation_running) { 718 if (emulation_running) {
@@ -767,14 +769,14 @@ void GMainWindow::InitializeWidgets() {
767 tr("Handheld controller can't be used on docked mode. Pro " 769 tr("Handheld controller can't be used on docked mode. Pro "
768 "controller will be selected.")); 770 "controller will be selected."));
769 controller_type = Settings::ControllerType::ProController; 771 controller_type = Settings::ControllerType::ProController;
770 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get()); 772 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system);
771 configure_dialog.ApplyConfiguration(); 773 configure_dialog.ApplyConfiguration();
772 controller_dialog->refreshConfiguration(); 774 controller_dialog->refreshConfiguration();
773 } 775 }
774 776
775 Settings::values.use_docked_mode.SetValue(!is_docked); 777 Settings::values.use_docked_mode.SetValue(!is_docked);
776 dock_status_button->setChecked(!is_docked); 778 dock_status_button->setChecked(!is_docked);
777 OnDockedModeChanged(is_docked, !is_docked); 779 OnDockedModeChanged(is_docked, !is_docked, *system);
778 }); 780 });
779 dock_status_button->setText(tr("DOCK")); 781 dock_status_button->setText(tr("DOCK"));
780 dock_status_button->setCheckable(true); 782 dock_status_button->setCheckable(true);
@@ -798,7 +800,7 @@ void GMainWindow::InitializeWidgets() {
798 } 800 }
799 } 801 }
800 802
801 Core::System::GetInstance().ApplySettings(); 803 system->ApplySettings();
802 UpdateGPUAccuracyButton(); 804 UpdateGPUAccuracyButton();
803 }); 805 });
804 UpdateGPUAccuracyButton(); 806 UpdateGPUAccuracyButton();
@@ -826,7 +828,7 @@ void GMainWindow::InitializeWidgets() {
826 Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); 828 Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);
827 } 829 }
828 830
829 Core::System::GetInstance().ApplySettings(); 831 system->ApplySettings();
830 }); 832 });
831 statusBar()->insertPermanentWidget(0, renderer_status_button); 833 statusBar()->insertPermanentWidget(0, renderer_status_button);
832 834
@@ -835,7 +837,7 @@ void GMainWindow::InitializeWidgets() {
835} 837}
836 838
837void GMainWindow::InitializeDebugWidgets() { 839void GMainWindow::InitializeDebugWidgets() {
838 QMenu* debug_menu = ui.menu_View_Debugging; 840 QMenu* debug_menu = ui->menu_View_Debugging;
839 841
840#if MICROPROFILE_ENABLED 842#if MICROPROFILE_ENABLED
841 microProfileDialog = new MicroProfileDialog(this); 843 microProfileDialog = new MicroProfileDialog(this);
@@ -843,7 +845,7 @@ void GMainWindow::InitializeDebugWidgets() {
843 debug_menu->addAction(microProfileDialog->toggleViewAction()); 845 debug_menu->addAction(microProfileDialog->toggleViewAction());
844#endif 846#endif
845 847
846 waitTreeWidget = new WaitTreeWidget(this); 848 waitTreeWidget = new WaitTreeWidget(*system, this);
847 addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); 849 addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
848 waitTreeWidget->hide(); 850 waitTreeWidget->hide();
849 debug_menu->addAction(waitTreeWidget->toggleViewAction()); 851 debug_menu->addAction(waitTreeWidget->toggleViewAction());
@@ -864,16 +866,16 @@ void GMainWindow::InitializeRecentFileMenuActions() {
864 actions_recent_files[i]->setVisible(false); 866 actions_recent_files[i]->setVisible(false);
865 connect(actions_recent_files[i], &QAction::triggered, this, &GMainWindow::OnMenuRecentFile); 867 connect(actions_recent_files[i], &QAction::triggered, this, &GMainWindow::OnMenuRecentFile);
866 868
867 ui.menu_recent_files->addAction(actions_recent_files[i]); 869 ui->menu_recent_files->addAction(actions_recent_files[i]);
868 } 870 }
869 ui.menu_recent_files->addSeparator(); 871 ui->menu_recent_files->addSeparator();
870 QAction* action_clear_recent_files = new QAction(this); 872 QAction* action_clear_recent_files = new QAction(this);
871 action_clear_recent_files->setText(tr("&Clear Recent Files")); 873 action_clear_recent_files->setText(tr("&Clear Recent Files"));
872 connect(action_clear_recent_files, &QAction::triggered, this, [this] { 874 connect(action_clear_recent_files, &QAction::triggered, this, [this] {
873 UISettings::values.recent_files.clear(); 875 UISettings::values.recent_files.clear();
874 UpdateRecentFiles(); 876 UpdateRecentFiles();
875 }); 877 });
876 ui.menu_recent_files->addAction(action_clear_recent_files); 878 ui->menu_recent_files->addAction(action_clear_recent_files);
877 879
878 UpdateRecentFiles(); 880 UpdateRecentFiles();
879} 881}
@@ -892,43 +894,43 @@ void GMainWindow::InitializeHotkeys() {
892 const QString fullscreen = QStringLiteral("Fullscreen"); 894 const QString fullscreen = QStringLiteral("Fullscreen");
893 const QString capture_screenshot = QStringLiteral("Capture Screenshot"); 895 const QString capture_screenshot = QStringLiteral("Capture Screenshot");
894 896
895 ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); 897 ui->action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file));
896 ui.action_Load_File->setShortcutContext( 898 ui->action_Load_File->setShortcutContext(
897 hotkey_registry.GetShortcutContext(main_window, load_file)); 899 hotkey_registry.GetShortcutContext(main_window, load_file));
898 900
899 ui.action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo)); 901 ui->action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo));
900 ui.action_Load_Amiibo->setShortcutContext( 902 ui->action_Load_Amiibo->setShortcutContext(
901 hotkey_registry.GetShortcutContext(main_window, load_amiibo)); 903 hotkey_registry.GetShortcutContext(main_window, load_amiibo));
902 904
903 ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu)); 905 ui->action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu));
904 ui.action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu)); 906 ui->action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu));
905 907
906 ui.action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation)); 908 ui->action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation));
907 ui.action_Restart->setShortcutContext( 909 ui->action_Restart->setShortcutContext(
908 hotkey_registry.GetShortcutContext(main_window, restart_emulation)); 910 hotkey_registry.GetShortcutContext(main_window, restart_emulation));
909 911
910 ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation)); 912 ui->action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation));
911 ui.action_Stop->setShortcutContext( 913 ui->action_Stop->setShortcutContext(
912 hotkey_registry.GetShortcutContext(main_window, stop_emulation)); 914 hotkey_registry.GetShortcutContext(main_window, stop_emulation));
913 915
914 ui.action_Show_Filter_Bar->setShortcut( 916 ui->action_Show_Filter_Bar->setShortcut(
915 hotkey_registry.GetKeySequence(main_window, toggle_filter_bar)); 917 hotkey_registry.GetKeySequence(main_window, toggle_filter_bar));
916 ui.action_Show_Filter_Bar->setShortcutContext( 918 ui->action_Show_Filter_Bar->setShortcutContext(
917 hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar)); 919 hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar));
918 920
919 ui.action_Show_Status_Bar->setShortcut( 921 ui->action_Show_Status_Bar->setShortcut(
920 hotkey_registry.GetKeySequence(main_window, toggle_status_bar)); 922 hotkey_registry.GetKeySequence(main_window, toggle_status_bar));
921 ui.action_Show_Status_Bar->setShortcutContext( 923 ui->action_Show_Status_Bar->setShortcutContext(
922 hotkey_registry.GetShortcutContext(main_window, toggle_status_bar)); 924 hotkey_registry.GetShortcutContext(main_window, toggle_status_bar));
923 925
924 ui.action_Capture_Screenshot->setShortcut( 926 ui->action_Capture_Screenshot->setShortcut(
925 hotkey_registry.GetKeySequence(main_window, capture_screenshot)); 927 hotkey_registry.GetKeySequence(main_window, capture_screenshot));
926 ui.action_Capture_Screenshot->setShortcutContext( 928 ui->action_Capture_Screenshot->setShortcutContext(
927 hotkey_registry.GetShortcutContext(main_window, capture_screenshot)); 929 hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
928 930
929 ui.action_Fullscreen->setShortcut( 931 ui->action_Fullscreen->setShortcut(
930 hotkey_registry.GetHotkey(main_window, fullscreen, this)->key()); 932 hotkey_registry.GetHotkey(main_window, fullscreen, this)->key());
931 ui.action_Fullscreen->setShortcutContext( 933 ui->action_Fullscreen->setShortcutContext(
932 hotkey_registry.GetShortcutContext(main_window, fullscreen)); 934 hotkey_registry.GetShortcutContext(main_window, fullscreen));
933 935
934 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), 936 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
@@ -946,19 +948,19 @@ void GMainWindow::InitializeHotkeys() {
946 }); 948 });
947 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this), 949 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this),
948 &QShortcut::activated, this, [this] { 950 &QShortcut::activated, this, [this] {
949 if (!Core::System::GetInstance().IsPoweredOn()) { 951 if (!system->IsPoweredOn()) {
950 return; 952 return;
951 } 953 }
952 BootGame(game_path); 954 BootGame(game_path);
953 }); 955 });
954 connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window), 956 connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
955 &QShortcut::activated, ui.action_Fullscreen, &QAction::trigger); 957 &QShortcut::activated, ui->action_Fullscreen, &QAction::trigger);
956 connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window), 958 connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
957 &QShortcut::activatedAmbiguously, ui.action_Fullscreen, &QAction::trigger); 959 &QShortcut::activatedAmbiguously, ui->action_Fullscreen, &QAction::trigger);
958 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this), 960 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
959 &QShortcut::activated, this, [&] { 961 &QShortcut::activated, this, [&] {
960 if (emulation_running) { 962 if (emulation_running) {
961 ui.action_Fullscreen->setChecked(false); 963 ui->action_Fullscreen->setChecked(false);
962 ToggleFullscreen(); 964 ToggleFullscreen();
963 } 965 }
964 }); 966 });
@@ -987,7 +989,7 @@ void GMainWindow::InitializeHotkeys() {
987 }); 989 });
988 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this), 990 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this),
989 &QShortcut::activated, this, [&] { 991 &QShortcut::activated, this, [&] {
990 if (ui.action_Load_Amiibo->isEnabled()) { 992 if (ui->action_Load_Amiibo->isEnabled()) {
991 OnLoadAmiibo(); 993 OnLoadAmiibo();
992 } 994 }
993 }); 995 });
@@ -1002,7 +1004,7 @@ void GMainWindow::InitializeHotkeys() {
1002 Settings::values.use_docked_mode.SetValue( 1004 Settings::values.use_docked_mode.SetValue(
1003 !Settings::values.use_docked_mode.GetValue()); 1005 !Settings::values.use_docked_mode.GetValue());
1004 OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(), 1006 OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(),
1005 Settings::values.use_docked_mode.GetValue()); 1007 Settings::values.use_docked_mode.GetValue(), *system);
1006 dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); 1008 dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
1007 }); 1009 });
1008 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this), 1010 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
@@ -1068,20 +1070,20 @@ void GMainWindow::RestoreUIState() {
1068 1070
1069 game_list->LoadInterfaceLayout(); 1071 game_list->LoadInterfaceLayout();
1070 1072
1071 ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode.GetValue()); 1073 ui->action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode.GetValue());
1072 ToggleWindowMode(); 1074 ToggleWindowMode();
1073 1075
1074 ui.action_Fullscreen->setChecked(UISettings::values.fullscreen.GetValue()); 1076 ui->action_Fullscreen->setChecked(UISettings::values.fullscreen.GetValue());
1075 1077
1076 ui.action_Display_Dock_Widget_Headers->setChecked( 1078 ui->action_Display_Dock_Widget_Headers->setChecked(
1077 UISettings::values.display_titlebar.GetValue()); 1079 UISettings::values.display_titlebar.GetValue());
1078 OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked()); 1080 OnDisplayTitleBars(ui->action_Display_Dock_Widget_Headers->isChecked());
1079 1081
1080 ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar.GetValue()); 1082 ui->action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar.GetValue());
1081 game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked()); 1083 game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked());
1082 1084
1083 ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue()); 1085 ui->action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
1084 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); 1086 statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
1085 Debugger::ToggleConsole(); 1087 Debugger::ToggleConsole();
1086} 1088}
1087 1089
@@ -1093,11 +1095,11 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
1093 state != Qt::ApplicationActive) { 1095 state != Qt::ApplicationActive) {
1094 LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state); 1096 LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state);
1095 } 1097 }
1096 if (ui.action_Pause->isEnabled() && 1098 if (ui->action_Pause->isEnabled() &&
1097 (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) { 1099 (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
1098 auto_paused = true; 1100 auto_paused = true;
1099 OnPauseGame(); 1101 OnPauseGame();
1100 } else if (ui.action_Start->isEnabled() && auto_paused && state == Qt::ApplicationActive) { 1102 } else if (ui->action_Start->isEnabled() && auto_paused && state == Qt::ApplicationActive) {
1101 auto_paused = false; 1103 auto_paused = false;
1102 OnStartGame(); 1104 OnStartGame();
1103 } 1105 }
@@ -1142,53 +1144,60 @@ void GMainWindow::ConnectWidgetEvents() {
1142 1144
1143void GMainWindow::ConnectMenuEvents() { 1145void GMainWindow::ConnectMenuEvents() {
1144 // File 1146 // File
1145 connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); 1147 connect(ui->action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile);
1146 connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder); 1148 connect(ui->action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder);
1147 connect(ui.action_Install_File_NAND, &QAction::triggered, this, 1149 connect(ui->action_Install_File_NAND, &QAction::triggered, this,
1148 &GMainWindow::OnMenuInstallToNAND); 1150 &GMainWindow::OnMenuInstallToNAND);
1149 connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); 1151 connect(ui->action_Exit, &QAction::triggered, this, &QMainWindow::close);
1150 connect(ui.action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo); 1152 connect(ui->action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo);
1151 1153
1152 // Emulation 1154 // Emulation
1153 connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); 1155 connect(ui->action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame);
1154 connect(ui.action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame); 1156 connect(ui->action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame);
1155 connect(ui.action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame); 1157 connect(ui->action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame);
1156 connect(ui.action_Report_Compatibility, &QAction::triggered, this, 1158 connect(ui->action_Report_Compatibility, &QAction::triggered, this,
1157 &GMainWindow::OnMenuReportCompatibility); 1159 &GMainWindow::OnMenuReportCompatibility);
1158 connect(ui.action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage); 1160 connect(ui->action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage);
1159 connect(ui.action_Open_Quickstart_Guide, &QAction::triggered, this, 1161 connect(ui->action_Open_Quickstart_Guide, &QAction::triggered, this,
1160 &GMainWindow::OnOpenQuickstartGuide); 1162 &GMainWindow::OnOpenQuickstartGuide);
1161 connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ); 1163 connect(ui->action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ);
1162 connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); 1164 connect(ui->action_Restart, &QAction::triggered, this,
1163 connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); 1165 [this] { BootGame(QString(game_path)); });
1164 connect(ui.action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas); 1166 connect(ui->action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
1165 connect(ui.action_Configure_Current_Game, &QAction::triggered, this, 1167 connect(ui->action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
1168 connect(ui->action_Configure_Current_Game, &QAction::triggered, this,
1166 &GMainWindow::OnConfigurePerGame); 1169 &GMainWindow::OnConfigurePerGame);
1167 1170
1168 // View 1171 // View
1169 connect(ui.action_Single_Window_Mode, &QAction::triggered, this, 1172 connect(ui->action_Single_Window_Mode, &QAction::triggered, this,
1170 &GMainWindow::ToggleWindowMode); 1173 &GMainWindow::ToggleWindowMode);
1171 connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this, 1174 connect(ui->action_Display_Dock_Widget_Headers, &QAction::triggered, this,
1172 &GMainWindow::OnDisplayTitleBars); 1175 &GMainWindow::OnDisplayTitleBars);
1173 connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); 1176 connect(ui->action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
1174 connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); 1177 connect(ui->action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
1175 connect(ui.action_Reset_Window_Size_720, &QAction::triggered, this, 1178
1179 connect(ui->action_Reset_Window_Size_720, &QAction::triggered, this,
1176 &GMainWindow::ResetWindowSize720); 1180 &GMainWindow::ResetWindowSize720);
1177 connect(ui.action_Reset_Window_Size_1080, &QAction::triggered, this, 1181 connect(ui->action_Reset_Window_Size_900, &QAction::triggered, this,
1182 &GMainWindow::ResetWindowSize900);
1183 connect(ui->action_Reset_Window_Size_1080, &QAction::triggered, this,
1178 &GMainWindow::ResetWindowSize1080); 1184 &GMainWindow::ResetWindowSize1080);
1185 ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_720);
1186 ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_900);
1187 ui->menu_Reset_Window_Size->addAction(ui->action_Reset_Window_Size_1080);
1179 1188
1180 // Fullscreen 1189 // Fullscreen
1181 connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); 1190 connect(ui->action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
1182 1191
1183 // Movie 1192 // Movie
1184 connect(ui.action_Capture_Screenshot, &QAction::triggered, this, 1193 connect(ui->action_Capture_Screenshot, &QAction::triggered, this,
1185 &GMainWindow::OnCaptureScreenshot); 1194 &GMainWindow::OnCaptureScreenshot);
1186 1195
1187 // Help 1196 // Help
1188 connect(ui.action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder); 1197 connect(ui->action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
1189 connect(ui.action_Rederive, &QAction::triggered, this, 1198 connect(ui->action_Rederive, &QAction::triggered, this,
1190 std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); 1199 std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
1191 connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnAbout); 1200 connect(ui->action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
1192} 1201}
1193 1202
1194void GMainWindow::OnDisplayTitleBars(bool show) { 1203void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -1232,10 +1241,9 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1232 return false; 1241 return false;
1233 } 1242 }
1234 1243
1235 Core::System& system{Core::System::GetInstance()}; 1244 system->SetFilesystem(vfs);
1236 system.SetFilesystem(vfs);
1237 1245
1238 system.SetAppletFrontendSet({ 1246 system->SetAppletFrontendSet({
1239 std::make_unique<QtControllerSelector>(*this), // Controller Selector 1247 std::make_unique<QtControllerSelector>(*this), // Controller Selector
1240 std::make_unique<QtErrorDisplay>(*this), // Error Display 1248 std::make_unique<QtErrorDisplay>(*this), // Error Display
1241 nullptr, // Parental Controls 1249 nullptr, // Parental Controls
@@ -1245,14 +1253,14 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1245 std::make_unique<QtWebBrowser>(*this), // Web Browser 1253 std::make_unique<QtWebBrowser>(*this), // Web Browser
1246 }); 1254 });
1247 1255
1248 const Core::System::ResultStatus result{ 1256 const Core::SystemResultStatus result{
1249 system.Load(*render_window, filename.toStdString(), program_id, program_index)}; 1257 system->Load(*render_window, filename.toStdString(), program_id, program_index)};
1250 1258
1251 const auto drd_callout = (UISettings::values.callout_flags.GetValue() & 1259 const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
1252 static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; 1260 static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
1253 1261
1254 if (result == Core::System::ResultStatus::Success && 1262 if (result == Core::SystemResultStatus::Success &&
1255 system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && 1263 system->GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory &&
1256 drd_callout) { 1264 drd_callout) {
1257 UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() | 1265 UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() |
1258 static_cast<u32>(CalloutFlag::DRDDeprecation); 1266 static_cast<u32>(CalloutFlag::DRDDeprecation);
@@ -1266,14 +1274,14 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1266 "wiki</a>. This message will not be shown again.")); 1274 "wiki</a>. This message will not be shown again."));
1267 } 1275 }
1268 1276
1269 if (result != Core::System::ResultStatus::Success) { 1277 if (result != Core::SystemResultStatus::Success) {
1270 switch (result) { 1278 switch (result) {
1271 case Core::System::ResultStatus::ErrorGetLoader: 1279 case Core::SystemResultStatus::ErrorGetLoader:
1272 LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filename.toStdString()); 1280 LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filename.toStdString());
1273 QMessageBox::critical(this, tr("Error while loading ROM!"), 1281 QMessageBox::critical(this, tr("Error while loading ROM!"),
1274 tr("The ROM format is not supported.")); 1282 tr("The ROM format is not supported."));
1275 break; 1283 break;
1276 case Core::System::ResultStatus::ErrorVideoCore: 1284 case Core::SystemResultStatus::ErrorVideoCore:
1277 QMessageBox::critical( 1285 QMessageBox::critical(
1278 this, tr("An error occurred initializing the video core."), 1286 this, tr("An error occurred initializing the video core."),
1279 tr("yuzu has encountered an error while running the video core, please see the " 1287 tr("yuzu has encountered an error while running the video core, please see the "
@@ -1287,8 +1295,8 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1287 break; 1295 break;
1288 1296
1289 default: 1297 default:
1290 if (result > Core::System::ResultStatus::ErrorLoader) { 1298 if (result > Core::SystemResultStatus::ErrorLoader) {
1291 const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader); 1299 const u16 loader_id = static_cast<u16>(Core::SystemResultStatus::ErrorLoader);
1292 const u16 error_id = static_cast<u16>(result) - loader_id; 1300 const u16 error_id = static_cast<u16>(result) - loader_id;
1293 const std::string error_code = fmt::format("({:04X}-{:04X})", loader_id, error_id); 1301 const std::string error_code = fmt::format("({:04X}-{:04X})", loader_id, error_id);
1294 LOG_CRITICAL(Frontend, "Failed to load ROM! {}", error_code); 1302 LOG_CRITICAL(Frontend, "Failed to load ROM! {}", error_code);
@@ -1316,7 +1324,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1316 } 1324 }
1317 game_path = filename; 1325 game_path = filename;
1318 1326
1319 system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt"); 1327 system->TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt");
1320 return true; 1328 return true;
1321} 1329}
1322 1330
@@ -1342,9 +1350,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1342 1350
1343 last_filename_booted = filename; 1351 last_filename_booted = filename;
1344 1352
1345 auto& system = Core::System::GetInstance();
1346 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); 1353 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
1347 const auto loader = Loader::GetLoader(system, v_file, program_id, program_index); 1354 const auto loader = Loader::GetLoader(*system, v_file, program_id, program_index);
1348 1355
1349 if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && 1356 if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success &&
1350 type == StartGameType::Normal) { 1357 type == StartGameType::Normal) {
@@ -1353,7 +1360,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1353 const auto config_file_name = title_id == 0 1360 const auto config_file_name = title_id == 0
1354 ? Common::FS::PathToUTF8String(file_path.filename()) 1361 ? Common::FS::PathToUTF8String(file_path.filename())
1355 : fmt::format("{:016X}", title_id); 1362 : fmt::format("{:016X}", title_id);
1356 Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); 1363 Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig);
1357 } 1364 }
1358 1365
1359 ConfigureVibration::SetAllVibrationDevices(); 1366 ConfigureVibration::SetAllVibrationDevices();
@@ -1376,14 +1383,17 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1376 return; 1383 return;
1377 1384
1378 // Create and start the emulation thread 1385 // Create and start the emulation thread
1379 emu_thread = std::make_unique<EmuThread>(); 1386 emu_thread = std::make_unique<EmuThread>(*system);
1380 emit EmulationStarting(emu_thread.get()); 1387 emit EmulationStarting(emu_thread.get());
1381 emu_thread->start(); 1388 emu_thread->start();
1382 1389
1383 // Register an ExecuteProgram callback such that Core can execute a sub-program 1390 // Register an ExecuteProgram callback such that Core can execute a sub-program
1384 system.RegisterExecuteProgramCallback( 1391 system->RegisterExecuteProgramCallback(
1385 [this](std::size_t program_index) { render_window->ExecuteProgram(program_index); }); 1392 [this](std::size_t program_index) { render_window->ExecuteProgram(program_index); });
1386 1393
1394 // Register an Exit callback such that Core can exit the currently running application.
1395 system->RegisterExitCallback([this]() { render_window->Exit(); });
1396
1387 connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); 1397 connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
1388 connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity); 1398 connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity);
1389 // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views 1399 // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views
@@ -1398,7 +1408,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1398 1408
1399 // Update the GUI 1409 // Update the GUI
1400 UpdateStatusButtons(); 1410 UpdateStatusButtons();
1401 if (ui.action_Single_Window_Mode->isChecked()) { 1411 if (ui->action_Single_Window_Mode->isChecked()) {
1402 game_list->hide(); 1412 game_list->hide();
1403 game_list_placeholder->hide(); 1413 game_list_placeholder->hide();
1404 } 1414 }
@@ -1416,11 +1426,11 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1416 1426
1417 std::string title_name; 1427 std::string title_name;
1418 std::string title_version; 1428 std::string title_version;
1419 const auto res = system.GetGameName(title_name); 1429 const auto res = system->GetGameName(title_name);
1420 1430
1421 const auto metadata = [&system, title_id] { 1431 const auto metadata = [this, title_id] {
1422 const FileSys::PatchManager pm(title_id, system.GetFileSystemController(), 1432 const FileSys::PatchManager pm(title_id, system->GetFileSystemController(),
1423 system.GetContentProvider()); 1433 system->GetContentProvider());
1424 return pm.GetControlMetadata(); 1434 return pm.GetControlMetadata();
1425 }(); 1435 }();
1426 if (metadata.first != nullptr) { 1436 if (metadata.first != nullptr) {
@@ -1431,20 +1441,20 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1431 title_name = Common::FS::PathToUTF8String( 1441 title_name = Common::FS::PathToUTF8String(
1432 std::filesystem::path{filename.toStdU16String()}.filename()); 1442 std::filesystem::path{filename.toStdU16String()}.filename());
1433 } 1443 }
1434 const bool is_64bit = system.Kernel().CurrentProcess()->Is64BitProcess(); 1444 const bool is_64bit = system->Kernel().CurrentProcess()->Is64BitProcess();
1435 const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); 1445 const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)");
1436 title_name = tr("%1 %2", "%1 is the title name. %2 indicates if the title is 64-bit or 32-bit") 1446 title_name = tr("%1 %2", "%1 is the title name. %2 indicates if the title is 64-bit or 32-bit")
1437 .arg(QString::fromStdString(title_name), instruction_set_suffix) 1447 .arg(QString::fromStdString(title_name), instruction_set_suffix)
1438 .toStdString(); 1448 .toStdString();
1439 LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); 1449 LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version);
1440 const auto gpu_vendor = system.GPU().Renderer().GetDeviceVendor(); 1450 const auto gpu_vendor = system->GPU().Renderer().GetDeviceVendor();
1441 UpdateWindowTitle(title_name, title_version, gpu_vendor); 1451 UpdateWindowTitle(title_name, title_version, gpu_vendor);
1442 1452
1443 loading_screen->Prepare(system.GetAppLoader()); 1453 loading_screen->Prepare(system->GetAppLoader());
1444 loading_screen->show(); 1454 loading_screen->show();
1445 1455
1446 emulation_running = true; 1456 emulation_running = true;
1447 if (ui.action_Fullscreen->isChecked()) { 1457 if (ui->action_Fullscreen->isChecked()) {
1448 ShowFullscreen(); 1458 ShowFullscreen();
1449 } 1459 }
1450 OnStartGame(); 1460 OnStartGame();
@@ -1455,7 +1465,7 @@ void GMainWindow::ShutdownGame() {
1455 return; 1465 return;
1456 } 1466 }
1457 1467
1458 if (ui.action_Fullscreen->isChecked()) { 1468 if (ui->action_Fullscreen->isChecked()) {
1459 HideFullscreen(); 1469 HideFullscreen();
1460 } 1470 }
1461 1471
@@ -1476,15 +1486,15 @@ void GMainWindow::ShutdownGame() {
1476 disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); 1486 disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
1477 1487
1478 // Update the GUI 1488 // Update the GUI
1479 ui.action_Start->setEnabled(false); 1489 ui->action_Start->setEnabled(false);
1480 ui.action_Start->setText(tr("Start")); 1490 ui->action_Start->setText(tr("Start"));
1481 ui.action_Pause->setEnabled(false); 1491 ui->action_Pause->setEnabled(false);
1482 ui.action_Stop->setEnabled(false); 1492 ui->action_Stop->setEnabled(false);
1483 ui.action_Restart->setEnabled(false); 1493 ui->action_Restart->setEnabled(false);
1484 ui.action_Configure_Current_Game->setEnabled(false); 1494 ui->action_Configure_Current_Game->setEnabled(false);
1485 ui.action_Report_Compatibility->setEnabled(false); 1495 ui->action_Report_Compatibility->setEnabled(false);
1486 ui.action_Load_Amiibo->setEnabled(false); 1496 ui->action_Load_Amiibo->setEnabled(false);
1487 ui.action_Capture_Screenshot->setEnabled(false); 1497 ui->action_Capture_Screenshot->setEnabled(false);
1488 render_window->hide(); 1498 render_window->hide();
1489 loading_screen->hide(); 1499 loading_screen->hide();
1490 loading_screen->Clear(); 1500 loading_screen->Clear();
@@ -1546,7 +1556,7 @@ void GMainWindow::UpdateRecentFiles() {
1546 } 1556 }
1547 1557
1548 // Enable the recent files menu if the list isn't empty 1558 // Enable the recent files menu if the list isn't empty
1549 ui.menu_recent_files->setEnabled(num_recent_files != 0); 1559 ui->menu_recent_files->setEnabled(num_recent_files != 0);
1550} 1560}
1551 1561
1552void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { 1562void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) {
@@ -1557,18 +1567,17 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
1557 const std::string& game_path) { 1567 const std::string& game_path) {
1558 std::filesystem::path path; 1568 std::filesystem::path path;
1559 QString open_target; 1569 QString open_target;
1560 auto& system = Core::System::GetInstance();
1561 1570
1562 const auto [user_save_size, device_save_size] = [this, &game_path, &program_id, &system] { 1571 const auto [user_save_size, device_save_size] = [this, &game_path, &program_id] {
1563 const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), 1572 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
1564 system.GetContentProvider()}; 1573 system->GetContentProvider()};
1565 const auto control = pm.GetControlMetadata().first; 1574 const auto control = pm.GetControlMetadata().first;
1566 if (control != nullptr) { 1575 if (control != nullptr) {
1567 return std::make_pair(control->GetDefaultNormalSaveSize(), 1576 return std::make_pair(control->GetDefaultNormalSaveSize(),
1568 control->GetDeviceSaveDataSize()); 1577 control->GetDeviceSaveDataSize());
1569 } else { 1578 } else {
1570 const auto file = Core::GetGameFileFromPath(vfs, game_path); 1579 const auto file = Core::GetGameFileFromPath(vfs, game_path);
1571 const auto loader = Loader::GetLoader(system, file); 1580 const auto loader = Loader::GetLoader(*system, file);
1572 1581
1573 FileSys::NACP nacp{}; 1582 FileSys::NACP nacp{};
1574 loader->ReadControlData(nacp); 1583 loader->ReadControlData(nacp);
@@ -1611,14 +1620,14 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
1611 ASSERT(user_id); 1620 ASSERT(user_id);
1612 1621
1613 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 1622 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
1614 system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1623 *system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
1615 program_id, user_id->uuid, 0); 1624 program_id, user_id->uuid, 0);
1616 1625
1617 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); 1626 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
1618 } else { 1627 } else {
1619 // Device save data 1628 // Device save data
1620 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( 1629 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath(
1621 system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1630 *system, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
1622 program_id, {}, 0); 1631 program_id, {}, 0);
1623 1632
1624 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); 1633 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path);
@@ -1657,7 +1666,7 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
1657 const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; 1666 const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
1658 if (!Common::FS::CreateDirs(shader_cache_folder_path)) { 1667 if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
1659 QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), 1668 QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"),
1660 tr("Filed to create the shader cache directory for this title.")); 1669 tr("Failed to create the shader cache directory for this title."));
1661 return; 1670 return;
1662 } 1671 }
1663 const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; 1672 const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)};
@@ -1745,7 +1754,7 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT
1745} 1754}
1746 1755
1747void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) { 1756void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) {
1748 const auto& fs_controller = Core::System::GetInstance().GetFileSystemController(); 1757 const auto& fs_controller = system->GetFileSystemController();
1749 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || 1758 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) ||
1750 fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); 1759 fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id);
1751 1760
@@ -1761,7 +1770,7 @@ void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) {
1761 1770
1762void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) { 1771void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) {
1763 const auto update_id = program_id | 0x800; 1772 const auto update_id = program_id | 0x800;
1764 const auto& fs_controller = Core::System::GetInstance().GetFileSystemController(); 1773 const auto& fs_controller = system->GetFileSystemController();
1765 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || 1774 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
1766 fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id); 1775 fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id);
1767 1776
@@ -1776,8 +1785,8 @@ void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type)
1776 1785
1777void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) { 1786void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) {
1778 u32 count{}; 1787 u32 count{};
1779 const auto& fs_controller = Core::System::GetInstance().GetFileSystemController(); 1788 const auto& fs_controller = system->GetFileSystemController();
1780 const auto dlc_entries = Core::System::GetInstance().GetContentProvider().ListEntriesFilter( 1789 const auto dlc_entries = system->GetContentProvider().ListEntriesFilter(
1781 FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); 1790 FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
1782 1791
1783 for (const auto& entry : dlc_entries) { 1792 for (const auto& entry : dlc_entries) {
@@ -1915,8 +1924,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
1915 "cancelled the operation.")); 1924 "cancelled the operation."));
1916 }; 1925 };
1917 1926
1918 auto& system = Core::System::GetInstance(); 1927 const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read));
1919 const auto loader = Loader::GetLoader(system, vfs->OpenFile(game_path, FileSys::Mode::Read));
1920 if (loader == nullptr) { 1928 if (loader == nullptr) {
1921 failed(); 1929 failed();
1922 return; 1930 return;
@@ -1928,7 +1936,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
1928 return; 1936 return;
1929 } 1937 }
1930 1938
1931 const auto& installed = system.GetContentProvider(); 1939 const auto& installed = system->GetContentProvider();
1932 const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id); 1940 const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
1933 1941
1934 if (!romfs_title_id) { 1942 if (!romfs_title_id) {
@@ -1948,7 +1956,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
1948 1956
1949 if (*romfs_title_id == program_id) { 1957 if (*romfs_title_id == program_id) {
1950 const u64 ivfc_offset = loader->ReadRomFSIVFCOffset(); 1958 const u64 ivfc_offset = loader->ReadRomFSIVFCOffset();
1951 const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), installed}; 1959 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), installed};
1952 romfs = 1960 romfs =
1953 pm.PatchRomFS(file, ivfc_offset, FileSys::ContentRecordType::Program, nullptr, false); 1961 pm.PatchRomFS(file, ivfc_offset, FileSys::ContentRecordType::Program, nullptr, false);
1954 } else { 1962 } else {
@@ -2074,7 +2082,7 @@ void GMainWindow::OnGameListAddDirectory() {
2074} 2082}
2075 2083
2076void GMainWindow::OnGameListShowList(bool show) { 2084void GMainWindow::OnGameListShowList(bool show) {
2077 if (emulation_running && ui.action_Single_Window_Mode->isChecked()) 2085 if (emulation_running && ui->action_Single_Window_Mode->isChecked())
2078 return; 2086 return;
2079 game_list->setVisible(show); 2087 game_list->setVisible(show);
2080 game_list_placeholder->setVisible(!show); 2088 game_list_placeholder->setVisible(!show);
@@ -2083,7 +2091,7 @@ void GMainWindow::OnGameListShowList(bool show) {
2083void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { 2091void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
2084 u64 title_id{}; 2092 u64 title_id{};
2085 const auto v_file = Core::GetGameFileFromPath(vfs, file); 2093 const auto v_file = Core::GetGameFileFromPath(vfs, file);
2086 const auto loader = Loader::GetLoader(Core::System::GetInstance(), v_file); 2094 const auto loader = Loader::GetLoader(*system, v_file);
2087 2095
2088 if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { 2096 if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
2089 QMessageBox::information(this, tr("Properties"), 2097 QMessageBox::information(this, tr("Properties"),
@@ -2176,7 +2184,7 @@ void GMainWindow::OnMenuInstallToNAND() {
2176 QStringList failed_files{}; // Files that failed to install due to errors 2184 QStringList failed_files{}; // Files that failed to install due to errors
2177 bool detected_base_install{}; // Whether a base game was attempted to be installed 2185 bool detected_base_install{}; // Whether a base game was attempted to be installed
2178 2186
2179 ui.action_Install_File_NAND->setEnabled(false); 2187 ui->action_Install_File_NAND->setEnabled(false);
2180 2188
2181 install_progress = new QProgressDialog(QString{}, tr("Cancel"), 0, total_size, this); 2189 install_progress = new QProgressDialog(QString{}, tr("Cancel"), 0, total_size, this);
2182 install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint & 2190 install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
@@ -2252,7 +2260,7 @@ void GMainWindow::OnMenuInstallToNAND() {
2252 Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / 2260 Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) /
2253 "game_list"); 2261 "game_list");
2254 game_list->PopulateAsync(UISettings::values.game_dirs); 2262 game_list->PopulateAsync(UISettings::values.game_dirs);
2255 ui.action_Install_File_NAND->setEnabled(true); 2263 ui->action_Install_File_NAND->setEnabled(true);
2256} 2264}
2257 2265
2258InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { 2266InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
@@ -2297,9 +2305,8 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
2297 if (nsp->GetStatus() != Loader::ResultStatus::Success) { 2305 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
2298 return InstallResult::Failure; 2306 return InstallResult::Failure;
2299 } 2307 }
2300 const auto res = 2308 const auto res = system->GetFileSystemController().GetUserNANDContents()->InstallEntry(
2301 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry( 2309 *nsp, true, qt_raw_copy);
2302 *nsp, true, qt_raw_copy);
2303 switch (res) { 2310 switch (res) {
2304 case FileSys::InstallResult::Success: 2311 case FileSys::InstallResult::Success:
2305 return InstallResult::Success; 2312 return InstallResult::Success;
@@ -2377,19 +2384,13 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) {
2377 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); 2384 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
2378 } 2385 }
2379 2386
2380 FileSys::InstallResult res; 2387 const bool is_application = index >= static_cast<s32>(FileSys::TitleType::Application);
2381 if (index >= static_cast<s32>(FileSys::TitleType::Application)) { 2388 const auto& fs_controller = system->GetFileSystemController();
2382 res = Core::System::GetInstance() 2389 auto* registered_cache = is_application ? fs_controller.GetUserNANDContents()
2383 .GetFileSystemController() 2390 : fs_controller.GetSystemNANDContents();
2384 .GetUserNANDContents()
2385 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
2386 } else {
2387 res = Core::System::GetInstance()
2388 .GetFileSystemController()
2389 .GetSystemNANDContents()
2390 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
2391 }
2392 2391
2392 const auto res = registered_cache->InstallEntry(*nca, static_cast<FileSys::TitleType>(index),
2393 true, qt_raw_copy);
2393 if (res == FileSys::InstallResult::Success) { 2394 if (res == FileSys::InstallResult::Success) {
2394 return InstallResult::Success; 2395 return InstallResult::Success;
2395 } else if (res == FileSys::InstallResult::OverwriteExisting) { 2396 } else if (res == FileSys::InstallResult::OverwriteExisting) {
@@ -2423,40 +2424,39 @@ void GMainWindow::OnStartGame() {
2423 2424
2424 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); 2425 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
2425 2426
2426 ui.action_Start->setEnabled(false); 2427 ui->action_Start->setEnabled(false);
2427 ui.action_Start->setText(tr("&Continue")); 2428 ui->action_Start->setText(tr("&Continue"));
2428 2429
2429 ui.action_Pause->setEnabled(true); 2430 ui->action_Pause->setEnabled(true);
2430 ui.action_Stop->setEnabled(true); 2431 ui->action_Stop->setEnabled(true);
2431 ui.action_Restart->setEnabled(true); 2432 ui->action_Restart->setEnabled(true);
2432 ui.action_Configure_Current_Game->setEnabled(true); 2433 ui->action_Configure_Current_Game->setEnabled(true);
2433 ui.action_Report_Compatibility->setEnabled(true); 2434 ui->action_Report_Compatibility->setEnabled(true);
2434 2435
2435 discord_rpc->Update(); 2436 discord_rpc->Update();
2436 ui.action_Load_Amiibo->setEnabled(true); 2437 ui->action_Load_Amiibo->setEnabled(true);
2437 ui.action_Capture_Screenshot->setEnabled(true); 2438 ui->action_Capture_Screenshot->setEnabled(true);
2438} 2439}
2439 2440
2440void GMainWindow::OnPauseGame() { 2441void GMainWindow::OnPauseGame() {
2441 emu_thread->SetRunning(false); 2442 emu_thread->SetRunning(false);
2442 2443
2443 ui.action_Start->setEnabled(true); 2444 ui->action_Start->setEnabled(true);
2444 ui.action_Pause->setEnabled(false); 2445 ui->action_Pause->setEnabled(false);
2445 ui.action_Stop->setEnabled(true); 2446 ui->action_Stop->setEnabled(true);
2446 ui.action_Capture_Screenshot->setEnabled(false); 2447 ui->action_Capture_Screenshot->setEnabled(false);
2447 2448
2448 AllowOSSleep(); 2449 AllowOSSleep();
2449} 2450}
2450 2451
2451void GMainWindow::OnStopGame() { 2452void GMainWindow::OnStopGame() {
2452 auto& system{Core::System::GetInstance()}; 2453 if (system->GetExitLock() && !ConfirmForceLockedExit()) {
2453 if (system.GetExitLock() && !ConfirmForceLockedExit()) {
2454 return; 2454 return;
2455 } 2455 }
2456 2456
2457 ShutdownGame(); 2457 ShutdownGame();
2458 2458
2459 Settings::RestoreGlobalState(system.IsPoweredOn()); 2459 Settings::RestoreGlobalState(system->IsPoweredOn());
2460 UpdateStatusButtons(); 2460 UpdateStatusButtons();
2461} 2461}
2462 2462
@@ -2469,9 +2469,13 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) {
2469 BootGame(last_filename_booted, 0, program_index); 2469 BootGame(last_filename_booted, 0, program_index);
2470} 2470}
2471 2471
2472void GMainWindow::OnExit() {
2473 OnStopGame();
2474}
2475
2472void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { 2476void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
2473 OverlayDialog dialog(render_window, Core::System::GetInstance(), error_code, error_text, 2477 OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"),
2474 QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); 2478 Qt::AlignLeft | Qt::AlignVCenter);
2475 dialog.exec(); 2479 dialog.exec();
2476 2480
2477 emit ErrorDisplayFinished(); 2481 emit ErrorDisplayFinished();
@@ -2480,7 +2484,7 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
2480void GMainWindow::OnMenuReportCompatibility() { 2484void GMainWindow::OnMenuReportCompatibility() {
2481 if (!Settings::values.yuzu_token.GetValue().empty() && 2485 if (!Settings::values.yuzu_token.GetValue().empty() &&
2482 !Settings::values.yuzu_username.GetValue().empty()) { 2486 !Settings::values.yuzu_username.GetValue().empty()) {
2483 CompatDB compatdb{this}; 2487 CompatDB compatdb{system->TelemetrySession(), this};
2484 compatdb.exec(); 2488 compatdb.exec();
2485 } else { 2489 } else {
2486 QMessageBox::critical( 2490 QMessageBox::critical(
@@ -2516,7 +2520,7 @@ void GMainWindow::ToggleFullscreen() {
2516 if (!emulation_running) { 2520 if (!emulation_running) {
2517 return; 2521 return;
2518 } 2522 }
2519 if (ui.action_Fullscreen->isChecked()) { 2523 if (ui->action_Fullscreen->isChecked()) {
2520 ShowFullscreen(); 2524 ShowFullscreen();
2521 } else { 2525 } else {
2522 HideFullscreen(); 2526 HideFullscreen();
@@ -2524,10 +2528,10 @@ void GMainWindow::ToggleFullscreen() {
2524} 2528}
2525 2529
2526void GMainWindow::ShowFullscreen() { 2530void GMainWindow::ShowFullscreen() {
2527 if (ui.action_Single_Window_Mode->isChecked()) { 2531 if (ui->action_Single_Window_Mode->isChecked()) {
2528 UISettings::values.geometry = saveGeometry(); 2532 UISettings::values.geometry = saveGeometry();
2529 2533
2530 ui.menubar->hide(); 2534 ui->menubar->hide();
2531 statusBar()->hide(); 2535 statusBar()->hide();
2532 2536
2533 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { 2537 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
@@ -2561,7 +2565,7 @@ void GMainWindow::ShowFullscreen() {
2561} 2565}
2562 2566
2563void GMainWindow::HideFullscreen() { 2567void GMainWindow::HideFullscreen() {
2564 if (ui.action_Single_Window_Mode->isChecked()) { 2568 if (ui->action_Single_Window_Mode->isChecked()) {
2565 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { 2569 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
2566 showNormal(); 2570 showNormal();
2567 restoreGeometry(UISettings::values.geometry); 2571 restoreGeometry(UISettings::values.geometry);
@@ -2573,8 +2577,8 @@ void GMainWindow::HideFullscreen() {
2573 show(); 2577 show();
2574 } 2578 }
2575 2579
2576 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); 2580 statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
2577 ui.menubar->show(); 2581 ui->menubar->show();
2578 } else { 2582 } else {
2579 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { 2583 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
2580 render_window->showNormal(); 2584 render_window->showNormal();
@@ -2590,10 +2594,10 @@ void GMainWindow::HideFullscreen() {
2590} 2594}
2591 2595
2592void GMainWindow::ToggleWindowMode() { 2596void GMainWindow::ToggleWindowMode() {
2593 if (ui.action_Single_Window_Mode->isChecked()) { 2597 if (ui->action_Single_Window_Mode->isChecked()) {
2594 // Render in the main window... 2598 // Render in the main window...
2595 render_window->BackupGeometry(); 2599 render_window->BackupGeometry();
2596 ui.horizontalLayout->addWidget(render_window); 2600 ui->horizontalLayout->addWidget(render_window);
2597 render_window->setFocusPolicy(Qt::StrongFocus); 2601 render_window->setFocusPolicy(Qt::StrongFocus);
2598 if (emulation_running) { 2602 if (emulation_running) {
2599 render_window->setVisible(true); 2603 render_window->setVisible(true);
@@ -2603,7 +2607,7 @@ void GMainWindow::ToggleWindowMode() {
2603 2607
2604 } else { 2608 } else {
2605 // Render in a separate window... 2609 // Render in a separate window...
2606 ui.horizontalLayout->removeWidget(render_window); 2610 ui->horizontalLayout->removeWidget(render_window);
2607 render_window->setParent(nullptr); 2611 render_window->setParent(nullptr);
2608 render_window->setFocusPolicy(Qt::NoFocus); 2612 render_window->setFocusPolicy(Qt::NoFocus);
2609 if (emulation_running) { 2613 if (emulation_running) {
@@ -2614,39 +2618,37 @@ void GMainWindow::ToggleWindowMode() {
2614 } 2618 }
2615} 2619}
2616 2620
2617void GMainWindow::ResetWindowSize720() { 2621void GMainWindow::ResetWindowSize(u32 width, u32 height) {
2618 const auto aspect_ratio = Layout::EmulationAspectRatio( 2622 const auto aspect_ratio = Layout::EmulationAspectRatio(
2619 static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()), 2623 static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()),
2620 static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width); 2624 static_cast<float>(height) / width);
2621 if (!ui.action_Single_Window_Mode->isChecked()) { 2625 if (!ui->action_Single_Window_Mode->isChecked()) {
2622 render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio, 2626 render_window->resize(height / aspect_ratio, height);
2623 Layout::ScreenUndocked::Height);
2624 } else { 2627 } else {
2625 resize(Layout::ScreenUndocked::Height / aspect_ratio, 2628 const bool show_status_bar = ui->action_Show_Status_Bar->isChecked();
2626 Layout::ScreenUndocked::Height + menuBar()->height() + 2629 const auto status_bar_height = show_status_bar ? statusBar()->height() : 0;
2627 (ui.action_Show_Status_Bar->isChecked() ? statusBar()->height() : 0)); 2630 resize(height / aspect_ratio, height + menuBar()->height() + status_bar_height);
2628 } 2631 }
2629} 2632}
2630 2633
2634void GMainWindow::ResetWindowSize720() {
2635 ResetWindowSize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height);
2636}
2637
2638void GMainWindow::ResetWindowSize900() {
2639 ResetWindowSize(1600U, 900U);
2640}
2641
2631void GMainWindow::ResetWindowSize1080() { 2642void GMainWindow::ResetWindowSize1080() {
2632 const auto aspect_ratio = Layout::EmulationAspectRatio( 2643 ResetWindowSize(Layout::ScreenDocked::Width, Layout::ScreenDocked::Height);
2633 static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()),
2634 static_cast<float>(Layout::ScreenDocked::Height) / Layout::ScreenDocked::Width);
2635 if (!ui.action_Single_Window_Mode->isChecked()) {
2636 render_window->resize(Layout::ScreenDocked::Height / aspect_ratio,
2637 Layout::ScreenDocked::Height);
2638 } else {
2639 resize(Layout::ScreenDocked::Height / aspect_ratio,
2640 Layout::ScreenDocked::Height + menuBar()->height() +
2641 (ui.action_Show_Status_Bar->isChecked() ? statusBar()->height() : 0));
2642 }
2643} 2644}
2644 2645
2645void GMainWindow::OnConfigure() { 2646void GMainWindow::OnConfigure() {
2646 const auto old_theme = UISettings::values.theme; 2647 const auto old_theme = UISettings::values.theme;
2647 const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue(); 2648 const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
2648 2649
2649 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get()); 2650 Settings::SetConfiguringGlobal(true);
2651 ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system);
2650 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, 2652 connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
2651 &GMainWindow::OnLanguageChanged); 2653 &GMainWindow::OnLanguageChanged);
2652 2654
@@ -2682,7 +2684,7 @@ void GMainWindow::OnConfigure() {
2682 2684
2683 Settings::values.disabled_addons.clear(); 2685 Settings::values.disabled_addons.clear();
2684 2686
2685 config = std::make_unique<Config>(); 2687 config = std::make_unique<Config>(*system);
2686 UISettings::values.reset_to_defaults = false; 2688 UISettings::values.reset_to_defaults = false;
2687 2689
2688 UISettings::values.game_dirs = std::move(old_game_dirs); 2690 UISettings::values.game_dirs = std::move(old_game_dirs);
@@ -2731,12 +2733,11 @@ void GMainWindow::OnConfigure() {
2731} 2733}
2732 2734
2733void GMainWindow::OnConfigureTas() { 2735void GMainWindow::OnConfigureTas() {
2734 const auto& system = Core::System::GetInstance();
2735 ConfigureTasDialog dialog(this); 2736 ConfigureTasDialog dialog(this);
2736 const auto result = dialog.exec(); 2737 const auto result = dialog.exec();
2737 2738
2738 if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { 2739 if (result != QDialog::Accepted && !UISettings::values.configuration_applied) {
2739 Settings::RestoreGlobalState(system.IsPoweredOn()); 2740 Settings::RestoreGlobalState(system->IsPoweredOn());
2740 return; 2741 return;
2741 } else if (result == QDialog::Accepted) { 2742 } else if (result == QDialog::Accepted) {
2742 dialog.ApplyConfiguration(); 2743 dialog.ApplyConfiguration();
@@ -2744,20 +2745,20 @@ void GMainWindow::OnConfigureTas() {
2744} 2745}
2745 2746
2746void GMainWindow::OnConfigurePerGame() { 2747void GMainWindow::OnConfigurePerGame() {
2747 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 2748 const u64 title_id = system->CurrentProcess()->GetTitleID();
2748 OpenPerGameConfiguration(title_id, game_path.toStdString()); 2749 OpenPerGameConfiguration(title_id, game_path.toStdString());
2749} 2750}
2750 2751
2751void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) { 2752void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) {
2752 const auto v_file = Core::GetGameFileFromPath(vfs, file_name); 2753 const auto v_file = Core::GetGameFileFromPath(vfs, file_name);
2753 const auto& system = Core::System::GetInstance();
2754 2754
2755 ConfigurePerGame dialog(this, title_id, file_name); 2755 Settings::SetConfiguringGlobal(false);
2756 ConfigurePerGame dialog(this, title_id, file_name, *system);
2756 dialog.LoadFromFile(v_file); 2757 dialog.LoadFromFile(v_file);
2757 const auto result = dialog.exec(); 2758 const auto result = dialog.exec();
2758 2759
2759 if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { 2760 if (result != QDialog::Accepted && !UISettings::values.configuration_applied) {
2760 Settings::RestoreGlobalState(system.IsPoweredOn()); 2761 Settings::RestoreGlobalState(system->IsPoweredOn());
2761 return; 2762 return;
2762 } else if (result == QDialog::Accepted) { 2763 } else if (result == QDialog::Accepted) {
2763 dialog.ApplyConfiguration(); 2764 dialog.ApplyConfiguration();
@@ -2769,7 +2770,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
2769 } 2770 }
2770 2771
2771 // Do not cause the global config to write local settings into the config file 2772 // Do not cause the global config to write local settings into the config file
2772 const bool is_powered_on = system.IsPoweredOn(); 2773 const bool is_powered_on = system->IsPoweredOn();
2773 Settings::RestoreGlobalState(is_powered_on); 2774 Settings::RestoreGlobalState(is_powered_on);
2774 2775
2775 UISettings::values.configuration_applied = false; 2776 UISettings::values.configuration_applied = false;
@@ -2792,8 +2793,7 @@ void GMainWindow::OnLoadAmiibo() {
2792} 2793}
2793 2794
2794void GMainWindow::LoadAmiibo(const QString& filename) { 2795void GMainWindow::LoadAmiibo(const QString& filename) {
2795 Core::System& system{Core::System::GetInstance()}; 2796 Service::SM::ServiceManager& sm = system->ServiceManager();
2796 Service::SM::ServiceManager& sm = system.ServiceManager();
2797 auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user"); 2797 auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user");
2798 if (nfc == nullptr) { 2798 if (nfc == nullptr) {
2799 return; 2799 return;
@@ -2835,8 +2835,8 @@ void GMainWindow::OnAbout() {
2835} 2835}
2836 2836
2837void GMainWindow::OnToggleFilterBar() { 2837void GMainWindow::OnToggleFilterBar() {
2838 game_list->SetFilterVisible(ui.action_Show_Filter_Bar->isChecked()); 2838 game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked());
2839 if (ui.action_Show_Filter_Bar->isChecked()) { 2839 if (ui->action_Show_Filter_Bar->isChecked()) {
2840 game_list->SetFilterFocus(); 2840 game_list->SetFilterFocus();
2841 } else { 2841 } else {
2842 game_list->ClearFilter(); 2842 game_list->ClearFilter();
@@ -2844,7 +2844,7 @@ void GMainWindow::OnToggleFilterBar() {
2844} 2844}
2845 2845
2846void GMainWindow::OnCaptureScreenshot() { 2846void GMainWindow::OnCaptureScreenshot() {
2847 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 2847 const u64 title_id = system->CurrentProcess()->GetTitleID();
2848 const auto screenshot_path = 2848 const auto screenshot_path =
2849 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)); 2849 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir));
2850 const auto date = 2850 const auto date =
@@ -2913,8 +2913,13 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie
2913 if (title_name.empty()) { 2913 if (title_name.empty()) {
2914 setWindowTitle(QString::fromStdString(window_title)); 2914 setWindowTitle(QString::fromStdString(window_title));
2915 } else { 2915 } else {
2916 const auto run_title = 2916 const auto run_title = [window_title, title_name, title_version, gpu_vendor]() {
2917 fmt::format("{} | {} | {} | {}", window_title, title_name, title_version, gpu_vendor); 2917 if (title_version.empty()) {
2918 return fmt::format("{} | {} | {}", window_title, title_name, gpu_vendor);
2919 }
2920 return fmt::format("{} | {} | {} | {}", window_title, title_name, title_version,
2921 gpu_vendor);
2922 }();
2918 setWindowTitle(QString::fromStdString(run_title)); 2923 setWindowTitle(QString::fromStdString(run_title));
2919 } 2924 }
2920} 2925}
@@ -2945,9 +2950,8 @@ void GMainWindow::UpdateStatusBar() {
2945 tas_label->clear(); 2950 tas_label->clear();
2946 } 2951 }
2947 2952
2948 auto& system = Core::System::GetInstance(); 2953 auto results = system->GetAndResetPerfStats();
2949 auto results = system.GetAndResetPerfStats(); 2954 auto& shader_notify = system->GPU().ShaderNotify();
2950 auto& shader_notify = system.GPU().ShaderNotify();
2951 const int shaders_building = shader_notify.ShadersBuilding(); 2955 const int shaders_building = shader_notify.ShadersBuilding();
2952 2956
2953 if (shaders_building > 0) { 2957 if (shaders_building > 0) {
@@ -3009,7 +3013,7 @@ void GMainWindow::UpdateStatusButtons() {
3009} 3013}
3010 3014
3011void GMainWindow::UpdateUISettings() { 3015void GMainWindow::UpdateUISettings() {
3012 if (!ui.action_Fullscreen->isChecked()) { 3016 if (!ui->action_Fullscreen->isChecked()) {
3013 UISettings::values.geometry = saveGeometry(); 3017 UISettings::values.geometry = saveGeometry();
3014 UISettings::values.renderwindow_geometry = render_window->saveGeometry(); 3018 UISettings::values.renderwindow_geometry = render_window->saveGeometry();
3015 } 3019 }
@@ -3018,11 +3022,11 @@ void GMainWindow::UpdateUISettings() {
3018 UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry(); 3022 UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry();
3019 UISettings::values.microprofile_visible = microProfileDialog->isVisible(); 3023 UISettings::values.microprofile_visible = microProfileDialog->isVisible();
3020#endif 3024#endif
3021 UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked(); 3025 UISettings::values.single_window_mode = ui->action_Single_Window_Mode->isChecked();
3022 UISettings::values.fullscreen = ui.action_Fullscreen->isChecked(); 3026 UISettings::values.fullscreen = ui->action_Fullscreen->isChecked();
3023 UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked(); 3027 UISettings::values.display_titlebar = ui->action_Display_Dock_Widget_Headers->isChecked();
3024 UISettings::values.show_filter_bar = ui.action_Show_Filter_Bar->isChecked(); 3028 UISettings::values.show_filter_bar = ui->action_Show_Filter_Bar->isChecked();
3025 UISettings::values.show_status_bar = ui.action_Show_Status_Bar->isChecked(); 3029 UISettings::values.show_status_bar = ui->action_Show_Status_Bar->isChecked();
3026 UISettings::values.first_start = false; 3030 UISettings::values.first_start = false;
3027} 3031}
3028 3032
@@ -3048,7 +3052,7 @@ void GMainWindow::OnMouseActivity() {
3048 } 3052 }
3049} 3053}
3050 3054
3051void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) { 3055void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) {
3052 QMessageBox::StandardButton answer; 3056 QMessageBox::StandardButton answer;
3053 QString status_message; 3057 QString status_message;
3054 const QString common_message = 3058 const QString common_message =
@@ -3063,7 +3067,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
3063 "back to the game list? Continuing emulation may result in crashes, corrupted save " 3067 "back to the game list? Continuing emulation may result in crashes, corrupted save "
3064 "data, or other bugs."); 3068 "data, or other bugs.");
3065 switch (result) { 3069 switch (result) {
3066 case Core::System::ResultStatus::ErrorSystemFiles: { 3070 case Core::SystemResultStatus::ErrorSystemFiles: {
3067 QString message; 3071 QString message;
3068 if (details.empty()) { 3072 if (details.empty()) {
3069 message = 3073 message =
@@ -3079,7 +3083,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
3079 break; 3083 break;
3080 } 3084 }
3081 3085
3082 case Core::System::ResultStatus::ErrorSharedFont: { 3086 case Core::SystemResultStatus::ErrorSharedFont: {
3083 const QString message = 3087 const QString message =
3084 tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message); 3088 tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message);
3085 answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message, 3089 answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
@@ -3108,7 +3112,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
3108 if (emu_thread) { 3112 if (emu_thread) {
3109 ShutdownGame(); 3113 ShutdownGame();
3110 3114
3111 Settings::RestoreGlobalState(Core::System::GetInstance().IsPoweredOn()); 3115 Settings::RestoreGlobalState(system->IsPoweredOn());
3112 UpdateStatusButtons(); 3116 UpdateStatusButtons();
3113 } 3117 }
3114 } else { 3118 } else {
@@ -3150,9 +3154,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
3150 const auto function = [this, &keys, &pdm] { 3154 const auto function = [this, &keys, &pdm] {
3151 keys.PopulateFromPartitionData(pdm); 3155 keys.PopulateFromPartitionData(pdm);
3152 3156
3153 auto& system = Core::System::GetInstance(); 3157 system->GetFileSystemController().CreateFactories(*vfs);
3154 system.GetFileSystemController().CreateFactories(*vfs); 3158 keys.DeriveETicket(pdm, system->GetContentProvider());
3155 keys.DeriveETicket(pdm, system.GetContentProvider());
3156 }; 3159 };
3157 3160
3158 QString errors; 3161 QString errors;
@@ -3194,7 +3197,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
3194 prog.close(); 3197 prog.close();
3195 } 3198 }
3196 3199
3197 Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs); 3200 system->GetFileSystemController().CreateFactories(*vfs);
3198 3201
3199 if (behavior == ReinitializeKeyBehavior::Warning) { 3202 if (behavior == ReinitializeKeyBehavior::Warning) {
3200 game_list->PopulateAsync(UISettings::values.game_dirs); 3203 game_list->PopulateAsync(UISettings::values.game_dirs);
@@ -3262,7 +3265,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
3262 if (emu_thread != nullptr) { 3265 if (emu_thread != nullptr) {
3263 ShutdownGame(); 3266 ShutdownGame();
3264 3267
3265 Settings::RestoreGlobalState(Core::System::GetInstance().IsPoweredOn()); 3268 Settings::RestoreGlobalState(system->IsPoweredOn());
3266 UpdateStatusButtons(); 3269 UpdateStatusButtons();
3267 } 3270 }
3268 3271
@@ -3337,7 +3340,7 @@ bool GMainWindow::ConfirmForceLockedExit() {
3337} 3340}
3338 3341
3339void GMainWindow::RequestGameExit() { 3342void GMainWindow::RequestGameExit() {
3340 auto& sm{Core::System::GetInstance().ServiceManager()}; 3343 auto& sm{system->ServiceManager()};
3341 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE"); 3344 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
3342 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE"); 3345 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
3343 bool has_signalled = false; 3346 bool has_signalled = false;
@@ -3353,7 +3356,7 @@ void GMainWindow::RequestGameExit() {
3353} 3356}
3354 3357
3355void GMainWindow::filterBarSetChecked(bool state) { 3358void GMainWindow::filterBarSetChecked(bool state) {
3356 ui.action_Show_Filter_Bar->setChecked(state); 3359 ui->action_Show_Filter_Bar->setChecked(state);
3357 emit(OnToggleFilterBar()); 3360 emit(OnToggleFilterBar());
3358} 3361}
3359 3362
@@ -3421,17 +3424,17 @@ void GMainWindow::OnLanguageChanged(const QString& locale) {
3421 3424
3422 UISettings::values.language = locale; 3425 UISettings::values.language = locale;
3423 LoadTranslation(); 3426 LoadTranslation();
3424 ui.retranslateUi(this); 3427 ui->retranslateUi(this);
3425 UpdateWindowTitle(); 3428 UpdateWindowTitle();
3426 3429
3427 if (emulation_running) 3430 if (emulation_running)
3428 ui.action_Start->setText(tr("&Continue")); 3431 ui->action_Start->setText(tr("&Continue"));
3429} 3432}
3430 3433
3431void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { 3434void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
3432#ifdef USE_DISCORD_PRESENCE 3435#ifdef USE_DISCORD_PRESENCE
3433 if (state) { 3436 if (state) {
3434 discord_rpc = std::make_unique<DiscordRPC::DiscordImpl>(); 3437 discord_rpc = std::make_unique<DiscordRPC::DiscordImpl>(*system);
3435 } else { 3438 } else {
3436 discord_rpc = std::make_unique<DiscordRPC::NullImpl>(); 3439 discord_rpc = std::make_unique<DiscordRPC::NullImpl>();
3437 } 3440 }
@@ -3485,8 +3488,7 @@ int main(int argc, char* argv[]) {
3485 // generating shaders 3488 // generating shaders
3486 setlocale(LC_ALL, "C"); 3489 setlocale(LC_ALL, "C");
3487 3490
3488 Core::System::InitializeGlobalInstance(); 3491 GMainWindow main_window{};
3489 GMainWindow main_window;
3490 // After settings have been loaded by GMainWindow, apply the filter 3492 // After settings have been loaded by GMainWindow, apply the filter
3491 main_window.show(); 3493 main_window.show();
3492 3494
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 36eed6103..aed15a0a0 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -13,9 +13,7 @@
13#include <QTranslator> 13#include <QTranslator>
14 14
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/core.h"
17#include "core/hle/service/acc/profile_manager.h" 16#include "core/hle/service/acc/profile_manager.h"
18#include "ui_main.h"
19#include "yuzu/compatibility_list.h" 17#include "yuzu/compatibility_list.h"
20#include "yuzu/hotkeys.h" 18#include "yuzu/hotkeys.h"
21 19
@@ -45,6 +43,11 @@ enum class StartGameType {
45 Global, // Only uses global configuration 43 Global, // Only uses global configuration
46}; 44};
47 45
46namespace Core {
47enum class SystemResultStatus : u32;
48class System;
49} // namespace Core
50
48namespace Core::Frontend { 51namespace Core::Frontend {
49struct ControllerParameters; 52struct ControllerParameters;
50struct InlineAppearParameters; 53struct InlineAppearParameters;
@@ -73,6 +76,10 @@ enum class SwkbdReplyType : u32;
73enum class WebExitReason : u32; 76enum class WebExitReason : u32;
74} // namespace Service::AM::Applets 77} // namespace Service::AM::Applets
75 78
79namespace Ui {
80class MainWindow;
81}
82
76enum class EmulatedDirectoryTarget { 83enum class EmulatedDirectoryTarget {
77 NAND, 84 NAND,
78 SDMC, 85 SDMC,
@@ -107,7 +114,7 @@ class GMainWindow : public QMainWindow {
107public: 114public:
108 void filterBarSetChecked(bool state); 115 void filterBarSetChecked(bool state);
109 void UpdateUITheme(); 116 void UpdateUITheme();
110 GMainWindow(); 117 explicit GMainWindow();
111 ~GMainWindow() override; 118 ~GMainWindow() override;
112 119
113 bool DropAction(QDropEvent* event); 120 bool DropAction(QDropEvent* event);
@@ -153,6 +160,7 @@ signals:
153public slots: 160public slots:
154 void OnLoadComplete(); 161 void OnLoadComplete();
155 void OnExecuteProgram(std::size_t program_index); 162 void OnExecuteProgram(std::size_t program_index);
163 void OnExit();
156 void ControllerSelectorReconfigureControllers( 164 void ControllerSelectorReconfigureControllers(
157 const Core::Frontend::ControllerParameters& parameters); 165 const Core::Frontend::ControllerParameters& parameters);
158 void SoftwareKeyboardInitialize( 166 void SoftwareKeyboardInitialize(
@@ -271,10 +279,12 @@ private slots:
271 void ShowFullscreen(); 279 void ShowFullscreen();
272 void HideFullscreen(); 280 void HideFullscreen();
273 void ToggleWindowMode(); 281 void ToggleWindowMode();
282 void ResetWindowSize(u32 width, u32 height);
274 void ResetWindowSize720(); 283 void ResetWindowSize720();
284 void ResetWindowSize900();
275 void ResetWindowSize1080(); 285 void ResetWindowSize1080();
276 void OnCaptureScreenshot(); 286 void OnCaptureScreenshot();
277 void OnCoreError(Core::System::ResultStatus, std::string); 287 void OnCoreError(Core::SystemResultStatus, std::string);
278 void OnReinitializeKeys(ReinitializeKeyBehavior behavior); 288 void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
279 void OnLanguageChanged(const QString& locale); 289 void OnLanguageChanged(const QString& locale);
280 void OnMouseActivity(); 290 void OnMouseActivity();
@@ -303,8 +313,9 @@ private:
303 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); 313 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
304 QString GetTasStateDescription() const; 314 QString GetTasStateDescription() const;
305 315
306 Ui::MainWindow ui; 316 std::unique_ptr<Ui::MainWindow> ui;
307 317
318 std::unique_ptr<Core::System> system;
308 std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc; 319 std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
309 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem; 320 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
310 321
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 653c010d8..a62e39a06 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -78,6 +78,35 @@
78 <property name="title"> 78 <property name="title">
79 <string>&amp;View</string> 79 <string>&amp;View</string>
80 </property> 80 </property>
81 <widget class="QMenu" name="menu_Reset_Window_Size">
82 <property name="title">
83 <string>&amp;Reset Window Size</string>
84 </property>
85 </widget>
86 <action name="action_Reset_Window_Size_720">
87 <property name="text">
88 <string>Reset Window Size to &amp;720p</string>
89 </property>
90 <property name="iconText">
91 <string>Reset Window Size to 720p</string>
92 </property>
93 </action>
94 <action name="action_Reset_Window_Size_900">
95 <property name="text">
96 <string>Reset Window Size to &amp;900p</string>
97 </property>
98 <property name="iconText">
99 <string>Reset Window Size to 900p</string>
100 </property>
101 </action>
102 <action name="action_Reset_Window_Size_1080">
103 <property name="text">
104 <string>Reset Window Size to &amp;1080p</string>
105 </property>
106 <property name="iconText">
107 <string>Reset Window Size to 1080p</string>
108 </property>
109 </action>
81 <widget class="QMenu" name="menu_View_Debugging"> 110 <widget class="QMenu" name="menu_View_Debugging">
82 <property name="title"> 111 <property name="title">
83 <string>&amp;Debugging</string> 112 <string>&amp;Debugging</string>
@@ -88,9 +117,8 @@
88 <addaction name="action_Display_Dock_Widget_Headers"/> 117 <addaction name="action_Display_Dock_Widget_Headers"/>
89 <addaction name="action_Show_Filter_Bar"/> 118 <addaction name="action_Show_Filter_Bar"/>
90 <addaction name="action_Show_Status_Bar"/> 119 <addaction name="action_Show_Status_Bar"/>
91 <addaction name="action_Reset_Window_Size_720"/>
92 <addaction name="action_Reset_Window_Size_1080"/>
93 <addaction name="separator"/> 120 <addaction name="separator"/>
121 <addaction name="menu_Reset_Window_Size"/>
94 <addaction name="menu_View_Debugging"/> 122 <addaction name="menu_View_Debugging"/>
95 </widget> 123 </widget>
96 <widget class="QMenu" name="menu_Tools"> 124 <widget class="QMenu" name="menu_Tools">
@@ -216,22 +244,6 @@
216 <string>Show Status Bar</string> 244 <string>Show Status Bar</string>
217 </property> 245 </property>
218 </action> 246 </action>
219 <action name="action_Reset_Window_Size_720">
220 <property name="text">
221 <string>Reset Window Size to &amp;720p</string>
222 </property>
223 <property name="iconText">
224 <string>Reset Window Size to 720p</string>
225 </property>
226 </action>
227 <action name="action_Reset_Window_Size_1080">
228 <property name="text">
229 <string>Reset Window Size to &amp;1080p</string>
230 </property>
231 <property name="iconText">
232 <string>Reset Window Size to 1080p</string>
233 </property>
234 </action>
235 <action name="action_Fullscreen"> 247 <action name="action_Fullscreen">
236 <property name="checkable"> 248 <property name="checkable">
237 <bool>true</bool> 249 <bool>true</bool>
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 81f741f20..cac19452f 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -60,7 +60,7 @@ struct Values {
60 Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"}; 60 Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"};
61 Settings::BasicSetting<bool> first_start{true, "firstStart"}; 61 Settings::BasicSetting<bool> first_start{true, "firstStart"};
62 Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; 62 Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
63 Settings::BasicSetting<bool> hide_mouse{false, "hideInactiveMouse"}; 63 Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"};
64 64
65 Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; 65 Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"};
66 66
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index d74eb7e2b..0b8fde691 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -412,8 +412,7 @@ void Config::ReadValues() {
412 412
413 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); 413 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
414 if (custom_rtc_enabled) { 414 if (custom_rtc_enabled) {
415 Settings::values.custom_rtc = 415 Settings::values.custom_rtc = sdl2_config->GetInteger("System", "custom_rtc", 0);
416 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0));
417 } else { 416 } else {
418 Settings::values.custom_rtc = std::nullopt; 417 Settings::values.custom_rtc = std::nullopt;
419 } 418 }
@@ -519,9 +518,8 @@ void Config::ReadValues() {
519 ReadSetting("WebService", Settings::values.yuzu_username); 518 ReadSetting("WebService", Settings::values.yuzu_username);
520 ReadSetting("WebService", Settings::values.yuzu_token); 519 ReadSetting("WebService", Settings::values.yuzu_token);
521 520
522 // Services 521 // Network
523 ReadSetting("Services", Settings::values.bcat_backend); 522 ReadSetting("Network", Settings::values.network_interface);
524 ReadSetting("Services", Settings::values.bcat_boxcat_local);
525} 523}
526 524
527void Config::Reload() { 525void Config::Reload() {
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 72f3213fb..339dca766 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -428,10 +428,11 @@ web_api_url = https://api.yuzu-emu.org
428yuzu_username = 428yuzu_username =
429yuzu_token = 429yuzu_token =
430 430
431[Services] 431[Network]
432# The name of the backend to use for BCAT 432# Name of the network interface device to use with yuzu LAN play.
433# If this is set to 'boxcat' boxcat will be used, otherwise a null implementation will be used 433# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo'
434bcat_backend = 434# e.g. On Windows: 'Ethernet', 'Wi-Fi'
435network_interface =
435 436
436[AddOns] 437[AddOns]
437# Used to disable add-ons 438# Used to disable add-ons
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index ba2c993ba..67587cc54 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -146,9 +146,8 @@ int main(int argc, char** argv) {
146 return -1; 146 return -1;
147 } 147 }
148 148
149 Core::System::InitializeGlobalInstance(); 149 Core::System system{};
150 auto& system{Core::System::GetInstance()}; 150 InputCommon::InputSubsystem input_subsystem{};
151 InputCommon::InputSubsystem input_subsystem;
152 151
153 // Apply the command line arguments 152 // Apply the command line arguments
154 system.ApplySettings(); 153 system.ApplySettings();
@@ -167,27 +166,27 @@ int main(int argc, char** argv) {
167 system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); 166 system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
168 system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); 167 system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
169 168
170 const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)}; 169 const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath)};
171 170
172 switch (load_result) { 171 switch (load_result) {
173 case Core::System::ResultStatus::ErrorGetLoader: 172 case Core::SystemResultStatus::ErrorGetLoader:
174 LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath); 173 LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath);
175 return -1; 174 return -1;
176 case Core::System::ResultStatus::ErrorLoader: 175 case Core::SystemResultStatus::ErrorLoader:
177 LOG_CRITICAL(Frontend, "Failed to load ROM!"); 176 LOG_CRITICAL(Frontend, "Failed to load ROM!");
178 return -1; 177 return -1;
179 case Core::System::ResultStatus::ErrorNotInitialized: 178 case Core::SystemResultStatus::ErrorNotInitialized:
180 LOG_CRITICAL(Frontend, "CPUCore not initialized"); 179 LOG_CRITICAL(Frontend, "CPUCore not initialized");
181 return -1; 180 return -1;
182 case Core::System::ResultStatus::ErrorVideoCore: 181 case Core::SystemResultStatus::ErrorVideoCore:
183 LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!"); 182 LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!");
184 return -1; 183 return -1;
185 case Core::System::ResultStatus::Success: 184 case Core::SystemResultStatus::Success:
186 break; // Expected case 185 break; // Expected case
187 default: 186 default:
188 if (static_cast<u32>(load_result) > 187 if (static_cast<u32>(load_result) >
189 static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) { 188 static_cast<u32>(Core::SystemResultStatus::ErrorLoader)) {
190 const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader); 189 const u16 loader_id = static_cast<u16>(Core::SystemResultStatus::ErrorLoader);
191 const u16 error_id = static_cast<u16>(load_result) - loader_id; 190 const u16 error_id = static_cast<u16>(load_result) - loader_id;
192 LOG_CRITICAL(Frontend, 191 LOG_CRITICAL(Frontend,
193 "While attempting to load the ROM requested, an error occurred. Please " 192 "While attempting to load the ROM requested, an error occurred. Please "