summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules6
-rw-r--r--.lgtm.yml13
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss5
m---------externals/libusb0
-rw-r--r--externals/libusb/CMakeLists.txt150
-rw-r--r--externals/libusb/config.h.in90
m---------externals/libusb/libusb0
-rw-r--r--externals/microprofile/microprofile.h2
m---------externals/xbyak0
-rw-r--r--src/common/common_funcs.h14
-rw-r--r--src/common/math_util.h2
-rw-r--r--src/common/quaternion.h30
-rw-r--r--src/common/thread.cpp12
-rw-r--r--src/common/thread.h9
-rw-r--r--src/common/x64/xbyak_abi.h32
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/core.cpp1
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/crypto/partition_data_manager.cpp1
-rw-r--r--src/core/file_sys/bis_factory.cpp1
-rw-r--r--src/core/file_sys/bis_factory.h3
-rw-r--r--src/core/file_sys/card_image.cpp5
-rw-r--r--src/core/file_sys/card_image.h7
-rw-r--r--src/core/file_sys/content_archive.cpp5
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp1
-rw-r--r--src/core/file_sys/control_metadata.h2
-rw-r--r--src/core/file_sys/kernel_executable.cpp3
-rw-r--r--src/core/file_sys/kernel_executable.h9
-rw-r--r--src/core/file_sys/nca_metadata.cpp1
-rw-r--r--src/core/file_sys/nca_metadata.h2
-rw-r--r--src/core/file_sys/partition_filesystem.cpp8
-rw-r--r--src/core/file_sys/partition_filesystem.h8
-rw-r--r--src/core/file_sys/patch_manager.cpp3
-rw-r--r--src/core/file_sys/patch_manager.h6
-rw-r--r--src/core/file_sys/program_metadata.cpp1
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/romfs.h1
-rw-r--r--src/core/file_sys/sdmc_factory.cpp2
-rw-r--r--src/core/file_sys/sdmc_factory.h2
-rw-r--r--src/core/file_sys/submission_package.cpp2
-rw-r--r--src/core/file_sys/submission_package.h6
-rw-r--r--src/core/file_sys/xts_archive.cpp10
-rw-r--r--src/core/file_sys/xts_archive.h10
-rw-r--r--src/core/frontend/framebuffer_layout.h1
-rw-r--r--src/core/hle/kernel/kernel.cpp3
-rw-r--r--src/core/hle/kernel/scheduler.cpp8
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/npad.h1
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp12
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp12
-rw-r--r--src/core/hle/service/nifm/nifm.cpp13
-rw-r--r--src/core/hle/service/ns/ns.cpp1
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sockets/blocking_worker.h162
-rw-r--r--src/core/hle/service/sockets/bsd.cpp809
-rw-r--r--src/core/hle/service/sockets/bsd.h150
-rw-r--r--src/core/hle/service/sockets/sockets.cpp6
-rw-r--r--src/core/hle/service/sockets/sockets.h85
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp165
-rw-r--r--src/core/hle/service/sockets/sockets_translate.h48
-rw-r--r--src/core/settings.h12
-rw-r--r--src/input_common/CMakeLists.txt4
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp2
-rw-r--r--src/input_common/gcadapter/gc_adapter.h2
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp22
-rw-r--r--src/input_common/main.cpp11
-rw-r--r--src/input_common/main.h3
-rw-r--r--src/input_common/motion_input.cpp181
-rw-r--r--src/input_common/motion_input.h68
-rw-r--r--src/input_common/sdl/sdl_impl.cpp114
-rw-r--r--src/input_common/touch_from_button.cpp50
-rw-r--r--src/input_common/touch_from_button.h23
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h51
-rw-r--r--src/video_core/fence_manager.h27
-rw-r--r--src/video_core/gpu.cpp4
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/macro/macro_jit_x64.cpp10
-rw-r--r--src/video_core/query_cache.h31
-rw-r--r--src/video_core/rasterizer_interface.h7
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_fence_manager.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_fence_manager.h6
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp261
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h26
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp63
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h23
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h16
-rw-r--r--src/video_core/renderer_opengl/gl_state_tracker.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_state_tracker.h28
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h6
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp19
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h21
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp23
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h16
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h9
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp17
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h8
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp92
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h28
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h3
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp128
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h13
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_state_tracker.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp34
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h16
-rw-r--r--src/video_core/shader/async_shaders.cpp6
-rw-r--r--src/video_core/shader/async_shaders.h26
-rw-r--r--src/video_core/shader/memory_util.cpp7
-rw-r--r--src/video_core/shader/memory_util.h6
-rw-r--r--src/video_core/texture_cache/surface_params.cpp11
-rw-r--r--src/video_core/texture_cache/surface_params.h5
-rw-r--r--src/video_core/texture_cache/texture_cache.h51
-rw-r--r--src/video_core/video_core.cpp11
-rw-r--r--src/yuzu/CMakeLists.txt7
-rw-r--r--src/yuzu/bootmanager.cpp10
-rw-r--r--src/yuzu/bootmanager.h5
-rw-r--r--src/yuzu/configuration/config.cpp115
-rw-r--r--src/yuzu/configuration/config.h5
-rw-r--r--src/yuzu/configuration/configure_input.cpp5
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.h1
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp8
-rw-r--r--src/yuzu/configuration/configure_motion_touch.cpp314
-rw-r--r--src/yuzu/configuration/configure_motion_touch.h90
-rw-r--r--src/yuzu/configuration/configure_motion_touch.ui327
-rw-r--r--src/yuzu/configuration/configure_touch_from_button.cpp623
-rw-r--r--src/yuzu/configuration/configure_touch_from_button.h92
-rw-r--r--src/yuzu/configuration/configure_touch_from_button.ui231
-rw-r--r--src/yuzu/configuration/configure_touch_widget.h62
-rw-r--r--src/yuzu/game_list_p.h32
-rw-r--r--src/yuzu/main.cpp4
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu/main.ui2
-rw-r--r--src/yuzu_cmd/yuzu.cpp5
-rw-r--r--src/yuzu_tester/yuzu.cpp1
150 files changed, 4765 insertions, 907 deletions
diff --git a/.gitmodules b/.gitmodules
index 79028bbb5..9d9356151 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -16,6 +16,9 @@
16[submodule "libressl"] 16[submodule "libressl"]
17 path = externals/libressl 17 path = externals/libressl
18 url = https://github.com/citra-emu/ext-libressl-portable.git 18 url = https://github.com/citra-emu/ext-libressl-portable.git
19[submodule "libusb"]
20 path = externals/libusb/libusb
21 url = https://github.com/libusb/libusb.git
19[submodule "discord-rpc"] 22[submodule "discord-rpc"]
20 path = externals/discord-rpc 23 path = externals/discord-rpc
21 url = https://github.com/discordapp/discord-rpc.git 24 url = https://github.com/discordapp/discord-rpc.git
@@ -34,9 +37,6 @@
34[submodule "xbyak"] 37[submodule "xbyak"]
35 path = externals/xbyak 38 path = externals/xbyak
36 url = https://github.com/herumi/xbyak.git 39 url = https://github.com/herumi/xbyak.git
37[submodule "externals/libusb"]
38 path = externals/libusb
39 url = https://github.com/ameerj/libusb
40[submodule "opus"] 40[submodule "opus"]
41 path = externals/opus/opus 41 path = externals/opus/opus
42 url = https://github.com/xiph/opus.git 42 url = https://github.com/xiph/opus.git
diff --git a/.lgtm.yml b/.lgtm.yml
new file mode 100644
index 000000000..932568593
--- /dev/null
+++ b/.lgtm.yml
@@ -0,0 +1,13 @@
1path_classifiers:
2 library: "externals"
3extraction:
4 cpp:
5 prepare:
6 packages:
7 - "libsdl2-dev"
8 - "qtmultimedia5-dev"
9 - "clang-format-10"
10 - "libtbb-dev"
11 - "libjack-jackd2-dev"
12 - "doxygen"
13 - "graphviz"
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 7755426f8..16218f0c2 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1371,3 +1371,8 @@ QGroupBox#vibrationGroup::title {
1371 padding-left: 1px; 1371 padding-left: 1px;
1372 padding-right: 1px; 1372 padding-right: 1px;
1373} 1373}
1374
1375/* touchscreen mapping widget */
1376TouchScreenPreview {
1377 qproperty-dotHighlightColor: #3daee9;
1378}
diff --git a/externals/libusb b/externals/libusb
deleted file mode 160000
Subproject 3406d72cda879f8792a88bf5f6bd0b7a65636f7
diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt
new file mode 100644
index 000000000..c0d24b126
--- /dev/null
+++ b/externals/libusb/CMakeLists.txt
@@ -0,0 +1,150 @@
1add_library(usb STATIC EXCLUDE_FROM_ALL
2 libusb/libusb/core.c
3 libusb/libusb/core.c
4 libusb/libusb/descriptor.c
5 libusb/libusb/hotplug.c
6 libusb/libusb/io.c
7 libusb/libusb/strerror.c
8 libusb/libusb/sync.c
9)
10set_target_properties(usb PROPERTIES VERSION 1.0.23)
11if(WIN32)
12 target_include_directories(usb
13 BEFORE
14 PUBLIC
15 libusb/libusb
16
17 PRIVATE
18 "${CMAKE_CURRENT_BINARY_DIR}"
19 )
20
21 if (NOT MINGW)
22 target_include_directories(usb BEFORE PRIVATE libusb/msvc)
23 endif()
24
25 # Works around other libraries providing their own definition of USB GUIDs (e.g. SDL2)
26 target_compile_definitions(usb PRIVATE "-DGUID_DEVINTERFACE_USB_DEVICE=(GUID){ 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}}")
27else()
28target_include_directories(usb
29 # turns out other projects also have "config.h", so make sure the
30 # LibUSB one comes first
31 BEFORE
32
33 PUBLIC
34 libusb/libusb
35
36 PRIVATE
37 "${CMAKE_CURRENT_BINARY_DIR}"
38)
39endif()
40
41if(WIN32 OR CYGWIN)
42 target_sources(usb PRIVATE
43 libusb/libusb/os/threads_windows.c
44 libusb/libusb/os/windows_winusb.c
45 libusb/libusb/os/windows_usbdk.c
46 libusb/libusb/os/windows_nt_common.c
47 )
48 set(OS_WINDOWS TRUE)
49elseif(APPLE)
50 target_sources(usb PRIVATE
51 libusb/libusb/os/darwin_usb.c
52 )
53 find_library(COREFOUNDATION_LIBRARY CoreFoundation)
54 find_library(IOKIT_LIBRARY IOKit)
55 find_library(OBJC_LIBRARY objc)
56 target_link_libraries(usb PRIVATE
57 ${COREFOUNDATION_LIBRARY}
58 ${IOKIT_LIBRARY}
59 ${OBJC_LIBRARY}
60 )
61 set(OS_DARWIN TRUE)
62elseif(ANDROID)
63 target_sources(usb PRIVATE
64 libusb/libusb/os/linux_usbfs.c
65 libusb/libusb/os/linux_netlink.c
66 )
67 find_library(LOG_LIBRARY log)
68 target_link_libraries(usb PRIVATE ${LOG_LIBRARY})
69 set(OS_LINUX TRUE)
70elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
71 target_sources(usb PRIVATE
72 libusb/libusb/os/linux_usbfs.c
73 )
74 find_package(Libudev)
75 if(LIBUDEV_FOUND)
76 target_sources(usb PRIVATE
77 libusb/libusb/os/linux_udev.c
78 )
79 target_link_libraries(usb PRIVATE "${LIBUDEV_LIBRARIES}")
80 target_include_directories(usb PRIVATE "${LIBUDEV_INCLUDE_DIR}")
81 set(HAVE_LIBUDEV TRUE)
82 set(USE_UDEV TRUE)
83 else()
84 target_sources(usb PRIVATE
85 libusb/libusb/os/linux_netlink.c
86 )
87 endif()
88 set(OS_LINUX TRUE)
89elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
90 target_sources(usb PRIVATE
91 libusb/libusb/os/netbsd_usb.c
92 )
93 set(OS_NETBSD TRUE)
94elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
95 target_sources(usb PRIVATE
96 libusb/libusb/os/openbsd_usb.c
97 )
98 set(OS_OPENBSD TRUE)
99endif()
100
101if(UNIX)
102 target_sources(usb PRIVATE
103 libusb/libusb/os/poll_posix.c
104 libusb/libusb/os/threads_posix.c
105 )
106 find_package(Threads REQUIRED)
107 if(THREADS_HAVE_PTHREAD_ARG)
108 target_compile_options(usb PUBLIC "-pthread")
109 endif()
110 if(CMAKE_THREAD_LIBS_INIT)
111 target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
112 endif()
113 set(THREADS_POSIX TRUE)
114elseif(WIN32)
115 target_sources(usb PRIVATE
116 libusb/libusb/os/poll_windows.c
117 libusb/libusb/os/threads_windows.c
118 )
119endif()
120
121include(CheckFunctionExists)
122include(CheckIncludeFiles)
123include(CheckTypeSize)
124check_include_files(asm/types.h HAVE_ASM_TYPES_H)
125check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
126check_include_files(linux/filter.h HAVE_LINUX_FILTER_H)
127check_include_files(linux/netlink.h HAVE_LINUX_NETLINK_H)
128check_include_files(poll.h HAVE_POLL_H)
129check_include_files(signal.h HAVE_SIGNAL_H)
130check_include_files(strings.h HAVE_STRINGS_H)
131check_type_size("struct timespec" STRUCT_TIMESPEC)
132check_function_exists(syslog HAVE_SYSLOG_FUNC)
133check_include_files(syslog.h HAVE_SYSLOG_H)
134check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
135check_include_files(sys/time.h HAVE_SYS_TIME_H)
136check_include_files(sys/types.h HAVE_SYS_TYPES_H)
137
138set(CMAKE_EXTRA_INCLUDE_FILES poll.h)
139check_type_size("nfds_t" nfds_t)
140unset(CMAKE_EXTRA_INCLUDE_FILES)
141if(HAVE_NFDS_T)
142 set(POLL_NFDS_TYPE "nfds_t")
143else()
144 set(POLL_NFDS_TYPE "unsigned int")
145endif()
146
147check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
148
149
150configure_file(config.h.in config.h)
diff --git a/externals/libusb/config.h.in b/externals/libusb/config.h.in
new file mode 100644
index 000000000..915b7390f
--- /dev/null
+++ b/externals/libusb/config.h.in
@@ -0,0 +1,90 @@
1/* Default visibility */
2#if defined(__GNUC__) || defined(__clang__)
3 #define DEFAULT_VISIBILITY __attribute__((visibility("default")))
4#elif defined(_MSC_VER)
5 #define DEFAULT_VISIBILITY __declspec(dllexport)
6#endif
7
8/* Start with debug message logging enabled */
9#undef ENABLE_DEBUG_LOGGING
10
11/* Message logging */
12#undef ENABLE_LOGGING
13
14/* Define to 1 if you have the <asm/types.h> header file. */
15#cmakedefine HAVE_ASM_TYPES_H 1
16
17/* Define to 1 if you have the `gettimeofday' function. */
18#cmakedefine HAVE_GETTIMEOFDAY 1
19
20/* Define to 1 if you have the `udev' library (-ludev). */
21#cmakedefine HAVE_LIBUDEV 1
22
23/* Define to 1 if you have the <linux/filter.h> header file. */
24#cmakedefine HAVE_LINUX_FILTER_H 1
25
26/* Define to 1 if you have the <linux/netlink.h> header file. */
27#cmakedefine HAVE_LINUX_NETLINK_H 1
28
29/* Define to 1 if you have the <poll.h> header file. */
30#cmakedefine HAVE_POLL_H 1
31
32/* Define to 1 if you have the <signal.h> header file. */
33#cmakedefine HAVE_SIGNAL_H 1
34
35/* Define to 1 if you have the <strings.h> header file. */
36#cmakedefine HAVE_STRINGS_H 1
37
38/* Define to 1 if the system has the type `struct timespec'. */
39#cmakedefine HAVE_STRUCT_TIMESPEC 1
40
41/* syslog() function available */
42#cmakedefine HAVE_SYSLOG_FUNC 1
43
44/* Define to 1 if you have the <syslog.h> header file. */
45#cmakedefine HAVE_SYSLOG_H 1
46
47/* Define to 1 if you have the <sys/socket.h> header file. */
48#cmakedefine HAVE_SYS_SOCKET_H 1
49
50/* Define to 1 if you have the <sys/time.h> header file. */
51#cmakedefine HAVE_SYS_TIME_H 1
52
53/* Define to 1 if you have the <sys/types.h> header file. */
54#cmakedefine HAVE_SYS_TYPES_H 1
55
56/* Darwin backend */
57#cmakedefine OS_DARWIN 1
58
59/* Linux backend */
60#cmakedefine OS_LINUX 1
61
62/* NetBSD backend */
63#cmakedefine OS_NETBSD 1
64
65/* OpenBSD backend */
66#cmakedefine OS_OPENBSD 1
67
68/* Windows backend */
69#cmakedefine OS_WINDOWS 1
70
71/* type of second poll() argument */
72#define POLL_NFDS_TYPE @POLL_NFDS_TYPE@
73
74/* Use POSIX Threads */
75#cmakedefine THREADS_POSIX
76
77/* timerfd headers available */
78#cmakedefine USBI_TIMERFD_AVAILABLE 1
79
80/* Enable output to system log */
81#define USE_SYSTEM_LOGGING_FACILITY 1
82
83/* Use udev for device enumeration/hotplug */
84#cmakedefine USE_UDEV 1
85
86/* Use GNU extensions */
87#define _GNU_SOURCE
88
89/* Oldest Windows version supported */
90#define WINVER 0x0501
diff --git a/externals/libusb/libusb b/externals/libusb/libusb
new file mode 160000
Subproject e782eeb2514266f6738e242cdcb18e3ae1ed06f
diff --git a/externals/microprofile/microprofile.h b/externals/microprofile/microprofile.h
index 6dae65a66..85d5bd5de 100644
--- a/externals/microprofile/microprofile.h
+++ b/externals/microprofile/microprofile.h
@@ -1037,7 +1037,7 @@ static void MicroProfileCreateThreadLogKey()
1037#else 1037#else
1038MP_THREAD_LOCAL MicroProfileThreadLog* g_MicroProfileThreadLog = 0; 1038MP_THREAD_LOCAL MicroProfileThreadLog* g_MicroProfileThreadLog = 0;
1039#endif 1039#endif
1040static bool g_bUseLock = false; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled) 1040static std::atomic<bool> g_bUseLock{false}; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled)
1041 1041
1042 1042
1043MICROPROFILE_DEFINE(g_MicroProfileFlip, "MicroProfile", "MicroProfileFlip", 0x3355ee); 1043MICROPROFILE_DEFINE(g_MicroProfileFlip, "MicroProfile", "MicroProfileFlip", 0x3355ee);
diff --git a/externals/xbyak b/externals/xbyak
Subproject 18c9caaa0a3ed5706c39f5aa86cce0db6e65b17 Subproject c306b8e5786eeeb87b8925a8af5c3bf057ff5a9
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 98421bced..367b6bf6e 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -64,14 +64,20 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
64 using T = std::underlying_type_t<type>; \ 64 using T = std::underlying_type_t<type>; \
65 return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \ 65 return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
66 } \ 66 } \
67 constexpr type& operator|=(type& a, type b) noexcept { \ 67 [[nodiscard]] constexpr type operator^(type a, type b) noexcept { \
68 using T = std::underlying_type_t<type>; \ 68 using T = std::underlying_type_t<type>; \
69 a = static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \ 69 return static_cast<type>(static_cast<T>(a) ^ static_cast<T>(b)); \
70 } \
71 constexpr type& operator|=(type& a, type b) noexcept { \
72 a = a | b; \
70 return a; \ 73 return a; \
71 } \ 74 } \
72 constexpr type& operator&=(type& a, type b) noexcept { \ 75 constexpr type& operator&=(type& a, type b) noexcept { \
73 using T = std::underlying_type_t<type>; \ 76 a = a & b; \
74 a = static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \ 77 return a; \
78 } \
79 constexpr type& operator^=(type& a, type b) noexcept { \
80 a = a ^ b; \
75 return a; \ 81 return a; \
76 } \ 82 } \
77 [[nodiscard]] constexpr type operator~(type key) noexcept { \ 83 [[nodiscard]] constexpr type operator~(type key) noexcept { \
diff --git a/src/common/math_util.h b/src/common/math_util.h
index cc35c90ee..b35ad8507 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -9,7 +9,7 @@
9 9
10namespace Common { 10namespace Common {
11 11
12constexpr float PI = 3.14159265f; 12constexpr float PI = 3.1415926535f;
13 13
14template <class T> 14template <class T>
15struct Rectangle { 15struct Rectangle {
diff --git a/src/common/quaternion.h b/src/common/quaternion.h
index da44f35cd..4d0871eb4 100644
--- a/src/common/quaternion.h
+++ b/src/common/quaternion.h
@@ -36,6 +36,36 @@ public:
36 T length = std::sqrt(xyz.Length2() + w * w); 36 T length = std::sqrt(xyz.Length2() + w * w);
37 return {xyz / length, w / length}; 37 return {xyz / length, w / length};
38 } 38 }
39
40 [[nodiscard]] std::array<decltype(-T{}), 16> ToMatrix() const {
41 const T x2 = xyz[0] * xyz[0];
42 const T y2 = xyz[1] * xyz[1];
43 const T z2 = xyz[2] * xyz[2];
44
45 const T xy = xyz[0] * xyz[1];
46 const T wz = w * xyz[2];
47 const T xz = xyz[0] * xyz[2];
48 const T wy = w * xyz[1];
49 const T yz = xyz[1] * xyz[2];
50 const T wx = w * xyz[0];
51
52 return {1.0f - 2.0f * (y2 + z2),
53 2.0f * (xy + wz),
54 2.0f * (xz - wy),
55 0.0f,
56 2.0f * (xy - wz),
57 1.0f - 2.0f * (x2 + z2),
58 2.0f * (yz + wx),
59 0.0f,
60 2.0f * (xz + wy),
61 2.0f * (yz - wx),
62 1.0f - 2.0f * (x2 + y2),
63 0.0f,
64 0.0f,
65 0.0f,
66 0.0f,
67 1.0f};
68 }
39}; 69};
40 70
41template <typename T> 71template <typename T>
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 8e5935e6a..d2c1ac60d 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.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 "common/common_funcs.h"
6#include "common/logging/log.h"
5#include "common/thread.h" 7#include "common/thread.h"
6#ifdef __APPLE__ 8#ifdef __APPLE__
7#include <mach/mach.h> 9#include <mach/mach.h>
@@ -19,6 +21,8 @@
19#include <unistd.h> 21#include <unistd.h>
20#endif 22#endif
21 23
24#include <string>
25
22#ifdef __FreeBSD__ 26#ifdef __FreeBSD__
23#define cpu_set_t cpuset_t 27#define cpu_set_t cpuset_t
24#endif 28#endif
@@ -110,6 +114,14 @@ void SetCurrentThreadName(const char* name) {
110 pthread_set_name_np(pthread_self(), name); 114 pthread_set_name_np(pthread_self(), name);
111#elif defined(__NetBSD__) 115#elif defined(__NetBSD__)
112 pthread_setname_np(pthread_self(), "%s", (void*)name); 116 pthread_setname_np(pthread_self(), "%s", (void*)name);
117#elif defined(__linux__)
118 // Linux limits thread names to 15 characters and will outright reject any
119 // attempt to set a longer name with ERANGE.
120 std::string truncated(name, std::min(strlen(name), static_cast<size_t>(15)));
121 if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) {
122 errno = e;
123 LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg());
124 }
113#else 125#else
114 pthread_setname_np(pthread_self(), name); 126 pthread_setname_np(pthread_self(), name);
115#endif 127#endif
diff --git a/src/common/thread.h b/src/common/thread.h
index 52b359413..a8c17c71a 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
7#include <chrono> 8#include <chrono>
8#include <condition_variable> 9#include <condition_variable>
9#include <cstddef> 10#include <cstddef>
@@ -25,13 +26,13 @@ public:
25 26
26 void Wait() { 27 void Wait() {
27 std::unique_lock lk{mutex}; 28 std::unique_lock lk{mutex};
28 condvar.wait(lk, [&] { return is_set; }); 29 condvar.wait(lk, [&] { return is_set.load(); });
29 is_set = false; 30 is_set = false;
30 } 31 }
31 32
32 bool WaitFor(const std::chrono::nanoseconds& time) { 33 bool WaitFor(const std::chrono::nanoseconds& time) {
33 std::unique_lock lk{mutex}; 34 std::unique_lock lk{mutex};
34 if (!condvar.wait_for(lk, time, [this] { return is_set; })) 35 if (!condvar.wait_for(lk, time, [this] { return is_set.load(); }))
35 return false; 36 return false;
36 is_set = false; 37 is_set = false;
37 return true; 38 return true;
@@ -40,7 +41,7 @@ public:
40 template <class Clock, class Duration> 41 template <class Clock, class Duration>
41 bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) { 42 bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
42 std::unique_lock lk{mutex}; 43 std::unique_lock lk{mutex};
43 if (!condvar.wait_until(lk, time, [this] { return is_set; })) 44 if (!condvar.wait_until(lk, time, [this] { return is_set.load(); }))
44 return false; 45 return false;
45 is_set = false; 46 is_set = false;
46 return true; 47 return true;
@@ -54,9 +55,9 @@ public:
54 } 55 }
55 56
56private: 57private:
57 bool is_set = false;
58 std::condition_variable condvar; 58 std::condition_variable condvar;
59 std::mutex mutex; 59 std::mutex mutex;
60 std::atomic_bool is_set{false};
60}; 61};
61 62
62class Barrier { 63class Barrier {
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
index a5f5d4fc1..26e4bfda5 100644
--- a/src/common/x64/xbyak_abi.h
+++ b/src/common/x64/xbyak_abi.h
@@ -11,7 +11,7 @@
11 11
12namespace Common::X64 { 12namespace Common::X64 {
13 13
14inline std::size_t RegToIndex(const Xbyak::Reg& reg) { 14constexpr std::size_t RegToIndex(const Xbyak::Reg& reg) {
15 using Kind = Xbyak::Reg::Kind; 15 using Kind = Xbyak::Reg::Kind;
16 ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0, 16 ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
17 "RegSet only support GPRs and XMM registers."); 17 "RegSet only support GPRs and XMM registers.");
@@ -19,17 +19,17 @@ inline std::size_t RegToIndex(const Xbyak::Reg& reg) {
19 return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16); 19 return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
20} 20}
21 21
22inline Xbyak::Reg64 IndexToReg64(std::size_t reg_index) { 22constexpr Xbyak::Reg64 IndexToReg64(std::size_t reg_index) {
23 ASSERT(reg_index < 16); 23 ASSERT(reg_index < 16);
24 return Xbyak::Reg64(static_cast<int>(reg_index)); 24 return Xbyak::Reg64(static_cast<int>(reg_index));
25} 25}
26 26
27inline Xbyak::Xmm IndexToXmm(std::size_t reg_index) { 27constexpr Xbyak::Xmm IndexToXmm(std::size_t reg_index) {
28 ASSERT(reg_index >= 16 && reg_index < 32); 28 ASSERT(reg_index >= 16 && reg_index < 32);
29 return Xbyak::Xmm(static_cast<int>(reg_index - 16)); 29 return Xbyak::Xmm(static_cast<int>(reg_index - 16));
30} 30}
31 31
32inline Xbyak::Reg IndexToReg(std::size_t reg_index) { 32constexpr Xbyak::Reg IndexToReg(std::size_t reg_index) {
33 if (reg_index < 16) { 33 if (reg_index < 16) {
34 return IndexToReg64(reg_index); 34 return IndexToReg64(reg_index);
35 } else { 35 } else {
@@ -45,17 +45,17 @@ inline std::bitset<32> BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
45 return bits; 45 return bits;
46} 46}
47 47
48const std::bitset<32> ABI_ALL_GPRS(0x0000FFFF); 48constexpr inline std::bitset<32> ABI_ALL_GPRS(0x0000FFFF);
49const std::bitset<32> ABI_ALL_XMMS(0xFFFF0000); 49constexpr inline std::bitset<32> ABI_ALL_XMMS(0xFFFF0000);
50 50
51#ifdef _WIN32 51#ifdef _WIN32
52 52
53// Microsoft x64 ABI 53// Microsoft x64 ABI
54const Xbyak::Reg ABI_RETURN = Xbyak::util::rax; 54constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
55const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx; 55constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
56const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx; 56constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
57const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8; 57constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
58const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9; 58constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
59 59
60const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({ 60const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
61 // GPRs 61 // GPRs
@@ -102,11 +102,11 @@ constexpr size_t ABI_SHADOW_SPACE = 0x20;
102#else 102#else
103 103
104// System V x86-64 ABI 104// System V x86-64 ABI
105const Xbyak::Reg ABI_RETURN = Xbyak::util::rax; 105constexpr inline Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
106const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi; 106constexpr inline Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
107const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi; 107constexpr inline Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
108const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx; 108constexpr inline Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
109const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx; 109constexpr inline Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
110 110
111const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({ 111const std::bitset<32> ABI_ALL_CALLER_SAVED = BuildRegSet({
112 // GPRs 112 // GPRs
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c85c9485f..b96ca9374 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -491,6 +491,7 @@ add_library(core STATIC
491 hle/service/sm/controller.h 491 hle/service/sm/controller.h
492 hle/service/sm/sm.cpp 492 hle/service/sm/sm.cpp
493 hle/service/sm/sm.h 493 hle/service/sm/sm.h
494 hle/service/sockets/blocking_worker.h
494 hle/service/sockets/bsd.cpp 495 hle/service/sockets/bsd.cpp
495 hle/service/sockets/bsd.h 496 hle/service/sockets/bsd.h
496 hle/service/sockets/ethc.cpp 497 hle/service/sockets/ethc.cpp
@@ -501,6 +502,8 @@ add_library(core STATIC
501 hle/service/sockets/sfdnsres.h 502 hle/service/sockets/sfdnsres.h
502 hle/service/sockets/sockets.cpp 503 hle/service/sockets/sockets.cpp
503 hle/service/sockets/sockets.h 504 hle/service/sockets/sockets.h
505 hle/service/sockets/sockets_translate.cpp
506 hle/service/sockets/sockets_translate.h
504 hle/service/spl/csrng.cpp 507 hle/service/spl/csrng.cpp
505 hle/service/spl/csrng.h 508 hle/service/spl/csrng.h
506 hle/service/spl/module.cpp 509 hle/service/spl/module.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index c2c0eec0b..df81e8e2c 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -188,7 +188,6 @@ struct System::Impl {
188 if (!gpu_core) { 188 if (!gpu_core) {
189 return ResultStatus::ErrorVideoCore; 189 return ResultStatus::ErrorVideoCore;
190 } 190 }
191 gpu_core->Renderer().Rasterizer().SetupDirtyFlags();
192 191
193 is_powered_on = true; 192 is_powered_on = true;
194 exit_lock = false; 193 exit_lock = false;
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index ef0bae556..688b99eba 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -328,7 +328,7 @@ void CpuManager::RunThread(std::size_t core) {
328 system.RegisterCoreThread(core); 328 system.RegisterCoreThread(core);
329 std::string name; 329 std::string name;
330 if (is_multicore) { 330 if (is_multicore) {
331 name = "yuzu:CoreCPUThread_" + std::to_string(core); 331 name = "yuzu:CPUCore_" + std::to_string(core);
332 } else { 332 } else {
333 name = "yuzu:CPUThread"; 333 name = "yuzu:CPUThread";
334 } 334 }
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index 46136d04a..5f1c86a09 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -26,6 +26,7 @@
26#include "core/file_sys/vfs.h" 26#include "core/file_sys/vfs.h"
27#include "core/file_sys/vfs_offset.h" 27#include "core/file_sys/vfs_offset.h"
28#include "core/file_sys/vfs_vector.h" 28#include "core/file_sys/vfs_vector.h"
29#include "core/loader/loader.h"
29 30
30using Common::AsArray; 31using Common::AsArray;
31 32
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 9ffda2e14..e04a54c3c 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -8,7 +8,6 @@
8#include "core/file_sys/bis_factory.h" 8#include "core/file_sys/bis_factory.h"
9#include "core/file_sys/mode.h" 9#include "core/file_sys/mode.h"
10#include "core/file_sys/registered_cache.h" 10#include "core/file_sys/registered_cache.h"
11#include "core/settings.h"
12 11
13namespace FileSys { 12namespace FileSys {
14 13
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 8f0451c98..438d3f8d8 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -6,7 +6,8 @@
6 6
7#include <memory> 7#include <memory>
8 8
9#include "core/file_sys/vfs.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs_types.h"
10 11
11namespace FileSys { 12namespace FileSys {
12 13
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 664a47e7f..956da68f7 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -8,11 +8,11 @@
8#include <fmt/ostream.h> 8#include <fmt/ostream.h>
9 9
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/crypto/key_manager.h"
11#include "core/file_sys/card_image.h" 12#include "core/file_sys/card_image.h"
12#include "core/file_sys/content_archive.h" 13#include "core/file_sys/content_archive.h"
13#include "core/file_sys/nca_metadata.h" 14#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/partition_filesystem.h" 15#include "core/file_sys/partition_filesystem.h"
15#include "core/file_sys/romfs.h"
16#include "core/file_sys/submission_package.h" 16#include "core/file_sys/submission_package.h"
17#include "core/file_sys/vfs_concat.h" 17#include "core/file_sys/vfs_concat.h"
18#include "core/file_sys/vfs_offset.h" 18#include "core/file_sys/vfs_offset.h"
@@ -31,7 +31,8 @@ constexpr std::array partition_names{
31 31
32XCI::XCI(VirtualFile file_) 32XCI::XCI(VirtualFile file_)
33 : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, 33 : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
34 partitions(partition_names.size()), partitions_raw(partition_names.size()) { 34 partitions(partition_names.size()),
35 partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
35 if (file->ReadObject(&header) != sizeof(GamecardHeader)) { 36 if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
36 status = Loader::ResultStatus::ErrorBadXCIHeader; 37 status = Loader::ResultStatus::ErrorBadXCIHeader;
37 return; 38 return;
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index e1b136426..2d0a0f285 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -9,9 +9,12 @@
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/crypto/key_manager.h"
13#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
14 13
14namespace Core::Crypto {
15class KeyManager;
16}
17
15namespace Loader { 18namespace Loader {
16enum class ResultStatus : u16; 19enum class ResultStatus : u16;
17} 20}
@@ -140,6 +143,6 @@ private:
140 143
141 u64 update_normal_partition_end; 144 u64 update_normal_partition_end;
142 145
143 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 146 Core::Crypto::KeyManager& keys;
144}; 147};
145} // namespace FileSys 148} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 5039341c7..426fb6bb5 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -10,10 +10,10 @@
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/crypto/aes_util.h" 11#include "core/crypto/aes_util.h"
12#include "core/crypto/ctr_encryption_layer.h" 12#include "core/crypto/ctr_encryption_layer.h"
13#include "core/crypto/key_manager.h"
13#include "core/file_sys/content_archive.h" 14#include "core/file_sys/content_archive.h"
14#include "core/file_sys/nca_patch.h" 15#include "core/file_sys/nca_patch.h"
15#include "core/file_sys/partition_filesystem.h" 16#include "core/file_sys/partition_filesystem.h"
16#include "core/file_sys/romfs.h"
17#include "core/file_sys/vfs_offset.h" 17#include "core/file_sys/vfs_offset.h"
18#include "core/loader/loader.h" 18#include "core/loader/loader.h"
19 19
@@ -119,7 +119,8 @@ static bool IsValidNCA(const NCAHeader& header) {
119} 119}
120 120
121NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) 121NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset)
122 : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) { 122 : file(std::move(file_)),
123 bktr_base_romfs(std::move(bktr_base_romfs_)), keys{Core::Crypto::KeyManager::Instance()} {
123 if (file == nullptr) { 124 if (file == nullptr) {
124 status = Loader::ResultStatus::ErrorNullFile; 125 status = Loader::ResultStatus::ErrorNullFile;
125 return; 126 return;
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index d25cbcf91..69292232a 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -158,7 +158,7 @@ private:
158 bool encrypted = false; 158 bool encrypted = false;
159 bool is_update = false; 159 bool is_update = false;
160 160
161 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 161 Core::Crypto::KeyManager& keys;
162}; 162};
163 163
164} // namespace FileSys 164} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 63cd2eead..b0a130345 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -5,6 +5,7 @@
5#include "common/string_util.h" 5#include "common/string_util.h"
6#include "common/swap.h" 6#include "common/swap.h"
7#include "core/file_sys/control_metadata.h" 7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/vfs.h"
8 9
9namespace FileSys { 10namespace FileSys {
10 11
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index e37b2fadf..9ab86e35b 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -10,7 +10,7 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs_types.h"
14 14
15namespace FileSys { 15namespace FileSys {
16 16
diff --git a/src/core/file_sys/kernel_executable.cpp b/src/core/file_sys/kernel_executable.cpp
index 76313679d..ef93ef3ed 100644
--- a/src/core/file_sys/kernel_executable.cpp
+++ b/src/core/file_sys/kernel_executable.cpp
@@ -2,9 +2,12 @@
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 <cstring>
6
5#include "common/string_util.h" 7#include "common/string_util.h"
6#include "core/file_sys/kernel_executable.h" 8#include "core/file_sys/kernel_executable.h"
7#include "core/file_sys/vfs_offset.h" 9#include "core/file_sys/vfs_offset.h"
10#include "core/loader/loader.h"
8 11
9namespace FileSys { 12namespace FileSys {
10 13
diff --git a/src/core/file_sys/kernel_executable.h b/src/core/file_sys/kernel_executable.h
index 324a57384..044c554d3 100644
--- a/src/core/file_sys/kernel_executable.h
+++ b/src/core/file_sys/kernel_executable.h
@@ -4,10 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <vector>
9
7#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h"
8#include "common/swap.h" 12#include "common/swap.h"
9#include "core/file_sys/vfs_types.h" 13#include "core/file_sys/vfs_types.h"
10#include "core/loader/loader.h" 14
15namespace Loader {
16enum class ResultStatus : u16;
17}
11 18
12namespace FileSys { 19namespace FileSys {
13 20
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 93d0df6b9..2d1476e3a 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -7,6 +7,7 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/swap.h" 8#include "common/swap.h"
9#include "core/file_sys/nca_metadata.h" 9#include "core/file_sys/nca_metadata.h"
10#include "core/file_sys/vfs.h"
10 11
11namespace FileSys { 12namespace FileSys {
12 13
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index 1f82fff0a..53535e5f5 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -10,7 +10,7 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs_types.h"
14 14
15namespace FileSys { 15namespace FileSys {
16class CNMT; 16class CNMT;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 846986736..48a2ed4d4 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -21,7 +21,7 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
21 magic == Common::MakeMagic('P', 'F', 'S', '0'); 21 magic == Common::MakeMagic('P', 'F', 'S', '0');
22} 22}
23 23
24PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) { 24PartitionFilesystem::PartitionFilesystem(VirtualFile file) {
25 // At least be as large as the header 25 // At least be as large as the header
26 if (file->GetSize() < sizeof(Header)) { 26 if (file->GetSize() < sizeof(Header)) {
27 status = Loader::ResultStatus::ErrorBadPFSHeader; 27 status = Loader::ResultStatus::ErrorBadPFSHeader;
@@ -89,11 +89,11 @@ std::map<std::string, u64> PartitionFilesystem::GetFileSizes() const {
89 return sizes; 89 return sizes;
90} 90}
91 91
92std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const { 92std::vector<VirtualFile> PartitionFilesystem::GetFiles() const {
93 return pfs_files; 93 return pfs_files;
94} 94}
95 95
96std::vector<std::shared_ptr<VfsDirectory>> PartitionFilesystem::GetSubdirectories() const { 96std::vector<VirtualDir> PartitionFilesystem::GetSubdirectories() const {
97 return {}; 97 return {};
98} 98}
99 99
@@ -101,7 +101,7 @@ std::string PartitionFilesystem::GetName() const {
101 return is_hfs ? "HFS0" : "PFS0"; 101 return is_hfs ? "HFS0" : "PFS0";
102} 102}
103 103
104std::shared_ptr<VfsDirectory> PartitionFilesystem::GetParentDirectory() const { 104VirtualDir PartitionFilesystem::GetParentDirectory() const {
105 // TODO(DarkLordZach): Add support for nested containers. 105 // TODO(DarkLordZach): Add support for nested containers.
106 return nullptr; 106 return nullptr;
107} 107}
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index 279193b19..0f831148e 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -24,7 +24,7 @@ namespace FileSys {
24 */ 24 */
25class PartitionFilesystem : public ReadOnlyVfsDirectory { 25class PartitionFilesystem : public ReadOnlyVfsDirectory {
26public: 26public:
27 explicit PartitionFilesystem(std::shared_ptr<VfsFile> file); 27 explicit PartitionFilesystem(VirtualFile file);
28 ~PartitionFilesystem() override; 28 ~PartitionFilesystem() override;
29 29
30 Loader::ResultStatus GetStatus() const; 30 Loader::ResultStatus GetStatus() const;
@@ -32,10 +32,10 @@ public:
32 std::map<std::string, u64> GetFileOffsets() const; 32 std::map<std::string, u64> GetFileOffsets() const;
33 std::map<std::string, u64> GetFileSizes() const; 33 std::map<std::string, u64> GetFileSizes() const;
34 34
35 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 35 std::vector<VirtualFile> GetFiles() const override;
36 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 36 std::vector<VirtualDir> GetSubdirectories() const override;
37 std::string GetName() const override; 37 std::string GetName() const override;
38 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 38 VirtualDir GetParentDirectory() const override;
39 void PrintDebugInfo() const; 39 void PrintDebugInfo() const;
40 40
41private: 41private:
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 729dbb5f4..c228d253e 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -49,8 +49,7 @@ std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
49 return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]); 49 return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
50} 50}
51 51
52std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir, 52VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) {
53 std::string_view name) {
54#ifdef _WIN32 53#ifdef _WIN32
55 return dir->GetSubdirectory(name); 54 return dir->GetSubdirectory(name);
56#else 55#else
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index f4cb918dd..532f4995f 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -6,10 +6,11 @@
6 6
7#include <map> 7#include <map>
8#include <memory> 8#include <memory>
9#include <optional>
9#include <string> 10#include <string>
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "core/file_sys/nca_metadata.h" 12#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs_types.h"
13#include "core/memory/dmnt_cheat_types.h" 14#include "core/memory/dmnt_cheat_types.h"
14 15
15namespace Core { 16namespace Core {
@@ -31,8 +32,7 @@ std::string FormatTitleVersion(u32 version,
31 32
32// Returns a directory with name matching name case-insensitive. Returns nullptr if directory 33// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
33// doesn't have a directory with name. 34// doesn't have a directory with name.
34std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir, 35VirtualDir FindSubdirectoryCaseless(VirtualDir dir, std::string_view name);
35 std::string_view name);
36 36
37// A centralized class to manage patches to games. 37// A centralized class to manage patches to games.
38class PatchManager { 38class PatchManager {
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 43169bf9f..9cf49bf44 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -7,6 +7,7 @@
7 7
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/file_sys/program_metadata.h" 9#include "core/file_sys/program_metadata.h"
10#include "core/file_sys/vfs.h"
10#include "core/loader/loader.h" 11#include "core/loader/loader.h"
11 12
12namespace FileSys { 13namespace FileSys {
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 35069972b..455532567 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -9,7 +9,7 @@
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs_types.h"
13 13
14namespace Loader { 14namespace Loader {
15enum class ResultStatus : u16; 15enum class ResultStatus : u16;
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
index 2fd07ed04..82e683782 100644
--- a/src/core/file_sys/romfs.h
+++ b/src/core/file_sys/romfs.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include "core/file_sys/vfs.h" 7#include "core/file_sys/vfs.h"
9 8
10namespace FileSys { 9namespace FileSys {
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index 6f732e4d8..cb56d8f2d 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -5,8 +5,8 @@
5#include <memory> 5#include <memory>
6#include "core/file_sys/registered_cache.h" 6#include "core/file_sys/registered_cache.h"
7#include "core/file_sys/sdmc_factory.h" 7#include "core/file_sys/sdmc_factory.h"
8#include "core/file_sys/vfs.h"
8#include "core/file_sys/xts_archive.h" 9#include "core/file_sys/xts_archive.h"
9#include "core/settings.h"
10 10
11namespace FileSys { 11namespace FileSys {
12 12
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index 42dc4e08a..2bb92ba93 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs_types.h"
9#include "core/hle/result.h" 9#include "core/hle/result.h"
10 10
11namespace FileSys { 11namespace FileSys {
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 175a8266a..b9ce93b7c 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -54,7 +54,7 @@ void SetTicketKeys(const std::vector<VirtualFile>& files) {
54 54
55NSP::NSP(VirtualFile file_) 55NSP::NSP(VirtualFile file_)
56 : file(std::move(file_)), status{Loader::ResultStatus::Success}, 56 : file(std::move(file_)), status{Loader::ResultStatus::Success},
57 pfs(std::make_shared<PartitionFilesystem>(file)) { 57 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
58 if (pfs->GetStatus() != Loader::ResultStatus::Success) { 58 if (pfs->GetStatus() != Loader::ResultStatus::Success) {
59 status = pfs->GetStatus(); 59 status = pfs->GetStatus();
60 return; 60 return;
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index cf89de6a9..2db5e46b8 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -10,6 +10,10 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs.h"
12 12
13namespace Core::Crypto {
14class KeyManager;
15}
16
13namespace Loader { 17namespace Loader {
14enum class ResultStatus : u16; 18enum class ResultStatus : u16;
15} 19}
@@ -73,7 +77,7 @@ private:
73 std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; 77 std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
74 std::vector<VirtualFile> ticket_files; 78 std::vector<VirtualFile> ticket_files;
75 79
76 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 80 Core::Crypto::KeyManager& keys;
77 81
78 VirtualFile romfs; 82 VirtualFile romfs;
79 VirtualDir exefs; 83 VirtualDir exefs;
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index ccf5966d0..24c58e7ae 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -15,8 +15,9 @@
15#include "common/hex_util.h" 15#include "common/hex_util.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/crypto/aes_util.h" 17#include "core/crypto/aes_util.h"
18#include "core/crypto/key_manager.h"
18#include "core/crypto/xts_encryption_layer.h" 19#include "core/crypto/xts_encryption_layer.h"
19#include "core/file_sys/partition_filesystem.h" 20#include "core/file_sys/content_archive.h"
20#include "core/file_sys/vfs_offset.h" 21#include "core/file_sys/vfs_offset.h"
21#include "core/file_sys/xts_archive.h" 22#include "core/file_sys/xts_archive.h"
22#include "core/loader/loader.h" 23#include "core/loader/loader.h"
@@ -43,7 +44,9 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
43 return true; 44 return true;
44} 45}
45 46
46NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { 47NAX::NAX(VirtualFile file_)
48 : header(std::make_unique<NAXHeader>()),
49 file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
47 std::string path = Common::FS::SanitizePath(file->GetFullPath()); 50 std::string path = Common::FS::SanitizePath(file->GetFullPath());
48 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca", 51 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
49 std::regex_constants::ECMAScript | 52 std::regex_constants::ECMAScript |
@@ -60,7 +63,8 @@ NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::m
60} 63}
61 64
62NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id) 65NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
63 : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { 66 : header(std::make_unique<NAXHeader>()),
67 file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
64 Core::Crypto::SHA256Hash hash{}; 68 Core::Crypto::SHA256Hash hash{};
65 mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0); 69 mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
66 status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0], 70 status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index 563531bb6..c472e226e 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -9,12 +9,16 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/crypto/key_manager.h" 11#include "core/crypto/key_manager.h"
12#include "core/file_sys/content_archive.h"
13#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
14#include "core/loader/loader.h" 13
14namespace Loader {
15enum class ResultStatus : u16;
16}
15 17
16namespace FileSys { 18namespace FileSys {
17 19
20class NCA;
21
18struct NAXHeader { 22struct NAXHeader {
19 std::array<u8, 0x20> hmac; 23 std::array<u8, 0x20> hmac;
20 u64_le magic; 24 u64_le magic;
@@ -62,6 +66,6 @@ private:
62 66
63 VirtualFile dec_file; 67 VirtualFile dec_file;
64 68
65 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 69 Core::Crypto::KeyManager& keys;
66}; 70};
67} // namespace FileSys 71} // namespace FileSys
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h
index 91ecc30ab..e2e3bbbb3 100644
--- a/src/core/frontend/framebuffer_layout.h
+++ b/src/core/frontend/framebuffer_layout.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h"
7#include "common/math_util.h" 8#include "common/math_util.h"
8 9
9namespace Layout { 10namespace Layout {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index cabe8d418..f2b0fe2fd 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -219,6 +219,7 @@ struct KernelCore::Impl {
219 return static_cast<u32>(system.GetCpuManager().CurrentCore()); 219 return static_cast<u32>(system.GetCpuManager().CurrentCore());
220 } 220 }
221 } 221 }
222 std::unique_lock lock{register_thread_mutex};
222 const auto it = host_thread_ids.find(this_id); 223 const auto it = host_thread_ids.find(this_id);
223 if (it == host_thread_ids.end()) { 224 if (it == host_thread_ids.end()) {
224 return Core::INVALID_HOST_THREAD_ID; 225 return Core::INVALID_HOST_THREAD_ID;
@@ -324,7 +325,7 @@ struct KernelCore::Impl {
324 std::unordered_map<std::thread::id, u32> host_thread_ids; 325 std::unordered_map<std::thread::id, u32> host_thread_ids;
325 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; 326 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
326 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; 327 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
327 std::mutex register_thread_mutex; 328 mutable std::mutex register_thread_mutex;
328 329
329 // Kernel memory management 330 // Kernel memory management
330 std::unique_ptr<Memory::MemoryManager> memory_manager; 331 std::unique_ptr<Memory::MemoryManager> memory_manager;
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index a4b234424..5cbd3b912 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -756,7 +756,11 @@ void Scheduler::SwitchToCurrent() {
756 current_thread = selected_thread; 756 current_thread = selected_thread;
757 is_context_switch_pending = false; 757 is_context_switch_pending = false;
758 } 758 }
759 while (!is_context_switch_pending) { 759 const auto is_switch_pending = [this] {
760 std::scoped_lock lock{guard};
761 return is_context_switch_pending;
762 };
763 do {
760 if (current_thread != nullptr && !current_thread->IsHLEThread()) { 764 if (current_thread != nullptr && !current_thread->IsHLEThread()) {
761 current_thread->context_guard.lock(); 765 current_thread->context_guard.lock();
762 if (!current_thread->IsRunnable()) { 766 if (!current_thread->IsRunnable()) {
@@ -775,7 +779,7 @@ void Scheduler::SwitchToCurrent() {
775 next_context = &idle_thread->GetHostContext(); 779 next_context = &idle_thread->GetHostContext();
776 } 780 }
777 Common::Fiber::YieldTo(switch_fiber, *next_context); 781 Common::Fiber::YieldTo(switch_fiber, *next_context);
778 } 782 } while (!is_switch_pending());
779 } 783 }
780} 784}
781 785
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 26fd87f58..649128be4 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -844,8 +844,7 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
844 return; 844 return;
845 } 845 }
846 846
847 FileSys::StorageId id; 847 FileSys::StorageId id{};
848
849 switch (parameters.space_id) { 848 switch (parameters.space_id) {
850 case FileSys::SaveDataSpaceId::NandUser: 849 case FileSys::SaveDataSpaceId::NandUser:
851 id = FileSys::StorageId::NandUser; 850 id = FileSys::StorageId::NandUser;
@@ -857,6 +856,10 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
857 case FileSys::SaveDataSpaceId::NandSystem: 856 case FileSys::SaveDataSpaceId::NandSystem:
858 id = FileSys::StorageId::NandSystem; 857 id = FileSys::StorageId::NandSystem;
859 break; 858 break;
859 case FileSys::SaveDataSpaceId::TemporaryStorage:
860 case FileSys::SaveDataSpaceId::ProperSystem:
861 case FileSys::SaveDataSpaceId::SafeMode:
862 UNREACHABLE();
860 } 863 }
861 864
862 auto filesystem = 865 auto filesystem =
@@ -902,7 +905,14 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
902 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData 905 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
903 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); 906 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
904 907
905 LOG_WARNING(Service_FS, "(STUBBED) called, flags={}", flags); 908 LOG_WARNING(Service_FS,
909 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
910 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
911 "attribute.type={}, attribute.rank={}, attribute.index={}",
912 flags, static_cast<u32>(parameters.space_id), parameters.attribute.title_id,
913 parameters.attribute.user_id[1], parameters.attribute.user_id[0],
914 parameters.attribute.save_id, static_cast<u32>(parameters.attribute.type),
915 static_cast<u32>(parameters.attribute.rank), parameters.attribute.index);
906 916
907 IPC::ResponseBuilder rb{ctx, 3}; 917 IPC::ResponseBuilder rb{ctx, 3};
908 rb.Push(RESULT_SUCCESS); 918 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 45fde8df2..e742497e1 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -574,6 +574,22 @@ Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMo
574 return gyroscope_zero_drift_mode; 574 return gyroscope_zero_drift_mode;
575} 575}
576 576
577void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
578 const auto npad_index_1 = NPadIdToIndex(npad_id_1);
579 const auto npad_index_2 = NPadIdToIndex(npad_id_2);
580
581 // If the controllers at both npad indices form a pair of left and right joycons, merge them.
582 // Otherwise, do nothing.
583 if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft &&
584 connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) ||
585 (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
586 connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
587 // Disconnect the joycon at the second id and connect the dual joycon at the first index.
588 DisconnectNPad(npad_id_2);
589 AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
590 }
591}
592
577void Controller_NPad::StartLRAssignmentMode() { 593void Controller_NPad::StartLRAssignmentMode() {
578 // Nothing internally is used for lr assignment mode. Since we have the ability to set the 594 // Nothing internally is used for lr assignment mode. Since we have the ability to set the
579 // controller types from boot, it doesn't really matter about showing a selection screen 595 // controller types from boot, it doesn't really matter about showing a selection screen
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 75ce5b731..ad25c6fbf 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -134,6 +134,7 @@ public:
134 void ConnectAllDisconnectedControllers(); 134 void ConnectAllDisconnectedControllers();
135 void ClearAllControllers(); 135 void ClearAllControllers();
136 136
137 void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2);
137 void StartLRAssignmentMode(); 138 void StartLRAssignmentMode();
138 void StopLRAssignmentMode(); 139 void StopLRAssignmentMode();
139 bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); 140 bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index e326f8f5c..0df395e85 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -40,9 +40,14 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
40 cur_entry.sampling_number = last_entry.sampling_number + 1; 40 cur_entry.sampling_number = last_entry.sampling_number + 1;
41 cur_entry.sampling_number2 = cur_entry.sampling_number; 41 cur_entry.sampling_number2 = cur_entry.sampling_number;
42 42
43 const auto [x, y, pressed] = touch_device->GetStatus(); 43 bool pressed = false;
44 float x, y;
45 std::tie(x, y, pressed) = touch_device->GetStatus();
44 auto& touch_entry = cur_entry.states[0]; 46 auto& touch_entry = cur_entry.states[0];
45 touch_entry.attribute.raw = 0; 47 touch_entry.attribute.raw = 0;
48 if (!pressed && touch_btn_device) {
49 std::tie(x, y, pressed) = touch_btn_device->GetStatus();
50 }
46 if (pressed && Settings::values.touchscreen.enabled) { 51 if (pressed && Settings::values.touchscreen.enabled) {
47 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); 52 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
48 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); 53 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
@@ -63,5 +68,10 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
63 68
64void Controller_Touchscreen::OnLoadInputDevices() { 69void Controller_Touchscreen::OnLoadInputDevices() {
65 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device); 70 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device);
71 if (Settings::values.use_touch_from_button) {
72 touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button");
73 } else {
74 touch_btn_device.reset();
75 }
66} 76}
67} // namespace Service::HID 77} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index a1d97269e..4d9042adc 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -68,6 +68,7 @@ private:
68 "TouchScreenSharedMemory is an invalid size"); 68 "TouchScreenSharedMemory is an invalid size");
69 TouchScreenSharedMemory shared_memory{}; 69 TouchScreenSharedMemory shared_memory{};
70 std::unique_ptr<Input::TouchDevice> touch_device; 70 std::unique_ptr<Input::TouchDevice> touch_device;
71 std::unique_ptr<Input::TouchDevice> touch_btn_device;
71 s64_le last_touch{}; 72 s64_le last_touch{};
72}; 73};
73} // namespace Service::HID 74} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 33416b5dd..bd3c2f26b 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -671,13 +671,15 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
671 671
672void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 672void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
673 IPC::RequestParser rp{ctx}; 673 IPC::RequestParser rp{ctx};
674 const auto unknown_1{rp.Pop<u32>()}; 674 const auto npad_id_1{rp.Pop<u32>()};
675 const auto unknown_2{rp.Pop<u32>()}; 675 const auto npad_id_2{rp.Pop<u32>()};
676 const auto applet_resource_user_id{rp.Pop<u64>()}; 676 const auto applet_resource_user_id{rp.Pop<u64>()};
677 677
678 LOG_WARNING(Service_HID, 678 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
679 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", 679 npad_id_1, npad_id_2, applet_resource_user_id);
680 unknown_1, unknown_2, applet_resource_user_id); 680
681 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
682 controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
681 683
682 IPC::ResponseBuilder rb{ctx, 2}; 684 IPC::ResponseBuilder rb{ctx, 2};
683 rb.Push(RESULT_SUCCESS); 685 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 01ddcdbd6..2e9d95195 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -9,6 +9,7 @@
9#include "core/hle/kernel/writable_event.h" 9#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nifm/nifm.h" 10#include "core/hle/service/nifm/nifm.h"
11#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12#include "core/network/network.h"
12#include "core/settings.h" 13#include "core/settings.h"
13 14
14namespace Service::NIFM { 15namespace Service::NIFM {
@@ -174,6 +175,16 @@ private:
174 IPC::ResponseBuilder rb{ctx, 2}; 175 IPC::ResponseBuilder rb{ctx, 2};
175 rb.Push(RESULT_SUCCESS); 176 rb.Push(RESULT_SUCCESS);
176 } 177 }
178 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
179 LOG_WARNING(Service_NIFM, "(STUBBED) called");
180
181 const auto [ipv4, error] = Network::GetHostIPv4Address();
182 UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
183
184 IPC::ResponseBuilder rb{ctx, 3};
185 rb.Push(RESULT_SUCCESS);
186 rb.PushRaw(ipv4);
187 }
177 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 188 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
178 LOG_DEBUG(Service_NIFM, "called"); 189 LOG_DEBUG(Service_NIFM, "called");
179 190
@@ -235,7 +246,7 @@ IGeneralService::IGeneralService(Core::System& system)
235 {9, nullptr, "SetNetworkProfile"}, 246 {9, nullptr, "SetNetworkProfile"},
236 {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, 247 {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"},
237 {11, nullptr, "GetScanDataOld"}, 248 {11, nullptr, "GetScanDataOld"},
238 {12, nullptr, "GetCurrentIpAddress"}, 249 {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"},
239 {13, nullptr, "GetCurrentAccessPointOld"}, 250 {13, nullptr, "GetCurrentAccessPointOld"},
240 {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"}, 251 {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"},
241 {15, nullptr, "GetCurrentIpConfigInfo"}, 252 {15, nullptr, "GetCurrentIpConfigInfo"},
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 886450be2..58ee1f712 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -5,6 +5,7 @@
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/file_sys/control_metadata.h" 6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h" 7#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/vfs.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/kernel/hle_ipc.h"
10#include "core/hle/service/ns/errors.h" 11#include "core/hle/service/ns/errors.h"
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index fa5347af9..538f28495 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -246,7 +246,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
246 PSC::InstallInterfaces(*sm); 246 PSC::InstallInterfaces(*sm);
247 PSM::InstallInterfaces(*sm); 247 PSM::InstallInterfaces(*sm);
248 Set::InstallInterfaces(*sm); 248 Set::InstallInterfaces(*sm);
249 Sockets::InstallInterfaces(*sm); 249 Sockets::InstallInterfaces(*sm, system);
250 SPL::InstallInterfaces(*sm); 250 SPL::InstallInterfaces(*sm);
251 SSL::InstallInterfaces(*sm); 251 SSL::InstallInterfaces(*sm);
252 Time::InstallInterfaces(system); 252 Time::InstallInterfaces(system);
diff --git a/src/core/hle/service/sockets/blocking_worker.h b/src/core/hle/service/sockets/blocking_worker.h
new file mode 100644
index 000000000..31ef6b821
--- /dev/null
+++ b/src/core/hle/service/sockets/blocking_worker.h
@@ -0,0 +1,162 @@
1// Copyright 2020 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 <memory>
9#include <string>
10#include <string_view>
11#include <thread>
12#include <variant>
13#include <vector>
14
15#include <fmt/format.h>
16
17#include "common/assert.h"
18#include "common/microprofile.h"
19#include "common/thread.h"
20#include "core/core.h"
21#include "core/hle/kernel/hle_ipc.h"
22#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/thread.h"
24#include "core/hle/kernel/writable_event.h"
25
26namespace Service::Sockets {
27
28/**
29 * Worker abstraction to execute blocking calls on host without blocking the guest thread
30 *
31 * @tparam Service Service where the work is executed
32 * @tparam ...Types Types of work to execute
33 */
34template <class Service, class... Types>
35class BlockingWorker {
36 using This = BlockingWorker<Service, Types...>;
37 using WorkVariant = std::variant<std::monostate, Types...>;
38
39public:
40 /// Create a new worker
41 static std::unique_ptr<This> Create(Core::System& system, Service* service,
42 std::string_view name) {
43 return std::unique_ptr<This>(new This(system, service, name));
44 }
45
46 ~BlockingWorker() {
47 while (!is_available.load(std::memory_order_relaxed)) {
48 // Busy wait until work is finished
49 std::this_thread::yield();
50 }
51 // Monostate means to exit the thread
52 work = std::monostate{};
53 work_event.Set();
54 thread.join();
55 }
56
57 /**
58 * Try to capture the worker to send work after a success
59 * @returns True when the worker has been successfully captured
60 */
61 bool TryCapture() {
62 bool expected = true;
63 return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed,
64 std::memory_order_relaxed);
65 }
66
67 /**
68 * Send work to this worker abstraction
69 * @see TryCapture must be called before attempting to call this function
70 */
71 template <class Work>
72 void SendWork(Work new_work) {
73 ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured");
74 work = std::move(new_work);
75 work_event.Set();
76 }
77
78 /// Generate a callback for @see SleepClientThread
79 template <class Work>
80 auto Callback() {
81 return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx,
82 Kernel::ThreadWakeupReason reason) {
83 ASSERT(reason == Kernel::ThreadWakeupReason::Signal);
84 std::get<Work>(work).Response(ctx);
85 is_available.store(true);
86 };
87 }
88
89 /// Get kernel event that will be signalled by the worker when the host operation finishes
90 std::shared_ptr<Kernel::WritableEvent> KernelEvent() const {
91 return kernel_event;
92 }
93
94private:
95 explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) {
96 auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name));
97 kernel_event = std::move(pair.writable);
98 thread = std::thread([this, &system, service, name] { Run(system, service, name); });
99 }
100
101 void Run(Core::System& system, Service* service, std::string_view name) {
102 system.RegisterHostThread();
103
104 const std::string thread_name = fmt::format("yuzu:{}", name);
105 MicroProfileOnThreadCreate(thread_name.c_str());
106 Common::SetCurrentThreadName(thread_name.c_str());
107
108 bool keep_running = true;
109 while (keep_running) {
110 work_event.Wait();
111
112 const auto visit_fn = [service, &keep_running](auto&& w) {
113 using T = std::decay_t<decltype(w)>;
114 if constexpr (std::is_same_v<T, std::monostate>) {
115 keep_running = false;
116 } else {
117 w.Execute(service);
118 }
119 };
120 std::visit(visit_fn, work);
121
122 kernel_event->Signal();
123 }
124 }
125
126 std::thread thread;
127 WorkVariant work;
128 Common::Event work_event;
129 std::shared_ptr<Kernel::WritableEvent> kernel_event;
130 std::atomic_bool is_available{true};
131};
132
133template <class Service, class... Types>
134class BlockingWorkerPool {
135 using Worker = BlockingWorker<Service, Types...>;
136
137public:
138 explicit BlockingWorkerPool(Core::System& system_, Service* service_)
139 : system{system_}, service{service_} {}
140
141 /// Returns a captured worker thread, creating new ones if necessary
142 Worker* CaptureWorker() {
143 for (auto& worker : workers) {
144 if (worker->TryCapture()) {
145 return worker.get();
146 }
147 }
148 auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size()));
149 [[maybe_unused]] const bool success = new_worker->TryCapture();
150 ASSERT(success);
151
152 return workers.emplace_back(std::move(new_worker)).get();
153 }
154
155private:
156 Core::System& system;
157 Service* const service;
158
159 std::vector<std::unique_ptr<Worker>> workers;
160};
161
162} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 8d4952c0e..803505452 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -2,18 +2,138 @@
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 <memory>
7#include <string>
8#include <utility>
9#include <vector>
10
11#include <fmt/format.h>
12
13#include "common/microprofile.h"
14#include "common/thread.h"
5#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/thread.h"
6#include "core/hle/service/sockets/bsd.h" 17#include "core/hle/service/sockets/bsd.h"
18#include "core/hle/service/sockets/sockets_translate.h"
19#include "core/network/network.h"
20#include "core/network/sockets.h"
7 21
8namespace Service::Sockets { 22namespace Service::Sockets {
9 23
24namespace {
25
26bool IsConnectionBased(Type type) {
27 switch (type) {
28 case Type::STREAM:
29 return true;
30 case Type::DGRAM:
31 return false;
32 default:
33 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
34 return false;
35 }
36}
37
38} // Anonymous namespace
39
40void BSD::PollWork::Execute(BSD* bsd) {
41 std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
42}
43
44void BSD::PollWork::Response(Kernel::HLERequestContext& ctx) {
45 ctx.WriteBuffer(write_buffer);
46
47 IPC::ResponseBuilder rb{ctx, 4};
48 rb.Push(RESULT_SUCCESS);
49 rb.Push<s32>(ret);
50 rb.PushEnum(bsd_errno);
51}
52
53void BSD::AcceptWork::Execute(BSD* bsd) {
54 std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
55}
56
57void BSD::AcceptWork::Response(Kernel::HLERequestContext& ctx) {
58 ctx.WriteBuffer(write_buffer);
59
60 IPC::ResponseBuilder rb{ctx, 5};
61 rb.Push(RESULT_SUCCESS);
62 rb.Push<s32>(ret);
63 rb.PushEnum(bsd_errno);
64 rb.Push<u32>(static_cast<u32>(write_buffer.size()));
65}
66
67void BSD::ConnectWork::Execute(BSD* bsd) {
68 bsd_errno = bsd->ConnectImpl(fd, addr);
69}
70
71void BSD::ConnectWork::Response(Kernel::HLERequestContext& ctx) {
72 IPC::ResponseBuilder rb{ctx, 4};
73 rb.Push(RESULT_SUCCESS);
74 rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
75 rb.PushEnum(bsd_errno);
76}
77
78void BSD::RecvWork::Execute(BSD* bsd) {
79 std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
80}
81
82void BSD::RecvWork::Response(Kernel::HLERequestContext& ctx) {
83 ctx.WriteBuffer(message);
84
85 IPC::ResponseBuilder rb{ctx, 4};
86 rb.Push(RESULT_SUCCESS);
87 rb.Push<s32>(ret);
88 rb.PushEnum(bsd_errno);
89}
90
91void BSD::RecvFromWork::Execute(BSD* bsd) {
92 std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
93}
94
95void BSD::RecvFromWork::Response(Kernel::HLERequestContext& ctx) {
96 ctx.WriteBuffer(message, 0);
97 if (!addr.empty()) {
98 ctx.WriteBuffer(addr, 1);
99 }
100
101 IPC::ResponseBuilder rb{ctx, 5};
102 rb.Push(RESULT_SUCCESS);
103 rb.Push<s32>(ret);
104 rb.PushEnum(bsd_errno);
105 rb.Push<u32>(static_cast<u32>(addr.size()));
106}
107
108void BSD::SendWork::Execute(BSD* bsd) {
109 std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
110}
111
112void BSD::SendWork::Response(Kernel::HLERequestContext& ctx) {
113 IPC::ResponseBuilder rb{ctx, 4};
114 rb.Push(RESULT_SUCCESS);
115 rb.Push<s32>(ret);
116 rb.PushEnum(bsd_errno);
117}
118
119void BSD::SendToWork::Execute(BSD* bsd) {
120 std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
121}
122
123void BSD::SendToWork::Response(Kernel::HLERequestContext& ctx) {
124 IPC::ResponseBuilder rb{ctx, 4};
125 rb.Push(RESULT_SUCCESS);
126 rb.Push<s32>(ret);
127 rb.PushEnum(bsd_errno);
128}
129
10void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { 130void BSD::RegisterClient(Kernel::HLERequestContext& ctx) {
11 LOG_WARNING(Service, "(STUBBED) called"); 131 LOG_WARNING(Service, "(STUBBED) called");
12 132
13 IPC::ResponseBuilder rb{ctx, 3}; 133 IPC::ResponseBuilder rb{ctx, 3};
14 134
15 rb.Push(RESULT_SUCCESS); 135 rb.Push(RESULT_SUCCESS);
16 rb.Push<u32>(0); // bsd errno 136 rb.Push<s32>(0); // bsd errno
17} 137}
18 138
19void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { 139void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
@@ -26,20 +146,19 @@ void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
26 146
27void BSD::Socket(Kernel::HLERequestContext& ctx) { 147void BSD::Socket(Kernel::HLERequestContext& ctx) {
28 IPC::RequestParser rp{ctx}; 148 IPC::RequestParser rp{ctx};
149 const u32 domain = rp.Pop<u32>();
150 const u32 type = rp.Pop<u32>();
151 const u32 protocol = rp.Pop<u32>();
29 152
30 u32 domain = rp.Pop<u32>(); 153 LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
31 u32 type = rp.Pop<u32>();
32 u32 protocol = rp.Pop<u32>();
33
34 LOG_WARNING(Service, "(STUBBED) called domain={} type={} protocol={}", domain, type, protocol);
35 154
36 u32 fd = next_fd++; 155 const auto [fd, bsd_errno] = SocketImpl(static_cast<Domain>(domain), static_cast<Type>(type),
156 static_cast<Protocol>(protocol));
37 157
38 IPC::ResponseBuilder rb{ctx, 4}; 158 IPC::ResponseBuilder rb{ctx, 4};
39
40 rb.Push(RESULT_SUCCESS); 159 rb.Push(RESULT_SUCCESS);
41 rb.Push<u32>(fd); 160 rb.Push<s32>(fd);
42 rb.Push<u32>(0); // bsd errno 161 rb.PushEnum(bsd_errno);
43} 162}
44 163
45void BSD::Select(Kernel::HLERequestContext& ctx) { 164void BSD::Select(Kernel::HLERequestContext& ctx) {
@@ -52,67 +171,663 @@ void BSD::Select(Kernel::HLERequestContext& ctx) {
52 rb.Push<u32>(0); // bsd errno 171 rb.Push<u32>(0); // bsd errno
53} 172}
54 173
174void BSD::Poll(Kernel::HLERequestContext& ctx) {
175 IPC::RequestParser rp{ctx};
176 const s32 nfds = rp.Pop<s32>();
177 const s32 timeout = rp.Pop<s32>();
178
179 LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout);
180
181 ExecuteWork(ctx, "BSD:Poll", timeout != 0,
182 PollWork{
183 .nfds = nfds,
184 .timeout = timeout,
185 .read_buffer = ctx.ReadBuffer(),
186 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
187 });
188}
189
190void BSD::Accept(Kernel::HLERequestContext& ctx) {
191 IPC::RequestParser rp{ctx};
192 const s32 fd = rp.Pop<s32>();
193
194 LOG_DEBUG(Service, "called. fd={}", fd);
195
196 ExecuteWork(ctx, "BSD:Accept", IsBlockingSocket(fd),
197 AcceptWork{
198 .fd = fd,
199 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
200 });
201}
202
55void BSD::Bind(Kernel::HLERequestContext& ctx) { 203void BSD::Bind(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service, "(STUBBED) called"); 204 IPC::RequestParser rp{ctx};
205 const s32 fd = rp.Pop<s32>();
57 206
58 IPC::ResponseBuilder rb{ctx, 4}; 207 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
59 208
60 rb.Push(RESULT_SUCCESS); 209 BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
61 rb.Push<u32>(0); // ret
62 rb.Push<u32>(0); // bsd errno
63} 210}
64 211
65void BSD::Connect(Kernel::HLERequestContext& ctx) { 212void BSD::Connect(Kernel::HLERequestContext& ctx) {
66 LOG_WARNING(Service, "(STUBBED) called"); 213 IPC::RequestParser rp{ctx};
214 const s32 fd = rp.Pop<s32>();
67 215
68 IPC::ResponseBuilder rb{ctx, 4}; 216 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
217
218 ExecuteWork(ctx, "BSD:Connect", IsBlockingSocket(fd),
219 ConnectWork{
220 .fd = fd,
221 .addr = ctx.ReadBuffer(),
222 });
223}
224
225void BSD::GetPeerName(Kernel::HLERequestContext& ctx) {
226 IPC::RequestParser rp{ctx};
227 const s32 fd = rp.Pop<s32>();
228
229 LOG_DEBUG(Service, "called. fd={}", fd);
69 230
231 std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
232 const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
233
234 ctx.WriteBuffer(write_buffer);
235
236 IPC::ResponseBuilder rb{ctx, 5};
70 rb.Push(RESULT_SUCCESS); 237 rb.Push(RESULT_SUCCESS);
71 rb.Push<u32>(0); // ret 238 rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
72 rb.Push<u32>(0); // bsd errno 239 rb.PushEnum(bsd_errno);
240 rb.Push<u32>(static_cast<u32>(write_buffer.size()));
241}
242
243void BSD::GetSockName(Kernel::HLERequestContext& ctx) {
244 IPC::RequestParser rp{ctx};
245 const s32 fd = rp.Pop<s32>();
246
247 LOG_DEBUG(Service, "called. fd={}", fd);
248
249 std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
250 const Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
251
252 ctx.WriteBuffer(write_buffer);
253
254 IPC::ResponseBuilder rb{ctx, 5};
255 rb.Push(RESULT_SUCCESS);
256 rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
257 rb.PushEnum(bsd_errno);
258 rb.Push<u32>(static_cast<u32>(write_buffer.size()));
73} 259}
74 260
75void BSD::Listen(Kernel::HLERequestContext& ctx) { 261void BSD::Listen(Kernel::HLERequestContext& ctx) {
76 LOG_WARNING(Service, "(STUBBED) called"); 262 IPC::RequestParser rp{ctx};
263 const s32 fd = rp.Pop<s32>();
264 const s32 backlog = rp.Pop<s32>();
77 265
78 IPC::ResponseBuilder rb{ctx, 4}; 266 LOG_DEBUG(Service, "called. fd={} backlog={}", fd, backlog);
267
268 BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
269}
270
271void BSD::Fcntl(Kernel::HLERequestContext& ctx) {
272 IPC::RequestParser rp{ctx};
273 const s32 fd = rp.Pop<s32>();
274 const s32 cmd = rp.Pop<s32>();
275 const s32 arg = rp.Pop<s32>();
79 276
277 LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
278
279 const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg);
280
281 IPC::ResponseBuilder rb{ctx, 4};
80 rb.Push(RESULT_SUCCESS); 282 rb.Push(RESULT_SUCCESS);
81 rb.Push<u32>(0); // ret 283 rb.Push<s32>(ret);
82 rb.Push<u32>(0); // bsd errno 284 rb.PushEnum(bsd_errno);
83} 285}
84 286
85void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { 287void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
86 LOG_WARNING(Service, "(STUBBED) called"); 288 IPC::RequestParser rp{ctx};
87 289
88 IPC::ResponseBuilder rb{ctx, 4}; 290 const s32 fd = rp.Pop<s32>();
291 const u32 level = rp.Pop<u32>();
292 const OptName optname = static_cast<OptName>(rp.Pop<u32>());
89 293
90 rb.Push(RESULT_SUCCESS); 294 const std::vector<u8> buffer = ctx.ReadBuffer();
91 rb.Push<u32>(0); // ret 295 const u8* optval = buffer.empty() ? nullptr : buffer.data();
92 rb.Push<u32>(0); // bsd errno 296 size_t optlen = buffer.size();
297
298 std::array<u64, 2> values;
299 if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) {
300 std::memcpy(values.data(), buffer.data(), sizeof(values));
301 optlen = sizeof(values);
302 optval = reinterpret_cast<const u8*>(values.data());
303 }
304
305 LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level,
306 static_cast<u32>(optname), optlen);
307
308 BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval));
309}
310
311void BSD::Shutdown(Kernel::HLERequestContext& ctx) {
312 IPC::RequestParser rp{ctx};
313
314 const s32 fd = rp.Pop<s32>();
315 const s32 how = rp.Pop<s32>();
316
317 LOG_DEBUG(Service, "called. fd={} how={}", fd, how);
318
319 BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
320}
321
322void BSD::Recv(Kernel::HLERequestContext& ctx) {
323 IPC::RequestParser rp{ctx};
324
325 const s32 fd = rp.Pop<s32>();
326 const u32 flags = rp.Pop<u32>();
327
328 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize());
329
330 ExecuteWork(ctx, "BSD:Recv", IsBlockingSocket(fd),
331 RecvWork{
332 .fd = fd,
333 .flags = flags,
334 .message = std::vector<u8>(ctx.GetWriteBufferSize()),
335 });
336}
337
338void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
339 IPC::RequestParser rp{ctx};
340
341 const s32 fd = rp.Pop<s32>();
342 const u32 flags = rp.Pop<u32>();
343
344 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags,
345 ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1));
346
347 ExecuteWork(ctx, "BSD:RecvFrom", IsBlockingSocket(fd),
348 RecvFromWork{
349 .fd = fd,
350 .flags = flags,
351 .message = std::vector<u8>(ctx.GetWriteBufferSize(0)),
352 .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)),
353 });
354}
355
356void BSD::Send(Kernel::HLERequestContext& ctx) {
357 IPC::RequestParser rp{ctx};
358
359 const s32 fd = rp.Pop<s32>();
360 const u32 flags = rp.Pop<u32>();
361
362 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize());
363
364 ExecuteWork(ctx, "BSD:Send", IsBlockingSocket(fd),
365 SendWork{
366 .fd = fd,
367 .flags = flags,
368 .message = ctx.ReadBuffer(),
369 });
93} 370}
94 371
95void BSD::SendTo(Kernel::HLERequestContext& ctx) { 372void BSD::SendTo(Kernel::HLERequestContext& ctx) {
96 LOG_WARNING(Service, "(STUBBED) called"); 373 IPC::RequestParser rp{ctx};
374 const s32 fd = rp.Pop<s32>();
375 const u32 flags = rp.Pop<u32>();
376
377 LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags,
378 ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1));
379
380 ExecuteWork(ctx, "BSD:SendTo", IsBlockingSocket(fd),
381 SendToWork{
382 .fd = fd,
383 .flags = flags,
384 .message = ctx.ReadBuffer(0),
385 .addr = ctx.ReadBuffer(1),
386 });
387}
97 388
98 IPC::ResponseBuilder rb{ctx, 4}; 389void BSD::Write(Kernel::HLERequestContext& ctx) {
390 IPC::RequestParser rp{ctx};
391 const s32 fd = rp.Pop<s32>();
99 392
100 rb.Push(RESULT_SUCCESS); 393 LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize());
101 rb.Push<u32>(0); // ret 394
102 rb.Push<u32>(0); // bsd errno 395 ExecuteWork(ctx, "BSD:Write", IsBlockingSocket(fd),
396 SendWork{
397 .fd = fd,
398 .flags = 0,
399 .message = ctx.ReadBuffer(),
400 });
103} 401}
104 402
105void BSD::Close(Kernel::HLERequestContext& ctx) { 403void BSD::Close(Kernel::HLERequestContext& ctx) {
106 LOG_WARNING(Service, "(STUBBED) called"); 404 IPC::RequestParser rp{ctx};
405 const s32 fd = rp.Pop<s32>();
406
407 LOG_DEBUG(Service, "called. fd={}", fd);
408
409 BuildErrnoResponse(ctx, CloseImpl(fd));
410}
411
412template <typename Work>
413void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
414 bool is_blocking, Work work) {
415 if (!is_blocking) {
416 work.Execute(this);
417 work.Response(ctx);
418 return;
419 }
420
421 // Signal a dummy response to make IPC validation happy
422 // This will be overwritten by the SleepClientThread callback
423 work.Response(ctx);
424
425 auto worker = worker_pool.CaptureWorker();
426
427 ctx.SleepClientThread(std::string(sleep_reason), std::numeric_limits<u64>::max(),
428 worker->Callback<Work>(), worker->KernelEvent());
429
430 worker->SendWork(std::move(work));
431}
432
433std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
434 if (type == Type::SEQPACKET) {
435 UNIMPLEMENTED_MSG("SOCK_SEQPACKET errno management");
436 } else if (type == Type::RAW && (domain != Domain::INET || protocol != Protocol::ICMP)) {
437 UNIMPLEMENTED_MSG("SOCK_RAW errno management");
438 }
439
440 [[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0;
441 UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
442 type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
443
444 const s32 fd = FindFreeFileDescriptorHandle();
445 if (fd < 0) {
446 LOG_ERROR(Service, "No more file descriptors available");
447 return {-1, Errno::MFILE};
448 }
449
450 FileDescriptor& descriptor = file_descriptors[fd].emplace();
451 // ENONMEM might be thrown here
452
453 LOG_INFO(Service, "New socket fd={}", fd);
454
455 descriptor.socket = std::make_unique<Network::Socket>();
456 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol));
457 descriptor.is_connection_based = IsConnectionBased(type);
458
459 return {fd, Errno::SUCCESS};
460}
107 461
462std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
463 s32 nfds, s32 timeout) {
464 if (write_buffer.size() < nfds * sizeof(PollFD)) {
465 return {-1, Errno::INVAL};
466 }
467
468 if (nfds == 0) {
469 // When no entries are provided, -1 is returned with errno zero
470 return {-1, Errno::SUCCESS};
471 }
472
473 const size_t length = std::min(read_buffer.size(), write_buffer.size());
474 std::vector<PollFD> fds(nfds);
475 std::memcpy(fds.data(), read_buffer.data(), length);
476
477 if (timeout >= 0) {
478 const s64 seconds = timeout / 1000;
479 const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
480
481 if (seconds < 0) {
482 return {-1, Errno::INVAL};
483 }
484 if (nanoseconds > 999'999'999) {
485 return {-1, Errno::INVAL};
486 }
487 } else if (timeout != -1) {
488 return {-1, Errno::INVAL};
489 }
490
491 for (PollFD& pollfd : fds) {
492 ASSERT(pollfd.revents == 0);
493
494 if (pollfd.fd > MAX_FD || pollfd.fd < 0) {
495 LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
496 pollfd.revents = 0;
497 return {0, Errno::SUCCESS};
498 }
499
500 std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
501 if (!descriptor) {
502 LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd);
503 pollfd.revents = POLL_NVAL;
504 return {0, Errno::SUCCESS};
505 }
506 }
507
508 std::vector<Network::PollFD> host_pollfds(fds.size());
509 std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) {
510 Network::PollFD result;
511 result.socket = file_descriptors[pollfd.fd]->socket.get();
512 result.events = TranslatePollEventsToHost(pollfd.events);
513 result.revents = 0;
514 return result;
515 });
516
517 const auto result = Network::Poll(host_pollfds, timeout);
518
519 const size_t num = host_pollfds.size();
520 for (size_t i = 0; i < num; ++i) {
521 fds[i].revents = TranslatePollEventsToGuest(host_pollfds[i].revents);
522 }
523 std::memcpy(write_buffer.data(), fds.data(), length);
524
525 return Translate(result);
526}
527
528std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
529 if (!IsFileDescriptorValid(fd)) {
530 return {-1, Errno::BADF};
531 }
532
533 const s32 new_fd = FindFreeFileDescriptorHandle();
534 if (new_fd < 0) {
535 LOG_ERROR(Service, "No more file descriptors available");
536 return {-1, Errno::MFILE};
537 }
538
539 FileDescriptor& descriptor = *file_descriptors[fd];
540 auto [result, bsd_errno] = descriptor.socket->Accept();
541 if (bsd_errno != Network::Errno::SUCCESS) {
542 return {-1, Translate(bsd_errno)};
543 }
544
545 FileDescriptor& new_descriptor = file_descriptors[new_fd].emplace();
546 new_descriptor.socket = std::move(result.socket);
547 new_descriptor.is_connection_based = descriptor.is_connection_based;
548
549 ASSERT(write_buffer.size() == sizeof(SockAddrIn));
550 const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
551 std::memcpy(write_buffer.data(), &guest_addr_in, sizeof(guest_addr_in));
552
553 return {new_fd, Errno::SUCCESS};
554}
555
556Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
557 if (!IsFileDescriptorValid(fd)) {
558 return Errno::BADF;
559 }
560 ASSERT(addr.size() == sizeof(SockAddrIn));
561 SockAddrIn addr_in;
562 std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
563
564 return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
565}
566
567Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) {
568 if (!IsFileDescriptorValid(fd)) {
569 return Errno::BADF;
570 }
571
572 UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
573 SockAddrIn addr_in;
574 std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
575
576 return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
577}
578
579Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
580 if (!IsFileDescriptorValid(fd)) {
581 return Errno::BADF;
582 }
583
584 const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
585 if (bsd_errno != Network::Errno::SUCCESS) {
586 return Translate(bsd_errno);
587 }
588 const SockAddrIn guest_addrin = Translate(addr_in);
589
590 ASSERT(write_buffer.size() == sizeof(guest_addrin));
591 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
592 return Translate(bsd_errno);
593}
594
595Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
596 if (!IsFileDescriptorValid(fd)) {
597 return Errno::BADF;
598 }
599
600 const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
601 if (bsd_errno != Network::Errno::SUCCESS) {
602 return Translate(bsd_errno);
603 }
604 const SockAddrIn guest_addrin = Translate(addr_in);
605
606 ASSERT(write_buffer.size() == sizeof(guest_addrin));
607 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
608 return Translate(bsd_errno);
609}
610
611Errno BSD::ListenImpl(s32 fd, s32 backlog) {
612 if (!IsFileDescriptorValid(fd)) {
613 return Errno::BADF;
614 }
615 return Translate(file_descriptors[fd]->socket->Listen(backlog));
616}
617
618std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
619 if (!IsFileDescriptorValid(fd)) {
620 return {-1, Errno::BADF};
621 }
622
623 FileDescriptor& descriptor = *file_descriptors[fd];
624
625 switch (cmd) {
626 case FcntlCmd::GETFL:
627 ASSERT(arg == 0);
628 return {descriptor.flags, Errno::SUCCESS};
629 case FcntlCmd::SETFL: {
630 const bool enable = (arg & FLAG_O_NONBLOCK) != 0;
631 const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
632 if (bsd_errno != Errno::SUCCESS) {
633 return {-1, bsd_errno};
634 }
635 descriptor.flags = arg;
636 return {0, Errno::SUCCESS};
637 }
638 default:
639 UNIMPLEMENTED_MSG("Unimplemented cmd={}", static_cast<int>(cmd));
640 return {-1, Errno::SUCCESS};
641 }
642}
643
644Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
645 UNIMPLEMENTED_IF(level != 0xffff); // SOL_SOCKET
646
647 if (!IsFileDescriptorValid(fd)) {
648 return Errno::BADF;
649 }
650
651 Network::Socket* const socket = file_descriptors[fd]->socket.get();
652
653 if (optname == OptName::LINGER) {
654 ASSERT(optlen == sizeof(Linger));
655 Linger linger;
656 std::memcpy(&linger, optval, sizeof(linger));
657 ASSERT(linger.onoff == 0 || linger.onoff == 1);
658
659 return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
660 }
661
662 ASSERT(optlen == sizeof(u32));
663 u32 value;
664 std::memcpy(&value, optval, sizeof(value));
665
666 switch (optname) {
667 case OptName::REUSEADDR:
668 ASSERT(value == 0 || value == 1);
669 return Translate(socket->SetReuseAddr(value != 0));
670 case OptName::BROADCAST:
671 ASSERT(value == 0 || value == 1);
672 return Translate(socket->SetBroadcast(value != 0));
673 case OptName::SNDBUF:
674 return Translate(socket->SetSndBuf(value));
675 case OptName::RCVBUF:
676 return Translate(socket->SetRcvBuf(value));
677 case OptName::SNDTIMEO:
678 return Translate(socket->SetSndTimeo(value));
679 case OptName::RCVTIMEO:
680 return Translate(socket->SetRcvTimeo(value));
681 default:
682 UNIMPLEMENTED_MSG("Unimplemented optname={}", static_cast<int>(optname));
683 return Errno::SUCCESS;
684 }
685}
686
687Errno BSD::ShutdownImpl(s32 fd, s32 how) {
688 if (!IsFileDescriptorValid(fd)) {
689 return Errno::BADF;
690 }
691 const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
692 return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
693}
694
695std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
696 if (!IsFileDescriptorValid(fd)) {
697 return {-1, Errno::BADF};
698 }
699 return Translate(file_descriptors[fd]->socket->Recv(flags, message));
700}
701
702std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
703 std::vector<u8>& addr) {
704 if (!IsFileDescriptorValid(fd)) {
705 return {-1, Errno::BADF};
706 }
707
708 FileDescriptor& descriptor = *file_descriptors[fd];
709
710 Network::SockAddrIn addr_in{};
711 Network::SockAddrIn* p_addr_in = nullptr;
712 if (descriptor.is_connection_based) {
713 // Connection based file descriptors (e.g. TCP) zero addr
714 addr.clear();
715 } else {
716 p_addr_in = &addr_in;
717 }
718
719 // Apply flags
720 if ((flags & FLAG_MSG_DONTWAIT) != 0) {
721 flags &= ~FLAG_MSG_DONTWAIT;
722 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
723 descriptor.socket->SetNonBlock(true);
724 }
725 }
726
727 const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
728
729 // Restore original state
730 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
731 descriptor.socket->SetNonBlock(false);
732 }
733
734 if (p_addr_in) {
735 if (ret < 0) {
736 addr.clear();
737 } else {
738 ASSERT(addr.size() == sizeof(SockAddrIn));
739 const SockAddrIn result = Translate(addr_in);
740 std::memcpy(addr.data(), &result, sizeof(result));
741 }
742 }
743
744 return {ret, bsd_errno};
745}
746
747std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) {
748 if (!IsFileDescriptorValid(fd)) {
749 return {-1, Errno::BADF};
750 }
751 return Translate(file_descriptors[fd]->socket->Send(message, flags));
752}
753
754std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
755 const std::vector<u8>& addr) {
756 if (!IsFileDescriptorValid(fd)) {
757 return {-1, Errno::BADF};
758 }
759
760 Network::SockAddrIn addr_in;
761 Network::SockAddrIn* p_addr_in = nullptr;
762 if (!addr.empty()) {
763 ASSERT(addr.size() == sizeof(SockAddrIn));
764 SockAddrIn guest_addr_in;
765 std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in));
766 addr_in = Translate(guest_addr_in);
767 }
768
769 return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
770}
771
772Errno BSD::CloseImpl(s32 fd) {
773 if (!IsFileDescriptorValid(fd)) {
774 return Errno::BADF;
775 }
776
777 const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
778 if (bsd_errno != Errno::SUCCESS) {
779 return bsd_errno;
780 }
781
782 LOG_INFO(Service, "Close socket fd={}", fd);
783
784 file_descriptors[fd].reset();
785 return bsd_errno;
786}
787
788s32 BSD::FindFreeFileDescriptorHandle() noexcept {
789 for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
790 if (!file_descriptors[fd]) {
791 return fd;
792 }
793 }
794 return -1;
795}
796
797bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
798 if (fd > MAX_FD || fd < 0) {
799 LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
800 return false;
801 }
802 if (!file_descriptors[fd]) {
803 LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
804 return false;
805 }
806 return true;
807}
808
809bool BSD::IsBlockingSocket(s32 fd) const noexcept {
810 // Inform invalid sockets as non-blocking
811 // This way we avoid using a worker thread as it will fail without blocking host
812 if (fd > MAX_FD || fd < 0) {
813 return false;
814 }
815 if (!file_descriptors[fd]) {
816 return false;
817 }
818 return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0;
819}
820
821void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept {
108 IPC::ResponseBuilder rb{ctx, 4}; 822 IPC::ResponseBuilder rb{ctx, 4};
109 823
110 rb.Push(RESULT_SUCCESS); 824 rb.Push(RESULT_SUCCESS);
111 rb.Push<u32>(0); // ret 825 rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
112 rb.Push<u32>(0); // bsd errno 826 rb.PushEnum(bsd_errno);
113} 827}
114 828
115BSD::BSD(const char* name) : ServiceFramework(name) { 829BSD::BSD(Core::System& system, const char* name)
830 : ServiceFramework(name), worker_pool{system, this} {
116 // clang-format off 831 // clang-format off
117 static const FunctionInfo functions[] = { 832 static const FunctionInfo functions[] = {
118 {0, &BSD::RegisterClient, "RegisterClient"}, 833 {0, &BSD::RegisterClient, "RegisterClient"},
@@ -121,25 +836,25 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
121 {3, nullptr, "SocketExempt"}, 836 {3, nullptr, "SocketExempt"},
122 {4, nullptr, "Open"}, 837 {4, nullptr, "Open"},
123 {5, &BSD::Select, "Select"}, 838 {5, &BSD::Select, "Select"},
124 {6, nullptr, "Poll"}, 839 {6, &BSD::Poll, "Poll"},
125 {7, nullptr, "Sysctl"}, 840 {7, nullptr, "Sysctl"},
126 {8, nullptr, "Recv"}, 841 {8, &BSD::Recv, "Recv"},
127 {9, nullptr, "RecvFrom"}, 842 {9, &BSD::RecvFrom, "RecvFrom"},
128 {10, nullptr, "Send"}, 843 {10, &BSD::Send, "Send"},
129 {11, &BSD::SendTo, "SendTo"}, 844 {11, &BSD::SendTo, "SendTo"},
130 {12, nullptr, "Accept"}, 845 {12, &BSD::Accept, "Accept"},
131 {13, &BSD::Bind, "Bind"}, 846 {13, &BSD::Bind, "Bind"},
132 {14, &BSD::Connect, "Connect"}, 847 {14, &BSD::Connect, "Connect"},
133 {15, nullptr, "GetPeerName"}, 848 {15, &BSD::GetPeerName, "GetPeerName"},
134 {16, nullptr, "GetSockName"}, 849 {16, &BSD::GetSockName, "GetSockName"},
135 {17, nullptr, "GetSockOpt"}, 850 {17, nullptr, "GetSockOpt"},
136 {18, &BSD::Listen, "Listen"}, 851 {18, &BSD::Listen, "Listen"},
137 {19, nullptr, "Ioctl"}, 852 {19, nullptr, "Ioctl"},
138 {20, nullptr, "Fcntl"}, 853 {20, &BSD::Fcntl, "Fcntl"},
139 {21, &BSD::SetSockOpt, "SetSockOpt"}, 854 {21, &BSD::SetSockOpt, "SetSockOpt"},
140 {22, nullptr, "Shutdown"}, 855 {22, &BSD::Shutdown, "Shutdown"},
141 {23, nullptr, "ShutdownAllSockets"}, 856 {23, nullptr, "ShutdownAllSockets"},
142 {24, nullptr, "Write"}, 857 {24, &BSD::Write, "Write"},
143 {25, nullptr, "Read"}, 858 {25, nullptr, "Read"},
144 {26, &BSD::Close, "Close"}, 859 {26, &BSD::Close, "Close"},
145 {27, nullptr, "DuplicateSocket"}, 860 {27, nullptr, "DuplicateSocket"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 3098e3baf..357531951 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -4,30 +4,174 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string_view>
9#include <vector>
10
11#include "common/common_types.h"
7#include "core/hle/kernel/hle_ipc.h" 12#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
14#include "core/hle/service/sockets/blocking_worker.h"
15#include "core/hle/service/sockets/sockets.h"
16
17namespace Core {
18class System;
19}
20
21namespace Network {
22class Socket;
23}
9 24
10namespace Service::Sockets { 25namespace Service::Sockets {
11 26
12class BSD final : public ServiceFramework<BSD> { 27class BSD final : public ServiceFramework<BSD> {
13public: 28public:
14 explicit BSD(const char* name); 29 explicit BSD(Core::System& system, const char* name);
15 ~BSD() override; 30 ~BSD() override;
16 31
17private: 32private:
33 /// Maximum number of file descriptors
34 static constexpr size_t MAX_FD = 128;
35
36 struct FileDescriptor {
37 std::unique_ptr<Network::Socket> socket;
38 s32 flags = 0;
39 bool is_connection_based = false;
40 };
41
42 struct PollWork {
43 void Execute(BSD* bsd);
44 void Response(Kernel::HLERequestContext& ctx);
45
46 s32 nfds;
47 s32 timeout;
48 std::vector<u8> read_buffer;
49 std::vector<u8> write_buffer;
50 s32 ret{};
51 Errno bsd_errno{};
52 };
53
54 struct AcceptWork {
55 void Execute(BSD* bsd);
56 void Response(Kernel::HLERequestContext& ctx);
57
58 s32 fd;
59 std::vector<u8> write_buffer;
60 s32 ret{};
61 Errno bsd_errno{};
62 };
63
64 struct ConnectWork {
65 void Execute(BSD* bsd);
66 void Response(Kernel::HLERequestContext& ctx);
67
68 s32 fd;
69 std::vector<u8> addr;
70 Errno bsd_errno{};
71 };
72
73 struct RecvWork {
74 void Execute(BSD* bsd);
75 void Response(Kernel::HLERequestContext& ctx);
76
77 s32 fd;
78 u32 flags;
79 std::vector<u8> message;
80 s32 ret{};
81 Errno bsd_errno{};
82 };
83
84 struct RecvFromWork {
85 void Execute(BSD* bsd);
86 void Response(Kernel::HLERequestContext& ctx);
87
88 s32 fd;
89 u32 flags;
90 std::vector<u8> message;
91 std::vector<u8> addr;
92 s32 ret{};
93 Errno bsd_errno{};
94 };
95
96 struct SendWork {
97 void Execute(BSD* bsd);
98 void Response(Kernel::HLERequestContext& ctx);
99
100 s32 fd;
101 u32 flags;
102 std::vector<u8> message;
103 s32 ret{};
104 Errno bsd_errno{};
105 };
106
107 struct SendToWork {
108 void Execute(BSD* bsd);
109 void Response(Kernel::HLERequestContext& ctx);
110
111 s32 fd;
112 u32 flags;
113 std::vector<u8> message;
114 std::vector<u8> addr;
115 s32 ret{};
116 Errno bsd_errno{};
117 };
118
18 void RegisterClient(Kernel::HLERequestContext& ctx); 119 void RegisterClient(Kernel::HLERequestContext& ctx);
19 void StartMonitoring(Kernel::HLERequestContext& ctx); 120 void StartMonitoring(Kernel::HLERequestContext& ctx);
20 void Socket(Kernel::HLERequestContext& ctx); 121 void Socket(Kernel::HLERequestContext& ctx);
21 void Select(Kernel::HLERequestContext& ctx); 122 void Select(Kernel::HLERequestContext& ctx);
123 void Poll(Kernel::HLERequestContext& ctx);
124 void Accept(Kernel::HLERequestContext& ctx);
22 void Bind(Kernel::HLERequestContext& ctx); 125 void Bind(Kernel::HLERequestContext& ctx);
23 void Connect(Kernel::HLERequestContext& ctx); 126 void Connect(Kernel::HLERequestContext& ctx);
127 void GetPeerName(Kernel::HLERequestContext& ctx);
128 void GetSockName(Kernel::HLERequestContext& ctx);
24 void Listen(Kernel::HLERequestContext& ctx); 129 void Listen(Kernel::HLERequestContext& ctx);
130 void Fcntl(Kernel::HLERequestContext& ctx);
25 void SetSockOpt(Kernel::HLERequestContext& ctx); 131 void SetSockOpt(Kernel::HLERequestContext& ctx);
132 void Shutdown(Kernel::HLERequestContext& ctx);
133 void Recv(Kernel::HLERequestContext& ctx);
134 void RecvFrom(Kernel::HLERequestContext& ctx);
135 void Send(Kernel::HLERequestContext& ctx);
26 void SendTo(Kernel::HLERequestContext& ctx); 136 void SendTo(Kernel::HLERequestContext& ctx);
137 void Write(Kernel::HLERequestContext& ctx);
27 void Close(Kernel::HLERequestContext& ctx); 138 void Close(Kernel::HLERequestContext& ctx);
28 139
29 /// Id to use for the next open file descriptor. 140 template <typename Work>
30 u32 next_fd = 1; 141 void ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason,
142 bool is_blocking, Work work);
143
144 std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
145 std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
146 s32 nfds, s32 timeout);
147 std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
148 Errno BindImpl(s32 fd, const std::vector<u8>& addr);
149 Errno ConnectImpl(s32 fd, const std::vector<u8>& addr);
150 Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
151 Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
152 Errno ListenImpl(s32 fd, s32 backlog);
153 std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
154 Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval);
155 Errno ShutdownImpl(s32 fd, s32 how);
156 std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
157 std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
158 std::vector<u8>& addr);
159 std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message);
160 std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
161 const std::vector<u8>& addr);
162 Errno CloseImpl(s32 fd);
163
164 s32 FindFreeFileDescriptorHandle() noexcept;
165 bool IsFileDescriptorValid(s32 fd) const noexcept;
166 bool IsBlockingSocket(s32 fd) const noexcept;
167
168 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
169
170 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
171
172 BlockingWorkerPool<BSD, PollWork, AcceptWork, ConnectWork, RecvWork, RecvFromWork, SendWork,
173 SendToWork>
174 worker_pool;
31}; 175};
32 176
33class BSDCFG final : public ServiceFramework<BSDCFG> { 177class BSDCFG final : public ServiceFramework<BSDCFG> {
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp
index 08d2d306a..1d27f7906 100644
--- a/src/core/hle/service/sockets/sockets.cpp
+++ b/src/core/hle/service/sockets/sockets.cpp
@@ -10,9 +10,9 @@
10 10
11namespace Service::Sockets { 11namespace Service::Sockets {
12 12
13void InstallInterfaces(SM::ServiceManager& service_manager) { 13void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
14 std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager); 14 std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager);
15 std::make_shared<BSD>("bsd:u")->InstallAsService(service_manager); 15 std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager);
16 std::make_shared<BSDCFG>()->InstallAsService(service_manager); 16 std::make_shared<BSDCFG>()->InstallAsService(service_manager);
17 17
18 std::make_shared<ETHC_C>()->InstallAsService(service_manager); 18 std::make_shared<ETHC_C>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index ca8a6a7e0..89a410076 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -4,11 +4,94 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
10namespace Core {
11class System;
12}
13
9namespace Service::Sockets { 14namespace Service::Sockets {
10 15
16enum class Errno : u32 {
17 SUCCESS = 0,
18 BADF = 9,
19 AGAIN = 11,
20 INVAL = 22,
21 MFILE = 24,
22 NOTCONN = 107,
23};
24
25enum class Domain : u32 {
26 INET = 2,
27};
28
29enum class Type : u32 {
30 STREAM = 1,
31 DGRAM = 2,
32 RAW = 3,
33 SEQPACKET = 5,
34};
35
36enum class Protocol : u32 {
37 UNSPECIFIED = 0,
38 ICMP = 1,
39 TCP = 6,
40 UDP = 17,
41};
42
43enum class OptName : u32 {
44 REUSEADDR = 0x4,
45 BROADCAST = 0x20,
46 LINGER = 0x80,
47 SNDBUF = 0x1001,
48 RCVBUF = 0x1002,
49 SNDTIMEO = 0x1005,
50 RCVTIMEO = 0x1006,
51};
52
53enum class ShutdownHow : s32 {
54 RD = 0,
55 WR = 1,
56 RDWR = 2,
57};
58
59enum class FcntlCmd : s32 {
60 GETFL = 3,
61 SETFL = 4,
62};
63
64struct SockAddrIn {
65 u8 len;
66 u8 family;
67 u16 portno;
68 std::array<u8, 4> ip;
69 std::array<u8, 8> zeroes;
70};
71
72struct PollFD {
73 s32 fd;
74 u16 events;
75 u16 revents;
76};
77
78struct Linger {
79 u32 onoff;
80 u32 linger;
81};
82
83constexpr u16 POLL_IN = 0x01;
84constexpr u16 POLL_PRI = 0x02;
85constexpr u16 POLL_OUT = 0x04;
86constexpr u16 POLL_ERR = 0x08;
87constexpr u16 POLL_HUP = 0x10;
88constexpr u16 POLL_NVAL = 0x20;
89
90constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
91
92constexpr u32 FLAG_O_NONBLOCK = 0x800;
93
11/// Registers all Sockets services with the specified service manager. 94/// Registers all Sockets services with the specified service manager.
12void InstallInterfaces(SM::ServiceManager& service_manager); 95void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
13 96
14} // namespace Service::Sockets 97} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
new file mode 100644
index 000000000..2be8f642d
--- /dev/null
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -0,0 +1,165 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <utility>
6
7#include "common/assert.h"
8#include "common/common_types.h"
9#include "core/hle/service/sockets/sockets.h"
10#include "core/hle/service/sockets/sockets_translate.h"
11#include "core/network/network.h"
12
13namespace Service::Sockets {
14
15Errno Translate(Network::Errno value) {
16 switch (value) {
17 case Network::Errno::SUCCESS:
18 return Errno::SUCCESS;
19 case Network::Errno::BADF:
20 return Errno::BADF;
21 case Network::Errno::AGAIN:
22 return Errno::AGAIN;
23 case Network::Errno::INVAL:
24 return Errno::INVAL;
25 case Network::Errno::MFILE:
26 return Errno::MFILE;
27 case Network::Errno::NOTCONN:
28 return Errno::NOTCONN;
29 default:
30 UNIMPLEMENTED_MSG("Unimplemented errno={}", static_cast<int>(value));
31 return Errno::SUCCESS;
32 }
33}
34
35std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
36 return {value.first, Translate(value.second)};
37}
38
39Network::Domain Translate(Domain domain) {
40 switch (domain) {
41 case Domain::INET:
42 return Network::Domain::INET;
43 default:
44 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
45 return {};
46 }
47}
48
49Domain Translate(Network::Domain domain) {
50 switch (domain) {
51 case Network::Domain::INET:
52 return Domain::INET;
53 default:
54 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
55 return {};
56 }
57}
58
59Network::Type Translate(Type type) {
60 switch (type) {
61 case Type::STREAM:
62 return Network::Type::STREAM;
63 case Type::DGRAM:
64 return Network::Type::DGRAM;
65 default:
66 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
67 }
68}
69
70Network::Protocol Translate(Type type, Protocol protocol) {
71 switch (protocol) {
72 case Protocol::UNSPECIFIED:
73 LOG_WARNING(Service, "Unspecified protocol, assuming protocol from type");
74 switch (type) {
75 case Type::DGRAM:
76 return Network::Protocol::UDP;
77 case Type::STREAM:
78 return Network::Protocol::TCP;
79 default:
80 return Network::Protocol::TCP;
81 }
82 case Protocol::TCP:
83 return Network::Protocol::TCP;
84 case Protocol::UDP:
85 return Network::Protocol::UDP;
86 default:
87 UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol));
88 return Network::Protocol::TCP;
89 }
90}
91
92u16 TranslatePollEventsToHost(u16 flags) {
93 u16 result = 0;
94 const auto translate = [&result, &flags](u16 from, u16 to) {
95 if ((flags & from) != 0) {
96 flags &= ~from;
97 result |= to;
98 }
99 };
100 translate(POLL_IN, Network::POLL_IN);
101 translate(POLL_PRI, Network::POLL_PRI);
102 translate(POLL_OUT, Network::POLL_OUT);
103 translate(POLL_ERR, Network::POLL_ERR);
104 translate(POLL_HUP, Network::POLL_HUP);
105 translate(POLL_NVAL, Network::POLL_NVAL);
106
107 UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags);
108 return result;
109}
110
111u16 TranslatePollEventsToGuest(u16 flags) {
112 u16 result = 0;
113 const auto translate = [&result, &flags](u16 from, u16 to) {
114 if ((flags & from) != 0) {
115 flags &= ~from;
116 result |= to;
117 }
118 };
119
120 translate(Network::POLL_IN, POLL_IN);
121 translate(Network::POLL_PRI, POLL_PRI);
122 translate(Network::POLL_OUT, POLL_OUT);
123 translate(Network::POLL_ERR, POLL_ERR);
124 translate(Network::POLL_HUP, POLL_HUP);
125 translate(Network::POLL_NVAL, POLL_NVAL);
126
127 UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags);
128 return result;
129}
130
131Network::SockAddrIn Translate(SockAddrIn value) {
132 ASSERT(value.len == 0 || value.len == sizeof(value));
133
134 Network::SockAddrIn result;
135 result.family = Translate(static_cast<Domain>(value.family));
136 result.ip = value.ip;
137 result.portno = value.portno >> 8 | value.portno << 8;
138 return result;
139}
140
141SockAddrIn Translate(Network::SockAddrIn value) {
142 SockAddrIn result;
143 result.len = sizeof(result);
144 result.family = static_cast<u8>(Translate(value.family));
145 result.portno = value.portno >> 8 | value.portno << 8;
146 result.ip = value.ip;
147 result.zeroes = {};
148 return result;
149}
150
151Network::ShutdownHow Translate(ShutdownHow how) {
152 switch (how) {
153 case ShutdownHow::RD:
154 return Network::ShutdownHow::RD;
155 case ShutdownHow::WR:
156 return Network::ShutdownHow::WR;
157 case ShutdownHow::RDWR:
158 return Network::ShutdownHow::RDWR;
159 default:
160 UNIMPLEMENTED_MSG("Unimplemented how={}", static_cast<int>(how));
161 return {};
162 }
163}
164
165} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h
new file mode 100644
index 000000000..8ed041e31
--- /dev/null
+++ b/src/core/hle/service/sockets/sockets_translate.h
@@ -0,0 +1,48 @@
1// Copyright 2020 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 <utility>
8
9#include "common/common_types.h"
10#include "core/hle/service/sockets/sockets.h"
11#include "core/network/network.h"
12
13namespace Service::Sockets {
14
15/// Translate abstract errno to guest errno
16Errno Translate(Network::Errno value);
17
18/// Translate abstract return value errno pair to guest return value errno pair
19std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
20
21/// Translate guest domain to abstract domain
22Network::Domain Translate(Domain domain);
23
24/// Translate abstract domain to guest domain
25Domain Translate(Network::Domain domain);
26
27/// Translate guest type to abstract type
28Network::Type Translate(Type type);
29
30/// Translate guest protocol to abstract protocol
31Network::Protocol Translate(Type type, Protocol protocol);
32
33/// Translate abstract poll event flags to guest poll event flags
34u16 TranslatePollEventsToHost(u16 flags);
35
36/// Translate guest poll event flags to abstract poll event flags
37u16 TranslatePollEventsToGuest(u16 flags);
38
39/// Translate guest socket address structure to abstract socket address structure
40Network::SockAddrIn Translate(SockAddrIn value);
41
42/// Translate abstract socket address structure to guest socket address structure
43SockAddrIn Translate(Network::SockAddrIn value);
44
45/// Translate guest shutdown mode to abstract shutdown mode
46Network::ShutdownHow Translate(ShutdownHow how);
47
48} // namespace Service::Sockets
diff --git a/src/core/settings.h b/src/core/settings.h
index 732c6a894..80f0d95a7 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -67,6 +67,11 @@ private:
67 Type local{}; 67 Type local{};
68}; 68};
69 69
70struct TouchFromButtonMap {
71 std::string name;
72 std::vector<std::string> buttons;
73};
74
70struct Values { 75struct Values {
71 // Audio 76 // Audio
72 std::string audio_device_id; 77 std::string audio_device_id;
@@ -145,15 +150,18 @@ struct Values {
145 ButtonsRaw debug_pad_buttons; 150 ButtonsRaw debug_pad_buttons;
146 AnalogsRaw debug_pad_analogs; 151 AnalogsRaw debug_pad_analogs;
147 152
148 std::string motion_device;
149
150 bool vibration_enabled; 153 bool vibration_enabled;
151 154
155 std::string motion_device;
156 std::string touch_device;
152 TouchscreenInput touchscreen; 157 TouchscreenInput touchscreen;
153 std::atomic_bool is_device_reload_pending{true}; 158 std::atomic_bool is_device_reload_pending{true};
159 bool use_touch_from_button;
160 int touch_from_button_map_index;
154 std::string udp_input_address; 161 std::string udp_input_address;
155 u16 udp_input_port; 162 u16 udp_input_port;
156 u8 udp_pad_index; 163 u8 udp_pad_index;
164 std::vector<TouchFromButtonMap> touch_from_button_maps;
157 165
158 // Data Storage 166 // Data Storage
159 bool use_virtual_sd; 167 bool use_virtual_sd;
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 56267c8a8..09361e37e 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -7,8 +7,12 @@ add_library(input_common STATIC
7 main.h 7 main.h
8 motion_emu.cpp 8 motion_emu.cpp
9 motion_emu.h 9 motion_emu.h
10 motion_input.cpp
11 motion_input.h
10 settings.cpp 12 settings.cpp
11 settings.h 13 settings.h
14 touch_from_button.cpp
15 touch_from_button.h
12 gcadapter/gc_adapter.cpp 16 gcadapter/gc_adapter.cpp
13 gcadapter/gc_adapter.h 17 gcadapter/gc_adapter.h
14 gcadapter/gc_poller.cpp 18 gcadapter/gc_poller.cpp
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index 74759ea7d..c6c423c4b 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -283,7 +283,7 @@ void Adapter::Reset() {
283 } 283 }
284} 284}
285 285
286bool Adapter::DeviceConnected(std::size_t port) { 286bool Adapter::DeviceConnected(std::size_t port) const {
287 return adapter_controllers_status[port] != ControllerTypes::None; 287 return adapter_controllers_status[port] != ControllerTypes::None;
288} 288}
289 289
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index bed81915c..20e97d283 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -76,7 +76,7 @@ public:
76 void EndConfiguration(); 76 void EndConfiguration();
77 77
78 /// Returns true if there is a device connected to port 78 /// Returns true if there is a device connected to port
79 bool DeviceConnected(std::size_t port); 79 bool DeviceConnected(std::size_t port) const;
80 80
81 std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); 81 std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
82 const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; 82 const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index 71cd85eeb..92e9e8e89 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -15,7 +15,7 @@ namespace InputCommon {
15 15
16class GCButton final : public Input::ButtonDevice { 16class GCButton final : public Input::ButtonDevice {
17public: 17public:
18 explicit GCButton(int port_, int button_, GCAdapter::Adapter* adapter) 18 explicit GCButton(int port_, int button_, const GCAdapter::Adapter* adapter)
19 : port(port_), button(button_), gcadapter(adapter) {} 19 : port(port_), button(button_), gcadapter(adapter) {}
20 20
21 ~GCButton() override; 21 ~GCButton() override;
@@ -30,15 +30,16 @@ public:
30private: 30private:
31 const int port; 31 const int port;
32 const int button; 32 const int button;
33 GCAdapter::Adapter* gcadapter; 33 const GCAdapter::Adapter* gcadapter;
34}; 34};
35 35
36class GCAxisButton final : public Input::ButtonDevice { 36class GCAxisButton final : public Input::ButtonDevice {
37public: 37public:
38 explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, 38 explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_,
39 GCAdapter::Adapter* adapter) 39 const GCAdapter::Adapter* adapter)
40 : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), 40 : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_),
41 gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} 41 gcadapter(adapter),
42 origin_value(static_cast<float>(adapter->GetOriginValue(port_, axis_))) {}
42 43
43 bool GetStatus() const override { 44 bool GetStatus() const override {
44 if (gcadapter->DeviceConnected(port)) { 45 if (gcadapter->DeviceConnected(port)) {
@@ -59,7 +60,7 @@ private:
59 const int axis; 60 const int axis;
60 float threshold; 61 float threshold;
61 bool trigger_if_greater; 62 bool trigger_if_greater;
62 GCAdapter::Adapter* gcadapter; 63 const GCAdapter::Adapter* gcadapter;
63 const float origin_value; 64 const float origin_value;
64}; 65};
65 66
@@ -148,11 +149,12 @@ void GCButtonFactory::EndConfiguration() {
148 149
149class GCAnalog final : public Input::AnalogDevice { 150class GCAnalog final : public Input::AnalogDevice {
150public: 151public:
151 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter, 152 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_,
152 float range_) 153 const GCAdapter::Adapter* adapter, float range_)
153 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), 154 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
154 origin_value_x(adapter->GetOriginValue(port_, axis_x_)), 155 origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))),
155 origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {} 156 origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))),
157 range(range_) {}
156 158
157 float GetAxis(int axis) const { 159 float GetAxis(int axis) const {
158 if (gcadapter->DeviceConnected(port)) { 160 if (gcadapter->DeviceConnected(port)) {
@@ -210,7 +212,7 @@ private:
210 const int axis_x; 212 const int axis_x;
211 const int axis_y; 213 const int axis_y;
212 const float deadzone; 214 const float deadzone;
213 GCAdapter::Adapter* gcadapter; 215 const GCAdapter::Adapter* gcadapter;
214 const float origin_value_x; 216 const float origin_value_x;
215 const float origin_value_y; 217 const float origin_value_y;
216 const float range; 218 const float range;
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 57e7a25fe..ea1a1cee6 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -11,6 +11,7 @@
11#include "input_common/keyboard.h" 11#include "input_common/keyboard.h"
12#include "input_common/main.h" 12#include "input_common/main.h"
13#include "input_common/motion_emu.h" 13#include "input_common/motion_emu.h"
14#include "input_common/touch_from_button.h"
14#include "input_common/udp/udp.h" 15#include "input_common/udp/udp.h"
15#ifdef HAVE_SDL2 16#ifdef HAVE_SDL2
16#include "input_common/sdl/sdl.h" 17#include "input_common/sdl/sdl.h"
@@ -32,6 +33,8 @@ struct InputSubsystem::Impl {
32 std::make_shared<AnalogFromButton>()); 33 std::make_shared<AnalogFromButton>());
33 motion_emu = std::make_shared<MotionEmu>(); 34 motion_emu = std::make_shared<MotionEmu>();
34 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); 35 Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
36 Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
37 std::make_shared<TouchFromButtonFactory>());
35 38
36#ifdef HAVE_SDL2 39#ifdef HAVE_SDL2
37 sdl = SDL::Init(); 40 sdl = SDL::Init();
@@ -46,6 +49,7 @@ struct InputSubsystem::Impl {
46 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); 49 Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
47 Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); 50 Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
48 motion_emu.reset(); 51 motion_emu.reset();
52 Input::UnregisterFactory<Input::TouchDevice>("touch_from_button");
49#ifdef HAVE_SDL2 53#ifdef HAVE_SDL2
50 sdl.reset(); 54 sdl.reset();
51#endif 55#endif
@@ -171,6 +175,13 @@ const GCButtonFactory* InputSubsystem::GetGCButtons() const {
171 return impl->gcbuttons.get(); 175 return impl->gcbuttons.get();
172} 176}
173 177
178void InputSubsystem::ReloadInputDevices() {
179 if (!impl->udp) {
180 return;
181 }
182 impl->udp->ReloadUDPClient();
183}
184
174std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers( 185std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
175 Polling::DeviceType type) const { 186 Polling::DeviceType type) const {
176#ifdef HAVE_SDL2 187#ifdef HAVE_SDL2
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 58e5dc250..f3fbf696e 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -115,6 +115,9 @@ public:
115 /// Retrieves the underlying GameCube button handler. 115 /// Retrieves the underlying GameCube button handler.
116 [[nodiscard]] const GCButtonFactory* GetGCButtons() const; 116 [[nodiscard]] const GCButtonFactory* GetGCButtons() const;
117 117
118 /// Reloads the input devices
119 void ReloadInputDevices();
120
118 /// Get all DevicePoller from all backends for a specific device type 121 /// Get all DevicePoller from all backends for a specific device type
119 [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers( 122 [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers(
120 Polling::DeviceType type) const; 123 Polling::DeviceType type) const;
diff --git a/src/input_common/motion_input.cpp b/src/input_common/motion_input.cpp
new file mode 100644
index 000000000..22a849866
--- /dev/null
+++ b/src/input_common/motion_input.cpp
@@ -0,0 +1,181 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included
4
5#include "common/math_util.h"
6#include "input_common/motion_input.h"
7
8namespace InputCommon {
9
10MotionInput::MotionInput(f32 new_kp, f32 new_ki, f32 new_kd)
11 : kp(new_kp), ki(new_ki), kd(new_kd), quat{{0, 0, -1}, 0} {}
12
13void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
14 accel = acceleration;
15}
16
17void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
18 gyro = gyroscope - gyro_drift;
19 if (gyro.Length2() < gyro_threshold) {
20 gyro = {};
21 }
22}
23
24void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
25 quat = quaternion;
26}
27
28void MotionInput::SetGyroDrift(const Common::Vec3f& drift) {
29 gyro_drift = drift;
30}
31
32void MotionInput::SetGyroThreshold(f32 threshold) {
33 gyro_threshold = threshold;
34}
35
36void MotionInput::EnableReset(bool reset) {
37 reset_enabled = reset;
38}
39
40void MotionInput::ResetRotations() {
41 rotations = {};
42}
43
44bool MotionInput::IsMoving(f32 sensitivity) const {
45 return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f;
46}
47
48bool MotionInput::IsCalibrated(f32 sensitivity) const {
49 return real_error.Length() < sensitivity;
50}
51
52void MotionInput::UpdateRotation(u64 elapsed_time) {
53 const f32 sample_period = elapsed_time / 1000000.0f;
54 if (sample_period > 0.1f) {
55 return;
56 }
57 rotations += gyro * sample_period;
58}
59
60void MotionInput::UpdateOrientation(u64 elapsed_time) {
61 if (!IsCalibrated(0.1f)) {
62 ResetOrientation();
63 }
64 // Short name local variable for readability
65 f32 q1 = quat.w;
66 f32 q2 = quat.xyz[0];
67 f32 q3 = quat.xyz[1];
68 f32 q4 = quat.xyz[2];
69 const f32 sample_period = elapsed_time / 1000000.0f;
70
71 // ignore invalid elapsed time
72 if (sample_period > 0.1f) {
73 return;
74 }
75
76 const auto normal_accel = accel.Normalized();
77 auto rad_gyro = gyro * Common::PI * 2;
78 const f32 swap = rad_gyro.x;
79 rad_gyro.x = rad_gyro.y;
80 rad_gyro.y = -swap;
81 rad_gyro.z = -rad_gyro.z;
82
83 // Ignore drift correction if acceleration is not reliable
84 if (accel.Length() >= 0.75f && accel.Length() <= 1.25f) {
85 const f32 ax = -normal_accel.x;
86 const f32 ay = normal_accel.y;
87 const f32 az = -normal_accel.z;
88
89 // Estimated direction of gravity
90 const f32 vx = 2.0f * (q2 * q4 - q1 * q3);
91 const f32 vy = 2.0f * (q1 * q2 + q3 * q4);
92 const f32 vz = q1 * q1 - q2 * q2 - q3 * q3 + q4 * q4;
93
94 // Error is cross product between estimated direction and measured direction of gravity
95 const Common::Vec3f new_real_error = {az * vx - ax * vz, ay * vz - az * vy,
96 ax * vy - ay * vx};
97
98 derivative_error = new_real_error - real_error;
99 real_error = new_real_error;
100
101 // Prevent integral windup
102 if (ki != 0.0f && !IsCalibrated(0.05f)) {
103 integral_error += real_error;
104 } else {
105 integral_error = {};
106 }
107
108 // Apply feedback terms
109 rad_gyro += kp * real_error;
110 rad_gyro += ki * integral_error;
111 rad_gyro += kd * derivative_error;
112 }
113
114 const f32 gx = rad_gyro.y;
115 const f32 gy = rad_gyro.x;
116 const f32 gz = rad_gyro.z;
117
118 // Integrate rate of change of quaternion
119 const f32 pa = q2;
120 const f32 pb = q3;
121 const f32 pc = q4;
122 q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * sample_period);
123 q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * sample_period);
124 q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * sample_period);
125 q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * sample_period);
126
127 quat.w = q1;
128 quat.xyz[0] = q2;
129 quat.xyz[1] = q3;
130 quat.xyz[2] = q4;
131 quat = quat.Normalized();
132}
133
134std::array<Common::Vec3f, 3> MotionInput::GetOrientation() const {
135 const Common::Quaternion<float> quad{
136 .xyz = {-quat.xyz[1], -quat.xyz[0], -quat.w},
137 .w = -quat.xyz[2],
138 };
139 const std::array<float, 16> matrix4x4 = quad.ToMatrix();
140
141 return {Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
142 Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
143 Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10])};
144}
145
146Common::Vec3f MotionInput::GetAcceleration() const {
147 return accel;
148}
149
150Common::Vec3f MotionInput::GetGyroscope() const {
151 return gyro;
152}
153
154Common::Quaternion<f32> MotionInput::GetQuaternion() const {
155 return quat;
156}
157
158Common::Vec3f MotionInput::GetRotations() const {
159 return rotations;
160}
161
162void MotionInput::ResetOrientation() {
163 if (!reset_enabled) {
164 return;
165 }
166 if (!IsMoving(0.5f) && accel.z <= -0.9f) {
167 ++reset_counter;
168 if (reset_counter > 900) {
169 // TODO: calculate quaternion from gravity vector
170 quat.w = 0;
171 quat.xyz[0] = 0;
172 quat.xyz[1] = 0;
173 quat.xyz[2] = -1;
174 integral_error = {};
175 reset_counter = 0;
176 }
177 } else {
178 reset_counter = 0;
179 }
180}
181} // namespace InputCommon
diff --git a/src/input_common/motion_input.h b/src/input_common/motion_input.h
new file mode 100644
index 000000000..54b4439d9
--- /dev/null
+++ b/src/input_common/motion_input.h
@@ -0,0 +1,68 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/quaternion.h"
9#include "common/vector_math.h"
10
11namespace InputCommon {
12
13class MotionInput {
14public:
15 MotionInput(f32 new_kp, f32 new_ki, f32 new_kd);
16
17 MotionInput(const MotionInput&) = default;
18 MotionInput& operator=(const MotionInput&) = default;
19
20 MotionInput(MotionInput&&) = default;
21 MotionInput& operator=(MotionInput&&) = default;
22
23 void SetAcceleration(const Common::Vec3f& acceleration);
24 void SetGyroscope(const Common::Vec3f& acceleration);
25 void SetQuaternion(const Common::Quaternion<f32>& quaternion);
26 void SetGyroDrift(const Common::Vec3f& drift);
27 void SetGyroThreshold(f32 threshold);
28
29 void EnableReset(bool reset);
30 void ResetRotations();
31
32 void UpdateRotation(u64 elapsed_time);
33 void UpdateOrientation(u64 elapsed_time);
34
35 std::array<Common::Vec3f, 3> GetOrientation() const;
36 Common::Vec3f GetAcceleration() const;
37 Common::Vec3f GetGyroscope() const;
38 Common::Vec3f GetRotations() const;
39 Common::Quaternion<f32> GetQuaternion() const;
40
41 bool IsMoving(f32 sensitivity) const;
42 bool IsCalibrated(f32 sensitivity) const;
43
44private:
45 void ResetOrientation();
46
47 // PID constants
48 const f32 kp;
49 const f32 ki;
50 const f32 kd;
51
52 // PID errors
53 Common::Vec3f real_error;
54 Common::Vec3f integral_error;
55 Common::Vec3f derivative_error;
56
57 Common::Quaternion<f32> quat;
58 Common::Vec3f rotations;
59 Common::Vec3f accel;
60 Common::Vec3f gyro;
61 Common::Vec3f gyro_drift;
62
63 f32 gyro_threshold = 0.0f;
64 u32 reset_counter = 0;
65 bool reset_enabled = true;
66};
67
68} // namespace InputCommon
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index c8d9eb2bc..a9e676f4b 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.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 <algorithm> 5#include <algorithm>
6#include <array>
6#include <atomic> 7#include <atomic>
7#include <cmath> 8#include <cmath>
8#include <functional> 9#include <functional>
@@ -358,7 +359,7 @@ public:
358 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), 359 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
359 y / r * (r - deadzone) / (1 - deadzone)); 360 y / r * (r - deadzone) / (1 - deadzone));
360 } 361 }
361 return std::make_tuple<float, float>(0.0f, 0.0f); 362 return {};
362 } 363 }
363 364
364 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 365 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
@@ -574,10 +575,10 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
574 575
575namespace { 576namespace {
576Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis, 577Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis,
577 float value = 0.1) { 578 float value = 0.1f) {
578 Common::ParamPackage params({{"engine", "sdl"}}); 579 Common::ParamPackage params({{"engine", "sdl"}});
579 params.Set("port", port); 580 params.Set("port", port);
580 params.Set("guid", guid); 581 params.Set("guid", std::move(guid));
581 params.Set("axis", axis); 582 params.Set("axis", axis);
582 if (value > 0) { 583 if (value > 0) {
583 params.Set("direction", "+"); 584 params.Set("direction", "+");
@@ -592,7 +593,7 @@ Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid
592Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) { 593Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) {
593 Common::ParamPackage params({{"engine", "sdl"}}); 594 Common::ParamPackage params({{"engine", "sdl"}});
594 params.Set("port", port); 595 params.Set("port", port);
595 params.Set("guid", guid); 596 params.Set("guid", std::move(guid));
596 params.Set("button", button); 597 params.Set("button", button);
597 return params; 598 return params;
598} 599}
@@ -601,7 +602,7 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u
601 Common::ParamPackage params({{"engine", "sdl"}}); 602 Common::ParamPackage params({{"engine", "sdl"}});
602 603
603 params.Set("port", port); 604 params.Set("port", port);
604 params.Set("guid", guid); 605 params.Set("guid", std::move(guid));
605 params.Set("hat", hat); 606 params.Set("hat", hat);
606 switch (value) { 607 switch (value) {
607 case SDL_HAT_UP: 608 case SDL_HAT_UP:
@@ -670,55 +671,62 @@ Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& gui
670} // Anonymous namespace 671} // Anonymous namespace
671 672
672ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) { 673ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
673 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
674 // We will add those afterwards
675 // This list also excludes Screenshot since theres not really a mapping for that
676 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerButton>
677 switch_to_sdl_button = {
678 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
679 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
680 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
681 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
682 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
683 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
684 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
685 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
686 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
687 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
688 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
689 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
690 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
691 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
692 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
693 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
694 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
695 };
696 if (!params.Has("guid") || !params.Has("port")) { 674 if (!params.Has("guid") || !params.Has("port")) {
697 return {}; 675 return {};
698 } 676 }
699 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); 677 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
700 auto controller = joystick->GetSDLGameController(); 678 auto* controller = joystick->GetSDLGameController();
701 if (!controller) { 679 if (controller == nullptr) {
702 return {}; 680 return {};
703 } 681 }
704 682
705 ButtonMapping mapping{}; 683 // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
684 // We will add those afterwards
685 // This list also excludes Screenshot since theres not really a mapping for that
686 using ButtonBindings =
687 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
688 static constexpr ButtonBindings switch_to_sdl_button{{
689 {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
690 {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
691 {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
692 {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
693 {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
694 {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
695 {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
696 {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
697 {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
698 {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
699 {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
700 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
701 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
702 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
703 {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
704 {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
705 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
706 }};
707
708 // Add the missing bindings for ZL/ZR
709 using ZBindings =
710 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
711 static constexpr ZBindings switch_to_sdl_axis{{
712 {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
713 {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
714 }};
715
716 ButtonMapping mapping;
717 mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
718
706 for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { 719 for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
707 const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); 720 const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
708 mapping[switch_button] = 721 mapping.insert_or_assign(
709 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding); 722 switch_button,
723 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
710 } 724 }
711
712 // Add the missing bindings for ZL/ZR
713 std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerAxis> switch_to_sdl_axis =
714 {
715 {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
716 {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
717 };
718 for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { 725 for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
719 const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); 726 const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
720 mapping[switch_button] = 727 mapping.insert_or_assign(
721 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding); 728 switch_button,
729 BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
722 } 730 }
723 731
724 return mapping; 732 return mapping;
@@ -729,8 +737,8 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
729 return {}; 737 return {};
730 } 738 }
731 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); 739 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
732 auto controller = joystick->GetSDLGameController(); 740 auto* controller = joystick->GetSDLGameController();
733 if (!controller) { 741 if (controller == nullptr) {
734 return {}; 742 return {};
735 } 743 }
736 744
@@ -739,16 +747,18 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
739 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); 747 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
740 const auto& binding_left_y = 748 const auto& binding_left_y =
741 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); 749 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
742 mapping[Settings::NativeAnalog::LStick] = 750 mapping.insert_or_assign(Settings::NativeAnalog::LStick,
743 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 751 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
744 binding_left_x.value.axis, binding_left_y.value.axis); 752 binding_left_x.value.axis,
753 binding_left_y.value.axis));
745 const auto& binding_right_x = 754 const auto& binding_right_x =
746 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); 755 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
747 const auto& binding_right_y = 756 const auto& binding_right_y =
748 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); 757 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
749 mapping[Settings::NativeAnalog::RStick] = 758 mapping.insert_or_assign(Settings::NativeAnalog::RStick,
750 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 759 BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
751 binding_right_x.value.axis, binding_right_y.value.axis); 760 binding_right_x.value.axis,
761 binding_right_y.value.axis));
752 return mapping; 762 return mapping;
753} 763}
754 764
@@ -784,7 +794,7 @@ public:
784 } 794 }
785 return {}; 795 return {};
786 } 796 }
787 std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) { 797 [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
788 switch (event.type) { 798 switch (event.type) {
789 case SDL_JOYAXISMOTION: 799 case SDL_JOYAXISMOTION:
790 if (std::abs(event.jaxis.value / 32767.0) < 0.5) { 800 if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
@@ -795,7 +805,7 @@ public:
795 case SDL_JOYHATMOTION: 805 case SDL_JOYHATMOTION:
796 return {SDLEventToButtonParamPackage(state, event)}; 806 return {SDLEventToButtonParamPackage(state, event)};
797 } 807 }
798 return {}; 808 return std::nullopt;
799 } 809 }
800}; 810};
801 811
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp
new file mode 100644
index 000000000..98da0ef1a
--- /dev/null
+++ b/src/input_common/touch_from_button.cpp
@@ -0,0 +1,50 @@
1// Copyright 2020 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/frontend/framebuffer_layout.h"
6#include "core/settings.h"
7#include "input_common/touch_from_button.h"
8
9namespace InputCommon {
10
11class TouchFromButtonDevice final : public Input::TouchDevice {
12public:
13 TouchFromButtonDevice() {
14 for (const auto& config_entry :
15 Settings::values.touch_from_button_maps[Settings::values.touch_from_button_map_index]
16 .buttons) {
17 const Common::ParamPackage package{config_entry};
18 map.emplace_back(
19 Input::CreateDevice<Input::ButtonDevice>(config_entry),
20 std::clamp(package.Get("x", 0), 0, static_cast<int>(Layout::ScreenUndocked::Width)),
21 std::clamp(package.Get("y", 0), 0,
22 static_cast<int>(Layout::ScreenUndocked::Height)));
23 }
24 }
25
26 std::tuple<float, float, bool> GetStatus() const override {
27 for (const auto& m : map) {
28 const bool state = std::get<0>(m)->GetStatus();
29 if (state) {
30 const float x = static_cast<float>(std::get<1>(m)) /
31 static_cast<int>(Layout::ScreenUndocked::Width);
32 const float y = static_cast<float>(std::get<2>(m)) /
33 static_cast<int>(Layout::ScreenUndocked::Height);
34 return {x, y, true};
35 }
36 }
37 return {};
38 }
39
40private:
41 // A vector of the mapped button, its x and its y-coordinate
42 std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map;
43};
44
45std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create(
46 const Common::ParamPackage& params) {
47 return std::make_unique<TouchFromButtonDevice>();
48}
49
50} // namespace InputCommon
diff --git a/src/input_common/touch_from_button.h b/src/input_common/touch_from_button.h
new file mode 100644
index 000000000..8b4d1aa96
--- /dev/null
+++ b/src/input_common/touch_from_button.h
@@ -0,0 +1,23 @@
1// Copyright 2020 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include "core/frontend/input.h"
9
10namespace InputCommon {
11
12/**
13 * A touch device factory that takes a list of button devices and combines them into a touch device.
14 */
15class TouchFromButtonFactory final : public Input::Factory<Input::TouchDevice> {
16public:
17 /**
18 * Creates a touch device from a list of button devices
19 */
20 std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
21};
22
23} // namespace InputCommon
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index b5dc68902..e7edd733f 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -51,46 +51,43 @@ public:
51 bool is_written = false, bool use_fast_cbuf = false) { 51 bool is_written = false, bool use_fast_cbuf = false) {
52 std::lock_guard lock{mutex}; 52 std::lock_guard lock{mutex};
53 53
54 auto& memory_manager = system.GPU().MemoryManager(); 54 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
55 const std::optional<VAddr> cpu_addr_opt = memory_manager.GpuToCpuAddress(gpu_addr); 55 if (!cpu_addr) {
56 if (!cpu_addr_opt) {
57 return GetEmptyBuffer(size); 56 return GetEmptyBuffer(size);
58 } 57 }
59 const VAddr cpu_addr = *cpu_addr_opt;
60 58
61 // Cache management is a big overhead, so only cache entries with a given size. 59 // Cache management is a big overhead, so only cache entries with a given size.
62 // TODO: Figure out which size is the best for given games. 60 // TODO: Figure out which size is the best for given games.
63 constexpr std::size_t max_stream_size = 0x800; 61 constexpr std::size_t max_stream_size = 0x800;
64 if (use_fast_cbuf || size < max_stream_size) { 62 if (use_fast_cbuf || size < max_stream_size) {
65 if (!is_written && !IsRegionWritten(cpu_addr, cpu_addr + size - 1)) { 63 if (!is_written && !IsRegionWritten(*cpu_addr, *cpu_addr + size - 1)) {
66 const bool is_granular = memory_manager.IsGranularRange(gpu_addr, size); 64 const bool is_granular = gpu_memory.IsGranularRange(gpu_addr, size);
67 if (use_fast_cbuf) { 65 if (use_fast_cbuf) {
68 u8* dest; 66 u8* dest;
69 if (is_granular) { 67 if (is_granular) {
70 dest = memory_manager.GetPointer(gpu_addr); 68 dest = gpu_memory.GetPointer(gpu_addr);
71 } else { 69 } else {
72 staging_buffer.resize(size); 70 staging_buffer.resize(size);
73 dest = staging_buffer.data(); 71 dest = staging_buffer.data();
74 memory_manager.ReadBlockUnsafe(gpu_addr, dest, size); 72 gpu_memory.ReadBlockUnsafe(gpu_addr, dest, size);
75 } 73 }
76 return ConstBufferUpload(dest, size); 74 return ConstBufferUpload(dest, size);
77 } 75 }
78 if (is_granular) { 76 if (is_granular) {
79 u8* const host_ptr = memory_manager.GetPointer(gpu_addr); 77 u8* const host_ptr = gpu_memory.GetPointer(gpu_addr);
80 return StreamBufferUpload(size, alignment, [host_ptr, size](u8* dest) { 78 return StreamBufferUpload(size, alignment, [host_ptr, size](u8* dest) {
81 std::memcpy(dest, host_ptr, size); 79 std::memcpy(dest, host_ptr, size);
82 }); 80 });
83 } else { 81 } else {
84 return StreamBufferUpload( 82 return StreamBufferUpload(size, alignment, [this, gpu_addr, size](u8* dest) {
85 size, alignment, [&memory_manager, gpu_addr, size](u8* dest) { 83 gpu_memory.ReadBlockUnsafe(gpu_addr, dest, size);
86 memory_manager.ReadBlockUnsafe(gpu_addr, dest, size); 84 });
87 });
88 } 85 }
89 } 86 }
90 } 87 }
91 88
92 Buffer* const block = GetBlock(cpu_addr, size); 89 Buffer* const block = GetBlock(*cpu_addr, size);
93 MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size); 90 MapInterval* const map = MapAddress(block, gpu_addr, *cpu_addr, size);
94 if (!map) { 91 if (!map) {
95 return GetEmptyBuffer(size); 92 return GetEmptyBuffer(size);
96 } 93 }
@@ -106,7 +103,7 @@ public:
106 } 103 }
107 } 104 }
108 105
109 return BufferInfo{block->Handle(), block->Offset(cpu_addr), block->Address()}; 106 return BufferInfo{block->Handle(), block->Offset(*cpu_addr), block->Address()};
110 } 107 }
111 108
112 /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset. 109 /// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
@@ -262,9 +259,11 @@ public:
262 virtual BufferInfo GetEmptyBuffer(std::size_t size) = 0; 259 virtual BufferInfo GetEmptyBuffer(std::size_t size) = 0;
263 260
264protected: 261protected:
265 explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system, 262 explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_,
266 std::unique_ptr<StreamBuffer> stream_buffer) 263 Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_,
267 : rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer)} {} 264 std::unique_ptr<StreamBuffer> stream_buffer_)
265 : rasterizer{rasterizer_}, gpu_memory{gpu_memory_}, cpu_memory{cpu_memory_},
266 stream_buffer{std::move(stream_buffer_)}, stream_buffer_handle{stream_buffer->Handle()} {}
268 267
269 ~BufferCache() = default; 268 ~BufferCache() = default;
270 269
@@ -326,14 +325,13 @@ private:
326 MapInterval* MapAddress(Buffer* block, GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size) { 325 MapInterval* MapAddress(Buffer* block, GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size) {
327 const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size); 326 const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size);
328 if (overlaps.empty()) { 327 if (overlaps.empty()) {
329 auto& memory_manager = system.GPU().MemoryManager();
330 const VAddr cpu_addr_end = cpu_addr + size; 328 const VAddr cpu_addr_end = cpu_addr + size;
331 if (memory_manager.IsGranularRange(gpu_addr, size)) { 329 if (gpu_memory.IsGranularRange(gpu_addr, size)) {
332 u8* host_ptr = memory_manager.GetPointer(gpu_addr); 330 u8* const host_ptr = gpu_memory.GetPointer(gpu_addr);
333 block->Upload(block->Offset(cpu_addr), size, host_ptr); 331 block->Upload(block->Offset(cpu_addr), size, host_ptr);
334 } else { 332 } else {
335 staging_buffer.resize(size); 333 staging_buffer.resize(size);
336 memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size); 334 gpu_memory.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size);
337 block->Upload(block->Offset(cpu_addr), size, staging_buffer.data()); 335 block->Upload(block->Offset(cpu_addr), size, staging_buffer.data());
338 } 336 }
339 return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr)); 337 return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr));
@@ -392,7 +390,7 @@ private:
392 continue; 390 continue;
393 } 391 }
394 staging_buffer.resize(size); 392 staging_buffer.resize(size);
395 system.Memory().ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size); 393 cpu_memory.ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size);
396 block->Upload(block->Offset(interval.lower()), size, staging_buffer.data()); 394 block->Upload(block->Offset(interval.lower()), size, staging_buffer.data());
397 } 395 }
398 } 396 }
@@ -431,7 +429,7 @@ private:
431 const std::size_t size = map->end - map->start; 429 const std::size_t size = map->end - map->start;
432 staging_buffer.resize(size); 430 staging_buffer.resize(size);
433 block->Download(block->Offset(map->start), size, staging_buffer.data()); 431 block->Download(block->Offset(map->start), size, staging_buffer.data());
434 system.Memory().WriteBlockUnsafe(map->start, staging_buffer.data(), size); 432 cpu_memory.WriteBlockUnsafe(map->start, staging_buffer.data(), size);
435 map->MarkAsModified(false, 0); 433 map->MarkAsModified(false, 0);
436 } 434 }
437 435
@@ -567,7 +565,8 @@ private:
567 } 565 }
568 566
569 VideoCore::RasterizerInterface& rasterizer; 567 VideoCore::RasterizerInterface& rasterizer;
570 Core::System& system; 568 Tegra::MemoryManager& gpu_memory;
569 Core::Memory::Memory& cpu_memory;
571 570
572 std::unique_ptr<StreamBuffer> stream_buffer; 571 std::unique_ptr<StreamBuffer> stream_buffer;
573 BufferType stream_buffer_handle; 572 BufferType stream_buffer_handle;
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index 06cc12d5a..de6991ef6 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -74,8 +74,6 @@ public:
74 } 74 }
75 75
76 void WaitPendingFences() { 76 void WaitPendingFences() {
77 auto& gpu{system.GPU()};
78 auto& memory_manager{gpu.MemoryManager()};
79 while (!fences.empty()) { 77 while (!fences.empty()) {
80 TFence& current_fence = fences.front(); 78 TFence& current_fence = fences.front();
81 if (ShouldWait()) { 79 if (ShouldWait()) {
@@ -83,8 +81,8 @@ public:
83 } 81 }
84 PopAsyncFlushes(); 82 PopAsyncFlushes();
85 if (current_fence->IsSemaphore()) { 83 if (current_fence->IsSemaphore()) {
86 memory_manager.template Write<u32>(current_fence->GetAddress(), 84 gpu_memory.template Write<u32>(current_fence->GetAddress(),
87 current_fence->GetPayload()); 85 current_fence->GetPayload());
88 } else { 86 } else {
89 gpu.IncrementSyncPoint(current_fence->GetPayload()); 87 gpu.IncrementSyncPoint(current_fence->GetPayload());
90 } 88 }
@@ -93,13 +91,13 @@ public:
93 } 91 }
94 92
95protected: 93protected:
96 FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 94 explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
97 TTextureCache& texture_cache, TTBufferCache& buffer_cache, 95 TTextureCache& texture_cache_, TTBufferCache& buffer_cache_,
98 TQueryCache& query_cache) 96 TQueryCache& query_cache_)
99 : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, 97 : rasterizer{rasterizer_}, gpu{gpu_}, gpu_memory{gpu.MemoryManager()},
100 buffer_cache{buffer_cache}, query_cache{query_cache} {} 98 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {}
101 99
102 virtual ~FenceManager() {} 100 virtual ~FenceManager() = default;
103 101
104 /// Creates a Sync Point Fence Interface, does not create a backend fence if 'is_stubbed' is 102 /// Creates a Sync Point Fence Interface, does not create a backend fence if 'is_stubbed' is
105 /// true 103 /// true
@@ -113,16 +111,15 @@ protected:
113 /// Waits until a fence has been signalled by the host GPU. 111 /// Waits until a fence has been signalled by the host GPU.
114 virtual void WaitFence(TFence& fence) = 0; 112 virtual void WaitFence(TFence& fence) = 0;
115 113
116 Core::System& system;
117 VideoCore::RasterizerInterface& rasterizer; 114 VideoCore::RasterizerInterface& rasterizer;
115 Tegra::GPU& gpu;
116 Tegra::MemoryManager& gpu_memory;
118 TTextureCache& texture_cache; 117 TTextureCache& texture_cache;
119 TTBufferCache& buffer_cache; 118 TTBufferCache& buffer_cache;
120 TQueryCache& query_cache; 119 TQueryCache& query_cache;
121 120
122private: 121private:
123 void TryReleasePendingFences() { 122 void TryReleasePendingFences() {
124 auto& gpu{system.GPU()};
125 auto& memory_manager{gpu.MemoryManager()};
126 while (!fences.empty()) { 123 while (!fences.empty()) {
127 TFence& current_fence = fences.front(); 124 TFence& current_fence = fences.front();
128 if (ShouldWait() && !IsFenceSignaled(current_fence)) { 125 if (ShouldWait() && !IsFenceSignaled(current_fence)) {
@@ -130,8 +127,8 @@ private:
130 } 127 }
131 PopAsyncFlushes(); 128 PopAsyncFlushes();
132 if (current_fence->IsSemaphore()) { 129 if (current_fence->IsSemaphore()) {
133 memory_manager.template Write<u32>(current_fence->GetAddress(), 130 gpu_memory.template Write<u32>(current_fence->GetAddress(),
134 current_fence->GetPayload()); 131 current_fence->GetPayload());
135 } else { 132 } else {
136 gpu.IncrementSyncPoint(current_fence->GetPayload()); 133 gpu.IncrementSyncPoint(current_fence->GetPayload());
137 } 134 }
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index acb6e6d46..4bb9256e9 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -28,8 +28,8 @@ namespace Tegra {
28MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); 28MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
29 29
30GPU::GPU(Core::System& system_, bool is_async_) 30GPU::GPU(Core::System& system_, bool is_async_)
31 : system{system_}, dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, 31 : system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)},
32 memory_manager{std::make_unique<Tegra::MemoryManager>(system)}, 32 dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)},
33 maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)}, 33 maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
34 fermi_2d{std::make_unique<Engines::Fermi2D>()}, 34 fermi_2d{std::make_unique<Engines::Fermi2D>()},
35 kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)}, 35 kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index c7d11deb2..2d15d1c6f 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -347,12 +347,11 @@ private:
347 347
348protected: 348protected:
349 Core::System& system; 349 Core::System& system;
350 std::unique_ptr<Tegra::MemoryManager> memory_manager;
350 std::unique_ptr<Tegra::DmaPusher> dma_pusher; 351 std::unique_ptr<Tegra::DmaPusher> dma_pusher;
351 std::unique_ptr<VideoCore::RendererBase> renderer; 352 std::unique_ptr<VideoCore::RendererBase> renderer;
352 353
353private: 354private:
354 std::unique_ptr<Tegra::MemoryManager> memory_manager;
355
356 /// Mapping of command subchannels to their bound engine ids 355 /// Mapping of command subchannels to their bound engine ids
357 std::array<EngineID, 8> bound_engines = {}; 356 std::array<EngineID, 8> bound_engines = {};
358 /// 3D engine 357 /// 3D engine
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp
index c1b9e4ad9..954b87515 100644
--- a/src/video_core/macro/macro_jit_x64.cpp
+++ b/src/video_core/macro/macro_jit_x64.cpp
@@ -14,11 +14,11 @@ MICROPROFILE_DEFINE(MacroJitCompile, "GPU", "Compile macro JIT", MP_RGB(173, 255
14MICROPROFILE_DEFINE(MacroJitExecute, "GPU", "Execute macro JIT", MP_RGB(255, 255, 0)); 14MICROPROFILE_DEFINE(MacroJitExecute, "GPU", "Execute macro JIT", MP_RGB(255, 255, 0));
15 15
16namespace Tegra { 16namespace Tegra {
17static const Xbyak::Reg64 STATE = Xbyak::util::rbx; 17constexpr Xbyak::Reg64 STATE = Xbyak::util::rbx;
18static const Xbyak::Reg32 RESULT = Xbyak::util::ebp; 18constexpr Xbyak::Reg32 RESULT = Xbyak::util::ebp;
19static const Xbyak::Reg64 PARAMETERS = Xbyak::util::r12; 19constexpr Xbyak::Reg64 PARAMETERS = Xbyak::util::r12;
20static const Xbyak::Reg32 METHOD_ADDRESS = Xbyak::util::r14d; 20constexpr Xbyak::Reg32 METHOD_ADDRESS = Xbyak::util::r14d;
21static const Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15; 21constexpr Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15;
22 22
23static const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({ 23static const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({
24 STATE, 24 STATE,
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index 0d3a88765..d13a66bb6 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -95,10 +95,12 @@ template <class QueryCache, class CachedQuery, class CounterStream, class HostCo
95 class QueryPool> 95 class QueryPool>
96class QueryCacheBase { 96class QueryCacheBase {
97public: 97public:
98 explicit QueryCacheBase(Core::System& system, VideoCore::RasterizerInterface& rasterizer) 98 explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_,
99 : system{system}, rasterizer{rasterizer}, streams{{CounterStream{ 99 Tegra::Engines::Maxwell3D& maxwell3d_,
100 static_cast<QueryCache&>(*this), 100 Tegra::MemoryManager& gpu_memory_)
101 VideoCore::QueryType::SamplesPassed}}} {} 101 : rasterizer{rasterizer_}, maxwell3d{maxwell3d_},
102 gpu_memory{gpu_memory_}, streams{{CounterStream{static_cast<QueryCache&>(*this),
103 VideoCore::QueryType::SamplesPassed}}} {}
102 104
103 void InvalidateRegion(VAddr addr, std::size_t size) { 105 void InvalidateRegion(VAddr addr, std::size_t size) {
104 std::unique_lock lock{mutex}; 106 std::unique_lock lock{mutex};
@@ -118,29 +120,27 @@ public:
118 */ 120 */
119 void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) { 121 void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) {
120 std::unique_lock lock{mutex}; 122 std::unique_lock lock{mutex};
121 auto& memory_manager = system.GPU().MemoryManager(); 123 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
122 const std::optional<VAddr> cpu_addr_opt = memory_manager.GpuToCpuAddress(gpu_addr); 124 ASSERT(cpu_addr);
123 ASSERT(cpu_addr_opt);
124 VAddr cpu_addr = *cpu_addr_opt;
125 125
126 CachedQuery* query = TryGet(cpu_addr); 126 CachedQuery* query = TryGet(*cpu_addr);
127 if (!query) { 127 if (!query) {
128 ASSERT_OR_EXECUTE(cpu_addr_opt, return;); 128 ASSERT_OR_EXECUTE(cpu_addr, return;);
129 const auto host_ptr = memory_manager.GetPointer(gpu_addr); 129 u8* const host_ptr = gpu_memory.GetPointer(gpu_addr);
130 130
131 query = Register(type, cpu_addr, host_ptr, timestamp.has_value()); 131 query = Register(type, *cpu_addr, host_ptr, timestamp.has_value());
132 } 132 }
133 133
134 query->BindCounter(Stream(type).Current(), timestamp); 134 query->BindCounter(Stream(type).Current(), timestamp);
135 if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) { 135 if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
136 AsyncFlushQuery(cpu_addr); 136 AsyncFlushQuery(*cpu_addr);
137 } 137 }
138 } 138 }
139 139
140 /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch. 140 /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch.
141 void UpdateCounters() { 141 void UpdateCounters() {
142 std::unique_lock lock{mutex}; 142 std::unique_lock lock{mutex};
143 const auto& regs = system.GPU().Maxwell3D().regs; 143 const auto& regs = maxwell3d.regs;
144 Stream(VideoCore::QueryType::SamplesPassed).Update(regs.samplecnt_enable); 144 Stream(VideoCore::QueryType::SamplesPassed).Update(regs.samplecnt_enable);
145 } 145 }
146 146
@@ -270,8 +270,9 @@ private:
270 static constexpr std::uintptr_t PAGE_SIZE = 4096; 270 static constexpr std::uintptr_t PAGE_SIZE = 4096;
271 static constexpr unsigned PAGE_BITS = 12; 271 static constexpr unsigned PAGE_BITS = 12;
272 272
273 Core::System& system;
274 VideoCore::RasterizerInterface& rasterizer; 273 VideoCore::RasterizerInterface& rasterizer;
274 Tegra::Engines::Maxwell3D& maxwell3d;
275 Tegra::MemoryManager& gpu_memory;
275 276
276 std::recursive_mutex mutex; 277 std::recursive_mutex mutex;
277 278
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 3cbdac8e7..b3e0919f8 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -106,11 +106,8 @@ public:
106 virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {} 106 virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
107 107
108 /// Initialize disk cached resources for the game being emulated 108 /// Initialize disk cached resources for the game being emulated
109 virtual void LoadDiskResources(const std::atomic_bool& stop_loading = false, 109 virtual void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
110 const DiskResourceLoadCallback& callback = {}) {} 110 const DiskResourceLoadCallback& callback) {}
111
112 /// Initializes renderer dirty flags
113 virtual void SetupDirtyFlags() {}
114 111
115 /// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver. 112 /// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.
116 GuestDriverProfile& AccessGuestDriverProfile() { 113 GuestDriverProfile& AccessGuestDriverProfile() {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index e866d8f2f..b1c4cd62f 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -59,9 +59,10 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
59 static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size)); 59 static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size));
60} 60}
61 61
62OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system, 62OGLBufferCache::OGLBufferCache(VideoCore::RasterizerInterface& rasterizer,
63 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
63 const Device& device_, std::size_t stream_size) 64 const Device& device_, std::size_t stream_size)
64 : GenericBufferCache{rasterizer, system, 65 : GenericBufferCache{rasterizer, gpu_memory, cpu_memory,
65 std::make_unique<OGLStreamBuffer>(device_, stream_size, true)}, 66 std::make_unique<OGLStreamBuffer>(device_, stream_size, true)},
66 device{device_} { 67 device{device_} {
67 if (!device.HasFastBufferSubData()) { 68 if (!device.HasFastBufferSubData()) {
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 88fdc0536..f75b32e31 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -52,7 +52,8 @@ private:
52using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>; 52using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>;
53class OGLBufferCache final : public GenericBufferCache { 53class OGLBufferCache final : public GenericBufferCache {
54public: 54public:
55 explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system, 55 explicit OGLBufferCache(VideoCore::RasterizerInterface& rasterizer,
56 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
56 const Device& device, std::size_t stream_size); 57 const Device& device, std::size_t stream_size);
57 ~OGLBufferCache(); 58 ~OGLBufferCache();
58 59
diff --git a/src/video_core/renderer_opengl/gl_fence_manager.cpp b/src/video_core/renderer_opengl/gl_fence_manager.cpp
index 3d2588dd2..b532fdcc2 100644
--- a/src/video_core/renderer_opengl/gl_fence_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_fence_manager.cpp
@@ -45,11 +45,10 @@ void GLInnerFence::Wait() {
45 glClientWaitSync(sync_object.handle, 0, GL_TIMEOUT_IGNORED); 45 glClientWaitSync(sync_object.handle, 0, GL_TIMEOUT_IGNORED);
46} 46}
47 47
48FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, 48FenceManagerOpenGL::FenceManagerOpenGL(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
49 VideoCore::RasterizerInterface& rasterizer,
50 TextureCacheOpenGL& texture_cache, 49 TextureCacheOpenGL& texture_cache,
51 OGLBufferCache& buffer_cache, QueryCache& query_cache) 50 OGLBufferCache& buffer_cache, QueryCache& query_cache)
52 : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache, query_cache) {} 51 : GenericFenceManager{rasterizer, gpu, texture_cache, buffer_cache, query_cache} {}
53 52
54Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) { 53Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) {
55 return std::make_shared<GLInnerFence>(value, is_stubbed); 54 return std::make_shared<GLInnerFence>(value, is_stubbed);
diff --git a/src/video_core/renderer_opengl/gl_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h
index 1686cf5c8..da1dcdace 100644
--- a/src/video_core/renderer_opengl/gl_fence_manager.h
+++ b/src/video_core/renderer_opengl/gl_fence_manager.h
@@ -37,9 +37,9 @@ using GenericFenceManager =
37 37
38class FenceManagerOpenGL final : public GenericFenceManager { 38class FenceManagerOpenGL final : public GenericFenceManager {
39public: 39public:
40 FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 40 explicit FenceManagerOpenGL(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
41 TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache, 41 TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache,
42 QueryCache& query_cache); 42 QueryCache& query_cache);
43 43
44protected: 44protected:
45 Fence CreateFence(u32 value, bool is_stubbed) override; 45 Fence CreateFence(u32 value, bool is_stubbed) override;
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp
index d7ba57aca..2bb8ec2b8 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_query_cache.cpp
@@ -30,12 +30,13 @@ constexpr GLenum GetTarget(VideoCore::QueryType type) {
30 30
31} // Anonymous namespace 31} // Anonymous namespace
32 32
33QueryCache::QueryCache(Core::System& system, RasterizerOpenGL& gl_rasterizer) 33QueryCache::QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d,
34 Tegra::MemoryManager& gpu_memory)
34 : VideoCommon::QueryCacheBase< 35 : VideoCommon::QueryCacheBase<
35 QueryCache, CachedQuery, CounterStream, HostCounter, 36 QueryCache, CachedQuery, CounterStream, HostCounter,
36 std::vector<OGLQuery>>{system, 37 std::vector<OGLQuery>>{static_cast<VideoCore::RasterizerInterface&>(rasterizer),
37 static_cast<VideoCore::RasterizerInterface&>(gl_rasterizer)}, 38 maxwell3d, gpu_memory},
38 gl_rasterizer{gl_rasterizer} {} 39 gl_rasterizer{rasterizer} {}
39 40
40QueryCache::~QueryCache() = default; 41QueryCache::~QueryCache() = default;
41 42
diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h
index d8e7052a1..dd626b66b 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.h
+++ b/src/video_core/renderer_opengl/gl_query_cache.h
@@ -29,7 +29,8 @@ using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>;
29class QueryCache final : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, 29class QueryCache final : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream,
30 HostCounter, std::vector<OGLQuery>> { 30 HostCounter, std::vector<OGLQuery>> {
31public: 31public:
32 explicit QueryCache(Core::System& system, RasterizerOpenGL& rasterizer); 32 explicit QueryCache(RasterizerOpenGL& rasterizer, Tegra::Engines::Maxwell3D& maxwell3d,
33 Tegra::MemoryManager& gpu_memory);
33 ~QueryCache(); 34 ~QueryCache();
34 35
35 OGLQuery AllocateQuery(VideoCore::QueryType type); 36 OGLQuery AllocateQuery(VideoCore::QueryType type);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4af5824cd..bbb2eb17c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -153,16 +153,19 @@ void UpdateBindlessPointers(GLenum target, GLuint64EXT* pointers, std::size_t nu
153 153
154} // Anonymous namespace 154} // Anonymous namespace
155 155
156RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 156RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_,
157 const Device& device, ScreenInfo& info, 157 Core::Memory::Memory& cpu_memory, const Device& device_,
158 ProgramManager& program_manager, StateTracker& state_tracker) 158 ScreenInfo& screen_info_, ProgramManager& program_manager_,
159 : RasterizerAccelerated{system.Memory()}, device{device}, texture_cache{system, *this, device, 159 StateTracker& state_tracker_)
160 state_tracker}, 160 : RasterizerAccelerated{cpu_memory}, gpu(gpu_), maxwell3d(gpu.Maxwell3D()),
161 shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, 161 kepler_compute(gpu.KeplerCompute()), gpu_memory(gpu.MemoryManager()), device(device_),
162 buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, 162 screen_info(screen_info_), program_manager(program_manager_), state_tracker(state_tracker_),
163 fence_manager{system, *this, texture_cache, buffer_cache, query_cache}, system{system}, 163 texture_cache(*this, maxwell3d, gpu_memory, device, state_tracker),
164 screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker}, 164 shader_cache(*this, emu_window, gpu, maxwell3d, kepler_compute, gpu_memory, device),
165 async_shaders{emu_window} { 165 query_cache(*this, maxwell3d, gpu_memory),
166 buffer_cache(*this, gpu_memory, cpu_memory, device, STREAM_BUFFER_SIZE),
167 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
168 async_shaders(emu_window) {
166 CheckExtensions(); 169 CheckExtensions();
167 170
168 unified_uniform_buffer.Create(); 171 unified_uniform_buffer.Create();
@@ -196,8 +199,7 @@ void RasterizerOpenGL::CheckExtensions() {
196} 199}
197 200
198void RasterizerOpenGL::SetupVertexFormat() { 201void RasterizerOpenGL::SetupVertexFormat() {
199 auto& gpu = system.GPU().Maxwell3D(); 202 auto& flags = maxwell3d.dirty.flags;
200 auto& flags = gpu.dirty.flags;
201 if (!flags[Dirty::VertexFormats]) { 203 if (!flags[Dirty::VertexFormats]) {
202 return; 204 return;
203 } 205 }
@@ -217,7 +219,7 @@ void RasterizerOpenGL::SetupVertexFormat() {
217 } 219 }
218 flags[Dirty::VertexFormat0 + index] = false; 220 flags[Dirty::VertexFormat0 + index] = false;
219 221
220 const auto attrib = gpu.regs.vertex_attrib_format[index]; 222 const auto attrib = maxwell3d.regs.vertex_attrib_format[index];
221 const auto gl_index = static_cast<GLuint>(index); 223 const auto gl_index = static_cast<GLuint>(index);
222 224
223 // Disable constant attributes. 225 // Disable constant attributes.
@@ -241,8 +243,7 @@ void RasterizerOpenGL::SetupVertexFormat() {
241} 243}
242 244
243void RasterizerOpenGL::SetupVertexBuffer() { 245void RasterizerOpenGL::SetupVertexBuffer() {
244 auto& gpu = system.GPU().Maxwell3D(); 246 auto& flags = maxwell3d.dirty.flags;
245 auto& flags = gpu.dirty.flags;
246 if (!flags[Dirty::VertexBuffers]) { 247 if (!flags[Dirty::VertexBuffers]) {
247 return; 248 return;
248 } 249 }
@@ -253,7 +254,7 @@ void RasterizerOpenGL::SetupVertexBuffer() {
253 const bool use_unified_memory = device.HasVertexBufferUnifiedMemory(); 254 const bool use_unified_memory = device.HasVertexBufferUnifiedMemory();
254 255
255 // Upload all guest vertex arrays sequentially to our buffer 256 // Upload all guest vertex arrays sequentially to our buffer
256 const auto& regs = gpu.regs; 257 const auto& regs = maxwell3d.regs;
257 for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_BINDINGS; ++index) { 258 for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_BINDINGS; ++index) {
258 if (!flags[Dirty::VertexBuffer0 + index]) { 259 if (!flags[Dirty::VertexBuffer0 + index]) {
259 continue; 260 continue;
@@ -290,14 +291,13 @@ void RasterizerOpenGL::SetupVertexBuffer() {
290} 291}
291 292
292void RasterizerOpenGL::SetupVertexInstances() { 293void RasterizerOpenGL::SetupVertexInstances() {
293 auto& gpu = system.GPU().Maxwell3D(); 294 auto& flags = maxwell3d.dirty.flags;
294 auto& flags = gpu.dirty.flags;
295 if (!flags[Dirty::VertexInstances]) { 295 if (!flags[Dirty::VertexInstances]) {
296 return; 296 return;
297 } 297 }
298 flags[Dirty::VertexInstances] = false; 298 flags[Dirty::VertexInstances] = false;
299 299
300 const auto& regs = gpu.regs; 300 const auto& regs = maxwell3d.regs;
301 for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) { 301 for (std::size_t index = 0; index < NUM_SUPPORTED_VERTEX_ATTRIBUTES; ++index) {
302 if (!flags[Dirty::VertexInstance0 + index]) { 302 if (!flags[Dirty::VertexInstance0 + index]) {
303 continue; 303 continue;
@@ -313,7 +313,7 @@ void RasterizerOpenGL::SetupVertexInstances() {
313 313
314GLintptr RasterizerOpenGL::SetupIndexBuffer() { 314GLintptr RasterizerOpenGL::SetupIndexBuffer() {
315 MICROPROFILE_SCOPE(OpenGL_Index); 315 MICROPROFILE_SCOPE(OpenGL_Index);
316 const auto& regs = system.GPU().Maxwell3D().regs; 316 const auto& regs = maxwell3d.regs;
317 const std::size_t size = CalculateIndexBufferSize(); 317 const std::size_t size = CalculateIndexBufferSize();
318 const auto info = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size); 318 const auto info = buffer_cache.UploadMemory(regs.index_array.IndexStart(), size);
319 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, info.handle); 319 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, info.handle);
@@ -322,15 +322,14 @@ GLintptr RasterizerOpenGL::SetupIndexBuffer() {
322 322
323void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { 323void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
324 MICROPROFILE_SCOPE(OpenGL_Shader); 324 MICROPROFILE_SCOPE(OpenGL_Shader);
325 auto& gpu = system.GPU().Maxwell3D();
326 u32 clip_distances = 0; 325 u32 clip_distances = 0;
327 326
328 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 327 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
329 const auto& shader_config = gpu.regs.shader_config[index]; 328 const auto& shader_config = maxwell3d.regs.shader_config[index];
330 const auto program{static_cast<Maxwell::ShaderProgram>(index)}; 329 const auto program{static_cast<Maxwell::ShaderProgram>(index)};
331 330
332 // Skip stages that are not enabled 331 // Skip stages that are not enabled
333 if (!gpu.regs.IsShaderConfigEnabled(index)) { 332 if (!maxwell3d.regs.IsShaderConfigEnabled(index)) {
334 switch (program) { 333 switch (program) {
335 case Maxwell::ShaderProgram::Geometry: 334 case Maxwell::ShaderProgram::Geometry:
336 program_manager.UseGeometryShader(0); 335 program_manager.UseGeometryShader(0);
@@ -391,11 +390,11 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
391 } 390 }
392 391
393 SyncClipEnabled(clip_distances); 392 SyncClipEnabled(clip_distances);
394 gpu.dirty.flags[Dirty::Shaders] = false; 393 maxwell3d.dirty.flags[Dirty::Shaders] = false;
395} 394}
396 395
397std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 396std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
398 const auto& regs = system.GPU().Maxwell3D().regs; 397 const auto& regs = maxwell3d.regs;
399 398
400 std::size_t size = 0; 399 std::size_t size = 0;
401 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 400 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
@@ -413,34 +412,27 @@ std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
413} 412}
414 413
415std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const { 414std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const {
416 const auto& regs = system.GPU().Maxwell3D().regs; 415 return static_cast<std::size_t>(maxwell3d.regs.index_array.count) *
417 416 static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes());
418 return static_cast<std::size_t>(regs.index_array.count) *
419 static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
420} 417}
421 418
422void RasterizerOpenGL::LoadDiskResources(const std::atomic_bool& stop_loading, 419void RasterizerOpenGL::LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
423 const VideoCore::DiskResourceLoadCallback& callback) { 420 const VideoCore::DiskResourceLoadCallback& callback) {
424 shader_cache.LoadDiskCache(stop_loading, callback); 421 shader_cache.LoadDiskCache(title_id, stop_loading, callback);
425}
426
427void RasterizerOpenGL::SetupDirtyFlags() {
428 state_tracker.Initialize();
429} 422}
430 423
431void RasterizerOpenGL::ConfigureFramebuffers() { 424void RasterizerOpenGL::ConfigureFramebuffers() {
432 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 425 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
433 auto& gpu = system.GPU().Maxwell3D(); 426 if (!maxwell3d.dirty.flags[VideoCommon::Dirty::RenderTargets]) {
434 if (!gpu.dirty.flags[VideoCommon::Dirty::RenderTargets]) {
435 return; 427 return;
436 } 428 }
437 gpu.dirty.flags[VideoCommon::Dirty::RenderTargets] = false; 429 maxwell3d.dirty.flags[VideoCommon::Dirty::RenderTargets] = false;
438 430
439 texture_cache.GuardRenderTargets(true); 431 texture_cache.GuardRenderTargets(true);
440 432
441 View depth_surface = texture_cache.GetDepthBufferSurface(true); 433 View depth_surface = texture_cache.GetDepthBufferSurface(true);
442 434
443 const auto& regs = gpu.regs; 435 const auto& regs = maxwell3d.regs;
444 UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0); 436 UNIMPLEMENTED_IF(regs.rt_separate_frag_data == 0);
445 437
446 // Bind the framebuffer surfaces 438 // Bind the framebuffer surfaces
@@ -472,8 +464,7 @@ void RasterizerOpenGL::ConfigureFramebuffers() {
472} 464}
473 465
474void RasterizerOpenGL::ConfigureClearFramebuffer(bool using_color, bool using_depth_stencil) { 466void RasterizerOpenGL::ConfigureClearFramebuffer(bool using_color, bool using_depth_stencil) {
475 auto& gpu = system.GPU().Maxwell3D(); 467 const auto& regs = maxwell3d.regs;
476 const auto& regs = gpu.regs;
477 468
478 texture_cache.GuardRenderTargets(true); 469 texture_cache.GuardRenderTargets(true);
479 View color_surface; 470 View color_surface;
@@ -523,12 +514,11 @@ void RasterizerOpenGL::ConfigureClearFramebuffer(bool using_color, bool using_de
523} 514}
524 515
525void RasterizerOpenGL::Clear() { 516void RasterizerOpenGL::Clear() {
526 const auto& gpu = system.GPU().Maxwell3D(); 517 if (!maxwell3d.ShouldExecute()) {
527 if (!gpu.ShouldExecute()) {
528 return; 518 return;
529 } 519 }
530 520
531 const auto& regs = gpu.regs; 521 const auto& regs = maxwell3d.regs;
532 bool use_color{}; 522 bool use_color{};
533 bool use_depth{}; 523 bool use_depth{};
534 bool use_stencil{}; 524 bool use_stencil{};
@@ -593,7 +583,6 @@ void RasterizerOpenGL::Clear() {
593 583
594void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { 584void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
595 MICROPROFILE_SCOPE(OpenGL_Drawing); 585 MICROPROFILE_SCOPE(OpenGL_Drawing);
596 auto& gpu = system.GPU().Maxwell3D();
597 586
598 query_cache.UpdateCounters(); 587 query_cache.UpdateCounters();
599 588
@@ -641,7 +630,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
641 630
642 if (invalidated) { 631 if (invalidated) {
643 // When the stream buffer has been invalidated, we have to consider vertex buffers as dirty 632 // When the stream buffer has been invalidated, we have to consider vertex buffers as dirty
644 auto& dirty = gpu.dirty.flags; 633 auto& dirty = maxwell3d.dirty.flags;
645 dirty[Dirty::VertexBuffers] = true; 634 dirty[Dirty::VertexBuffers] = true;
646 for (int index = Dirty::VertexBuffer0; index <= Dirty::VertexBuffer31; ++index) { 635 for (int index = Dirty::VertexBuffer0; index <= Dirty::VertexBuffer31; ++index) {
647 dirty[index] = true; 636 dirty[index] = true;
@@ -662,7 +651,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
662 // Setup emulation uniform buffer. 651 // Setup emulation uniform buffer.
663 if (!device.UseAssemblyShaders()) { 652 if (!device.UseAssemblyShaders()) {
664 MaxwellUniformData ubo; 653 MaxwellUniformData ubo;
665 ubo.SetFromRegs(gpu); 654 ubo.SetFromRegs(maxwell3d);
666 const auto info = 655 const auto info =
667 buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment()); 656 buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment());
668 glBindBufferRange(GL_UNIFORM_BUFFER, EmulationUniformBlockBinding, info.handle, info.offset, 657 glBindBufferRange(GL_UNIFORM_BUFFER, EmulationUniformBlockBinding, info.handle, info.offset,
@@ -671,7 +660,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
671 660
672 // Setup shaders and their used resources. 661 // Setup shaders and their used resources.
673 texture_cache.GuardSamplers(true); 662 texture_cache.GuardSamplers(true);
674 const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(gpu.regs.draw.topology); 663 const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d.regs.draw.topology);
675 SetupShaders(primitive_mode); 664 SetupShaders(primitive_mode);
676 texture_cache.GuardSamplers(false); 665 texture_cache.GuardSamplers(false);
677 666
@@ -688,14 +677,14 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
688 677
689 BeginTransformFeedback(primitive_mode); 678 BeginTransformFeedback(primitive_mode);
690 679
691 const GLuint base_instance = static_cast<GLuint>(gpu.regs.vb_base_instance); 680 const GLuint base_instance = static_cast<GLuint>(maxwell3d.regs.vb_base_instance);
692 const GLsizei num_instances = 681 const GLsizei num_instances =
693 static_cast<GLsizei>(is_instanced ? gpu.mme_draw.instance_count : 1); 682 static_cast<GLsizei>(is_instanced ? maxwell3d.mme_draw.instance_count : 1);
694 if (is_indexed) { 683 if (is_indexed) {
695 const GLint base_vertex = static_cast<GLint>(gpu.regs.vb_element_base); 684 const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vb_element_base);
696 const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.index_array.count); 685 const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.index_array.count);
697 const GLvoid* offset = reinterpret_cast<const GLvoid*>(index_buffer_offset); 686 const GLvoid* offset = reinterpret_cast<const GLvoid*>(index_buffer_offset);
698 const GLenum format = MaxwellToGL::IndexFormat(gpu.regs.index_array.format); 687 const GLenum format = MaxwellToGL::IndexFormat(maxwell3d.regs.index_array.format);
699 if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { 688 if (num_instances == 1 && base_instance == 0 && base_vertex == 0) {
700 glDrawElements(primitive_mode, num_vertices, format, offset); 689 glDrawElements(primitive_mode, num_vertices, format, offset);
701 } else if (num_instances == 1 && base_instance == 0) { 690 } else if (num_instances == 1 && base_instance == 0) {
@@ -714,8 +703,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
714 base_instance); 703 base_instance);
715 } 704 }
716 } else { 705 } else {
717 const GLint base_vertex = static_cast<GLint>(gpu.regs.vertex_buffer.first); 706 const GLint base_vertex = static_cast<GLint>(maxwell3d.regs.vertex_buffer.first);
718 const GLsizei num_vertices = static_cast<GLsizei>(gpu.regs.vertex_buffer.count); 707 const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d.regs.vertex_buffer.count);
719 if (num_instances == 1 && base_instance == 0) { 708 if (num_instances == 1 && base_instance == 0) {
720 glDrawArrays(primitive_mode, base_vertex, num_vertices); 709 glDrawArrays(primitive_mode, base_vertex, num_vertices);
721 } else if (base_instance == 0) { 710 } else if (base_instance == 0) {
@@ -730,7 +719,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) {
730 719
731 ++num_queued_commands; 720 ++num_queued_commands;
732 721
733 system.GPU().TickWork(); 722 gpu.TickWork();
734} 723}
735 724
736void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { 725void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
@@ -753,7 +742,8 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
753 742
754 buffer_cache.Unmap(); 743 buffer_cache.Unmap();
755 744
756 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 745 const auto& launch_desc = kepler_compute.launch_description;
746 program_manager.BindCompute(kernel->GetHandle());
757 glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z); 747 glDispatchCompute(launch_desc.grid_dim_x, launch_desc.grid_dim_y, launch_desc.grid_dim_z);
758 ++num_queued_commands; 748 ++num_queued_commands;
759} 749}
@@ -815,17 +805,14 @@ void RasterizerOpenGL::SyncGuestHost() {
815} 805}
816 806
817void RasterizerOpenGL::SignalSemaphore(GPUVAddr addr, u32 value) { 807void RasterizerOpenGL::SignalSemaphore(GPUVAddr addr, u32 value) {
818 auto& gpu{system.GPU()};
819 if (!gpu.IsAsync()) { 808 if (!gpu.IsAsync()) {
820 auto& memory_manager{gpu.MemoryManager()}; 809 gpu_memory.Write<u32>(addr, value);
821 memory_manager.Write<u32>(addr, value);
822 return; 810 return;
823 } 811 }
824 fence_manager.SignalSemaphore(addr, value); 812 fence_manager.SignalSemaphore(addr, value);
825} 813}
826 814
827void RasterizerOpenGL::SignalSyncPoint(u32 value) { 815void RasterizerOpenGL::SignalSyncPoint(u32 value) {
828 auto& gpu{system.GPU()};
829 if (!gpu.IsAsync()) { 816 if (!gpu.IsAsync()) {
830 gpu.IncrementSyncPoint(value); 817 gpu.IncrementSyncPoint(value);
831 return; 818 return;
@@ -834,7 +821,6 @@ void RasterizerOpenGL::SignalSyncPoint(u32 value) {
834} 821}
835 822
836void RasterizerOpenGL::ReleaseFences() { 823void RasterizerOpenGL::ReleaseFences() {
837 auto& gpu{system.GPU()};
838 if (!gpu.IsAsync()) { 824 if (!gpu.IsAsync()) {
839 return; 825 return;
840 } 826 }
@@ -920,7 +906,7 @@ void RasterizerOpenGL::SetupDrawConstBuffers(std::size_t stage_index, Shader* sh
920 GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV}; 906 GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV};
921 907
922 MICROPROFILE_SCOPE(OpenGL_UBO); 908 MICROPROFILE_SCOPE(OpenGL_UBO);
923 const auto& stages = system.GPU().Maxwell3D().state.shader_stages; 909 const auto& stages = maxwell3d.state.shader_stages;
924 const auto& shader_stage = stages[stage_index]; 910 const auto& shader_stage = stages[stage_index];
925 const auto& entries = shader->GetEntries(); 911 const auto& entries = shader->GetEntries();
926 const bool use_unified = entries.use_unified_uniforms; 912 const bool use_unified = entries.use_unified_uniforms;
@@ -945,7 +931,7 @@ void RasterizerOpenGL::SetupDrawConstBuffers(std::size_t stage_index, Shader* sh
945 931
946void RasterizerOpenGL::SetupComputeConstBuffers(Shader* kernel) { 932void RasterizerOpenGL::SetupComputeConstBuffers(Shader* kernel) {
947 MICROPROFILE_SCOPE(OpenGL_UBO); 933 MICROPROFILE_SCOPE(OpenGL_UBO);
948 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 934 const auto& launch_desc = kepler_compute.launch_description;
949 const auto& entries = kernel->GetEntries(); 935 const auto& entries = kernel->GetEntries();
950 const bool use_unified = entries.use_unified_uniforms; 936 const bool use_unified = entries.use_unified_uniforms;
951 937
@@ -1018,9 +1004,7 @@ void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* sh
1018 GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV, 1004 GL_GEOMETRY_PROGRAM_NV, GL_FRAGMENT_PROGRAM_NV,
1019 }; 1005 };
1020 1006
1021 auto& gpu{system.GPU()}; 1007 const auto& cbufs{maxwell3d.state.shader_stages[stage_index]};
1022 auto& memory_manager{gpu.MemoryManager()};
1023 const auto& cbufs{gpu.Maxwell3D().state.shader_stages[stage_index]};
1024 const auto& entries{shader->GetEntries().global_memory_entries}; 1008 const auto& entries{shader->GetEntries().global_memory_entries};
1025 1009
1026 std::array<GLuint64EXT, 32> pointers; 1010 std::array<GLuint64EXT, 32> pointers;
@@ -1030,8 +1014,8 @@ void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* sh
1030 u32 binding = assembly_shaders ? 0 : device.GetBaseBindings(stage_index).shader_storage_buffer; 1014 u32 binding = assembly_shaders ? 0 : device.GetBaseBindings(stage_index).shader_storage_buffer;
1031 for (const auto& entry : entries) { 1015 for (const auto& entry : entries) {
1032 const GPUVAddr addr{cbufs.const_buffers[entry.cbuf_index].address + entry.cbuf_offset}; 1016 const GPUVAddr addr{cbufs.const_buffers[entry.cbuf_index].address + entry.cbuf_offset};
1033 const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)}; 1017 const GPUVAddr gpu_addr{gpu_memory.Read<u64>(addr)};
1034 const u32 size{memory_manager.Read<u32>(addr + 8)}; 1018 const u32 size{gpu_memory.Read<u32>(addr + 8)};
1035 SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]); 1019 SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]);
1036 ++binding; 1020 ++binding;
1037 } 1021 }
@@ -1041,9 +1025,7 @@ void RasterizerOpenGL::SetupDrawGlobalMemory(std::size_t stage_index, Shader* sh
1041} 1025}
1042 1026
1043void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) { 1027void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) {
1044 auto& gpu{system.GPU()}; 1028 const auto& cbufs{kepler_compute.launch_description.const_buffer_config};
1045 auto& memory_manager{gpu.MemoryManager()};
1046 const auto& cbufs{gpu.KeplerCompute().launch_description.const_buffer_config};
1047 const auto& entries{kernel->GetEntries().global_memory_entries}; 1029 const auto& entries{kernel->GetEntries().global_memory_entries};
1048 1030
1049 std::array<GLuint64EXT, 32> pointers; 1031 std::array<GLuint64EXT, 32> pointers;
@@ -1052,8 +1034,8 @@ void RasterizerOpenGL::SetupComputeGlobalMemory(Shader* kernel) {
1052 u32 binding = 0; 1034 u32 binding = 0;
1053 for (const auto& entry : entries) { 1035 for (const auto& entry : entries) {
1054 const GPUVAddr addr{cbufs[entry.cbuf_index].Address() + entry.cbuf_offset}; 1036 const GPUVAddr addr{cbufs[entry.cbuf_index].Address() + entry.cbuf_offset};
1055 const GPUVAddr gpu_addr{memory_manager.Read<u64>(addr)}; 1037 const GPUVAddr gpu_addr{gpu_memory.Read<u64>(addr)};
1056 const u32 size{memory_manager.Read<u32>(addr + 8)}; 1038 const u32 size{gpu_memory.Read<u32>(addr + 8)};
1057 SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]); 1039 SetupGlobalMemory(binding, entry, gpu_addr, size, &pointers[binding]);
1058 ++binding; 1040 ++binding;
1059 } 1041 }
@@ -1077,7 +1059,6 @@ void RasterizerOpenGL::SetupGlobalMemory(u32 binding, const GlobalMemoryEntry& e
1077 1059
1078void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader) { 1060void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader) {
1079 MICROPROFILE_SCOPE(OpenGL_Texture); 1061 MICROPROFILE_SCOPE(OpenGL_Texture);
1080 const auto& maxwell3d = system.GPU().Maxwell3D();
1081 u32 binding = device.GetBaseBindings(stage_index).sampler; 1062 u32 binding = device.GetBaseBindings(stage_index).sampler;
1082 for (const auto& entry : shader->GetEntries().samplers) { 1063 for (const auto& entry : shader->GetEntries().samplers) {
1083 const auto shader_type = static_cast<ShaderType>(stage_index); 1064 const auto shader_type = static_cast<ShaderType>(stage_index);
@@ -1090,11 +1071,10 @@ void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, Shader* shader
1090 1071
1091void RasterizerOpenGL::SetupComputeTextures(Shader* kernel) { 1072void RasterizerOpenGL::SetupComputeTextures(Shader* kernel) {
1092 MICROPROFILE_SCOPE(OpenGL_Texture); 1073 MICROPROFILE_SCOPE(OpenGL_Texture);
1093 const auto& compute = system.GPU().KeplerCompute();
1094 u32 binding = 0; 1074 u32 binding = 0;
1095 for (const auto& entry : kernel->GetEntries().samplers) { 1075 for (const auto& entry : kernel->GetEntries().samplers) {
1096 for (std::size_t i = 0; i < entry.size; ++i) { 1076 for (std::size_t i = 0; i < entry.size; ++i) {
1097 const auto texture = GetTextureInfo(compute, entry, ShaderType::Compute, i); 1077 const auto texture = GetTextureInfo(kepler_compute, entry, ShaderType::Compute, i);
1098 SetupTexture(binding++, texture, entry); 1078 SetupTexture(binding++, texture, entry);
1099 } 1079 }
1100 } 1080 }
@@ -1118,20 +1098,18 @@ void RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextu
1118} 1098}
1119 1099
1120void RasterizerOpenGL::SetupDrawImages(std::size_t stage_index, Shader* shader) { 1100void RasterizerOpenGL::SetupDrawImages(std::size_t stage_index, Shader* shader) {
1121 const auto& maxwell3d = system.GPU().Maxwell3D();
1122 u32 binding = device.GetBaseBindings(stage_index).image; 1101 u32 binding = device.GetBaseBindings(stage_index).image;
1123 for (const auto& entry : shader->GetEntries().images) { 1102 for (const auto& entry : shader->GetEntries().images) {
1124 const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage_index); 1103 const auto shader_type = static_cast<ShaderType>(stage_index);
1125 const auto tic = GetTextureInfo(maxwell3d, entry, shader_type).tic; 1104 const auto tic = GetTextureInfo(maxwell3d, entry, shader_type).tic;
1126 SetupImage(binding++, tic, entry); 1105 SetupImage(binding++, tic, entry);
1127 } 1106 }
1128} 1107}
1129 1108
1130void RasterizerOpenGL::SetupComputeImages(Shader* shader) { 1109void RasterizerOpenGL::SetupComputeImages(Shader* shader) {
1131 const auto& compute = system.GPU().KeplerCompute();
1132 u32 binding = 0; 1110 u32 binding = 0;
1133 for (const auto& entry : shader->GetEntries().images) { 1111 for (const auto& entry : shader->GetEntries().images) {
1134 const auto tic = GetTextureInfo(compute, entry, Tegra::Engines::ShaderType::Compute).tic; 1112 const auto tic = GetTextureInfo(kepler_compute, entry, ShaderType::Compute).tic;
1135 SetupImage(binding++, tic, entry); 1113 SetupImage(binding++, tic, entry);
1136 } 1114 }
1137} 1115}
@@ -1151,9 +1129,8 @@ void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& t
1151} 1129}
1152 1130
1153void RasterizerOpenGL::SyncViewport() { 1131void RasterizerOpenGL::SyncViewport() {
1154 auto& gpu = system.GPU().Maxwell3D(); 1132 auto& flags = maxwell3d.dirty.flags;
1155 auto& flags = gpu.dirty.flags; 1133 const auto& regs = maxwell3d.regs;
1156 const auto& regs = gpu.regs;
1157 1134
1158 const bool dirty_viewport = flags[Dirty::Viewports]; 1135 const bool dirty_viewport = flags[Dirty::Viewports];
1159 const bool dirty_clip_control = flags[Dirty::ClipControl]; 1136 const bool dirty_clip_control = flags[Dirty::ClipControl];
@@ -1225,25 +1202,23 @@ void RasterizerOpenGL::SyncViewport() {
1225} 1202}
1226 1203
1227void RasterizerOpenGL::SyncDepthClamp() { 1204void RasterizerOpenGL::SyncDepthClamp() {
1228 auto& gpu = system.GPU().Maxwell3D(); 1205 auto& flags = maxwell3d.dirty.flags;
1229 auto& flags = gpu.dirty.flags;
1230 if (!flags[Dirty::DepthClampEnabled]) { 1206 if (!flags[Dirty::DepthClampEnabled]) {
1231 return; 1207 return;
1232 } 1208 }
1233 flags[Dirty::DepthClampEnabled] = false; 1209 flags[Dirty::DepthClampEnabled] = false;
1234 1210
1235 oglEnable(GL_DEPTH_CLAMP, gpu.regs.view_volume_clip_control.depth_clamp_disabled == 0); 1211 oglEnable(GL_DEPTH_CLAMP, maxwell3d.regs.view_volume_clip_control.depth_clamp_disabled == 0);
1236} 1212}
1237 1213
1238void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) { 1214void RasterizerOpenGL::SyncClipEnabled(u32 clip_mask) {
1239 auto& gpu = system.GPU().Maxwell3D(); 1215 auto& flags = maxwell3d.dirty.flags;
1240 auto& flags = gpu.dirty.flags;
1241 if (!flags[Dirty::ClipDistances] && !flags[Dirty::Shaders]) { 1216 if (!flags[Dirty::ClipDistances] && !flags[Dirty::Shaders]) {
1242 return; 1217 return;
1243 } 1218 }
1244 flags[Dirty::ClipDistances] = false; 1219 flags[Dirty::ClipDistances] = false;
1245 1220
1246 clip_mask &= gpu.regs.clip_distance_enabled; 1221 clip_mask &= maxwell3d.regs.clip_distance_enabled;
1247 if (clip_mask == last_clip_distance_mask) { 1222 if (clip_mask == last_clip_distance_mask) {
1248 return; 1223 return;
1249 } 1224 }
@@ -1259,9 +1234,8 @@ void RasterizerOpenGL::SyncClipCoef() {
1259} 1234}
1260 1235
1261void RasterizerOpenGL::SyncCullMode() { 1236void RasterizerOpenGL::SyncCullMode() {
1262 auto& gpu = system.GPU().Maxwell3D(); 1237 auto& flags = maxwell3d.dirty.flags;
1263 auto& flags = gpu.dirty.flags; 1238 const auto& regs = maxwell3d.regs;
1264 const auto& regs = gpu.regs;
1265 1239
1266 if (flags[Dirty::CullTest]) { 1240 if (flags[Dirty::CullTest]) {
1267 flags[Dirty::CullTest] = false; 1241 flags[Dirty::CullTest] = false;
@@ -1276,26 +1250,24 @@ void RasterizerOpenGL::SyncCullMode() {
1276} 1250}
1277 1251
1278void RasterizerOpenGL::SyncPrimitiveRestart() { 1252void RasterizerOpenGL::SyncPrimitiveRestart() {
1279 auto& gpu = system.GPU().Maxwell3D(); 1253 auto& flags = maxwell3d.dirty.flags;
1280 auto& flags = gpu.dirty.flags;
1281 if (!flags[Dirty::PrimitiveRestart]) { 1254 if (!flags[Dirty::PrimitiveRestart]) {
1282 return; 1255 return;
1283 } 1256 }
1284 flags[Dirty::PrimitiveRestart] = false; 1257 flags[Dirty::PrimitiveRestart] = false;
1285 1258
1286 if (gpu.regs.primitive_restart.enabled) { 1259 if (maxwell3d.regs.primitive_restart.enabled) {
1287 glEnable(GL_PRIMITIVE_RESTART); 1260 glEnable(GL_PRIMITIVE_RESTART);
1288 glPrimitiveRestartIndex(gpu.regs.primitive_restart.index); 1261 glPrimitiveRestartIndex(maxwell3d.regs.primitive_restart.index);
1289 } else { 1262 } else {
1290 glDisable(GL_PRIMITIVE_RESTART); 1263 glDisable(GL_PRIMITIVE_RESTART);
1291 } 1264 }
1292} 1265}
1293 1266
1294void RasterizerOpenGL::SyncDepthTestState() { 1267void RasterizerOpenGL::SyncDepthTestState() {
1295 auto& gpu = system.GPU().Maxwell3D(); 1268 auto& flags = maxwell3d.dirty.flags;
1296 auto& flags = gpu.dirty.flags; 1269 const auto& regs = maxwell3d.regs;
1297 1270
1298 const auto& regs = gpu.regs;
1299 if (flags[Dirty::DepthMask]) { 1271 if (flags[Dirty::DepthMask]) {
1300 flags[Dirty::DepthMask] = false; 1272 flags[Dirty::DepthMask] = false;
1301 glDepthMask(regs.depth_write_enabled ? GL_TRUE : GL_FALSE); 1273 glDepthMask(regs.depth_write_enabled ? GL_TRUE : GL_FALSE);
@@ -1313,14 +1285,13 @@ void RasterizerOpenGL::SyncDepthTestState() {
1313} 1285}
1314 1286
1315void RasterizerOpenGL::SyncStencilTestState() { 1287void RasterizerOpenGL::SyncStencilTestState() {
1316 auto& gpu = system.GPU().Maxwell3D(); 1288 auto& flags = maxwell3d.dirty.flags;
1317 auto& flags = gpu.dirty.flags;
1318 if (!flags[Dirty::StencilTest]) { 1289 if (!flags[Dirty::StencilTest]) {
1319 return; 1290 return;
1320 } 1291 }
1321 flags[Dirty::StencilTest] = false; 1292 flags[Dirty::StencilTest] = false;
1322 1293
1323 const auto& regs = gpu.regs; 1294 const auto& regs = maxwell3d.regs;
1324 oglEnable(GL_STENCIL_TEST, regs.stencil_enable); 1295 oglEnable(GL_STENCIL_TEST, regs.stencil_enable);
1325 1296
1326 glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func), 1297 glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func),
@@ -1345,25 +1316,24 @@ void RasterizerOpenGL::SyncStencilTestState() {
1345} 1316}
1346 1317
1347void RasterizerOpenGL::SyncRasterizeEnable() { 1318void RasterizerOpenGL::SyncRasterizeEnable() {
1348 auto& gpu = system.GPU().Maxwell3D(); 1319 auto& flags = maxwell3d.dirty.flags;
1349 auto& flags = gpu.dirty.flags;
1350 if (!flags[Dirty::RasterizeEnable]) { 1320 if (!flags[Dirty::RasterizeEnable]) {
1351 return; 1321 return;
1352 } 1322 }
1353 flags[Dirty::RasterizeEnable] = false; 1323 flags[Dirty::RasterizeEnable] = false;
1354 1324
1355 oglEnable(GL_RASTERIZER_DISCARD, gpu.regs.rasterize_enable == 0); 1325 oglEnable(GL_RASTERIZER_DISCARD, maxwell3d.regs.rasterize_enable == 0);
1356} 1326}
1357 1327
1358void RasterizerOpenGL::SyncPolygonModes() { 1328void RasterizerOpenGL::SyncPolygonModes() {
1359 auto& gpu = system.GPU().Maxwell3D(); 1329 auto& flags = maxwell3d.dirty.flags;
1360 auto& flags = gpu.dirty.flags;
1361 if (!flags[Dirty::PolygonModes]) { 1330 if (!flags[Dirty::PolygonModes]) {
1362 return; 1331 return;
1363 } 1332 }
1364 flags[Dirty::PolygonModes] = false; 1333 flags[Dirty::PolygonModes] = false;
1365 1334
1366 if (gpu.regs.fill_rectangle) { 1335 const auto& regs = maxwell3d.regs;
1336 if (regs.fill_rectangle) {
1367 if (!GLAD_GL_NV_fill_rectangle) { 1337 if (!GLAD_GL_NV_fill_rectangle) {
1368 LOG_ERROR(Render_OpenGL, "GL_NV_fill_rectangle used and not supported"); 1338 LOG_ERROR(Render_OpenGL, "GL_NV_fill_rectangle used and not supported");
1369 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 1339 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@@ -1376,27 +1346,26 @@ void RasterizerOpenGL::SyncPolygonModes() {
1376 return; 1346 return;
1377 } 1347 }
1378 1348
1379 if (gpu.regs.polygon_mode_front == gpu.regs.polygon_mode_back) { 1349 if (regs.polygon_mode_front == regs.polygon_mode_back) {
1380 flags[Dirty::PolygonModeFront] = false; 1350 flags[Dirty::PolygonModeFront] = false;
1381 flags[Dirty::PolygonModeBack] = false; 1351 flags[Dirty::PolygonModeBack] = false;
1382 glPolygonMode(GL_FRONT_AND_BACK, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_front)); 1352 glPolygonMode(GL_FRONT_AND_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_front));
1383 return; 1353 return;
1384 } 1354 }
1385 1355
1386 if (flags[Dirty::PolygonModeFront]) { 1356 if (flags[Dirty::PolygonModeFront]) {
1387 flags[Dirty::PolygonModeFront] = false; 1357 flags[Dirty::PolygonModeFront] = false;
1388 glPolygonMode(GL_FRONT, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_front)); 1358 glPolygonMode(GL_FRONT, MaxwellToGL::PolygonMode(regs.polygon_mode_front));
1389 } 1359 }
1390 1360
1391 if (flags[Dirty::PolygonModeBack]) { 1361 if (flags[Dirty::PolygonModeBack]) {
1392 flags[Dirty::PolygonModeBack] = false; 1362 flags[Dirty::PolygonModeBack] = false;
1393 glPolygonMode(GL_BACK, MaxwellToGL::PolygonMode(gpu.regs.polygon_mode_back)); 1363 glPolygonMode(GL_BACK, MaxwellToGL::PolygonMode(regs.polygon_mode_back));
1394 } 1364 }
1395} 1365}
1396 1366
1397void RasterizerOpenGL::SyncColorMask() { 1367void RasterizerOpenGL::SyncColorMask() {
1398 auto& gpu = system.GPU().Maxwell3D(); 1368 auto& flags = maxwell3d.dirty.flags;
1399 auto& flags = gpu.dirty.flags;
1400 if (!flags[Dirty::ColorMasks]) { 1369 if (!flags[Dirty::ColorMasks]) {
1401 return; 1370 return;
1402 } 1371 }
@@ -1405,7 +1374,7 @@ void RasterizerOpenGL::SyncColorMask() {
1405 const bool force = flags[Dirty::ColorMaskCommon]; 1374 const bool force = flags[Dirty::ColorMaskCommon];
1406 flags[Dirty::ColorMaskCommon] = false; 1375 flags[Dirty::ColorMaskCommon] = false;
1407 1376
1408 const auto& regs = gpu.regs; 1377 const auto& regs = maxwell3d.regs;
1409 if (regs.color_mask_common) { 1378 if (regs.color_mask_common) {
1410 if (!force && !flags[Dirty::ColorMask0]) { 1379 if (!force && !flags[Dirty::ColorMask0]) {
1411 return; 1380 return;
@@ -1430,33 +1399,30 @@ void RasterizerOpenGL::SyncColorMask() {
1430} 1399}
1431 1400
1432void RasterizerOpenGL::SyncMultiSampleState() { 1401void RasterizerOpenGL::SyncMultiSampleState() {
1433 auto& gpu = system.GPU().Maxwell3D(); 1402 auto& flags = maxwell3d.dirty.flags;
1434 auto& flags = gpu.dirty.flags;
1435 if (!flags[Dirty::MultisampleControl]) { 1403 if (!flags[Dirty::MultisampleControl]) {
1436 return; 1404 return;
1437 } 1405 }
1438 flags[Dirty::MultisampleControl] = false; 1406 flags[Dirty::MultisampleControl] = false;
1439 1407
1440 const auto& regs = system.GPU().Maxwell3D().regs; 1408 const auto& regs = maxwell3d.regs;
1441 oglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE, regs.multisample_control.alpha_to_coverage); 1409 oglEnable(GL_SAMPLE_ALPHA_TO_COVERAGE, regs.multisample_control.alpha_to_coverage);
1442 oglEnable(GL_SAMPLE_ALPHA_TO_ONE, regs.multisample_control.alpha_to_one); 1410 oglEnable(GL_SAMPLE_ALPHA_TO_ONE, regs.multisample_control.alpha_to_one);
1443} 1411}
1444 1412
1445void RasterizerOpenGL::SyncFragmentColorClampState() { 1413void RasterizerOpenGL::SyncFragmentColorClampState() {
1446 auto& gpu = system.GPU().Maxwell3D(); 1414 auto& flags = maxwell3d.dirty.flags;
1447 auto& flags = gpu.dirty.flags;
1448 if (!flags[Dirty::FragmentClampColor]) { 1415 if (!flags[Dirty::FragmentClampColor]) {
1449 return; 1416 return;
1450 } 1417 }
1451 flags[Dirty::FragmentClampColor] = false; 1418 flags[Dirty::FragmentClampColor] = false;
1452 1419
1453 glClampColor(GL_CLAMP_FRAGMENT_COLOR, gpu.regs.frag_color_clamp ? GL_TRUE : GL_FALSE); 1420 glClampColor(GL_CLAMP_FRAGMENT_COLOR, maxwell3d.regs.frag_color_clamp ? GL_TRUE : GL_FALSE);
1454} 1421}
1455 1422
1456void RasterizerOpenGL::SyncBlendState() { 1423void RasterizerOpenGL::SyncBlendState() {
1457 auto& gpu = system.GPU().Maxwell3D(); 1424 auto& flags = maxwell3d.dirty.flags;
1458 auto& flags = gpu.dirty.flags; 1425 const auto& regs = maxwell3d.regs;
1459 const auto& regs = gpu.regs;
1460 1426
1461 if (flags[Dirty::BlendColor]) { 1427 if (flags[Dirty::BlendColor]) {
1462 flags[Dirty::BlendColor] = false; 1428 flags[Dirty::BlendColor] = false;
@@ -1513,14 +1479,13 @@ void RasterizerOpenGL::SyncBlendState() {
1513} 1479}
1514 1480
1515void RasterizerOpenGL::SyncLogicOpState() { 1481void RasterizerOpenGL::SyncLogicOpState() {
1516 auto& gpu = system.GPU().Maxwell3D(); 1482 auto& flags = maxwell3d.dirty.flags;
1517 auto& flags = gpu.dirty.flags;
1518 if (!flags[Dirty::LogicOp]) { 1483 if (!flags[Dirty::LogicOp]) {
1519 return; 1484 return;
1520 } 1485 }
1521 flags[Dirty::LogicOp] = false; 1486 flags[Dirty::LogicOp] = false;
1522 1487
1523 const auto& regs = gpu.regs; 1488 const auto& regs = maxwell3d.regs;
1524 if (regs.logic_op.enable) { 1489 if (regs.logic_op.enable) {
1525 glEnable(GL_COLOR_LOGIC_OP); 1490 glEnable(GL_COLOR_LOGIC_OP);
1526 glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.operation)); 1491 glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.operation));
@@ -1530,14 +1495,13 @@ void RasterizerOpenGL::SyncLogicOpState() {
1530} 1495}
1531 1496
1532void RasterizerOpenGL::SyncScissorTest() { 1497void RasterizerOpenGL::SyncScissorTest() {
1533 auto& gpu = system.GPU().Maxwell3D(); 1498 auto& flags = maxwell3d.dirty.flags;
1534 auto& flags = gpu.dirty.flags;
1535 if (!flags[Dirty::Scissors]) { 1499 if (!flags[Dirty::Scissors]) {
1536 return; 1500 return;
1537 } 1501 }
1538 flags[Dirty::Scissors] = false; 1502 flags[Dirty::Scissors] = false;
1539 1503
1540 const auto& regs = gpu.regs; 1504 const auto& regs = maxwell3d.regs;
1541 for (std::size_t index = 0; index < Maxwell::NumViewports; ++index) { 1505 for (std::size_t index = 0; index < Maxwell::NumViewports; ++index) {
1542 if (!flags[Dirty::Scissor0 + index]) { 1506 if (!flags[Dirty::Scissor0 + index]) {
1543 continue; 1507 continue;
@@ -1556,16 +1520,15 @@ void RasterizerOpenGL::SyncScissorTest() {
1556} 1520}
1557 1521
1558void RasterizerOpenGL::SyncPointState() { 1522void RasterizerOpenGL::SyncPointState() {
1559 auto& gpu = system.GPU().Maxwell3D(); 1523 auto& flags = maxwell3d.dirty.flags;
1560 auto& flags = gpu.dirty.flags;
1561 if (!flags[Dirty::PointSize]) { 1524 if (!flags[Dirty::PointSize]) {
1562 return; 1525 return;
1563 } 1526 }
1564 flags[Dirty::PointSize] = false; 1527 flags[Dirty::PointSize] = false;
1565 1528
1566 oglEnable(GL_POINT_SPRITE, gpu.regs.point_sprite_enable); 1529 oglEnable(GL_POINT_SPRITE, maxwell3d.regs.point_sprite_enable);
1567 1530
1568 if (gpu.regs.vp_point_size.enable) { 1531 if (maxwell3d.regs.vp_point_size.enable) {
1569 // By definition of GL_POINT_SIZE, it only matters if GL_PROGRAM_POINT_SIZE is disabled. 1532 // By definition of GL_POINT_SIZE, it only matters if GL_PROGRAM_POINT_SIZE is disabled.
1570 glEnable(GL_PROGRAM_POINT_SIZE); 1533 glEnable(GL_PROGRAM_POINT_SIZE);
1571 return; 1534 return;
@@ -1573,32 +1536,30 @@ void RasterizerOpenGL::SyncPointState() {
1573 1536
1574 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid 1537 // Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
1575 // in OpenGL). 1538 // in OpenGL).
1576 glPointSize(std::max(1.0f, gpu.regs.point_size)); 1539 glPointSize(std::max(1.0f, maxwell3d.regs.point_size));
1577 glDisable(GL_PROGRAM_POINT_SIZE); 1540 glDisable(GL_PROGRAM_POINT_SIZE);
1578} 1541}
1579 1542
1580void RasterizerOpenGL::SyncLineState() { 1543void RasterizerOpenGL::SyncLineState() {
1581 auto& gpu = system.GPU().Maxwell3D(); 1544 auto& flags = maxwell3d.dirty.flags;
1582 auto& flags = gpu.dirty.flags;
1583 if (!flags[Dirty::LineWidth]) { 1545 if (!flags[Dirty::LineWidth]) {
1584 return; 1546 return;
1585 } 1547 }
1586 flags[Dirty::LineWidth] = false; 1548 flags[Dirty::LineWidth] = false;
1587 1549
1588 const auto& regs = gpu.regs; 1550 const auto& regs = maxwell3d.regs;
1589 oglEnable(GL_LINE_SMOOTH, regs.line_smooth_enable); 1551 oglEnable(GL_LINE_SMOOTH, regs.line_smooth_enable);
1590 glLineWidth(regs.line_smooth_enable ? regs.line_width_smooth : regs.line_width_aliased); 1552 glLineWidth(regs.line_smooth_enable ? regs.line_width_smooth : regs.line_width_aliased);
1591} 1553}
1592 1554
1593void RasterizerOpenGL::SyncPolygonOffset() { 1555void RasterizerOpenGL::SyncPolygonOffset() {
1594 auto& gpu = system.GPU().Maxwell3D(); 1556 auto& flags = maxwell3d.dirty.flags;
1595 auto& flags = gpu.dirty.flags;
1596 if (!flags[Dirty::PolygonOffset]) { 1557 if (!flags[Dirty::PolygonOffset]) {
1597 return; 1558 return;
1598 } 1559 }
1599 flags[Dirty::PolygonOffset] = false; 1560 flags[Dirty::PolygonOffset] = false;
1600 1561
1601 const auto& regs = gpu.regs; 1562 const auto& regs = maxwell3d.regs;
1602 oglEnable(GL_POLYGON_OFFSET_FILL, regs.polygon_offset_fill_enable); 1563 oglEnable(GL_POLYGON_OFFSET_FILL, regs.polygon_offset_fill_enable);
1603 oglEnable(GL_POLYGON_OFFSET_LINE, regs.polygon_offset_line_enable); 1564 oglEnable(GL_POLYGON_OFFSET_LINE, regs.polygon_offset_line_enable);
1604 oglEnable(GL_POLYGON_OFFSET_POINT, regs.polygon_offset_point_enable); 1565 oglEnable(GL_POLYGON_OFFSET_POINT, regs.polygon_offset_point_enable);
@@ -1612,14 +1573,13 @@ void RasterizerOpenGL::SyncPolygonOffset() {
1612} 1573}
1613 1574
1614void RasterizerOpenGL::SyncAlphaTest() { 1575void RasterizerOpenGL::SyncAlphaTest() {
1615 auto& gpu = system.GPU().Maxwell3D(); 1576 auto& flags = maxwell3d.dirty.flags;
1616 auto& flags = gpu.dirty.flags;
1617 if (!flags[Dirty::AlphaTest]) { 1577 if (!flags[Dirty::AlphaTest]) {
1618 return; 1578 return;
1619 } 1579 }
1620 flags[Dirty::AlphaTest] = false; 1580 flags[Dirty::AlphaTest] = false;
1621 1581
1622 const auto& regs = gpu.regs; 1582 const auto& regs = maxwell3d.regs;
1623 if (regs.alpha_test_enabled && regs.rt_control.count > 1) { 1583 if (regs.alpha_test_enabled && regs.rt_control.count > 1) {
1624 LOG_WARNING(Render_OpenGL, "Alpha testing with more than one render target is not tested"); 1584 LOG_WARNING(Render_OpenGL, "Alpha testing with more than one render target is not tested");
1625 } 1585 }
@@ -1633,20 +1593,19 @@ void RasterizerOpenGL::SyncAlphaTest() {
1633} 1593}
1634 1594
1635void RasterizerOpenGL::SyncFramebufferSRGB() { 1595void RasterizerOpenGL::SyncFramebufferSRGB() {
1636 auto& gpu = system.GPU().Maxwell3D(); 1596 auto& flags = maxwell3d.dirty.flags;
1637 auto& flags = gpu.dirty.flags;
1638 if (!flags[Dirty::FramebufferSRGB]) { 1597 if (!flags[Dirty::FramebufferSRGB]) {
1639 return; 1598 return;
1640 } 1599 }
1641 flags[Dirty::FramebufferSRGB] = false; 1600 flags[Dirty::FramebufferSRGB] = false;
1642 1601
1643 oglEnable(GL_FRAMEBUFFER_SRGB, gpu.regs.framebuffer_srgb); 1602 oglEnable(GL_FRAMEBUFFER_SRGB, maxwell3d.regs.framebuffer_srgb);
1644} 1603}
1645 1604
1646void RasterizerOpenGL::SyncTransformFeedback() { 1605void RasterizerOpenGL::SyncTransformFeedback() {
1647 // TODO(Rodrigo): Inject SKIP_COMPONENTS*_NV when required. An unimplemented message will signal 1606 // TODO(Rodrigo): Inject SKIP_COMPONENTS*_NV when required. An unimplemented message will signal
1648 // when this is required. 1607 // when this is required.
1649 const auto& regs = system.GPU().Maxwell3D().regs; 1608 const auto& regs = maxwell3d.regs;
1650 1609
1651 static constexpr std::size_t STRIDE = 3; 1610 static constexpr std::size_t STRIDE = 3;
1652 std::array<GLint, 128 * STRIDE * Maxwell::NumTransformFeedbackBuffers> attribs; 1611 std::array<GLint, 128 * STRIDE * Maxwell::NumTransformFeedbackBuffers> attribs;
@@ -1698,7 +1657,7 @@ void RasterizerOpenGL::SyncTransformFeedback() {
1698} 1657}
1699 1658
1700void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) { 1659void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
1701 const auto& regs = system.GPU().Maxwell3D().regs; 1660 const auto& regs = maxwell3d.regs;
1702 if (regs.tfb_enabled == 0) { 1661 if (regs.tfb_enabled == 0) {
1703 return; 1662 return;
1704 } 1663 }
@@ -1741,7 +1700,7 @@ void RasterizerOpenGL::BeginTransformFeedback(GLenum primitive_mode) {
1741} 1700}
1742 1701
1743void RasterizerOpenGL::EndTransformFeedback() { 1702void RasterizerOpenGL::EndTransformFeedback() {
1744 const auto& regs = system.GPU().Maxwell3D().regs; 1703 const auto& regs = maxwell3d.regs;
1745 if (regs.tfb_enabled == 0) { 1704 if (regs.tfb_enabled == 0) {
1746 return; 1705 return;
1747 } 1706 }
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index ccc6f50f6..f451404b2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -36,8 +36,8 @@
36#include "video_core/shader/async_shaders.h" 36#include "video_core/shader/async_shaders.h"
37#include "video_core/textures/texture.h" 37#include "video_core/textures/texture.h"
38 38
39namespace Core { 39namespace Core::Memory {
40class System; 40class Memory;
41} 41}
42 42
43namespace Core::Frontend { 43namespace Core::Frontend {
@@ -55,9 +55,10 @@ struct DrawParameters;
55 55
56class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { 56class RasterizerOpenGL : public VideoCore::RasterizerAccelerated {
57public: 57public:
58 explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 58 explicit RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
59 const Device& device, ScreenInfo& info, 59 Core::Memory::Memory& cpu_memory, const Device& device,
60 ProgramManager& program_manager, StateTracker& state_tracker); 60 ScreenInfo& screen_info, ProgramManager& program_manager,
61 StateTracker& state_tracker);
61 ~RasterizerOpenGL() override; 62 ~RasterizerOpenGL() override;
62 63
63 void Draw(bool is_indexed, bool is_instanced) override; 64 void Draw(bool is_indexed, bool is_instanced) override;
@@ -83,9 +84,8 @@ public:
83 const Tegra::Engines::Fermi2D::Config& copy_config) override; 84 const Tegra::Engines::Fermi2D::Config& copy_config) override;
84 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 85 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
85 u32 pixel_stride) override; 86 u32 pixel_stride) override;
86 void LoadDiskResources(const std::atomic_bool& stop_loading, 87 void LoadDiskResources(u64 title_id, const std::atomic_bool& stop_loading,
87 const VideoCore::DiskResourceLoadCallback& callback) override; 88 const VideoCore::DiskResourceLoadCallback& callback) override;
88 void SetupDirtyFlags() override;
89 89
90 /// Returns true when there are commands queued to the OpenGL server. 90 /// Returns true when there are commands queued to the OpenGL server.
91 bool AnyCommandQueued() const { 91 bool AnyCommandQueued() const {
@@ -237,7 +237,15 @@ private:
237 237
238 void SetupShaders(GLenum primitive_mode); 238 void SetupShaders(GLenum primitive_mode);
239 239
240 Tegra::GPU& gpu;
241 Tegra::Engines::Maxwell3D& maxwell3d;
242 Tegra::Engines::KeplerCompute& kepler_compute;
243 Tegra::MemoryManager& gpu_memory;
244
240 const Device& device; 245 const Device& device;
246 ScreenInfo& screen_info;
247 ProgramManager& program_manager;
248 StateTracker& state_tracker;
241 249
242 TextureCacheOpenGL texture_cache; 250 TextureCacheOpenGL texture_cache;
243 ShaderCacheOpenGL shader_cache; 251 ShaderCacheOpenGL shader_cache;
@@ -247,10 +255,6 @@ private:
247 OGLBufferCache buffer_cache; 255 OGLBufferCache buffer_cache;
248 FenceManagerOpenGL fence_manager; 256 FenceManagerOpenGL fence_manager;
249 257
250 Core::System& system;
251 ScreenInfo& screen_info;
252 ProgramManager& program_manager;
253 StateTracker& state_tracker;
254 VideoCommon::Shader::AsyncShaders async_shaders; 258 VideoCommon::Shader::AsyncShaders async_shaders;
255 259
256 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 260 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index a07d56ef0..bd56bed0c 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -239,12 +239,11 @@ std::unique_ptr<Shader> Shader::CreateStageFromMemory(
239 ProgramCode code_b, VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr) { 239 ProgramCode code_b, VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr) {
240 const auto shader_type = GetShaderType(program_type); 240 const auto shader_type = GetShaderType(program_type);
241 241
242 auto& gpu = params.system.GPU(); 242 auto& gpu = params.gpu;
243 gpu.ShaderNotify().MarkSharderBuilding(); 243 gpu.ShaderNotify().MarkSharderBuilding();
244 244
245 auto registry = std::make_shared<Registry>(shader_type, gpu.Maxwell3D()); 245 auto registry = std::make_shared<Registry>(shader_type, gpu.Maxwell3D());
246 if (!async_shaders.IsShaderAsync(params.system.GPU()) || 246 if (!async_shaders.IsShaderAsync(gpu) || !params.device.UseAsynchronousShaders()) {
247 !params.device.UseAsynchronousShaders()) {
248 const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry); 247 const ShaderIR ir(code, STAGE_MAIN_OFFSET, COMPILER_SETTINGS, *registry);
249 // TODO(Rodrigo): Handle VertexA shaders 248 // TODO(Rodrigo): Handle VertexA shaders
250 // std::optional<ShaderIR> ir_b; 249 // std::optional<ShaderIR> ir_b;
@@ -287,11 +286,10 @@ std::unique_ptr<Shader> Shader::CreateStageFromMemory(
287 286
288std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params, 287std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params,
289 ProgramCode code) { 288 ProgramCode code) {
290 auto& gpu = params.system.GPU(); 289 auto& gpu = params.gpu;
291 gpu.ShaderNotify().MarkSharderBuilding(); 290 gpu.ShaderNotify().MarkSharderBuilding();
292 291
293 auto& engine = gpu.KeplerCompute(); 292 auto registry = std::make_shared<Registry>(ShaderType::Compute, params.engine);
294 auto registry = std::make_shared<Registry>(ShaderType::Compute, engine);
295 const ShaderIR ir(code, KERNEL_MAIN_OFFSET, COMPILER_SETTINGS, *registry); 293 const ShaderIR ir(code, KERNEL_MAIN_OFFSET, COMPILER_SETTINGS, *registry);
296 const u64 uid = params.unique_identifier; 294 const u64 uid = params.unique_identifier;
297 auto program = BuildShader(params.device, ShaderType::Compute, uid, ir, *registry); 295 auto program = BuildShader(params.device, ShaderType::Compute, uid, ir, *registry);
@@ -320,15 +318,20 @@ std::unique_ptr<Shader> Shader::CreateFromCache(const ShaderParameters& params,
320 precompiled_shader.registry, precompiled_shader.entries, precompiled_shader.program)); 318 precompiled_shader.registry, precompiled_shader.entries, precompiled_shader.program));
321} 319}
322 320
323ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, 321ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer,
324 Core::Frontend::EmuWindow& emu_window, const Device& device) 322 Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
325 : VideoCommon::ShaderCache<Shader>{rasterizer}, system{system}, 323 Tegra::Engines::Maxwell3D& maxwell3d_,
326 emu_window{emu_window}, device{device}, disk_cache{system} {} 324 Tegra::Engines::KeplerCompute& kepler_compute_,
325 Tegra::MemoryManager& gpu_memory_, const Device& device_)
326 : VideoCommon::ShaderCache<Shader>{rasterizer}, emu_window{emu_window_}, gpu{gpu_},
327 gpu_memory{gpu_memory_}, maxwell3d{maxwell3d_},
328 kepler_compute{kepler_compute_}, device{device_} {}
327 329
328ShaderCacheOpenGL::~ShaderCacheOpenGL() = default; 330ShaderCacheOpenGL::~ShaderCacheOpenGL() = default;
329 331
330void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, 332void ShaderCacheOpenGL::LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
331 const VideoCore::DiskResourceLoadCallback& callback) { 333 const VideoCore::DiskResourceLoadCallback& callback) {
334 disk_cache.BindTitleID(title_id);
332 const std::optional transferable = disk_cache.LoadTransferable(); 335 const std::optional transferable = disk_cache.LoadTransferable();
333 if (!transferable) { 336 if (!transferable) {
334 return; 337 return;
@@ -481,21 +484,19 @@ ProgramSharedPtr ShaderCacheOpenGL::GeneratePrecompiledProgram(
481 484
482Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program, 485Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
483 VideoCommon::Shader::AsyncShaders& async_shaders) { 486 VideoCommon::Shader::AsyncShaders& async_shaders) {
484 if (!system.GPU().Maxwell3D().dirty.flags[Dirty::Shaders]) { 487 if (!maxwell3d.dirty.flags[Dirty::Shaders]) {
485 auto* last_shader = last_shaders[static_cast<std::size_t>(program)]; 488 auto* last_shader = last_shaders[static_cast<std::size_t>(program)];
486 if (last_shader->IsBuilt()) { 489 if (last_shader->IsBuilt()) {
487 return last_shader; 490 return last_shader;
488 } 491 }
489 } 492 }
490 493
491 auto& memory_manager{system.GPU().MemoryManager()}; 494 const GPUVAddr address{GetShaderAddress(maxwell3d, program)};
492 const GPUVAddr address{GetShaderAddress(system, program)};
493 495
494 if (device.UseAsynchronousShaders() && async_shaders.HasCompletedWork()) { 496 if (device.UseAsynchronousShaders() && async_shaders.HasCompletedWork()) {
495 auto completed_work = async_shaders.GetCompletedWork(); 497 auto completed_work = async_shaders.GetCompletedWork();
496 for (auto& work : completed_work) { 498 for (auto& work : completed_work) {
497 Shader* shader = TryGet(work.cpu_address); 499 Shader* shader = TryGet(work.cpu_address);
498 auto& gpu = system.GPU();
499 gpu.ShaderNotify().MarkShaderComplete(); 500 gpu.ShaderNotify().MarkShaderComplete();
500 if (shader == nullptr) { 501 if (shader == nullptr) {
501 continue; 502 continue;
@@ -507,14 +508,13 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
507 shader->AsyncGLASMBuilt(std::move(work.program.glasm)); 508 shader->AsyncGLASMBuilt(std::move(work.program.glasm));
508 } 509 }
509 510
511 auto& registry = shader->GetRegistry();
512
510 ShaderDiskCacheEntry entry; 513 ShaderDiskCacheEntry entry;
511 entry.type = work.shader_type; 514 entry.type = work.shader_type;
512 entry.code = std::move(work.code); 515 entry.code = std::move(work.code);
513 entry.code_b = std::move(work.code_b); 516 entry.code_b = std::move(work.code_b);
514 entry.unique_identifier = work.uid; 517 entry.unique_identifier = work.uid;
515
516 auto& registry = shader->GetRegistry();
517
518 entry.bound_buffer = registry.GetBoundBuffer(); 518 entry.bound_buffer = registry.GetBoundBuffer();
519 entry.graphics_info = registry.GetGraphicsInfo(); 519 entry.graphics_info = registry.GetGraphicsInfo();
520 entry.keys = registry.GetKeys(); 520 entry.keys = registry.GetKeys();
@@ -525,28 +525,28 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
525 } 525 }
526 526
527 // Look up shader in the cache based on address 527 // Look up shader in the cache based on address
528 const auto cpu_addr{memory_manager.GpuToCpuAddress(address)}; 528 const std::optional<VAddr> cpu_addr{gpu_memory.GpuToCpuAddress(address)};
529 if (Shader* const shader{cpu_addr ? TryGet(*cpu_addr) : null_shader.get()}) { 529 if (Shader* const shader{cpu_addr ? TryGet(*cpu_addr) : null_shader.get()}) {
530 return last_shaders[static_cast<std::size_t>(program)] = shader; 530 return last_shaders[static_cast<std::size_t>(program)] = shader;
531 } 531 }
532 532
533 const auto host_ptr{memory_manager.GetPointer(address)}; 533 const u8* const host_ptr{gpu_memory.GetPointer(address)};
534 534
535 // No shader found - create a new one 535 // No shader found - create a new one
536 ProgramCode code{GetShaderCode(memory_manager, address, host_ptr, false)}; 536 ProgramCode code{GetShaderCode(gpu_memory, address, host_ptr, false)};
537 ProgramCode code_b; 537 ProgramCode code_b;
538 if (program == Maxwell::ShaderProgram::VertexA) { 538 if (program == Maxwell::ShaderProgram::VertexA) {
539 const GPUVAddr address_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)}; 539 const GPUVAddr address_b{GetShaderAddress(maxwell3d, Maxwell::ShaderProgram::VertexB)};
540 const u8* host_ptr_b = memory_manager.GetPointer(address_b); 540 const u8* host_ptr_b = gpu_memory.GetPointer(address_b);
541 code_b = GetShaderCode(memory_manager, address_b, host_ptr_b, false); 541 code_b = GetShaderCode(gpu_memory, address_b, host_ptr_b, false);
542 } 542 }
543 const std::size_t code_size = code.size() * sizeof(u64); 543 const std::size_t code_size = code.size() * sizeof(u64);
544 544
545 const u64 unique_identifier = GetUniqueIdentifier( 545 const u64 unique_identifier = GetUniqueIdentifier(
546 GetShaderType(program), program == Maxwell::ShaderProgram::VertexA, code, code_b); 546 GetShaderType(program), program == Maxwell::ShaderProgram::VertexA, code, code_b);
547 547
548 const ShaderParameters params{system, disk_cache, device, 548 const ShaderParameters params{gpu, maxwell3d, disk_cache, device,
549 *cpu_addr, host_ptr, unique_identifier}; 549 *cpu_addr, host_ptr, unique_identifier};
550 550
551 std::unique_ptr<Shader> shader; 551 std::unique_ptr<Shader> shader;
552 const auto found = runtime_cache.find(unique_identifier); 552 const auto found = runtime_cache.find(unique_identifier);
@@ -568,21 +568,20 @@ Shader* ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program,
568} 568}
569 569
570Shader* ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) { 570Shader* ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) {
571 auto& memory_manager{system.GPU().MemoryManager()}; 571 const std::optional<VAddr> cpu_addr{gpu_memory.GpuToCpuAddress(code_addr)};
572 const auto cpu_addr{memory_manager.GpuToCpuAddress(code_addr)};
573 572
574 if (Shader* const kernel = cpu_addr ? TryGet(*cpu_addr) : null_kernel.get()) { 573 if (Shader* const kernel = cpu_addr ? TryGet(*cpu_addr) : null_kernel.get()) {
575 return kernel; 574 return kernel;
576 } 575 }
577 576
578 const auto host_ptr{memory_manager.GetPointer(code_addr)};
579 // No kernel found, create a new one 577 // No kernel found, create a new one
580 ProgramCode code{GetShaderCode(memory_manager, code_addr, host_ptr, true)}; 578 const u8* host_ptr{gpu_memory.GetPointer(code_addr)};
579 ProgramCode code{GetShaderCode(gpu_memory, code_addr, host_ptr, true)};
581 const std::size_t code_size{code.size() * sizeof(u64)}; 580 const std::size_t code_size{code.size() * sizeof(u64)};
582 const u64 unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)}; 581 const u64 unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)};
583 582
584 const ShaderParameters params{system, disk_cache, device, 583 const ShaderParameters params{gpu, kepler_compute, disk_cache, device,
585 *cpu_addr, host_ptr, unique_identifier}; 584 *cpu_addr, host_ptr, unique_identifier};
586 585
587 std::unique_ptr<Shader> kernel; 586 std::unique_ptr<Shader> kernel;
588 const auto found = runtime_cache.find(unique_identifier); 587 const auto found = runtime_cache.find(unique_identifier);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 7528ac686..1708af06a 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -25,8 +25,8 @@
25#include "video_core/shader/shader_ir.h" 25#include "video_core/shader/shader_ir.h"
26#include "video_core/shader_cache.h" 26#include "video_core/shader_cache.h"
27 27
28namespace Core { 28namespace Tegra {
29class System; 29class MemoryManager;
30} 30}
31 31
32namespace Core::Frontend { 32namespace Core::Frontend {
@@ -57,11 +57,12 @@ struct PrecompiledShader {
57}; 57};
58 58
59struct ShaderParameters { 59struct ShaderParameters {
60 Core::System& system; 60 Tegra::GPU& gpu;
61 Tegra::Engines::ConstBufferEngineInterface& engine;
61 ShaderDiskCacheOpenGL& disk_cache; 62 ShaderDiskCacheOpenGL& disk_cache;
62 const Device& device; 63 const Device& device;
63 VAddr cpu_addr; 64 VAddr cpu_addr;
64 u8* host_ptr; 65 const u8* host_ptr;
65 u64 unique_identifier; 66 u64 unique_identifier;
66}; 67};
67 68
@@ -118,12 +119,14 @@ private:
118 119
119class ShaderCacheOpenGL final : public VideoCommon::ShaderCache<Shader> { 120class ShaderCacheOpenGL final : public VideoCommon::ShaderCache<Shader> {
120public: 121public:
121 explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, 122 explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::Frontend::EmuWindow& emu_window,
122 Core::Frontend::EmuWindow& emu_window, const Device& device); 123 Tegra::GPU& gpu, Tegra::Engines::Maxwell3D& maxwell3d,
124 Tegra::Engines::KeplerCompute& kepler_compute,
125 Tegra::MemoryManager& gpu_memory, const Device& device);
123 ~ShaderCacheOpenGL() override; 126 ~ShaderCacheOpenGL() override;
124 127
125 /// Loads disk cache for the current game 128 /// Loads disk cache for the current game
126 void LoadDiskCache(const std::atomic_bool& stop_loading, 129 void LoadDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
127 const VideoCore::DiskResourceLoadCallback& callback); 130 const VideoCore::DiskResourceLoadCallback& callback);
128 131
129 /// Gets the current specified shader stage program 132 /// Gets the current specified shader stage program
@@ -138,9 +141,13 @@ private:
138 const ShaderDiskCacheEntry& entry, const ShaderDiskCachePrecompiled& precompiled_entry, 141 const ShaderDiskCacheEntry& entry, const ShaderDiskCachePrecompiled& precompiled_entry,
139 const std::unordered_set<GLenum>& supported_formats); 142 const std::unordered_set<GLenum>& supported_formats);
140 143
141 Core::System& system;
142 Core::Frontend::EmuWindow& emu_window; 144 Core::Frontend::EmuWindow& emu_window;
145 Tegra::GPU& gpu;
146 Tegra::MemoryManager& gpu_memory;
147 Tegra::Engines::Maxwell3D& maxwell3d;
148 Tegra::Engines::KeplerCompute& kepler_compute;
143 const Device& device; 149 const Device& device;
150
144 ShaderDiskCacheOpenGL disk_cache; 151 ShaderDiskCacheOpenGL disk_cache;
145 std::unordered_map<u64, PrecompiledShader> runtime_cache; 152 std::unordered_map<u64, PrecompiledShader> runtime_cache;
146 153
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 40c0877c1..166ee34e1 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -206,13 +206,17 @@ bool ShaderDiskCacheEntry::Save(Common::FS::IOFile& file) const {
206 flat_bindless_samplers.size(); 206 flat_bindless_samplers.size();
207} 207}
208 208
209ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL(Core::System& system) : system{system} {} 209ShaderDiskCacheOpenGL::ShaderDiskCacheOpenGL() = default;
210 210
211ShaderDiskCacheOpenGL::~ShaderDiskCacheOpenGL() = default; 211ShaderDiskCacheOpenGL::~ShaderDiskCacheOpenGL() = default;
212 212
213void ShaderDiskCacheOpenGL::BindTitleID(u64 title_id_) {
214 title_id = title_id_;
215}
216
213std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTransferable() { 217std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTransferable() {
214 // Skip games without title id 218 // Skip games without title id
215 const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0; 219 const bool has_title_id = title_id != 0;
216 if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) { 220 if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) {
217 return std::nullopt; 221 return std::nullopt;
218 } 222 }
@@ -474,7 +478,7 @@ std::string ShaderDiskCacheOpenGL::GetBaseDir() const {
474} 478}
475 479
476std::string ShaderDiskCacheOpenGL::GetTitleID() const { 480std::string ShaderDiskCacheOpenGL::GetTitleID() const {
477 return fmt::format("{:016X}", system.CurrentProcess()->GetTitleID()); 481 return fmt::format("{:016X}", title_id);
478} 482}
479 483
480} // namespace OpenGL 484} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
index db2bb73bc..aef841c1d 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
@@ -21,10 +21,6 @@
21#include "video_core/engines/shader_type.h" 21#include "video_core/engines/shader_type.h"
22#include "video_core/shader/registry.h" 22#include "video_core/shader/registry.h"
23 23
24namespace Core {
25class System;
26}
27
28namespace Common::FS { 24namespace Common::FS {
29class IOFile; 25class IOFile;
30} 26}
@@ -70,9 +66,12 @@ struct ShaderDiskCachePrecompiled {
70 66
71class ShaderDiskCacheOpenGL { 67class ShaderDiskCacheOpenGL {
72public: 68public:
73 explicit ShaderDiskCacheOpenGL(Core::System& system); 69 explicit ShaderDiskCacheOpenGL();
74 ~ShaderDiskCacheOpenGL(); 70 ~ShaderDiskCacheOpenGL();
75 71
72 /// Binds a title ID for all future operations.
73 void BindTitleID(u64 title_id);
74
76 /// Loads transferable cache. If file has a old version or on failure, it deletes the file. 75 /// Loads transferable cache. If file has a old version or on failure, it deletes the file.
77 std::optional<std::vector<ShaderDiskCacheEntry>> LoadTransferable(); 76 std::optional<std::vector<ShaderDiskCacheEntry>> LoadTransferable();
78 77
@@ -157,8 +156,6 @@ private:
157 return LoadArrayFromPrecompiled(&object, 1); 156 return LoadArrayFromPrecompiled(&object, 1);
158 } 157 }
159 158
160 Core::System& system;
161
162 // Stores whole precompiled cache which will be read from or saved to the precompiled chache 159 // Stores whole precompiled cache which will be read from or saved to the precompiled chache
163 // file 160 // file
164 FileSys::VectorVfsFile precompiled_cache_virtual_file; 161 FileSys::VectorVfsFile precompiled_cache_virtual_file;
@@ -168,8 +165,11 @@ private:
168 // Stored transferable shaders 165 // Stored transferable shaders
169 std::unordered_set<u64> stored_transferable; 166 std::unordered_set<u64> stored_transferable;
170 167
168 /// Title ID to operate on
169 u64 title_id = 0;
170
171 // The cache has been loaded at boot 171 // The cache has been loaded at boot
172 bool is_usable{}; 172 bool is_usable = false;
173}; 173};
174 174
175} // namespace OpenGL 175} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp
index d24fad3de..6bcf831f2 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.cpp
+++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp
@@ -214,10 +214,8 @@ void SetupDirtyMisc(Tables& tables) {
214 214
215} // Anonymous namespace 215} // Anonymous namespace
216 216
217StateTracker::StateTracker(Core::System& system) : system{system} {} 217StateTracker::StateTracker(Tegra::GPU& gpu) : flags{gpu.Maxwell3D().dirty.flags} {
218 218 auto& dirty = gpu.Maxwell3D().dirty;
219void StateTracker::Initialize() {
220 auto& dirty = system.GPU().Maxwell3D().dirty;
221 auto& tables = dirty.tables; 219 auto& tables = dirty.tables;
222 SetupDirtyRenderTargets(tables); 220 SetupDirtyRenderTargets(tables);
223 SetupDirtyColorMasks(tables); 221 SetupDirtyColorMasks(tables);
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.h b/src/video_core/renderer_opengl/gl_state_tracker.h
index 0f823288e..9d127548f 100644
--- a/src/video_core/renderer_opengl/gl_state_tracker.h
+++ b/src/video_core/renderer_opengl/gl_state_tracker.h
@@ -13,8 +13,8 @@
13#include "video_core/dirty_flags.h" 13#include "video_core/dirty_flags.h"
14#include "video_core/engines/maxwell_3d.h" 14#include "video_core/engines/maxwell_3d.h"
15 15
16namespace Core { 16namespace Tegra {
17class System; 17class GPU;
18} 18}
19 19
20namespace OpenGL { 20namespace OpenGL {
@@ -90,9 +90,7 @@ static_assert(Last <= std::numeric_limits<u8>::max());
90 90
91class StateTracker { 91class StateTracker {
92public: 92public:
93 explicit StateTracker(Core::System& system); 93 explicit StateTracker(Tegra::GPU& gpu);
94
95 void Initialize();
96 94
97 void BindIndexBuffer(GLuint new_index_buffer) { 95 void BindIndexBuffer(GLuint new_index_buffer) {
98 if (index_buffer == new_index_buffer) { 96 if (index_buffer == new_index_buffer) {
@@ -103,7 +101,6 @@ public:
103 } 101 }
104 102
105 void NotifyScreenDrawVertexArray() { 103 void NotifyScreenDrawVertexArray() {
106 auto& flags = system.GPU().Maxwell3D().dirty.flags;
107 flags[OpenGL::Dirty::VertexFormats] = true; 104 flags[OpenGL::Dirty::VertexFormats] = true;
108 flags[OpenGL::Dirty::VertexFormat0 + 0] = true; 105 flags[OpenGL::Dirty::VertexFormat0 + 0] = true;
109 flags[OpenGL::Dirty::VertexFormat0 + 1] = true; 106 flags[OpenGL::Dirty::VertexFormat0 + 1] = true;
@@ -117,98 +114,81 @@ public:
117 } 114 }
118 115
119 void NotifyPolygonModes() { 116 void NotifyPolygonModes() {
120 auto& flags = system.GPU().Maxwell3D().dirty.flags;
121 flags[OpenGL::Dirty::PolygonModes] = true; 117 flags[OpenGL::Dirty::PolygonModes] = true;
122 flags[OpenGL::Dirty::PolygonModeFront] = true; 118 flags[OpenGL::Dirty::PolygonModeFront] = true;
123 flags[OpenGL::Dirty::PolygonModeBack] = true; 119 flags[OpenGL::Dirty::PolygonModeBack] = true;
124 } 120 }
125 121
126 void NotifyViewport0() { 122 void NotifyViewport0() {
127 auto& flags = system.GPU().Maxwell3D().dirty.flags;
128 flags[OpenGL::Dirty::Viewports] = true; 123 flags[OpenGL::Dirty::Viewports] = true;
129 flags[OpenGL::Dirty::Viewport0] = true; 124 flags[OpenGL::Dirty::Viewport0] = true;
130 } 125 }
131 126
132 void NotifyScissor0() { 127 void NotifyScissor0() {
133 auto& flags = system.GPU().Maxwell3D().dirty.flags;
134 flags[OpenGL::Dirty::Scissors] = true; 128 flags[OpenGL::Dirty::Scissors] = true;
135 flags[OpenGL::Dirty::Scissor0] = true; 129 flags[OpenGL::Dirty::Scissor0] = true;
136 } 130 }
137 131
138 void NotifyColorMask0() { 132 void NotifyColorMask0() {
139 auto& flags = system.GPU().Maxwell3D().dirty.flags;
140 flags[OpenGL::Dirty::ColorMasks] = true; 133 flags[OpenGL::Dirty::ColorMasks] = true;
141 flags[OpenGL::Dirty::ColorMask0] = true; 134 flags[OpenGL::Dirty::ColorMask0] = true;
142 } 135 }
143 136
144 void NotifyBlend0() { 137 void NotifyBlend0() {
145 auto& flags = system.GPU().Maxwell3D().dirty.flags;
146 flags[OpenGL::Dirty::BlendStates] = true; 138 flags[OpenGL::Dirty::BlendStates] = true;
147 flags[OpenGL::Dirty::BlendState0] = true; 139 flags[OpenGL::Dirty::BlendState0] = true;
148 } 140 }
149 141
150 void NotifyFramebuffer() { 142 void NotifyFramebuffer() {
151 auto& flags = system.GPU().Maxwell3D().dirty.flags;
152 flags[VideoCommon::Dirty::RenderTargets] = true; 143 flags[VideoCommon::Dirty::RenderTargets] = true;
153 } 144 }
154 145
155 void NotifyFrontFace() { 146 void NotifyFrontFace() {
156 auto& flags = system.GPU().Maxwell3D().dirty.flags;
157 flags[OpenGL::Dirty::FrontFace] = true; 147 flags[OpenGL::Dirty::FrontFace] = true;
158 } 148 }
159 149
160 void NotifyCullTest() { 150 void NotifyCullTest() {
161 auto& flags = system.GPU().Maxwell3D().dirty.flags;
162 flags[OpenGL::Dirty::CullTest] = true; 151 flags[OpenGL::Dirty::CullTest] = true;
163 } 152 }
164 153
165 void NotifyDepthMask() { 154 void NotifyDepthMask() {
166 auto& flags = system.GPU().Maxwell3D().dirty.flags;
167 flags[OpenGL::Dirty::DepthMask] = true; 155 flags[OpenGL::Dirty::DepthMask] = true;
168 } 156 }
169 157
170 void NotifyDepthTest() { 158 void NotifyDepthTest() {
171 auto& flags = system.GPU().Maxwell3D().dirty.flags;
172 flags[OpenGL::Dirty::DepthTest] = true; 159 flags[OpenGL::Dirty::DepthTest] = true;
173 } 160 }
174 161
175 void NotifyStencilTest() { 162 void NotifyStencilTest() {
176 auto& flags = system.GPU().Maxwell3D().dirty.flags;
177 flags[OpenGL::Dirty::StencilTest] = true; 163 flags[OpenGL::Dirty::StencilTest] = true;
178 } 164 }
179 165
180 void NotifyPolygonOffset() { 166 void NotifyPolygonOffset() {
181 auto& flags = system.GPU().Maxwell3D().dirty.flags;
182 flags[OpenGL::Dirty::PolygonOffset] = true; 167 flags[OpenGL::Dirty::PolygonOffset] = true;
183 } 168 }
184 169
185 void NotifyRasterizeEnable() { 170 void NotifyRasterizeEnable() {
186 auto& flags = system.GPU().Maxwell3D().dirty.flags;
187 flags[OpenGL::Dirty::RasterizeEnable] = true; 171 flags[OpenGL::Dirty::RasterizeEnable] = true;
188 } 172 }
189 173
190 void NotifyFramebufferSRGB() { 174 void NotifyFramebufferSRGB() {
191 auto& flags = system.GPU().Maxwell3D().dirty.flags;
192 flags[OpenGL::Dirty::FramebufferSRGB] = true; 175 flags[OpenGL::Dirty::FramebufferSRGB] = true;
193 } 176 }
194 177
195 void NotifyLogicOp() { 178 void NotifyLogicOp() {
196 auto& flags = system.GPU().Maxwell3D().dirty.flags;
197 flags[OpenGL::Dirty::LogicOp] = true; 179 flags[OpenGL::Dirty::LogicOp] = true;
198 } 180 }
199 181
200 void NotifyClipControl() { 182 void NotifyClipControl() {
201 auto& flags = system.GPU().Maxwell3D().dirty.flags;
202 flags[OpenGL::Dirty::ClipControl] = true; 183 flags[OpenGL::Dirty::ClipControl] = true;
203 } 184 }
204 185
205 void NotifyAlphaTest() { 186 void NotifyAlphaTest() {
206 auto& flags = system.GPU().Maxwell3D().dirty.flags;
207 flags[OpenGL::Dirty::AlphaTest] = true; 187 flags[OpenGL::Dirty::AlphaTest] = true;
208 } 188 }
209 189
210private: 190private:
211 Core::System& system; 191 Tegra::Engines::Maxwell3D::DirtyState::Flags& flags;
212 192
213 GLuint index_buffer = 0; 193 GLuint index_buffer = 0;
214}; 194};
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index f403f388a..a863ef218 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -532,10 +532,12 @@ OGLTextureView CachedSurfaceView::CreateTextureView() const {
532 return texture_view; 532 return texture_view;
533} 533}
534 534
535TextureCacheOpenGL::TextureCacheOpenGL(Core::System& system, 535TextureCacheOpenGL::TextureCacheOpenGL(VideoCore::RasterizerInterface& rasterizer,
536 VideoCore::RasterizerInterface& rasterizer, 536 Tegra::Engines::Maxwell3D& maxwell3d,
537 const Device& device, StateTracker& state_tracker) 537 Tegra::MemoryManager& gpu_memory, const Device& device,
538 : TextureCacheBase{system, rasterizer, device.HasASTC()}, state_tracker{state_tracker} { 538 StateTracker& state_tracker_)
539 : TextureCacheBase{rasterizer, maxwell3d, gpu_memory, device.HasASTC()}, state_tracker{
540 state_tracker_} {
539 src_framebuffer.Create(); 541 src_framebuffer.Create();
540 dst_framebuffer.Create(); 542 dst_framebuffer.Create();
541} 543}
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index de8f18489..7787134fc 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -129,8 +129,10 @@ private:
129 129
130class TextureCacheOpenGL final : public TextureCacheBase { 130class TextureCacheOpenGL final : public TextureCacheBase {
131public: 131public:
132 explicit TextureCacheOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 132 explicit TextureCacheOpenGL(VideoCore::RasterizerInterface& rasterizer,
133 const Device& device, StateTracker& state_tracker); 133 Tegra::Engines::Maxwell3D& maxwell3d,
134 Tegra::MemoryManager& gpu_memory, const Device& device,
135 StateTracker& state_tracker);
134 ~TextureCacheOpenGL(); 136 ~TextureCacheOpenGL();
135 137
136protected: 138protected:
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index b759c2dba..a4c5b8f74 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -275,11 +275,13 @@ public:
275 } 275 }
276}; 276};
277 277
278RendererOpenGL::RendererOpenGL(Core::System& system_, Core::Frontend::EmuWindow& emu_window_, 278RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
279 Tegra::GPU& gpu_, 279 Core::Frontend::EmuWindow& emu_window_,
280 std::unique_ptr<Core::Frontend::GraphicsContext> context_) 280 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
281 : RendererBase{emu_window_, std::move(context_)}, system{system_}, 281 std::unique_ptr<Core::Frontend::GraphicsContext> context)
282 emu_window{emu_window_}, gpu{gpu_}, program_manager{device}, has_debug_tool{HasDebugTool()} {} 282 : RendererBase{emu_window_, std::move(context)}, telemetry_session{telemetry_session_},
283 emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device},
284 has_debug_tool{HasDebugTool()} {}
283 285
284RendererOpenGL::~RendererOpenGL() = default; 286RendererOpenGL::~RendererOpenGL() = default;
285 287
@@ -386,7 +388,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
386 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)}; 388 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
387 const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)}; 389 const u32 bytes_per_pixel{VideoCore::Surface::GetBytesPerPixel(pixel_format)};
388 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel}; 390 const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
389 u8* const host_ptr{system.Memory().GetPointer(framebuffer_addr)}; 391 u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)};
390 rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes); 392 rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes);
391 393
392 // TODO(Rodrigo): Read this from HLE 394 // TODO(Rodrigo): Read this from HLE
@@ -471,7 +473,6 @@ void RendererOpenGL::AddTelemetryFields() {
471 LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor); 473 LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
472 LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model); 474 LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
473 475
474 auto& telemetry_session = system.TelemetrySession();
475 constexpr auto user_system = Common::Telemetry::FieldType::UserSystem; 476 constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
476 telemetry_session.AddField(user_system, "GPU_Vendor", gpu_vendor); 477 telemetry_session.AddField(user_system, "GPU_Vendor", gpu_vendor);
477 telemetry_session.AddField(user_system, "GPU_Model", gpu_model); 478 telemetry_session.AddField(user_system, "GPU_Model", gpu_model);
@@ -482,8 +483,8 @@ void RendererOpenGL::CreateRasterizer() {
482 if (rasterizer) { 483 if (rasterizer) {
483 return; 484 return;
484 } 485 }
485 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, device, screen_info, 486 rasterizer = std::make_unique<RasterizerOpenGL>(emu_window, gpu, cpu_memory, device,
486 program_manager, state_tracker); 487 screen_info, program_manager, state_tracker);
487} 488}
488 489
489void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, 490void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 52ea76b7d..5329577fb 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -16,16 +16,25 @@
16 16
17namespace Core { 17namespace Core {
18class System; 18class System;
19} 19class TelemetrySession;
20} // namespace Core
20 21
21namespace Core::Frontend { 22namespace Core::Frontend {
22class EmuWindow; 23class EmuWindow;
23} 24}
24 25
26namespace Core::Memory {
27class Memory;
28}
29
25namespace Layout { 30namespace Layout {
26struct FramebufferLayout; 31struct FramebufferLayout;
27} 32}
28 33
34namespace Tegra {
35class GPU;
36}
37
29namespace OpenGL { 38namespace OpenGL {
30 39
31/// Structure used for storing information about the textures for the Switch screen 40/// Structure used for storing information about the textures for the Switch screen
@@ -56,7 +65,8 @@ class FrameMailbox;
56 65
57class RendererOpenGL final : public VideoCore::RendererBase { 66class RendererOpenGL final : public VideoCore::RendererBase {
58public: 67public:
59 explicit RendererOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, 68 explicit RendererOpenGL(Core::TelemetrySession& telemetry_session,
69 Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory,
60 Tegra::GPU& gpu, 70 Tegra::GPU& gpu,
61 std::unique_ptr<Core::Frontend::GraphicsContext> context); 71 std::unique_ptr<Core::Frontend::GraphicsContext> context);
62 ~RendererOpenGL() override; 72 ~RendererOpenGL() override;
@@ -94,12 +104,13 @@ private:
94 104
95 bool Present(int timeout_ms); 105 bool Present(int timeout_ms);
96 106
97 Core::System& system; 107 Core::TelemetrySession& telemetry_session;
98 Core::Frontend::EmuWindow& emu_window; 108 Core::Frontend::EmuWindow& emu_window;
109 Core::Memory::Memory& cpu_memory;
99 Tegra::GPU& gpu; 110 Tegra::GPU& gpu;
100 const Device device;
101 111
102 StateTracker state_tracker{system}; 112 const Device device;
113 StateTracker state_tracker{gpu};
103 114
104 // OpenGL object IDs 115 // OpenGL object IDs
105 OGLBuffer vertex_buffer; 116 OGLBuffer vertex_buffer;
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index ae46e0444..0e4583986 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -86,7 +86,7 @@ Common::DynamicLibrary OpenVulkanLibrary() {
86 if (!library.Open(filename.c_str())) { 86 if (!library.Open(filename.c_str())) {
87 // Android devices may not have libvulkan.so.1, only libvulkan.so. 87 // Android devices may not have libvulkan.so.1, only libvulkan.so.
88 filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); 88 filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
89 library.Open(filename.c_str()); 89 (void)library.Open(filename.c_str());
90 } 90 }
91#endif 91#endif
92 return library; 92 return library;
@@ -237,10 +237,12 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
237 237
238} // Anonymous namespace 238} // Anonymous namespace
239 239
240RendererVulkan::RendererVulkan(Core::System& system_, Core::Frontend::EmuWindow& emu_window, 240RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
241 Tegra::GPU& gpu_, 241 Core::Frontend::EmuWindow& emu_window,
242 Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
242 std::unique_ptr<Core::Frontend::GraphicsContext> context) 243 std::unique_ptr<Core::Frontend::GraphicsContext> context)
243 : RendererBase{emu_window, std::move(context)}, system{system_}, gpu{gpu_} {} 244 : RendererBase{emu_window, std::move(context)}, telemetry_session{telemetry_session_},
245 cpu_memory{cpu_memory_}, gpu{gpu_} {}
244 246
245RendererVulkan::~RendererVulkan() { 247RendererVulkan::~RendererVulkan() {
246 ShutDown(); 248 ShutDown();
@@ -304,15 +306,15 @@ bool RendererVulkan::Init() {
304 swapchain = std::make_unique<VKSwapchain>(*surface, *device); 306 swapchain = std::make_unique<VKSwapchain>(*surface, *device);
305 swapchain->Create(framebuffer.width, framebuffer.height, false); 307 swapchain->Create(framebuffer.width, framebuffer.height, false);
306 308
307 state_tracker = std::make_unique<StateTracker>(system); 309 state_tracker = std::make_unique<StateTracker>(gpu);
308 310
309 scheduler = std::make_unique<VKScheduler>(*device, *resource_manager, *state_tracker); 311 scheduler = std::make_unique<VKScheduler>(*device, *resource_manager, *state_tracker);
310 312
311 rasterizer = std::make_unique<RasterizerVulkan>(system, render_window, screen_info, *device, 313 rasterizer = std::make_unique<RasterizerVulkan>(
312 *resource_manager, *memory_manager, 314 render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, *device,
313 *state_tracker, *scheduler); 315 *resource_manager, *memory_manager, *state_tracker, *scheduler);
314 316
315 blit_screen = std::make_unique<VKBlitScreen>(system, render_window, *rasterizer, *device, 317 blit_screen = std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device,
316 *resource_manager, *memory_manager, *swapchain, 318 *resource_manager, *memory_manager, *swapchain,
317 *scheduler, screen_info); 319 *scheduler, screen_info);
318 320
@@ -440,8 +442,7 @@ void RendererVulkan::Report() const {
440 LOG_INFO(Render_Vulkan, "Device: {}", model_name); 442 LOG_INFO(Render_Vulkan, "Device: {}", model_name);
441 LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version); 443 LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version);
442 444
443 auto& telemetry_session = system.TelemetrySession(); 445 static constexpr auto field = Common::Telemetry::FieldType::UserSystem;
444 constexpr auto field = Common::Telemetry::FieldType::UserSystem;
445 telemetry_session.AddField(field, "GPU_Vendor", vendor_name); 446 telemetry_session.AddField(field, "GPU_Vendor", vendor_name);
446 telemetry_session.AddField(field, "GPU_Model", model_name); 447 telemetry_session.AddField(field, "GPU_Model", model_name);
447 telemetry_session.AddField(field, "GPU_Vulkan_Driver", driver_name); 448 telemetry_session.AddField(field, "GPU_Vulkan_Driver", driver_name);
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 13debbbc0..ddff77942 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -14,7 +14,15 @@
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/renderer_vulkan/wrapper.h"
15 15
16namespace Core { 16namespace Core {
17class System; 17class TelemetrySession;
18}
19
20namespace Core::Memory {
21class Memory;
22}
23
24namespace Tegra {
25class GPU;
18} 26}
19 27
20namespace Vulkan { 28namespace Vulkan {
@@ -38,7 +46,8 @@ struct VKScreenInfo {
38 46
39class RendererVulkan final : public VideoCore::RendererBase { 47class RendererVulkan final : public VideoCore::RendererBase {
40public: 48public:
41 explicit RendererVulkan(Core::System& system, Core::Frontend::EmuWindow& emu_window, 49 explicit RendererVulkan(Core::TelemetrySession& telemtry_session,
50 Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory,
42 Tegra::GPU& gpu, 51 Tegra::GPU& gpu,
43 std::unique_ptr<Core::Frontend::GraphicsContext> context); 52 std::unique_ptr<Core::Frontend::GraphicsContext> context);
44 ~RendererVulkan() override; 53 ~RendererVulkan() override;
@@ -59,7 +68,8 @@ private:
59 68
60 void Report() const; 69 void Report() const;
61 70
62 Core::System& system; 71 Core::TelemetrySession& telemetry_session;
72 Core::Memory::Memory& cpu_memory;
63 Tegra::GPU& gpu; 73 Tegra::GPU& gpu;
64 74
65 Common::DynamicLibrary library; 75 Common::DynamicLibrary library;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index a551e3de8..2bea7b24d 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -210,14 +210,16 @@ struct VKBlitScreen::BufferData {
210 // Unaligned image data goes here 210 // Unaligned image data goes here
211}; 211};
212 212
213VKBlitScreen::VKBlitScreen(Core::System& system, Core::Frontend::EmuWindow& render_window, 213VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_,
214 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, 214 Core::Frontend::EmuWindow& render_window_,
215 VKResourceManager& resource_manager, VKMemoryManager& memory_manager, 215 VideoCore::RasterizerInterface& rasterizer_, const VKDevice& device_,
216 VKSwapchain& swapchain, VKScheduler& scheduler, 216 VKResourceManager& resource_manager_, VKMemoryManager& memory_manager_,
217 const VKScreenInfo& screen_info) 217 VKSwapchain& swapchain_, VKScheduler& scheduler_,
218 : system{system}, render_window{render_window}, rasterizer{rasterizer}, device{device}, 218 const VKScreenInfo& screen_info_)
219 resource_manager{resource_manager}, memory_manager{memory_manager}, swapchain{swapchain}, 219 : cpu_memory{cpu_memory_}, render_window{render_window_},
220 scheduler{scheduler}, image_count{swapchain.GetImageCount()}, screen_info{screen_info} { 220 rasterizer{rasterizer_}, device{device_}, resource_manager{resource_manager_},
221 memory_manager{memory_manager_}, swapchain{swapchain_}, scheduler{scheduler_},
222 image_count{swapchain.GetImageCount()}, screen_info{screen_info_} {
221 watches.resize(image_count); 223 watches.resize(image_count);
222 std::generate(watches.begin(), watches.end(), 224 std::generate(watches.begin(), watches.end(),
223 []() { return std::make_unique<VKFenceWatch>(); }); 225 []() { return std::make_unique<VKFenceWatch>(); });
@@ -259,7 +261,7 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon
259 const auto pixel_format = 261 const auto pixel_format =
260 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format); 262 VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
261 const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset; 263 const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
262 const auto host_ptr = system.Memory().GetPointer(framebuffer_addr); 264 const auto host_ptr = cpu_memory.GetPointer(framebuffer_addr);
263 rasterizer.FlushRegion(ToCacheAddr(host_ptr), GetSizeInBytes(framebuffer)); 265 rasterizer.FlushRegion(ToCacheAddr(host_ptr), GetSizeInBytes(framebuffer));
264 266
265 // TODO(Rodrigo): Read this from HLE 267 // TODO(Rodrigo): Read this from HLE
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 243640fab..838d38f69 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -15,6 +15,10 @@ namespace Core {
15class System; 15class System;
16} 16}
17 17
18namespace Core::Memory {
19class Memory;
20}
21
18namespace Core::Frontend { 22namespace Core::Frontend {
19class EmuWindow; 23class EmuWindow;
20} 24}
@@ -39,7 +43,8 @@ class VKSwapchain;
39 43
40class VKBlitScreen final { 44class VKBlitScreen final {
41public: 45public:
42 explicit VKBlitScreen(Core::System& system, Core::Frontend::EmuWindow& render_window, 46 explicit VKBlitScreen(Core::Memory::Memory& cpu_memory,
47 Core::Frontend::EmuWindow& render_window,
43 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device, 48 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
44 VKResourceManager& resource_manager, VKMemoryManager& memory_manager, 49 VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
45 VKSwapchain& swapchain, VKScheduler& scheduler, 50 VKSwapchain& swapchain, VKScheduler& scheduler,
@@ -81,7 +86,7 @@ private:
81 u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, 86 u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer,
82 std::size_t image_index) const; 87 std::size_t image_index) const;
83 88
84 Core::System& system; 89 Core::Memory::Memory& cpu_memory;
85 Core::Frontend::EmuWindow& render_window; 90 Core::Frontend::EmuWindow& render_window;
86 VideoCore::RasterizerInterface& rasterizer; 91 VideoCore::RasterizerInterface& rasterizer;
87 const VKDevice& device; 92 const VKDevice& device;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 1d2f8b557..d9d3da9ea 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -145,14 +145,15 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst
145 }); 145 });
146} 146}
147 147
148VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system, 148VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer,
149 const VKDevice& device, VKMemoryManager& memory_manager, 149 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
150 VKScheduler& scheduler, VKStagingBufferPool& staging_pool) 150 const VKDevice& device_, VKMemoryManager& memory_manager_,
151 : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, system, 151 VKScheduler& scheduler_, VKStagingBufferPool& staging_pool_)
152 CreateStreamBuffer(device, 152 : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer, gpu_memory, cpu_memory,
153 scheduler)}, 153 CreateStreamBuffer(device_,
154 device{device}, memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{ 154 scheduler_)},
155 staging_pool} {} 155 device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{
156 staging_pool_} {}
156 157
157VKBufferCache::~VKBufferCache() = default; 158VKBufferCache::~VKBufferCache() = default;
158 159
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 991ee451c..7fb5ceedf 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -13,10 +13,6 @@
13#include "video_core/renderer_vulkan/vk_stream_buffer.h" 13#include "video_core/renderer_vulkan/vk_stream_buffer.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/renderer_vulkan/wrapper.h"
15 15
16namespace Core {
17class System;
18}
19
20namespace Vulkan { 16namespace Vulkan {
21 17
22class VKDevice; 18class VKDevice;
@@ -53,7 +49,8 @@ private:
53 49
54class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { 50class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> {
55public: 51public:
56 explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system, 52 explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer,
53 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
57 const VKDevice& device, VKMemoryManager& memory_manager, 54 const VKDevice& device, VKMemoryManager& memory_manager,
58 VKScheduler& scheduler, VKStagingBufferPool& staging_pool); 55 VKScheduler& scheduler, VKStagingBufferPool& staging_pool);
59 ~VKBufferCache(); 56 ~VKBufferCache();
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 030b4dbd3..4205bd573 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -380,6 +380,14 @@ bool VKDevice::Create() {
380 380
381 CollectTelemetryParameters(); 381 CollectTelemetryParameters();
382 382
383 if (ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR) {
384 // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but the <stride> field
385 // seems to be bugged. Blacklisting it for now.
386 LOG_WARNING(Render_Vulkan,
387 "Blacklisting AMD proprietary from VK_EXT_extended_dynamic_state");
388 ext_extended_dynamic_state = false;
389 }
390
383 graphics_queue = logical.GetQueue(graphics_family); 391 graphics_queue = logical.GetQueue(graphics_family);
384 present_queue = logical.GetQueue(present_family); 392 present_queue = logical.GetQueue(present_family);
385 393
@@ -691,12 +699,7 @@ std::vector<const char*> VKDevice::LoadExtensions() {
691 } 699 }
692 } 700 }
693 701
694 if (has_ext_extended_dynamic_state && driver_id == VK_DRIVER_ID_AMD_PROPRIETARY) { 702 if (has_ext_extended_dynamic_state) {
695 // AMD's proprietary driver supports VK_EXT_extended_dynamic_state but the <stride> field
696 // seems to be bugged. Blacklisting it for now.
697 LOG_WARNING(Render_Vulkan,
698 "Blacklisting AMD proprietary from VK_EXT_extended_dynamic_state");
699 } else if (has_ext_extended_dynamic_state) {
700 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state; 703 VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state;
701 dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; 704 dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
702 dynamic_state.pNext = nullptr; 705 dynamic_state.pNext = nullptr;
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index d7f65d435..55a8348fc 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -71,12 +71,12 @@ bool InnerFence::IsEventSignalled() const {
71 } 71 }
72} 72}
73 73
74VKFenceManager::VKFenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 74VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
75 const VKDevice& device, VKScheduler& scheduler, 75 Tegra::MemoryManager& memory_manager, VKTextureCache& texture_cache,
76 VKTextureCache& texture_cache, VKBufferCache& buffer_cache, 76 VKBufferCache& buffer_cache, VKQueryCache& query_cache,
77 VKQueryCache& query_cache) 77 const VKDevice& device_, VKScheduler& scheduler_)
78 : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache, query_cache), 78 : GenericFenceManager(rasterizer, gpu, texture_cache, buffer_cache, query_cache),
79 device{device}, scheduler{scheduler} {} 79 device{device_}, scheduler{scheduler_} {}
80 80
81Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { 81Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) {
82 return std::make_shared<InnerFence>(device, scheduler, value, is_stubbed); 82 return std::make_shared<InnerFence>(device, scheduler, value, is_stubbed);
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index 043fe7947..1547d6d30 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -55,10 +55,10 @@ using GenericFenceManager =
55 55
56class VKFenceManager final : public GenericFenceManager { 56class VKFenceManager final : public GenericFenceManager {
57public: 57public:
58 explicit VKFenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 58 explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer, Tegra::GPU& gpu,
59 const VKDevice& device, VKScheduler& scheduler, 59 Tegra::MemoryManager& memory_manager, VKTextureCache& texture_cache,
60 VKTextureCache& texture_cache, VKBufferCache& buffer_cache, 60 VKBufferCache& buffer_cache, VKQueryCache& query_cache,
61 VKQueryCache& query_cache); 61 const VKDevice& device, VKScheduler& scheduler);
62 62
63protected: 63protected:
64 Fence CreateFence(u32 value, bool is_stubbed) override; 64 Fence CreateFence(u32 value, bool is_stubbed) override;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index cfdcdd6ab..5c038f4bc 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -135,64 +135,56 @@ bool ComputePipelineCacheKey::operator==(const ComputePipelineCacheKey& rhs) con
135 return std::memcmp(&rhs, this, sizeof *this) == 0; 135 return std::memcmp(&rhs, this, sizeof *this) == 0;
136} 136}
137 137
138Shader::Shader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, 138Shader::Shader(Tegra::Engines::ConstBufferEngineInterface& engine, Tegra::Engines::ShaderType stage,
139 VideoCommon::Shader::ProgramCode program_code, u32 main_offset) 139 GPUVAddr gpu_addr_, VAddr cpu_addr, VideoCommon::Shader::ProgramCode program_code_,
140 : gpu_addr{gpu_addr}, program_code{std::move(program_code)}, 140 u32 main_offset)
141 registry{stage, GetEngine(system, stage)}, shader_ir{this->program_code, main_offset, 141 : gpu_addr(gpu_addr_), program_code(std::move(program_code_)), registry(stage, engine),
142 compiler_settings, registry}, 142 shader_ir(program_code, main_offset, compiler_settings, registry),
143 entries{GenerateShaderEntries(shader_ir)} {} 143 entries(GenerateShaderEntries(shader_ir)) {}
144 144
145Shader::~Shader() = default; 145Shader::~Shader() = default;
146 146
147Tegra::Engines::ConstBufferEngineInterface& Shader::GetEngine(Core::System& system, 147VKPipelineCache::VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu_,
148 Tegra::Engines::ShaderType stage) { 148 Tegra::Engines::Maxwell3D& maxwell3d_,
149 if (stage == ShaderType::Compute) { 149 Tegra::Engines::KeplerCompute& kepler_compute_,
150 return system.GPU().KeplerCompute(); 150 Tegra::MemoryManager& gpu_memory_, const VKDevice& device_,
151 } else { 151 VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_,
152 return system.GPU().Maxwell3D(); 152 VKUpdateDescriptorQueue& update_descriptor_queue_,
153 } 153 VKRenderPassCache& renderpass_cache_)
154} 154 : VideoCommon::ShaderCache<Shader>{rasterizer}, gpu{gpu_}, maxwell3d{maxwell3d_},
155 155 kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_},
156VKPipelineCache::VKPipelineCache(Core::System& system, RasterizerVulkan& rasterizer, 156 scheduler{scheduler_}, descriptor_pool{descriptor_pool_},
157 const VKDevice& device, VKScheduler& scheduler, 157 update_descriptor_queue{update_descriptor_queue_}, renderpass_cache{renderpass_cache_} {}
158 VKDescriptorPool& descriptor_pool,
159 VKUpdateDescriptorQueue& update_descriptor_queue,
160 VKRenderPassCache& renderpass_cache)
161 : VideoCommon::ShaderCache<Shader>{rasterizer}, system{system}, device{device},
162 scheduler{scheduler}, descriptor_pool{descriptor_pool},
163 update_descriptor_queue{update_descriptor_queue}, renderpass_cache{renderpass_cache} {}
164 158
165VKPipelineCache::~VKPipelineCache() = default; 159VKPipelineCache::~VKPipelineCache() = default;
166 160
167std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() { 161std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
168 const auto& gpu = system.GPU().Maxwell3D();
169
170 std::array<Shader*, Maxwell::MaxShaderProgram> shaders{}; 162 std::array<Shader*, Maxwell::MaxShaderProgram> shaders{};
163
171 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 164 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
172 const auto program{static_cast<Maxwell::ShaderProgram>(index)}; 165 const auto program{static_cast<Maxwell::ShaderProgram>(index)};
173 166
174 // Skip stages that are not enabled 167 // Skip stages that are not enabled
175 if (!gpu.regs.IsShaderConfigEnabled(index)) { 168 if (!maxwell3d.regs.IsShaderConfigEnabled(index)) {
176 continue; 169 continue;
177 } 170 }
178 171
179 auto& memory_manager{system.GPU().MemoryManager()}; 172 const GPUVAddr gpu_addr{GetShaderAddress(maxwell3d, program)};
180 const GPUVAddr program_addr{GetShaderAddress(system, program)}; 173 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
181 const std::optional cpu_addr = memory_manager.GpuToCpuAddress(program_addr);
182 ASSERT(cpu_addr); 174 ASSERT(cpu_addr);
183 175
184 Shader* result = cpu_addr ? TryGet(*cpu_addr) : null_shader.get(); 176 Shader* result = cpu_addr ? TryGet(*cpu_addr) : null_shader.get();
185 if (!result) { 177 if (!result) {
186 const auto host_ptr{memory_manager.GetPointer(program_addr)}; 178 const u8* const host_ptr{gpu_memory.GetPointer(gpu_addr)};
187 179
188 // No shader found - create a new one 180 // No shader found - create a new one
189 constexpr u32 stage_offset = STAGE_MAIN_OFFSET; 181 static constexpr u32 stage_offset = STAGE_MAIN_OFFSET;
190 const auto stage = static_cast<ShaderType>(index == 0 ? 0 : index - 1); 182 const auto stage = static_cast<ShaderType>(index == 0 ? 0 : index - 1);
191 ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, false); 183 ProgramCode code = GetShaderCode(gpu_memory, gpu_addr, host_ptr, false);
192 const std::size_t size_in_bytes = code.size() * sizeof(u64); 184 const std::size_t size_in_bytes = code.size() * sizeof(u64);
193 185
194 auto shader = std::make_unique<Shader>(system, stage, program_addr, std::move(code), 186 auto shader = std::make_unique<Shader>(maxwell3d, stage, gpu_addr, *cpu_addr,
195 stage_offset); 187 std::move(code), stage_offset);
196 result = shader.get(); 188 result = shader.get();
197 189
198 if (cpu_addr) { 190 if (cpu_addr) {
@@ -215,11 +207,11 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
215 } 207 }
216 last_graphics_key = key; 208 last_graphics_key = key;
217 209
218 if (device.UseAsynchronousShaders() && async_shaders.IsShaderAsync(system.GPU())) { 210 if (device.UseAsynchronousShaders() && async_shaders.IsShaderAsync(gpu)) {
219 std::unique_lock lock{pipeline_cache}; 211 std::unique_lock lock{pipeline_cache};
220 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key); 212 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
221 if (is_cache_miss) { 213 if (is_cache_miss) {
222 system.GPU().ShaderNotify().MarkSharderBuilding(); 214 gpu.ShaderNotify().MarkSharderBuilding();
223 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 215 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
224 const auto [program, bindings] = DecompileShaders(key.fixed_state); 216 const auto [program, bindings] = DecompileShaders(key.fixed_state);
225 async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool, 217 async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool,
@@ -233,13 +225,13 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
233 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key); 225 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
234 auto& entry = pair->second; 226 auto& entry = pair->second;
235 if (is_cache_miss) { 227 if (is_cache_miss) {
236 system.GPU().ShaderNotify().MarkSharderBuilding(); 228 gpu.ShaderNotify().MarkSharderBuilding();
237 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 229 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
238 const auto [program, bindings] = DecompileShaders(key.fixed_state); 230 const auto [program, bindings] = DecompileShaders(key.fixed_state);
239 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool, 231 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool,
240 update_descriptor_queue, renderpass_cache, key, 232 update_descriptor_queue, renderpass_cache, key,
241 bindings, program); 233 bindings, program);
242 system.GPU().ShaderNotify().MarkShaderComplete(); 234 gpu.ShaderNotify().MarkShaderComplete();
243 } 235 }
244 last_graphics_pipeline = entry.get(); 236 last_graphics_pipeline = entry.get();
245 return last_graphics_pipeline; 237 return last_graphics_pipeline;
@@ -255,22 +247,21 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
255 } 247 }
256 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 248 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
257 249
258 auto& memory_manager = system.GPU().MemoryManager(); 250 const GPUVAddr gpu_addr = key.shader;
259 const auto program_addr = key.shader;
260 251
261 const auto cpu_addr = memory_manager.GpuToCpuAddress(program_addr); 252 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
262 ASSERT(cpu_addr); 253 ASSERT(cpu_addr);
263 254
264 Shader* shader = cpu_addr ? TryGet(*cpu_addr) : null_kernel.get(); 255 Shader* shader = cpu_addr ? TryGet(*cpu_addr) : null_kernel.get();
265 if (!shader) { 256 if (!shader) {
266 // No shader found - create a new one 257 // No shader found - create a new one
267 const auto host_ptr = memory_manager.GetPointer(program_addr); 258 const auto host_ptr = gpu_memory.GetPointer(gpu_addr);
268 259
269 ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, true); 260 ProgramCode code = GetShaderCode(gpu_memory, gpu_addr, host_ptr, true);
270 const std::size_t size_in_bytes = code.size() * sizeof(u64); 261 const std::size_t size_in_bytes = code.size() * sizeof(u64);
271 262
272 auto shader_info = std::make_unique<Shader>(system, ShaderType::Compute, program_addr, 263 auto shader_info = std::make_unique<Shader>(kepler_compute, ShaderType::Compute, gpu_addr,
273 std::move(code), KERNEL_MAIN_OFFSET); 264 *cpu_addr, std::move(code), KERNEL_MAIN_OFFSET);
274 shader = shader_info.get(); 265 shader = shader_info.get();
275 266
276 if (cpu_addr) { 267 if (cpu_addr) {
@@ -298,7 +289,7 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
298} 289}
299 290
300void VKPipelineCache::EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline) { 291void VKPipelineCache::EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline) {
301 system.GPU().ShaderNotify().MarkShaderComplete(); 292 gpu.ShaderNotify().MarkShaderComplete();
302 std::unique_lock lock{pipeline_cache}; 293 std::unique_lock lock{pipeline_cache};
303 graphics_cache.at(pipeline->GetCacheKey()) = std::move(pipeline); 294 graphics_cache.at(pipeline->GetCacheKey()) = std::move(pipeline);
304} 295}
@@ -339,9 +330,6 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) {
339 330
340std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> 331std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
341VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { 332VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
342 auto& memory_manager = system.GPU().MemoryManager();
343 const auto& gpu = system.GPU().Maxwell3D();
344
345 Specialization specialization; 333 Specialization specialization;
346 if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points || 334 if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points ||
347 device.IsExtExtendedDynamicStateSupported()) { 335 device.IsExtExtendedDynamicStateSupported()) {
@@ -364,12 +352,12 @@ VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
364 const auto program_enum = static_cast<Maxwell::ShaderProgram>(index); 352 const auto program_enum = static_cast<Maxwell::ShaderProgram>(index);
365 353
366 // Skip stages that are not enabled 354 // Skip stages that are not enabled
367 if (!gpu.regs.IsShaderConfigEnabled(index)) { 355 if (!maxwell3d.regs.IsShaderConfigEnabled(index)) {
368 continue; 356 continue;
369 } 357 }
370 358
371 const GPUVAddr gpu_addr = GetShaderAddress(system, program_enum); 359 const GPUVAddr gpu_addr = GetShaderAddress(maxwell3d, program_enum);
372 const std::optional<VAddr> cpu_addr = memory_manager.GpuToCpuAddress(gpu_addr); 360 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
373 Shader* const shader = cpu_addr ? TryGet(*cpu_addr) : null_shader.get(); 361 Shader* const shader = cpu_addr ? TryGet(*cpu_addr) : null_shader.get();
374 362
375 const std::size_t stage = index == 0 ? 0 : index - 1; // Stage indices are 0 - 5 363 const std::size_t stage = index == 0 ? 0 : index - 1; // Stage indices are 0 - 5
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index c04829e77..1a31fd9f6 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -85,7 +85,8 @@ namespace Vulkan {
85 85
86class Shader { 86class Shader {
87public: 87public:
88 explicit Shader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, 88 explicit Shader(Tegra::Engines::ConstBufferEngineInterface& engine,
89 Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, VAddr cpu_addr,
89 VideoCommon::Shader::ProgramCode program_code, u32 main_offset); 90 VideoCommon::Shader::ProgramCode program_code, u32 main_offset);
90 ~Shader(); 91 ~Shader();
91 92
@@ -97,22 +98,19 @@ public:
97 return shader_ir; 98 return shader_ir;
98 } 99 }
99 100
100 const VideoCommon::Shader::Registry& GetRegistry() const {
101 return registry;
102 }
103
104 const VideoCommon::Shader::ShaderIR& GetIR() const { 101 const VideoCommon::Shader::ShaderIR& GetIR() const {
105 return shader_ir; 102 return shader_ir;
106 } 103 }
107 104
105 const VideoCommon::Shader::Registry& GetRegistry() const {
106 return registry;
107 }
108
108 const ShaderEntries& GetEntries() const { 109 const ShaderEntries& GetEntries() const {
109 return entries; 110 return entries;
110 } 111 }
111 112
112private: 113private:
113 static Tegra::Engines::ConstBufferEngineInterface& GetEngine(Core::System& system,
114 Tegra::Engines::ShaderType stage);
115
116 GPUVAddr gpu_addr{}; 114 GPUVAddr gpu_addr{};
117 VideoCommon::Shader::ProgramCode program_code; 115 VideoCommon::Shader::ProgramCode program_code;
118 VideoCommon::Shader::Registry registry; 116 VideoCommon::Shader::Registry registry;
@@ -122,9 +120,11 @@ private:
122 120
123class VKPipelineCache final : public VideoCommon::ShaderCache<Shader> { 121class VKPipelineCache final : public VideoCommon::ShaderCache<Shader> {
124public: 122public:
125 explicit VKPipelineCache(Core::System& system, RasterizerVulkan& rasterizer, 123 explicit VKPipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu,
126 const VKDevice& device, VKScheduler& scheduler, 124 Tegra::Engines::Maxwell3D& maxwell3d,
127 VKDescriptorPool& descriptor_pool, 125 Tegra::Engines::KeplerCompute& kepler_compute,
126 Tegra::MemoryManager& gpu_memory, const VKDevice& device,
127 VKScheduler& scheduler, VKDescriptorPool& descriptor_pool,
128 VKUpdateDescriptorQueue& update_descriptor_queue, 128 VKUpdateDescriptorQueue& update_descriptor_queue,
129 VKRenderPassCache& renderpass_cache); 129 VKRenderPassCache& renderpass_cache);
130 ~VKPipelineCache() override; 130 ~VKPipelineCache() override;
@@ -145,7 +145,11 @@ private:
145 std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> DecompileShaders( 145 std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> DecompileShaders(
146 const FixedPipelineState& fixed_state); 146 const FixedPipelineState& fixed_state);
147 147
148 Core::System& system; 148 Tegra::GPU& gpu;
149 Tegra::Engines::Maxwell3D& maxwell3d;
150 Tegra::Engines::KeplerCompute& kepler_compute;
151 Tegra::MemoryManager& gpu_memory;
152
149 const VKDevice& device; 153 const VKDevice& device;
150 VKScheduler& scheduler; 154 VKScheduler& scheduler;
151 VKDescriptorPool& descriptor_pool; 155 VKDescriptorPool& descriptor_pool;
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 6cd63d090..5a97c959d 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -68,10 +68,11 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
68 usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false; 68 usage[pool_index * GROW_STEP + static_cast<std::ptrdiff_t>(query.second)] = false;
69} 69}
70 70
71VKQueryCache::VKQueryCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 71VKQueryCache::VKQueryCache(VideoCore::RasterizerInterface& rasterizer,
72 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
72 const VKDevice& device, VKScheduler& scheduler) 73 const VKDevice& device, VKScheduler& scheduler)
73 : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter, 74 : VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter,
74 QueryPool>{system, rasterizer}, 75 QueryPool>{rasterizer, maxwell3d, gpu_memory},
75 device{device}, scheduler{scheduler} { 76 device{device}, scheduler{scheduler} {
76 for (std::size_t i = 0; i < static_cast<std::size_t>(VideoCore::NumQueryTypes); ++i) { 77 for (std::size_t i = 0; i < static_cast<std::size_t>(VideoCore::NumQueryTypes); ++i) {
77 query_pools[i].Initialize(device, static_cast<VideoCore::QueryType>(i)); 78 query_pools[i].Initialize(device, static_cast<VideoCore::QueryType>(i));
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index 40119e6d3..9be996e55 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -56,7 +56,8 @@ class VKQueryCache final
56 : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter, 56 : public VideoCommon::QueryCacheBase<VKQueryCache, CachedQuery, CounterStream, HostCounter,
57 QueryPool> { 57 QueryPool> {
58public: 58public:
59 explicit VKQueryCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 59 explicit VKQueryCache(VideoCore::RasterizerInterface& rasterizer,
60 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
60 const VKDevice& device, VKScheduler& scheduler); 61 const VKDevice& device, VKScheduler& scheduler);
61 ~VKQueryCache(); 62 ~VKQueryCache();
62 63
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index ff1b52eab..bafebe294 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -381,28 +381,30 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const {
381 } 381 }
382} 382}
383 383
384RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& renderer, 384RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu_,
385 VKScreenInfo& screen_info, const VKDevice& device, 385 Tegra::MemoryManager& gpu_memory_,
386 VKResourceManager& resource_manager, 386 Core::Memory::Memory& cpu_memory, VKScreenInfo& screen_info_,
387 VKMemoryManager& memory_manager, StateTracker& state_tracker, 387 const VKDevice& device_, VKResourceManager& resource_manager_,
388 VKScheduler& scheduler) 388 VKMemoryManager& memory_manager_, StateTracker& state_tracker_,
389 : RasterizerAccelerated{system.Memory()}, system{system}, render_window{renderer}, 389 VKScheduler& scheduler_)
390 screen_info{screen_info}, device{device}, resource_manager{resource_manager}, 390 : RasterizerAccelerated(cpu_memory), gpu(gpu_), gpu_memory(gpu_memory_),
391 memory_manager{memory_manager}, state_tracker{state_tracker}, scheduler{scheduler}, 391 maxwell3d(gpu.Maxwell3D()), kepler_compute(gpu.KeplerCompute()), screen_info(screen_info_),
392 device(device_), resource_manager(resource_manager_), memory_manager(memory_manager_),
393 state_tracker(state_tracker_), scheduler(scheduler_),
392 staging_pool(device, memory_manager, scheduler), descriptor_pool(device), 394 staging_pool(device, memory_manager, scheduler), descriptor_pool(device),
393 update_descriptor_queue(device, scheduler), renderpass_cache(device), 395 update_descriptor_queue(device, scheduler), renderpass_cache(device),
394 quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 396 quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
395 quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 397 quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
396 uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 398 uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue),
397 texture_cache(system, *this, device, resource_manager, memory_manager, scheduler, 399 texture_cache(*this, maxwell3d, gpu_memory, device, resource_manager, memory_manager,
398 staging_pool), 400 scheduler, staging_pool),
399 pipeline_cache(system, *this, device, scheduler, descriptor_pool, update_descriptor_queue, 401 pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler,
400 renderpass_cache), 402 descriptor_pool, update_descriptor_queue, renderpass_cache),
401 buffer_cache(*this, system, device, memory_manager, scheduler, staging_pool), 403 buffer_cache(*this, gpu_memory, cpu_memory, device, memory_manager, scheduler, staging_pool),
402 sampler_cache(device), 404 sampler_cache(device), query_cache(*this, maxwell3d, gpu_memory, device, scheduler),
403 fence_manager(system, *this, device, scheduler, texture_cache, buffer_cache, query_cache), 405 fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device,
404 query_cache(system, *this, device, scheduler), 406 scheduler),
405 wfi_event{device.GetLogical().CreateNewEvent()}, async_shaders{renderer} { 407 wfi_event(device.GetLogical().CreateNewEvent()), async_shaders(emu_window) {
406 scheduler.SetQueryCache(query_cache); 408 scheduler.SetQueryCache(query_cache);
407 if (device.UseAsynchronousShaders()) { 409 if (device.UseAsynchronousShaders()) {
408 async_shaders.AllocateWorkers(); 410 async_shaders.AllocateWorkers();
@@ -414,15 +416,13 @@ RasterizerVulkan::~RasterizerVulkan() = default;
414void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { 416void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
415 MICROPROFILE_SCOPE(Vulkan_Drawing); 417 MICROPROFILE_SCOPE(Vulkan_Drawing);
416 418
419 SCOPE_EXIT({ gpu.TickWork(); });
417 FlushWork(); 420 FlushWork();
418 421
419 query_cache.UpdateCounters(); 422 query_cache.UpdateCounters();
420 423
421 SCOPE_EXIT({ system.GPU().TickWork(); });
422
423 const auto& gpu = system.GPU().Maxwell3D();
424 GraphicsPipelineCacheKey key; 424 GraphicsPipelineCacheKey key;
425 key.fixed_state.Fill(gpu.regs, device.IsExtExtendedDynamicStateSupported()); 425 key.fixed_state.Fill(maxwell3d.regs, device.IsExtExtendedDynamicStateSupported());
426 426
427 buffer_cache.Map(CalculateGraphicsStreamBufferSize(is_indexed)); 427 buffer_cache.Map(CalculateGraphicsStreamBufferSize(is_indexed));
428 428
@@ -480,8 +480,7 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
480void RasterizerVulkan::Clear() { 480void RasterizerVulkan::Clear() {
481 MICROPROFILE_SCOPE(Vulkan_Clearing); 481 MICROPROFILE_SCOPE(Vulkan_Clearing);
482 482
483 const auto& gpu = system.GPU().Maxwell3D(); 483 if (!maxwell3d.ShouldExecute()) {
484 if (!system.GPU().Maxwell3D().ShouldExecute()) {
485 return; 484 return;
486 } 485 }
487 486
@@ -490,7 +489,7 @@ void RasterizerVulkan::Clear() {
490 489
491 query_cache.UpdateCounters(); 490 query_cache.UpdateCounters();
492 491
493 const auto& regs = gpu.regs; 492 const auto& regs = maxwell3d.regs;
494 const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 493 const bool use_color = regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
495 regs.clear_buffers.A; 494 regs.clear_buffers.A;
496 const bool use_depth = regs.clear_buffers.Z; 495 const bool use_depth = regs.clear_buffers.Z;
@@ -559,7 +558,7 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) {
559 558
560 query_cache.UpdateCounters(); 559 query_cache.UpdateCounters();
561 560
562 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 561 const auto& launch_desc = kepler_compute.launch_description;
563 auto& pipeline = pipeline_cache.GetComputePipeline({ 562 auto& pipeline = pipeline_cache.GetComputePipeline({
564 .shader = code_addr, 563 .shader = code_addr,
565 .shared_memory_size = launch_desc.shared_alloc, 564 .shared_memory_size = launch_desc.shared_alloc,
@@ -655,16 +654,14 @@ void RasterizerVulkan::SyncGuestHost() {
655} 654}
656 655
657void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) { 656void RasterizerVulkan::SignalSemaphore(GPUVAddr addr, u32 value) {
658 auto& gpu{system.GPU()};
659 if (!gpu.IsAsync()) { 657 if (!gpu.IsAsync()) {
660 gpu.MemoryManager().Write<u32>(addr, value); 658 gpu_memory.Write<u32>(addr, value);
661 return; 659 return;
662 } 660 }
663 fence_manager.SignalSemaphore(addr, value); 661 fence_manager.SignalSemaphore(addr, value);
664} 662}
665 663
666void RasterizerVulkan::SignalSyncPoint(u32 value) { 664void RasterizerVulkan::SignalSyncPoint(u32 value) {
667 auto& gpu{system.GPU()};
668 if (!gpu.IsAsync()) { 665 if (!gpu.IsAsync()) {
669 gpu.IncrementSyncPoint(value); 666 gpu.IncrementSyncPoint(value);
670 return; 667 return;
@@ -673,7 +670,6 @@ void RasterizerVulkan::SignalSyncPoint(u32 value) {
673} 670}
674 671
675void RasterizerVulkan::ReleaseFences() { 672void RasterizerVulkan::ReleaseFences() {
676 auto& gpu{system.GPU()};
677 if (!gpu.IsAsync()) { 673 if (!gpu.IsAsync()) {
678 return; 674 return;
679 } 675 }
@@ -751,10 +747,6 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
751 return true; 747 return true;
752} 748}
753 749
754void RasterizerVulkan::SetupDirtyFlags() {
755 state_tracker.Initialize();
756}
757
758void RasterizerVulkan::FlushWork() { 750void RasterizerVulkan::FlushWork() {
759 static constexpr u32 DRAWS_TO_DISPATCH = 4096; 751 static constexpr u32 DRAWS_TO_DISPATCH = 4096;
760 752
@@ -778,10 +770,9 @@ void RasterizerVulkan::FlushWork() {
778 770
779RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) { 771RasterizerVulkan::Texceptions RasterizerVulkan::UpdateAttachments(bool is_clear) {
780 MICROPROFILE_SCOPE(Vulkan_RenderTargets); 772 MICROPROFILE_SCOPE(Vulkan_RenderTargets);
781 auto& maxwell3d = system.GPU().Maxwell3D();
782 auto& dirty = maxwell3d.dirty.flags;
783 auto& regs = maxwell3d.regs;
784 773
774 const auto& regs = maxwell3d.regs;
775 auto& dirty = maxwell3d.dirty.flags;
785 const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets]; 776 const bool update_rendertargets = dirty[VideoCommon::Dirty::RenderTargets];
786 dirty[VideoCommon::Dirty::RenderTargets] = false; 777 dirty[VideoCommon::Dirty::RenderTargets] = false;
787 778
@@ -844,7 +835,7 @@ std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers(
844 return true; 835 return true;
845 }; 836 };
846 837
847 const auto& regs = system.GPU().Maxwell3D().regs; 838 const auto& regs = maxwell3d.regs;
848 const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count); 839 const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count);
849 for (std::size_t index = 0; index < num_attachments; ++index) { 840 for (std::size_t index = 0; index < num_attachments; ++index) {
850 if (try_push(color_attachments[index])) { 841 if (try_push(color_attachments[index])) {
@@ -880,13 +871,12 @@ RasterizerVulkan::DrawParameters RasterizerVulkan::SetupGeometry(FixedPipelineSt
880 bool is_instanced) { 871 bool is_instanced) {
881 MICROPROFILE_SCOPE(Vulkan_Geometry); 872 MICROPROFILE_SCOPE(Vulkan_Geometry);
882 873
883 const auto& gpu = system.GPU().Maxwell3D(); 874 const auto& regs = maxwell3d.regs;
884 const auto& regs = gpu.regs;
885 875
886 SetupVertexArrays(buffer_bindings); 876 SetupVertexArrays(buffer_bindings);
887 877
888 const u32 base_instance = regs.vb_base_instance; 878 const u32 base_instance = regs.vb_base_instance;
889 const u32 num_instances = is_instanced ? gpu.mme_draw.instance_count : 1; 879 const u32 num_instances = is_instanced ? maxwell3d.mme_draw.instance_count : 1;
890 const u32 base_vertex = is_indexed ? regs.vb_element_base : regs.vertex_buffer.first; 880 const u32 base_vertex = is_indexed ? regs.vb_element_base : regs.vertex_buffer.first;
891 const u32 num_vertices = is_indexed ? regs.index_array.count : regs.vertex_buffer.count; 881 const u32 num_vertices = is_indexed ? regs.index_array.count : regs.vertex_buffer.count;
892 882
@@ -947,7 +937,7 @@ void RasterizerVulkan::SetupImageTransitions(
947} 937}
948 938
949void RasterizerVulkan::UpdateDynamicStates() { 939void RasterizerVulkan::UpdateDynamicStates() {
950 auto& regs = system.GPU().Maxwell3D().regs; 940 auto& regs = maxwell3d.regs;
951 UpdateViewportsState(regs); 941 UpdateViewportsState(regs);
952 UpdateScissorsState(regs); 942 UpdateScissorsState(regs);
953 UpdateDepthBias(regs); 943 UpdateDepthBias(regs);
@@ -968,7 +958,7 @@ void RasterizerVulkan::UpdateDynamicStates() {
968} 958}
969 959
970void RasterizerVulkan::BeginTransformFeedback() { 960void RasterizerVulkan::BeginTransformFeedback() {
971 const auto& regs = system.GPU().Maxwell3D().regs; 961 const auto& regs = maxwell3d.regs;
972 if (regs.tfb_enabled == 0) { 962 if (regs.tfb_enabled == 0) {
973 return; 963 return;
974 } 964 }
@@ -1000,7 +990,7 @@ void RasterizerVulkan::BeginTransformFeedback() {
1000} 990}
1001 991
1002void RasterizerVulkan::EndTransformFeedback() { 992void RasterizerVulkan::EndTransformFeedback() {
1003 const auto& regs = system.GPU().Maxwell3D().regs; 993 const auto& regs = maxwell3d.regs;
1004 if (regs.tfb_enabled == 0) { 994 if (regs.tfb_enabled == 0) {
1005 return; 995 return;
1006 } 996 }
@@ -1013,7 +1003,7 @@ void RasterizerVulkan::EndTransformFeedback() {
1013} 1003}
1014 1004
1015void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) { 1005void RasterizerVulkan::SetupVertexArrays(BufferBindings& buffer_bindings) {
1016 const auto& regs = system.GPU().Maxwell3D().regs; 1006 const auto& regs = maxwell3d.regs;
1017 1007
1018 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { 1008 for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
1019 const auto& vertex_array = regs.vertex_array[index]; 1009 const auto& vertex_array = regs.vertex_array[index];
@@ -1039,7 +1029,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
1039 if (params.num_vertices == 0) { 1029 if (params.num_vertices == 0) {
1040 return; 1030 return;
1041 } 1031 }
1042 const auto& regs = system.GPU().Maxwell3D().regs; 1032 const auto& regs = maxwell3d.regs;
1043 switch (regs.draw.topology) { 1033 switch (regs.draw.topology) {
1044 case Maxwell::PrimitiveTopology::Quads: { 1034 case Maxwell::PrimitiveTopology::Quads: {
1045 if (!params.is_indexed) { 1035 if (!params.is_indexed) {
@@ -1087,8 +1077,7 @@ void RasterizerVulkan::SetupIndexBuffer(BufferBindings& buffer_bindings, DrawPar
1087 1077
1088void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) { 1078void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, std::size_t stage) {
1089 MICROPROFILE_SCOPE(Vulkan_ConstBuffers); 1079 MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
1090 const auto& gpu = system.GPU().Maxwell3D(); 1080 const auto& shader_stage = maxwell3d.state.shader_stages[stage];
1091 const auto& shader_stage = gpu.state.shader_stages[stage];
1092 for (const auto& entry : entries.const_buffers) { 1081 for (const auto& entry : entries.const_buffers) {
1093 SetupConstBuffer(entry, shader_stage.const_buffers[entry.GetIndex()]); 1082 SetupConstBuffer(entry, shader_stage.const_buffers[entry.GetIndex()]);
1094 } 1083 }
@@ -1096,8 +1085,7 @@ void RasterizerVulkan::SetupGraphicsConstBuffers(const ShaderEntries& entries, s
1096 1085
1097void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) { 1086void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries, std::size_t stage) {
1098 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); 1087 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
1099 auto& gpu{system.GPU()}; 1088 const auto& cbufs{maxwell3d.state.shader_stages[stage]};
1100 const auto cbufs{gpu.Maxwell3D().state.shader_stages[stage]};
1101 1089
1102 for (const auto& entry : entries.global_buffers) { 1090 for (const auto& entry : entries.global_buffers) {
1103 const auto addr = cbufs.const_buffers[entry.GetCbufIndex()].address + entry.GetCbufOffset(); 1091 const auto addr = cbufs.const_buffers[entry.GetCbufIndex()].address + entry.GetCbufOffset();
@@ -1107,19 +1095,17 @@ void RasterizerVulkan::SetupGraphicsGlobalBuffers(const ShaderEntries& entries,
1107 1095
1108void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) { 1096void RasterizerVulkan::SetupGraphicsUniformTexels(const ShaderEntries& entries, std::size_t stage) {
1109 MICROPROFILE_SCOPE(Vulkan_Textures); 1097 MICROPROFILE_SCOPE(Vulkan_Textures);
1110 const auto& gpu = system.GPU().Maxwell3D();
1111 for (const auto& entry : entries.uniform_texels) { 1098 for (const auto& entry : entries.uniform_texels) {
1112 const auto image = GetTextureInfo(gpu, entry, stage).tic; 1099 const auto image = GetTextureInfo(maxwell3d, entry, stage).tic;
1113 SetupUniformTexels(image, entry); 1100 SetupUniformTexels(image, entry);
1114 } 1101 }
1115} 1102}
1116 1103
1117void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) { 1104void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::size_t stage) {
1118 MICROPROFILE_SCOPE(Vulkan_Textures); 1105 MICROPROFILE_SCOPE(Vulkan_Textures);
1119 const auto& gpu = system.GPU().Maxwell3D();
1120 for (const auto& entry : entries.samplers) { 1106 for (const auto& entry : entries.samplers) {
1121 for (std::size_t i = 0; i < entry.size; ++i) { 1107 for (std::size_t i = 0; i < entry.size; ++i) {
1122 const auto texture = GetTextureInfo(gpu, entry, stage, i); 1108 const auto texture = GetTextureInfo(maxwell3d, entry, stage, i);
1123 SetupTexture(texture, entry); 1109 SetupTexture(texture, entry);
1124 } 1110 }
1125 } 1111 }
@@ -1127,25 +1113,23 @@ void RasterizerVulkan::SetupGraphicsTextures(const ShaderEntries& entries, std::
1127 1113
1128void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) { 1114void RasterizerVulkan::SetupGraphicsStorageTexels(const ShaderEntries& entries, std::size_t stage) {
1129 MICROPROFILE_SCOPE(Vulkan_Textures); 1115 MICROPROFILE_SCOPE(Vulkan_Textures);
1130 const auto& gpu = system.GPU().Maxwell3D();
1131 for (const auto& entry : entries.storage_texels) { 1116 for (const auto& entry : entries.storage_texels) {
1132 const auto image = GetTextureInfo(gpu, entry, stage).tic; 1117 const auto image = GetTextureInfo(maxwell3d, entry, stage).tic;
1133 SetupStorageTexel(image, entry); 1118 SetupStorageTexel(image, entry);
1134 } 1119 }
1135} 1120}
1136 1121
1137void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) { 1122void RasterizerVulkan::SetupGraphicsImages(const ShaderEntries& entries, std::size_t stage) {
1138 MICROPROFILE_SCOPE(Vulkan_Images); 1123 MICROPROFILE_SCOPE(Vulkan_Images);
1139 const auto& gpu = system.GPU().Maxwell3D();
1140 for (const auto& entry : entries.images) { 1124 for (const auto& entry : entries.images) {
1141 const auto tic = GetTextureInfo(gpu, entry, stage).tic; 1125 const auto tic = GetTextureInfo(maxwell3d, entry, stage).tic;
1142 SetupImage(tic, entry); 1126 SetupImage(tic, entry);
1143 } 1127 }
1144} 1128}
1145 1129
1146void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) { 1130void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) {
1147 MICROPROFILE_SCOPE(Vulkan_ConstBuffers); 1131 MICROPROFILE_SCOPE(Vulkan_ConstBuffers);
1148 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 1132 const auto& launch_desc = kepler_compute.launch_description;
1149 for (const auto& entry : entries.const_buffers) { 1133 for (const auto& entry : entries.const_buffers) {
1150 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; 1134 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
1151 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value(); 1135 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
@@ -1159,7 +1143,7 @@ void RasterizerVulkan::SetupComputeConstBuffers(const ShaderEntries& entries) {
1159 1143
1160void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) { 1144void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) {
1161 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers); 1145 MICROPROFILE_SCOPE(Vulkan_GlobalBuffers);
1162 const auto cbufs{system.GPU().KeplerCompute().launch_description.const_buffer_config}; 1146 const auto& cbufs{kepler_compute.launch_description.const_buffer_config};
1163 for (const auto& entry : entries.global_buffers) { 1147 for (const auto& entry : entries.global_buffers) {
1164 const auto addr{cbufs[entry.GetCbufIndex()].Address() + entry.GetCbufOffset()}; 1148 const auto addr{cbufs[entry.GetCbufIndex()].Address() + entry.GetCbufOffset()};
1165 SetupGlobalBuffer(entry, addr); 1149 SetupGlobalBuffer(entry, addr);
@@ -1168,19 +1152,17 @@ void RasterizerVulkan::SetupComputeGlobalBuffers(const ShaderEntries& entries) {
1168 1152
1169void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) { 1153void RasterizerVulkan::SetupComputeUniformTexels(const ShaderEntries& entries) {
1170 MICROPROFILE_SCOPE(Vulkan_Textures); 1154 MICROPROFILE_SCOPE(Vulkan_Textures);
1171 const auto& gpu = system.GPU().KeplerCompute();
1172 for (const auto& entry : entries.uniform_texels) { 1155 for (const auto& entry : entries.uniform_texels) {
1173 const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic; 1156 const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic;
1174 SetupUniformTexels(image, entry); 1157 SetupUniformTexels(image, entry);
1175 } 1158 }
1176} 1159}
1177 1160
1178void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) { 1161void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
1179 MICROPROFILE_SCOPE(Vulkan_Textures); 1162 MICROPROFILE_SCOPE(Vulkan_Textures);
1180 const auto& gpu = system.GPU().KeplerCompute();
1181 for (const auto& entry : entries.samplers) { 1163 for (const auto& entry : entries.samplers) {
1182 for (std::size_t i = 0; i < entry.size; ++i) { 1164 for (std::size_t i = 0; i < entry.size; ++i) {
1183 const auto texture = GetTextureInfo(gpu, entry, ComputeShaderIndex, i); 1165 const auto texture = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex, i);
1184 SetupTexture(texture, entry); 1166 SetupTexture(texture, entry);
1185 } 1167 }
1186 } 1168 }
@@ -1188,18 +1170,16 @@ void RasterizerVulkan::SetupComputeTextures(const ShaderEntries& entries) {
1188 1170
1189void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) { 1171void RasterizerVulkan::SetupComputeStorageTexels(const ShaderEntries& entries) {
1190 MICROPROFILE_SCOPE(Vulkan_Textures); 1172 MICROPROFILE_SCOPE(Vulkan_Textures);
1191 const auto& gpu = system.GPU().KeplerCompute();
1192 for (const auto& entry : entries.storage_texels) { 1173 for (const auto& entry : entries.storage_texels) {
1193 const auto image = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic; 1174 const auto image = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic;
1194 SetupStorageTexel(image, entry); 1175 SetupStorageTexel(image, entry);
1195 } 1176 }
1196} 1177}
1197 1178
1198void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) { 1179void RasterizerVulkan::SetupComputeImages(const ShaderEntries& entries) {
1199 MICROPROFILE_SCOPE(Vulkan_Images); 1180 MICROPROFILE_SCOPE(Vulkan_Images);
1200 const auto& gpu = system.GPU().KeplerCompute();
1201 for (const auto& entry : entries.images) { 1181 for (const auto& entry : entries.images) {
1202 const auto tic = GetTextureInfo(gpu, entry, ComputeShaderIndex).tic; 1182 const auto tic = GetTextureInfo(kepler_compute, entry, ComputeShaderIndex).tic;
1203 SetupImage(tic, entry); 1183 SetupImage(tic, entry);
1204 } 1184 }
1205} 1185}
@@ -1223,9 +1203,8 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry,
1223} 1203}
1224 1204
1225void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address) { 1205void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAddr address) {
1226 auto& memory_manager{system.GPU().MemoryManager()}; 1206 const u64 actual_addr = gpu_memory.Read<u64>(address);
1227 const auto actual_addr = memory_manager.Read<u64>(address); 1207 const u32 size = gpu_memory.Read<u32>(address + 8);
1228 const auto size = memory_manager.Read<u32>(address + 8);
1229 1208
1230 if (size == 0) { 1209 if (size == 0) {
1231 // Sometimes global memory pointers don't have a proper size. Upload a dummy entry 1210 // Sometimes global memory pointers don't have a proper size. Upload a dummy entry
@@ -1508,7 +1487,7 @@ std::size_t RasterizerVulkan::CalculateComputeStreamBufferSize() const {
1508} 1487}
1509 1488
1510std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { 1489std::size_t RasterizerVulkan::CalculateVertexArraysSize() const {
1511 const auto& regs = system.GPU().Maxwell3D().regs; 1490 const auto& regs = maxwell3d.regs;
1512 1491
1513 std::size_t size = 0; 1492 std::size_t size = 0;
1514 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { 1493 for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
@@ -1523,9 +1502,8 @@ std::size_t RasterizerVulkan::CalculateVertexArraysSize() const {
1523} 1502}
1524 1503
1525std::size_t RasterizerVulkan::CalculateIndexBufferSize() const { 1504std::size_t RasterizerVulkan::CalculateIndexBufferSize() const {
1526 const auto& regs = system.GPU().Maxwell3D().regs; 1505 return static_cast<std::size_t>(maxwell3d.regs.index_array.count) *
1527 return static_cast<std::size_t>(regs.index_array.count) * 1506 static_cast<std::size_t>(maxwell3d.regs.index_array.FormatSizeInBytes());
1528 static_cast<std::size_t>(regs.index_array.FormatSizeInBytes());
1529} 1507}
1530 1508
1531std::size_t RasterizerVulkan::CalculateConstBufferSize( 1509std::size_t RasterizerVulkan::CalculateConstBufferSize(
@@ -1540,7 +1518,7 @@ std::size_t RasterizerVulkan::CalculateConstBufferSize(
1540} 1518}
1541 1519
1542RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const { 1520RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) const {
1543 const auto& regs = system.GPU().Maxwell3D().regs; 1521 const auto& regs = maxwell3d.regs;
1544 const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count); 1522 const std::size_t num_attachments = static_cast<std::size_t>(regs.rt_control.count);
1545 1523
1546 RenderPassParams params; 1524 RenderPassParams params;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index f640ba649..16251d0f6 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -106,7 +106,8 @@ struct ImageView {
106 106
107class RasterizerVulkan final : public VideoCore::RasterizerAccelerated { 107class RasterizerVulkan final : public VideoCore::RasterizerAccelerated {
108public: 108public:
109 explicit RasterizerVulkan(Core::System& system, Core::Frontend::EmuWindow& render_window, 109 explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
110 Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory,
110 VKScreenInfo& screen_info, const VKDevice& device, 111 VKScreenInfo& screen_info, const VKDevice& device,
111 VKResourceManager& resource_manager, VKMemoryManager& memory_manager, 112 VKResourceManager& resource_manager, VKMemoryManager& memory_manager,
112 StateTracker& state_tracker, VKScheduler& scheduler); 113 StateTracker& state_tracker, VKScheduler& scheduler);
@@ -135,7 +136,6 @@ public:
135 const Tegra::Engines::Fermi2D::Config& copy_config) override; 136 const Tegra::Engines::Fermi2D::Config& copy_config) override;
136 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 137 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
137 u32 pixel_stride) override; 138 u32 pixel_stride) override;
138 void SetupDirtyFlags() override;
139 139
140 VideoCommon::Shader::AsyncShaders& GetAsyncShaders() { 140 VideoCommon::Shader::AsyncShaders& GetAsyncShaders() {
141 return async_shaders; 141 return async_shaders;
@@ -279,8 +279,11 @@ private:
279 279
280 VkBuffer DefaultBuffer(); 280 VkBuffer DefaultBuffer();
281 281
282 Core::System& system; 282 Tegra::GPU& gpu;
283 Core::Frontend::EmuWindow& render_window; 283 Tegra::MemoryManager& gpu_memory;
284 Tegra::Engines::Maxwell3D& maxwell3d;
285 Tegra::Engines::KeplerCompute& kepler_compute;
286
284 VKScreenInfo& screen_info; 287 VKScreenInfo& screen_info;
285 const VKDevice& device; 288 const VKDevice& device;
286 VKResourceManager& resource_manager; 289 VKResourceManager& resource_manager;
@@ -300,8 +303,8 @@ private:
300 VKPipelineCache pipeline_cache; 303 VKPipelineCache pipeline_cache;
301 VKBufferCache buffer_cache; 304 VKBufferCache buffer_cache;
302 VKSamplerCache sampler_cache; 305 VKSamplerCache sampler_cache;
303 VKFenceManager fence_manager;
304 VKQueryCache query_cache; 306 VKQueryCache query_cache;
307 VKFenceManager fence_manager;
305 308
306 vk::Buffer default_buffer; 309 vk::Buffer default_buffer;
307 VKMemoryCommit default_buffer_commit; 310 VKMemoryCommit default_buffer_commit;
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
index 4bd1009f9..5d2c4a796 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp
@@ -132,12 +132,9 @@ void SetupDirtyStencilTestEnable(Tables& tables) {
132 132
133} // Anonymous namespace 133} // Anonymous namespace
134 134
135StateTracker::StateTracker(Core::System& system) 135StateTracker::StateTracker(Tegra::GPU& gpu)
136 : system{system}, invalidation_flags{MakeInvalidationFlags()} {} 136 : flags{gpu.Maxwell3D().dirty.flags}, invalidation_flags{MakeInvalidationFlags()} {
137 137 auto& tables = gpu.Maxwell3D().dirty.tables;
138void StateTracker::Initialize() {
139 auto& dirty = system.GPU().Maxwell3D().dirty;
140 auto& tables = dirty.tables;
141 SetupDirtyRenderTargets(tables); 138 SetupDirtyRenderTargets(tables);
142 SetupDirtyViewports(tables); 139 SetupDirtyViewports(tables);
143 SetupDirtyScissors(tables); 140 SetupDirtyScissors(tables);
@@ -155,9 +152,4 @@ void StateTracker::Initialize() {
155 SetupDirtyStencilTestEnable(tables); 152 SetupDirtyStencilTestEnable(tables);
156} 153}
157 154
158void StateTracker::InvalidateCommandBufferState() {
159 system.GPU().Maxwell3D().dirty.flags |= invalidation_flags;
160 current_topology = INVALID_TOPOLOGY;
161}
162
163} // namespace Vulkan 155} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h
index 13a6ce786..1de789e57 100644
--- a/src/video_core/renderer_vulkan/vk_state_tracker.h
+++ b/src/video_core/renderer_vulkan/vk_state_tracker.h
@@ -45,11 +45,12 @@ class StateTracker {
45 using Maxwell = Tegra::Engines::Maxwell3D::Regs; 45 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
46 46
47public: 47public:
48 explicit StateTracker(Core::System& system); 48 explicit StateTracker(Tegra::GPU& gpu);
49 49
50 void Initialize(); 50 void InvalidateCommandBufferState() {
51 51 flags |= invalidation_flags;
52 void InvalidateCommandBufferState(); 52 current_topology = INVALID_TOPOLOGY;
53 }
53 54
54 bool TouchViewports() { 55 bool TouchViewports() {
55 return Exchange(Dirty::Viewports, false); 56 return Exchange(Dirty::Viewports, false);
@@ -121,13 +122,12 @@ private:
121 static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u); 122 static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u);
122 123
123 bool Exchange(std::size_t id, bool new_value) const noexcept { 124 bool Exchange(std::size_t id, bool new_value) const noexcept {
124 auto& flags = system.GPU().Maxwell3D().dirty.flags;
125 const bool is_dirty = flags[id]; 125 const bool is_dirty = flags[id];
126 flags[id] = new_value; 126 flags[id] = new_value;
127 return is_dirty; 127 return is_dirty;
128 } 128 }
129 129
130 Core::System& system; 130 Tegra::Engines::Maxwell3D::DirtyState::Flags& flags;
131 Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags; 131 Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
132 Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY; 132 Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY;
133}; 133};
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
index a5526a3f5..3c9171a5e 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -57,9 +57,9 @@ u32 GetMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
57 57
58} // Anonymous namespace 58} // Anonymous namespace
59 59
60VKStreamBuffer::VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler, 60VKStreamBuffer::VKStreamBuffer(const VKDevice& device_, VKScheduler& scheduler_,
61 VkBufferUsageFlags usage) 61 VkBufferUsageFlags usage)
62 : device{device}, scheduler{scheduler} { 62 : device{device_}, scheduler{scheduler_} {
63 CreateBuffers(usage); 63 CreateBuffers(usage);
64 ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE); 64 ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
65 ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE); 65 ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 2c6f54101..06182d909 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -188,13 +188,13 @@ u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, Tegra::Texture::Swizzl
188 188
189} // Anonymous namespace 189} // Anonymous namespace
190 190
191CachedSurface::CachedSurface(Core::System& system, const VKDevice& device, 191CachedSurface::CachedSurface(const VKDevice& device, VKResourceManager& resource_manager,
192 VKResourceManager& resource_manager, VKMemoryManager& memory_manager, 192 VKMemoryManager& memory_manager, VKScheduler& scheduler,
193 VKScheduler& scheduler, VKStagingBufferPool& staging_pool, 193 VKStagingBufferPool& staging_pool, GPUVAddr gpu_addr,
194 GPUVAddr gpu_addr, const SurfaceParams& params) 194 const SurfaceParams& params)
195 : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, system{system}, 195 : SurfaceBase<View>{gpu_addr, params, device.IsOptimalAstcSupported()}, device{device},
196 device{device}, resource_manager{resource_manager}, 196 resource_manager{resource_manager}, memory_manager{memory_manager}, scheduler{scheduler},
197 memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{staging_pool} { 197 staging_pool{staging_pool} {
198 if (params.IsBuffer()) { 198 if (params.IsBuffer()) {
199 buffer = CreateBuffer(device, params, host_memory_size); 199 buffer = CreateBuffer(device, params, host_memory_size);
200 commit = memory_manager.Commit(buffer, false); 200 commit = memory_manager.Commit(buffer, false);
@@ -490,19 +490,21 @@ VkImageView CachedSurfaceView::GetAttachment() {
490 return *render_target; 490 return *render_target;
491} 491}
492 492
493VKTextureCache::VKTextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 493VKTextureCache::VKTextureCache(VideoCore::RasterizerInterface& rasterizer,
494 const VKDevice& device, VKResourceManager& resource_manager, 494 Tegra::Engines::Maxwell3D& maxwell3d,
495 VKMemoryManager& memory_manager, VKScheduler& scheduler, 495 Tegra::MemoryManager& gpu_memory, const VKDevice& device_,
496 VKStagingBufferPool& staging_pool) 496 VKResourceManager& resource_manager_,
497 : TextureCache(system, rasterizer, device.IsOptimalAstcSupported()), device{device}, 497 VKMemoryManager& memory_manager_, VKScheduler& scheduler_,
498 resource_manager{resource_manager}, memory_manager{memory_manager}, scheduler{scheduler}, 498 VKStagingBufferPool& staging_pool_)
499 staging_pool{staging_pool} {} 499 : TextureCache(rasterizer, maxwell3d, gpu_memory, device_.IsOptimalAstcSupported()),
500 device{device_}, resource_manager{resource_manager_},
501 memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{staging_pool_} {}
500 502
501VKTextureCache::~VKTextureCache() = default; 503VKTextureCache::~VKTextureCache() = default;
502 504
503Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) { 505Surface VKTextureCache::CreateSurface(GPUVAddr gpu_addr, const SurfaceParams& params) {
504 return std::make_shared<CachedSurface>(system, device, resource_manager, memory_manager, 506 return std::make_shared<CachedSurface>(device, resource_manager, memory_manager, scheduler,
505 scheduler, staging_pool, gpu_addr, params); 507 staging_pool, gpu_addr, params);
506} 508}
507 509
508void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface, 510void VKTextureCache::ImageCopy(Surface& src_surface, Surface& dst_surface,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 807e26c8a..e47d02c41 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -15,10 +15,6 @@
15#include "video_core/texture_cache/surface_base.h" 15#include "video_core/texture_cache/surface_base.h"
16#include "video_core/texture_cache/texture_cache.h" 16#include "video_core/texture_cache/texture_cache.h"
17 17
18namespace Core {
19class System;
20}
21
22namespace VideoCore { 18namespace VideoCore {
23class RasterizerInterface; 19class RasterizerInterface;
24} 20}
@@ -45,10 +41,10 @@ class CachedSurface final : public VideoCommon::SurfaceBase<View> {
45 friend CachedSurfaceView; 41 friend CachedSurfaceView;
46 42
47public: 43public:
48 explicit CachedSurface(Core::System& system, const VKDevice& device, 44 explicit CachedSurface(const VKDevice& device, VKResourceManager& resource_manager,
49 VKResourceManager& resource_manager, VKMemoryManager& memory_manager, 45 VKMemoryManager& memory_manager, VKScheduler& scheduler,
50 VKScheduler& scheduler, VKStagingBufferPool& staging_pool, 46 VKStagingBufferPool& staging_pool, GPUVAddr gpu_addr,
51 GPUVAddr gpu_addr, const SurfaceParams& params); 47 const SurfaceParams& params);
52 ~CachedSurface(); 48 ~CachedSurface();
53 49
54 void UploadTexture(const std::vector<u8>& staging_buffer) override; 50 void UploadTexture(const std::vector<u8>& staging_buffer) override;
@@ -101,7 +97,6 @@ private:
101 97
102 VkImageSubresourceRange GetImageSubresourceRange() const; 98 VkImageSubresourceRange GetImageSubresourceRange() const;
103 99
104 Core::System& system;
105 const VKDevice& device; 100 const VKDevice& device;
106 VKResourceManager& resource_manager; 101 VKResourceManager& resource_manager;
107 VKMemoryManager& memory_manager; 102 VKMemoryManager& memory_manager;
@@ -201,7 +196,8 @@ private:
201 196
202class VKTextureCache final : public TextureCacheBase { 197class VKTextureCache final : public TextureCacheBase {
203public: 198public:
204 explicit VKTextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 199 explicit VKTextureCache(VideoCore::RasterizerInterface& rasterizer,
200 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
205 const VKDevice& device, VKResourceManager& resource_manager, 201 const VKDevice& device, VKResourceManager& resource_manager,
206 VKMemoryManager& memory_manager, VKScheduler& scheduler, 202 VKMemoryManager& memory_manager, VKScheduler& scheduler,
207 VKStagingBufferPool& staging_pool); 203 VKStagingBufferPool& staging_pool);
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp
index f815584f7..aabd62c5c 100644
--- a/src/video_core/shader/async_shaders.cpp
+++ b/src/video_core/shader/async_shaders.cpp
@@ -73,11 +73,11 @@ void AsyncShaders::KillWorkers() {
73 worker_threads.clear(); 73 worker_threads.clear();
74} 74}
75 75
76bool AsyncShaders::HasWorkQueued() { 76bool AsyncShaders::HasWorkQueued() const {
77 return !pending_queue.empty(); 77 return !pending_queue.empty();
78} 78}
79 79
80bool AsyncShaders::HasCompletedWork() { 80bool AsyncShaders::HasCompletedWork() const {
81 std::shared_lock lock{completed_mutex}; 81 std::shared_lock lock{completed_mutex};
82 return !finished_work.empty(); 82 return !finished_work.empty();
83} 83}
@@ -102,7 +102,7 @@ bool AsyncShaders::IsShaderAsync(const Tegra::GPU& gpu) const {
102} 102}
103 103
104std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() { 104std::vector<AsyncShaders::Result> AsyncShaders::GetCompletedWork() {
105 std::vector<AsyncShaders::Result> results; 105 std::vector<Result> results;
106 { 106 {
107 std::unique_lock lock{completed_mutex}; 107 std::unique_lock lock{completed_mutex};
108 results.assign(std::make_move_iterator(finished_work.begin()), 108 results.assign(std::make_move_iterator(finished_work.begin()),
diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h
index d5ae814d5..7cf8d994c 100644
--- a/src/video_core/shader/async_shaders.h
+++ b/src/video_core/shader/async_shaders.h
@@ -5,11 +5,10 @@
5#pragma once 5#pragma once
6 6
7#include <condition_variable> 7#include <condition_variable>
8#include <deque>
9#include <memory> 8#include <memory>
10#include <shared_mutex> 9#include <shared_mutex>
11#include <thread> 10#include <thread>
12#include "common/bit_field.h" 11
13#include "common/common_types.h" 12#include "common/common_types.h"
14#include "video_core/renderer_opengl/gl_device.h" 13#include "video_core/renderer_opengl/gl_device.h"
15#include "video_core/renderer_opengl/gl_resource_manager.h" 14#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -17,7 +16,6 @@
17#include "video_core/renderer_vulkan/vk_device.h" 16#include "video_core/renderer_vulkan/vk_device.h"
18#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 17#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
19#include "video_core/renderer_vulkan/vk_scheduler.h" 18#include "video_core/renderer_vulkan/vk_scheduler.h"
20#include "video_core/renderer_vulkan/vk_update_descriptor.h"
21 19
22namespace Core::Frontend { 20namespace Core::Frontend {
23class EmuWindow; 21class EmuWindow;
@@ -70,20 +68,20 @@ public:
70 void KillWorkers(); 68 void KillWorkers();
71 69
72 /// Check to see if any shaders have actually been compiled 70 /// Check to see if any shaders have actually been compiled
73 bool HasCompletedWork(); 71 [[nodiscard]] bool HasCompletedWork() const;
74 72
75 /// Deduce if a shader can be build on another thread of MUST be built in sync. We cannot build 73 /// Deduce if a shader can be build on another thread of MUST be built in sync. We cannot build
76 /// every shader async as some shaders are only built and executed once. We try to "guess" which 74 /// every shader async as some shaders are only built and executed once. We try to "guess" which
77 /// shader would be used only once 75 /// shader would be used only once
78 bool IsShaderAsync(const Tegra::GPU& gpu) const; 76 [[nodiscard]] bool IsShaderAsync(const Tegra::GPU& gpu) const;
79 77
80 /// Pulls completed compiled shaders 78 /// Pulls completed compiled shaders
81 std::vector<Result> GetCompletedWork(); 79 [[nodiscard]] std::vector<Result> GetCompletedWork();
82 80
83 void QueueOpenGLShader(const OpenGL::Device& device, Tegra::Engines::ShaderType shader_type, 81 void QueueOpenGLShader(const OpenGL::Device& device, Tegra::Engines::ShaderType shader_type,
84 u64 uid, std::vector<u64> code, std::vector<u64> code_b, u32 main_offset, 82 u64 uid, std::vector<u64> code, std::vector<u64> code_b, u32 main_offset,
85 VideoCommon::Shader::CompilerSettings compiler_settings, 83 CompilerSettings compiler_settings, const Registry& registry,
86 const VideoCommon::Shader::Registry& registry, VAddr cpu_addr); 84 VAddr cpu_addr);
87 85
88 void QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, const Vulkan::VKDevice& device, 86 void QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, const Vulkan::VKDevice& device,
89 Vulkan::VKScheduler& scheduler, 87 Vulkan::VKScheduler& scheduler,
@@ -97,7 +95,7 @@ private:
97 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context); 95 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context);
98 96
99 /// Check our worker queue to see if we have any work queued already 97 /// Check our worker queue to see if we have any work queued already
100 bool HasWorkQueued(); 98 [[nodiscard]] bool HasWorkQueued() const;
101 99
102 struct WorkerParams { 100 struct WorkerParams {
103 Backend backend; 101 Backend backend;
@@ -108,8 +106,8 @@ private:
108 std::vector<u64> code; 106 std::vector<u64> code;
109 std::vector<u64> code_b; 107 std::vector<u64> code_b;
110 u32 main_offset; 108 u32 main_offset;
111 VideoCommon::Shader::CompilerSettings compiler_settings; 109 CompilerSettings compiler_settings;
112 std::optional<VideoCommon::Shader::Registry> registry; 110 std::optional<Registry> registry;
113 VAddr cpu_address; 111 VAddr cpu_address;
114 112
115 // For Vulkan 113 // For Vulkan
@@ -125,13 +123,13 @@ private:
125 }; 123 };
126 124
127 std::condition_variable cv; 125 std::condition_variable cv;
128 std::mutex queue_mutex; 126 mutable std::mutex queue_mutex;
129 std::shared_mutex completed_mutex; 127 mutable std::shared_mutex completed_mutex;
130 std::atomic<bool> is_thread_exiting{}; 128 std::atomic<bool> is_thread_exiting{};
131 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list; 129 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list;
132 std::vector<std::thread> worker_threads; 130 std::vector<std::thread> worker_threads;
133 std::queue<WorkerParams> pending_queue; 131 std::queue<WorkerParams> pending_queue;
134 std::vector<AsyncShaders::Result> finished_work; 132 std::vector<Result> finished_work;
135 Core::Frontend::EmuWindow& emu_window; 133 Core::Frontend::EmuWindow& emu_window;
136}; 134};
137 135
diff --git a/src/video_core/shader/memory_util.cpp b/src/video_core/shader/memory_util.cpp
index 5071c83ca..e18ccba8e 100644
--- a/src/video_core/shader/memory_util.cpp
+++ b/src/video_core/shader/memory_util.cpp
@@ -16,11 +16,10 @@
16 16
17namespace VideoCommon::Shader { 17namespace VideoCommon::Shader {
18 18
19GPUVAddr GetShaderAddress(Core::System& system, 19GPUVAddr GetShaderAddress(Tegra::Engines::Maxwell3D& maxwell3d,
20 Tegra::Engines::Maxwell3D::Regs::ShaderProgram program) { 20 Tegra::Engines::Maxwell3D::Regs::ShaderProgram program) {
21 const auto& gpu{system.GPU().Maxwell3D()}; 21 const auto& shader_config{maxwell3d.regs.shader_config[static_cast<std::size_t>(program)]};
22 const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]}; 22 return maxwell3d.regs.code_address.CodeAddress() + shader_config.offset;
23 return gpu.regs.code_address.CodeAddress() + shader_config.offset;
24} 23}
25 24
26bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) { 25bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) {
diff --git a/src/video_core/shader/memory_util.h b/src/video_core/shader/memory_util.h
index be90d24fd..4624d38e6 100644
--- a/src/video_core/shader/memory_util.h
+++ b/src/video_core/shader/memory_util.h
@@ -11,10 +11,6 @@
11#include "video_core/engines/maxwell_3d.h" 11#include "video_core/engines/maxwell_3d.h"
12#include "video_core/engines/shader_type.h" 12#include "video_core/engines/shader_type.h"
13 13
14namespace Core {
15class System;
16}
17
18namespace Tegra { 14namespace Tegra {
19class MemoryManager; 15class MemoryManager;
20} 16}
@@ -27,7 +23,7 @@ constexpr u32 STAGE_MAIN_OFFSET = 10;
27constexpr u32 KERNEL_MAIN_OFFSET = 0; 23constexpr u32 KERNEL_MAIN_OFFSET = 0;
28 24
29/// Gets the address for the specified shader stage program 25/// Gets the address for the specified shader stage program
30GPUVAddr GetShaderAddress(Core::System& system, 26GPUVAddr GetShaderAddress(Tegra::Engines::Maxwell3D& maxwell3d,
31 Tegra::Engines::Maxwell3D::Regs::ShaderProgram program); 27 Tegra::Engines::Maxwell3D::Regs::ShaderProgram program);
32 28
33/// Gets if the current instruction offset is a scheduler instruction 29/// Gets if the current instruction offset is a scheduler instruction
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index e614a92df..e8515321b 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -163,13 +163,11 @@ SurfaceParams SurfaceParams::CreateForImage(const FormatLookupTable& lookup_tabl
163 return params; 163 return params;
164} 164}
165 165
166SurfaceParams SurfaceParams::CreateForDepthBuffer(Core::System& system) { 166SurfaceParams SurfaceParams::CreateForDepthBuffer(Tegra::Engines::Maxwell3D& maxwell3d) {
167 const auto& regs = system.GPU().Maxwell3D().regs; 167 const auto& regs = maxwell3d.regs;
168
169 const auto block_depth = std::min(regs.zeta.memory_layout.block_depth.Value(), 5U); 168 const auto block_depth = std::min(regs.zeta.memory_layout.block_depth.Value(), 5U);
170 const bool is_layered = regs.zeta_layers > 1 && block_depth == 0; 169 const bool is_layered = regs.zeta_layers > 1 && block_depth == 0;
171 const auto pixel_format = PixelFormatFromDepthFormat(regs.zeta.format); 170 const auto pixel_format = PixelFormatFromDepthFormat(regs.zeta.format);
172
173 return { 171 return {
174 .is_tiled = regs.zeta.memory_layout.type == 172 .is_tiled = regs.zeta.memory_layout.type ==
175 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear, 173 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear,
@@ -191,8 +189,9 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer(Core::System& system) {
191 }; 189 };
192} 190}
193 191
194SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::size_t index) { 192SurfaceParams SurfaceParams::CreateForFramebuffer(Tegra::Engines::Maxwell3D& maxwell3d,
195 const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; 193 std::size_t index) {
194 const auto& config{maxwell3d.regs.rt[index]};
196 SurfaceParams params; 195 SurfaceParams params;
197 params.is_tiled = 196 params.is_tiled =
198 config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; 197 config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
index 118aa689e..4466c3c34 100644
--- a/src/video_core/texture_cache/surface_params.h
+++ b/src/video_core/texture_cache/surface_params.h
@@ -33,10 +33,11 @@ public:
33 const VideoCommon::Shader::Image& entry); 33 const VideoCommon::Shader::Image& entry);
34 34
35 /// Creates SurfaceCachedParams for a depth buffer configuration. 35 /// Creates SurfaceCachedParams for a depth buffer configuration.
36 static SurfaceParams CreateForDepthBuffer(Core::System& system); 36 static SurfaceParams CreateForDepthBuffer(Tegra::Engines::Maxwell3D& maxwell3d);
37 37
38 /// Creates SurfaceCachedParams from a framebuffer configuration. 38 /// Creates SurfaceCachedParams from a framebuffer configuration.
39 static SurfaceParams CreateForFramebuffer(Core::System& system, std::size_t index); 39 static SurfaceParams CreateForFramebuffer(Tegra::Engines::Maxwell3D& maxwell3d,
40 std::size_t index);
40 41
41 /// Creates SurfaceCachedParams from a Fermi2D surface configuration. 42 /// Creates SurfaceCachedParams from a Fermi2D surface configuration.
42 static SurfaceParams CreateForFermiCopySurface( 43 static SurfaceParams CreateForFermiCopySurface(
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 96c4e4cc2..ea835c59f 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -135,8 +135,7 @@ public:
135 return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); 135 return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
136 } 136 }
137 137
138 const std::optional<VAddr> cpu_addr = 138 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
139 system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
140 if (!cpu_addr) { 139 if (!cpu_addr) {
141 return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); 140 return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
142 } 141 }
@@ -160,8 +159,7 @@ public:
160 if (!gpu_addr) { 159 if (!gpu_addr) {
161 return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); 160 return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
162 } 161 }
163 const std::optional<VAddr> cpu_addr = 162 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
164 system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
165 if (!cpu_addr) { 163 if (!cpu_addr) {
166 return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); 164 return GetNullSurface(SurfaceParams::ExpectedTarget(entry));
167 } 165 }
@@ -183,11 +181,11 @@ public:
183 181
184 TView GetDepthBufferSurface(bool preserve_contents) { 182 TView GetDepthBufferSurface(bool preserve_contents) {
185 std::lock_guard lock{mutex}; 183 std::lock_guard lock{mutex};
186 auto& maxwell3d = system.GPU().Maxwell3D(); 184 auto& dirty = maxwell3d.dirty;
187 if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) { 185 if (!dirty.flags[VideoCommon::Dirty::ZetaBuffer]) {
188 return depth_buffer.view; 186 return depth_buffer.view;
189 } 187 }
190 maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer] = false; 188 dirty.flags[VideoCommon::Dirty::ZetaBuffer] = false;
191 189
192 const auto& regs{maxwell3d.regs}; 190 const auto& regs{maxwell3d.regs};
193 const auto gpu_addr{regs.zeta.Address()}; 191 const auto gpu_addr{regs.zeta.Address()};
@@ -195,13 +193,12 @@ public:
195 SetEmptyDepthBuffer(); 193 SetEmptyDepthBuffer();
196 return {}; 194 return {};
197 } 195 }
198 const std::optional<VAddr> cpu_addr = 196 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
199 system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
200 if (!cpu_addr) { 197 if (!cpu_addr) {
201 SetEmptyDepthBuffer(); 198 SetEmptyDepthBuffer();
202 return {}; 199 return {};
203 } 200 }
204 const auto depth_params{SurfaceParams::CreateForDepthBuffer(system)}; 201 const auto depth_params{SurfaceParams::CreateForDepthBuffer(maxwell3d)};
205 auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, preserve_contents, true); 202 auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, preserve_contents, true);
206 if (depth_buffer.target) 203 if (depth_buffer.target)
207 depth_buffer.target->MarkAsRenderTarget(false, NO_RT); 204 depth_buffer.target->MarkAsRenderTarget(false, NO_RT);
@@ -215,7 +212,6 @@ public:
215 TView GetColorBufferSurface(std::size_t index, bool preserve_contents) { 212 TView GetColorBufferSurface(std::size_t index, bool preserve_contents) {
216 std::lock_guard lock{mutex}; 213 std::lock_guard lock{mutex};
217 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); 214 ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
218 auto& maxwell3d = system.GPU().Maxwell3D();
219 if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index]) { 215 if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ColorBuffer0 + index]) {
220 return render_targets[index].view; 216 return render_targets[index].view;
221 } 217 }
@@ -235,15 +231,14 @@ public:
235 return {}; 231 return {};
236 } 232 }
237 233
238 const std::optional<VAddr> cpu_addr = 234 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
239 system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
240 if (!cpu_addr) { 235 if (!cpu_addr) {
241 SetEmptyColorBuffer(index); 236 SetEmptyColorBuffer(index);
242 return {}; 237 return {};
243 } 238 }
244 239
245 auto surface_view = 240 auto surface_view =
246 GetSurface(gpu_addr, *cpu_addr, SurfaceParams::CreateForFramebuffer(system, index), 241 GetSurface(gpu_addr, *cpu_addr, SurfaceParams::CreateForFramebuffer(maxwell3d, index),
247 preserve_contents, true); 242 preserve_contents, true);
248 if (render_targets[index].target) { 243 if (render_targets[index].target) {
249 auto& surface = render_targets[index].target; 244 auto& surface = render_targets[index].target;
@@ -300,9 +295,8 @@ public:
300 const GPUVAddr dst_gpu_addr = dst_config.Address(); 295 const GPUVAddr dst_gpu_addr = dst_config.Address();
301 DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr); 296 DeduceBestBlit(src_params, dst_params, src_gpu_addr, dst_gpu_addr);
302 297
303 const auto& memory_manager = system.GPU().MemoryManager(); 298 const std::optional<VAddr> dst_cpu_addr = gpu_memory.GpuToCpuAddress(dst_gpu_addr);
304 const std::optional<VAddr> dst_cpu_addr = memory_manager.GpuToCpuAddress(dst_gpu_addr); 299 const std::optional<VAddr> src_cpu_addr = gpu_memory.GpuToCpuAddress(src_gpu_addr);
305 const std::optional<VAddr> src_cpu_addr = memory_manager.GpuToCpuAddress(src_gpu_addr);
306 std::pair dst_surface = GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false); 300 std::pair dst_surface = GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false);
307 TView src_surface = GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false).second; 301 TView src_surface = GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false).second;
308 ImageBlit(src_surface, dst_surface.second, copy_config); 302 ImageBlit(src_surface, dst_surface.second, copy_config);
@@ -358,9 +352,11 @@ public:
358 } 352 }
359 353
360protected: 354protected:
361 explicit TextureCache(Core::System& system, VideoCore::RasterizerInterface& rasterizer, 355 explicit TextureCache(VideoCore::RasterizerInterface& rasterizer_,
362 bool is_astc_supported) 356 Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
363 : system{system}, is_astc_supported{is_astc_supported}, rasterizer{rasterizer} { 357 bool is_astc_supported_)
358 : is_astc_supported{is_astc_supported_}, rasterizer{rasterizer_}, maxwell3d{maxwell3d_},
359 gpu_memory{gpu_memory_} {
364 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 360 for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
365 SetEmptyColorBuffer(i); 361 SetEmptyColorBuffer(i);
366 } 362 }
@@ -395,7 +391,7 @@ protected:
395 virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0; 391 virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0;
396 392
397 void ManageRenderTargetUnregister(TSurface& surface) { 393 void ManageRenderTargetUnregister(TSurface& surface) {
398 auto& dirty = system.GPU().Maxwell3D().dirty; 394 auto& dirty = maxwell3d.dirty;
399 const u32 index = surface->GetRenderTarget(); 395 const u32 index = surface->GetRenderTarget();
400 if (index == DEPTH_RT) { 396 if (index == DEPTH_RT) {
401 dirty.flags[VideoCommon::Dirty::ZetaBuffer] = true; 397 dirty.flags[VideoCommon::Dirty::ZetaBuffer] = true;
@@ -408,8 +404,7 @@ protected:
408 void Register(TSurface surface) { 404 void Register(TSurface surface) {
409 const GPUVAddr gpu_addr = surface->GetGpuAddr(); 405 const GPUVAddr gpu_addr = surface->GetGpuAddr();
410 const std::size_t size = surface->GetSizeInBytes(); 406 const std::size_t size = surface->GetSizeInBytes();
411 const std::optional<VAddr> cpu_addr = 407 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
412 system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
413 if (!cpu_addr) { 408 if (!cpu_addr) {
414 LOG_CRITICAL(HW_GPU, "Failed to register surface with unmapped gpu_address 0x{:016x}", 409 LOG_CRITICAL(HW_GPU, "Failed to register surface with unmapped gpu_address 0x{:016x}",
415 gpu_addr); 410 gpu_addr);
@@ -459,7 +454,6 @@ protected:
459 return new_surface; 454 return new_surface;
460 } 455 }
461 456
462 Core::System& system;
463 const bool is_astc_supported; 457 const bool is_astc_supported;
464 458
465private: 459private:
@@ -954,8 +948,7 @@ private:
954 * @param params The parameters on the candidate surface. 948 * @param params The parameters on the candidate surface.
955 **/ 949 **/
956 Deduction DeduceSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) { 950 Deduction DeduceSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
957 const std::optional<VAddr> cpu_addr = 951 const std::optional<VAddr> cpu_addr = gpu_memory.GpuToCpuAddress(gpu_addr);
958 system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
959 952
960 if (!cpu_addr) { 953 if (!cpu_addr) {
961 Deduction result{}; 954 Deduction result{};
@@ -1112,7 +1105,7 @@ private:
1112 1105
1113 void LoadSurface(const TSurface& surface) { 1106 void LoadSurface(const TSurface& surface) {
1114 staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes()); 1107 staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
1115 surface->LoadBuffer(system.GPU().MemoryManager(), staging_cache); 1108 surface->LoadBuffer(gpu_memory, staging_cache);
1116 surface->UploadTexture(staging_cache.GetBuffer(0)); 1109 surface->UploadTexture(staging_cache.GetBuffer(0));
1117 surface->MarkAsModified(false, Tick()); 1110 surface->MarkAsModified(false, Tick());
1118 } 1111 }
@@ -1123,7 +1116,7 @@ private:
1123 } 1116 }
1124 staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes()); 1117 staging_cache.GetBuffer(0).resize(surface->GetHostSizeInBytes());
1125 surface->DownloadTexture(staging_cache.GetBuffer(0)); 1118 surface->DownloadTexture(staging_cache.GetBuffer(0));
1126 surface->FlushBuffer(system.GPU().MemoryManager(), staging_cache); 1119 surface->FlushBuffer(gpu_memory, staging_cache);
1127 surface->MarkAsModified(false, Tick()); 1120 surface->MarkAsModified(false, Tick());
1128 } 1121 }
1129 1122
@@ -1253,6 +1246,8 @@ private:
1253 } 1246 }
1254 1247
1255 VideoCore::RasterizerInterface& rasterizer; 1248 VideoCore::RasterizerInterface& rasterizer;
1249 Tegra::Engines::Maxwell3D& maxwell3d;
1250 Tegra::MemoryManager& gpu_memory;
1256 1251
1257 FormatLookupTable format_lookup_table; 1252 FormatLookupTable format_lookup_table;
1258 FormatCompatibility format_compatibility; 1253 FormatCompatibility format_compatibility;
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 4e3a092c7..a14df06a3 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -21,14 +21,17 @@ namespace {
21std::unique_ptr<VideoCore::RendererBase> CreateRenderer( 21std::unique_ptr<VideoCore::RendererBase> CreateRenderer(
22 Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, 22 Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
23 std::unique_ptr<Core::Frontend::GraphicsContext> context) { 23 std::unique_ptr<Core::Frontend::GraphicsContext> context) {
24 auto& telemetry_session = system.TelemetrySession();
25 auto& cpu_memory = system.Memory();
26
24 switch (Settings::values.renderer_backend.GetValue()) { 27 switch (Settings::values.renderer_backend.GetValue()) {
25 case Settings::RendererBackend::OpenGL: 28 case Settings::RendererBackend::OpenGL:
26 return std::make_unique<OpenGL::RendererOpenGL>(system, emu_window, gpu, 29 return std::make_unique<OpenGL::RendererOpenGL>(telemetry_session, emu_window, cpu_memory,
27 std::move(context)); 30 gpu, std::move(context));
28#ifdef HAS_VULKAN 31#ifdef HAS_VULKAN
29 case Settings::RendererBackend::Vulkan: 32 case Settings::RendererBackend::Vulkan:
30 return std::make_unique<Vulkan::RendererVulkan>(system, emu_window, gpu, 33 return std::make_unique<Vulkan::RendererVulkan>(telemetry_session, emu_window, cpu_memory,
31 std::move(context)); 34 gpu, std::move(context));
32#endif 35#endif
33 default: 36 default:
34 return nullptr; 37 return nullptr;
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 6987e85e1..3ea4e5601 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -68,6 +68,9 @@ add_executable(yuzu
68 configuration/configure_input_advanced.cpp 68 configuration/configure_input_advanced.cpp
69 configuration/configure_input_advanced.h 69 configuration/configure_input_advanced.h
70 configuration/configure_input_advanced.ui 70 configuration/configure_input_advanced.ui
71 configuration/configure_motion_touch.cpp
72 configuration/configure_motion_touch.h
73 configuration/configure_motion_touch.ui
71 configuration/configure_mouse_advanced.cpp 74 configuration/configure_mouse_advanced.cpp
72 configuration/configure_mouse_advanced.h 75 configuration/configure_mouse_advanced.h
73 configuration/configure_mouse_advanced.ui 76 configuration/configure_mouse_advanced.ui
@@ -86,9 +89,13 @@ add_executable(yuzu
86 configuration/configure_system.cpp 89 configuration/configure_system.cpp
87 configuration/configure_system.h 90 configuration/configure_system.h
88 configuration/configure_system.ui 91 configuration/configure_system.ui
92 configuration/configure_touch_from_button.cpp
93 configuration/configure_touch_from_button.h
94 configuration/configure_touch_from_button.ui
89 configuration/configure_touchscreen_advanced.cpp 95 configuration/configure_touchscreen_advanced.cpp
90 configuration/configure_touchscreen_advanced.h 96 configuration/configure_touchscreen_advanced.h
91 configuration/configure_touchscreen_advanced.ui 97 configuration/configure_touchscreen_advanced.ui
98 configuration/configure_touch_widget.h
92 configuration/configure_ui.cpp 99 configuration/configure_ui.cpp
93 configuration/configure_ui.h 100 configuration/configure_ui.h
94 configuration/configure_ui.ui 101 configuration/configure_ui.ui
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index f1b428bde..caa2d06d3 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -30,6 +30,7 @@
30#include "common/scope_exit.h" 30#include "common/scope_exit.h"
31#include "core/core.h" 31#include "core/core.h"
32#include "core/frontend/framebuffer_layout.h" 32#include "core/frontend/framebuffer_layout.h"
33#include "core/hle/kernel/process.h"
33#include "core/settings.h" 34#include "core/settings.h"
34#include "input_common/keyboard.h" 35#include "input_common/keyboard.h"
35#include "input_common/main.h" 36#include "input_common/main.h"
@@ -63,7 +64,8 @@ void EmuThread::run() {
63 emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); 64 emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
64 65
65 system.Renderer().Rasterizer().LoadDiskResources( 66 system.Renderer().Rasterizer().LoadDiskResources(
66 stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { 67 system.CurrentProcess()->GetTitleID(), stop_run,
68 [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
67 emit LoadProgress(stage, value, total); 69 emit LoadProgress(stage, value, total);
68 }); 70 });
69 71
@@ -305,8 +307,8 @@ static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow*
305} 307}
306 308
307GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, 309GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
308 InputCommon::InputSubsystem* input_subsystem_) 310 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_)
309 : QWidget(parent), emu_thread(emu_thread_), input_subsystem{input_subsystem_} { 311 : QWidget(parent), emu_thread(emu_thread_), input_subsystem{std::move(input_subsystem_)} {
310 setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") 312 setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")
311 .arg(QString::fromUtf8(Common::g_build_name), 313 .arg(QString::fromUtf8(Common::g_build_name),
312 QString::fromUtf8(Common::g_scm_branch), 314 QString::fromUtf8(Common::g_scm_branch),
@@ -452,7 +454,7 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
452 int active_points = 0; 454 int active_points = 0;
453 455
454 // average all active touch points 456 // average all active touch points
455 for (const auto tp : event->touchPoints()) { 457 for (const auto& tp : event->touchPoints()) {
456 if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) { 458 if (tp.state() & (Qt::TouchPointPressed | Qt::TouchPointMoved | Qt::TouchPointStationary)) {
457 active_points++; 459 active_points++;
458 pos += tp.pos(); 460 pos += tp.pos();
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index ecb3b8135..ca35cf831 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -6,6 +6,7 @@
6 6
7#include <atomic> 7#include <atomic>
8#include <condition_variable> 8#include <condition_variable>
9#include <memory>
9#include <mutex> 10#include <mutex>
10 11
11#include <QImage> 12#include <QImage>
@@ -126,7 +127,7 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
126 127
127public: 128public:
128 explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, 129 explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
129 InputCommon::InputSubsystem* input_subsystem_); 130 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_);
130 ~GRenderWindow() override; 131 ~GRenderWindow() override;
131 132
132 // EmuWindow implementation. 133 // EmuWindow implementation.
@@ -188,7 +189,7 @@ private:
188 QStringList GetUnsupportedGLExtensions() const; 189 QStringList GetUnsupportedGLExtensions() const;
189 190
190 EmuThread* emu_thread; 191 EmuThread* emu_thread;
191 InputCommon::InputSubsystem* input_subsystem; 192 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
192 193
193 // Main context that will be shared with all other contexts that are requested. 194 // Main context that will be shared with all other contexts that are requested.
194 // If this is used in a shared context setting, then this should not be used directly, but 195 // If this is used in a shared context setting, then this should not be used directly, but
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 489877be9..2bc55a26a 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -51,8 +51,10 @@ const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config:
51 }, 51 },
52}}; 52}};
53 53
54const int Config::default_lstick_mod = Qt::Key_E; 54const std::array<int, 2> Config::default_stick_mod = {
55const int Config::default_rstick_mod = Qt::Key_R; 55 Qt::Key_E,
56 Qt::Key_R,
57};
56 58
57const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons = 59const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
58 { 60 {
@@ -285,7 +287,7 @@ void Config::ReadPlayerValues() {
285 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { 287 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
286 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 288 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
287 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], 289 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
288 default_analogs[i][3], default_analogs[i][4], 0.5f); 290 default_analogs[i][3], default_stick_mod[i], 0.5f);
289 auto& player_analogs = player.analogs[i]; 291 auto& player_analogs = player.analogs[i];
290 292
291 player_analogs = qt_config 293 player_analogs = qt_config
@@ -323,7 +325,7 @@ void Config::ReadDebugValues() {
323 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { 325 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
324 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 326 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
325 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], 327 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
326 default_analogs[i][3], default_analogs[i][4], 0.5f); 328 default_analogs[i][3], default_stick_mod[i], 0.5f);
327 auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; 329 auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
328 330
329 debug_pad_analogs = qt_config 331 debug_pad_analogs = qt_config
@@ -418,14 +420,64 @@ void Config::ReadControlValues() {
418 ReadKeyboardValues(); 420 ReadKeyboardValues();
419 ReadMouseValues(); 421 ReadMouseValues();
420 ReadTouchscreenValues(); 422 ReadTouchscreenValues();
423 ReadMotionTouchValues();
421 424
422 Settings::values.vibration_enabled = 425 Settings::values.vibration_enabled =
423 ReadSetting(QStringLiteral("vibration_enabled"), true).toBool(); 426 ReadSetting(QStringLiteral("vibration_enabled"), true).toBool();
427 Settings::values.use_docked_mode =
428 ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
429
430 qt_config->endGroup();
431}
432
433void Config::ReadMotionTouchValues() {
434 int num_touch_from_button_maps =
435 qt_config->beginReadArray(QStringLiteral("touch_from_button_maps"));
436
437 if (num_touch_from_button_maps > 0) {
438 const auto append_touch_from_button_map = [this] {
439 Settings::TouchFromButtonMap map;
440 map.name = ReadSetting(QStringLiteral("name"), QStringLiteral("default"))
441 .toString()
442 .toStdString();
443 const int num_touch_maps = qt_config->beginReadArray(QStringLiteral("entries"));
444 map.buttons.reserve(num_touch_maps);
445 for (int i = 0; i < num_touch_maps; i++) {
446 qt_config->setArrayIndex(i);
447 std::string touch_mapping =
448 ReadSetting(QStringLiteral("bind")).toString().toStdString();
449 map.buttons.emplace_back(std::move(touch_mapping));
450 }
451 qt_config->endArray(); // entries
452 Settings::values.touch_from_button_maps.emplace_back(std::move(map));
453 };
454
455 for (int i = 0; i < num_touch_from_button_maps; ++i) {
456 qt_config->setArrayIndex(i);
457 append_touch_from_button_map();
458 }
459 } else {
460 Settings::values.touch_from_button_maps.emplace_back(
461 Settings::TouchFromButtonMap{"default", {}});
462 num_touch_from_button_maps = 1;
463 }
464 qt_config->endArray();
465
424 Settings::values.motion_device = 466 Settings::values.motion_device =
425 ReadSetting(QStringLiteral("motion_device"), 467 ReadSetting(QStringLiteral("motion_device"),
426 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")) 468 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"))
427 .toString() 469 .toString()
428 .toStdString(); 470 .toStdString();
471 Settings::values.touch_device =
472 ReadSetting(QStringLiteral("touch_device"), QStringLiteral("engine:emu_window"))
473 .toString()
474 .toStdString();
475 Settings::values.use_touch_from_button =
476 ReadSetting(QStringLiteral("use_touch_from_button"), false).toBool();
477 Settings::values.touch_from_button_map_index =
478 ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt();
479 Settings::values.touch_from_button_map_index =
480 std::clamp(Settings::values.touch_from_button_map_index, 0, num_touch_from_button_maps - 1);
429 Settings::values.udp_input_address = 481 Settings::values.udp_input_address =
430 ReadSetting(QStringLiteral("udp_input_address"), 482 ReadSetting(QStringLiteral("udp_input_address"),
431 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR)) 483 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR))
@@ -436,10 +488,6 @@ void Config::ReadControlValues() {
436 .toInt()); 488 .toInt());
437 Settings::values.udp_pad_index = 489 Settings::values.udp_pad_index =
438 static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt()); 490 static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt());
439 Settings::values.use_docked_mode =
440 ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
441
442 qt_config->endGroup();
443} 491}
444 492
445void Config::ReadCoreValues() { 493void Config::ReadCoreValues() {
@@ -877,7 +925,7 @@ void Config::SavePlayerValues() {
877 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { 925 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
878 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 926 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
879 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], 927 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
880 default_analogs[i][3], default_analogs[i][4], 0.5f); 928 default_analogs[i][3], default_stick_mod[i], 0.5f);
881 WriteSetting(QStringLiteral("player_%1_").arg(p) + 929 WriteSetting(QStringLiteral("player_%1_").arg(p) +
882 QString::fromStdString(Settings::NativeAnalog::mapping[i]), 930 QString::fromStdString(Settings::NativeAnalog::mapping[i]),
883 QString::fromStdString(player.analogs[i]), 931 QString::fromStdString(player.analogs[i]),
@@ -898,7 +946,7 @@ void Config::SaveDebugValues() {
898 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { 946 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
899 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 947 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
900 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], 948 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
901 default_analogs[i][3], default_analogs[i][4], 0.5f); 949 default_analogs[i][3], default_stick_mod[i], 0.5f);
902 WriteSetting(QStringLiteral("debug_pad_") + 950 WriteSetting(QStringLiteral("debug_pad_") +
903 QString::fromStdString(Settings::NativeAnalog::mapping[i]), 951 QString::fromStdString(Settings::NativeAnalog::mapping[i]),
904 QString::fromStdString(Settings::values.debug_pad_analogs[i]), 952 QString::fromStdString(Settings::values.debug_pad_analogs[i]),
@@ -932,6 +980,43 @@ void Config::SaveTouchscreenValues() {
932 WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); 980 WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15);
933} 981}
934 982
983void Config::SaveMotionTouchValues() {
984 WriteSetting(QStringLiteral("motion_device"),
985 QString::fromStdString(Settings::values.motion_device),
986 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
987 WriteSetting(QStringLiteral("touch_device"),
988 QString::fromStdString(Settings::values.touch_device),
989 QStringLiteral("engine:emu_window"));
990 WriteSetting(QStringLiteral("use_touch_from_button"), Settings::values.use_touch_from_button,
991 false);
992 WriteSetting(QStringLiteral("touch_from_button_map"),
993 Settings::values.touch_from_button_map_index, 0);
994 WriteSetting(QStringLiteral("udp_input_address"),
995 QString::fromStdString(Settings::values.udp_input_address),
996 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR));
997 WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
998 InputCommon::CemuhookUDP::DEFAULT_PORT);
999 WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
1000
1001 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
1002 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
1003 qt_config->setArrayIndex(static_cast<int>(p));
1004 WriteSetting(QStringLiteral("name"),
1005 QString::fromStdString(Settings::values.touch_from_button_maps[p].name),
1006 QStringLiteral("default"));
1007 qt_config->beginWriteArray(QStringLiteral("entries"));
1008 for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size();
1009 ++q) {
1010 qt_config->setArrayIndex(static_cast<int>(q));
1011 WriteSetting(
1012 QStringLiteral("bind"),
1013 QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q]));
1014 }
1015 qt_config->endArray();
1016 }
1017 qt_config->endArray();
1018}
1019
935void Config::SaveValues() { 1020void Config::SaveValues() {
936 if (global) { 1021 if (global) {
937 SaveControlValues(); 1022 SaveControlValues();
@@ -974,18 +1059,16 @@ void Config::SaveControlValues() {
974 SaveDebugValues(); 1059 SaveDebugValues();
975 SaveMouseValues(); 1060 SaveMouseValues();
976 SaveTouchscreenValues(); 1061 SaveTouchscreenValues();
1062 SaveMotionTouchValues();
977 1063
978 WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true); 1064 WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true);
979 WriteSetting(QStringLiteral("motion_device"), 1065 WriteSetting(QStringLiteral("motion_device"),
980 QString::fromStdString(Settings::values.motion_device), 1066 QString::fromStdString(Settings::values.motion_device),
981 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01")); 1067 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
1068 WriteSetting(QStringLiteral("touch_device"),
1069 QString::fromStdString(Settings::values.touch_device),
1070 QStringLiteral("engine:emu_window"));
982 WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false); 1071 WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
983 WriteSetting(QStringLiteral("udp_input_address"),
984 QString::fromStdString(Settings::values.udp_input_address),
985 QString::fromUtf8(InputCommon::CemuhookUDP::DEFAULT_ADDR));
986 WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
987 InputCommon::CemuhookUDP::DEFAULT_PORT);
988 WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
989 WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false); 1072 WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
990 1073
991 qt_config->endGroup(); 1074 qt_config->endGroup();
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 9eeaf9d1e..ca0d29c6c 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -24,8 +24,7 @@ public:
24 24
25 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; 25 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
26 static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; 26 static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
27 static const int default_lstick_mod; 27 static const std::array<int, 2> default_stick_mod;
28 static const int default_rstick_mod;
29 static const std::array<int, Settings::NativeMouseButton::NumMouseButtons> 28 static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
30 default_mouse_buttons; 29 default_mouse_buttons;
31 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; 30 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
@@ -39,6 +38,7 @@ private:
39 void ReadKeyboardValues(); 38 void ReadKeyboardValues();
40 void ReadMouseValues(); 39 void ReadMouseValues();
41 void ReadTouchscreenValues(); 40 void ReadTouchscreenValues();
41 void ReadMotionTouchValues();
42 42
43 // Read functions bases off the respective config section names. 43 // Read functions bases off the respective config section names.
44 void ReadAudioValues(); 44 void ReadAudioValues();
@@ -65,6 +65,7 @@ private:
65 void SaveDebugValues(); 65 void SaveDebugValues();
66 void SaveMouseValues(); 66 void SaveMouseValues();
67 void SaveTouchscreenValues(); 67 void SaveTouchscreenValues();
68 void SaveMotionTouchValues();
68 69
69 // Save functions based off the respective config section names. 70 // Save functions based off the respective config section names.
70 void SaveAudioValues(); 71 void SaveAudioValues();
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 5223eed1d..ae3e31762 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -20,6 +20,7 @@
20#include "yuzu/configuration/configure_input.h" 20#include "yuzu/configuration/configure_input.h"
21#include "yuzu/configuration/configure_input_advanced.h" 21#include "yuzu/configuration/configure_input_advanced.h"
22#include "yuzu/configuration/configure_input_player.h" 22#include "yuzu/configuration/configure_input_player.h"
23#include "yuzu/configuration/configure_motion_touch.h"
23#include "yuzu/configuration/configure_mouse_advanced.h" 24#include "yuzu/configuration/configure_mouse_advanced.h"
24#include "yuzu/configuration/configure_touchscreen_advanced.h" 25#include "yuzu/configuration/configure_touchscreen_advanced.h"
25 26
@@ -127,6 +128,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
127 }); 128 });
128 connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, 129 connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
129 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); 130 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
131 connect(advanced, &ConfigureInputAdvanced::CallMotionTouchConfigDialog,
132 [this, input_subsystem] {
133 CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
134 });
130 135
131 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); 136 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
132 connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); 137 connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index db42b826b..81f9dc16c 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -86,6 +86,8 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
86 connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); }); 86 connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); });
87 connect(ui->touchscreen_advanced, &QPushButton::clicked, this, 87 connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
88 [this] { CallTouchscreenConfigDialog(); }); 88 [this] { CallTouchscreenConfigDialog(); });
89 connect(ui->buttonMotionTouch, &QPushButton::clicked, this,
90 &ConfigureInputAdvanced::CallMotionTouchConfigDialog);
89 91
90 LoadConfiguration(); 92 LoadConfiguration();
91} 93}
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h
index d8fcec52d..50bb87768 100644
--- a/src/yuzu/configuration/configure_input_advanced.h
+++ b/src/yuzu/configuration/configure_input_advanced.h
@@ -28,6 +28,7 @@ signals:
28 void CallDebugControllerDialog(); 28 void CallDebugControllerDialog();
29 void CallMouseConfigDialog(); 29 void CallMouseConfigDialog();
30 void CallTouchscreenConfigDialog(); 30 void CallTouchscreenConfigDialog();
31 void CallMotionTouchConfigDialog();
31 32
32private: 33private:
33 void changeEvent(QEvent* event) override; 34 void changeEvent(QEvent* event) override;
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 4e11796a7..a53578837 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -305,8 +305,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
305 } 305 }
306 306
307 // Handle clicks for the modifier buttons as well. 307 // Handle clicks for the modifier buttons as well.
308 ConfigureButtonClick(ui->buttonLStickMod, &lstick_mod, Config::default_lstick_mod); 308 ConfigureButtonClick(ui->buttonLStickMod, &lstick_mod, Config::default_stick_mod[0]);
309 ConfigureButtonClick(ui->buttonRStickMod, &rstick_mod, Config::default_rstick_mod); 309 ConfigureButtonClick(ui->buttonRStickMod, &rstick_mod, Config::default_stick_mod[1]);
310 310
311 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { 311 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
312 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { 312 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
@@ -532,9 +532,9 @@ void ConfigureInputPlayer::RestoreDefaults() {
532 532
533 // Reset Modifier Buttons 533 // Reset Modifier Buttons
534 lstick_mod = 534 lstick_mod =
535 Common::ParamPackage(InputCommon::GenerateKeyboardParam(Config::default_lstick_mod)); 535 Common::ParamPackage(InputCommon::GenerateKeyboardParam(Config::default_stick_mod[0]));
536 rstick_mod = 536 rstick_mod =
537 Common::ParamPackage(InputCommon::GenerateKeyboardParam(Config::default_rstick_mod)); 537 Common::ParamPackage(InputCommon::GenerateKeyboardParam(Config::default_stick_mod[1]));
538 538
539 // Reset Analogs 539 // Reset Analogs
540 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { 540 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp
new file mode 100644
index 000000000..c7d085151
--- /dev/null
+++ b/src/yuzu/configuration/configure_motion_touch.cpp
@@ -0,0 +1,314 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <QCloseEvent>
7#include <QLabel>
8#include <QMessageBox>
9#include <QPushButton>
10#include <QVBoxLayout>
11#include "common/logging/log.h"
12#include "core/settings.h"
13#include "input_common/main.h"
14#include "input_common/udp/client.h"
15#include "input_common/udp/udp.h"
16#include "ui_configure_motion_touch.h"
17#include "yuzu/configuration/configure_motion_touch.h"
18#include "yuzu/configuration/configure_touch_from_button.h"
19
20CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent,
21 const std::string& host, u16 port,
22 u8 pad_index, u16 client_id)
23 : QDialog(parent) {
24 layout = new QVBoxLayout;
25 status_label = new QLabel(tr("Communicating with the server..."));
26 cancel_button = new QPushButton(tr("Cancel"));
27 connect(cancel_button, &QPushButton::clicked, this, [this] {
28 if (!completed) {
29 job->Stop();
30 }
31 accept();
32 });
33 layout->addWidget(status_label);
34 layout->addWidget(cancel_button);
35 setLayout(layout);
36
37 using namespace InputCommon::CemuhookUDP;
38 job = std::make_unique<CalibrationConfigurationJob>(
39 host, port, pad_index, client_id,
40 [this](CalibrationConfigurationJob::Status status) {
41 QString text;
42 switch (status) {
43 case CalibrationConfigurationJob::Status::Ready:
44 text = tr("Touch the top left corner <br>of your touchpad.");
45 break;
46 case CalibrationConfigurationJob::Status::Stage1Completed:
47 text = tr("Now touch the bottom right corner <br>of your touchpad.");
48 break;
49 case CalibrationConfigurationJob::Status::Completed:
50 text = tr("Configuration completed!");
51 break;
52 }
53 QMetaObject::invokeMethod(this, "UpdateLabelText", Q_ARG(QString, text));
54 if (status == CalibrationConfigurationJob::Status::Completed) {
55 QMetaObject::invokeMethod(this, "UpdateButtonText", Q_ARG(QString, tr("OK")));
56 }
57 },
58 [this](u16 min_x_, u16 min_y_, u16 max_x_, u16 max_y_) {
59 completed = true;
60 min_x = min_x_;
61 min_y = min_y_;
62 max_x = max_x_;
63 max_y = max_y_;
64 });
65}
66
67CalibrationConfigurationDialog::~CalibrationConfigurationDialog() = default;
68
69void CalibrationConfigurationDialog::UpdateLabelText(const QString& text) {
70 status_label->setText(text);
71}
72
73void CalibrationConfigurationDialog::UpdateButtonText(const QString& text) {
74 cancel_button->setText(text);
75}
76
77constexpr std::array<std::pair<const char*, const char*>, 2> MotionProviders = {{
78 {"motion_emu", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Mouse (Right Click)")},
79 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
80}};
81
82constexpr std::array<std::pair<const char*, const char*>, 2> TouchProviders = {{
83 {"emu_window", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "Emulator Window")},
84 {"cemuhookudp", QT_TRANSLATE_NOOP("ConfigureMotionTouch", "CemuhookUDP")},
85}};
86
87ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
88 InputCommon::InputSubsystem* input_subsystem_)
89 : QDialog(parent), input_subsystem{input_subsystem_},
90 ui(std::make_unique<Ui::ConfigureMotionTouch>()) {
91 ui->setupUi(this);
92 for (const auto& [provider, name] : MotionProviders) {
93 ui->motion_provider->addItem(tr(name), QString::fromUtf8(provider));
94 }
95 for (const auto& [provider, name] : TouchProviders) {
96 ui->touch_provider->addItem(tr(name), QString::fromUtf8(provider));
97 }
98
99 ui->udp_learn_more->setOpenExternalLinks(true);
100 ui->udp_learn_more->setText(
101 tr("<a "
102 "href='https://yuzu-emu.org/wiki/"
103 "using-a-controller-or-android-phone-for-motion-or-touch-input'><span "
104 "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>"));
105
106 SetConfiguration();
107 UpdateUiDisplay();
108 ConnectEvents();
109}
110
111ConfigureMotionTouch::~ConfigureMotionTouch() = default;
112
113void ConfigureMotionTouch::SetConfiguration() {
114 const Common::ParamPackage motion_param(Settings::values.motion_device);
115 const Common::ParamPackage touch_param(Settings::values.touch_device);
116 const std::string motion_engine = motion_param.Get("engine", "motion_emu");
117 const std::string touch_engine = touch_param.Get("engine", "emu_window");
118
119 ui->motion_provider->setCurrentIndex(
120 ui->motion_provider->findData(QString::fromStdString(motion_engine)));
121 ui->touch_provider->setCurrentIndex(
122 ui->touch_provider->findData(QString::fromStdString(touch_engine)));
123 ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button);
124 touch_from_button_maps = Settings::values.touch_from_button_maps;
125 for (const auto& touch_map : touch_from_button_maps) {
126 ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
127 }
128 ui->touch_from_button_map->setCurrentIndex(Settings::values.touch_from_button_map_index);
129 ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
130
131 min_x = touch_param.Get("min_x", 100);
132 min_y = touch_param.Get("min_y", 50);
133 max_x = touch_param.Get("max_x", 1800);
134 max_y = touch_param.Get("max_y", 850);
135
136 ui->udp_server->setText(QString::fromStdString(Settings::values.udp_input_address));
137 ui->udp_port->setText(QString::number(Settings::values.udp_input_port));
138 ui->udp_pad_index->setCurrentIndex(Settings::values.udp_pad_index);
139}
140
141void ConfigureMotionTouch::UpdateUiDisplay() {
142 const QString motion_engine = ui->motion_provider->currentData().toString();
143 const QString touch_engine = ui->touch_provider->currentData().toString();
144 const QString cemuhook_udp = QStringLiteral("cemuhookudp");
145
146 if (motion_engine == QStringLiteral("motion_emu")) {
147 ui->motion_sensitivity_label->setVisible(true);
148 ui->motion_sensitivity->setVisible(true);
149 } else {
150 ui->motion_sensitivity_label->setVisible(false);
151 ui->motion_sensitivity->setVisible(false);
152 }
153
154 if (touch_engine == cemuhook_udp) {
155 ui->touch_calibration->setVisible(true);
156 ui->touch_calibration_config->setVisible(true);
157 ui->touch_calibration_label->setVisible(true);
158 ui->touch_calibration->setText(
159 QStringLiteral("(%1, %2) - (%3, %4)").arg(min_x).arg(min_y).arg(max_x).arg(max_y));
160 } else {
161 ui->touch_calibration->setVisible(false);
162 ui->touch_calibration_config->setVisible(false);
163 ui->touch_calibration_label->setVisible(false);
164 }
165
166 if (motion_engine == cemuhook_udp || touch_engine == cemuhook_udp) {
167 ui->udp_config_group_box->setVisible(true);
168 } else {
169 ui->udp_config_group_box->setVisible(false);
170 }
171}
172
173void ConfigureMotionTouch::ConnectEvents() {
174 connect(ui->motion_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
175 [this](int index) { UpdateUiDisplay(); });
176 connect(ui->touch_provider, qOverload<int>(&QComboBox::currentIndexChanged), this,
177 [this](int index) { UpdateUiDisplay(); });
178 connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest);
179 connect(ui->touch_calibration_config, &QPushButton::clicked, this,
180 &ConfigureMotionTouch::OnConfigureTouchCalibration);
181 connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this,
182 &ConfigureMotionTouch::OnConfigureTouchFromButton);
183 connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] {
184 if (CanCloseDialog()) {
185 reject();
186 }
187 });
188}
189
190void ConfigureMotionTouch::OnCemuhookUDPTest() {
191 ui->udp_test->setEnabled(false);
192 ui->udp_test->setText(tr("Testing"));
193 udp_test_in_progress = true;
194 InputCommon::CemuhookUDP::TestCommunication(
195 ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toInt()),
196 static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872,
197 [this] {
198 LOG_INFO(Frontend, "UDP input test success");
199 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true));
200 },
201 [this] {
202 LOG_ERROR(Frontend, "UDP input test failed");
203 QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, false));
204 });
205}
206
207void ConfigureMotionTouch::OnConfigureTouchCalibration() {
208 ui->touch_calibration_config->setEnabled(false);
209 ui->touch_calibration_config->setText(tr("Configuring"));
210 CalibrationConfigurationDialog dialog(
211 this, ui->udp_server->text().toStdString(), static_cast<u16>(ui->udp_port->text().toUInt()),
212 static_cast<u8>(ui->udp_pad_index->currentIndex()), 24872);
213 dialog.exec();
214 if (dialog.completed) {
215 min_x = dialog.min_x;
216 min_y = dialog.min_y;
217 max_x = dialog.max_x;
218 max_y = dialog.max_y;
219 LOG_INFO(Frontend,
220 "UDP touchpad calibration config success: min_x={}, min_y={}, max_x={}, max_y={}",
221 min_x, min_y, max_x, max_y);
222 UpdateUiDisplay();
223 } else {
224 LOG_ERROR(Frontend, "UDP touchpad calibration config failed");
225 }
226 ui->touch_calibration_config->setEnabled(true);
227 ui->touch_calibration_config->setText(tr("Configure"));
228}
229
230void ConfigureMotionTouch::closeEvent(QCloseEvent* event) {
231 if (CanCloseDialog()) {
232 event->accept();
233 } else {
234 event->ignore();
235 }
236}
237
238void ConfigureMotionTouch::ShowUDPTestResult(bool result) {
239 udp_test_in_progress = false;
240 if (result) {
241 QMessageBox::information(this, tr("Test Successful"),
242 tr("Successfully received data from the server."));
243 } else {
244 QMessageBox::warning(this, tr("Test Failed"),
245 tr("Could not receive valid data from the server.<br>Please verify "
246 "that the server is set up correctly and "
247 "the address and port are correct."));
248 }
249 ui->udp_test->setEnabled(true);
250 ui->udp_test->setText(tr("Test"));
251}
252
253void ConfigureMotionTouch::OnConfigureTouchFromButton() {
254 ConfigureTouchFromButton dialog{this, touch_from_button_maps, input_subsystem,
255 ui->touch_from_button_map->currentIndex()};
256 if (dialog.exec() != QDialog::Accepted) {
257 return;
258 }
259 touch_from_button_maps = dialog.GetMaps();
260
261 while (ui->touch_from_button_map->count() > 0) {
262 ui->touch_from_button_map->removeItem(0);
263 }
264 for (const auto& touch_map : touch_from_button_maps) {
265 ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
266 }
267 ui->touch_from_button_map->setCurrentIndex(dialog.GetSelectedIndex());
268}
269
270bool ConfigureMotionTouch::CanCloseDialog() {
271 if (udp_test_in_progress) {
272 QMessageBox::warning(this, tr("Citra"),
273 tr("UDP Test or calibration configuration is in progress.<br>Please "
274 "wait for them to finish."));
275 return false;
276 }
277 return true;
278}
279
280void ConfigureMotionTouch::ApplyConfiguration() {
281 if (!CanCloseDialog()) {
282 return;
283 }
284
285 std::string motion_engine = ui->motion_provider->currentData().toString().toStdString();
286 std::string touch_engine = ui->touch_provider->currentData().toString().toStdString();
287
288 Common::ParamPackage motion_param{}, touch_param{};
289 motion_param.Set("engine", std::move(motion_engine));
290 touch_param.Set("engine", std::move(touch_engine));
291
292 if (motion_engine == "motion_emu") {
293 motion_param.Set("sensitivity", static_cast<float>(ui->motion_sensitivity->value()));
294 }
295
296 if (touch_engine == "cemuhookudp") {
297 touch_param.Set("min_x", min_x);
298 touch_param.Set("min_y", min_y);
299 touch_param.Set("max_x", max_x);
300 touch_param.Set("max_y", max_y);
301 }
302
303 Settings::values.motion_device = motion_param.Serialize();
304 Settings::values.touch_device = touch_param.Serialize();
305 Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked();
306 Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex();
307 Settings::values.touch_from_button_maps = touch_from_button_maps;
308 Settings::values.udp_input_address = ui->udp_server->text().toStdString();
309 Settings::values.udp_input_port = static_cast<u16>(ui->udp_port->text().toInt());
310 Settings::values.udp_pad_index = static_cast<u8>(ui->udp_pad_index->currentIndex());
311 input_subsystem->ReloadInputDevices();
312
313 accept();
314}
diff --git a/src/yuzu/configuration/configure_motion_touch.h b/src/yuzu/configuration/configure_motion_touch.h
new file mode 100644
index 000000000..3d4b5d659
--- /dev/null
+++ b/src/yuzu/configuration/configure_motion_touch.h
@@ -0,0 +1,90 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QDialog>
9#include "common/param_package.h"
10
11class QLabel;
12class QPushButton;
13class QVBoxLayout;
14
15namespace InputCommon {
16class InputSubsystem;
17}
18
19namespace InputCommon::CemuhookUDP {
20class CalibrationConfigurationJob;
21}
22
23namespace Ui {
24class ConfigureMotionTouch;
25}
26
27/// A dialog for touchpad calibration configuration.
28class CalibrationConfigurationDialog : public QDialog {
29 Q_OBJECT
30public:
31 explicit CalibrationConfigurationDialog(QWidget* parent, const std::string& host, u16 port,
32 u8 pad_index, u16 client_id);
33 ~CalibrationConfigurationDialog() override;
34
35private:
36 Q_INVOKABLE void UpdateLabelText(const QString& text);
37 Q_INVOKABLE void UpdateButtonText(const QString& text);
38
39 QVBoxLayout* layout;
40 QLabel* status_label;
41 QPushButton* cancel_button;
42 std::unique_ptr<InputCommon::CemuhookUDP::CalibrationConfigurationJob> job;
43
44 // Configuration results
45 bool completed{};
46 u16 min_x{};
47 u16 min_y{};
48 u16 max_x{};
49 u16 max_y{};
50
51 friend class ConfigureMotionTouch;
52};
53
54class ConfigureMotionTouch : public QDialog {
55 Q_OBJECT
56
57public:
58 explicit ConfigureMotionTouch(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_);
59 ~ConfigureMotionTouch() override;
60
61public slots:
62 void ApplyConfiguration();
63
64private slots:
65 void OnCemuhookUDPTest();
66 void OnConfigureTouchCalibration();
67 void OnConfigureTouchFromButton();
68
69private:
70 void closeEvent(QCloseEvent* event) override;
71 Q_INVOKABLE void ShowUDPTestResult(bool result);
72 void SetConfiguration();
73 void UpdateUiDisplay();
74 void ConnectEvents();
75 bool CanCloseDialog();
76
77 InputCommon::InputSubsystem* input_subsystem;
78
79 std::unique_ptr<Ui::ConfigureMotionTouch> ui;
80
81 // Coordinate system of the CemuhookUDP touch provider
82 int min_x{};
83 int min_y{};
84 int max_x{};
85 int max_y{};
86
87 bool udp_test_in_progress{};
88
89 std::vector<Settings::TouchFromButtonMap> touch_from_button_maps;
90};
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui
new file mode 100644
index 000000000..602cf8cd8
--- /dev/null
+++ b/src/yuzu/configuration/configure_motion_touch.ui
@@ -0,0 +1,327 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureMotionTouch</class>
4 <widget class="QDialog" name="ConfigureMotionTouch">
5 <property name="windowTitle">
6 <string>Configure Motion / Touch</string>
7 </property>
8 <property name="geometry">
9 <rect>
10 <x>0</x>
11 <y>0</y>
12 <width>500</width>
13 <height>450</height>
14 </rect>
15 </property>
16 <layout class="QVBoxLayout">
17 <item>
18 <widget class="QGroupBox" name="motion_group_box">
19 <property name="title">
20 <string>Motion</string>
21 </property>
22 <layout class="QVBoxLayout">
23 <item>
24 <layout class="QHBoxLayout">
25 <item>
26 <widget class="QLabel" name="motion_provider_label">
27 <property name="text">
28 <string>Motion Provider:</string>
29 </property>
30 </widget>
31 </item>
32 <item>
33 <widget class="QComboBox" name="motion_provider"/>
34 </item>
35 </layout>
36 </item>
37 <item>
38 <layout class="QHBoxLayout">
39 <item>
40 <widget class="QLabel" name="motion_sensitivity_label">
41 <property name="text">
42 <string>Sensitivity:</string>
43 </property>
44 </widget>
45 </item>
46 <item>
47 <widget class="QDoubleSpinBox" name="motion_sensitivity">
48 <property name="alignment">
49 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
50 </property>
51 <property name="decimals">
52 <number>4</number>
53 </property>
54 <property name="minimum">
55 <double>0.010000000000000</double>
56 </property>
57 <property name="maximum">
58 <double>10.000000000000000</double>
59 </property>
60 <property name="singleStep">
61 <double>0.001000000000000</double>
62 </property>
63 <property name="value">
64 <double>0.010000000000000</double>
65 </property>
66 </widget>
67 </item>
68 </layout>
69 </item>
70 </layout>
71 </widget>
72 </item>
73 <item>
74 <widget class="QGroupBox" name="touch_group_box">
75 <property name="title">
76 <string>Touch</string>
77 </property>
78 <layout class="QVBoxLayout">
79 <item>
80 <layout class="QHBoxLayout">
81 <item>
82 <widget class="QLabel" name="touch_provider_label">
83 <property name="text">
84 <string>Touch Provider:</string>
85 </property>
86 </widget>
87 </item>
88 <item>
89 <widget class="QComboBox" name="touch_provider"/>
90 </item>
91 </layout>
92 </item>
93 <item>
94 <layout class="QHBoxLayout">
95 <item>
96 <widget class="QLabel" name="touch_calibration_label">
97 <property name="text">
98 <string>Calibration:</string>
99 </property>
100 </widget>
101 </item>
102 <item>
103 <widget class="QLabel" name="touch_calibration">
104 <property name="text">
105 <string>(100, 50) - (1800, 850)</string>
106 </property>
107 <property name="alignment">
108 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
109 </property>
110 </widget>
111 </item>
112 <item>
113 <widget class="QPushButton" name="touch_calibration_config">
114 <property name="sizePolicy">
115 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
116 <horstretch>0</horstretch>
117 <verstretch>0</verstretch>
118 </sizepolicy>
119 </property>
120 <property name="text">
121 <string>Configure</string>
122 </property>
123 </widget>
124 </item>
125 </layout>
126 </item>
127 <item>
128 <layout class="QHBoxLayout">
129 <item>
130 <widget class="QCheckBox" name="touch_from_button_checkbox">
131 <property name="sizePolicy">
132 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
133 <horstretch>0</horstretch>
134 <verstretch>0</verstretch>
135 </sizepolicy>
136 </property>
137 <property name="text">
138 <string>Use button mapping:</string>
139 </property>
140 </widget>
141 </item>
142 <item>
143 <widget class="QComboBox" name="touch_from_button_map"/>
144 </item>
145 <item>
146 <widget class="QPushButton" name="touch_from_button_config_btn">
147 <property name="sizePolicy">
148 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
149 <horstretch>0</horstretch>
150 <verstretch>0</verstretch>
151 </sizepolicy>
152 </property>
153 <property name="text">
154 <string>Configure</string>
155 </property>
156 </widget>
157 </item>
158 </layout>
159 </item>
160 </layout>
161 </widget>
162 </item>
163 <item>
164 <widget class="QGroupBox" name="udp_config_group_box">
165 <property name="title">
166 <string>CemuhookUDP Config</string>
167 </property>
168 <layout class="QVBoxLayout">
169 <item>
170 <widget class="QLabel" name="udp_help">
171 <property name="text">
172 <string>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</string>
173 </property>
174 <property name="alignment">
175 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
176 </property>
177 <property name="wordWrap">
178 <bool>true</bool>
179 </property>
180 </widget>
181 </item>
182 <item>
183 <layout class="QHBoxLayout">
184 <item>
185 <widget class="QLabel" name="udp_server_label">
186 <property name="text">
187 <string>Server:</string>
188 </property>
189 </widget>
190 </item>
191 <item>
192 <widget class="QLineEdit" name="udp_server">
193 <property name="sizePolicy">
194 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
195 <horstretch>0</horstretch>
196 <verstretch>0</verstretch>
197 </sizepolicy>
198 </property>
199 </widget>
200 </item>
201 </layout>
202 </item>
203 <item>
204 <layout class="QHBoxLayout">
205 <item>
206 <widget class="QLabel" name="udp_port_label">
207 <property name="text">
208 <string>Port:</string>
209 </property>
210 </widget>
211 </item>
212 <item>
213 <widget class="QLineEdit" name="udp_port">
214 <property name="sizePolicy">
215 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
216 <horstretch>0</horstretch>
217 <verstretch>0</verstretch>
218 </sizepolicy>
219 </property>
220 </widget>
221 </item>
222 </layout>
223 </item>
224 <item>
225 <layout class="QHBoxLayout">
226 <item>
227 <widget class="QLabel" name="udp_pad_index_label">
228 <property name="text">
229 <string>Pad:</string>
230 </property>
231 </widget>
232 </item>
233 <item>
234 <widget class="QComboBox" name="udp_pad_index">
235 <item>
236 <property name="text">
237 <string>Pad 1</string>
238 </property>
239 </item>
240 <item>
241 <property name="text">
242 <string>Pad 2</string>
243 </property>
244 </item>
245 <item>
246 <property name="text">
247 <string>Pad 3</string>
248 </property>
249 </item>
250 <item>
251 <property name="text">
252 <string>Pad 4</string>
253 </property>
254 </item>
255 </widget>
256 </item>
257 </layout>
258 </item>
259 <item>
260 <layout class="QHBoxLayout">
261 <item>
262 <widget class="QLabel" name="udp_learn_more">
263 <property name="text">
264 <string>Learn More</string>
265 </property>
266 </widget>
267 </item>
268 <item>
269 <widget class="QPushButton" name="udp_test">
270 <property name="sizePolicy">
271 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
272 <horstretch>0</horstretch>
273 <verstretch>0</verstretch>
274 </sizepolicy>
275 </property>
276 <property name="text">
277 <string>Test</string>
278 </property>
279 </widget>
280 </item>
281 </layout>
282 </item>
283 </layout>
284 </widget>
285 </item>
286 <item>
287 <spacer>
288 <property name="orientation">
289 <enum>Qt::Vertical</enum>
290 </property>
291 <property name="sizeHint" stdset="0">
292 <size>
293 <width>167</width>
294 <height>55</height>
295 </size>
296 </property>
297 </spacer>
298 </item>
299 <item>
300 <widget class="QDialogButtonBox" name="buttonBox">
301 <property name="standardButtons">
302 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
303 </property>
304 </widget>
305 </item>
306 </layout>
307 </widget>
308 <resources/>
309 <connections>
310 <connection>
311 <sender>buttonBox</sender>
312 <signal>accepted()</signal>
313 <receiver>ConfigureMotionTouch</receiver>
314 <slot>ApplyConfiguration()</slot>
315 <hints>
316 <hint type="sourcelabel">
317 <x>220</x>
318 <y>380</y>
319 </hint>
320 <hint type="destinationlabel">
321 <x>220</x>
322 <y>200</y>
323 </hint>
324 </hints>
325 </connection>
326 </connections>
327</ui>
diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp
new file mode 100644
index 000000000..15557e4b8
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_from_button.cpp
@@ -0,0 +1,623 @@
1// Copyright 2020 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QInputDialog>
6#include <QKeyEvent>
7#include <QMessageBox>
8#include <QMouseEvent>
9#include <QResizeEvent>
10#include <QStandardItemModel>
11#include <QTimer>
12#include "common/param_package.h"
13#include "core/frontend/framebuffer_layout.h"
14#include "core/settings.h"
15#include "input_common/main.h"
16#include "ui_configure_touch_from_button.h"
17#include "yuzu/configuration/configure_touch_from_button.h"
18#include "yuzu/configuration/configure_touch_widget.h"
19
20static QString GetKeyName(int key_code) {
21 switch (key_code) {
22 case Qt::Key_Shift:
23 return QObject::tr("Shift");
24 case Qt::Key_Control:
25 return QObject::tr("Ctrl");
26 case Qt::Key_Alt:
27 return QObject::tr("Alt");
28 case Qt::Key_Meta:
29 return QString{};
30 default:
31 return QKeySequence(key_code).toString();
32 }
33}
34
35static QString ButtonToText(const Common::ParamPackage& param) {
36 if (!param.Has("engine")) {
37 return QObject::tr("[not set]");
38 }
39
40 if (param.Get("engine", "") == "keyboard") {
41 return GetKeyName(param.Get("code", 0));
42 }
43
44 if (param.Get("engine", "") == "sdl") {
45 if (param.Has("hat")) {
46 const QString hat_str = QString::fromStdString(param.Get("hat", ""));
47 const QString direction_str = QString::fromStdString(param.Get("direction", ""));
48
49 return QObject::tr("Hat %1 %2").arg(hat_str, direction_str);
50 }
51
52 if (param.Has("axis")) {
53 const QString axis_str = QString::fromStdString(param.Get("axis", ""));
54 const QString direction_str = QString::fromStdString(param.Get("direction", ""));
55
56 return QObject::tr("Axis %1%2").arg(axis_str, direction_str);
57 }
58
59 if (param.Has("button")) {
60 const QString button_str = QString::fromStdString(param.Get("button", ""));
61
62 return QObject::tr("Button %1").arg(button_str);
63 }
64
65 return {};
66 }
67
68 return QObject::tr("[unknown]");
69}
70
71ConfigureTouchFromButton::ConfigureTouchFromButton(
72 QWidget* parent, const std::vector<Settings::TouchFromButtonMap>& touch_maps,
73 InputCommon::InputSubsystem* input_subsystem_, const int default_index)
74 : QDialog(parent), ui(std::make_unique<Ui::ConfigureTouchFromButton>()),
75 touch_maps(touch_maps), input_subsystem{input_subsystem_}, selected_index(default_index),
76 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
77 ui->setupUi(this);
78 binding_list_model = new QStandardItemModel(0, 3, this);
79 binding_list_model->setHorizontalHeaderLabels(
80 {tr("Button"), tr("X", "X axis"), tr("Y", "Y axis")});
81 ui->binding_list->setModel(binding_list_model);
82 ui->bottom_screen->SetCoordLabel(ui->coord_label);
83
84 SetConfiguration();
85 UpdateUiDisplay();
86 ConnectEvents();
87}
88
89ConfigureTouchFromButton::~ConfigureTouchFromButton() = default;
90
91void ConfigureTouchFromButton::showEvent(QShowEvent* ev) {
92 QWidget::showEvent(ev);
93
94 // width values are not valid in the constructor
95 const int w =
96 ui->binding_list->viewport()->contentsRect().width() / binding_list_model->columnCount();
97 if (w <= 0) {
98 return;
99 }
100 ui->binding_list->setColumnWidth(0, w);
101 ui->binding_list->setColumnWidth(1, w);
102 ui->binding_list->setColumnWidth(2, w);
103}
104
105void ConfigureTouchFromButton::SetConfiguration() {
106 for (const auto& touch_map : touch_maps) {
107 ui->mapping->addItem(QString::fromStdString(touch_map.name));
108 }
109
110 ui->mapping->setCurrentIndex(selected_index);
111}
112
113void ConfigureTouchFromButton::UpdateUiDisplay() {
114 ui->button_delete->setEnabled(touch_maps.size() > 1);
115 ui->button_delete_bind->setEnabled(false);
116
117 binding_list_model->removeRows(0, binding_list_model->rowCount());
118
119 for (const auto& button_str : touch_maps[selected_index].buttons) {
120 Common::ParamPackage package{button_str};
121 QStandardItem* button = new QStandardItem(ButtonToText(package));
122 button->setData(QString::fromStdString(button_str));
123 button->setEditable(false);
124 QStandardItem* xcoord = new QStandardItem(QString::number(package.Get("x", 0)));
125 QStandardItem* ycoord = new QStandardItem(QString::number(package.Get("y", 0)));
126 binding_list_model->appendRow({button, xcoord, ycoord});
127
128 const int dot = ui->bottom_screen->AddDot(package.Get("x", 0), package.Get("y", 0));
129 button->setData(dot, DataRoleDot);
130 }
131}
132
133void ConfigureTouchFromButton::ConnectEvents() {
134 connect(ui->mapping, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
135 SaveCurrentMapping();
136 selected_index = index;
137 UpdateUiDisplay();
138 });
139 connect(ui->button_new, &QPushButton::clicked, this, &ConfigureTouchFromButton::NewMapping);
140 connect(ui->button_delete, &QPushButton::clicked, this,
141 &ConfigureTouchFromButton::DeleteMapping);
142 connect(ui->button_rename, &QPushButton::clicked, this,
143 &ConfigureTouchFromButton::RenameMapping);
144 connect(ui->button_delete_bind, &QPushButton::clicked, this,
145 &ConfigureTouchFromButton::DeleteBinding);
146 connect(ui->binding_list, &QTreeView::doubleClicked, this,
147 &ConfigureTouchFromButton::EditBinding);
148 connect(ui->binding_list->selectionModel(), &QItemSelectionModel::selectionChanged, this,
149 &ConfigureTouchFromButton::OnBindingSelection);
150 connect(binding_list_model, &QStandardItemModel::itemChanged, this,
151 &ConfigureTouchFromButton::OnBindingChanged);
152 connect(ui->binding_list->model(), &QStandardItemModel::rowsAboutToBeRemoved, this,
153 &ConfigureTouchFromButton::OnBindingDeleted);
154 connect(ui->bottom_screen, &TouchScreenPreview::DotAdded, this,
155 &ConfigureTouchFromButton::NewBinding);
156 connect(ui->bottom_screen, &TouchScreenPreview::DotSelected, this,
157 &ConfigureTouchFromButton::SetActiveBinding);
158 connect(ui->bottom_screen, &TouchScreenPreview::DotMoved, this,
159 &ConfigureTouchFromButton::SetCoordinates);
160 connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
161 &ConfigureTouchFromButton::ApplyConfiguration);
162
163 connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
164
165 connect(poll_timer.get(), &QTimer::timeout, [this]() {
166 Common::ParamPackage params;
167 for (auto& poller : device_pollers) {
168 params = poller->GetNextInput();
169 if (params.Has("engine")) {
170 SetPollingResult(params, false);
171 return;
172 }
173 }
174 });
175}
176
177void ConfigureTouchFromButton::SaveCurrentMapping() {
178 auto& map = touch_maps[selected_index];
179 map.buttons.clear();
180 for (int i = 0, rc = binding_list_model->rowCount(); i < rc; ++i) {
181 const auto bind_str = binding_list_model->index(i, 0)
182 .data(Qt::ItemDataRole::UserRole + 1)
183 .toString()
184 .toStdString();
185 if (bind_str.empty()) {
186 continue;
187 }
188 Common::ParamPackage params{bind_str};
189 if (!params.Has("engine")) {
190 continue;
191 }
192 params.Set("x", binding_list_model->index(i, 1).data().toInt());
193 params.Set("y", binding_list_model->index(i, 2).data().toInt());
194 map.buttons.emplace_back(params.Serialize());
195 }
196}
197
198void ConfigureTouchFromButton::NewMapping() {
199 const QString name =
200 QInputDialog::getText(this, tr("New Profile"), tr("Enter the name for the new profile."));
201 if (name.isEmpty()) {
202 return;
203 }
204 touch_maps.emplace_back(Settings::TouchFromButtonMap{name.toStdString(), {}});
205 ui->mapping->addItem(name);
206 ui->mapping->setCurrentIndex(ui->mapping->count() - 1);
207}
208
209void ConfigureTouchFromButton::DeleteMapping() {
210 const auto answer = QMessageBox::question(
211 this, tr("Delete Profile"), tr("Delete profile %1?").arg(ui->mapping->currentText()));
212 if (answer != QMessageBox::Yes) {
213 return;
214 }
215 const bool blocked = ui->mapping->blockSignals(true);
216 ui->mapping->removeItem(selected_index);
217 ui->mapping->blockSignals(blocked);
218 touch_maps.erase(touch_maps.begin() + selected_index);
219 selected_index = ui->mapping->currentIndex();
220 UpdateUiDisplay();
221}
222
223void ConfigureTouchFromButton::RenameMapping() {
224 const QString new_name = QInputDialog::getText(this, tr("Rename Profile"), tr("New name:"));
225 if (new_name.isEmpty()) {
226 return;
227 }
228 ui->mapping->setItemText(selected_index, new_name);
229 touch_maps[selected_index].name = new_name.toStdString();
230}
231
232void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is_new) {
233 binding_list_model->item(row_index, 0)->setText(tr("[press key]"));
234
235 input_setter = [this, row_index, is_new](const Common::ParamPackage& params,
236 const bool cancel) {
237 auto* cell = binding_list_model->item(row_index, 0);
238 if (cancel) {
239 if (is_new) {
240 binding_list_model->removeRow(row_index);
241 } else {
242 cell->setText(
243 ButtonToText(Common::ParamPackage{cell->data().toString().toStdString()}));
244 }
245 } else {
246 cell->setText(ButtonToText(params));
247 cell->setData(QString::fromStdString(params.Serialize()));
248 }
249 };
250
251 device_pollers = input_subsystem->GetPollers(InputCommon::Polling::DeviceType::Button);
252
253 for (auto& poller : device_pollers) {
254 poller->Start();
255 }
256
257 grabKeyboard();
258 grabMouse();
259 qApp->setOverrideCursor(QCursor(Qt::CursorShape::ArrowCursor));
260 timeout_timer->start(5000); // Cancel after 5 seconds
261 poll_timer->start(200); // Check for new inputs every 200ms
262}
263
264void ConfigureTouchFromButton::NewBinding(const QPoint& pos) {
265 auto* button = new QStandardItem();
266 button->setEditable(false);
267 auto* x_coord = new QStandardItem(QString::number(pos.x()));
268 auto* y_coord = new QStandardItem(QString::number(pos.y()));
269
270 const int dot_id = ui->bottom_screen->AddDot(pos.x(), pos.y());
271 button->setData(dot_id, DataRoleDot);
272
273 binding_list_model->appendRow({button, x_coord, y_coord});
274 ui->binding_list->setFocus();
275 ui->binding_list->setCurrentIndex(button->index());
276
277 GetButtonInput(binding_list_model->rowCount() - 1, true);
278}
279
280void ConfigureTouchFromButton::EditBinding(const QModelIndex& qi) {
281 if (qi.row() >= 0 && qi.column() == 0) {
282 GetButtonInput(qi.row(), false);
283 }
284}
285
286void ConfigureTouchFromButton::DeleteBinding() {
287 const int row_index = ui->binding_list->currentIndex().row();
288 if (row_index < 0) {
289 return;
290 }
291 ui->bottom_screen->RemoveDot(binding_list_model->index(row_index, 0).data(DataRoleDot).toInt());
292 binding_list_model->removeRow(row_index);
293}
294
295void ConfigureTouchFromButton::OnBindingSelection(const QItemSelection& selected,
296 const QItemSelection& deselected) {
297 ui->button_delete_bind->setEnabled(!selected.isEmpty());
298 if (!selected.isEmpty()) {
299 const auto dot_data = selected.indexes().first().data(DataRoleDot);
300 if (dot_data.isValid()) {
301 ui->bottom_screen->HighlightDot(dot_data.toInt());
302 }
303 }
304 if (!deselected.isEmpty()) {
305 const auto dot_data = deselected.indexes().first().data(DataRoleDot);
306 if (dot_data.isValid()) {
307 ui->bottom_screen->HighlightDot(dot_data.toInt(), false);
308 }
309 }
310}
311
312void ConfigureTouchFromButton::OnBindingChanged(QStandardItem* item) {
313 if (item->column() == 0) {
314 return;
315 }
316
317 const bool blocked = binding_list_model->blockSignals(true);
318 item->setText(QString::number(
319 std::clamp(item->text().toInt(), 0,
320 static_cast<int>((item->column() == 1 ? Layout::ScreenUndocked::Width
321 : Layout::ScreenUndocked::Height) -
322 1))));
323 binding_list_model->blockSignals(blocked);
324
325 const auto dot_data = binding_list_model->index(item->row(), 0).data(DataRoleDot);
326 if (dot_data.isValid()) {
327 ui->bottom_screen->MoveDot(dot_data.toInt(),
328 binding_list_model->item(item->row(), 1)->text().toInt(),
329 binding_list_model->item(item->row(), 2)->text().toInt());
330 }
331}
332
333void ConfigureTouchFromButton::OnBindingDeleted(const QModelIndex& parent, int first, int last) {
334 for (int i = first; i <= last; ++i) {
335 const auto ix = binding_list_model->index(i, 0);
336 if (!ix.isValid()) {
337 return;
338 }
339 const auto dot_data = ix.data(DataRoleDot);
340 if (dot_data.isValid()) {
341 ui->bottom_screen->RemoveDot(dot_data.toInt());
342 }
343 }
344}
345
346void ConfigureTouchFromButton::SetActiveBinding(const int dot_id) {
347 for (int i = 0; i < binding_list_model->rowCount(); ++i) {
348 if (binding_list_model->index(i, 0).data(DataRoleDot) == dot_id) {
349 ui->binding_list->setCurrentIndex(binding_list_model->index(i, 0));
350 ui->binding_list->setFocus();
351 return;
352 }
353 }
354}
355
356void ConfigureTouchFromButton::SetCoordinates(const int dot_id, const QPoint& pos) {
357 for (int i = 0; i < binding_list_model->rowCount(); ++i) {
358 if (binding_list_model->item(i, 0)->data(DataRoleDot) == dot_id) {
359 binding_list_model->item(i, 1)->setText(QString::number(pos.x()));
360 binding_list_model->item(i, 2)->setText(QString::number(pos.y()));
361 return;
362 }
363 }
364}
365
366void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params,
367 const bool cancel) {
368 releaseKeyboard();
369 releaseMouse();
370 qApp->restoreOverrideCursor();
371 timeout_timer->stop();
372 poll_timer->stop();
373 for (auto& poller : device_pollers) {
374 poller->Stop();
375 }
376 if (input_setter) {
377 (*input_setter)(params, cancel);
378 input_setter.reset();
379 }
380}
381
382void ConfigureTouchFromButton::keyPressEvent(QKeyEvent* event) {
383 if (!input_setter && event->key() == Qt::Key_Delete) {
384 DeleteBinding();
385 return;
386 }
387
388 if (!input_setter) {
389 return QDialog::keyPressEvent(event);
390 }
391
392 if (event->key() != Qt::Key_Escape) {
393 SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
394 false);
395 } else {
396 SetPollingResult({}, true);
397 }
398}
399
400void ConfigureTouchFromButton::ApplyConfiguration() {
401 SaveCurrentMapping();
402 accept();
403}
404
405int ConfigureTouchFromButton::GetSelectedIndex() const {
406 return selected_index;
407}
408
409std::vector<Settings::TouchFromButtonMap> ConfigureTouchFromButton::GetMaps() const {
410 return touch_maps;
411}
412
413TouchScreenPreview::TouchScreenPreview(QWidget* parent) : QFrame(parent) {
414 setBackgroundRole(QPalette::ColorRole::Base);
415}
416
417TouchScreenPreview::~TouchScreenPreview() = default;
418
419void TouchScreenPreview::SetCoordLabel(QLabel* const label) {
420 coord_label = label;
421}
422
423int TouchScreenPreview::AddDot(const int device_x, const int device_y) {
424 QFont dot_font{QStringLiteral("monospace")};
425 dot_font.setStyleHint(QFont::Monospace);
426 dot_font.setPointSize(20);
427
428 auto* dot = new QLabel(this);
429 dot->setAttribute(Qt::WA_TranslucentBackground);
430 dot->setFont(dot_font);
431 dot->setText(QChar(0xD7)); // U+00D7 Multiplication Sign
432 dot->setAlignment(Qt::AlignmentFlag::AlignCenter);
433 dot->setProperty(PropId, ++max_dot_id);
434 dot->setProperty(PropX, device_x);
435 dot->setProperty(PropY, device_y);
436 dot->setCursor(Qt::CursorShape::PointingHandCursor);
437 dot->setMouseTracking(true);
438 dot->installEventFilter(this);
439 dot->show();
440 PositionDot(dot, device_x, device_y);
441 dots.emplace_back(max_dot_id, dot);
442 return max_dot_id;
443}
444
445void TouchScreenPreview::RemoveDot(const int id) {
446 const auto iter = std::find_if(dots.begin(), dots.end(),
447 [id](const auto& entry) { return entry.first == id; });
448 if (iter == dots.cend()) {
449 return;
450 }
451
452 iter->second->deleteLater();
453 dots.erase(iter);
454}
455
456void TouchScreenPreview::HighlightDot(const int id, const bool active) const {
457 for (const auto& dot : dots) {
458 if (dot.first == id) {
459 // use color property from the stylesheet, or fall back to the default palette
460 if (dot_highlight_color.isValid()) {
461 dot.second->setStyleSheet(
462 active ? QStringLiteral("color: %1").arg(dot_highlight_color.name())
463 : QString{});
464 } else {
465 dot.second->setForegroundRole(active ? QPalette::ColorRole::LinkVisited
466 : QPalette::ColorRole::NoRole);
467 }
468 if (active) {
469 dot.second->raise();
470 }
471 return;
472 }
473 }
474}
475
476void TouchScreenPreview::MoveDot(const int id, const int device_x, const int device_y) const {
477 const auto iter = std::find_if(dots.begin(), dots.end(),
478 [id](const auto& entry) { return entry.first == id; });
479 if (iter == dots.cend()) {
480 return;
481 }
482
483 iter->second->setProperty(PropX, device_x);
484 iter->second->setProperty(PropY, device_y);
485 PositionDot(iter->second, device_x, device_y);
486}
487
488void TouchScreenPreview::resizeEvent(QResizeEvent* event) {
489 if (ignore_resize) {
490 return;
491 }
492
493 const int target_width = std::min(width(), height() * 4 / 3);
494 const int target_height = std::min(height(), width() * 3 / 4);
495 if (target_width == width() && target_height == height()) {
496 return;
497 }
498 ignore_resize = true;
499 setGeometry((parentWidget()->contentsRect().width() - target_width) / 2, y(), target_width,
500 target_height);
501 ignore_resize = false;
502
503 if (event->oldSize().width() != target_width || event->oldSize().height() != target_height) {
504 for (const auto& dot : dots) {
505 PositionDot(dot.second);
506 }
507 }
508}
509
510void TouchScreenPreview::mouseMoveEvent(QMouseEvent* event) {
511 if (!coord_label) {
512 return;
513 }
514 const auto pos = MapToDeviceCoords(event->x(), event->y());
515 if (pos) {
516 coord_label->setText(QStringLiteral("X: %1, Y: %2").arg(pos->x()).arg(pos->y()));
517 } else {
518 coord_label->clear();
519 }
520}
521
522void TouchScreenPreview::leaveEvent(QEvent* event) {
523 if (coord_label) {
524 coord_label->clear();
525 }
526}
527
528void TouchScreenPreview::mousePressEvent(QMouseEvent* event) {
529 if (event->button() != Qt::MouseButton::LeftButton) {
530 return;
531 }
532 const auto pos = MapToDeviceCoords(event->x(), event->y());
533 if (pos) {
534 emit DotAdded(*pos);
535 }
536}
537
538bool TouchScreenPreview::eventFilter(QObject* obj, QEvent* event) {
539 switch (event->type()) {
540 case QEvent::Type::MouseButtonPress: {
541 const auto mouse_event = static_cast<QMouseEvent*>(event);
542 if (mouse_event->button() != Qt::MouseButton::LeftButton) {
543 break;
544 }
545 emit DotSelected(obj->property(PropId).toInt());
546
547 drag_state.dot = qobject_cast<QLabel*>(obj);
548 drag_state.start_pos = mouse_event->globalPos();
549 return true;
550 }
551 case QEvent::Type::MouseMove: {
552 if (!drag_state.dot) {
553 break;
554 }
555 const auto mouse_event = static_cast<QMouseEvent*>(event);
556 if (!drag_state.active) {
557 drag_state.active =
558 (mouse_event->globalPos() - drag_state.start_pos).manhattanLength() >=
559 QApplication::startDragDistance();
560 if (!drag_state.active) {
561 break;
562 }
563 }
564 auto current_pos = mapFromGlobal(mouse_event->globalPos());
565 current_pos.setX(std::clamp(current_pos.x(), contentsMargins().left(),
566 contentsMargins().left() + contentsRect().width() - 1));
567 current_pos.setY(std::clamp(current_pos.y(), contentsMargins().top(),
568 contentsMargins().top() + contentsRect().height() - 1));
569 const auto device_coord = MapToDeviceCoords(current_pos.x(), current_pos.y());
570 if (device_coord) {
571 drag_state.dot->setProperty(PropX, device_coord->x());
572 drag_state.dot->setProperty(PropY, device_coord->y());
573 PositionDot(drag_state.dot, device_coord->x(), device_coord->y());
574 emit DotMoved(drag_state.dot->property(PropId).toInt(), *device_coord);
575 if (coord_label) {
576 coord_label->setText(
577 QStringLiteral("X: %1, Y: %2").arg(device_coord->x()).arg(device_coord->y()));
578 }
579 }
580 return true;
581 }
582 case QEvent::Type::MouseButtonRelease: {
583 drag_state.dot.clear();
584 drag_state.active = false;
585 return true;
586 }
587 default:
588 break;
589 }
590 return obj->eventFilter(obj, event);
591}
592
593std::optional<QPoint> TouchScreenPreview::MapToDeviceCoords(const int screen_x,
594 const int screen_y) const {
595 const float t_x = 0.5f + static_cast<float>(screen_x - contentsMargins().left()) *
596 (Layout::ScreenUndocked::Width - 1) / (contentsRect().width() - 1);
597 const float t_y = 0.5f + static_cast<float>(screen_y - contentsMargins().top()) *
598 (Layout::ScreenUndocked::Height - 1) /
599 (contentsRect().height() - 1);
600 if (t_x >= 0.5f && t_x < Layout::ScreenUndocked::Width && t_y >= 0.5f &&
601 t_y < Layout::ScreenUndocked::Height) {
602
603 return QPoint{static_cast<int>(t_x), static_cast<int>(t_y)};
604 }
605 return std::nullopt;
606}
607
608void TouchScreenPreview::PositionDot(QLabel* const dot, const int device_x,
609 const int device_y) const {
610 const float device_coord_x =
611 static_cast<float>(device_x >= 0 ? device_x : dot->property(PropX).toInt());
612 int x_coord = static_cast<int>(
613 device_coord_x * (contentsRect().width() - 1) / (Layout::ScreenUndocked::Width - 1) +
614 contentsMargins().left() - static_cast<float>(dot->width()) / 2 + 0.5f);
615
616 const float device_coord_y =
617 static_cast<float>(device_y >= 0 ? device_y : dot->property(PropY).toInt());
618 const int y_coord = static_cast<int>(
619 device_coord_y * (contentsRect().height() - 1) / (Layout::ScreenUndocked::Height - 1) +
620 contentsMargins().top() - static_cast<float>(dot->height()) / 2 + 0.5f);
621
622 dot->move(x_coord, y_coord);
623}
diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h
new file mode 100644
index 000000000..d9513e3bc
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_from_button.h
@@ -0,0 +1,92 @@
1// Copyright 2020 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <memory>
9#include <optional>
10#include <vector>
11#include <QDialog>
12
13class QItemSelection;
14class QModelIndex;
15class QStandardItemModel;
16class QStandardItem;
17class QTimer;
18
19namespace Common {
20class ParamPackage;
21}
22
23namespace InputCommon {
24class InputSubsystem;
25}
26
27namespace InputCommon::Polling {
28class DevicePoller;
29}
30
31namespace Settings {
32struct TouchFromButtonMap;
33}
34
35namespace Ui {
36class ConfigureTouchFromButton;
37}
38
39class ConfigureTouchFromButton : public QDialog {
40 Q_OBJECT
41
42public:
43 explicit ConfigureTouchFromButton(QWidget* parent,
44 const std::vector<Settings::TouchFromButtonMap>& touch_maps,
45 InputCommon::InputSubsystem* input_subsystem_,
46 int default_index = 0);
47 ~ConfigureTouchFromButton() override;
48
49 int GetSelectedIndex() const;
50 std::vector<Settings::TouchFromButtonMap> GetMaps() const;
51
52public slots:
53 void ApplyConfiguration();
54 void NewBinding(const QPoint& pos);
55 void SetActiveBinding(int dot_id);
56 void SetCoordinates(int dot_id, const QPoint& pos);
57
58protected:
59 void showEvent(QShowEvent* ev) override;
60 void keyPressEvent(QKeyEvent* event) override;
61
62private slots:
63 void NewMapping();
64 void DeleteMapping();
65 void RenameMapping();
66 void EditBinding(const QModelIndex& qi);
67 void DeleteBinding();
68 void OnBindingSelection(const QItemSelection& selected, const QItemSelection& deselected);
69 void OnBindingChanged(QStandardItem* item);
70 void OnBindingDeleted(const QModelIndex& parent, int first, int last);
71
72private:
73 void SetConfiguration();
74 void UpdateUiDisplay();
75 void ConnectEvents();
76 void GetButtonInput(int row_index, bool is_new);
77 void SetPollingResult(const Common::ParamPackage& params, bool cancel);
78 void SaveCurrentMapping();
79
80 std::unique_ptr<Ui::ConfigureTouchFromButton> ui;
81 std::vector<Settings::TouchFromButtonMap> touch_maps;
82 QStandardItemModel* binding_list_model;
83 InputCommon::InputSubsystem* input_subsystem;
84 int selected_index;
85
86 std::unique_ptr<QTimer> timeout_timer;
87 std::unique_ptr<QTimer> poll_timer;
88 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
89 std::optional<std::function<void(const Common::ParamPackage&, bool)>> input_setter;
90
91 static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2;
92};
diff --git a/src/yuzu/configuration/configure_touch_from_button.ui b/src/yuzu/configuration/configure_touch_from_button.ui
new file mode 100644
index 000000000..f581e27e0
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_from_button.ui
@@ -0,0 +1,231 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureTouchFromButton</class>
4 <widget class="QDialog" name="ConfigureTouchFromButton">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>500</width>
10 <height>500</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Touchscreen Mappings</string>
15 </property>
16 <layout class="QVBoxLayout">
17 <item>
18 <layout class="QHBoxLayout" name="horizontalLayout">
19 <item>
20 <widget class="QLabel" name="label">
21 <property name="text">
22 <string>Mapping:</string>
23 </property>
24 <property name="textFormat">
25 <enum>Qt::PlainText</enum>
26 </property>
27 </widget>
28 </item>
29 <item>
30 <widget class="QComboBox" name="mapping">
31 <property name="sizePolicy">
32 <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
33 <horstretch>0</horstretch>
34 <verstretch>0</verstretch>
35 </sizepolicy>
36 </property>
37 </widget>
38 </item>
39 <item>
40 <widget class="QPushButton" name="button_new">
41 <property name="sizePolicy">
42 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
43 <horstretch>0</horstretch>
44 <verstretch>0</verstretch>
45 </sizepolicy>
46 </property>
47 <property name="text">
48 <string>New</string>
49 </property>
50 </widget>
51 </item>
52 <item>
53 <widget class="QPushButton" name="button_delete">
54 <property name="sizePolicy">
55 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
56 <horstretch>0</horstretch>
57 <verstretch>0</verstretch>
58 </sizepolicy>
59 </property>
60 <property name="text">
61 <string>Delete</string>
62 </property>
63 </widget>
64 </item>
65 <item>
66 <widget class="QPushButton" name="button_rename">
67 <property name="sizePolicy">
68 <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
69 <horstretch>0</horstretch>
70 <verstretch>0</verstretch>
71 </sizepolicy>
72 </property>
73 <property name="text">
74 <string>Rename</string>
75 </property>
76 </widget>
77 </item>
78 </layout>
79 </item>
80 <item>
81 <widget class="Line" name="line">
82 <property name="orientation">
83 <enum>Qt::Horizontal</enum>
84 </property>
85 </widget>
86 </item>
87 <item>
88 <layout class="QHBoxLayout" name="horizontalLayout_2">
89 <item>
90 <widget class="QLabel" name="label_2">
91 <property name="text">
92 <string>Click the bottom area to add a point, then press a button to bind.
93Drag points to change position, or double-click table cells to edit values.</string>
94 </property>
95 <property name="textFormat">
96 <enum>Qt::PlainText</enum>
97 </property>
98 </widget>
99 </item>
100 <item>
101 <spacer name="horizontalSpacer">
102 <property name="orientation">
103 <enum>Qt::Horizontal</enum>
104 </property>
105 <property name="sizeHint" stdset="0">
106 <size>
107 <width>40</width>
108 <height>20</height>
109 </size>
110 </property>
111 </spacer>
112 </item>
113 <item>
114 <widget class="QPushButton" name="button_delete_bind">
115 <property name="text">
116 <string>Delete Point</string>
117 </property>
118 </widget>
119 </item>
120 </layout>
121 </item>
122 <item>
123 <widget class="QTreeView" name="binding_list">
124 <property name="sizePolicy">
125 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
126 <horstretch>0</horstretch>
127 <verstretch>0</verstretch>
128 </sizepolicy>
129 </property>
130 <property name="rootIsDecorated">
131 <bool>false</bool>
132 </property>
133 <property name="uniformRowHeights">
134 <bool>true</bool>
135 </property>
136 <property name="itemsExpandable">
137 <bool>false</bool>
138 </property>
139 </widget>
140 </item>
141 <item>
142 <widget class="TouchScreenPreview" name="bottom_screen">
143 <property name="sizePolicy">
144 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
145 <horstretch>0</horstretch>
146 <verstretch>0</verstretch>
147 </sizepolicy>
148 </property>
149 <property name="minimumSize">
150 <size>
151 <width>160</width>
152 <height>120</height>
153 </size>
154 </property>
155 <property name="baseSize">
156 <size>
157 <width>320</width>
158 <height>240</height>
159 </size>
160 </property>
161 <property name="cursor">
162 <cursorShape>CrossCursor</cursorShape>
163 </property>
164 <property name="mouseTracking">
165 <bool>true</bool>
166 </property>
167 <property name="autoFillBackground">
168 <bool>true</bool>
169 </property>
170 <property name="frameShape">
171 <enum>QFrame::StyledPanel</enum>
172 </property>
173 <property name="frameShadow">
174 <enum>QFrame::Sunken</enum>
175 </property>
176 </widget>
177 </item>
178 <item>
179 <layout class="QHBoxLayout" name="horizontalLayout_3">
180 <item>
181 <widget class="QLabel" name="coord_label">
182 <property name="sizePolicy">
183 <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
184 <horstretch>0</horstretch>
185 <verstretch>0</verstretch>
186 </sizepolicy>
187 </property>
188 <property name="textFormat">
189 <enum>Qt::PlainText</enum>
190 </property>
191 </widget>
192 </item>
193 <item>
194 <widget class="QDialogButtonBox" name="buttonBox">
195 <property name="standardButtons">
196 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
197 </property>
198 </widget>
199 </item>
200 </layout>
201 </item>
202 </layout>
203 </widget>
204 <customwidgets>
205 <customwidget>
206 <class>TouchScreenPreview</class>
207 <extends>QFrame</extends>
208 <header>yuzu/configuration/configure_touch_widget.h</header>
209 <container>1</container>
210 </customwidget>
211 </customwidgets>
212 <resources/>
213 <connections>
214 <connection>
215 <sender>buttonBox</sender>
216 <signal>rejected()</signal>
217 <receiver>ConfigureTouchFromButton</receiver>
218 <slot>reject()</slot>
219 <hints>
220 <hint type="sourcelabel">
221 <x>249</x>
222 <y>428</y>
223 </hint>
224 <hint type="destinationlabel">
225 <x>249</x>
226 <y>224</y>
227 </hint>
228 </hints>
229 </connection>
230 </connections>
231</ui>
diff --git a/src/yuzu/configuration/configure_touch_widget.h b/src/yuzu/configuration/configure_touch_widget.h
new file mode 100644
index 000000000..347b46583
--- /dev/null
+++ b/src/yuzu/configuration/configure_touch_widget.h
@@ -0,0 +1,62 @@
1// Copyright 2020 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <optional>
8#include <utility>
9#include <vector>
10#include <QFrame>
11#include <QPointer>
12
13class QLabel;
14
15// Widget for representing touchscreen coordinates
16class TouchScreenPreview : public QFrame {
17 Q_OBJECT
18 Q_PROPERTY(QColor dotHighlightColor MEMBER dot_highlight_color)
19
20public:
21 explicit TouchScreenPreview(QWidget* parent);
22 ~TouchScreenPreview() override;
23
24 void SetCoordLabel(QLabel*);
25 int AddDot(int device_x, int device_y);
26 void RemoveDot(int id);
27 void HighlightDot(int id, bool active = true) const;
28 void MoveDot(int id, int device_x, int device_y) const;
29
30signals:
31 void DotAdded(const QPoint& pos);
32 void DotSelected(int dot_id);
33 void DotMoved(int dot_id, const QPoint& pos);
34
35protected:
36 void resizeEvent(QResizeEvent*) override;
37 void mouseMoveEvent(QMouseEvent*) override;
38 void leaveEvent(QEvent*) override;
39 void mousePressEvent(QMouseEvent*) override;
40 bool eventFilter(QObject*, QEvent*) override;
41
42private:
43 std::optional<QPoint> MapToDeviceCoords(int screen_x, int screen_y) const;
44 void PositionDot(QLabel* dot, int device_x = -1, int device_y = -1) const;
45
46 bool ignore_resize = false;
47 QPointer<QLabel> coord_label;
48
49 std::vector<std::pair<int, QLabel*>> dots;
50 int max_dot_id = 0;
51 QColor dot_highlight_color;
52 static constexpr char PropId[] = "dot_id";
53 static constexpr char PropX[] = "device_x";
54 static constexpr char PropY[] = "device_y";
55
56 struct DragState {
57 bool active = false;
58 QPointer<QLabel> dot;
59 QPoint start_pos;
60 };
61 DragState drag_state;
62};
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 0cd0054c8..92779a9c7 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -49,10 +49,10 @@ class GameListItem : public QStandardItem {
49 49
50public: 50public:
51 // used to access type from item index 51 // used to access type from item index
52 static const int TypeRole = Qt::UserRole + 1; 52 static constexpr int TypeRole = Qt::UserRole + 1;
53 static const int SortRole = Qt::UserRole + 2; 53 static constexpr int SortRole = Qt::UserRole + 2;
54 GameListItem() = default; 54 GameListItem() = default;
55 GameListItem(const QString& string) : QStandardItem(string) { 55 explicit GameListItem(const QString& string) : QStandardItem(string) {
56 setData(string, SortRole); 56 setData(string, SortRole);
57 } 57 }
58}; 58};
@@ -65,10 +65,10 @@ public:
65 */ 65 */
66class GameListItemPath : public GameListItem { 66class GameListItemPath : public GameListItem {
67public: 67public:
68 static const int TitleRole = SortRole + 1; 68 static constexpr int TitleRole = SortRole + 1;
69 static const int FullPathRole = SortRole + 2; 69 static constexpr int FullPathRole = SortRole + 2;
70 static const int ProgramIdRole = SortRole + 3; 70 static constexpr int ProgramIdRole = SortRole + 3;
71 static const int FileTypeRole = SortRole + 4; 71 static constexpr int FileTypeRole = SortRole + 4;
72 72
73 GameListItemPath() = default; 73 GameListItemPath() = default;
74 GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data, 74 GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data,
@@ -110,18 +110,22 @@ public:
110 const auto& row1 = row_data.at(UISettings::values.row_1_text_id); 110 const auto& row1 = row_data.at(UISettings::values.row_1_text_id);
111 const int row2_id = UISettings::values.row_2_text_id; 111 const int row2_id = UISettings::values.row_2_text_id;
112 112
113 if (role == SortRole) 113 if (role == SortRole) {
114 return row1.toLower(); 114 return row1.toLower();
115 }
115 116
116 if (row2_id == 4) // None 117 // None
118 if (row2_id == 4) {
117 return row1; 119 return row1;
120 }
118 121
119 const auto& row2 = row_data.at(row2_id); 122 const auto& row2 = row_data.at(row2_id);
120 123
121 if (row1 == row2) 124 if (row1 == row2) {
122 return row1; 125 return row1;
126 }
123 127
124 return QString(row1 + QStringLiteral("\n ") + row2); 128 return QStringLiteral("%1\n %2").arg(row1, row2);
125 } 129 }
126 130
127 return GameListItem::data(role); 131 return GameListItem::data(role);
@@ -131,7 +135,7 @@ public:
131class GameListItemCompat : public GameListItem { 135class GameListItemCompat : public GameListItem {
132 Q_DECLARE_TR_FUNCTIONS(GameListItemCompat) 136 Q_DECLARE_TR_FUNCTIONS(GameListItemCompat)
133public: 137public:
134 static const int CompatNumberRole = SortRole; 138 static constexpr int CompatNumberRole = SortRole;
135 GameListItemCompat() = default; 139 GameListItemCompat() = default;
136 explicit GameListItemCompat(const QString& compatibility) { 140 explicit GameListItemCompat(const QString& compatibility) {
137 setData(type(), TypeRole); 141 setData(type(), TypeRole);
@@ -181,7 +185,7 @@ public:
181 */ 185 */
182class GameListItemSize : public GameListItem { 186class GameListItemSize : public GameListItem {
183public: 187public:
184 static const int SizeRole = SortRole; 188 static constexpr int SizeRole = SortRole;
185 189
186 GameListItemSize() = default; 190 GameListItemSize() = default;
187 explicit GameListItemSize(const qulonglong size_bytes) { 191 explicit GameListItemSize(const qulonglong size_bytes) {
@@ -217,7 +221,7 @@ public:
217 221
218class GameListDir : public GameListItem { 222class GameListDir : public GameListItem {
219public: 223public:
220 static const int GameDirRole = Qt::UserRole + 2; 224 static constexpr int GameDirRole = Qt::UserRole + 2;
221 225
222 explicit GameListDir(UISettings::GameDir& directory, 226 explicit GameListDir(UISettings::GameDir& directory,
223 GameListItemType dir_type = GameListItemType::CustomDir) 227 GameListItemType dir_type = GameListItemType::CustomDir)
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index cab9d680a..a1b61d119 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -187,7 +187,7 @@ static void InitializeLogging() {
187} 187}
188 188
189GMainWindow::GMainWindow() 189GMainWindow::GMainWindow()
190 : input_subsystem{std::make_unique<InputCommon::InputSubsystem>()}, 190 : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
191 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, 191 config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
192 provider{std::make_unique<FileSys::ManualContentProvider>()} { 192 provider{std::make_unique<FileSys::ManualContentProvider>()} {
193 InitializeLogging(); 193 InitializeLogging();
@@ -474,7 +474,7 @@ void GMainWindow::InitializeWidgets() {
474#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING 474#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
475 ui.action_Report_Compatibility->setVisible(true); 475 ui.action_Report_Compatibility->setVisible(true);
476#endif 476#endif
477 render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem.get()); 477 render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem);
478 render_window->hide(); 478 render_window->hide();
479 479
480 game_list = new GameList(vfs, provider.get(), this); 480 game_list = new GameList(vfs, provider.get(), this);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 957f20fa8..0ce66a1ca 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -258,7 +258,7 @@ private:
258 Ui::MainWindow ui; 258 Ui::MainWindow ui;
259 259
260 std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc; 260 std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;
261 std::unique_ptr<InputCommon::InputSubsystem> input_subsystem; 261 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
262 262
263 GRenderWindow* render_window; 263 GRenderWindow* render_window;
264 GameList* game_list; 264 GameList* game_list;
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 87ea985d8..2f3792247 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -293,7 +293,7 @@
293 <bool>false</bool> 293 <bool>false</bool>
294 </property> 294 </property>
295 <property name="text"> 295 <property name="text">
296 <string>Configure Current Game..</string> 296 <string>Configure Current Game...</string>
297 </property> 297 </property>
298 </action> 298 </action>
299 </widget> 299 </widget>
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 4f00c804d..e960b5413 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -26,6 +26,7 @@
26#include "core/file_sys/registered_cache.h" 26#include "core/file_sys/registered_cache.h"
27#include "core/file_sys/vfs_real.h" 27#include "core/file_sys/vfs_real.h"
28#include "core/gdbstub/gdbstub.h" 28#include "core/gdbstub/gdbstub.h"
29#include "core/hle/kernel/process.h"
29#include "core/hle/service/filesystem/filesystem.h" 30#include "core/hle/service/filesystem/filesystem.h"
30#include "core/loader/loader.h" 31#include "core/loader/loader.h"
31#include "core/settings.h" 32#include "core/settings.h"
@@ -235,7 +236,9 @@ int main(int argc, char** argv) {
235 // Core is loaded, start the GPU (makes the GPU contexts current to this thread) 236 // Core is loaded, start the GPU (makes the GPU contexts current to this thread)
236 system.GPU().Start(); 237 system.GPU().Start();
237 238
238 system.Renderer().Rasterizer().LoadDiskResources(); 239 system.Renderer().Rasterizer().LoadDiskResources(
240 system.CurrentProcess()->GetTitleID(), false,
241 [](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
239 242
240 std::thread render_thread([&emu_window] { emu_window->Present(); }); 243 std::thread render_thread([&emu_window] { emu_window->Present(); });
241 system.Run(); 244 system.Run();
diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp
index 7acf0caad..5798ce43a 100644
--- a/src/yuzu_tester/yuzu.cpp
+++ b/src/yuzu_tester/yuzu.cpp
@@ -255,7 +255,6 @@ int main(int argc, char** argv) {
255 "SDLHideTester"); 255 "SDLHideTester");
256 256
257 system.GPU().Start(); 257 system.GPU().Start();
258 system.Renderer().Rasterizer().LoadDiskResources();
259 258
260 system.Run(); 259 system.Run();
261 while (!finished) { 260 while (!finished) {