summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/renderer/performance/performance_manager.cpp1
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/atomic_helpers.h1
-rw-r--r--src/common/cache_management.cpp60
-rw-r--r--src/common/cache_management.h27
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp1
-rw-r--r--src/core/hid/emulated_console.cpp94
-rw-r--r--src/core/hid/emulated_console.h15
-rw-r--r--src/core/hid/input_converter.cpp3
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp1
-rw-r--r--src/core/hle/kernel/k_page_table.cpp3
-rw-r--r--src/core/hle/kernel/k_process.cpp1
-rw-r--r--src/core/hle/kernel/svc.cpp26
-rw-r--r--src/core/hle/kernel/svc_wrap.h8
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp1
-rw-r--r--src/core/hle/service/am/applets/applet_general_backend.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp32
-rw-r--r--src/core/hle/service/hid/hid.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp5
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp6
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.h5
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp14
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.h3
-rw-r--r--src/core/hle/service/service.cpp1
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp1
-rw-r--r--src/core/memory.cpp65
-rw-r--r--src/core/memory.h34
-rw-r--r--src/input_common/helpers/touch_from_buttons.cpp9
-rw-r--r--src/input_common/input_poller.cpp18
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.cpp1
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp3
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp3
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp5
-rw-r--r--src/video_core/engines/maxwell_3d.cpp6
-rw-r--r--src/video_core/engines/maxwell_3d.h6
-rw-r--r--src/video_core/engines/maxwell_dma.cpp1
-rw-r--r--src/video_core/engines/puller.cpp4
-rw-r--r--src/video_core/macro/macro_hle.cpp16
-rw-r--r--src/video_core/macro/macro_interpreter.cpp2
-rw-r--r--src/video_core/macro/macro_jit_x64.cpp1
-rw-r--r--src/video_core/rasterizer_interface.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp1
-rw-r--r--src/video_core/textures/decoders.cpp3
-rw-r--r--src/yuzu/compatdb.cpp1
-rw-r--r--src/yuzu/main.cpp3
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp1
-rw-r--r--src/yuzu_cmd/yuzu.cpp1
56 files changed, 432 insertions, 92 deletions
diff --git a/src/audio_core/renderer/performance/performance_manager.cpp b/src/audio_core/renderer/performance/performance_manager.cpp
index fd5873e1e..8aa0f5ed0 100644
--- a/src/audio_core/renderer/performance/performance_manager.cpp
+++ b/src/audio_core/renderer/performance/performance_manager.cpp
@@ -26,6 +26,7 @@ void PerformanceManager::CreateImpl(const size_t version) {
26 impl = std::make_unique< 26 impl = std::make_unique<
27 PerformanceManagerImpl<PerformanceVersion::Version1, PerformanceFrameHeaderVersion1, 27 PerformanceManagerImpl<PerformanceVersion::Version1, PerformanceFrameHeaderVersion1,
28 PerformanceEntryVersion1, PerformanceDetailVersion1>>(); 28 PerformanceEntryVersion1, PerformanceDetailVersion1>>();
29 break;
29 } 30 }
30} 31}
31 32
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index c0555f840..b7c15c191 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -34,6 +34,8 @@ add_library(common STATIC
34 bit_util.h 34 bit_util.h
35 cityhash.cpp 35 cityhash.cpp
36 cityhash.h 36 cityhash.h
37 cache_management.cpp
38 cache_management.h
37 common_funcs.h 39 common_funcs.h
38 common_types.h 40 common_types.h
39 concepts.h 41 concepts.h
diff --git a/src/common/atomic_helpers.h b/src/common/atomic_helpers.h
index bef5015c1..aef3b66a4 100644
--- a/src/common/atomic_helpers.h
+++ b/src/common/atomic_helpers.h
@@ -156,6 +156,7 @@ AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN {
156 break; 156 break;
157 default: 157 default:
158 assert(false); 158 assert(false);
159 break;
159 } 160 }
160} 161}
161 162
diff --git a/src/common/cache_management.cpp b/src/common/cache_management.cpp
new file mode 100644
index 000000000..57810b76a
--- /dev/null
+++ b/src/common/cache_management.cpp
@@ -0,0 +1,60 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cstring>
5
6#include "alignment.h"
7#include "cache_management.h"
8#include "common_types.h"
9
10namespace Common {
11
12#if defined(ARCHITECTURE_x86_64)
13
14// Most cache operations are no-ops on x86
15
16void DataCacheLineCleanByVAToPoU(void* start, size_t size) {}
17void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {}
18void DataCacheLineCleanByVAToPoC(void* start, size_t size) {}
19void DataCacheZeroByVA(void* start, size_t size) {
20 std::memset(start, 0, size);
21}
22
23#elif defined(ARCHITECTURE_arm64)
24
25// BS/DminLine is log2(cache size in words), we want size in bytes
26#define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2))
27#define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2))
28
29#define DEFINE_DC_OP(op_name, function_name) \
30 void function_name(void* start, size_t size) { \
31 size_t ctr_el0; \
32 asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0)); \
33 size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0); \
34 uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \
35 uintptr_t va_end = va_start + size; \
36 for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \
37 asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \
38 } \
39 }
40
41#define DEFINE_DC_OP_DCZID(op_name, function_name) \
42 void function_name(void* start, size_t size) { \
43 size_t dczid_el0; \
44 asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0)); \
45 size_t cacheline_size = EXTRACT_BS(dczid_el0); \
46 uintptr_t va_start = reinterpret_cast<uintptr_t>(start); \
47 uintptr_t va_end = va_start + size; \
48 for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \
49 asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \
50 } \
51 }
52
53DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU);
54DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC);
55DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC);
56DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA);
57
58#endif
59
60} // namespace Common
diff --git a/src/common/cache_management.h b/src/common/cache_management.h
new file mode 100644
index 000000000..e467b87e4
--- /dev/null
+++ b/src/common/cache_management.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "stdlib.h"
7
8namespace Common {
9
10// Data cache instructions enabled at EL0 by SCTLR_EL1.UCI.
11// VA = virtual address
12// PoC = point of coherency
13// PoU = point of unification
14
15// dc cvau
16void DataCacheLineCleanByVAToPoU(void* start, size_t size);
17
18// dc civac
19void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size);
20
21// dc cvac
22void DataCacheLineCleanByVAToPoC(void* start, size_t size);
23
24// dc zva
25void DataCacheZeroByVA(void* start, size_t size);
26
27} // namespace Common
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index afb7fb3a0..cb53d64ba 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -348,7 +348,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
348 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { 348 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
349 config.unsafe_optimizations = true; 349 config.unsafe_optimizations = true;
350 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 350 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
351 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
352 config.fastmem_address_space_bits = 64; 351 config.fastmem_address_space_bits = 64;
353 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; 352 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
354 } 353 }
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index aac45907d..fb7e5802a 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() {
19} 19}
20 20
21void EmulatedConsole::SetTouchParams() { 21void EmulatedConsole::SetTouchParams() {
22 // TODO(german77): Support any number of fingers
23 std::size_t index = 0; 22 std::size_t index = 0;
24 23
25 // Hardcode mouse, touchscreen and cemuhook parameters 24 // We can't use mouse as touch if native mouse is enabled
26 if (!Settings::values.mouse_enabled) { 25 if (!Settings::values.mouse_enabled) {
27 // We can't use mouse as touch if native mouse is enabled
28 touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; 26 touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
29 } 27 }
30 28
31 touch_params[index++] = 29 touch_params[index++] =
32 Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; 30 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
33 touch_params[index++] = 31 touch_params[index++] =
34 Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; 32 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
35 touch_params[index++] = 33
36 Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; 34 for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
37 touch_params[index++] = 35 Common::ParamPackage touchscreen_param{};
38 Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; 36 touchscreen_param.Set("engine", "touch");
39 touch_params[index++] = 37 touchscreen_param.Set("axis_x", i * 2);
40 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; 38 touchscreen_param.Set("axis_y", (i * 2) + 1);
41 touch_params[index++] = 39 touchscreen_param.Set("button", i);
42 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; 40 touch_params[index++] = touchscreen_param;
41 }
43 42
44 const auto button_index = 43 const auto button_index =
45 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); 44 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
@@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() {
47 46
48 // Map the rest of the fingers from touch from button configuration 47 // Map the rest of the fingers from touch from button configuration
49 for (const auto& config_entry : touch_buttons) { 48 for (const auto& config_entry : touch_buttons) {
50 if (index >= touch_params.size()) { 49 if (index >= MaxTouchDevices) {
51 continue; 50 continue;
52 } 51 }
53 Common::ParamPackage params{config_entry}; 52 Common::ParamPackage params{config_entry};
@@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() {
60 touch_button_params.Set("button", params.Serialize()); 59 touch_button_params.Set("button", params.Serialize());
61 touch_button_params.Set("x", x); 60 touch_button_params.Set("x", x);
62 touch_button_params.Set("y", y); 61 touch_button_params.Set("y", y);
63 touch_button_params.Set("touch_id", static_cast<int>(index));
64 touch_params[index] = touch_button_params; 62 touch_params[index] = touch_button_params;
65 index++; 63 index++;
66 } 64 }
@@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
178} 176}
179 177
180void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { 178void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
181 if (index >= console.touch_values.size()) { 179 if (index >= MaxTouchDevices) {
182 return; 180 return;
183 } 181 }
184 std::unique_lock lock{mutex}; 182 std::unique_lock lock{mutex};
185 183
186 console.touch_values[index] = TransformToTouch(callback); 184 const auto touch_input = TransformToTouch(callback);
185 auto touch_index = GetIndexFromFingerId(index);
186 bool is_new_input = false;
187
188 if (!touch_index.has_value() && touch_input.pressed.value) {
189 touch_index = GetNextFreeIndex();
190 is_new_input = true;
191 }
192
193 // No free entries or invalid state. Ignore input
194 if (!touch_index.has_value()) {
195 return;
196 }
197
198 auto& touch_value = console.touch_values[touch_index.value()];
199
200 if (is_new_input) {
201 touch_value.pressed.value = true;
202 touch_value.id = static_cast<u32>(index);
203 }
204
205 touch_value.x = touch_input.x;
206 touch_value.y = touch_input.y;
207
208 if (!touch_input.pressed.value) {
209 touch_value.pressed.value = false;
210 }
187 211
188 if (is_configuring) { 212 if (is_configuring) {
189 lock.unlock(); 213 lock.unlock();
@@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
191 return; 215 return;
192 } 216 }
193 217
194 // TODO(german77): Remap touch id in sequential order 218 // Touch outside allowed range. Ignore input
195 console.touch_state[index] = { 219 if (touch_index.value() >= MaxActiveTouchInputs) {
196 .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, 220 return;
197 .id = static_cast<u32>(console.touch_values[index].id), 221 }
198 .pressed = console.touch_values[index].pressed.value, 222
223 console.touch_state[touch_index.value()] = {
224 .position = {touch_value.x.value, touch_value.y.value},
225 .id = static_cast<u32>(touch_index.value()),
226 .pressed = touch_input.pressed.value,
199 }; 227 };
200 228
201 lock.unlock(); 229 lock.unlock();
@@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const {
222 return console.touch_state; 250 return console.touch_state;
223} 251}
224 252
253std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const {
254 for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
255 const auto& finger = console.touch_values[index];
256 if (!finger.pressed.value) {
257 continue;
258 }
259 if (finger.id == static_cast<int>(finger_id)) {
260 return index;
261 }
262 }
263 return std::nullopt;
264}
265
266std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const {
267 for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
268 if (!console.touch_values[index].pressed.value) {
269 return index;
270 }
271 }
272 return std::nullopt;
273}
274
225void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { 275void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
226 std::scoped_lock lock{callback_mutex}; 276 std::scoped_lock lock{callback_mutex};
227 for (const auto& poller_pair : callback_list) { 277 for (const auto& poller_pair : callback_list) {
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index 1c510cd19..697ecd2d6 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -7,6 +7,7 @@
7#include <functional> 7#include <functional>
8#include <memory> 8#include <memory>
9#include <mutex> 9#include <mutex>
10#include <optional>
10#include <unordered_map> 11#include <unordered_map>
11 12
12#include "common/common_funcs.h" 13#include "common/common_funcs.h"
@@ -20,6 +21,8 @@
20#include "core/hid/motion_input.h" 21#include "core/hid/motion_input.h"
21 22
22namespace Core::HID { 23namespace Core::HID {
24static constexpr std::size_t MaxTouchDevices = 32;
25static constexpr std::size_t MaxActiveTouchInputs = 16;
23 26
24struct ConsoleMotionInfo { 27struct ConsoleMotionInfo {
25 Common::Input::MotionStatus raw_status{}; 28 Common::Input::MotionStatus raw_status{};
@@ -27,13 +30,13 @@ struct ConsoleMotionInfo {
27}; 30};
28 31
29using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>; 32using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>;
30using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 16>; 33using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
31 34
32using ConsoleMotionParams = Common::ParamPackage; 35using ConsoleMotionParams = Common::ParamPackage;
33using TouchParams = std::array<Common::ParamPackage, 16>; 36using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
34 37
35using ConsoleMotionValues = ConsoleMotionInfo; 38using ConsoleMotionValues = ConsoleMotionInfo;
36using TouchValues = std::array<Common::Input::TouchStatus, 16>; 39using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
37 40
38struct TouchFinger { 41struct TouchFinger {
39 u64 last_touch{}; 42 u64 last_touch{};
@@ -55,7 +58,7 @@ struct ConsoleMotion {
55 bool is_at_rest{}; 58 bool is_at_rest{};
56}; 59};
57 60
58using TouchFingerState = std::array<TouchFinger, 16>; 61using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;
59 62
60struct ConsoleStatus { 63struct ConsoleStatus {
61 // Data from input_common 64 // Data from input_common
@@ -166,6 +169,10 @@ private:
166 */ 169 */
167 void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); 170 void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
168 171
172 std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
173
174 std::optional<std::size_t> GetNextFreeIndex() const;
175
169 /** 176 /**
170 * Triggers a callback that something has changed on the console status 177 * Triggers a callback that something has changed on the console status
171 * @param type Input type of the event to trigger 178 * @param type Input type of the event to trigger
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 5d8b75b50..502692875 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus&
200 x = std::clamp(x, 0.0f, 1.0f); 200 x = std::clamp(x, 0.0f, 1.0f);
201 y = std::clamp(y, 0.0f, 1.0f); 201 y = std::clamp(y, 0.0f, 1.0f);
202 202
203 // Limit id to maximum number of fingers
204 status.id = std::clamp(status.id, 0, 16);
205
206 if (status.pressed.inverted) { 203 if (status.pressed.inverted) {
207 status.pressed.value = !status.pressed.value; 204 status.pressed.value = !status.pressed.value;
208 } 205 }
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index bda098511..7b363eb1e 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -243,6 +243,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
243 // If we somehow get an invalid type, abort. 243 // If we somehow get an invalid type, abort.
244 default: 244 default:
245 ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); 245 ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]);
246 break;
246 } 247 }
247 248
248 // If we've hit the end of a gap, free it. 249 // If we've hit the end of a gap, free it.
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 5387bf5fe..612fc76fa 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -2301,6 +2301,7 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size,
2301 break; 2301 break;
2302 default: 2302 default:
2303 ASSERT(false); 2303 ASSERT(false);
2304 break;
2304 } 2305 }
2305 } 2306 }
2306 2307
@@ -2803,6 +2804,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_
2803 break; 2804 break;
2804 default: 2805 default:
2805 ASSERT(false); 2806 ASSERT(false);
2807 break;
2806 } 2808 }
2807 2809
2808 addr += size; 2810 addr += size;
@@ -2838,6 +2840,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm,
2838 break; 2840 break;
2839 default: 2841 default:
2840 ASSERT(false); 2842 ASSERT(false);
2843 break;
2841 } 2844 }
2842 R_SUCCEED(); 2845 R_SUCCEED();
2843} 2846}
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 55a9c5fae..d1dc62401 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -395,6 +395,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
395 395
396 default: 396 default:
397 ASSERT(false); 397 ASSERT(false);
398 break;
398 } 399 }
399 400
400 // Create TLS region 401 // Create TLS region
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 9962ad171..e520cab47 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2701,14 +2701,24 @@ static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr ou
2701 return ResultSuccess; 2701 return ResultSuccess;
2702} 2702}
2703 2703
2704static Result FlushProcessDataCache32([[maybe_unused]] Core::System& system, 2704static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address,
2705 [[maybe_unused]] Handle handle, [[maybe_unused]] u32 address, 2705 u64 size) {
2706 [[maybe_unused]] u32 size) { 2706 // Validate address/size.
2707 // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, 2707 R_UNLESS(size > 0, ResultInvalidSize);
2708 // as all emulation is done in the same cache level in host architecture, thus data cache 2708 R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
2709 // does not need flushing. 2709 R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
2710 LOG_DEBUG(Kernel_SVC, "called"); 2710
2711 return ResultSuccess; 2711 // Get the process from its handle.
2712 KScopedAutoObject process =
2713 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle);
2714 R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
2715
2716 // Verify the region is within range.
2717 auto& page_table = process->PageTable();
2718 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
2719
2720 // Perform the operation.
2721 R_RETURN(system.Memory().FlushDataCache(*process, address, size));
2712} 2722}
2713 2723
2714namespace { 2724namespace {
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 272c54cf7..3730937fe 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -722,4 +722,12 @@ void SvcWrap32(Core::System& system) {
722 FuncReturn(system, retval); 722 FuncReturn(system, retval);
723} 723}
724 724
725// Used by Invalidate/Store/FlushProcessDataCache32
726template <Result func(Core::System&, Handle, u64, u64)>
727void SvcWrap32(Core::System& system) {
728 const u64 address = (Param(system, 3) << 32) | Param(system, 2);
729 const u64 size = (Param(system, 4) << 32) | Param(system, 1);
730 FuncReturn32(system, func(system, Param32(system, 0), address, size).raw);
731}
732
725} // namespace Kernel 733} // namespace Kernel
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp
index fcf34bf7e..bae0d99a6 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -144,6 +144,7 @@ void Error::Initialize() {
144 break; 144 break;
145 default: 145 default:
146 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); 146 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode);
147 break;
147 } 148 }
148} 149}
149 150
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp
index c34ef08b3..e50acdaf6 100644
--- a/src/core/hle/service/am/applets/applet_general_backend.cpp
+++ b/src/core/hle/service/am/applets/applet_general_backend.cpp
@@ -129,6 +129,7 @@ void Auth::Execute() {
129 } 129 }
130 default: 130 default:
131 unimplemented_log(); 131 unimplemented_log();
132 break;
132 } 133 }
133} 134}
134 135
@@ -192,6 +193,7 @@ void PhotoViewer::Execute() {
192 break; 193 break;
193 default: 194 default:
194 UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); 195 UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode);
196 break;
195 } 197 }
196} 198}
197 199
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 79375bd2f..bf28440c6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -36,8 +36,9 @@ namespace Service::HID {
36 36
37// Updating period for each HID device. 37// Updating period for each HID device.
38// Period time is obtained by measuring the number of samples in a second on HW using a homebrew 38// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
39// Correct pad_update_ns is 4ms this is overclocked to lower input lag 39// Correct npad_update_ns is 4ms this is overclocked to lower input lag
40constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) 40constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
41constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
41constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) 42constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
42constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) 43constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
43 44
@@ -75,11 +76,19 @@ IAppletResource::IAppletResource(Core::System& system_,
75 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); 76 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
76 77
77 // Register update callbacks 78 // Register update callbacks
78 pad_update_event = Core::Timing::CreateEvent( 79 npad_update_event = Core::Timing::CreateEvent(
79 "HID::UpdatePadCallback", 80 "HID::UpdatePadCallback",
80 [this](std::uintptr_t user_data, s64 time, 81 [this](std::uintptr_t user_data, s64 time,
81 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { 82 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
82 const auto guard = LockService(); 83 const auto guard = LockService();
84 UpdateNpad(user_data, ns_late);
85 return std::nullopt;
86 });
87 default_update_event = Core::Timing::CreateEvent(
88 "HID::UpdateDefaultCallback",
89 [this](std::uintptr_t user_data, s64 time,
90 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
91 const auto guard = LockService();
83 UpdateControllers(user_data, ns_late); 92 UpdateControllers(user_data, ns_late);
84 return std::nullopt; 93 return std::nullopt;
85 }); 94 });
@@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_,
100 return std::nullopt; 109 return std::nullopt;
101 }); 110 });
102 111
103 system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); 112 system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
113 system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
114 default_update_event);
104 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, 115 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
105 mouse_keyboard_update_event); 116 mouse_keyboard_update_event);
106 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, 117 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
@@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) {
118} 129}
119 130
120IAppletResource::~IAppletResource() { 131IAppletResource::~IAppletResource() {
121 system.CoreTiming().UnscheduleEvent(pad_update_event, 0); 132 system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
133 system.CoreTiming().UnscheduleEvent(default_update_event, 0);
122 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); 134 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
123 system.CoreTiming().UnscheduleEvent(motion_update_event, 0); 135 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
124} 136}
@@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
144 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { 156 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
145 continue; 157 continue;
146 } 158 }
159 // Npad has it's own update event
160 if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
161 continue;
162 }
147 controller->OnUpdate(core_timing); 163 controller->OnUpdate(core_timing);
148 } 164 }
149} 165}
150 166
167void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
168 auto& core_timing = system.CoreTiming();
169
170 controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
171}
172
151void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, 173void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
152 std::chrono::nanoseconds ns_late) { 174 std::chrono::nanoseconds ns_late) {
153 auto& core_timing = system.CoreTiming(); 175 auto& core_timing = system.CoreTiming();
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 340d26fdc..b7c2a23ef 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -71,12 +71,14 @@ private:
71 71
72 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 72 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
73 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 73 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
74 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
74 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 75 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
75 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 76 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
76 77
77 KernelHelpers::ServiceContext& service_context; 78 KernelHelpers::ServiceContext& service_context;
78 79
79 std::shared_ptr<Core::Timing::EventType> pad_update_event; 80 std::shared_ptr<Core::Timing::EventType> npad_update_event;
81 std::shared_ptr<Core::Timing::EventType> default_update_event;
80 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; 82 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
81 std::shared_ptr<Core::Timing::EventType> motion_update_event; 83 std::shared_ptr<Core::Timing::EventType> motion_update_event;
82 84
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index ced57dfe6..b97813fbc 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) {
300 return error_notifier_event; 300 return error_notifier_event;
301 case 2: 301 case 2:
302 return unknown_event; 302 return unknown_event;
303 default: { 303 default:
304 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); 304 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
305 return nullptr;
305 } 306 }
306 }
307 return nullptr;
308} 307}
309 308
310} // namespace Service::Nvidia::Devices 309} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 45a759fa8..e123564c6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) {
364 return sm_exception_breakpoint_pause_report_event; 364 return sm_exception_breakpoint_pause_report_event;
365 case 3: 365 case 3:
366 return error_notifier_event; 366 return error_notifier_event;
367 default: { 367 default:
368 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); 368 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
369 return nullptr;
369 } 370 }
370 }
371 return nullptr;
372} 371}
373 372
374} // namespace Service::Nvidia::Devices 373} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
index ea4a14ea4..3d1338e66 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
@@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() {
23} 23}
24 24
25void BufferQueueCore::SignalDequeueCondition() { 25void BufferQueueCore::SignalDequeueCondition() {
26 dequeue_possible.store(true);
26 dequeue_condition.notify_all(); 27 dequeue_condition.notify_all();
27} 28}
28 29
29bool BufferQueueCore::WaitForDequeueCondition() { 30bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
30 if (is_shutting_down) { 31 if (is_shutting_down) {
31 return false; 32 return false;
32 } 33 }
33 34
34 dequeue_condition.wait(mutex); 35 dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
36 dequeue_possible.store(false);
35 37
36 return true; 38 return true;
37} 39}
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h
index ca6baefaf..85b3bc4c1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.h
@@ -38,7 +38,7 @@ public:
38 38
39private: 39private:
40 void SignalDequeueCondition(); 40 void SignalDequeueCondition();
41 bool WaitForDequeueCondition(); 41 bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
42 42
43 s32 GetMinUndequeuedBufferCountLocked(bool async) const; 43 s32 GetMinUndequeuedBufferCountLocked(bool async) const;
44 s32 GetMinMaxBufferCountLocked(bool async) const; 44 s32 GetMinMaxBufferCountLocked(bool async) const;
@@ -60,7 +60,8 @@ private:
60 BufferQueueDefs::SlotsType slots{}; 60 BufferQueueDefs::SlotsType slots{};
61 std::vector<BufferItem> queue; 61 std::vector<BufferItem> queue;
62 s32 override_max_buffer_count{}; 62 s32 override_max_buffer_count{};
63 mutable std::condition_variable_any dequeue_condition; 63 std::condition_variable dequeue_condition;
64 std::atomic<bool> dequeue_possible{};
64 const bool use_async_buffer{}; // This is always disabled on HOS 65 const bool use_async_buffer{}; // This is always disabled on HOS
65 bool dequeue_buffer_cannot_block{}; 66 bool dequeue_buffer_cannot_block{};
66 PixelFormat default_buffer_format{PixelFormat::Rgba8888}; 67 PixelFormat default_buffer_format{PixelFormat::Rgba8888};
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
index 41ba44b21..e601b5da1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
121 return Status::NoError; 121 return Status::NoError;
122} 122}
123 123
124Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, 124Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags,
125 Status* return_flags) const { 125 std::unique_lock<std::mutex>& lk) const {
126 bool try_again = true; 126 bool try_again = true;
127 127
128 while (try_again) { 128 while (try_again) {
@@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
214 return Status::WouldBlock; 214 return Status::WouldBlock;
215 } 215 }
216 216
217 if (!core->WaitForDequeueCondition()) { 217 if (!core->WaitForDequeueCondition(lk)) {
218 // We are no longer running 218 // We are no longer running
219 return Status::NoError; 219 return Status::NoError;
220 } 220 }
@@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
237 Status return_flags = Status::NoError; 237 Status return_flags = Status::NoError;
238 bool attached_by_consumer = false; 238 bool attached_by_consumer = false;
239 { 239 {
240 std::scoped_lock lock{core->mutex}; 240 std::unique_lock lock{core->mutex};
241 core->WaitWhileAllocatingLocked(); 241 core->WaitWhileAllocatingLocked();
242 242
243 if (format == PixelFormat::NoFormat) { 243 if (format == PixelFormat::NoFormat) {
@@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
248 usage |= core->consumer_usage_bit; 248 usage |= core->consumer_usage_bit;
249 249
250 s32 found{}; 250 s32 found{};
251 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); 251 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock);
252 if (status != Status::NoError) { 252 if (status != Status::NoError) {
253 return status; 253 return status;
254 } 254 }
@@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
400 return Status::BadValue; 400 return Status::BadValue;
401 } 401 }
402 402
403 std::scoped_lock lock{core->mutex}; 403 std::unique_lock lock{core->mutex};
404 core->WaitWhileAllocatingLocked(); 404 core->WaitWhileAllocatingLocked();
405 405
406 Status return_flags = Status::NoError; 406 Status return_flags = Status::NoError;
407 s32 found{}; 407 s32 found{};
408 408
409 const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); 409 const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock);
410 if (status != Status::NoError) { 410 if (status != Status::NoError) {
411 return status; 411 return status;
412 } 412 }
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h
index 7526bf8ec..1d380480f 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h
@@ -70,7 +70,8 @@ public:
70private: 70private:
71 BufferQueueProducer(const BufferQueueProducer&) = delete; 71 BufferQueueProducer(const BufferQueueProducer&) = delete;
72 72
73 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const; 73 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags,
74 std::unique_lock<std::mutex>& lk) const;
74 75
75 Kernel::KEvent* buffer_wait_event{}; 76 Kernel::KEvent* buffer_wait_event{};
76 Service::KernelHelpers::ServiceContext& service_context; 77 Service::KernelHelpers::ServiceContext& service_context;
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 5ab41c0c4..0de67f1e1 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
228 } 228 }
229 229
230 UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); 230 UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType());
231 break;
231 } 232 }
232 233
233 // If emulation was shutdown, we are closing service threads, do not write the response back to 234 // If emulation was shutdown, we are closing service threads, do not write the response back to
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index 2aa675df9..f9ada7c93 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) {
280 } 280 }
281 default: 281 default:
282 ASSERT(false); 282 ASSERT(false);
283 break;
283 } 284 }
284 return value + rule.transition_time + offset; 285 return value + rule.transition_time + offset;
285} 286}
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 3ca80c8ff..3141122f1 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -6,6 +6,7 @@
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/atomic_ops.h" 8#include "common/atomic_ops.h"
9#include "common/cache_management.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "common/page_table.h" 12#include "common/page_table.h"
@@ -329,6 +330,55 @@ struct Memory::Impl {
329 }); 330 });
330 } 331 }
331 332
333 template <typename Callback>
334 Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size,
335 Callback&& cb) {
336 class InvalidMemoryException : public std::exception {};
337
338 try {
339 WalkBlock(
340 process, dest_addr, size,
341 [&](const std::size_t block_size, const VAddr current_vaddr) {
342 LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr);
343 throw InvalidMemoryException();
344 },
345 [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); },
346 [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) {
347 system.GPU().FlushRegion(current_vaddr, block_size);
348 cb(block_size, host_ptr);
349 },
350 [](const std::size_t block_size) {});
351 } catch (InvalidMemoryException&) {
352 return Kernel::ResultInvalidCurrentMemory;
353 }
354
355 return ResultSuccess;
356 }
357
358 Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
359 auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
360 // Do nothing; this operation (dc ivac) cannot be supported
361 // from EL0
362 };
363 return PerformCacheOperation(process, dest_addr, size, perform);
364 }
365
366 Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
367 auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
368 // dc cvac: Store to point of coherency
369 Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size);
370 };
371 return PerformCacheOperation(process, dest_addr, size, perform);
372 }
373
374 Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
375 auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
376 // dc civac: Store to point of coherency, and invalidate from cache
377 Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size);
378 };
379 return PerformCacheOperation(process, dest_addr, size, perform);
380 }
381
332 void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { 382 void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) {
333 if (vaddr == 0) { 383 if (vaddr == 0) {
334 return; 384 return;
@@ -786,6 +836,21 @@ void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const s
786 impl->ZeroBlock(process, dest_addr, size); 836 impl->ZeroBlock(process, dest_addr, size);
787} 837}
788 838
839Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr,
840 const std::size_t size) {
841 return impl->InvalidateDataCache(process, dest_addr, size);
842}
843
844Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr,
845 const std::size_t size) {
846 return impl->StoreDataCache(process, dest_addr, size);
847}
848
849Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr,
850 const std::size_t size) {
851 return impl->FlushDataCache(process, dest_addr, size);
852}
853
789void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { 854void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
790 impl->RasterizerMarkRegionCached(vaddr, size, cached); 855 impl->RasterizerMarkRegionCached(vaddr, size, cached);
791} 856}
diff --git a/src/core/memory.h b/src/core/memory.h
index 81eac448b..31fe699d8 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -7,6 +7,7 @@
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/result.h"
10 11
11namespace Common { 12namespace Common {
12struct PageTable; 13struct PageTable;
@@ -450,6 +451,39 @@ public:
450 void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); 451 void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
451 452
452 /** 453 /**
454 * Invalidates a range of bytes within the current process' address space at the specified
455 * virtual address.
456 *
457 * @param process The process that will have data invalidated within its address space.
458 * @param dest_addr The destination virtual address to invalidate the data from.
459 * @param size The size of the range to invalidate, in bytes.
460 *
461 */
462 Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
463
464 /**
465 * Stores a range of bytes within the current process' address space at the specified
466 * virtual address.
467 *
468 * @param process The process that will have data stored within its address space.
469 * @param dest_addr The destination virtual address to store the data from.
470 * @param size The size of the range to store, in bytes.
471 *
472 */
473 Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
474
475 /**
476 * Flushes a range of bytes within the current process' address space at the specified
477 * virtual address.
478 *
479 * @param process The process that will have data flushed within its address space.
480 * @param dest_addr The destination virtual address to flush the data from.
481 * @param size The size of the range to flush, in bytes.
482 *
483 */
484 Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
485
486 /**
453 * Marks each page within the specified address range as cached or uncached. 487 * Marks each page within the specified address range as cached or uncached.
454 * 488 *
455 * @param vaddr The virtual address indicating the start of the address range. 489 * @param vaddr The virtual address indicating the start of the address range.
diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp
index da4a3dca5..003a38da5 100644
--- a/src/input_common/helpers/touch_from_buttons.cpp
+++ b/src/input_common/helpers/touch_from_buttons.cpp
@@ -10,8 +10,8 @@ namespace InputCommon {
10class TouchFromButtonDevice final : public Common::Input::InputDevice { 10class TouchFromButtonDevice final : public Common::Input::InputDevice {
11public: 11public:
12 using Button = std::unique_ptr<Common::Input::InputDevice>; 12 using Button = std::unique_ptr<Common::Input::InputDevice>;
13 TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) 13 TouchFromButtonDevice(Button button_, float x_, float y_)
14 : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { 14 : button(std::move(button_)), x(x_), y(y_) {
15 last_button_value = false; 15 last_button_value = false;
16 button->SetCallback({ 16 button->SetCallback({
17 .on_change = 17 .on_change =
@@ -34,7 +34,6 @@ public:
34 .pressed = button_status, 34 .pressed = button_status,
35 .x = {}, 35 .x = {},
36 .y = {}, 36 .y = {},
37 .id = touch_id,
38 }; 37 };
39 status.x.properties = properties; 38 status.x.properties = properties;
40 status.y.properties = properties; 39 status.y.properties = properties;
@@ -62,7 +61,6 @@ public:
62private: 61private:
63 Button button; 62 Button button;
64 bool last_button_value; 63 bool last_button_value;
65 const int touch_id;
66 const float x; 64 const float x;
67 const float y; 65 const float y;
68 const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; 66 const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
@@ -73,10 +71,9 @@ std::unique_ptr<Common::Input::InputDevice> TouchFromButton::Create(
73 const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); 71 const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize();
74 auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( 72 auto button = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
75 params.Get("button", null_engine)); 73 params.Get("button", null_engine));
76 const auto touch_id = params.Get("touch_id", 0);
77 const float x = params.Get("x", 0.0f) / 1280.0f; 74 const float x = params.Get("x", 0.0f) / 1280.0f;
78 const float y = params.Get("y", 0.0f) / 720.0f; 75 const float y = params.Get("y", 0.0f) / 720.0f;
79 return std::make_unique<TouchFromButtonDevice>(std::move(button), touch_id, x, y); 76 return std::make_unique<TouchFromButtonDevice>(std::move(button), x, y);
80} 77}
81 78
82} // namespace InputCommon 79} // namespace InputCommon
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 4ac182147..fb8be42e2 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -229,13 +229,12 @@ private:
229 229
230class InputFromTouch final : public Common::Input::InputDevice { 230class InputFromTouch final : public Common::Input::InputDevice {
231public: 231public:
232 explicit InputFromTouch(PadIdentifier identifier_, int touch_id_, int button_, bool toggle_, 232 explicit InputFromTouch(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_,
233 bool inverted_, int axis_x_, int axis_y_, 233 int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_,
234 Common::Input::AnalogProperties properties_x_,
235 Common::Input::AnalogProperties properties_y_, 234 Common::Input::AnalogProperties properties_y_,
236 InputEngine* input_engine_) 235 InputEngine* input_engine_)
237 : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_), 236 : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_),
238 inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), 237 axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_),
239 properties_y(properties_y_), input_engine(input_engine_) { 238 properties_y(properties_y_), input_engine(input_engine_) {
240 UpdateCallback engine_callback{[this]() { OnChange(); }}; 239 UpdateCallback engine_callback{[this]() { OnChange(); }};
241 const InputIdentifier button_input_identifier{ 240 const InputIdentifier button_input_identifier{
@@ -271,8 +270,7 @@ public:
271 } 270 }
272 271
273 Common::Input::TouchStatus GetStatus() const { 272 Common::Input::TouchStatus GetStatus() const {
274 Common::Input::TouchStatus status; 273 Common::Input::TouchStatus status{};
275 status.id = touch_id;
276 status.pressed = { 274 status.pressed = {
277 .value = input_engine->GetButton(identifier, button), 275 .value = input_engine->GetButton(identifier, button),
278 .inverted = inverted, 276 .inverted = inverted,
@@ -307,7 +305,6 @@ public:
307 305
308private: 306private:
309 const PadIdentifier identifier; 307 const PadIdentifier identifier;
310 const int touch_id;
311 const int button; 308 const int button;
312 const bool toggle; 309 const bool toggle;
313 const bool inverted; 310 const bool inverted;
@@ -919,7 +916,6 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice(
919 916
920std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice( 917std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(
921 const Common::ParamPackage& params) { 918 const Common::ParamPackage& params) {
922 const auto touch_id = params.Get("touch_id", 0);
923 const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); 919 const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
924 const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); 920 const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f);
925 const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); 921 const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f);
@@ -954,8 +950,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice(
954 input_engine->PreSetAxis(identifier, axis_x); 950 input_engine->PreSetAxis(identifier, axis_x);
955 input_engine->PreSetAxis(identifier, axis_y); 951 input_engine->PreSetAxis(identifier, axis_y);
956 input_engine->PreSetButton(identifier, button); 952 input_engine->PreSetButton(identifier, button);
957 return std::make_unique<InputFromTouch>(identifier, touch_id, button, toggle, inverted, axis_x, 953 return std::make_unique<InputFromTouch>(identifier, button, toggle, inverted, axis_x, axis_y,
958 axis_y, properties_x, properties_y, input_engine.get()); 954 properties_x, properties_y, input_engine.get());
959} 955}
960 956
961std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice( 957std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateBatteryDevice(
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index 3b0176bf6..0cb1e193e 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -320,6 +320,7 @@ void SetupOptions(const IR::Program& program, const Profile& profile,
320 } 320 }
321 if (stage == Stage::Fragment) { 321 if (stage == Stage::Fragment) {
322 header += "OPTION ARB_draw_buffers;"; 322 header += "OPTION ARB_draw_buffers;";
323 header += "OPTION ARB_fragment_layer_viewport;";
323 } 324 }
324} 325}
325 326
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
index d6562c842..f0bd84ab2 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp
@@ -104,6 +104,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
104 case IR::Attribute::PrimitiveId: 104 case IR::Attribute::PrimitiveId:
105 ctx.Add("MOV.F {}.x,primitive.id;", inst); 105 ctx.Add("MOV.F {}.x,primitive.id;", inst);
106 break; 106 break;
107 case IR::Attribute::Layer:
108 ctx.Add("MOV.F {}.x,fragment.layer;", inst);
109 break;
107 case IR::Attribute::PositionX: 110 case IR::Attribute::PositionX:
108 case IR::Attribute::PositionY: 111 case IR::Attribute::PositionY:
109 case IR::Attribute::PositionZ: 112 case IR::Attribute::PositionZ:
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
index c1671c37b..39579cf5d 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
@@ -205,6 +205,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
205 case IR::Attribute::PrimitiveId: 205 case IR::Attribute::PrimitiveId:
206 ctx.AddF32("{}=itof(gl_PrimitiveID);", inst); 206 ctx.AddF32("{}=itof(gl_PrimitiveID);", inst);
207 break; 207 break;
208 case IR::Attribute::Layer:
209 ctx.AddF32("{}=itof(gl_Layer);", inst);
210 break;
208 case IR::Attribute::PositionX: 211 case IR::Attribute::PositionX:
209 case IR::Attribute::PositionY: 212 case IR::Attribute::PositionY:
210 case IR::Attribute::PositionZ: 213 case IR::Attribute::PositionZ:
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 5b3b5d1f3..01f6ec9b5 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -315,6 +315,8 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
315 switch (attr) { 315 switch (attr) {
316 case IR::Attribute::PrimitiveId: 316 case IR::Attribute::PrimitiveId:
317 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id)); 317 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id));
318 case IR::Attribute::Layer:
319 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.layer));
318 case IR::Attribute::PositionX: 320 case IR::Attribute::PositionX:
319 case IR::Attribute::PositionY: 321 case IR::Attribute::PositionY:
320 case IR::Attribute::PositionZ: 322 case IR::Attribute::PositionZ:
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 0bfc2dd89..8e3e40cd5 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -1359,6 +1359,11 @@ void EmitContext::DefineInputs(const IR::Program& program) {
1359 if (loads[IR::Attribute::PrimitiveId]) { 1359 if (loads[IR::Attribute::PrimitiveId]) {
1360 primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId); 1360 primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId);
1361 } 1361 }
1362 if (loads[IR::Attribute::Layer]) {
1363 AddCapability(spv::Capability::Geometry);
1364 layer = DefineInput(*this, U32[1], false, spv::BuiltIn::Layer);
1365 Decorate(layer, spv::Decoration::Flat);
1366 }
1362 if (loads.AnyComponent(IR::Attribute::PositionX)) { 1367 if (loads.AnyComponent(IR::Attribute::PositionX)) {
1363 const bool is_fragment{stage != Stage::Fragment}; 1368 const bool is_fragment{stage != Stage::Fragment};
1364 const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; 1369 const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord};
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index d502d181c..5bb1427c1 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -232,7 +232,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
232 use_topology_override = true; 232 use_topology_override = true;
233 return; 233 return;
234 case MAXWELL3D_REG_INDEX(clear_surface): 234 case MAXWELL3D_REG_INDEX(clear_surface):
235 return ProcessClearBuffers(); 235 return ProcessClearBuffers(1);
236 case MAXWELL3D_REG_INDEX(report_semaphore.query): 236 case MAXWELL3D_REG_INDEX(report_semaphore.query):
237 return ProcessQueryGet(); 237 return ProcessQueryGet();
238 case MAXWELL3D_REG_INDEX(render_enable.mode): 238 case MAXWELL3D_REG_INDEX(render_enable.mode):
@@ -596,8 +596,8 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {
596 return regs.reg_array[method]; 596 return regs.reg_array[method];
597} 597}
598 598
599void Maxwell3D::ProcessClearBuffers() { 599void Maxwell3D::ProcessClearBuffers(u32 layer_count) {
600 rasterizer->Clear(); 600 rasterizer->Clear(layer_count);
601} 601}
602 602
603void Maxwell3D::ProcessDraw(u32 instance_count) { 603void Maxwell3D::ProcessDraw(u32 instance_count) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 34b085388..c3099f9a6 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -3086,6 +3086,9 @@ public:
3086 3086
3087 std::vector<u8> inline_index_draw_indexes; 3087 std::vector<u8> inline_index_draw_indexes;
3088 3088
3089 /// Handles a write to the CLEAR_BUFFERS register.
3090 void ProcessClearBuffers(u32 layer_count);
3091
3089private: 3092private:
3090 void InitializeRegisterDefaults(); 3093 void InitializeRegisterDefaults();
3091 3094
@@ -3120,9 +3123,6 @@ private:
3120 /// Handles firmware blob 4 3123 /// Handles firmware blob 4
3121 void ProcessFirmwareCall4(); 3124 void ProcessFirmwareCall4();
3122 3125
3123 /// Handles a write to the CLEAR_BUFFERS register.
3124 void ProcessClearBuffers();
3125
3126 /// Handles a write to the QUERY_GET register. 3126 /// Handles a write to the QUERY_GET register.
3127 void ProcessQueryGet(); 3127 void ProcessQueryGet();
3128 3128
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 54523a4b2..1bf6ca2dd 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -314,6 +314,7 @@ void MaxwellDMA::ReleaseSemaphore() {
314 } 314 }
315 default: 315 default:
316 ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast<u32>(type.Value())); 316 ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast<u32>(type.Value()));
317 break;
317 } 318 }
318} 319}
319 320
diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp
index 3977bb0fb..4d2278811 100644
--- a/src/video_core/engines/puller.cpp
+++ b/src/video_core/engines/puller.cpp
@@ -50,6 +50,7 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) {
50 break; 50 break;
51 default: 51 default:
52 UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id); 52 UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id);
53 break;
53 } 54 }
54} 55}
55 56
@@ -65,6 +66,7 @@ void Puller::ProcessFenceActionMethod() {
65 break; 66 break;
66 default: 67 default:
67 UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value()); 68 UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value());
69 break;
68 } 70 }
69} 71}
70 72
@@ -228,6 +230,7 @@ void Puller::CallEngineMethod(const MethodCall& method_call) {
228 break; 230 break;
229 default: 231 default:
230 UNIMPLEMENTED_MSG("Unimplemented engine"); 232 UNIMPLEMENTED_MSG("Unimplemented engine");
233 break;
231 } 234 }
232} 235}
233 236
@@ -254,6 +257,7 @@ void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_s
254 break; 257 break;
255 default: 258 default:
256 UNIMPLEMENTED_MSG("Unimplemented engine"); 259 UNIMPLEMENTED_MSG("Unimplemented engine");
260 break;
257 } 261 }
258} 262}
259 263
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index f896591bf..0f3262edb 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -126,11 +126,25 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
126 } 126 }
127} 127}
128 128
129constexpr std::array<std::pair<u64, HLEFunction>, 4> hle_funcs{{ 129// Multi-layer Clear
130void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
131 ASSERT(parameters.size() == 1);
132
133 const Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]};
134 const u32 rt_index = clear_params.RT;
135 const u32 num_layers = maxwell3d.regs.rt[rt_index].depth;
136 ASSERT(clear_params.layer == 0);
137
138 maxwell3d.regs.clear_surface.raw = clear_params.raw;
139 maxwell3d.ProcessClearBuffers(num_layers);
140}
141
142constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{
130 {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, 143 {0x771BB18C62444DA0, &HLE_771BB18C62444DA0},
131 {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD}, 144 {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD},
132 {0x0217920100488FF7, &HLE_0217920100488FF7}, 145 {0x0217920100488FF7, &HLE_0217920100488FF7},
133 {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164}, 146 {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164},
147 {0xEAD26C3E2109B06B, &HLE_EAD26C3E2109B06B},
134}}; 148}};
135 149
136class HLEMacroImpl final : public CachedMacro { 150class HLEMacroImpl final : public CachedMacro {
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp
index c0d32c112..0d63495a9 100644
--- a/src/video_core/macro/macro_interpreter.cpp
+++ b/src/video_core/macro/macro_interpreter.cpp
@@ -201,6 +201,7 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) {
201 } 201 }
202 default: 202 default:
203 UNIMPLEMENTED_MSG("Unimplemented macro operation {}", opcode.operation.Value()); 203 UNIMPLEMENTED_MSG("Unimplemented macro operation {}", opcode.operation.Value());
204 break;
204 } 205 }
205 206
206 // An instruction with the Exit flag will not actually 207 // An instruction with the Exit flag will not actually
@@ -297,6 +298,7 @@ void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 r
297 break; 298 break;
298 default: 299 default:
299 UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation); 300 UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation);
301 break;
300 } 302 }
301} 303}
302 304
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp
index 25c1ce798..7347cbd88 100644
--- a/src/video_core/macro/macro_jit_x64.cpp
+++ b/src/video_core/macro/macro_jit_x64.cpp
@@ -652,6 +652,7 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3
652 break; 652 break;
653 default: 653 default:
654 UNIMPLEMENTED_MSG("Unimplemented macro operation {}", operation); 654 UNIMPLEMENTED_MSG("Unimplemented macro operation {}", operation);
655 break;
655 } 656 }
656} 657}
657 658
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 1cbfef090..cfd872a40 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -43,7 +43,7 @@ public:
43 virtual void Draw(bool is_indexed, u32 instance_count) = 0; 43 virtual void Draw(bool is_indexed, u32 instance_count) = 0;
44 44
45 /// Clear the current framebuffer 45 /// Clear the current framebuffer
46 virtual void Clear() = 0; 46 virtual void Clear(u32 layer_count) = 0;
47 47
48 /// Dispatches a compute shader invocation 48 /// Dispatches a compute shader invocation
49 virtual void DispatchCompute() = 0; 49 virtual void DispatchCompute() = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index d05a5f60b..115a5e010 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -136,7 +136,7 @@ void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_load
136 shader_cache.LoadDiskResources(title_id, stop_loading, callback); 136 shader_cache.LoadDiskResources(title_id, stop_loading, callback);
137} 137}
138 138
139void RasterizerOpenGL::Clear() { 139void RasterizerOpenGL::Clear(u32 layer_count) {
140 MICROPROFILE_SCOPE(OpenGL_Clears); 140 MICROPROFILE_SCOPE(OpenGL_Clears);
141 if (!maxwell3d->ShouldExecute()) { 141 if (!maxwell3d->ShouldExecute()) {
142 return; 142 return;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 793e0d608..449a14f12 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -69,7 +69,7 @@ public:
69 ~RasterizerOpenGL() override; 69 ~RasterizerOpenGL() override;
70 70
71 void Draw(bool is_indexed, u32 instance_count) override; 71 void Draw(bool is_indexed, u32 instance_count) override;
72 void Clear() override; 72 void Clear(u32 layer_count) override;
73 void DispatchCompute() override; 73 void DispatchCompute() override;
74 void ResetCounter(VideoCore::QueryType type) override; 74 void ResetCounter(VideoCore::QueryType type) override;
75 void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; 75 void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override;
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 99cd11d1e..9f7ce7414 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -891,6 +891,7 @@ void Image::CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t b
891 break; 891 break;
892 default: 892 default:
893 ASSERT(false); 893 ASSERT(false);
894 break;
894 } 895 }
895} 896}
896 897
@@ -927,6 +928,7 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b
927 break; 928 break;
928 default: 929 default:
929 ASSERT(false); 930 ASSERT(false);
931 break;
930 } 932 }
931 // Compressed formats don't have a pixel format or type 933 // Compressed formats don't have a pixel format or type
932 const bool is_compressed = gl_format == GL_NONE; 934 const bool is_compressed = gl_format == GL_NONE;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 8bd5eba7e..f29462f7c 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -340,6 +340,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
340 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; 340 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
341 // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", 341 // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",
342 // static_cast<u32>(framebuffer.pixel_format)); 342 // static_cast<u32>(framebuffer.pixel_format));
343 break;
343 } 344 }
344 345
345 texture.resource.Release(); 346 texture.resource.Release();
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f69c0c50f..67b88621a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -213,7 +213,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
213 EndTransformFeedback(); 213 EndTransformFeedback();
214} 214}
215 215
216void RasterizerVulkan::Clear() { 216void RasterizerVulkan::Clear(u32 layer_count) {
217 MICROPROFILE_SCOPE(Vulkan_Clearing); 217 MICROPROFILE_SCOPE(Vulkan_Clearing);
218 218
219 if (!maxwell3d->ShouldExecute()) { 219 if (!maxwell3d->ShouldExecute()) {
@@ -256,7 +256,7 @@ void RasterizerVulkan::Clear() {
256 .rect = regs.clear_control.use_scissor ? GetScissorState(regs, 0, up_scale, down_shift) 256 .rect = regs.clear_control.use_scissor ? GetScissorState(regs, 0, up_scale, down_shift)
257 : default_scissor, 257 : default_scissor,
258 .baseArrayLayer = regs.clear_surface.layer, 258 .baseArrayLayer = regs.clear_surface.layer,
259 .layerCount = 1, 259 .layerCount = layer_count,
260 }; 260 };
261 if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) { 261 if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) {
262 return; 262 return;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index b0bc306f5..70f36d58a 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -65,7 +65,7 @@ public:
65 ~RasterizerVulkan() override; 65 ~RasterizerVulkan() override;
66 66
67 void Draw(bool is_indexed, u32 instance_count) override; 67 void Draw(bool is_indexed, u32 instance_count) override;
68 void Clear() override; 68 void Clear(u32 layer_count) override;
69 void DispatchCompute() override; 69 void DispatchCompute() override;
70 void ResetCounter(VideoCore::QueryType type) override; 70 void ResetCounter(VideoCore::QueryType type) override;
71 void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; 71 void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 7934f2a51..4a7b633b7 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -221,6 +221,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s
221 [[fallthrough]]; 221 [[fallthrough]];
222 default: 222 default:
223 vk::Check(result); 223 vk::Check(result);
224 break;
224 } 225 }
225 }); 226 });
226 chunk->MarkSubmit(); 227 chunk->MarkSubmit();
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 853b80d8a..a65bbeb1c 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -108,6 +108,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
108 break; 108 break;
109 default: 109 default:
110 ASSERT_MSG(false, "Invalid surface type"); 110 ASSERT_MSG(false, "Invalid surface type");
111 break;
111 } 112 }
112 } 113 }
113 if (info.storage) { 114 if (info.storage) {
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index fd1a4b987..59120cd09 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -170,6 +170,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe
170#undef BPP_CASE 170#undef BPP_CASE
171 default: 171 default:
172 ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); 172 ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel);
173 break;
173 } 174 }
174} 175}
175 176
@@ -217,6 +218,7 @@ void SwizzleSubrect(std::span<u8> output, std::span<const u8> input, u32 bytes_p
217#undef BPP_CASE 218#undef BPP_CASE
218 default: 219 default:
219 ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); 220 ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel);
221 break;
220 } 222 }
221} 223}
222 224
@@ -240,6 +242,7 @@ void UnswizzleSubrect(std::span<u8> output, std::span<const u8> input, u32 bytes
240#undef BPP_CASE 242#undef BPP_CASE
241 default: 243 default:
242 ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); 244 ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel);
245 break;
243 } 246 }
244} 247}
245 248
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index b03e71248..05f49c0d2 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -126,6 +126,7 @@ void CompatDB::Submit() {
126 break; 126 break;
127 default: 127 default:
128 LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); 128 LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
129 break;
129 } 130 }
130} 131}
131 132
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 72498f52a..7ee2302cc 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1956,6 +1956,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
1956 } 1956 }
1957 default: 1957 default:
1958 UNIMPLEMENTED(); 1958 UNIMPLEMENTED();
1959 break;
1959 } 1960 }
1960 1961
1961 const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path)); 1962 const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path));
@@ -3199,6 +3200,7 @@ void GMainWindow::OnToggleGpuAccuracy() {
3199 case Settings::GPUAccuracy::Extreme: 3200 case Settings::GPUAccuracy::Extreme:
3200 default: { 3201 default: {
3201 Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High); 3202 Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
3203 break;
3202 } 3204 }
3203 } 3205 }
3204 3206
@@ -3531,6 +3533,7 @@ void GMainWindow::UpdateGPUAccuracyButton() {
3531 default: { 3533 default: {
3532 gpu_accuracy_button->setText(tr("GPU ERROR")); 3534 gpu_accuracy_button->setText(tr("GPU ERROR"));
3533 gpu_accuracy_button->setChecked(true); 3535 gpu_accuracy_button->setChecked(true);
3536 break;
3534 } 3537 }
3535 } 3538 }
3536} 3539}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
index 65455c86e..25948328c 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -84,6 +84,7 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
84 default: 84 default:
85 LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); 85 LOG_CRITICAL(Frontend, "Window manager subsystem not implemented");
86 std::exit(EXIT_FAILURE); 86 std::exit(EXIT_FAILURE);
87 break;
87 } 88 }
88 89
89 OnResize(); 90 OnResize();
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index e16f79eb4..dfe5a30ea 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -351,6 +351,7 @@ int main(int argc, char** argv) {
351 "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", 351 "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
352 loader_id, error_id, static_cast<Loader::ResultStatus>(error_id)); 352 loader_id, error_id, static_cast<Loader::ResultStatus>(error_id));
353 } 353 }
354 break;
354 } 355 }
355 356
356 system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL"); 357 system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL");