summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/renderer/system.cpp5
-rw-r--r--src/common/address_space.inc2
-rw-r--r--src/common/input.h2
-rw-r--r--src/common/settings.cpp4
-rw-r--r--src/common/settings.h4
-rw-r--r--src/common/vector_math.h14
-rw-r--r--src/core/core.cpp7
-rw-r--r--src/core/hid/emulated_controller.cpp10
-rw-r--r--src/core/hid/emulated_controller.h1
-rw-r--r--src/core/hid/input_converter.cpp1
-rw-r--r--src/core/hid/motion_input.cpp36
-rw-r--r--src/core/hid/motion_input.h2
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp7
-rw-r--r--src/core/hle/kernel/k_auto_object.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp31
-rw-r--r--src/core/hle/service/ipc_helpers.h1
-rw-r--r--src/core/hle/service/kernel_helpers.cpp3
-rw-r--r--src/core/hle/service/mutex.cpp3
-rw-r--r--src/core/hle/service/server_manager.cpp6
-rw-r--r--src/core/hle/service/sm/sm.cpp3
-rw-r--r--src/core/hle/service/sm/sm_controller.cpp3
-rw-r--r--src/core/memory.cpp2
-rw-r--r--src/input_common/input_engine.cpp2
-rw-r--r--src/input_common/input_poller.cpp1
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h2
-rw-r--r--src/video_core/buffer_cache/memory_tracker_base.h6
-rw-r--r--src/video_core/compatible_formats.cpp20
-rw-r--r--src/video_core/fence_manager.h143
-rw-r--r--src/video_core/memory_manager.cpp13
-rw-r--r--src/video_core/memory_manager.h4
-rw-r--r--src/video_core/query_cache.h137
-rw-r--r--src/video_core/renderer_opengl/gl_fence_manager.h12
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.h6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h3
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp3
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h11
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp6
-rw-r--r--src/video_core/shader_cache.cpp4
-rw-r--r--src/video_core/shader_environment.cpp16
-rw-r--r--src/video_core/shader_environment.h6
-rw-r--r--src/video_core/surface.cpp5
-rw-r--r--src/video_core/surface.h12
-rw-r--r--src/video_core/texture_cache/format_lookup_table.cpp6
-rw-r--r--src/video_core/texture_cache/formatter.h6
-rw-r--r--src/video_core/texture_cache/texture_cache.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp4
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/configure_general.cpp9
-rw-r--r--src/yuzu/configuration/configure_general.h1
-rw-r--r--src/yuzu/configuration/configure_general.ui7
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp8
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h1
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui10
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp10
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp91
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h5
-rw-r--r--src/yuzu/configuration/configure_system.cpp10
-rw-r--r--src/yuzu/configuration/configure_system.h1
-rw-r--r--src/yuzu/configuration/configure_system.ui7
-rw-r--r--src/yuzu_cmd/config.cpp3
-rw-r--r--src/yuzu_cmd/default_ini.h8
70 files changed, 626 insertions, 185 deletions
diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp
index ad869facb..53b258c4f 100644
--- a/src/audio_core/renderer/system.cpp
+++ b/src/audio_core/renderer/system.cpp
@@ -436,10 +436,7 @@ void System::Stop() {
436 } 436 }
437 437
438 if (execution_mode == ExecutionMode::Auto) { 438 if (execution_mode == ExecutionMode::Auto) {
439 // Should wait for the system to terminate here, but core timing (should have) already 439 terminate_event.Wait();
440 // stopped, so this isn't needed. Find a way to make this definite.
441
442 // terminate_event.Wait();
443 } 440 }
444} 441}
445 442
diff --git a/src/common/address_space.inc b/src/common/address_space.inc
index 2195dabd5..c97dc8651 100644
--- a/src/common/address_space.inc
+++ b/src/common/address_space.inc
@@ -72,7 +72,7 @@ MAP_MEMBER(void)::MapLocked(VaType virt, PaType phys, VaType size, ExtraBlockInf
72 } 72 }
73 }()}; 73 }()};
74 74
75 if (block_end_predecessor->virt >= virt) { 75 if (block_end_predecessor != blocks.begin() && block_end_predecessor->virt >= virt) {
76 // If this block's start would be overlapped by the map then reuse it as a tail 76 // If this block's start would be overlapped by the map then reuse it as a tail
77 // block 77 // block
78 block_end_predecessor->virt = virt_end; 78 block_end_predecessor->virt = virt_end;
diff --git a/src/common/input.h b/src/common/input.h
index 51b277c1f..66fb15f0a 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -111,6 +111,8 @@ struct AnalogProperties {
111 float offset{}; 111 float offset{};
112 // Invert direction of the sensor data 112 // Invert direction of the sensor data
113 bool inverted{}; 113 bool inverted{};
114 // Invert the state if it's converted to a button
115 bool inverted_button{};
114 // Press once to activate, press again to release 116 // Press once to activate, press again to release
115 bool toggle{}; 117 bool toggle{};
116}; 118};
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 77ff21128..174460c5e 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -45,6 +45,7 @@ void LogSettings() {
45 log_setting("System_LanguageIndex", values.language_index.GetValue()); 45 log_setting("System_LanguageIndex", values.language_index.GetValue());
46 log_setting("System_RegionIndex", values.region_index.GetValue()); 46 log_setting("System_RegionIndex", values.region_index.GetValue());
47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
48 log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue());
48 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 49 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
49 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue()); 50 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
50 log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue()); 51 log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
@@ -191,7 +192,7 @@ void RestoreGlobalState(bool is_powered_on) {
191 192
192 // Core 193 // Core
193 values.use_multi_core.SetGlobal(true); 194 values.use_multi_core.SetGlobal(true);
194 values.use_extended_memory_layout.SetGlobal(true); 195 values.use_unsafe_extended_memory_layout.SetGlobal(true);
195 196
196 // CPU 197 // CPU
197 values.cpu_accuracy.SetGlobal(true); 198 values.cpu_accuracy.SetGlobal(true);
@@ -226,7 +227,6 @@ void RestoreGlobalState(bool is_powered_on) {
226 values.shader_backend.SetGlobal(true); 227 values.shader_backend.SetGlobal(true);
227 values.use_asynchronous_shaders.SetGlobal(true); 228 values.use_asynchronous_shaders.SetGlobal(true);
228 values.use_fast_gpu_time.SetGlobal(true); 229 values.use_fast_gpu_time.SetGlobal(true);
229 values.use_pessimistic_flushes.SetGlobal(true);
230 values.use_vulkan_driver_pipeline_cache.SetGlobal(true); 230 values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
231 values.bg_red.SetGlobal(true); 231 values.bg_red.SetGlobal(true);
232 values.bg_green.SetGlobal(true); 232 values.bg_green.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 5379d0dd5..55200c36f 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -388,7 +388,8 @@ struct Values {
388 388
389 // Core 389 // Core
390 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"}; 390 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
391 SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"}; 391 SwitchableSetting<bool> use_unsafe_extended_memory_layout{false,
392 "use_unsafe_extended_memory_layout"};
392 393
393 // Cpu 394 // Cpu
394 SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, 395 SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
@@ -460,7 +461,6 @@ struct Values {
460 ShaderBackend::SPIRV, "shader_backend"}; 461 ShaderBackend::SPIRV, "shader_backend"};
461 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 462 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
462 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 463 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
463 SwitchableSetting<bool> use_pessimistic_flushes{false, "use_pessimistic_flushes"};
464 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true, 464 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
465 "use_vulkan_driver_pipeline_cache"}; 465 "use_vulkan_driver_pipeline_cache"};
466 466
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 0e2095c45..b4885835d 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -259,6 +259,20 @@ public:
259 return *this; 259 return *this;
260 } 260 }
261 261
262 void RotateFromOrigin(float roll, float pitch, float yaw) {
263 float temp = y;
264 y = std::cos(roll) * y - std::sin(roll) * z;
265 z = std::sin(roll) * temp + std::cos(roll) * z;
266
267 temp = x;
268 x = std::cos(pitch) * x + std::sin(pitch) * z;
269 z = -std::sin(pitch) * temp + std::cos(pitch) * z;
270
271 temp = x;
272 x = std::cos(yaw) * x - std::sin(yaw) * y;
273 y = std::sin(yaw) * temp + std::cos(yaw) * y;
274 }
275
262 [[nodiscard]] constexpr T Length2() const { 276 [[nodiscard]] constexpr T Length2() const {
263 return x * x + y * y + z * z; 277 return x * x + y * y + z * z;
264 } 278 }
diff --git a/src/core/core.cpp b/src/core/core.cpp
index caa6a77be..06fba4ce5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -137,7 +137,7 @@ struct System::Impl {
137 device_memory = std::make_unique<Core::DeviceMemory>(); 137 device_memory = std::make_unique<Core::DeviceMemory>();
138 138
139 is_multicore = Settings::values.use_multi_core.GetValue(); 139 is_multicore = Settings::values.use_multi_core.GetValue();
140 extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); 140 extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
141 141
142 core_timing.SetMulticore(is_multicore); 142 core_timing.SetMulticore(is_multicore);
143 core_timing.Initialize([&system]() { system.RegisterHostThread(); }); 143 core_timing.Initialize([&system]() { system.RegisterHostThread(); });
@@ -169,7 +169,7 @@ struct System::Impl {
169 void ReinitializeIfNecessary(System& system) { 169 void ReinitializeIfNecessary(System& system) {
170 const bool must_reinitialize = 170 const bool must_reinitialize =
171 is_multicore != Settings::values.use_multi_core.GetValue() || 171 is_multicore != Settings::values.use_multi_core.GetValue() ||
172 extended_memory_layout != Settings::values.use_extended_memory_layout.GetValue(); 172 extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
173 173
174 if (!must_reinitialize) { 174 if (!must_reinitialize) {
175 return; 175 return;
@@ -178,7 +178,7 @@ struct System::Impl {
178 LOG_DEBUG(Kernel, "Re-initializing"); 178 LOG_DEBUG(Kernel, "Re-initializing");
179 179
180 is_multicore = Settings::values.use_multi_core.GetValue(); 180 is_multicore = Settings::values.use_multi_core.GetValue();
181 extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); 181 extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
182 182
183 Initialize(system); 183 Initialize(system);
184 } 184 }
@@ -293,6 +293,7 @@ struct System::Impl {
293 ASSERT(Kernel::KProcess::Initialize(main_process, system, "main", 293 ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
294 Kernel::KProcess::ProcessType::Userland, resource_limit) 294 Kernel::KProcess::ProcessType::Userland, resource_limit)
295 .IsSuccess()); 295 .IsSuccess());
296 Kernel::KProcess::Register(system.Kernel(), main_process);
296 kernel.MakeApplicationProcess(main_process); 297 kernel.MakeApplicationProcess(main_process);
297 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); 298 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
298 if (load_result != Loader::ResultStatus::Success) { 299 if (load_result != Loader::ResultStatus::Success) {
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index a70f8807c..ecab85893 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -376,6 +376,7 @@ void EmulatedController::ReloadInput() {
376 motion.accel = emulated_motion.GetAcceleration(); 376 motion.accel = emulated_motion.GetAcceleration();
377 motion.gyro = emulated_motion.GetGyroscope(); 377 motion.gyro = emulated_motion.GetGyroscope();
378 motion.rotation = emulated_motion.GetRotations(); 378 motion.rotation = emulated_motion.GetRotations();
379 motion.euler = emulated_motion.GetEulerAngles();
379 motion.orientation = emulated_motion.GetOrientation(); 380 motion.orientation = emulated_motion.GetOrientation();
380 motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity); 381 motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
381 } 382 }
@@ -551,6 +552,8 @@ void EmulatedController::EnableSystemButtons() {
551void EmulatedController::DisableSystemButtons() { 552void EmulatedController::DisableSystemButtons() {
552 std::scoped_lock lock{mutex}; 553 std::scoped_lock lock{mutex};
553 system_buttons_enabled = false; 554 system_buttons_enabled = false;
555 controller.home_button_state.raw = 0;
556 controller.capture_button_state.raw = 0;
554} 557}
555 558
556void EmulatedController::ResetSystemButtons() { 559void EmulatedController::ResetSystemButtons() {
@@ -734,6 +737,8 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
734 if (is_configuring) { 737 if (is_configuring) {
735 controller.npad_button_state.raw = NpadButton::None; 738 controller.npad_button_state.raw = NpadButton::None;
736 controller.debug_pad_button_state.raw = 0; 739 controller.debug_pad_button_state.raw = 0;
740 controller.home_button_state.raw = 0;
741 controller.capture_button_state.raw = 0;
737 lock.unlock(); 742 lock.unlock();
738 TriggerOnChange(ControllerTriggerType::Button, false); 743 TriggerOnChange(ControllerTriggerType::Button, false);
739 return; 744 return;
@@ -976,14 +981,11 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
976 emulated.UpdateOrientation(raw_status.delta_timestamp); 981 emulated.UpdateOrientation(raw_status.delta_timestamp);
977 force_update_motion = raw_status.force_update; 982 force_update_motion = raw_status.force_update;
978 983
979 if (is_configuring) {
980 return;
981 }
982
983 auto& motion = controller.motion_state[index]; 984 auto& motion = controller.motion_state[index];
984 motion.accel = emulated.GetAcceleration(); 985 motion.accel = emulated.GetAcceleration();
985 motion.gyro = emulated.GetGyroscope(); 986 motion.gyro = emulated.GetGyroscope();
986 motion.rotation = emulated.GetRotations(); 987 motion.rotation = emulated.GetRotations();
988 motion.euler = emulated.GetEulerAngles();
987 motion.orientation = emulated.GetOrientation(); 989 motion.orientation = emulated.GetOrientation();
988 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); 990 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
989} 991}
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 429655355..6e01f4e12 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -106,6 +106,7 @@ struct ControllerMotion {
106 Common::Vec3f accel{}; 106 Common::Vec3f accel{};
107 Common::Vec3f gyro{}; 107 Common::Vec3f gyro{};
108 Common::Vec3f rotation{}; 108 Common::Vec3f rotation{};
109 Common::Vec3f euler{};
109 std::array<Common::Vec3f, 3> orientation{}; 110 std::array<Common::Vec3f, 3> orientation{};
110 bool is_at_rest{}; 111 bool is_at_rest{};
111}; 112};
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 7cee39a53..a38e3bb3f 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -54,6 +54,7 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
54 case Common::Input::InputType::Analog: 54 case Common::Input::InputType::Analog:
55 status.value = TransformToTrigger(callback).pressed.value; 55 status.value = TransformToTrigger(callback).pressed.value;
56 status.toggle = callback.analog_status.properties.toggle; 56 status.toggle = callback.analog_status.properties.toggle;
57 status.inverted = callback.analog_status.properties.inverted_button;
57 break; 58 break;
58 case Common::Input::InputType::Trigger: 59 case Common::Input::InputType::Trigger:
59 status.value = TransformToTrigger(callback).pressed.value; 60 status.value = TransformToTrigger(callback).pressed.value;
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp
index 0dd66c1cc..b60478dbb 100644
--- a/src/core/hid/motion_input.cpp
+++ b/src/core/hid/motion_input.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <cmath>
5
4#include "common/math_util.h" 6#include "common/math_util.h"
5#include "core/hid/motion_input.h" 7#include "core/hid/motion_input.h"
6 8
@@ -51,6 +53,20 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
51 quat = quaternion; 53 quat = quaternion;
52} 54}
53 55
56void MotionInput::SetEulerAngles(const Common::Vec3f& euler_angles) {
57 const float cr = std::cos(euler_angles.x * 0.5f);
58 const float sr = std::sin(euler_angles.x * 0.5f);
59 const float cp = std::cos(euler_angles.y * 0.5f);
60 const float sp = std::sin(euler_angles.y * 0.5f);
61 const float cy = std::cos(euler_angles.z * 0.5f);
62 const float sy = std::sin(euler_angles.z * 0.5f);
63
64 quat.w = cr * cp * cy + sr * sp * sy;
65 quat.xyz.x = sr * cp * cy - cr * sp * sy;
66 quat.xyz.y = cr * sp * cy + sr * cp * sy;
67 quat.xyz.z = cr * cp * sy - sr * sp * cy;
68}
69
54void MotionInput::SetGyroBias(const Common::Vec3f& bias) { 70void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
55 gyro_bias = bias; 71 gyro_bias = bias;
56} 72}
@@ -222,6 +238,26 @@ Common::Vec3f MotionInput::GetRotations() const {
222 return rotations; 238 return rotations;
223} 239}
224 240
241Common::Vec3f MotionInput::GetEulerAngles() const {
242 // roll (x-axis rotation)
243 const float sinr_cosp = 2 * (quat.w * quat.xyz.x + quat.xyz.y * quat.xyz.z);
244 const float cosr_cosp = 1 - 2 * (quat.xyz.x * quat.xyz.x + quat.xyz.y * quat.xyz.y);
245
246 // pitch (y-axis rotation)
247 const float sinp = std::sqrt(1 + 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
248 const float cosp = std::sqrt(1 - 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
249
250 // yaw (z-axis rotation)
251 const float siny_cosp = 2 * (quat.w * quat.xyz.z + quat.xyz.x * quat.xyz.y);
252 const float cosy_cosp = 1 - 2 * (quat.xyz.y * quat.xyz.y + quat.xyz.z * quat.xyz.z);
253
254 return {
255 std::atan2(sinr_cosp, cosr_cosp),
256 2 * std::atan2(sinp, cosp) - Common::PI / 2,
257 std::atan2(siny_cosp, cosy_cosp),
258 };
259}
260
225void MotionInput::ResetOrientation() { 261void MotionInput::ResetOrientation() {
226 if (!reset_enabled || only_accelerometer) { 262 if (!reset_enabled || only_accelerometer) {
227 return; 263 return;
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h
index 9f3fc1cf7..482719359 100644
--- a/src/core/hid/motion_input.h
+++ b/src/core/hid/motion_input.h
@@ -35,6 +35,7 @@ public:
35 void SetAcceleration(const Common::Vec3f& acceleration); 35 void SetAcceleration(const Common::Vec3f& acceleration);
36 void SetGyroscope(const Common::Vec3f& gyroscope); 36 void SetGyroscope(const Common::Vec3f& gyroscope);
37 void SetQuaternion(const Common::Quaternion<f32>& quaternion); 37 void SetQuaternion(const Common::Quaternion<f32>& quaternion);
38 void SetEulerAngles(const Common::Vec3f& euler_angles);
38 void SetGyroBias(const Common::Vec3f& bias); 39 void SetGyroBias(const Common::Vec3f& bias);
39 void SetGyroThreshold(f32 threshold); 40 void SetGyroThreshold(f32 threshold);
40 41
@@ -54,6 +55,7 @@ public:
54 [[nodiscard]] Common::Vec3f GetGyroBias() const; 55 [[nodiscard]] Common::Vec3f GetGyroBias() const;
55 [[nodiscard]] Common::Vec3f GetRotations() const; 56 [[nodiscard]] Common::Vec3f GetRotations() const;
56 [[nodiscard]] Common::Quaternion<f32> GetQuaternion() const; 57 [[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
58 [[nodiscard]] Common::Vec3f GetEulerAngles() const;
57 59
58 [[nodiscard]] bool IsMoving(f32 sensitivity) const; 60 [[nodiscard]] bool IsMoving(f32 sensitivity) const;
59 [[nodiscard]] bool IsCalibrated(f32 sensitivity) const; 61 [[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
index 36d0d20d2..49bdc671e 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -35,12 +35,13 @@ namespace {
35using namespace Common::Literals; 35using namespace Common::Literals;
36 36
37u32 GetMemorySizeForInit() { 37u32 GetMemorySizeForInit() {
38 return Settings::values.use_extended_memory_layout ? Smc::MemorySize_8GB : Smc::MemorySize_4GB; 38 return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemorySize_8GB
39 : Smc::MemorySize_4GB;
39} 40}
40 41
41Smc::MemoryArrangement GetMemoryArrangeForInit() { 42Smc::MemoryArrangement GetMemoryArrangeForInit() {
42 return Settings::values.use_extended_memory_layout ? Smc::MemoryArrangement_8GB 43 return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemoryArrangement_8GB
43 : Smc::MemoryArrangement_4GB; 44 : Smc::MemoryArrangement_4GB;
44} 45}
45} // namespace 46} // namespace
46 47
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 9b71fe371..f384b1568 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -182,8 +182,8 @@ public:
182 explicit KAutoObjectWithList(KernelCore& kernel) : KAutoObject(kernel) {} 182 explicit KAutoObjectWithList(KernelCore& kernel) : KAutoObject(kernel) {}
183 183
184 static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) { 184 static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) {
185 const u64 lid = lhs.GetId(); 185 const uintptr_t lid = reinterpret_cast<uintptr_t>(std::addressof(lhs));
186 const u64 rid = rhs.GetId(); 186 const uintptr_t rid = reinterpret_cast<uintptr_t>(std::addressof(rhs));
187 187
188 if (lid < rid) { 188 if (lid < rid) {
189 return -1; 189 return -1;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4f3366c9d..f33600ca5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -95,7 +95,7 @@ struct KernelCore::Impl {
95 pt_heap_region.GetSize()); 95 pt_heap_region.GetSize());
96 } 96 }
97 97
98 InitializeHackSharedMemory(); 98 InitializeHackSharedMemory(kernel);
99 RegisterHostThread(nullptr); 99 RegisterHostThread(nullptr);
100 } 100 }
101 101
@@ -216,10 +216,12 @@ struct KernelCore::Impl {
216 auto* main_thread{Kernel::KThread::Create(system.Kernel())}; 216 auto* main_thread{Kernel::KThread::Create(system.Kernel())};
217 main_thread->SetCurrentCore(core); 217 main_thread->SetCurrentCore(core);
218 ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, core).IsSuccess()); 218 ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, core).IsSuccess());
219 KThread::Register(system.Kernel(), main_thread);
219 220
220 auto* idle_thread{Kernel::KThread::Create(system.Kernel())}; 221 auto* idle_thread{Kernel::KThread::Create(system.Kernel())};
221 idle_thread->SetCurrentCore(core); 222 idle_thread->SetCurrentCore(core);
222 ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, core).IsSuccess()); 223 ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, core).IsSuccess());
224 KThread::Register(system.Kernel(), idle_thread);
223 225
224 schedulers[i]->Initialize(main_thread, idle_thread, core); 226 schedulers[i]->Initialize(main_thread, idle_thread, core);
225 } 227 }
@@ -230,6 +232,7 @@ struct KernelCore::Impl {
230 const Core::Timing::CoreTiming& core_timing) { 232 const Core::Timing::CoreTiming& core_timing) {
231 system_resource_limit = KResourceLimit::Create(system.Kernel()); 233 system_resource_limit = KResourceLimit::Create(system.Kernel());
232 system_resource_limit->Initialize(&core_timing); 234 system_resource_limit->Initialize(&core_timing);
235 KResourceLimit::Register(kernel, system_resource_limit);
233 236
234 const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()}; 237 const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()};
235 const auto total_size{sizes.first}; 238 const auto total_size{sizes.first};
@@ -355,6 +358,7 @@ struct KernelCore::Impl {
355 ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {}, 358 ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {},
356 core_id) 359 core_id)
357 .IsSuccess()); 360 .IsSuccess());
361 KThread::Register(system.Kernel(), shutdown_threads[core_id]);
358 } 362 }
359 } 363 }
360 364
@@ -729,7 +733,7 @@ struct KernelCore::Impl {
729 memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize()); 733 memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize());
730 } 734 }
731 735
732 void InitializeHackSharedMemory() { 736 void InitializeHackSharedMemory(KernelCore& kernel) {
733 // Setup memory regions for emulated processes 737 // Setup memory regions for emulated processes
734 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel 738 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel
735 constexpr std::size_t hid_size{0x40000}; 739 constexpr std::size_t hid_size{0x40000};
@@ -746,14 +750,23 @@ struct KernelCore::Impl {
746 750
747 hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 751 hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
748 Svc::MemoryPermission::Read, hid_size); 752 Svc::MemoryPermission::Read, hid_size);
753 KSharedMemory::Register(kernel, hid_shared_mem);
754
749 font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 755 font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
750 Svc::MemoryPermission::Read, font_size); 756 Svc::MemoryPermission::Read, font_size);
757 KSharedMemory::Register(kernel, font_shared_mem);
758
751 irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 759 irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
752 Svc::MemoryPermission::Read, irs_size); 760 Svc::MemoryPermission::Read, irs_size);
761 KSharedMemory::Register(kernel, irs_shared_mem);
762
753 time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 763 time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
754 Svc::MemoryPermission::Read, time_size); 764 Svc::MemoryPermission::Read, time_size);
765 KSharedMemory::Register(kernel, time_shared_mem);
766
755 hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 767 hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
756 Svc::MemoryPermission::Read, hidbus_size); 768 Svc::MemoryPermission::Read, hidbus_size);
769 KSharedMemory::Register(kernel, hidbus_shared_mem);
757 } 770 }
758 771
759 std::mutex registered_objects_lock; 772 std::mutex registered_objects_lock;
@@ -1072,12 +1085,15 @@ static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process,
1072 // Commit the thread reservation. 1085 // Commit the thread reservation.
1073 thread_reservation.Commit(); 1086 thread_reservation.Commit();
1074 1087
1088 // Register the thread.
1089 KThread::Register(kernel, thread);
1090
1075 return std::jthread( 1091 return std::jthread(
1076 [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] { 1092 [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] {
1077 // Set the thread name. 1093 // Set the thread name.
1078 Common::SetCurrentThreadName(thread_name.c_str()); 1094 Common::SetCurrentThreadName(thread_name.c_str());
1079 1095
1080 // Register the thread. 1096 // Set the thread as current.
1081 kernel.RegisterHostThread(thread); 1097 kernel.RegisterHostThread(thread);
1082 1098
1083 // Run the callback. 1099 // Run the callback.
@@ -1099,6 +1115,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
1099 // Ensure that we don't hold onto any extra references. 1115 // Ensure that we don't hold onto any extra references.
1100 SCOPE_EXIT({ process->Close(); }); 1116 SCOPE_EXIT({ process->Close(); });
1101 1117
1118 // Register the new process.
1119 KProcess::Register(*this, process);
1120
1102 // Run the host thread. 1121 // Run the host thread.
1103 return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func)); 1122 return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func));
1104} 1123}
@@ -1124,6 +1143,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
1124 // Ensure that we don't hold onto any extra references. 1143 // Ensure that we don't hold onto any extra references.
1125 SCOPE_EXIT({ process->Close(); }); 1144 SCOPE_EXIT({ process->Close(); });
1126 1145
1146 // Register the new process.
1147 KProcess::Register(*this, process);
1148
1127 // Reserve a new thread from the process resource limit. 1149 // Reserve a new thread from the process resource limit.
1128 KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax); 1150 KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax);
1129 ASSERT(thread_reservation.Succeeded()); 1151 ASSERT(thread_reservation.Succeeded());
@@ -1136,6 +1158,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
1136 // Commit the thread reservation. 1158 // Commit the thread reservation.
1137 thread_reservation.Commit(); 1159 thread_reservation.Commit();
1138 1160
1161 // Register the new thread.
1162 KThread::Register(*this, thread);
1163
1139 // Begin running the thread. 1164 // Begin running the thread.
1140 ASSERT(R_SUCCEEDED(thread->Run())); 1165 ASSERT(R_SUCCEEDED(thread->Run()));
1141} 1166}
diff --git a/src/core/hle/service/ipc_helpers.h b/src/core/hle/service/ipc_helpers.h
index e4cb4e1f2..0e222362e 100644
--- a/src/core/hle/service/ipc_helpers.h
+++ b/src/core/hle/service/ipc_helpers.h
@@ -156,6 +156,7 @@ public:
156 156
157 auto* session = Kernel::KSession::Create(kernel); 157 auto* session = Kernel::KSession::Create(kernel);
158 session->Initialize(nullptr, 0); 158 session->Initialize(nullptr, 0);
159 Kernel::KSession::Register(kernel, session);
159 160
160 auto next_manager = std::make_shared<Service::SessionRequestManager>( 161 auto next_manager = std::make_shared<Service::SessionRequestManager>(
161 kernel, manager->GetServerManager()); 162 kernel, manager->GetServerManager());
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
index a39ce5212..6a313a03b 100644
--- a/src/core/hle/service/kernel_helpers.cpp
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -25,6 +25,9 @@ ServiceContext::ServiceContext(Core::System& system_, std::string name_)
25 Kernel::KProcess::ProcessType::KernelInternal, 25 Kernel::KProcess::ProcessType::KernelInternal,
26 kernel.GetSystemResourceLimit()) 26 kernel.GetSystemResourceLimit())
27 .IsSuccess()); 27 .IsSuccess());
28
29 // Register the process.
30 Kernel::KProcess::Register(kernel, process);
28 process_created = true; 31 process_created = true;
29} 32}
30 33
diff --git a/src/core/hle/service/mutex.cpp b/src/core/hle/service/mutex.cpp
index 07589a0f0..b0ff71d1b 100644
--- a/src/core/hle/service/mutex.cpp
+++ b/src/core/hle/service/mutex.cpp
@@ -12,6 +12,9 @@ Mutex::Mutex(Core::System& system) : m_system(system) {
12 m_event = Kernel::KEvent::Create(system.Kernel()); 12 m_event = Kernel::KEvent::Create(system.Kernel());
13 m_event->Initialize(nullptr); 13 m_event->Initialize(nullptr);
14 14
15 // Register the event.
16 Kernel::KEvent::Register(system.Kernel(), m_event);
17
15 ASSERT(R_SUCCEEDED(m_event->Signal())); 18 ASSERT(R_SUCCEEDED(m_event->Signal()));
16} 19}
17 20
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index 6b4a1291e..156bc27d8 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -33,6 +33,9 @@ ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_m
33 // Initialize event. 33 // Initialize event.
34 m_event = Kernel::KEvent::Create(system.Kernel()); 34 m_event = Kernel::KEvent::Create(system.Kernel());
35 m_event->Initialize(nullptr); 35 m_event->Initialize(nullptr);
36
37 // Register event.
38 Kernel::KEvent::Register(system.Kernel(), m_event);
36} 39}
37 40
38ServerManager::~ServerManager() { 41ServerManager::~ServerManager() {
@@ -160,6 +163,9 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
160 // Initialize the event. 163 // Initialize the event.
161 m_deferral_event->Initialize(nullptr); 164 m_deferral_event->Initialize(nullptr);
162 165
166 // Register the event.
167 Kernel::KEvent::Register(m_system.Kernel(), m_deferral_event);
168
163 // Set the output. 169 // Set the output.
164 *out_event = m_deferral_event; 170 *out_event = m_deferral_event;
165 171
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index c45be5726..1608fa24c 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -64,6 +64,9 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
64 auto* port = Kernel::KPort::Create(kernel); 64 auto* port = Kernel::KPort::Create(kernel);
65 port->Initialize(ServerSessionCountMax, false, 0); 65 port->Initialize(ServerSessionCountMax, false, 0);
66 66
67 // Register the port.
68 Kernel::KPort::Register(kernel, port);
69
67 service_ports.emplace(name, port); 70 service_ports.emplace(name, port);
68 registered_services.emplace(name, handler); 71 registered_services.emplace(name, handler);
69 if (deferral_event) { 72 if (deferral_event) {
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp
index 419c1df2b..7dce28fe0 100644
--- a/src/core/hle/service/sm/sm_controller.cpp
+++ b/src/core/hle/service/sm/sm_controller.cpp
@@ -49,6 +49,9 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
49 // Commit the session reservation. 49 // Commit the session reservation.
50 session_reservation.Commit(); 50 session_reservation.Commit();
51 51
52 // Register the session.
53 Kernel::KSession::Register(system.Kernel(), session);
54
52 // Register with server manager. 55 // Register with server manager.
53 session_manager->GetServerManager().RegisterSession(&session->GetServerSession(), 56 session_manager->GetServerManager().RegisterSession(&session->GetServerSession(),
54 session_manager); 57 session_manager);
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 432310632..a9667463f 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -462,7 +462,7 @@ struct Memory::Impl {
462 } 462 }
463 463
464 if (Settings::IsFastmemEnabled()) { 464 if (Settings::IsFastmemEnabled()) {
465 const bool is_read_enable = Settings::IsGPULevelHigh() || !cached; 465 const bool is_read_enable = !Settings::IsGPULevelExtreme() || !cached;
466 system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached); 466 system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
467 } 467 }
468 468
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp
index 91aa96aa7..49f5e7f54 100644
--- a/src/input_common/input_engine.cpp
+++ b/src/input_common/input_engine.cpp
@@ -58,6 +58,8 @@ void InputEngine::SetHatButton(const PadIdentifier& identifier, int button, u8 v
58} 58}
59 59
60void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value) { 60void InputEngine::SetAxis(const PadIdentifier& identifier, int axis, f32 value) {
61 value /= 2.0f;
62 value -= 0.5f;
61 { 63 {
62 std::scoped_lock lock{mutex}; 64 std::scoped_lock lock{mutex};
63 ControllerData& controller = controller_list.at(identifier); 65 ControllerData& controller = controller_list.at(identifier);
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 8c6a6521a..5c2c4a463 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -939,6 +939,7 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateAnalogDevice(
939 .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), 939 .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f),
940 .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), 940 .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f),
941 .inverted = params.Get("invert", "+") == "-", 941 .inverted = params.Get("invert", "+") == "-",
942 .inverted_button = params.Get("inverted", false) != 0,
942 .toggle = params.Get("toggle", false) != 0, 943 .toggle = params.Get("toggle", false) != 0,
943 }; 944 };
944 input_engine->PreSetController(identifier); 945 input_engine->PreSetController(identifier);
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 7975564b5..e534e1e9c 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1426,7 +1426,7 @@ bool BufferCache<P>::SynchronizeBufferNoModified(Buffer& buffer, VAddr cpu_addr,
1426 .size = sub_size, 1426 .size = sub_size,
1427 }); 1427 });
1428 total_size_bytes += sub_size; 1428 total_size_bytes += sub_size;
1429 largest_copy = std::max(largest_copy, sub_size); 1429 largest_copy = std::max<u64>(largest_copy, sub_size);
1430 } 1430 }
1431 const std::span<BufferCopy> copies_span(copies.data(), copies.size()); 1431 const std::span<BufferCopy> copies_span(copies.data(), copies.size());
1432 UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); 1432 UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
diff --git a/src/video_core/buffer_cache/memory_tracker_base.h b/src/video_core/buffer_cache/memory_tracker_base.h
index 4bc59017f..dc4ebfcaa 100644
--- a/src/video_core/buffer_cache/memory_tracker_base.h
+++ b/src/video_core/buffer_cache/memory_tracker_base.h
@@ -170,7 +170,8 @@ private:
170 std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS}; 170 std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS};
171 u64 page_offset{cpu_address & HIGHER_PAGE_MASK}; 171 u64 page_offset{cpu_address & HIGHER_PAGE_MASK};
172 while (remaining_size > 0) { 172 while (remaining_size > 0) {
173 const std::size_t copy_amount{std::min(HIGHER_PAGE_SIZE - page_offset, remaining_size)}; 173 const std::size_t copy_amount{
174 std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
174 auto* manager{top_tier[page_index]}; 175 auto* manager{top_tier[page_index]};
175 if (manager) { 176 if (manager) {
176 if constexpr (BOOL_BREAK) { 177 if constexpr (BOOL_BREAK) {
@@ -206,7 +207,8 @@ private:
206 u64 begin = std::numeric_limits<u64>::max(); 207 u64 begin = std::numeric_limits<u64>::max();
207 u64 end = 0; 208 u64 end = 0;
208 while (remaining_size > 0) { 209 while (remaining_size > 0) {
209 const std::size_t copy_amount{std::min(HIGHER_PAGE_SIZE - page_offset, remaining_size)}; 210 const std::size_t copy_amount{
211 std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
210 auto* manager{top_tier[page_index]}; 212 auto* manager{top_tier[page_index]};
211 const auto execute = [&] { 213 const auto execute = [&] {
212 auto [new_begin, new_end] = func(manager, page_offset, copy_amount); 214 auto [new_begin, new_end] = func(manager, page_offset, copy_amount);
diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp
index 4e75f33ca..ab4f4d407 100644
--- a/src/video_core/compatible_formats.cpp
+++ b/src/video_core/compatible_formats.cpp
@@ -126,15 +126,14 @@ constexpr std::array VIEW_CLASS_ASTC_8x8_RGBA{
126 PixelFormat::ASTC_2D_8X8_SRGB, 126 PixelFormat::ASTC_2D_8X8_SRGB,
127}; 127};
128 128
129// Missing formats: 129constexpr std::array VIEW_CLASS_ASTC_10x5_RGBA{
130// PixelFormat::ASTC_2D_10X5_UNORM 130 PixelFormat::ASTC_2D_10X5_UNORM,
131// PixelFormat::ASTC_2D_10X5_SRGB 131 PixelFormat::ASTC_2D_10X5_SRGB,
132 132};
133// Missing formats:
134// PixelFormat::ASTC_2D_10X6_SRGB
135 133
136constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{ 134constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{
137 PixelFormat::ASTC_2D_10X6_UNORM, 135 PixelFormat::ASTC_2D_10X6_UNORM,
136 PixelFormat::ASTC_2D_10X6_SRGB,
138}; 137};
139 138
140constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{ 139constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{
@@ -147,9 +146,10 @@ constexpr std::array VIEW_CLASS_ASTC_10x10_RGBA{
147 PixelFormat::ASTC_2D_10X10_SRGB, 146 PixelFormat::ASTC_2D_10X10_SRGB,
148}; 147};
149 148
150// Missing formats 149constexpr std::array VIEW_CLASS_ASTC_12x10_RGBA{
151// ASTC_2D_12X10_UNORM, 150 PixelFormat::ASTC_2D_12X10_UNORM,
152// ASTC_2D_12X10_SRGB, 151 PixelFormat::ASTC_2D_12X10_SRGB,
152};
153 153
154constexpr std::array VIEW_CLASS_ASTC_12x12_RGBA{ 154constexpr std::array VIEW_CLASS_ASTC_12x12_RGBA{
155 PixelFormat::ASTC_2D_12X12_UNORM, 155 PixelFormat::ASTC_2D_12X12_UNORM,
@@ -229,9 +229,11 @@ constexpr Table MakeViewTable() {
229 EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA); 229 EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA);
230 EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA); 230 EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA);
231 EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA); 231 EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA);
232 EnableRange(view, VIEW_CLASS_ASTC_10x5_RGBA);
232 EnableRange(view, VIEW_CLASS_ASTC_10x6_RGBA); 233 EnableRange(view, VIEW_CLASS_ASTC_10x6_RGBA);
233 EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA); 234 EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA);
234 EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA); 235 EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA);
236 EnableRange(view, VIEW_CLASS_ASTC_12x10_RGBA);
235 EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA); 237 EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA);
236 return view; 238 return view;
237} 239}
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index c390ac91b..3b2f6aab6 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -4,13 +4,20 @@
4#pragma once 4#pragma once
5 5
6#include <algorithm> 6#include <algorithm>
7#include <condition_variable>
7#include <cstring> 8#include <cstring>
8#include <deque> 9#include <deque>
9#include <functional> 10#include <functional>
10#include <memory> 11#include <memory>
12#include <mutex>
13#include <thread>
11#include <queue> 14#include <queue>
12 15
13#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/microprofile.h"
18#include "common/scope_exit.h"
19#include "common/settings.h"
20#include "common/thread.h"
14#include "video_core/delayed_destruction_ring.h" 21#include "video_core/delayed_destruction_ring.h"
15#include "video_core/gpu.h" 22#include "video_core/gpu.h"
16#include "video_core/host1x/host1x.h" 23#include "video_core/host1x/host1x.h"
@@ -23,15 +30,26 @@ class FenceBase {
23public: 30public:
24 explicit FenceBase(bool is_stubbed_) : is_stubbed{is_stubbed_} {} 31 explicit FenceBase(bool is_stubbed_) : is_stubbed{is_stubbed_} {}
25 32
33 bool IsStubbed() const {
34 return is_stubbed;
35 }
36
26protected: 37protected:
27 bool is_stubbed; 38 bool is_stubbed;
28}; 39};
29 40
30template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache> 41template <typename Traits>
31class FenceManager { 42class FenceManager {
43 using TFence = typename Traits::FenceType;
44 using TTextureCache = typename Traits::TextureCacheType;
45 using TBufferCache = typename Traits::BufferCacheType;
46 using TQueryCache = typename Traits::QueryCacheType;
47 static constexpr bool can_async_check = Traits::HAS_ASYNC_CHECK;
48
32public: 49public:
33 /// Notify the fence manager about a new frame 50 /// Notify the fence manager about a new frame
34 void TickFrame() { 51 void TickFrame() {
52 std::unique_lock lock(ring_guard);
35 delayed_destruction_ring.Tick(); 53 delayed_destruction_ring.Tick();
36 } 54 }
37 55
@@ -46,17 +64,33 @@ public:
46 } 64 }
47 65
48 void SignalFence(std::function<void()>&& func) { 66 void SignalFence(std::function<void()>&& func) {
49 TryReleasePendingFences(); 67 rasterizer.InvalidateGPUCache();
68 bool delay_fence = Settings::IsGPULevelHigh();
69 if constexpr (!can_async_check) {
70 TryReleasePendingFences<false>();
71 }
50 const bool should_flush = ShouldFlush(); 72 const bool should_flush = ShouldFlush();
51 CommitAsyncFlushes(); 73 CommitAsyncFlushes();
52 uncommitted_operations.emplace_back(std::move(func));
53 CommitOperations();
54 TFence new_fence = CreateFence(!should_flush); 74 TFence new_fence = CreateFence(!should_flush);
55 fences.push(new_fence); 75 if constexpr (can_async_check) {
76 guard.lock();
77 }
78 if (delay_fence) {
79 uncommitted_operations.emplace_back(std::move(func));
80 }
81 pending_operations.emplace_back(std::move(uncommitted_operations));
56 QueueFence(new_fence); 82 QueueFence(new_fence);
83 if (!delay_fence) {
84 func();
85 }
86 fences.push(std::move(new_fence));
57 if (should_flush) { 87 if (should_flush) {
58 rasterizer.FlushCommands(); 88 rasterizer.FlushCommands();
59 } 89 }
90 if constexpr (can_async_check) {
91 guard.unlock();
92 cv.notify_all();
93 }
60 } 94 }
61 95
62 void SignalSyncPoint(u32 value) { 96 void SignalSyncPoint(u32 value) {
@@ -66,29 +100,30 @@ public:
66 } 100 }
67 101
68 void WaitPendingFences() { 102 void WaitPendingFences() {
69 while (!fences.empty()) { 103 if constexpr (!can_async_check) {
70 TFence& current_fence = fences.front(); 104 TryReleasePendingFences<true>();
71 if (ShouldWait()) {
72 WaitFence(current_fence);
73 }
74 PopAsyncFlushes();
75 auto operations = std::move(pending_operations.front());
76 pending_operations.pop_front();
77 for (auto& operation : operations) {
78 operation();
79 }
80 PopFence();
81 } 105 }
82 } 106 }
83 107
84protected: 108protected:
85 explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, 109 explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
86 TTextureCache& texture_cache_, TTBufferCache& buffer_cache_, 110 TTextureCache& texture_cache_, TBufferCache& buffer_cache_,
87 TQueryCache& query_cache_) 111 TQueryCache& query_cache_)
88 : rasterizer{rasterizer_}, gpu{gpu_}, syncpoint_manager{gpu.Host1x().GetSyncpointManager()}, 112 : rasterizer{rasterizer_}, gpu{gpu_}, syncpoint_manager{gpu.Host1x().GetSyncpointManager()},
89 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {} 113 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {
114 if constexpr (can_async_check) {
115 fence_thread =
116 std::jthread([this](std::stop_token token) { ReleaseThreadFunc(token); });
117 }
118 }
90 119
91 virtual ~FenceManager() = default; 120 virtual ~FenceManager() {
121 if constexpr (can_async_check) {
122 fence_thread.request_stop();
123 cv.notify_all();
124 fence_thread.join();
125 }
126 }
92 127
93 /// Creates a Fence Interface, does not create a backend fence if 'is_stubbed' is 128 /// Creates a Fence Interface, does not create a backend fence if 'is_stubbed' is
94 /// true 129 /// true
@@ -104,15 +139,20 @@ protected:
104 Tegra::GPU& gpu; 139 Tegra::GPU& gpu;
105 Tegra::Host1x::SyncpointManager& syncpoint_manager; 140 Tegra::Host1x::SyncpointManager& syncpoint_manager;
106 TTextureCache& texture_cache; 141 TTextureCache& texture_cache;
107 TTBufferCache& buffer_cache; 142 TBufferCache& buffer_cache;
108 TQueryCache& query_cache; 143 TQueryCache& query_cache;
109 144
110private: 145private:
146 template <bool force_wait>
111 void TryReleasePendingFences() { 147 void TryReleasePendingFences() {
112 while (!fences.empty()) { 148 while (!fences.empty()) {
113 TFence& current_fence = fences.front(); 149 TFence& current_fence = fences.front();
114 if (ShouldWait() && !IsFenceSignaled(current_fence)) { 150 if (ShouldWait() && !IsFenceSignaled(current_fence)) {
115 return; 151 if constexpr (force_wait) {
152 WaitFence(current_fence);
153 } else {
154 return;
155 }
116 } 156 }
117 PopAsyncFlushes(); 157 PopAsyncFlushes();
118 auto operations = std::move(pending_operations.front()); 158 auto operations = std::move(pending_operations.front());
@@ -120,7 +160,49 @@ private:
120 for (auto& operation : operations) { 160 for (auto& operation : operations) {
121 operation(); 161 operation();
122 } 162 }
123 PopFence(); 163 {
164 std::unique_lock lock(ring_guard);
165 delayed_destruction_ring.Push(std::move(current_fence));
166 }
167 fences.pop();
168 }
169 }
170
171 void ReleaseThreadFunc(std::stop_token stop_token) {
172 std::string name = "GPUFencingThread";
173 MicroProfileOnThreadCreate(name.c_str());
174
175 // Cleanup
176 SCOPE_EXIT({ MicroProfileOnThreadExit(); });
177
178 Common::SetCurrentThreadName(name.c_str());
179 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
180
181 TFence current_fence;
182 std::deque<std::function<void()>> current_operations;
183 while (!stop_token.stop_requested()) {
184 {
185 std::unique_lock lock(guard);
186 cv.wait(lock, [&] { return stop_token.stop_requested() || !fences.empty(); });
187 if (stop_token.stop_requested()) [[unlikely]] {
188 return;
189 }
190 current_fence = std::move(fences.front());
191 current_operations = std::move(pending_operations.front());
192 fences.pop();
193 pending_operations.pop_front();
194 }
195 if (!current_fence->IsStubbed()) {
196 WaitFence(current_fence);
197 }
198 PopAsyncFlushes();
199 for (auto& operation : current_operations) {
200 operation();
201 }
202 {
203 std::unique_lock lock(ring_guard);
204 delayed_destruction_ring.Push(std::move(current_fence));
205 }
124 } 206 }
125 } 207 }
126 208
@@ -154,19 +236,16 @@ private:
154 query_cache.CommitAsyncFlushes(); 236 query_cache.CommitAsyncFlushes();
155 } 237 }
156 238
157 void PopFence() {
158 delayed_destruction_ring.Push(std::move(fences.front()));
159 fences.pop();
160 }
161
162 void CommitOperations() {
163 pending_operations.emplace_back(std::move(uncommitted_operations));
164 }
165
166 std::queue<TFence> fences; 239 std::queue<TFence> fences;
167 std::deque<std::function<void()>> uncommitted_operations; 240 std::deque<std::function<void()>> uncommitted_operations;
168 std::deque<std::deque<std::function<void()>>> pending_operations; 241 std::deque<std::deque<std::function<void()>>> pending_operations;
169 242
243 std::mutex guard;
244 std::mutex ring_guard;
245 std::condition_variable cv;
246
247 std::jthread fence_thread;
248
170 DelayedDestructionRing<TFence, 6> delayed_destruction_ring; 249 DelayedDestructionRing<TFence, 6> delayed_destruction_ring;
171}; 250};
172 251
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 01fb5b546..7b2cde7a7 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -82,6 +82,7 @@ void MemoryManager::SetEntry(size_t position, MemoryManager::EntryType entry) {
82} 82}
83 83
84PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const { 84PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const {
85 std::unique_lock<std::mutex> lock(guard);
85 return kind_map.GetValueAt(gpu_addr); 86 return kind_map.GetValueAt(gpu_addr);
86} 87}
87 88
@@ -160,7 +161,10 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr
160 } 161 }
161 remaining_size -= big_page_size; 162 remaining_size -= big_page_size;
162 } 163 }
163 kind_map.Map(gpu_addr, gpu_addr + size, kind); 164 {
165 std::unique_lock<std::mutex> lock(guard);
166 kind_map.Map(gpu_addr, gpu_addr + size, kind);
167 }
164 return gpu_addr; 168 return gpu_addr;
165} 169}
166 170
@@ -553,6 +557,7 @@ size_t MemoryManager::MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const {
553} 557}
554 558
555size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const { 559size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const {
560 std::unique_lock<std::mutex> lock(guard);
556 return kind_map.GetContinuousSizeFrom(gpu_addr); 561 return kind_map.GetContinuousSizeFrom(gpu_addr);
557} 562}
558 563
@@ -745,10 +750,10 @@ void MemoryManager::FlushCaching() {
745 return; 750 return;
746 } 751 }
747 accumulator->Callback([this](GPUVAddr addr, size_t size) { 752 accumulator->Callback([this](GPUVAddr addr, size_t size) {
748 GetSubmappedRangeImpl<false>(addr, size, page_stash); 753 GetSubmappedRangeImpl<false>(addr, size, page_stash2);
749 }); 754 });
750 rasterizer->InnerInvalidation(page_stash); 755 rasterizer->InnerInvalidation(page_stash2);
751 page_stash.clear(); 756 page_stash2.clear();
752 accumulator->Clear(); 757 accumulator->Clear();
753} 758}
754 759
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index fbbe856c4..794535122 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -5,6 +5,7 @@
5 5
6#include <atomic> 6#include <atomic>
7#include <map> 7#include <map>
8#include <mutex>
8#include <optional> 9#include <optional>
9#include <vector> 10#include <vector>
10 11
@@ -215,6 +216,9 @@ private:
215 216
216 std::vector<u64> big_page_continuous; 217 std::vector<u64> big_page_continuous;
217 std::vector<std::pair<VAddr, std::size_t>> page_stash{}; 218 std::vector<std::pair<VAddr, std::size_t>> page_stash{};
219 std::vector<std::pair<VAddr, std::size_t>> page_stash2{};
220
221 mutable std::mutex guard;
218 222
219 static constexpr size_t continuous_bits = 64; 223 static constexpr size_t continuous_bits = 64;
220 224
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index 8906ba6d8..941de95c1 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -6,6 +6,7 @@
6#include <algorithm> 6#include <algorithm>
7#include <array> 7#include <array>
8#include <cstring> 8#include <cstring>
9#include <functional>
9#include <iterator> 10#include <iterator>
10#include <list> 11#include <list>
11#include <memory> 12#include <memory>
@@ -17,13 +18,19 @@
17 18
18#include "common/assert.h" 19#include "common/assert.h"
19#include "common/settings.h" 20#include "common/settings.h"
21#include "core/memory.h"
20#include "video_core/control/channel_state_cache.h" 22#include "video_core/control/channel_state_cache.h"
21#include "video_core/engines/maxwell_3d.h" 23#include "video_core/engines/maxwell_3d.h"
22#include "video_core/memory_manager.h" 24#include "video_core/memory_manager.h"
23#include "video_core/rasterizer_interface.h" 25#include "video_core/rasterizer_interface.h"
26#include "video_core/texture_cache/slot_vector.h"
24 27
25namespace VideoCommon { 28namespace VideoCommon {
26 29
30using AsyncJobId = SlotId;
31
32static constexpr AsyncJobId NULL_ASYNC_JOB_ID{0};
33
27template <class QueryCache, class HostCounter> 34template <class QueryCache, class HostCounter>
28class CounterStreamBase { 35class CounterStreamBase {
29public: 36public:
@@ -93,9 +100,13 @@ private:
93template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter> 100template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter>
94class QueryCacheBase : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { 101class QueryCacheBase : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
95public: 102public:
96 explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_) 103 explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_,
97 : rasterizer{rasterizer_}, streams{{CounterStream{static_cast<QueryCache&>(*this), 104 Core::Memory::Memory& cpu_memory_)
98 VideoCore::QueryType::SamplesPassed}}} {} 105 : rasterizer{rasterizer_},
106 cpu_memory{cpu_memory_}, streams{{CounterStream{static_cast<QueryCache&>(*this),
107 VideoCore::QueryType::SamplesPassed}}} {
108 (void)slot_async_jobs.insert(); // Null value
109 }
99 110
100 void InvalidateRegion(VAddr addr, std::size_t size) { 111 void InvalidateRegion(VAddr addr, std::size_t size) {
101 std::unique_lock lock{mutex}; 112 std::unique_lock lock{mutex};
@@ -126,10 +137,15 @@ public:
126 query = Register(type, *cpu_addr, host_ptr, timestamp.has_value()); 137 query = Register(type, *cpu_addr, host_ptr, timestamp.has_value());
127 } 138 }
128 139
129 query->BindCounter(Stream(type).Current(), timestamp); 140 auto result = query->BindCounter(Stream(type).Current(), timestamp);
130 if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) { 141 if (result) {
131 AsyncFlushQuery(*cpu_addr); 142 auto async_job_id = query->GetAsyncJob();
143 auto& async_job = slot_async_jobs[async_job_id];
144 async_job.collected = true;
145 async_job.value = *result;
146 query->SetAsyncJob(NULL_ASYNC_JOB_ID);
132 } 147 }
148 AsyncFlushQuery(query, timestamp, lock);
133 } 149 }
134 150
135 /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch. 151 /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch.
@@ -173,15 +189,18 @@ public:
173 } 189 }
174 190
175 void CommitAsyncFlushes() { 191 void CommitAsyncFlushes() {
192 std::unique_lock lock{mutex};
176 committed_flushes.push_back(uncommitted_flushes); 193 committed_flushes.push_back(uncommitted_flushes);
177 uncommitted_flushes.reset(); 194 uncommitted_flushes.reset();
178 } 195 }
179 196
180 bool HasUncommittedFlushes() const { 197 bool HasUncommittedFlushes() const {
198 std::unique_lock lock{mutex};
181 return uncommitted_flushes != nullptr; 199 return uncommitted_flushes != nullptr;
182 } 200 }
183 201
184 bool ShouldWaitAsyncFlushes() const { 202 bool ShouldWaitAsyncFlushes() const {
203 std::unique_lock lock{mutex};
185 if (committed_flushes.empty()) { 204 if (committed_flushes.empty()) {
186 return false; 205 return false;
187 } 206 }
@@ -189,6 +208,7 @@ public:
189 } 208 }
190 209
191 void PopAsyncFlushes() { 210 void PopAsyncFlushes() {
211 std::unique_lock lock{mutex};
192 if (committed_flushes.empty()) { 212 if (committed_flushes.empty()) {
193 return; 213 return;
194 } 214 }
@@ -197,15 +217,25 @@ public:
197 committed_flushes.pop_front(); 217 committed_flushes.pop_front();
198 return; 218 return;
199 } 219 }
200 for (VAddr query_address : *flush_list) { 220 for (AsyncJobId async_job_id : *flush_list) {
201 FlushAndRemoveRegion(query_address, 4); 221 AsyncJob& async_job = slot_async_jobs[async_job_id];
222 if (!async_job.collected) {
223 FlushAndRemoveRegion(async_job.query_location, 2, true);
224 }
202 } 225 }
203 committed_flushes.pop_front(); 226 committed_flushes.pop_front();
204 } 227 }
205 228
206private: 229private:
230 struct AsyncJob {
231 bool collected = false;
232 u64 value = 0;
233 VAddr query_location = 0;
234 std::optional<u64> timestamp{};
235 };
236
207 /// Flushes a memory range to guest memory and removes it from the cache. 237 /// Flushes a memory range to guest memory and removes it from the cache.
208 void FlushAndRemoveRegion(VAddr addr, std::size_t size) { 238 void FlushAndRemoveRegion(VAddr addr, std::size_t size, bool async = false) {
209 const u64 addr_begin = addr; 239 const u64 addr_begin = addr;
210 const u64 addr_end = addr_begin + size; 240 const u64 addr_end = addr_begin + size;
211 const auto in_range = [addr_begin, addr_end](const CachedQuery& query) { 241 const auto in_range = [addr_begin, addr_end](const CachedQuery& query) {
@@ -226,7 +256,16 @@ private:
226 continue; 256 continue;
227 } 257 }
228 rasterizer.UpdatePagesCachedCount(query.GetCpuAddr(), query.SizeInBytes(), -1); 258 rasterizer.UpdatePagesCachedCount(query.GetCpuAddr(), query.SizeInBytes(), -1);
229 query.Flush(); 259 AsyncJobId async_job_id = query.GetAsyncJob();
260 auto flush_result = query.Flush(async);
261 if (async_job_id == NULL_ASYNC_JOB_ID) {
262 ASSERT_MSG(false, "This should not be reachable at all");
263 continue;
264 }
265 AsyncJob& async_job = slot_async_jobs[async_job_id];
266 async_job.collected = true;
267 async_job.value = flush_result;
268 query.SetAsyncJob(NULL_ASYNC_JOB_ID);
230 } 269 }
231 std::erase_if(contents, in_range); 270 std::erase_if(contents, in_range);
232 } 271 }
@@ -253,26 +292,60 @@ private:
253 return found != std::end(contents) ? &*found : nullptr; 292 return found != std::end(contents) ? &*found : nullptr;
254 } 293 }
255 294
256 void AsyncFlushQuery(VAddr addr) { 295 void AsyncFlushQuery(CachedQuery* query, std::optional<u64> timestamp,
257 if (!uncommitted_flushes) { 296 std::unique_lock<std::recursive_mutex>& lock) {
258 uncommitted_flushes = std::make_shared<std::vector<VAddr>>(); 297 const AsyncJobId new_async_job_id = slot_async_jobs.insert();
298 {
299 AsyncJob& async_job = slot_async_jobs[new_async_job_id];
300 query->SetAsyncJob(new_async_job_id);
301 async_job.query_location = query->GetCpuAddr();
302 async_job.collected = false;
303
304 if (!uncommitted_flushes) {
305 uncommitted_flushes = std::make_shared<std::vector<AsyncJobId>>();
306 }
307 uncommitted_flushes->push_back(new_async_job_id);
259 } 308 }
260 uncommitted_flushes->push_back(addr); 309 lock.unlock();
310 std::function<void()> operation([this, new_async_job_id, timestamp] {
311 std::unique_lock local_lock{mutex};
312 AsyncJob& async_job = slot_async_jobs[new_async_job_id];
313 u64 value = async_job.value;
314 VAddr address = async_job.query_location;
315 slot_async_jobs.erase(new_async_job_id);
316 local_lock.unlock();
317 if (timestamp) {
318 u64 timestamp_value = *timestamp;
319 cpu_memory.WriteBlockUnsafe(address + sizeof(u64), &timestamp_value, sizeof(u64));
320 cpu_memory.WriteBlockUnsafe(address, &value, sizeof(u64));
321 rasterizer.InvalidateRegion(address, sizeof(u64) * 2,
322 VideoCommon::CacheType::NoQueryCache);
323 } else {
324 u32 small_value = static_cast<u32>(value);
325 cpu_memory.WriteBlockUnsafe(address, &small_value, sizeof(u32));
326 rasterizer.InvalidateRegion(address, sizeof(u32),
327 VideoCommon::CacheType::NoQueryCache);
328 }
329 });
330 rasterizer.SyncOperation(std::move(operation));
261 } 331 }
262 332
263 static constexpr std::uintptr_t YUZU_PAGESIZE = 4096; 333 static constexpr std::uintptr_t YUZU_PAGESIZE = 4096;
264 static constexpr unsigned YUZU_PAGEBITS = 12; 334 static constexpr unsigned YUZU_PAGEBITS = 12;
265 335
336 SlotVector<AsyncJob> slot_async_jobs;
337
266 VideoCore::RasterizerInterface& rasterizer; 338 VideoCore::RasterizerInterface& rasterizer;
339 Core::Memory::Memory& cpu_memory;
267 340
268 std::recursive_mutex mutex; 341 mutable std::recursive_mutex mutex;
269 342
270 std::unordered_map<u64, std::vector<CachedQuery>> cached_queries; 343 std::unordered_map<u64, std::vector<CachedQuery>> cached_queries;
271 344
272 std::array<CounterStream, VideoCore::NumQueryTypes> streams; 345 std::array<CounterStream, VideoCore::NumQueryTypes> streams;
273 346
274 std::shared_ptr<std::vector<VAddr>> uncommitted_flushes{}; 347 std::shared_ptr<std::vector<AsyncJobId>> uncommitted_flushes{};
275 std::list<std::shared_ptr<std::vector<VAddr>>> committed_flushes; 348 std::list<std::shared_ptr<std::vector<AsyncJobId>>> committed_flushes;
276}; 349};
277 350
278template <class QueryCache, class HostCounter> 351template <class QueryCache, class HostCounter>
@@ -291,12 +364,12 @@ public:
291 virtual ~HostCounterBase() = default; 364 virtual ~HostCounterBase() = default;
292 365
293 /// Returns the current value of the query. 366 /// Returns the current value of the query.
294 u64 Query() { 367 u64 Query(bool async = false) {
295 if (result) { 368 if (result) {
296 return *result; 369 return *result;
297 } 370 }
298 371
299 u64 value = BlockingQuery() + base_result; 372 u64 value = BlockingQuery(async) + base_result;
300 if (dependency) { 373 if (dependency) {
301 value += dependency->Query(); 374 value += dependency->Query();
302 dependency = nullptr; 375 dependency = nullptr;
@@ -317,7 +390,7 @@ public:
317 390
318protected: 391protected:
319 /// Returns the value of query from the backend API blocking as needed. 392 /// Returns the value of query from the backend API blocking as needed.
320 virtual u64 BlockingQuery() const = 0; 393 virtual u64 BlockingQuery(bool async = false) const = 0;
321 394
322private: 395private:
323 std::shared_ptr<HostCounter> dependency; ///< Counter to add to this value. 396 std::shared_ptr<HostCounter> dependency; ///< Counter to add to this value.
@@ -340,26 +413,33 @@ public:
340 CachedQueryBase& operator=(const CachedQueryBase&) = delete; 413 CachedQueryBase& operator=(const CachedQueryBase&) = delete;
341 414
342 /// Flushes the query to guest memory. 415 /// Flushes the query to guest memory.
343 virtual void Flush() { 416 virtual u64 Flush(bool async = false) {
344 // When counter is nullptr it means that it's just been reset. We are supposed to write a 417 // When counter is nullptr it means that it's just been reset. We are supposed to write a
345 // zero in these cases. 418 // zero in these cases.
346 const u64 value = counter ? counter->Query() : 0; 419 const u64 value = counter ? counter->Query(async) : 0;
420 if (async) {
421 return value;
422 }
347 std::memcpy(host_ptr, &value, sizeof(u64)); 423 std::memcpy(host_ptr, &value, sizeof(u64));
348 424
349 if (timestamp) { 425 if (timestamp) {
350 std::memcpy(host_ptr + TIMESTAMP_OFFSET, &*timestamp, sizeof(u64)); 426 std::memcpy(host_ptr + TIMESTAMP_OFFSET, &*timestamp, sizeof(u64));
351 } 427 }
428 return value;
352 } 429 }
353 430
354 /// Binds a counter to this query. 431 /// Binds a counter to this query.
355 void BindCounter(std::shared_ptr<HostCounter> counter_, std::optional<u64> timestamp_) { 432 std::optional<u64> BindCounter(std::shared_ptr<HostCounter> counter_,
433 std::optional<u64> timestamp_) {
434 std::optional<u64> result{};
356 if (counter) { 435 if (counter) {
357 // If there's an old counter set it means the query is being rewritten by the game. 436 // If there's an old counter set it means the query is being rewritten by the game.
358 // To avoid losing the data forever, flush here. 437 // To avoid losing the data forever, flush here.
359 Flush(); 438 result = std::make_optional(Flush());
360 } 439 }
361 counter = std::move(counter_); 440 counter = std::move(counter_);
362 timestamp = timestamp_; 441 timestamp = timestamp_;
442 return result;
363 } 443 }
364 444
365 VAddr GetCpuAddr() const noexcept { 445 VAddr GetCpuAddr() const noexcept {
@@ -374,6 +454,14 @@ public:
374 return with_timestamp ? LARGE_QUERY_SIZE : SMALL_QUERY_SIZE; 454 return with_timestamp ? LARGE_QUERY_SIZE : SMALL_QUERY_SIZE;
375 } 455 }
376 456
457 void SetAsyncJob(AsyncJobId assigned_async_job_) {
458 assigned_async_job = assigned_async_job_;
459 }
460
461 AsyncJobId GetAsyncJob() const {
462 return assigned_async_job;
463 }
464
377protected: 465protected:
378 /// Returns true when querying the counter may potentially block. 466 /// Returns true when querying the counter may potentially block.
379 bool WaitPending() const noexcept { 467 bool WaitPending() const noexcept {
@@ -389,6 +477,7 @@ private:
389 u8* host_ptr; ///< Writable host pointer. 477 u8* host_ptr; ///< Writable host pointer.
390 std::shared_ptr<HostCounter> counter; ///< Host counter to query, owns the dependency tree. 478 std::shared_ptr<HostCounter> counter; ///< Host counter to query, owns the dependency tree.
391 std::optional<u64> timestamp; ///< Timestamp to flush to guest memory. 479 std::optional<u64> timestamp; ///< Timestamp to flush to guest memory.
480 AsyncJobId assigned_async_job;
392}; 481};
393 482
394} // namespace VideoCommon 483} // namespace VideoCommon
diff --git a/src/video_core/renderer_opengl/gl_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h
index f1446e732..e21b19dcc 100644
--- a/src/video_core/renderer_opengl/gl_fence_manager.h
+++ b/src/video_core/renderer_opengl/gl_fence_manager.h
@@ -30,7 +30,17 @@ private:
30}; 30};
31 31
32using Fence = std::shared_ptr<GLInnerFence>; 32using Fence = std::shared_ptr<GLInnerFence>;
33using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCache, BufferCache, QueryCache>; 33
34struct FenceManagerParams {
35 using FenceType = Fence;
36 using BufferCacheType = BufferCache;
37 using TextureCacheType = TextureCache;
38 using QueryCacheType = QueryCache;
39
40 static constexpr bool HAS_ASYNC_CHECK = false;
41};
42
43using GenericFenceManager = VideoCommon::FenceManager<FenceManagerParams>;
34 44
35class FenceManagerOpenGL final : public GenericFenceManager { 45class FenceManagerOpenGL final : public GenericFenceManager {
36public: 46public:
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp
index 5070db441..99d7347f5 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_query_cache.cpp
@@ -26,8 +26,8 @@ constexpr GLenum GetTarget(VideoCore::QueryType type) {
26 26
27} // Anonymous namespace 27} // Anonymous namespace
28 28
29QueryCache::QueryCache(RasterizerOpenGL& rasterizer_) 29QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_)
30 : QueryCacheBase(rasterizer_), gl_rasterizer{rasterizer_} {} 30 : QueryCacheBase(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {}
31 31
32QueryCache::~QueryCache() = default; 32QueryCache::~QueryCache() = default;
33 33
@@ -74,7 +74,7 @@ void HostCounter::EndQuery() {
74 glEndQuery(GetTarget(type)); 74 glEndQuery(GetTarget(type));
75} 75}
76 76
77u64 HostCounter::BlockingQuery() const { 77u64 HostCounter::BlockingQuery([[maybe_unused]] bool async) const {
78 GLint64 value; 78 GLint64 value;
79 glGetQueryObjecti64v(query.handle, GL_QUERY_RESULT, &value); 79 glGetQueryObjecti64v(query.handle, GL_QUERY_RESULT, &value);
80 return static_cast<u64>(value); 80 return static_cast<u64>(value);
@@ -96,7 +96,7 @@ CachedQuery& CachedQuery::operator=(CachedQuery&& rhs) noexcept {
96 return *this; 96 return *this;
97} 97}
98 98
99void CachedQuery::Flush() { 99u64 CachedQuery::Flush([[maybe_unused]] bool async) {
100 // Waiting for a query while another query of the same target is enabled locks Nvidia's driver. 100 // Waiting for a query while another query of the same target is enabled locks Nvidia's driver.
101 // To avoid this disable and re-enable keeping the dependency stream. 101 // To avoid this disable and re-enable keeping the dependency stream.
102 // But we only have to do this if we have pending waits to be done. 102 // But we only have to do this if we have pending waits to be done.
@@ -106,11 +106,13 @@ void CachedQuery::Flush() {
106 stream.Update(false); 106 stream.Update(false);
107 } 107 }
108 108
109 VideoCommon::CachedQueryBase<HostCounter>::Flush(); 109 auto result = VideoCommon::CachedQueryBase<HostCounter>::Flush();
110 110
111 if (slice_counter) { 111 if (slice_counter) {
112 stream.Update(true); 112 stream.Update(true);
113 } 113 }
114
115 return result;
114} 116}
115 117
116} // namespace OpenGL 118} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h
index 14ce59990..872513f22 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.h
+++ b/src/video_core/renderer_opengl/gl_query_cache.h
@@ -28,7 +28,7 @@ using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>;
28class QueryCache final 28class QueryCache final
29 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { 29 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> {
30public: 30public:
31 explicit QueryCache(RasterizerOpenGL& rasterizer_); 31 explicit QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_);
32 ~QueryCache(); 32 ~QueryCache();
33 33
34 OGLQuery AllocateQuery(VideoCore::QueryType type); 34 OGLQuery AllocateQuery(VideoCore::QueryType type);
@@ -51,7 +51,7 @@ public:
51 void EndQuery(); 51 void EndQuery();
52 52
53private: 53private:
54 u64 BlockingQuery() const override; 54 u64 BlockingQuery(bool async = false) const override;
55 55
56 QueryCache& cache; 56 QueryCache& cache;
57 const VideoCore::QueryType type; 57 const VideoCore::QueryType type;
@@ -70,7 +70,7 @@ public:
70 CachedQuery(const CachedQuery&) = delete; 70 CachedQuery(const CachedQuery&) = delete;
71 CachedQuery& operator=(const CachedQuery&) = delete; 71 CachedQuery& operator=(const CachedQuery&) = delete;
72 72
73 void Flush() override; 73 u64 Flush(bool async = false) override;
74 74
75private: 75private:
76 QueryCache* cache; 76 QueryCache* cache;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4993d4709..0089b4b27 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -63,7 +63,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra
63 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 63 buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
64 shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager, 64 shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager,
65 state_tracker, gpu.ShaderNotify()), 65 state_tracker, gpu.ShaderNotify()),
66 query_cache(*this), accelerate_dma(buffer_cache, texture_cache), 66 query_cache(*this, cpu_memory_), accelerate_dma(buffer_cache, texture_cache),
67 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache), 67 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
68 blit_image(program_manager_) {} 68 blit_image(program_manager_) {}
69 69
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 032a8ebc5..47cccd0e5 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -861,9 +861,12 @@ GLuint Image::StorageHandle() noexcept {
861 case PixelFormat::ASTC_2D_8X5_SRGB: 861 case PixelFormat::ASTC_2D_8X5_SRGB:
862 case PixelFormat::ASTC_2D_5X4_SRGB: 862 case PixelFormat::ASTC_2D_5X4_SRGB:
863 case PixelFormat::ASTC_2D_5X5_SRGB: 863 case PixelFormat::ASTC_2D_5X5_SRGB:
864 case PixelFormat::ASTC_2D_10X5_SRGB:
865 case PixelFormat::ASTC_2D_10X6_SRGB:
864 case PixelFormat::ASTC_2D_10X8_SRGB: 866 case PixelFormat::ASTC_2D_10X8_SRGB:
865 case PixelFormat::ASTC_2D_6X6_SRGB: 867 case PixelFormat::ASTC_2D_6X6_SRGB:
866 case PixelFormat::ASTC_2D_10X10_SRGB: 868 case PixelFormat::ASTC_2D_10X10_SRGB:
869 case PixelFormat::ASTC_2D_12X10_SRGB:
867 case PixelFormat::ASTC_2D_12X12_SRGB: 870 case PixelFormat::ASTC_2D_12X12_SRGB:
868 case PixelFormat::ASTC_2D_8X6_SRGB: 871 case PixelFormat::ASTC_2D_8X6_SRGB:
869 case PixelFormat::ASTC_2D_6X5_SRGB: 872 case PixelFormat::ASTC_2D_6X5_SRGB:
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index ef1190e1f..c7dc7e0a1 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -100,10 +100,13 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
100 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM 100 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM
101 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB 101 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB
102 {GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM 102 {GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM
103 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR}, // ASTC_2D_10X6_SRGB
103 {GL_COMPRESSED_RGBA_ASTC_10x5_KHR}, // ASTC_2D_10X5_UNORM 104 {GL_COMPRESSED_RGBA_ASTC_10x5_KHR}, // ASTC_2D_10X5_UNORM
104 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR}, // ASTC_2D_10X5_SRGB 105 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR}, // ASTC_2D_10X5_SRGB
105 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM 106 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM
106 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB 107 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB
108 {GL_COMPRESSED_RGBA_ASTC_12x10_KHR}, // ASTC_2D_12X10_UNORM
109 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR}, // ASTC_2D_12X10_SRGB
107 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM 110 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM
108 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB 111 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB
109 {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6_UNORM 112 {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6_UNORM
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 5dce51be8..8853cf0f7 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -197,10 +197,13 @@ struct FormatTuple {
197 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM 197 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM
198 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB 198 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB
199 {VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM 199 {VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM
200 {VK_FORMAT_ASTC_10x6_SRGB_BLOCK}, // ASTC_2D_10X6_SRGB
200 {VK_FORMAT_ASTC_10x5_UNORM_BLOCK}, // ASTC_2D_10X5_UNORM 201 {VK_FORMAT_ASTC_10x5_UNORM_BLOCK}, // ASTC_2D_10X5_UNORM
201 {VK_FORMAT_ASTC_10x5_SRGB_BLOCK}, // ASTC_2D_10X5_SRGB 202 {VK_FORMAT_ASTC_10x5_SRGB_BLOCK}, // ASTC_2D_10X5_SRGB
202 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM 203 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM
203 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB 204 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB
205 {VK_FORMAT_ASTC_12x10_UNORM_BLOCK}, // ASTC_2D_12X10_UNORM
206 {VK_FORMAT_ASTC_12x10_SRGB_BLOCK}, // ASTC_2D_12X10_SRGB
204 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM 207 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM
205 {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB 208 {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB
206 {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6_UNORM 209 {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6_UNORM
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 69dc76180..908625c66 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -134,7 +134,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
134 Frame* frame = present_manager.GetRenderFrame(); 134 Frame* frame = present_manager.GetRenderFrame();
135 blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb); 135 blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
136 scheduler.Flush(*frame->render_ready); 136 scheduler.Flush(*frame->render_ready);
137 scheduler.Record([this, frame](vk::CommandBuffer) { present_manager.PushFrame(frame); }); 137 present_manager.Present(frame);
138 138
139 gpu.RendererFrameEndNotify(); 139 gpu.RendererFrameEndNotify();
140 rasterizer.TickFrame(); 140 rasterizer.TickFrame();
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index 0214b103a..fad9e3832 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -5,6 +5,7 @@
5 5
6#include "video_core/renderer_vulkan/vk_buffer_cache.h" 6#include "video_core/renderer_vulkan/vk_buffer_cache.h"
7#include "video_core/renderer_vulkan/vk_fence_manager.h" 7#include "video_core/renderer_vulkan/vk_fence_manager.h"
8#include "video_core/renderer_vulkan/vk_query_cache.h"
8#include "video_core/renderer_vulkan/vk_scheduler.h" 9#include "video_core/renderer_vulkan/vk_scheduler.h"
9#include "video_core/renderer_vulkan/vk_texture_cache.h" 10#include "video_core/renderer_vulkan/vk_texture_cache.h"
10#include "video_core/vulkan_common/vulkan_device.h" 11#include "video_core/vulkan_common/vulkan_device.h"
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index 7fe2afcd9..145359d4e 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -40,7 +40,16 @@ private:
40}; 40};
41using Fence = std::shared_ptr<InnerFence>; 41using Fence = std::shared_ptr<InnerFence>;
42 42
43using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCache, BufferCache, QueryCache>; 43struct FenceManagerParams {
44 using FenceType = Fence;
45 using BufferCacheType = BufferCache;
46 using TextureCacheType = TextureCache;
47 using QueryCacheType = QueryCache;
48
49 static constexpr bool HAS_ASYNC_CHECK = true;
50};
51
52using GenericFenceManager = VideoCommon::FenceManager<FenceManagerParams>;
44 53
45class FenceManager final : public GenericFenceManager { 54class FenceManager final : public GenericFenceManager {
46public: 55public:
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index a137c66f2..c49583013 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -153,16 +153,19 @@ Frame* PresentManager::GetRenderFrame() {
153 return frame; 153 return frame;
154} 154}
155 155
156void PresentManager::PushFrame(Frame* frame) { 156void PresentManager::Present(Frame* frame) {
157 if (!use_present_thread) { 157 if (!use_present_thread) {
158 scheduler.WaitWorker();
158 CopyToSwapchain(frame); 159 CopyToSwapchain(frame);
159 free_queue.push(frame); 160 free_queue.push(frame);
160 return; 161 return;
161 } 162 }
162 163
163 std::unique_lock lock{queue_mutex}; 164 scheduler.Record([this, frame](vk::CommandBuffer) {
164 present_queue.push(frame); 165 std::unique_lock lock{queue_mutex};
165 frame_cv.notify_one(); 166 present_queue.push(frame);
167 frame_cv.notify_one();
168 });
166} 169}
167 170
168void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, 171void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb,
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
index 9885fd7c6..420a775e2 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.h
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -45,7 +45,7 @@ public:
45 Frame* GetRenderFrame(); 45 Frame* GetRenderFrame();
46 46
47 /// Pushes a frame for presentation 47 /// Pushes a frame for presentation
48 void PushFrame(Frame* frame); 48 void Present(Frame* frame);
49 49
50 /// Recreates the present frame to match the provided parameters 50 /// Recreates the present frame to match the provided parameters
51 void RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, 51 void RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb,
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 929c8ece6..d67490449 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -66,9 +66,10 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
66 } 66 }
67} 67}
68 68
69QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_, 69QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_,
70 Core::Memory::Memory& cpu_memory_, const Device& device_,
70 Scheduler& scheduler_) 71 Scheduler& scheduler_)
71 : QueryCacheBase{rasterizer_}, device{device_}, scheduler{scheduler_}, 72 : QueryCacheBase{rasterizer_, cpu_memory_}, device{device_}, scheduler{scheduler_},
72 query_pools{ 73 query_pools{
73 QueryPool{device_, scheduler_, QueryType::SamplesPassed}, 74 QueryPool{device_, scheduler_, QueryType::SamplesPassed},
74 } {} 75 } {}
@@ -98,8 +99,10 @@ HostCounter::HostCounter(QueryCache& cache_, std::shared_ptr<HostCounter> depend
98 query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} { 99 query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} {
99 const vk::Device* logical = &cache.GetDevice().GetLogical(); 100 const vk::Device* logical = &cache.GetDevice().GetLogical();
100 cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { 101 cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) {
102 const bool use_precise = Settings::IsGPULevelHigh();
101 logical->ResetQueryPool(query.first, query.second, 1); 103 logical->ResetQueryPool(query.first, query.second, 1);
102 cmdbuf.BeginQuery(query.first, query.second, VK_QUERY_CONTROL_PRECISE_BIT); 104 cmdbuf.BeginQuery(query.first, query.second,
105 use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0);
103 }); 106 });
104} 107}
105 108
@@ -112,8 +115,10 @@ void HostCounter::EndQuery() {
112 [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); }); 115 [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); });
113} 116}
114 117
115u64 HostCounter::BlockingQuery() const { 118u64 HostCounter::BlockingQuery(bool async) const {
116 cache.GetScheduler().Wait(tick); 119 if (!async) {
120 cache.GetScheduler().Wait(tick);
121 }
117 u64 data; 122 u64 data;
118 const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults( 123 const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults(
119 query.first, query.second, 1, sizeof(data), &data, sizeof(data), 124 query.first, query.second, 1, sizeof(data), &data, sizeof(data),
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index 26762ee09..c1b9552eb 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -52,7 +52,8 @@ private:
52class QueryCache final 52class QueryCache final
53 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { 53 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> {
54public: 54public:
55 explicit QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_, 55 explicit QueryCache(VideoCore::RasterizerInterface& rasterizer_,
56 Core::Memory::Memory& cpu_memory_, const Device& device_,
56 Scheduler& scheduler_); 57 Scheduler& scheduler_);
57 ~QueryCache(); 58 ~QueryCache();
58 59
@@ -83,7 +84,7 @@ public:
83 void EndQuery(); 84 void EndQuery();
84 85
85private: 86private:
86 u64 BlockingQuery() const override; 87 u64 BlockingQuery(bool async = false) const override;
87 88
88 QueryCache& cache; 89 QueryCache& cache;
89 const VideoCore::QueryType type; 90 const VideoCore::QueryType type;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 2559a3aa7..d1489fc95 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -172,7 +172,8 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
172 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 172 buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
173 pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue, 173 pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue,
174 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), 174 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),
175 query_cache{*this, device, scheduler}, accelerate_dma(buffer_cache, texture_cache, scheduler), 175 query_cache{*this, cpu_memory_, device, scheduler},
176 accelerate_dma(buffer_cache, texture_cache, scheduler),
176 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), 177 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
177 wfi_event(device.GetLogical().CreateEvent()) { 178 wfi_event(device.GetLogical().CreateEvent()) {
178 scheduler.SetQueryCache(query_cache); 179 scheduler.SetQueryCache(query_cache);
@@ -675,7 +676,8 @@ bool RasterizerVulkan::AccelerateConditionalRendering() {
675 const GPUVAddr condition_address{maxwell3d->regs.render_enable.Address()}; 676 const GPUVAddr condition_address{maxwell3d->regs.render_enable.Address()};
676 Maxwell::ReportSemaphore::Compare cmp; 677 Maxwell::ReportSemaphore::Compare cmp;
677 if (gpu_memory->IsMemoryDirty(condition_address, sizeof(cmp), 678 if (gpu_memory->IsMemoryDirty(condition_address, sizeof(cmp),
678 VideoCommon::CacheType::BufferCache)) { 679 VideoCommon::CacheType::BufferCache |
680 VideoCommon::CacheType::QueryCache)) {
679 return true; 681 return true;
680 } 682 }
681 return false; 683 return false;
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index d9482371b..c5213875b 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -228,14 +228,14 @@ const ShaderInfo* ShaderCache::MakeShaderInfo(GenericEnvironment& env, VAddr cpu
228 auto info = std::make_unique<ShaderInfo>(); 228 auto info = std::make_unique<ShaderInfo>();
229 if (const std::optional<u64> cached_hash{env.Analyze()}) { 229 if (const std::optional<u64> cached_hash{env.Analyze()}) {
230 info->unique_hash = *cached_hash; 230 info->unique_hash = *cached_hash;
231 info->size_bytes = env.CachedSize(); 231 info->size_bytes = env.CachedSizeBytes();
232 } else { 232 } else {
233 // Slow path, not really hit on commercial games 233 // Slow path, not really hit on commercial games
234 // Build a control flow graph to get the real shader size 234 // Build a control flow graph to get the real shader size
235 Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block; 235 Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block;
236 Shader::Maxwell::Flow::CFG cfg{env, flow_block, env.StartAddress()}; 236 Shader::Maxwell::Flow::CFG cfg{env, flow_block, env.StartAddress()};
237 info->unique_hash = env.CalculateHash(); 237 info->unique_hash = env.CalculateHash();
238 info->size_bytes = env.ReadSize(); 238 info->size_bytes = env.ReadSizeBytes();
239 } 239 }
240 const size_t size_bytes{info->size_bytes}; 240 const size_t size_bytes{info->size_bytes};
241 const ShaderInfo* const result{info.get()}; 241 const ShaderInfo* const result{info.get()};
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 574760f80..c7cb56243 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -170,15 +170,19 @@ std::optional<u64> GenericEnvironment::Analyze() {
170void GenericEnvironment::SetCachedSize(size_t size_bytes) { 170void GenericEnvironment::SetCachedSize(size_t size_bytes) {
171 cached_lowest = start_address; 171 cached_lowest = start_address;
172 cached_highest = start_address + static_cast<u32>(size_bytes); 172 cached_highest = start_address + static_cast<u32>(size_bytes);
173 code.resize(CachedSize()); 173 code.resize(CachedSizeWords());
174 gpu_memory->ReadBlock(program_base + cached_lowest, code.data(), code.size() * sizeof(u64)); 174 gpu_memory->ReadBlock(program_base + cached_lowest, code.data(), code.size() * sizeof(u64));
175} 175}
176 176
177size_t GenericEnvironment::CachedSize() const noexcept { 177size_t GenericEnvironment::CachedSizeWords() const noexcept {
178 return cached_highest - cached_lowest + INST_SIZE; 178 return CachedSizeBytes() / INST_SIZE;
179} 179}
180 180
181size_t GenericEnvironment::ReadSize() const noexcept { 181size_t GenericEnvironment::CachedSizeBytes() const noexcept {
182 return static_cast<size_t>(cached_highest) - cached_lowest + INST_SIZE;
183}
184
185size_t GenericEnvironment::ReadSizeBytes() const noexcept {
182 return read_highest - read_lowest + INST_SIZE; 186 return read_highest - read_lowest + INST_SIZE;
183} 187}
184 188
@@ -187,7 +191,7 @@ bool GenericEnvironment::CanBeSerialized() const noexcept {
187} 191}
188 192
189u64 GenericEnvironment::CalculateHash() const { 193u64 GenericEnvironment::CalculateHash() const {
190 const size_t size{ReadSize()}; 194 const size_t size{ReadSizeBytes()};
191 const auto data{std::make_unique<char[]>(size)}; 195 const auto data{std::make_unique<char[]>(size)};
192 gpu_memory->ReadBlock(program_base + read_lowest, data.get(), size); 196 gpu_memory->ReadBlock(program_base + read_lowest, data.get(), size);
193 return Common::CityHash64(data.get(), size); 197 return Common::CityHash64(data.get(), size);
@@ -198,7 +202,7 @@ void GenericEnvironment::Dump(u64 hash) {
198} 202}
199 203
200void GenericEnvironment::Serialize(std::ofstream& file) const { 204void GenericEnvironment::Serialize(std::ofstream& file) const {
201 const u64 code_size{static_cast<u64>(CachedSize())}; 205 const u64 code_size{static_cast<u64>(CachedSizeBytes())};
202 const u64 num_texture_types{static_cast<u64>(texture_types.size())}; 206 const u64 num_texture_types{static_cast<u64>(texture_types.size())};
203 const u64 num_texture_pixel_formats{static_cast<u64>(texture_pixel_formats.size())}; 207 const u64 num_texture_pixel_formats{static_cast<u64>(texture_pixel_formats.size())};
204 const u64 num_cbuf_values{static_cast<u64>(cbuf_values.size())}; 208 const u64 num_cbuf_values{static_cast<u64>(cbuf_values.size())};
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h
index d75987a52..a0f61cbda 100644
--- a/src/video_core/shader_environment.h
+++ b/src/video_core/shader_environment.h
@@ -48,9 +48,11 @@ public:
48 48
49 void SetCachedSize(size_t size_bytes); 49 void SetCachedSize(size_t size_bytes);
50 50
51 [[nodiscard]] size_t CachedSize() const noexcept; 51 [[nodiscard]] size_t CachedSizeWords() const noexcept;
52 52
53 [[nodiscard]] size_t ReadSize() const noexcept; 53 [[nodiscard]] size_t CachedSizeBytes() const noexcept;
54
55 [[nodiscard]] size_t ReadSizeBytes() const noexcept;
54 56
55 [[nodiscard]] bool CanBeSerialized() const noexcept; 57 [[nodiscard]] bool CanBeSerialized() const noexcept;
56 58
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 1a76d4178..cb51529e4 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -250,10 +250,13 @@ bool IsPixelFormatASTC(PixelFormat format) {
250 case PixelFormat::ASTC_2D_6X6_UNORM: 250 case PixelFormat::ASTC_2D_6X6_UNORM:
251 case PixelFormat::ASTC_2D_6X6_SRGB: 251 case PixelFormat::ASTC_2D_6X6_SRGB:
252 case PixelFormat::ASTC_2D_10X6_UNORM: 252 case PixelFormat::ASTC_2D_10X6_UNORM:
253 case PixelFormat::ASTC_2D_10X6_SRGB:
253 case PixelFormat::ASTC_2D_10X5_UNORM: 254 case PixelFormat::ASTC_2D_10X5_UNORM:
254 case PixelFormat::ASTC_2D_10X5_SRGB: 255 case PixelFormat::ASTC_2D_10X5_SRGB:
255 case PixelFormat::ASTC_2D_10X10_UNORM: 256 case PixelFormat::ASTC_2D_10X10_UNORM:
256 case PixelFormat::ASTC_2D_10X10_SRGB: 257 case PixelFormat::ASTC_2D_10X10_SRGB:
258 case PixelFormat::ASTC_2D_12X10_UNORM:
259 case PixelFormat::ASTC_2D_12X10_SRGB:
257 case PixelFormat::ASTC_2D_12X12_UNORM: 260 case PixelFormat::ASTC_2D_12X12_UNORM:
258 case PixelFormat::ASTC_2D_12X12_SRGB: 261 case PixelFormat::ASTC_2D_12X12_SRGB:
259 case PixelFormat::ASTC_2D_8X6_UNORM: 262 case PixelFormat::ASTC_2D_8X6_UNORM:
@@ -279,11 +282,13 @@ bool IsPixelFormatSRGB(PixelFormat format) {
279 case PixelFormat::ASTC_2D_8X5_SRGB: 282 case PixelFormat::ASTC_2D_8X5_SRGB:
280 case PixelFormat::ASTC_2D_5X4_SRGB: 283 case PixelFormat::ASTC_2D_5X4_SRGB:
281 case PixelFormat::ASTC_2D_5X5_SRGB: 284 case PixelFormat::ASTC_2D_5X5_SRGB:
285 case PixelFormat::ASTC_2D_10X6_SRGB:
282 case PixelFormat::ASTC_2D_10X8_SRGB: 286 case PixelFormat::ASTC_2D_10X8_SRGB:
283 case PixelFormat::ASTC_2D_6X6_SRGB: 287 case PixelFormat::ASTC_2D_6X6_SRGB:
284 case PixelFormat::ASTC_2D_10X5_SRGB: 288 case PixelFormat::ASTC_2D_10X5_SRGB:
285 case PixelFormat::ASTC_2D_10X10_SRGB: 289 case PixelFormat::ASTC_2D_10X10_SRGB:
286 case PixelFormat::ASTC_2D_12X12_SRGB: 290 case PixelFormat::ASTC_2D_12X12_SRGB:
291 case PixelFormat::ASTC_2D_12X10_SRGB:
287 case PixelFormat::ASTC_2D_8X6_SRGB: 292 case PixelFormat::ASTC_2D_8X6_SRGB:
288 case PixelFormat::ASTC_2D_6X5_SRGB: 293 case PixelFormat::ASTC_2D_6X5_SRGB:
289 return true; 294 return true;
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 44b79af20..0225d3287 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -95,10 +95,13 @@ enum class PixelFormat {
95 ASTC_2D_6X6_UNORM, 95 ASTC_2D_6X6_UNORM,
96 ASTC_2D_6X6_SRGB, 96 ASTC_2D_6X6_SRGB,
97 ASTC_2D_10X6_UNORM, 97 ASTC_2D_10X6_UNORM,
98 ASTC_2D_10X6_SRGB,
98 ASTC_2D_10X5_UNORM, 99 ASTC_2D_10X5_UNORM,
99 ASTC_2D_10X5_SRGB, 100 ASTC_2D_10X5_SRGB,
100 ASTC_2D_10X10_UNORM, 101 ASTC_2D_10X10_UNORM,
101 ASTC_2D_10X10_SRGB, 102 ASTC_2D_10X10_SRGB,
103 ASTC_2D_12X10_UNORM,
104 ASTC_2D_12X10_SRGB,
102 ASTC_2D_12X12_UNORM, 105 ASTC_2D_12X12_UNORM,
103 ASTC_2D_12X12_SRGB, 106 ASTC_2D_12X12_SRGB,
104 ASTC_2D_8X6_UNORM, 107 ASTC_2D_8X6_UNORM,
@@ -232,10 +235,13 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
232 6, // ASTC_2D_6X6_UNORM 235 6, // ASTC_2D_6X6_UNORM
233 6, // ASTC_2D_6X6_SRGB 236 6, // ASTC_2D_6X6_SRGB
234 10, // ASTC_2D_10X6_UNORM 237 10, // ASTC_2D_10X6_UNORM
238 10, // ASTC_2D_10X6_SRGB
235 10, // ASTC_2D_10X5_UNORM 239 10, // ASTC_2D_10X5_UNORM
236 10, // ASTC_2D_10X5_SRGB 240 10, // ASTC_2D_10X5_SRGB
237 10, // ASTC_2D_10X10_UNORM 241 10, // ASTC_2D_10X10_UNORM
238 10, // ASTC_2D_10X10_SRGB 242 10, // ASTC_2D_10X10_SRGB
243 12, // ASTC_2D_12X10_UNORM
244 12, // ASTC_2D_12X10_SRGB
239 12, // ASTC_2D_12X12_UNORM 245 12, // ASTC_2D_12X12_UNORM
240 12, // ASTC_2D_12X12_SRGB 246 12, // ASTC_2D_12X12_SRGB
241 8, // ASTC_2D_8X6_UNORM 247 8, // ASTC_2D_8X6_UNORM
@@ -338,10 +344,13 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
338 6, // ASTC_2D_6X6_UNORM 344 6, // ASTC_2D_6X6_UNORM
339 6, // ASTC_2D_6X6_SRGB 345 6, // ASTC_2D_6X6_SRGB
340 6, // ASTC_2D_10X6_UNORM 346 6, // ASTC_2D_10X6_UNORM
347 6, // ASTC_2D_10X6_SRGB
341 5, // ASTC_2D_10X5_UNORM 348 5, // ASTC_2D_10X5_UNORM
342 5, // ASTC_2D_10X5_SRGB 349 5, // ASTC_2D_10X5_SRGB
343 10, // ASTC_2D_10X10_UNORM 350 10, // ASTC_2D_10X10_UNORM
344 10, // ASTC_2D_10X10_SRGB 351 10, // ASTC_2D_10X10_SRGB
352 10, // ASTC_2D_12X10_UNORM
353 10, // ASTC_2D_12X10_SRGB
345 12, // ASTC_2D_12X12_UNORM 354 12, // ASTC_2D_12X12_UNORM
346 12, // ASTC_2D_12X12_SRGB 355 12, // ASTC_2D_12X12_SRGB
347 6, // ASTC_2D_8X6_UNORM 356 6, // ASTC_2D_8X6_UNORM
@@ -444,10 +453,13 @@ constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
444 128, // ASTC_2D_6X6_UNORM 453 128, // ASTC_2D_6X6_UNORM
445 128, // ASTC_2D_6X6_SRGB 454 128, // ASTC_2D_6X6_SRGB
446 128, // ASTC_2D_10X6_UNORM 455 128, // ASTC_2D_10X6_UNORM
456 128, // ASTC_2D_10X6_SRGB
447 128, // ASTC_2D_10X5_UNORM 457 128, // ASTC_2D_10X5_UNORM
448 128, // ASTC_2D_10X5_SRGB 458 128, // ASTC_2D_10X5_SRGB
449 128, // ASTC_2D_10X10_UNORM 459 128, // ASTC_2D_10X10_UNORM
450 128, // ASTC_2D_10X10_SRGB 460 128, // ASTC_2D_10X10_SRGB
461 128, // ASTC_2D_12X10_UNORM
462 128, // ASTC_2D_12X10_SRGB
451 128, // ASTC_2D_12X12_UNORM 463 128, // ASTC_2D_12X12_UNORM
452 128, // ASTC_2D_12X12_SRGB 464 128, // ASTC_2D_12X12_SRGB
453 128, // ASTC_2D_8X6_UNORM 465 128, // ASTC_2D_8X6_UNORM
diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp
index 5fc2b2fec..11ced6c38 100644
--- a/src/video_core/texture_cache/format_lookup_table.cpp
+++ b/src/video_core/texture_cache/format_lookup_table.cpp
@@ -210,6 +210,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
210 return PixelFormat::ASTC_2D_6X6_SRGB; 210 return PixelFormat::ASTC_2D_6X6_SRGB;
211 case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR): 211 case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR):
212 return PixelFormat::ASTC_2D_10X6_UNORM; 212 return PixelFormat::ASTC_2D_10X6_UNORM;
213 case Hash(TextureFormat::ASTC_2D_10X6, UNORM, SRGB):
214 return PixelFormat::ASTC_2D_10X6_SRGB;
213 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, LINEAR): 215 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, LINEAR):
214 return PixelFormat::ASTC_2D_10X5_UNORM; 216 return PixelFormat::ASTC_2D_10X5_UNORM;
215 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, SRGB): 217 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, SRGB):
@@ -218,6 +220,10 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
218 return PixelFormat::ASTC_2D_10X10_UNORM; 220 return PixelFormat::ASTC_2D_10X10_UNORM;
219 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB): 221 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB):
220 return PixelFormat::ASTC_2D_10X10_SRGB; 222 return PixelFormat::ASTC_2D_10X10_SRGB;
223 case Hash(TextureFormat::ASTC_2D_12X10, UNORM, LINEAR):
224 return PixelFormat::ASTC_2D_12X10_UNORM;
225 case Hash(TextureFormat::ASTC_2D_12X10, UNORM, SRGB):
226 return PixelFormat::ASTC_2D_12X10_SRGB;
221 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, LINEAR): 227 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, LINEAR):
222 return PixelFormat::ASTC_2D_12X12_UNORM; 228 return PixelFormat::ASTC_2D_12X12_UNORM;
223 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, SRGB): 229 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, SRGB):
diff --git a/src/video_core/texture_cache/formatter.h b/src/video_core/texture_cache/formatter.h
index f1f0a057b..b97147797 100644
--- a/src/video_core/texture_cache/formatter.h
+++ b/src/video_core/texture_cache/formatter.h
@@ -179,6 +179,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
179 return "ASTC_2D_6X6_SRGB"; 179 return "ASTC_2D_6X6_SRGB";
180 case PixelFormat::ASTC_2D_10X6_UNORM: 180 case PixelFormat::ASTC_2D_10X6_UNORM:
181 return "ASTC_2D_10X6_UNORM"; 181 return "ASTC_2D_10X6_UNORM";
182 case PixelFormat::ASTC_2D_10X6_SRGB:
183 return "ASTC_2D_10X6_SRGB";
182 case PixelFormat::ASTC_2D_10X5_UNORM: 184 case PixelFormat::ASTC_2D_10X5_UNORM:
183 return "ASTC_2D_10X5_UNORM"; 185 return "ASTC_2D_10X5_UNORM";
184 case PixelFormat::ASTC_2D_10X5_SRGB: 186 case PixelFormat::ASTC_2D_10X5_SRGB:
@@ -187,6 +189,10 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
187 return "ASTC_2D_10X10_UNORM"; 189 return "ASTC_2D_10X10_UNORM";
188 case PixelFormat::ASTC_2D_10X10_SRGB: 190 case PixelFormat::ASTC_2D_10X10_SRGB:
189 return "ASTC_2D_10X10_SRGB"; 191 return "ASTC_2D_10X10_SRGB";
192 case PixelFormat::ASTC_2D_12X10_UNORM:
193 return "ASTC_2D_12X10_UNORM";
194 case PixelFormat::ASTC_2D_12X10_SRGB:
195 return "ASTC_2D_12X10_SRGB";
190 case PixelFormat::ASTC_2D_12X12_UNORM: 196 case PixelFormat::ASTC_2D_12X12_UNORM:
191 return "ASTC_2D_12X12_UNORM"; 197 return "ASTC_2D_12X12_UNORM";
192 case PixelFormat::ASTC_2D_12X12_SRGB: 198 case PixelFormat::ASTC_2D_12X12_SRGB:
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index e601f8446..f335009d0 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -888,7 +888,7 @@ void TextureCache<P>::DownloadImageIntoBuffer(typename TextureCache<P>::Image* i
888 buffer, 888 buffer,
889 download_map.buffer, 889 download_map.buffer,
890 }; 890 };
891 std::array buffer_offsets{ 891 std::array<u64, 2> buffer_offsets{
892 buffer_offset, 892 buffer_offset,
893 download_map.offset, 893 download_map.offset,
894 }; 894 };
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 6f288b3f8..6ffca2af2 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -617,7 +617,9 @@ bool Device::ShouldBoostClocks() const {
617 617
618 const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F; 618 const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F;
619 619
620 return validated_driver && !is_steam_deck; 620 const bool is_debugging = this->HasDebuggingToolAttached();
621
622 return validated_driver && !is_steam_deck && !is_debugging;
621} 623}
622 624
623bool Device::GetSuitability(bool requires_swapchain) { 625bool Device::GetSuitability(bool requires_swapchain) {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 305891d18..0131f63e7 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -497,7 +497,7 @@ void Config::ReadCoreValues() {
497 qt_config->beginGroup(QStringLiteral("Core")); 497 qt_config->beginGroup(QStringLiteral("Core"));
498 498
499 ReadGlobalSetting(Settings::values.use_multi_core); 499 ReadGlobalSetting(Settings::values.use_multi_core);
500 ReadGlobalSetting(Settings::values.use_extended_memory_layout); 500 ReadGlobalSetting(Settings::values.use_unsafe_extended_memory_layout);
501 501
502 qt_config->endGroup(); 502 qt_config->endGroup();
503} 503}
@@ -713,7 +713,6 @@ void Config::ReadRendererValues() {
713 ReadGlobalSetting(Settings::values.shader_backend); 713 ReadGlobalSetting(Settings::values.shader_backend);
714 ReadGlobalSetting(Settings::values.use_asynchronous_shaders); 714 ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
715 ReadGlobalSetting(Settings::values.use_fast_gpu_time); 715 ReadGlobalSetting(Settings::values.use_fast_gpu_time);
716 ReadGlobalSetting(Settings::values.use_pessimistic_flushes);
717 ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); 716 ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
718 ReadGlobalSetting(Settings::values.bg_red); 717 ReadGlobalSetting(Settings::values.bg_red);
719 ReadGlobalSetting(Settings::values.bg_green); 718 ReadGlobalSetting(Settings::values.bg_green);
@@ -1162,7 +1161,7 @@ void Config::SaveCoreValues() {
1162 qt_config->beginGroup(QStringLiteral("Core")); 1161 qt_config->beginGroup(QStringLiteral("Core"));
1163 1162
1164 WriteGlobalSetting(Settings::values.use_multi_core); 1163 WriteGlobalSetting(Settings::values.use_multi_core);
1165 WriteGlobalSetting(Settings::values.use_extended_memory_layout); 1164 WriteGlobalSetting(Settings::values.use_unsafe_extended_memory_layout);
1166 1165
1167 qt_config->endGroup(); 1166 qt_config->endGroup();
1168} 1167}
@@ -1359,7 +1358,6 @@ void Config::SaveRendererValues() {
1359 Settings::values.shader_backend.UsingGlobal()); 1358 Settings::values.shader_backend.UsingGlobal());
1360 WriteGlobalSetting(Settings::values.use_asynchronous_shaders); 1359 WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
1361 WriteGlobalSetting(Settings::values.use_fast_gpu_time); 1360 WriteGlobalSetting(Settings::values.use_fast_gpu_time);
1362 WriteGlobalSetting(Settings::values.use_pessimistic_flushes);
1363 WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); 1361 WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
1364 WriteGlobalSetting(Settings::values.bg_red); 1362 WriteGlobalSetting(Settings::values.bg_red);
1365 WriteGlobalSetting(Settings::values.bg_green); 1363 WriteGlobalSetting(Settings::values.bg_green);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 207bcdc4d..26258d744 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -35,9 +35,6 @@ void ConfigureGeneral::SetConfiguration() {
35 35
36 ui->use_multi_core->setEnabled(runtime_lock); 36 ui->use_multi_core->setEnabled(runtime_lock);
37 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue()); 37 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
38 ui->use_extended_memory_layout->setEnabled(runtime_lock);
39 ui->use_extended_memory_layout->setChecked(
40 Settings::values.use_extended_memory_layout.GetValue());
41 38
42 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue()); 39 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
43 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue()); 40 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
@@ -79,9 +76,6 @@ void ConfigureGeneral::ResetDefaults() {
79void ConfigureGeneral::ApplyConfiguration() { 76void ConfigureGeneral::ApplyConfiguration() {
80 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core, 77 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
81 use_multi_core); 78 use_multi_core);
82 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_extended_memory_layout,
83 ui->use_extended_memory_layout,
84 use_extended_memory_layout);
85 79
86 if (Settings::IsConfiguringGlobal()) { 80 if (Settings::IsConfiguringGlobal()) {
87 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 81 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
@@ -141,9 +135,6 @@ void ConfigureGeneral::SetupPerGameUI() {
141 Settings::values.use_speed_limit, use_speed_limit); 135 Settings::values.use_speed_limit, use_speed_limit);
142 ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, 136 ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
143 use_multi_core); 137 use_multi_core);
144 ConfigurationShared::SetColoredTristate(ui->use_extended_memory_layout,
145 Settings::values.use_extended_memory_layout,
146 use_extended_memory_layout);
147 138
148 connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { 139 connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() {
149 ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && 140 ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index a090c1a3f..7ff63f425 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -47,7 +47,6 @@ private:
47 47
48 ConfigurationShared::CheckState use_speed_limit; 48 ConfigurationShared::CheckState use_speed_limit;
49 ConfigurationShared::CheckState use_multi_core; 49 ConfigurationShared::CheckState use_multi_core;
50 ConfigurationShared::CheckState use_extended_memory_layout;
51 50
52 const Core::System& system; 51 const Core::System& system;
53}; 52};
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index add110bb0..986a1625b 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -62,13 +62,6 @@
62 </widget> 62 </widget>
63 </item> 63 </item>
64 <item> 64 <item>
65 <widget class="QCheckBox" name="use_extended_memory_layout">
66 <property name="text">
67 <string>Extended memory layout (8GB DRAM)</string>
68 </property>
69 </widget>
70 </item>
71 <item>
72 <widget class="QCheckBox" name="toggle_check_exit"> 65 <widget class="QCheckBox" name="toggle_check_exit">
73 <property name="text"> 66 <property name="text">
74 <string>Confirm exit while emulation is running</string> 67 <string>Confirm exit while emulation is running</string>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 7f7bf0e4d..ddda79983 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -34,7 +34,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
34 ui->async_astc->setChecked(Settings::values.async_astc.GetValue()); 34 ui->async_astc->setChecked(Settings::values.async_astc.GetValue());
35 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); 35 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
36 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); 36 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
37 ui->use_pessimistic_flushes->setChecked(Settings::values.use_pessimistic_flushes.GetValue());
38 ui->use_vulkan_driver_pipeline_cache->setChecked( 37 ui->use_vulkan_driver_pipeline_cache->setChecked(
39 Settings::values.use_vulkan_driver_pipeline_cache.GetValue()); 38 Settings::values.use_vulkan_driver_pipeline_cache.GetValue());
40 39
@@ -71,8 +70,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
71 use_asynchronous_shaders); 70 use_asynchronous_shaders);
72 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, 71 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
73 ui->use_fast_gpu_time, use_fast_gpu_time); 72 ui->use_fast_gpu_time, use_fast_gpu_time);
74 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_pessimistic_flushes,
75 ui->use_pessimistic_flushes, use_pessimistic_flushes);
76 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache, 73 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache,
77 ui->use_vulkan_driver_pipeline_cache, 74 ui->use_vulkan_driver_pipeline_cache,
78 use_vulkan_driver_pipeline_cache); 75 use_vulkan_driver_pipeline_cache);
@@ -102,8 +99,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
102 ui->use_asynchronous_shaders->setEnabled( 99 ui->use_asynchronous_shaders->setEnabled(
103 Settings::values.use_asynchronous_shaders.UsingGlobal()); 100 Settings::values.use_asynchronous_shaders.UsingGlobal());
104 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); 101 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
105 ui->use_pessimistic_flushes->setEnabled(
106 Settings::values.use_pessimistic_flushes.UsingGlobal());
107 ui->use_vulkan_driver_pipeline_cache->setEnabled( 102 ui->use_vulkan_driver_pipeline_cache->setEnabled(
108 Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal()); 103 Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal());
109 ui->anisotropic_filtering_combobox->setEnabled( 104 ui->anisotropic_filtering_combobox->setEnabled(
@@ -125,9 +120,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
125 use_asynchronous_shaders); 120 use_asynchronous_shaders);
126 ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time, 121 ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time,
127 Settings::values.use_fast_gpu_time, use_fast_gpu_time); 122 Settings::values.use_fast_gpu_time, use_fast_gpu_time);
128 ConfigurationShared::SetColoredTristate(ui->use_pessimistic_flushes,
129 Settings::values.use_pessimistic_flushes,
130 use_pessimistic_flushes);
131 ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache, 123 ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache,
132 Settings::values.use_vulkan_driver_pipeline_cache, 124 Settings::values.use_vulkan_driver_pipeline_cache,
133 use_vulkan_driver_pipeline_cache); 125 use_vulkan_driver_pipeline_cache);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 5394ed40a..ff5060957 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -42,7 +42,6 @@ private:
42 ConfigurationShared::CheckState async_astc; 42 ConfigurationShared::CheckState async_astc;
43 ConfigurationShared::CheckState use_asynchronous_shaders; 43 ConfigurationShared::CheckState use_asynchronous_shaders;
44 ConfigurationShared::CheckState use_fast_gpu_time; 44 ConfigurationShared::CheckState use_fast_gpu_time;
45 ConfigurationShared::CheckState use_pessimistic_flushes;
46 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; 45 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache;
47 46
48 const Core::System& system; 47 const Core::System& system;
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index d7ec18939..1234f695c 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -127,16 +127,6 @@
127 </widget> 127 </widget>
128 </item> 128 </item>
129 <item> 129 <item>
130 <widget class="QCheckBox" name="use_pessimistic_flushes">
131 <property name="toolTip">
132 <string>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</string>
133 </property>
134 <property name="text">
135 <string>Use pessimistic buffer flushes (Hack)</string>
136 </property>
137 </widget>
138 </item>
139 <item>
140 <widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache"> 130 <widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache">
141 <property name="toolTip"> 131 <property name="toolTip">
142 <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</string> 132 <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</string>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 50b62293e..54f42e0c9 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -206,7 +206,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
206 } 206 }
207 if (param.Has("axis")) { 207 if (param.Has("axis")) {
208 const QString axis = QString::fromStdString(param.Get("axis", "")); 208 const QString axis = QString::fromStdString(param.Get("axis", ""));
209 return QObject::tr("%1%2Axis %3").arg(toggle, invert, axis); 209 return QObject::tr("%1%2%3Axis %4").arg(toggle, inverted, invert, axis);
210 } 210 }
211 if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) { 211 if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) {
212 const QString axis_x = QString::fromStdString(param.Get("axis_x", "")); 212 const QString axis_x = QString::fromStdString(param.Get("axis_x", ""));
@@ -229,7 +229,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
229 return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name); 229 return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name);
230 } 230 }
231 if (param.Has("axis")) { 231 if (param.Has("axis")) {
232 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); 232 return QObject::tr("%1%2%3Axis %4").arg(toggle, inverted, invert, button_name);
233 } 233 }
234 if (param.Has("motion")) { 234 if (param.Has("motion")) {
235 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); 235 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name);
@@ -410,6 +410,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
410 button_map[button_id]->setText(ButtonToText(param)); 410 button_map[button_id]->setText(ButtonToText(param));
411 emulated_controller->SetButtonParam(button_id, param); 411 emulated_controller->SetButtonParam(button_id, param);
412 }); 412 });
413 context_menu.addAction(tr("Invert button"), [&] {
414 const bool invert_value = !param.Get("inverted", false);
415 param.Set("inverted", invert_value);
416 button_map[button_id]->setText(ButtonToText(param));
417 emulated_controller->SetButtonParam(button_id, param);
418 });
413 context_menu.addAction(tr("Set threshold"), [&] { 419 context_menu.addAction(tr("Set threshold"), [&] {
414 const int button_threshold = 420 const int button_threshold =
415 static_cast<int>(param.Get("threshold", 0.5f) * 100.0f); 421 static_cast<int>(param.Get("threshold", 0.5f) * 100.0f);
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index c287220fc..fe1ee2289 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -180,6 +180,10 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ
180 battery_values = controller->GetBatteryValues(); 180 battery_values = controller->GetBatteryValues();
181 needs_redraw = true; 181 needs_redraw = true;
182 break; 182 break;
183 case Core::HID::ControllerTriggerType::Motion:
184 motion_values = controller->GetMotions();
185 needs_redraw = true;
186 break;
183 default: 187 default:
184 break; 188 break;
185 } 189 }
@@ -313,6 +317,15 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
313 DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0)); 317 DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0));
314 } 318 }
315 319
320 {
321 // Draw motion cubes
322 using namespace Settings::NativeMotion;
323 p.setPen(colors.outline);
324 p.setBrush(colors.transparent);
325 Draw3dCube(p, center + QPointF(-140, 90),
326 motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
327 }
328
316 using namespace Settings::NativeButton; 329 using namespace Settings::NativeButton;
317 330
318 // D-pad constants 331 // D-pad constants
@@ -435,6 +448,15 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
435 DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90)); 448 DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90));
436 } 449 }
437 450
451 {
452 // Draw motion cubes
453 using namespace Settings::NativeMotion;
454 p.setPen(colors.outline);
455 p.setBrush(colors.transparent);
456 Draw3dCube(p, center + QPointF(140, 90),
457 motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
458 }
459
438 using namespace Settings::NativeButton; 460 using namespace Settings::NativeButton;
439 461
440 // Face buttons constants 462 // Face buttons constants
@@ -555,6 +577,17 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
555 DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90)); 577 DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90));
556 } 578 }
557 579
580 {
581 // Draw motion cubes
582 using namespace Settings::NativeMotion;
583 p.setPen(colors.outline);
584 p.setBrush(colors.transparent);
585 Draw3dCube(p, center + QPointF(-180, -5),
586 motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
587 Draw3dCube(p, center + QPointF(180, -5),
588 motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
589 }
590
558 using namespace Settings::NativeButton; 591 using namespace Settings::NativeButton;
559 592
560 // Face buttons constants 593 // Face buttons constants
@@ -647,6 +680,15 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
647 DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0)); 680 DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0));
648 } 681 }
649 682
683 {
684 // Draw motion cubes
685 using namespace Settings::NativeMotion;
686 p.setPen(colors.outline);
687 p.setBrush(colors.transparent);
688 Draw3dCube(p, center + QPointF(0, -115),
689 motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f);
690 }
691
650 using namespace Settings::NativeButton; 692 using namespace Settings::NativeButton;
651 693
652 // Face buttons constants 694 // Face buttons constants
@@ -750,6 +792,15 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
750 DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105)); 792 DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105));
751 } 793 }
752 794
795 {
796 // Draw motion cubes
797 using namespace Settings::NativeMotion;
798 p.setPen(colors.button);
799 p.setBrush(colors.transparent);
800 Draw3dCube(p, center + QPointF(0, -100),
801 motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f);
802 }
803
753 using namespace Settings::NativeButton; 804 using namespace Settings::NativeButton;
754 805
755 // Face buttons constants 806 // Face buttons constants
@@ -2871,6 +2922,46 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di
2871 DrawPolygon(p, arrow_symbol); 2922 DrawPolygon(p, arrow_symbol);
2872} 2923}
2873 2924
2925// Draw motion functions
2926void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler,
2927 float size) {
2928 std::array<Common::Vec3f, 8> cube{
2929 Common::Vec3f{-1, -1, -1},
2930 {-1, 1, -1},
2931 {1, 1, -1},
2932 {1, -1, -1},
2933 {-1, -1, 1},
2934 {-1, 1, 1},
2935 {1, 1, 1},
2936 {1, -1, 1},
2937 };
2938
2939 for (Common::Vec3f& point : cube) {
2940 point.RotateFromOrigin(euler.x, euler.y, euler.z);
2941 point *= size;
2942 }
2943
2944 const std::array<QPointF, 4> front_face{
2945 center + QPointF{cube[0].x, cube[0].y},
2946 center + QPointF{cube[1].x, cube[1].y},
2947 center + QPointF{cube[2].x, cube[2].y},
2948 center + QPointF{cube[3].x, cube[3].y},
2949 };
2950 const std::array<QPointF, 4> back_face{
2951 center + QPointF{cube[4].x, cube[4].y},
2952 center + QPointF{cube[5].x, cube[5].y},
2953 center + QPointF{cube[6].x, cube[6].y},
2954 center + QPointF{cube[7].x, cube[7].y},
2955 };
2956
2957 DrawPolygon(p, front_face);
2958 DrawPolygon(p, back_face);
2959 p.drawLine(center + QPointF{cube[0].x, cube[0].y}, center + QPointF{cube[4].x, cube[4].y});
2960 p.drawLine(center + QPointF{cube[1].x, cube[1].y}, center + QPointF{cube[5].x, cube[5].y});
2961 p.drawLine(center + QPointF{cube[2].x, cube[2].y}, center + QPointF{cube[6].x, cube[6].y});
2962 p.drawLine(center + QPointF{cube[3].x, cube[3].y}, center + QPointF{cube[7].x, cube[7].y});
2963}
2964
2874template <size_t N> 2965template <size_t N>
2875void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) { 2966void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) {
2876 p.drawPolygon(polygon.data(), static_cast<int>(polygon.size())); 2967 p.drawPolygon(polygon.data(), static_cast<int>(polygon.size()));
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 267d134de..a16943c3c 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -9,6 +9,7 @@
9 9
10#include "common/input.h" 10#include "common/input.h"
11#include "common/settings_input.h" 11#include "common/settings_input.h"
12#include "common/vector_math.h"
12#include "core/hid/emulated_controller.h" 13#include "core/hid/emulated_controller.h"
13#include "core/hid/hid_types.h" 14#include "core/hid/hid_types.h"
14 15
@@ -193,6 +194,9 @@ private:
193 void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); 194 void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
194 void DrawArrow(QPainter& p, QPointF center, Direction direction, float size); 195 void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
195 196
197 // Draw motion functions
198 void Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler, float size);
199
196 // Draw primitive types 200 // Draw primitive types
197 template <size_t N> 201 template <size_t N>
198 void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon); 202 void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon);
@@ -222,4 +226,5 @@ private:
222 Core::HID::SticksValues stick_values{}; 226 Core::HID::SticksValues stick_values{};
223 Core::HID::TriggerValues trigger_values{}; 227 Core::HID::TriggerValues trigger_values{};
224 Core::HID::BatteryValues battery_values{}; 228 Core::HID::BatteryValues battery_values{};
229 Core::HID::MotionState motion_values{};
225}; 230};
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 6af34f793..286ccc5cd 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -111,6 +111,9 @@ void ConfigureSystem::SetConfiguration() {
111 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time)); 111 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time));
112 ui->device_name_edit->setText( 112 ui->device_name_edit->setText(
113 QString::fromUtf8(Settings::values.device_name.GetValue().c_str())); 113 QString::fromUtf8(Settings::values.device_name.GetValue().c_str()));
114 ui->use_unsafe_extended_memory_layout->setEnabled(enabled);
115 ui->use_unsafe_extended_memory_layout->setChecked(
116 Settings::values.use_unsafe_extended_memory_layout.GetValue());
114 117
115 if (Settings::IsConfiguringGlobal()) { 118 if (Settings::IsConfiguringGlobal()) {
116 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); 119 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
@@ -160,6 +163,9 @@ void ConfigureSystem::ApplyConfiguration() {
160 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region); 163 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
161 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index, 164 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
162 ui->combo_time_zone); 165 ui->combo_time_zone);
166 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_unsafe_extended_memory_layout,
167 ui->use_unsafe_extended_memory_layout,
168 use_unsafe_extended_memory_layout);
163 169
164 if (Settings::IsConfiguringGlobal()) { 170 if (Settings::IsConfiguringGlobal()) {
165 // Guard if during game and set to game-specific value 171 // Guard if during game and set to game-specific value
@@ -215,6 +221,10 @@ void ConfigureSystem::SetupPerGameUI() {
215 Settings::values.rng_seed.GetValue().has_value(), 221 Settings::values.rng_seed.GetValue().has_value(),
216 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed); 222 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
217 223
224 ConfigurationShared::SetColoredTristate(ui->use_unsafe_extended_memory_layout,
225 Settings::values.use_unsafe_extended_memory_layout,
226 use_unsafe_extended_memory_layout);
227
218 ui->custom_rtc_checkbox->setVisible(false); 228 ui->custom_rtc_checkbox->setVisible(false);
219 ui->custom_rtc_edit->setVisible(false); 229 ui->custom_rtc_edit->setVisible(false);
220} 230}
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index ec28724a1..ce1a91601 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -41,6 +41,7 @@ private:
41 bool enabled = false; 41 bool enabled = false;
42 42
43 ConfigurationShared::CheckState use_rng_seed; 43 ConfigurationShared::CheckState use_rng_seed;
44 ConfigurationShared::CheckState use_unsafe_extended_memory_layout;
44 45
45 Core::System& system; 46 Core::System& system;
46}; 47};
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 9e7bc3b93..e0caecd5e 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -478,6 +478,13 @@
478 </property> 478 </property>
479 </widget> 479 </widget>
480 </item> 480 </item>
481 <item row="7" column="0">
482 <widget class="QCheckBox" name="use_unsafe_extended_memory_layout">
483 <property name="text">
484 <string>Unsafe extended memory layout (8GB DRAM)</string>
485 </property>
486 </widget>
487 </item>
481 </layout> 488 </layout>
482 </item> 489 </item>
483 </layout> 490 </layout>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index a2f1d3d7e..352e6a4c7 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -264,7 +264,7 @@ void Config::ReadValues() {
264 264
265 // Core 265 // Core
266 ReadSetting("Core", Settings::values.use_multi_core); 266 ReadSetting("Core", Settings::values.use_multi_core);
267 ReadSetting("Core", Settings::values.use_extended_memory_layout); 267 ReadSetting("Core", Settings::values.use_unsafe_extended_memory_layout);
268 268
269 // Cpu 269 // Cpu
270 ReadSetting("Cpu", Settings::values.cpu_accuracy); 270 ReadSetting("Cpu", Settings::values.cpu_accuracy);
@@ -317,7 +317,6 @@ void Config::ReadValues() {
317 ReadSetting("Renderer", Settings::values.accelerate_astc); 317 ReadSetting("Renderer", Settings::values.accelerate_astc);
318 ReadSetting("Renderer", Settings::values.async_astc); 318 ReadSetting("Renderer", Settings::values.async_astc);
319 ReadSetting("Renderer", Settings::values.use_fast_gpu_time); 319 ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
320 ReadSetting("Renderer", Settings::values.use_pessimistic_flushes);
321 ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache); 320 ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache);
322 321
323 ReadSetting("Renderer", Settings::values.bg_red); 322 ReadSetting("Renderer", Settings::values.bg_red);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index c0c89fbb9..db6fba922 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -163,9 +163,9 @@ keyboard_enabled =
163# 0: Disabled, 1 (default): Enabled 163# 0: Disabled, 1 (default): Enabled
164use_multi_core = 164use_multi_core =
165 165
166# Enable extended guest system memory layout (8GB DRAM) 166# Enable unsafe extended guest system memory layout (8GB DRAM)
167# 0 (default): Disabled, 1: Enabled 167# 0 (default): Disabled, 1: Enabled
168use_extended_memory_layout = 168use_unsafe_extended_memory_layout =
169 169
170[Cpu] 170[Cpu]
171# Adjusts various optimizations. 171# Adjusts various optimizations.
@@ -374,10 +374,6 @@ use_asynchronous_gpu_emulation =
374# 0: Off, 1 (default): On 374# 0: Off, 1 (default): On
375use_fast_gpu_time = 375use_fast_gpu_time =
376 376
377# Force unmodified buffers to be flushed, which can cost performance.
378# 0: Off (default), 1: On
379use_pessimistic_flushes =
380
381# Whether to use garbage collection or not for GPU caches. 377# Whether to use garbage collection or not for GPU caches.
382# 0 (default): Off, 1: On 378# 0 (default): Off, 1: On
383use_caches_gc = 379use_caches_gc =