summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/address_space.inc2
-rw-r--r--src/common/scratch_buffer.h9
-rw-r--r--src/common/settings.cpp2
-rw-r--r--src/common/settings.h3
-rw-r--r--src/core/CMakeLists.txt21
-rw-r--r--src/core/core.cpp4
-rw-r--r--src/core/core.h2
-rw-r--r--src/core/file_sys/savedata_factory.cpp4
-rw-r--r--src/core/file_sys/vfs_layered.cpp9
-rw-r--r--src/core/file_sys/vfs_vector.cpp19
-rw-r--r--src/core/file_sys/vfs_vector.h4
-rw-r--r--src/core/frontend/applets/cabinet.cpp2
-rw-r--r--src/core/frontend/applets/cabinet.h10
-rw-r--r--src/core/hid/emulated_controller.cpp35
-rw-r--r--src/core/hid/emulated_controller.h8
-rw-r--r--src/core/hid/input_converter.cpp2
-rw-r--r--src/core/hid/motion_input.cpp21
-rw-r--r--src/core/hid/motion_input.h11
-rw-r--r--src/core/hle/service/am/am.cpp33
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.cpp24
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.h6
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp17
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp8
-rw-r--r--src/core/hle/service/hid/controllers/npad.h4
-rw-r--r--src/core/hle/service/hid/hid.cpp20
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.cpp (renamed from src/core/hle/service/nfp/amiibo_crypto.cpp)4
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.h (renamed from src/core/hle/service/nfp/amiibo_crypto.h)4
-rw-r--r--src/core/hle/service/nfc/common/device.cpp (renamed from src/core/hle/service/nfp/nfp_device.cpp)695
-rw-r--r--src/core/hle/service/nfc/common/device.h138
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp695
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h100
-rw-r--r--src/core/hle/service/nfc/mifare_result.h17
-rw-r--r--src/core/hle/service/nfc/mifare_types.h63
-rw-r--r--src/core/hle/service/nfc/mifare_user.cpp400
-rw-r--r--src/core/hle/service/nfc/mifare_user.h52
-rw-r--r--src/core/hle/service/nfc/nfc.cpp159
-rw-r--r--src/core/hle/service/nfc/nfc_device.cpp288
-rw-r--r--src/core/hle/service/nfc/nfc_device.h78
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp382
-rw-r--r--src/core/hle/service/nfc/nfc_interface.h (renamed from src/core/hle/service/nfc/nfc_user.h)33
-rw-r--r--src/core/hle/service/nfc/nfc_result.h33
-rw-r--r--src/core/hle/service/nfc/nfc_types.h90
-rw-r--r--src/core/hle/service/nfc/nfc_user.cpp365
-rw-r--r--src/core/hle/service/nfp/nfp.cpp36
-rw-r--r--src/core/hle/service/nfp/nfp_device.h120
-rw-r--r--src/core/hle/service/nfp/nfp_interface.cpp839
-rw-r--r--src/core/hle/service/nfp/nfp_interface.h37
-rw-r--r--src/core/hle/service/nfp/nfp_result.h29
-rw-r--r--src/core/hle/service/nfp/nfp_types.h129
-rw-r--r--src/core/hle/service/nifm/nifm.cpp6
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp5
-rw-r--r--src/core/hle/service/nvnflinger/parcel.h72
-rw-r--r--src/core/hle/service/service.h20
-rw-r--r--src/core/hle/service/time/clock_types.h12
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp19
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h5
-rw-r--r--src/core/hle/service/vi/vi.cpp12
-rw-r--r--src/core/internal_network/network.cpp2
-rw-r--r--src/core/internal_network/network_interface.cpp2
-rw-r--r--src/core/memory.cpp25
-rw-r--r--src/input_common/drivers/sdl_driver.cpp35
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp7
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h2
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h8
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp34
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.h6
-rw-r--r--src/input_common/input_engine.cpp2
-rw-r--r--src/input_common/input_poller.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp8
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp7
-rw-r--r--src/tests/video_core/memory_tracker.cpp4
-rw-r--r--src/video_core/buffer_cache/buffer_base.h9
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h176
-rw-r--r--src/video_core/buffer_cache/buffer_cache_base.h10
-rw-r--r--src/video_core/buffer_cache/memory_tracker_base.h26
-rw-r--r--src/video_core/buffer_cache/word_manager.h27
-rw-r--r--src/video_core/engines/maxwell_dma.cpp8
-rw-r--r--src/video_core/engines/sw_blitter/blitter.cpp25
-rw-r--r--src/video_core/fence_manager.h5
-rw-r--r--src/video_core/gpu.cpp19
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/host1x/codecs/h264.cpp4
-rw-r--r--src/video_core/query_cache.h2
-rw-r--r--src/video_core/rasterizer_download_area.h16
-rw-r--r--src/video_core/rasterizer_interface.h3
-rw-r--r--src/video_core/renderer_null/null_rasterizer.cpp10
-rw-r--r--src/video_core/renderer_null/null_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp25
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h1
-rw-r--r--src/video_core/renderer_vulkan/pipeline_helper.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h9
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp39
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h14
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp40
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp16
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h6
-rw-r--r--src/video_core/texture_cache/formatter.cpp22
-rw-r--r--src/video_core/texture_cache/formatter.h2
-rw-r--r--src/video_core/texture_cache/image_info.cpp12
-rw-r--r--src/video_core/texture_cache/image_info.h2
-rw-r--r--src/video_core/texture_cache/image_view_base.cpp12
-rw-r--r--src/video_core/texture_cache/image_view_base.h7
-rw-r--r--src/video_core/texture_cache/texture_cache.h53
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h4
-rw-r--r--src/video_core/texture_cache/util.cpp10
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h3
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp2
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.cpp12
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.h14
-rw-r--r--src/yuzu/applets/qt_profile_select.cpp1
-rw-r--r--src/yuzu/bootmanager.h1
-rw-r--r--src/yuzu/configuration/config.cpp4
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp7
-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_advanced.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui22
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp3
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp20
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu/main.h8
-rw-r--r--src/yuzu/qt_common.cpp2
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/default_ini.h4
139 files changed, 3150 insertions, 3044 deletions
diff --git a/src/common/address_space.inc b/src/common/address_space.inc
index c97dc8651..1ee82df53 100644
--- a/src/common/address_space.inc
+++ b/src/common/address_space.inc
@@ -336,7 +336,7 @@ ALLOC_MEMBER(VaType)::Allocate(VaType size) {
336 ASSERT_MSG(false, "Unexpected allocator state!"); 336 ASSERT_MSG(false, "Unexpected allocator state!");
337 } 337 }
338 338
339 auto search_predecessor{this->blocks.begin()}; 339 auto search_predecessor{std::next(this->blocks.begin())};
340 auto search_successor{std::next(search_predecessor)}; 340 auto search_successor{std::next(search_predecessor)};
341 341
342 while (search_successor != this->blocks.end() && 342 while (search_successor != this->blocks.end() &&
diff --git a/src/common/scratch_buffer.h b/src/common/scratch_buffer.h
index 26d4e76dc..a69a5a7af 100644
--- a/src/common/scratch_buffer.h
+++ b/src/common/scratch_buffer.h
@@ -23,7 +23,10 @@ public:
23 buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {} 23 buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
24 24
25 ~ScratchBuffer() = default; 25 ~ScratchBuffer() = default;
26 ScratchBuffer(const ScratchBuffer&) = delete;
27 ScratchBuffer& operator=(const ScratchBuffer&) = delete;
26 ScratchBuffer(ScratchBuffer&&) = default; 28 ScratchBuffer(ScratchBuffer&&) = default;
29 ScratchBuffer& operator=(ScratchBuffer&&) = default;
27 30
28 /// This will only grow the buffer's capacity if size is greater than the current capacity. 31 /// This will only grow the buffer's capacity if size is greater than the current capacity.
29 /// The previously held data will remain intact. 32 /// The previously held data will remain intact.
@@ -87,6 +90,12 @@ public:
87 return buffer_capacity; 90 return buffer_capacity;
88 } 91 }
89 92
93 void swap(ScratchBuffer& other) noexcept {
94 std::swap(last_requested_size, other.last_requested_size);
95 std::swap(buffer_capacity, other.buffer_capacity);
96 std::swap(buffer, other.buffer);
97 }
98
90private: 99private:
91 size_t last_requested_size{}; 100 size_t last_requested_size{};
92 size_t buffer_capacity{}; 101 size_t buffer_capacity{};
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 61b5d0c1a..ba617aea1 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -62,6 +62,7 @@ void LogSettings() {
62 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); 62 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
63 log_setting("Renderer_AsyncASTC", values.async_astc.GetValue()); 63 log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
64 log_setting("Renderer_UseVsync", values.vsync_mode.GetValue()); 64 log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
65 log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue());
65 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue()); 66 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
66 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 67 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
67 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); 68 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
@@ -223,6 +224,7 @@ void RestoreGlobalState(bool is_powered_on) {
223 values.nvdec_emulation.SetGlobal(true); 224 values.nvdec_emulation.SetGlobal(true);
224 values.accelerate_astc.SetGlobal(true); 225 values.accelerate_astc.SetGlobal(true);
225 values.async_astc.SetGlobal(true); 226 values.async_astc.SetGlobal(true);
227 values.use_reactive_flushing.SetGlobal(true);
226 values.shader_backend.SetGlobal(true); 228 values.shader_backend.SetGlobal(true);
227 values.use_asynchronous_shaders.SetGlobal(true); 229 values.use_asynchronous_shaders.SetGlobal(true);
228 values.use_fast_gpu_time.SetGlobal(true); 230 values.use_fast_gpu_time.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 573597f3d..36ffcd693 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -465,6 +465,7 @@ struct Values {
465 SwitchableSetting<bool> async_astc{false, "async_astc"}; 465 SwitchableSetting<bool> async_astc{false, "async_astc"};
466 Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate, 466 Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate,
467 VSyncMode::FIFORelaxed, "use_vsync"}; 467 VSyncMode::FIFORelaxed, "use_vsync"};
468 SwitchableSetting<bool> use_reactive_flushing{true, "use_reactive_flushing"};
468 SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL, 469 SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL,
469 ShaderBackend::SPIRV, "shader_backend"}; 470 ShaderBackend::SPIRV, "shader_backend"};
470 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 471 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
@@ -535,6 +536,8 @@ struct Values {
535 Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"}; 536 Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"};
536 Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"}; 537 Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"};
537 538
539 Setting<bool> random_amiibo_id{false, "random_amiibo_id"};
540
538 // Data Storage 541 // Data Storage
539 Setting<bool> use_virtual_sd{true, "use_virtual_sd"}; 542 Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
540 Setting<bool> gamecard_inserted{false, "gamecard_inserted"}; 543 Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8817a99c9..45328158f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -555,21 +555,22 @@ add_library(core STATIC
555 hle/service/mnpp/mnpp_app.h 555 hle/service/mnpp/mnpp_app.h
556 hle/service/ncm/ncm.cpp 556 hle/service/ncm/ncm.cpp
557 hle/service/ncm/ncm.h 557 hle/service/ncm/ncm.h
558 hle/service/nfc/mifare_user.cpp 558 hle/service/nfc/common/amiibo_crypto.cpp
559 hle/service/nfc/mifare_user.h 559 hle/service/nfc/common/amiibo_crypto.h
560 hle/service/nfc/common/device.cpp
561 hle/service/nfc/common/device.h
562 hle/service/nfc/common/device_manager.cpp
563 hle/service/nfc/common/device_manager.h
564 hle/service/nfc/mifare_result.h
565 hle/service/nfc/mifare_types.h
560 hle/service/nfc/nfc.cpp 566 hle/service/nfc/nfc.cpp
561 hle/service/nfc/nfc.h 567 hle/service/nfc/nfc.h
562 hle/service/nfc/nfc_device.cpp 568 hle/service/nfc/nfc_interface.cpp
563 hle/service/nfc/nfc_device.h 569 hle/service/nfc/nfc_interface.h
564 hle/service/nfc/nfc_result.h 570 hle/service/nfc/nfc_result.h
565 hle/service/nfc/nfc_user.cpp 571 hle/service/nfc/nfc_types.h
566 hle/service/nfc/nfc_user.h
567 hle/service/nfp/amiibo_crypto.cpp
568 hle/service/nfp/amiibo_crypto.h
569 hle/service/nfp/nfp.cpp 572 hle/service/nfp/nfp.cpp
570 hle/service/nfp/nfp.h 573 hle/service/nfp/nfp.h
571 hle/service/nfp/nfp_device.cpp
572 hle/service/nfp/nfp_device.h
573 hle/service/nfp/nfp_interface.cpp 574 hle/service/nfp/nfp_interface.cpp
574 hle/service/nfp/nfp_interface.h 575 hle/service/nfp/nfp_interface.h
575 hle/service/nfp/nfp_result.h 576 hle/service/nfp/nfp_result.h
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 06fba4ce5..b5f62690e 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -612,6 +612,10 @@ void System::PrepareReschedule(const u32 core_index) {
612 impl->kernel.PrepareReschedule(core_index); 612 impl->kernel.PrepareReschedule(core_index);
613} 613}
614 614
615size_t System::GetCurrentHostThreadID() const {
616 return impl->kernel.GetCurrentHostThreadID();
617}
618
615PerfStatsResults System::GetAndResetPerfStats() { 619PerfStatsResults System::GetAndResetPerfStats() {
616 return impl->GetAndResetPerfStats(); 620 return impl->GetAndResetPerfStats();
617} 621}
diff --git a/src/core/core.h b/src/core/core.h
index 4a5aba032..4f153154f 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -222,6 +222,8 @@ public:
222 /// Prepare the core emulation for a reschedule 222 /// Prepare the core emulation for a reschedule
223 void PrepareReschedule(u32 core_index); 223 void PrepareReschedule(u32 core_index);
224 224
225 [[nodiscard]] size_t GetCurrentHostThreadID() const;
226
225 /// Gets and resets core performance statistics 227 /// Gets and resets core performance statistics
226 [[nodiscard]] PerfStatsResults GetAndResetPerfStats(); 228 [[nodiscard]] PerfStatsResults GetAndResetPerfStats();
227 229
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 769065b6f..70b36f170 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -82,9 +82,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
82 // Only detect account/device saves from the future location. 82 // Only detect account/device saves from the future location.
83 switch (type) { 83 switch (type) {
84 case SaveDataType::SaveData: 84 case SaveDataType::SaveData:
85 return fmt::format("{}/account/{}/{:016X}/1", space_id_path, uuid.RawString(), title_id); 85 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
86 case SaveDataType::DeviceSaveData: 86 case SaveDataType::DeviceSaveData:
87 return fmt::format("{}/device/{:016X}/1", space_id_path, title_id); 87 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
88 default: 88 default:
89 return ""; 89 return "";
90 } 90 }
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index da05dd395..3e6426afc 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <algorithm> 4#include <algorithm>
5#include <set>
5#include <utility> 6#include <utility>
6#include "core/file_sys/vfs_layered.h" 7#include "core/file_sys/vfs_layered.h"
7 8
@@ -58,11 +59,13 @@ std::string LayeredVfsDirectory::GetFullPath() const {
58 59
59std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { 60std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
60 std::vector<VirtualFile> out; 61 std::vector<VirtualFile> out;
62 std::set<std::string, std::less<>> out_names;
63
61 for (const auto& layer : dirs) { 64 for (const auto& layer : dirs) {
62 for (const auto& file : layer->GetFiles()) { 65 for (const auto& file : layer->GetFiles()) {
63 if (std::find_if(out.begin(), out.end(), [&file](const VirtualFile& comp) { 66 auto file_name = file->GetName();
64 return comp->GetName() == file->GetName(); 67 if (!out_names.contains(file_name)) {
65 }) == out.end()) { 68 out_names.emplace(std::move(file_name));
66 out.push_back(file); 69 out.push_back(file);
67 } 70 }
68 } 71 }
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 251d9d7c9..af1df4c51 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -67,6 +67,23 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
67 67
68VectorVfsDirectory::~VectorVfsDirectory() = default; 68VectorVfsDirectory::~VectorVfsDirectory() = default;
69 69
70VirtualFile VectorVfsDirectory::GetFile(std::string_view file_name) const {
71 if (!optimized_file_index_built) {
72 optimized_file_index.clear();
73 for (size_t i = 0; i < files.size(); i++) {
74 optimized_file_index.emplace(files[i]->GetName(), i);
75 }
76 optimized_file_index_built = true;
77 }
78
79 const auto it = optimized_file_index.find(file_name);
80 if (it != optimized_file_index.end()) {
81 return files[it->second];
82 }
83
84 return nullptr;
85}
86
70std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const { 87std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const {
71 return files; 88 return files;
72} 89}
@@ -107,6 +124,7 @@ bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
107} 124}
108 125
109bool VectorVfsDirectory::DeleteFile(std::string_view file_name) { 126bool VectorVfsDirectory::DeleteFile(std::string_view file_name) {
127 optimized_file_index_built = false;
110 return FindAndRemoveVectorElement(files, file_name); 128 return FindAndRemoveVectorElement(files, file_name);
111} 129}
112 130
@@ -124,6 +142,7 @@ VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) {
124} 142}
125 143
126void VectorVfsDirectory::AddFile(VirtualFile file) { 144void VectorVfsDirectory::AddFile(VirtualFile file) {
145 optimized_file_index_built = false;
127 files.push_back(std::move(file)); 146 files.push_back(std::move(file));
128} 147}
129 148
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index bfedb6e42..c9955755b 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -105,6 +105,7 @@ public:
105 VirtualDir parent = nullptr); 105 VirtualDir parent = nullptr);
106 ~VectorVfsDirectory() override; 106 ~VectorVfsDirectory() override;
107 107
108 VirtualFile GetFile(std::string_view file_name) const override;
108 std::vector<VirtualFile> GetFiles() const override; 109 std::vector<VirtualFile> GetFiles() const override;
109 std::vector<VirtualDir> GetSubdirectories() const override; 110 std::vector<VirtualDir> GetSubdirectories() const override;
110 bool IsWritable() const override; 111 bool IsWritable() const override;
@@ -126,6 +127,9 @@ private:
126 127
127 VirtualDir parent; 128 VirtualDir parent;
128 std::string name; 129 std::string name;
130
131 mutable std::map<std::string, size_t, std::less<>> optimized_file_index;
132 mutable bool optimized_file_index_built{};
129}; 133};
130 134
131} // namespace FileSys 135} // namespace FileSys
diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp
index 2d501eeae..c33ce248b 100644
--- a/src/core/frontend/applets/cabinet.cpp
+++ b/src/core/frontend/applets/cabinet.cpp
@@ -14,7 +14,7 @@ void DefaultCabinetApplet::Close() const {}
14 14
15void DefaultCabinetApplet::ShowCabinetApplet( 15void DefaultCabinetApplet::ShowCabinetApplet(
16 const CabinetCallback& callback, const CabinetParameters& parameters, 16 const CabinetCallback& callback, const CabinetParameters& parameters,
17 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { 17 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
18 LOG_WARNING(Service_AM, "(STUBBED) called"); 18 LOG_WARNING(Service_AM, "(STUBBED) called");
19 callback(false, {}); 19 callback(false, {});
20} 20}
diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h
index 74dc5a4f6..af3fc6c3d 100644
--- a/src/core/frontend/applets/cabinet.h
+++ b/src/core/frontend/applets/cabinet.h
@@ -7,9 +7,9 @@
7#include "core/frontend/applets/applet.h" 7#include "core/frontend/applets/applet.h"
8#include "core/hle/service/nfp/nfp_types.h" 8#include "core/hle/service/nfp/nfp_types.h"
9 9
10namespace Service::NFP { 10namespace Service::NFC {
11class NfpDevice; 11class NfcDevice;
12} // namespace Service::NFP 12} // namespace Service::NFC
13 13
14namespace Core::Frontend { 14namespace Core::Frontend {
15 15
@@ -26,14 +26,14 @@ public:
26 virtual ~CabinetApplet(); 26 virtual ~CabinetApplet();
27 virtual void ShowCabinetApplet(const CabinetCallback& callback, 27 virtual void ShowCabinetApplet(const CabinetCallback& callback,
28 const CabinetParameters& parameters, 28 const CabinetParameters& parameters,
29 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0; 29 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const = 0;
30}; 30};
31 31
32class DefaultCabinetApplet final : public CabinetApplet { 32class DefaultCabinetApplet final : public CabinetApplet {
33public: 33public:
34 void Close() const override; 34 void Close() const override;
35 void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, 35 void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
36 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; 36 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
37}; 37};
38 38
39} // namespace Core::Frontend 39} // namespace Core::Frontend
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index ecab85893..366880711 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -688,6 +688,12 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage
688 ReloadInput(); 688 ReloadInput();
689} 689}
690 690
691void EmulatedController::StartMotionCalibration() {
692 for (ControllerMotionInfo& motion : controller.motion_values) {
693 motion.emulated.Calibrate();
694 }
695}
696
691void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, 697void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
692 Common::UUID uuid) { 698 Common::UUID uuid) {
693 if (index >= controller.button_values.size()) { 699 if (index >= controller.button_values.size()) {
@@ -979,7 +985,6 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
979 emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold); 985 emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold);
980 emulated.UpdateRotation(raw_status.delta_timestamp); 986 emulated.UpdateRotation(raw_status.delta_timestamp);
981 emulated.UpdateOrientation(raw_status.delta_timestamp); 987 emulated.UpdateOrientation(raw_status.delta_timestamp);
982 force_update_motion = raw_status.force_update;
983 988
984 auto& motion = controller.motion_state[index]; 989 auto& motion = controller.motion_state[index];
985 motion.accel = emulated.GetAcceleration(); 990 motion.accel = emulated.GetAcceleration();
@@ -1618,19 +1623,6 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
1618 1623
1619MotionState EmulatedController::GetMotions() const { 1624MotionState EmulatedController::GetMotions() const {
1620 std::unique_lock lock{mutex}; 1625 std::unique_lock lock{mutex};
1621
1622 // Some drivers like mouse motion need constant refreshing
1623 if (force_update_motion) {
1624 for (auto& device : motion_devices) {
1625 if (!device) {
1626 continue;
1627 }
1628 lock.unlock();
1629 device->ForceUpdate();
1630 lock.lock();
1631 }
1632 }
1633
1634 return controller.motion_state; 1626 return controller.motion_state;
1635} 1627}
1636 1628
@@ -1696,8 +1688,21 @@ void EmulatedController::DeleteCallback(int key) {
1696 callback_list.erase(iterator); 1688 callback_list.erase(iterator);
1697} 1689}
1698 1690
1699void EmulatedController::TurboButtonUpdate() { 1691void EmulatedController::StatusUpdate() {
1700 turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2); 1692 turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
1693
1694 // Some drivers like key motion need constant refreshing
1695 for (std::size_t index = 0; index < motion_devices.size(); ++index) {
1696 const auto& raw_status = controller.motion_values[index].raw_status;
1697 auto& device = motion_devices[index];
1698 if (!raw_status.force_update) {
1699 continue;
1700 }
1701 if (!device) {
1702 continue;
1703 }
1704 device->ForceUpdate();
1705 }
1701} 1706}
1702 1707
1703NpadButton EmulatedController::GetTurboButtonMask() const { 1708NpadButton EmulatedController::GetTurboButtonMask() const {
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 6e01f4e12..88fad2f56 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -290,6 +290,9 @@ public:
290 */ 290 */
291 void SetMotionParam(std::size_t index, Common::ParamPackage param); 291 void SetMotionParam(std::size_t index, Common::ParamPackage param);
292 292
293 /// Auto calibrates the current motion devices
294 void StartMotionCalibration();
295
293 /// Returns the latest button status from the controller with parameters 296 /// Returns the latest button status from the controller with parameters
294 ButtonValues GetButtonsValues() const; 297 ButtonValues GetButtonsValues() const;
295 298
@@ -415,8 +418,8 @@ public:
415 */ 418 */
416 void DeleteCallback(int key); 419 void DeleteCallback(int key);
417 420
418 /// Swaps the state of the turbo buttons 421 /// Swaps the state of the turbo buttons and updates motion input
419 void TurboButtonUpdate(); 422 void StatusUpdate();
420 423
421private: 424private:
422 /// creates input devices from params 425 /// creates input devices from params
@@ -528,7 +531,6 @@ private:
528 bool is_configuring{false}; 531 bool is_configuring{false};
529 bool system_buttons_enabled{true}; 532 bool system_buttons_enabled{true};
530 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; 533 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
531 bool force_update_motion{false};
532 u32 turbo_button_state{0}; 534 u32 turbo_button_state{0};
533 535
534 // Temporary values to avoid doing changes while the controller is in configuring mode 536 // Temporary values to avoid doing changes while the controller is in configuring mode
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 53b00b1f9..4ccb1c596 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -86,7 +86,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
86 .range = 1.0f, 86 .range = 1.0f,
87 .offset = 0.0f, 87 .offset = 0.0f,
88 }; 88 };
89 status.delta_timestamp = 5000; 89 status.delta_timestamp = 1000;
90 status.force_update = true; 90 status.force_update = true;
91 status.accel.x = { 91 status.accel.x = {
92 .value = 0.0f, 92 .value = 0.0f,
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp
index b60478dbb..f56f2ae1d 100644
--- a/src/core/hid/motion_input.cpp
+++ b/src/core/hid/motion_input.cpp
@@ -37,11 +37,17 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
37 gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue); 37 gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue);
38 gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue); 38 gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue);
39 39
40 // Auto adjust drift to minimize drift 40 // Auto adjust gyro_bias to minimize drift
41 if (!IsMoving(IsAtRestRelaxed)) { 41 if (!IsMoving(IsAtRestRelaxed)) {
42 gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); 42 gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
43 } 43 }
44 44
45 // Adjust drift when calibration mode is enabled
46 if (calibration_mode) {
47 gyro_bias = (gyro_bias * 0.99f) + (gyroscope * 0.01f);
48 StopCalibration();
49 }
50
45 if (gyro.Length() < gyro_threshold * user_gyro_threshold) { 51 if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
46 gyro = {}; 52 gyro = {};
47 } else { 53 } else {
@@ -107,6 +113,19 @@ void MotionInput::UpdateRotation(u64 elapsed_time) {
107 rotations += gyro * sample_period; 113 rotations += gyro * sample_period;
108} 114}
109 115
116void MotionInput::Calibrate() {
117 calibration_mode = true;
118 calibration_counter = 0;
119}
120
121void MotionInput::StopCalibration() {
122 if (calibration_counter++ > CalibrationSamples) {
123 calibration_mode = false;
124 ResetQuaternion();
125 ResetRotations();
126 }
127}
128
110// Based on Madgwick's implementation of Mayhony's AHRS algorithm. 129// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
111// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs 130// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
112void MotionInput::UpdateOrientation(u64 elapsed_time) { 131void MotionInput::UpdateOrientation(u64 elapsed_time) {
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h
index 482719359..11678983d 100644
--- a/src/core/hid/motion_input.h
+++ b/src/core/hid/motion_input.h
@@ -23,6 +23,8 @@ public:
23 static constexpr float GyroMaxValue = 5.0f; 23 static constexpr float GyroMaxValue = 5.0f;
24 static constexpr float AccelMaxValue = 7.0f; 24 static constexpr float AccelMaxValue = 7.0f;
25 25
26 static constexpr std::size_t CalibrationSamples = 300;
27
26 explicit MotionInput(); 28 explicit MotionInput();
27 29
28 MotionInput(const MotionInput&) = default; 30 MotionInput(const MotionInput&) = default;
@@ -49,6 +51,8 @@ public:
49 void UpdateRotation(u64 elapsed_time); 51 void UpdateRotation(u64 elapsed_time);
50 void UpdateOrientation(u64 elapsed_time); 52 void UpdateOrientation(u64 elapsed_time);
51 53
54 void Calibrate();
55
52 [[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const; 56 [[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
53 [[nodiscard]] Common::Vec3f GetAcceleration() const; 57 [[nodiscard]] Common::Vec3f GetAcceleration() const;
54 [[nodiscard]] Common::Vec3f GetGyroscope() const; 58 [[nodiscard]] Common::Vec3f GetGyroscope() const;
@@ -61,6 +65,7 @@ public:
61 [[nodiscard]] bool IsCalibrated(f32 sensitivity) const; 65 [[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
62 66
63private: 67private:
68 void StopCalibration();
64 void ResetOrientation(); 69 void ResetOrientation();
65 void SetOrientationFromAccelerometer(); 70 void SetOrientationFromAccelerometer();
66 71
@@ -103,6 +108,12 @@ private:
103 108
104 // Use accelerometer values to calculate position 109 // Use accelerometer values to calculate position
105 bool only_accelerometer = true; 110 bool only_accelerometer = true;
111
112 // When enabled it will aggressively adjust for gyro drift
113 bool calibration_mode = false;
114
115 // Used to auto disable calibration mode
116 std::size_t calibration_counter = 0;
106}; 117};
107 118
108} // namespace Core::HID 119} // namespace Core::HID
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index e59de844c..a2375508a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -13,6 +13,7 @@
13#include "core/file_sys/savedata_factory.h" 13#include "core/file_sys/savedata_factory.h"
14#include "core/hle/kernel/k_event.h" 14#include "core/hle/kernel/k_event.h"
15#include "core/hle/kernel/k_transfer_memory.h" 15#include "core/hle/kernel/k_transfer_memory.h"
16#include "core/hle/result.h"
16#include "core/hle/service/acc/profile_manager.h" 17#include "core/hle/service/acc/profile_manager.h"
17#include "core/hle/service/am/am.h" 18#include "core/hle/service/am/am.h"
18#include "core/hle/service/am/applet_ae.h" 19#include "core/hle/service/am/applet_ae.h"
@@ -1335,7 +1336,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1335 {24, nullptr, "GetLaunchStorageInfoForDebug"}, 1336 {24, nullptr, "GetLaunchStorageInfoForDebug"},
1336 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, 1337 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
1337 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, 1338 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
1338 {27, nullptr, "CreateCacheStorage"}, 1339 {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
1339 {28, nullptr, "GetSaveDataSizeMax"}, 1340 {28, nullptr, "GetSaveDataSizeMax"},
1340 {29, nullptr, "GetCacheStorageMax"}, 1341 {29, nullptr, "GetCacheStorageMax"},
1341 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, 1342 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
@@ -1738,6 +1739,36 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
1738 rb.Push(size.journal); 1739 rb.Push(size.journal);
1739} 1740}
1740 1741
1742void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
1743 struct InputParameters {
1744 u16 index;
1745 s64 size;
1746 s64 journal_size;
1747 };
1748 static_assert(sizeof(InputParameters) == 24);
1749
1750 struct OutputParameters {
1751 u32 storage_target;
1752 u64 required_size;
1753 };
1754 static_assert(sizeof(OutputParameters) == 16);
1755
1756 IPC::RequestParser rp{ctx};
1757 const auto params = rp.PopRaw<InputParameters>();
1758
1759 LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
1760 params.index, params.size, params.journal_size);
1761
1762 const OutputParameters resp{
1763 .storage_target = 1,
1764 .required_size = 0,
1765 };
1766
1767 IPC::ResponseBuilder rb{ctx, 6};
1768 rb.Push(ResultSuccess);
1769 rb.PushRaw(resp);
1770}
1771
1741void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) { 1772void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
1742 LOG_WARNING(Service_AM, "(STUBBED) called"); 1773 LOG_WARNING(Service_AM, "(STUBBED) called");
1743 1774
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 0dbc6485e..d4fd163da 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -333,6 +333,7 @@ private:
333 void GetPseudoDeviceId(HLERequestContext& ctx); 333 void GetPseudoDeviceId(HLERequestContext& ctx);
334 void ExtendSaveData(HLERequestContext& ctx); 334 void ExtendSaveData(HLERequestContext& ctx);
335 void GetSaveDataSize(HLERequestContext& ctx); 335 void GetSaveDataSize(HLERequestContext& ctx);
336 void CreateCacheStorage(HLERequestContext& ctx);
336 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); 337 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
337 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); 338 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
338 void BeginBlockingHomeButton(HLERequestContext& ctx); 339 void BeginBlockingHomeButton(HLERequestContext& ctx);
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
index 93c9f2a55..8b754e9d4 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.cpp
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -11,7 +11,7 @@
11#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_cabinet.h" 12#include "core/hle/service/am/applets/applet_cabinet.h"
13#include "core/hle/service/mii/mii_manager.h" 13#include "core/hle/service/mii/mii_manager.h"
14#include "core/hle/service/nfp/nfp_device.h" 14#include "core/hle/service/nfc/common/device.h"
15 15
16namespace Service::AM::Applets { 16namespace Service::AM::Applets {
17 17
@@ -72,10 +72,10 @@ void Cabinet::Execute() {
72 72
73 // TODO: listen on all controllers 73 // TODO: listen on all controllers
74 if (nfp_device == nullptr) { 74 if (nfp_device == nullptr) {
75 nfp_device = std::make_shared<Service::NFP::NfpDevice>( 75 nfp_device = std::make_shared<Service::NFC::NfcDevice>(
76 system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); 76 system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
77 nfp_device->Initialize(); 77 nfp_device->Initialize();
78 nfp_device->StartDetection(Service::NFP::TagProtocol::All); 78 nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
79 } 79 }
80 80
81 const Core::Frontend::CabinetParameters parameters{ 81 const Core::Frontend::CabinetParameters parameters{
@@ -106,20 +106,22 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
106 Cancel(); 106 Cancel();
107 } 107 }
108 108
109 if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && 109 if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
110 nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { 110 nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
111 Cancel(); 111 Cancel();
112 } 112 }
113 113
114 if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) { 114 if (nfp_device->GetCurrentState() == Service::NFC::DeviceState::TagFound) {
115 nfp_device->Mount(Service::NFP::MountTarget::All); 115 nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
116 } 116 }
117 117
118 switch (applet_input_common.applet_mode) { 118 switch (applet_input_common.applet_mode) {
119 case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { 119 case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
120 Service::NFP::AmiiboName name{}; 120 Service::NFP::RegisterInfoPrivate register_info{};
121 std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); 121 std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(),
122 nfp_device->SetRegisterInfoPrivate(name); 122 std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1));
123
124 nfp_device->SetRegisterInfoPrivate(register_info);
123 break; 125 break;
124 } 126 }
125 case Service::NFP::CabinetMode::StartGameDataEraser: 127 case Service::NFP::CabinetMode::StartGameDataEraser:
@@ -139,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
139 applet_output.device_handle = applet_input_common.device_handle; 141 applet_output.device_handle = applet_input_common.device_handle;
140 applet_output.result = CabinetResult::Cancel; 142 applet_output.result = CabinetResult::Cancel;
141 const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); 143 const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
142 const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); 144 const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false);
143 nfp_device->Finalize(); 145 nfp_device->Finalize();
144 146
145 if (reg_result.IsSuccess()) { 147 if (reg_result.IsSuccess()) {
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h
index edd295a27..b56427021 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.h
+++ b/src/core/hle/service/am/applets/applet_cabinet.h
@@ -19,8 +19,8 @@ namespace Core {
19class System; 19class System;
20} // namespace Core 20} // namespace Core
21 21
22namespace Service::NFP { 22namespace Service::NFC {
23class NfpDevice; 23class NfcDevice;
24} 24}
25 25
26namespace Service::AM::Applets { 26namespace Service::AM::Applets {
@@ -96,7 +96,7 @@ private:
96 Core::System& system; 96 Core::System& system;
97 97
98 bool is_complete{false}; 98 bool is_complete{false};
99 std::shared_ptr<Service::NFP::NfpDevice> nfp_device; 99 std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
100 Kernel::KEvent* availability_change_event; 100 Kernel::KEvent* availability_change_event;
101 KernelHelpers::ServiceContext service_context; 101 KernelHelpers::ServiceContext service_context;
102 StartParamForAmiiboSettings applet_input_common{}; 102 StartParamForAmiiboSettings applet_input_common{};
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 9e559d97e..f73a864c3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -24,8 +24,10 @@
24#include "core/file_sys/savedata_factory.h" 24#include "core/file_sys/savedata_factory.h"
25#include "core/file_sys/system_archive/system_archive.h" 25#include "core/file_sys/system_archive/system_archive.h"
26#include "core/file_sys/vfs.h" 26#include "core/file_sys/vfs.h"
27#include "core/hle/result.h"
27#include "core/hle/service/filesystem/filesystem.h" 28#include "core/hle/service/filesystem/filesystem.h"
28#include "core/hle/service/filesystem/fsp_srv.h" 29#include "core/hle/service/filesystem/fsp_srv.h"
30#include "core/hle/service/hle_ipc.h"
29#include "core/hle/service/ipc_helpers.h" 31#include "core/hle/service/ipc_helpers.h"
30#include "core/reporter.h" 32#include "core/reporter.h"
31 33
@@ -552,9 +554,9 @@ public:
552 // Write the data to memory 554 // Write the data to memory
553 ctx.WriteBuffer(begin, range_size); 555 ctx.WriteBuffer(begin, range_size);
554 556
555 IPC::ResponseBuilder rb{ctx, 3}; 557 IPC::ResponseBuilder rb{ctx, 4};
556 rb.Push(ResultSuccess); 558 rb.Push(ResultSuccess);
557 rb.Push<u32>(static_cast<u32>(actual_entries)); 559 rb.Push<u64>(actual_entries);
558 } 560 }
559 561
560private: 562private:
@@ -712,7 +714,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
712 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 714 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
713 {60, nullptr, "OpenSaveDataInfoReader"}, 715 {60, nullptr, "OpenSaveDataInfoReader"},
714 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 716 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
715 {62, nullptr, "OpenCacheStorageList"}, 717 {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
716 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 718 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
717 {65, nullptr, "UpdateSaveDataMacForDebug"}, 719 {65, nullptr, "UpdateSaveDataMacForDebug"},
718 {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, 720 {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
@@ -921,6 +923,15 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
921 std::make_shared<ISaveDataInfoReader>(system, space, fsc)); 923 std::make_shared<ISaveDataInfoReader>(system, space, fsc));
922} 924}
923 925
926void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
927 LOG_WARNING(Service_FS, "(STUBBED) called");
928
929 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
930 rb.Push(ResultSuccess);
931 rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage,
932 fsc);
933}
934
924void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { 935void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
925 LOG_WARNING(Service_FS, "(STUBBED) called."); 936 LOG_WARNING(Service_FS, "(STUBBED) called.");
926 937
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 49f17c7c3..4f3c2f6de 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -42,6 +42,7 @@ private:
42 void OpenSaveDataFileSystem(HLERequestContext& ctx); 42 void OpenSaveDataFileSystem(HLERequestContext& ctx);
43 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); 43 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
44 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); 44 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
45 void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
45 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); 46 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
46 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); 47 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
47 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); 48 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 8abf71608..28818c813 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -423,8 +423,8 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
423 return; 423 return;
424 } 424 }
425 425
426 // This function is unique to yuzu for the turbo buttons to work properly 426 // This function is unique to yuzu for the turbo buttons and motion to work properly
427 controller.device->TurboButtonUpdate(); 427 controller.device->StatusUpdate();
428 428
429 auto& pad_entry = controller.npad_pad_state; 429 auto& pad_entry = controller.npad_pad_state;
430 auto& trigger_entry = controller.npad_trigger_state; 430 auto& trigger_entry = controller.npad_trigger_state;
@@ -979,8 +979,8 @@ void Controller_NPad::VibrateController(
979} 979}
980 980
981void Controller_NPad::VibrateControllers( 981void Controller_NPad::VibrateControllers(
982 const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, 982 std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
983 const std::vector<Core::HID::VibrationValue>& vibration_values) { 983 std::span<const Core::HID::VibrationValue> vibration_values) {
984 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { 984 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
985 return; 985 return;
986 } 986 }
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 9cfe298f1..776411261 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -112,8 +112,8 @@ public:
112 const Core::HID::VibrationValue& vibration_value); 112 const Core::HID::VibrationValue& vibration_value);
113 113
114 void VibrateControllers( 114 void VibrateControllers(
115 const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, 115 std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
116 const std::vector<Core::HID::VibrationValue>& vibration_values); 116 std::span<const Core::HID::VibrationValue> vibration_values);
117 117
118 Core::HID::VibrationValue GetLastVibration( 118 Core::HID::VibrationValue GetLastVibration(
119 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; 119 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 87e7b864a..2bf1d8a27 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1601,16 +1601,16 @@ void Hid::SendVibrationValues(HLERequestContext& ctx) {
1601 IPC::RequestParser rp{ctx}; 1601 IPC::RequestParser rp{ctx};
1602 const auto applet_resource_user_id{rp.Pop<u64>()}; 1602 const auto applet_resource_user_id{rp.Pop<u64>()};
1603 1603
1604 const auto handles = ctx.ReadBuffer(0); 1604 const auto handle_data = ctx.ReadBuffer(0);
1605 const auto vibrations = ctx.ReadBuffer(1); 1605 const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
1606 1606 const auto vibration_data = ctx.ReadBuffer(1);
1607 std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles( 1607 const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
1608 handles.size() / sizeof(Core::HID::VibrationDeviceHandle)); 1608
1609 std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() / 1609 auto vibration_device_handles =
1610 sizeof(Core::HID::VibrationValue)); 1610 std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
1611 1611 handle_count);
1612 std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); 1612 auto vibration_values = std::span(
1613 std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); 1613 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
1614 1614
1615 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1615 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1616 .VibrateControllers(vibration_device_handles, vibration_values); 1616 .VibrateControllers(vibration_device_handles, vibration_values);
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
index a3622e792..f3901ee8d 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -12,7 +12,7 @@
12#include "common/fs/fs.h" 12#include "common/fs/fs.h"
13#include "common/fs/path_util.h" 13#include "common/fs/path_util.h"
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15#include "core/hle/service/nfp/amiibo_crypto.h" 15#include "core/hle/service/nfc/common/amiibo_crypto.h"
16 16
17namespace Service::NFP::AmiiboCrypto { 17namespace Service::NFP::AmiiboCrypto {
18 18
@@ -55,7 +55,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
55 if (amiibo_data.constant_value != 0xA5) { 55 if (amiibo_data.constant_value != 0xA5) {
56 return false; 56 return false;
57 } 57 }
58 if (amiibo_data.model_info.tag_type != PackedTagType::Type2) { 58 if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
59 return false; 59 return false;
60 } 60 }
61 if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) { 61 if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) {
diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfc/common/amiibo_crypto.h
index f6208ee6b..bf3044ed9 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.h
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.h
@@ -24,9 +24,9 @@ using DrgbOutput = std::array<u8, 0x20>;
24struct HashSeed { 24struct HashSeed {
25 u16_be magic; 25 u16_be magic;
26 std::array<u8, 0xE> padding; 26 std::array<u8, 0xE> padding;
27 UniqueSerialNumber uid_1; 27 NFC::UniqueSerialNumber uid_1;
28 u8 nintendo_id_1; 28 u8 nintendo_id_1;
29 UniqueSerialNumber uid_2; 29 NFC::UniqueSerialNumber uid_2;
30 u8 nintendo_id_2; 30 u8 nintendo_id_2;
31 std::array<u8, 0x20> keygen_salt; 31 std::array<u8, 0x20> keygen_salt;
32}; 32};
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 3f9af53c8..322bde2ed 100644
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -1,8 +1,6 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 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 <array>
5
6#ifdef _MSC_VER 4#ifdef _MSC_VER
7#pragma warning(push) 5#pragma warning(push)
8#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used 6#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used
@@ -26,21 +24,22 @@
26#include "core/hle/service/ipc_helpers.h" 24#include "core/hle/service/ipc_helpers.h"
27#include "core/hle/service/mii/mii_manager.h" 25#include "core/hle/service/mii/mii_manager.h"
28#include "core/hle/service/mii/types.h" 26#include "core/hle/service/mii/types.h"
29#include "core/hle/service/nfp/amiibo_crypto.h" 27#include "core/hle/service/nfc/common/amiibo_crypto.h"
30#include "core/hle/service/nfp/nfp_device.h" 28#include "core/hle/service/nfc/common/device.h"
31#include "core/hle/service/nfp/nfp_result.h" 29#include "core/hle/service/nfc/mifare_result.h"
30#include "core/hle/service/nfc/nfc_result.h"
32#include "core/hle/service/time/time_manager.h" 31#include "core/hle/service/time/time_manager.h"
33#include "core/hle/service/time/time_zone_content_manager.h" 32#include "core/hle/service/time/time_zone_content_manager.h"
34#include "core/hle/service/time/time_zone_types.h" 33#include "core/hle/service/time/time_zone_types.h"
35 34
36namespace Service::NFP { 35namespace Service::NFC {
37NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, 36NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
38 KernelHelpers::ServiceContext& service_context_, 37 KernelHelpers::ServiceContext& service_context_,
39 Kernel::KEvent* availability_change_event_) 38 Kernel::KEvent* availability_change_event_)
40 : npad_id{npad_id_}, system{system_}, service_context{service_context_}, 39 : npad_id{npad_id_}, system{system_}, service_context{service_context_},
41 availability_change_event{availability_change_event_} { 40 availability_change_event{availability_change_event_} {
42 activate_event = service_context.CreateEvent("IUser:NFPActivateEvent"); 41 activate_event = service_context.CreateEvent("NFC:ActivateEvent");
43 deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent"); 42 deactivate_event = service_context.CreateEvent("NFC:DeactivateEvent");
44 npad_device = system.HIDCore().GetEmulatedController(npad_id); 43 npad_device = system.HIDCore().GetEmulatedController(npad_id);
45 44
46 Core::HID::ControllerUpdateCallback engine_callback{ 45 Core::HID::ControllerUpdateCallback engine_callback{
@@ -49,14 +48,11 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
49 }; 48 };
50 is_controller_set = true; 49 is_controller_set = true;
51 callback_key = npad_device->SetCallback(engine_callback); 50 callback_key = npad_device->SetCallback(engine_callback);
52
53 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
54 current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point;
55} 51}
56 52
57NfpDevice::~NfpDevice() { 53NfcDevice::~NfcDevice() {
58 activate_event->Close(); 54 service_context.CloseEvent(activate_event);
59 deactivate_event->Close(); 55 service_context.CloseEvent(deactivate_event);
60 if (!is_controller_set) { 56 if (!is_controller_set) {
61 return; 57 return;
62 } 58 }
@@ -64,7 +60,7 @@ NfpDevice::~NfpDevice() {
64 is_controller_set = false; 60 is_controller_set = false;
65}; 61};
66 62
67void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { 63void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
68 if (!is_initalized) { 64 if (!is_initalized) {
69 return; 65 return;
70 } 66 }
@@ -92,14 +88,14 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
92 const auto nfc_status = npad_device->GetNfc(); 88 const auto nfc_status = npad_device->GetNfc();
93 switch (nfc_status.state) { 89 switch (nfc_status.state) {
94 case Common::Input::NfcState::NewAmiibo: 90 case Common::Input::NfcState::NewAmiibo:
95 LoadAmiibo(nfc_status.data); 91 LoadNfcTag(nfc_status.data);
96 break; 92 break;
97 case Common::Input::NfcState::AmiiboRemoved: 93 case Common::Input::NfcState::AmiiboRemoved:
98 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { 94 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
99 break; 95 break;
100 } 96 }
101 if (device_state != DeviceState::SearchingForTag) { 97 if (device_state != DeviceState::SearchingForTag) {
102 CloseAmiibo(); 98 CloseNfcTag();
103 } 99 }
104 break; 100 break;
105 default: 101 default:
@@ -107,28 +103,29 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
107 } 103 }
108} 104}
109 105
110bool NfpDevice::LoadAmiibo(std::span<const u8> data) { 106bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
111 if (device_state != DeviceState::SearchingForTag) { 107 if (device_state != DeviceState::SearchingForTag) {
112 LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state); 108 LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
113 return false; 109 return false;
114 } 110 }
115 111
116 if (data.size() != sizeof(EncryptedNTAG215File)) { 112 if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
117 LOG_ERROR(Service_NFP, "Not an amiibo, size={}", data.size()); 113 LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
118 return false; 114 return false;
119 } 115 }
120 116
121 // TODO: Filter by allowed_protocols here 117 mifare_data.resize(data.size());
118 memcpy(mifare_data.data(), data.data(), data.size());
122 119
123 memcpy(&tag_data, data.data(), sizeof(EncryptedNTAG215File)); 120 memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
124 is_plain_amiibo = AmiiboCrypto::IsAmiiboValid(tag_data); 121 is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
125 122
126 if (is_plain_amiibo) { 123 if (is_plain_amiibo) {
127 encrypted_tag_data = AmiiboCrypto::EncodedDataToNfcData(tag_data); 124 encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(tag_data);
128 LOG_INFO(Service_NFP, "Using plain amiibo"); 125 LOG_INFO(Service_NFP, "Using plain amiibo");
129 } else { 126 } else {
130 tag_data = {}; 127 tag_data = {};
131 memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); 128 memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
132 } 129 }
133 130
134 device_state = DeviceState::TagFound; 131 device_state = DeviceState::TagFound;
@@ -137,8 +134,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
137 return true; 134 return true;
138} 135}
139 136
140void NfpDevice::CloseAmiibo() { 137void NfcDevice::CloseNfcTag() {
141 LOG_INFO(Service_NFP, "Remove amiibo"); 138 LOG_INFO(Service_NFC, "Remove nfc tag");
142 139
143 if (device_state == DeviceState::TagMounted) { 140 if (device_state == DeviceState::TagMounted) {
144 Unmount(); 141 Unmount();
@@ -147,26 +144,28 @@ void NfpDevice::CloseAmiibo() {
147 device_state = DeviceState::TagRemoved; 144 device_state = DeviceState::TagRemoved;
148 encrypted_tag_data = {}; 145 encrypted_tag_data = {};
149 tag_data = {}; 146 tag_data = {};
147 mifare_data = {};
150 activate_event->GetReadableEvent().Clear(); 148 activate_event->GetReadableEvent().Clear();
151 deactivate_event->Signal(); 149 deactivate_event->Signal();
152} 150}
153 151
154Kernel::KReadableEvent& NfpDevice::GetActivateEvent() const { 152Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
155 return activate_event->GetReadableEvent(); 153 return activate_event->GetReadableEvent();
156} 154}
157 155
158Kernel::KReadableEvent& NfpDevice::GetDeactivateEvent() const { 156Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
159 return deactivate_event->GetReadableEvent(); 157 return deactivate_event->GetReadableEvent();
160} 158}
161 159
162void NfpDevice::Initialize() { 160void NfcDevice::Initialize() {
163 device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; 161 device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
164 encrypted_tag_data = {}; 162 encrypted_tag_data = {};
165 tag_data = {}; 163 tag_data = {};
164 mifare_data = {};
166 is_initalized = true; 165 is_initalized = true;
167} 166}
168 167
169void NfpDevice::Finalize() { 168void NfcDevice::Finalize() {
170 if (device_state == DeviceState::TagMounted) { 169 if (device_state == DeviceState::TagMounted) {
171 Unmount(); 170 Unmount();
172 } 171 }
@@ -177,17 +176,17 @@ void NfpDevice::Finalize() {
177 is_initalized = false; 176 is_initalized = false;
178} 177}
179 178
180Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { 179Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
181 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { 180 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
182 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 181 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
183 return WrongDeviceState; 182 return ResultWrongDeviceState;
184 } 183 }
185 184
186 if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, 185 if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
187 Common::Input::PollingMode::NFC) != 186 Common::Input::PollingMode::NFC) !=
188 Common::Input::DriverResult::Success) { 187 Common::Input::DriverResult::Success) {
189 LOG_ERROR(Service_NFP, "Nfc not supported"); 188 LOG_ERROR(Service_NFC, "Nfc not supported");
190 return NfcDisabled; 189 return ResultNfcDisabled;
191 } 190 }
192 191
193 device_state = DeviceState::SearchingForTag; 192 device_state = DeviceState::SearchingForTag;
@@ -195,7 +194,7 @@ Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
195 return ResultSuccess; 194 return ResultSuccess;
196} 195}
197 196
198Result NfpDevice::StopDetection() { 197Result NfcDevice::StopDetection() {
199 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, 198 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
200 Common::Input::PollingMode::Active); 199 Common::Input::PollingMode::Active);
201 200
@@ -204,7 +203,7 @@ Result NfpDevice::StopDetection() {
204 } 203 }
205 204
206 if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { 205 if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
207 CloseAmiibo(); 206 CloseNfcTag();
208 } 207 }
209 208
210 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { 209 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
@@ -212,94 +211,139 @@ Result NfpDevice::StopDetection() {
212 return ResultSuccess; 211 return ResultSuccess;
213 } 212 }
214 213
215 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 214 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
216 return WrongDeviceState; 215 return ResultWrongDeviceState;
217} 216}
218 217
219Result NfpDevice::Flush() { 218Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
220 if (device_state != DeviceState::TagMounted) { 219 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
221 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 220 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
222 if (device_state == DeviceState::TagRemoved) { 221 if (device_state == DeviceState::TagRemoved) {
223 return TagRemoved; 222 return ResultTagRemoved;
224 } 223 }
225 return WrongDeviceState; 224 return ResultWrongDeviceState;
226 } 225 }
227 226
228 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 227 UniqueSerialNumber uuid = encrypted_tag_data.uuid.uid;
229 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
230 return WrongDeviceState;
231 }
232 228
233 auto& settings = tag_data.settings; 229 // Generate random UUID to bypass amiibo load limits
230 if (Settings::values.random_amiibo_id) {
231 Common::TinyMT rng{};
232 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
233 rng.GenerateRandomBytes(uuid.data(), sizeof(UniqueSerialNumber));
234 uuid[3] = 0x88 ^ uuid[0] ^ uuid[1] ^ uuid[2];
235 }
234 236
235 const auto& current_date = GetAmiiboDate(current_posix_time); 237 if (is_mifare) {
236 if (settings.write_date.raw_date != current_date.raw_date) { 238 tag_info = {
237 settings.write_date = current_date; 239 .uuid = uuid,
238 UpdateSettingsCrc(); 240 .uuid_extension = {},
241 .uuid_length = static_cast<u8>(uuid.size()),
242 .protocol = NfcProtocol::TypeA,
243 .tag_type = TagType::Type4,
244 };
245 return ResultSuccess;
239 } 246 }
240 247
241 tag_data.write_counter++; 248 // Protocol and tag type may change here
249 tag_info = {
250 .uuid = uuid,
251 .uuid_extension = {},
252 .uuid_length = static_cast<u8>(uuid.size()),
253 .protocol = NfcProtocol::TypeA,
254 .tag_type = TagType::Type2,
255 };
242 256
243 FlushWithBreak(BreakType::Normal); 257 return ResultSuccess;
258}
244 259
245 is_data_moddified = false; 260Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
261 std::span<MifareReadBlockData> read_block_data) const {
262 Result result = ResultSuccess;
246 263
247 return ResultSuccess; 264 for (std::size_t i = 0; i < parameters.size(); i++) {
265 result = ReadMifare(parameters[i], read_block_data[i]);
266 if (result.IsError()) {
267 break;
268 }
269 }
270
271 return result;
248} 272}
249 273
250Result NfpDevice::FlushDebug() { 274Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
251 if (device_state != DeviceState::TagMounted) { 275 MifareReadBlockData& read_block_data) const {
276 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
277 read_block_data.sector_number = parameter.sector_number;
278
279 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
252 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 280 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
253 if (device_state == DeviceState::TagRemoved) { 281 if (device_state == DeviceState::TagRemoved) {
254 return TagRemoved; 282 return ResultTagRemoved;
255 } 283 }
256 return WrongDeviceState; 284 return ResultWrongDeviceState;
257 } 285 }
258 286
259 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 287 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
260 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 288 return Mifare::ResultReadError;
261 return WrongDeviceState;
262 } 289 }
263 290
264 tag_data.write_counter++; 291 // TODO: Use parameter.sector_key to read encrypted data
265 292 memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock));
266 FlushWithBreak(BreakType::Normal);
267
268 is_data_moddified = false;
269 293
270 return ResultSuccess; 294 return ResultSuccess;
271} 295}
272 296
273Result NfpDevice::FlushWithBreak(BreakType break_type) { 297Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
274 if (break_type != BreakType::Normal) { 298 Result result = ResultSuccess;
275 LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
276 return WrongDeviceState;
277 }
278 299
279 std::vector<u8> data(sizeof(EncryptedNTAG215File)); 300 for (std::size_t i = 0; i < parameters.size(); i++) {
280 if (is_plain_amiibo) { 301 result = WriteMifare(parameters[i]);
281 memcpy(data.data(), &tag_data, sizeof(tag_data)); 302 if (result.IsError()) {
282 } else { 303 break;
283 if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
284 LOG_ERROR(Service_NFP, "Failed to encode data");
285 return WriteAmiiboFailed;
286 } 304 }
287
288 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
289 } 305 }
290 306
291 if (!npad_device->WriteNfc(data)) { 307 if (!npad_device->WriteNfc(mifare_data)) {
292 LOG_ERROR(Service_NFP, "Error writing to file"); 308 LOG_ERROR(Service_NFP, "Error writing to file");
293 return WriteAmiiboFailed; 309 return Mifare::ResultReadError;
310 }
311
312 return result;
313}
314
315Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
316 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
317
318 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
319 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
320 if (device_state == DeviceState::TagRemoved) {
321 return ResultTagRemoved;
322 }
323 return ResultWrongDeviceState;
324 }
325
326 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
327 return Mifare::ResultReadError;
294 } 328 }
295 329
330 // TODO: Use parameter.sector_key to encrypt the data
331 memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock));
332
333 return ResultSuccess;
334}
335
336Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
337 std::span<const u8> command_data,
338 std::span<u8> out_data) {
339 // Not implemented
296 return ResultSuccess; 340 return ResultSuccess;
297} 341}
298 342
299Result NfpDevice::Mount(MountTarget mount_target_) { 343Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) {
300 if (device_state != DeviceState::TagFound) { 344 if (device_state != DeviceState::TagFound) {
301 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 345 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
302 return WrongDeviceState; 346 return ResultWrongDeviceState;
303 } 347 }
304 348
305 // The loaded amiibo is not encrypted 349 // The loaded amiibo is not encrypted
@@ -309,22 +353,22 @@ Result NfpDevice::Mount(MountTarget mount_target_) {
309 return ResultSuccess; 353 return ResultSuccess;
310 } 354 }
311 355
312 if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { 356 if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
313 LOG_ERROR(Service_NFP, "Not an amiibo"); 357 LOG_ERROR(Service_NFP, "Not an amiibo");
314 return NotAnAmiibo; 358 return ResultNotAnAmiibo;
315 } 359 }
316 360
317 // Mark amiibos as read only when keys are missing 361 // Mark amiibos as read only when keys are missing
318 if (!AmiiboCrypto::IsKeyAvailable()) { 362 if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
319 LOG_ERROR(Service_NFP, "No keys detected"); 363 LOG_ERROR(Service_NFP, "No keys detected");
320 device_state = DeviceState::TagMounted; 364 device_state = DeviceState::TagMounted;
321 mount_target = MountTarget::Rom; 365 mount_target = NFP::MountTarget::Rom;
322 return ResultSuccess; 366 return ResultSuccess;
323 } 367 }
324 368
325 if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { 369 if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
326 LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state); 370 LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
327 return CorruptedData; 371 return ResultCorruptedData;
328 } 372 }
329 373
330 device_state = DeviceState::TagMounted; 374 device_state = DeviceState::TagMounted;
@@ -332,13 +376,13 @@ Result NfpDevice::Mount(MountTarget mount_target_) {
332 return ResultSuccess; 376 return ResultSuccess;
333} 377}
334 378
335Result NfpDevice::Unmount() { 379Result NfcDevice::Unmount() {
336 if (device_state != DeviceState::TagMounted) { 380 if (device_state != DeviceState::TagMounted) {
337 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 381 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
338 if (device_state == DeviceState::TagRemoved) { 382 if (device_state == DeviceState::TagRemoved) {
339 return TagRemoved; 383 return ResultTagRemoved;
340 } 384 }
341 return WrongDeviceState; 385 return ResultWrongDeviceState;
342 } 386 }
343 387
344 // Save data before unloading the amiibo 388 // Save data before unloading the amiibo
@@ -347,43 +391,123 @@ Result NfpDevice::Unmount() {
347 } 391 }
348 392
349 device_state = DeviceState::TagFound; 393 device_state = DeviceState::TagFound;
350 mount_target = MountTarget::None; 394 mount_target = NFP::MountTarget::None;
351 is_app_area_open = false; 395 is_app_area_open = false;
352 396
353 return ResultSuccess; 397 return ResultSuccess;
354} 398}
355 399
356Result NfpDevice::GetTagInfo(TagInfo& tag_info) const { 400Result NfcDevice::Flush() {
357 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { 401 if (device_state != DeviceState::TagMounted) {
358 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 402 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
359 if (device_state == DeviceState::TagRemoved) { 403 if (device_state == DeviceState::TagRemoved) {
360 return TagRemoved; 404 return ResultTagRemoved;
361 } 405 }
362 return WrongDeviceState; 406 return ResultWrongDeviceState;
363 } 407 }
364 408
365 tag_info = { 409 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
366 .uuid = encrypted_tag_data.uuid.uid, 410 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
367 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), 411 return ResultWrongDeviceState;
368 .protocol = TagProtocol::TypeA, 412 }
369 .tag_type = TagType::Type2, 413
370 }; 414 auto& settings = tag_data.settings;
415
416 const auto& current_date = GetAmiiboDate(GetCurrentPosixTime());
417 if (settings.write_date.raw_date != current_date.raw_date) {
418 settings.write_date = current_date;
419 UpdateSettingsCrc();
420 }
421
422 tag_data.write_counter++;
423
424 FlushWithBreak(NFP::BreakType::Normal);
425
426 is_data_moddified = false;
427
428 return ResultSuccess;
429}
430
431Result NfcDevice::FlushDebug() {
432 if (device_state != DeviceState::TagMounted) {
433 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
434 if (device_state == DeviceState::TagRemoved) {
435 return ResultTagRemoved;
436 }
437 return ResultWrongDeviceState;
438 }
439
440 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
441 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
442 return ResultWrongDeviceState;
443 }
444
445 tag_data.write_counter++;
446
447 FlushWithBreak(NFP::BreakType::Normal);
448
449 is_data_moddified = false;
450
451 return ResultSuccess;
452}
453
454Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
455 if (break_type != NFP::BreakType::Normal) {
456 LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
457 return ResultWrongDeviceState;
458 }
459
460 std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
461 if (is_plain_amiibo) {
462 memcpy(data.data(), &tag_data, sizeof(tag_data));
463 } else {
464 if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
465 LOG_ERROR(Service_NFP, "Failed to encode data");
466 return ResultWriteAmiiboFailed;
467 }
468
469 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
470 }
471
472 if (!npad_device->WriteNfc(data)) {
473 LOG_ERROR(Service_NFP, "Error writing to file");
474 return ResultWriteAmiiboFailed;
475 }
371 476
372 return ResultSuccess; 477 return ResultSuccess;
373} 478}
374 479
375Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { 480Result NfcDevice::Restore() {
376 if (device_state != DeviceState::TagMounted) { 481 if (device_state != DeviceState::TagMounted) {
377 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 482 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
378 if (device_state == DeviceState::TagRemoved) { 483 if (device_state == DeviceState::TagRemoved) {
379 return TagRemoved; 484 return ResultTagRemoved;
380 } 485 }
381 return WrongDeviceState; 486 return ResultWrongDeviceState;
382 } 487 }
383 488
384 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 489 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
490 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
491 return ResultWrongDeviceState;
492 }
493
494 // TODO: Load amiibo from backup on system
495 LOG_ERROR(Service_NFP, "Not Implemented");
496 return ResultSuccess;
497}
498
499Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
500 if (device_state != DeviceState::TagMounted) {
501 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
502 if (device_state == DeviceState::TagRemoved) {
503 return ResultTagRemoved;
504 }
505 return ResultWrongDeviceState;
506 }
507
508 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
385 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 509 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
386 return WrongDeviceState; 510 return ResultWrongDeviceState;
387 } 511 }
388 512
389 const auto& settings = tag_data.settings; 513 const auto& settings = tag_data.settings;
@@ -393,21 +517,22 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const {
393 .last_write_date = settings.write_date.GetWriteDate(), 517 .last_write_date = settings.write_date.GetWriteDate(),
394 .write_counter = tag_data.write_counter, 518 .write_counter = tag_data.write_counter,
395 .version = tag_data.amiibo_version, 519 .version = tag_data.amiibo_version,
396 .application_area_size = sizeof(ApplicationArea), 520 .application_area_size = sizeof(NFP::ApplicationArea),
397 }; 521 };
398 return ResultSuccess; 522 return ResultSuccess;
399} 523}
400 524
401Result NfpDevice::GetModelInfo(ModelInfo& model_info) const { 525Result NfcDevice::GetModelInfo(NFP::ModelInfo& model_info) const {
402 if (device_state != DeviceState::TagMounted) { 526 if (device_state != DeviceState::TagMounted) {
403 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 527 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
404 if (device_state == DeviceState::TagRemoved) { 528 if (device_state == DeviceState::TagRemoved) {
405 return TagRemoved; 529 return ResultTagRemoved;
406 } 530 }
407 return WrongDeviceState; 531 return ResultWrongDeviceState;
408 } 532 }
409 533
410 const auto& model_info_data = encrypted_tag_data.user_memory.model_info; 534 const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
535
411 model_info = { 536 model_info = {
412 .character_id = model_info_data.character_id, 537 .character_id = model_info_data.character_id,
413 .character_variant = model_info_data.character_variant, 538 .character_variant = model_info_data.character_variant,
@@ -418,22 +543,22 @@ Result NfpDevice::GetModelInfo(ModelInfo& model_info) const {
418 return ResultSuccess; 543 return ResultSuccess;
419} 544}
420 545
421Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { 546Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const {
422 if (device_state != DeviceState::TagMounted) { 547 if (device_state != DeviceState::TagMounted) {
423 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 548 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
424 if (device_state == DeviceState::TagRemoved) { 549 if (device_state == DeviceState::TagRemoved) {
425 return TagRemoved; 550 return ResultTagRemoved;
426 } 551 }
427 return WrongDeviceState; 552 return ResultWrongDeviceState;
428 } 553 }
429 554
430 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 555 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
431 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 556 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
432 return WrongDeviceState; 557 return ResultWrongDeviceState;
433 } 558 }
434 559
435 if (tag_data.settings.settings.amiibo_initialized == 0) { 560 if (tag_data.settings.settings.amiibo_initialized == 0) {
436 return RegistrationIsNotInitialized; 561 return ResultRegistrationIsNotInitialized;
437 } 562 }
438 563
439 Service::Mii::MiiManager manager; 564 Service::Mii::MiiManager manager;
@@ -450,22 +575,22 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const {
450 return ResultSuccess; 575 return ResultSuccess;
451} 576}
452 577
453Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const { 578Result NfcDevice::GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const {
454 if (device_state != DeviceState::TagMounted) { 579 if (device_state != DeviceState::TagMounted) {
455 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 580 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
456 if (device_state == DeviceState::TagRemoved) { 581 if (device_state == DeviceState::TagRemoved) {
457 return TagRemoved; 582 return ResultTagRemoved;
458 } 583 }
459 return WrongDeviceState; 584 return ResultWrongDeviceState;
460 } 585 }
461 586
462 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 587 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
463 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 588 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
464 return WrongDeviceState; 589 return ResultWrongDeviceState;
465 } 590 }
466 591
467 if (tag_data.settings.settings.amiibo_initialized == 0) { 592 if (tag_data.settings.settings.amiibo_initialized == 0) {
468 return RegistrationIsNotInitialized; 593 return ResultRegistrationIsNotInitialized;
469 } 594 }
470 595
471 Service::Mii::MiiManager manager; 596 Service::Mii::MiiManager manager;
@@ -482,18 +607,18 @@ Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) con
482 return ResultSuccess; 607 return ResultSuccess;
483} 608}
484 609
485Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { 610Result NfcDevice::GetAdminInfo(NFP::AdminInfo& admin_info) const {
486 if (device_state != DeviceState::TagMounted) { 611 if (device_state != DeviceState::TagMounted) {
487 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 612 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
488 if (device_state == DeviceState::TagRemoved) { 613 if (device_state == DeviceState::TagRemoved) {
489 return TagRemoved; 614 return ResultTagRemoved;
490 } 615 }
491 return WrongDeviceState; 616 return ResultWrongDeviceState;
492 } 617 }
493 618
494 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 619 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
495 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 620 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
496 return WrongDeviceState; 621 return ResultWrongDeviceState;
497 } 622 }
498 623
499 u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4); 624 u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4);
@@ -503,17 +628,18 @@ Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
503 628
504 u64 application_id = 0; 629 u64 application_id = 0;
505 u32 application_area_id = 0; 630 u32 application_area_id = 0;
506 AppAreaVersion app_area_version = AppAreaVersion::NotSet; 631 NFP::AppAreaVersion app_area_version = NFP::AppAreaVersion::NotSet;
507 if (tag_data.settings.settings.appdata_initialized != 0) { 632 if (tag_data.settings.settings.appdata_initialized != 0) {
508 application_id = tag_data.application_id; 633 application_id = tag_data.application_id;
509 app_area_version = 634 app_area_version = static_cast<NFP::AppAreaVersion>(
510 static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf); 635 application_id >> NFP::application_id_version_offset & 0xf);
511 636
512 // Restore application id to original value 637 // Restore application id to original value
513 if (application_id >> 0x38 != 0) { 638 if (application_id >> 0x38 != 0) {
514 const u8 application_byte = tag_data.application_id_byte & 0xf; 639 const u8 application_byte = tag_data.application_id_byte & 0xf;
515 application_id = RemoveVersionByte(application_id) | 640 application_id =
516 (static_cast<u64>(application_byte) << application_id_version_offset); 641 RemoveVersionByte(application_id) |
642 (static_cast<u64>(application_byte) << NFP::application_id_version_offset);
517 } 643 }
518 644
519 application_area_id = tag_data.application_area_id; 645 application_area_id = tag_data.application_area_id;
@@ -532,25 +658,26 @@ Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
532 return ResultSuccess; 658 return ResultSuccess;
533} 659}
534 660
535Result NfpDevice::DeleteRegisterInfo() { 661Result NfcDevice::DeleteRegisterInfo() {
536 if (device_state != DeviceState::TagMounted) { 662 if (device_state != DeviceState::TagMounted) {
537 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 663 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
538 if (device_state == DeviceState::TagRemoved) { 664 if (device_state == DeviceState::TagRemoved) {
539 return TagRemoved; 665 return ResultTagRemoved;
540 } 666 }
541 return WrongDeviceState; 667 return ResultWrongDeviceState;
542 } 668 }
543 669
544 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 670 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
545 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 671 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
546 return WrongDeviceState; 672 return ResultWrongDeviceState;
547 } 673 }
548 674
549 if (tag_data.settings.settings.amiibo_initialized == 0) { 675 if (tag_data.settings.settings.amiibo_initialized == 0) {
550 return RegistrationIsNotInitialized; 676 return ResultRegistrationIsNotInitialized;
551 } 677 }
552 678
553 Common::TinyMT rng{}; 679 Common::TinyMT rng{};
680 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
554 rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii)); 681 rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii));
555 rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name)); 682 rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name));
556 rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8)); 683 rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8));
@@ -564,18 +691,18 @@ Result NfpDevice::DeleteRegisterInfo() {
564 return Flush(); 691 return Flush();
565} 692}
566 693
567Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) { 694Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info) {
568 if (device_state != DeviceState::TagMounted) { 695 if (device_state != DeviceState::TagMounted) {
569 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 696 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
570 if (device_state == DeviceState::TagRemoved) { 697 if (device_state == DeviceState::TagRemoved) {
571 return TagRemoved; 698 return ResultTagRemoved;
572 } 699 }
573 return WrongDeviceState; 700 return ResultWrongDeviceState;
574 } 701 }
575 702
576 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 703 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
577 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 704 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
578 return WrongDeviceState; 705 return ResultWrongDeviceState;
579 } 706 }
580 707
581 Service::Mii::MiiManager manager; 708 Service::Mii::MiiManager manager;
@@ -583,11 +710,11 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
583 auto& settings = tag_data.settings; 710 auto& settings = tag_data.settings;
584 711
585 if (tag_data.settings.settings.amiibo_initialized == 0) { 712 if (tag_data.settings.settings.amiibo_initialized == 0) {
586 settings.init_date = GetAmiiboDate(current_posix_time); 713 settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
587 settings.write_date.raw_date = 0; 714 settings.write_date.raw_date = 0;
588 } 715 }
589 716
590 SetAmiiboName(settings, amiibo_name); 717 SetAmiiboName(settings, register_info.amiibo_name);
591 tag_data.owner_mii = manager.BuildFromStoreData(mii); 718 tag_data.owner_mii = manager.BuildFromStoreData(mii);
592 tag_data.mii_extension = manager.SetFromStoreData(mii); 719 tag_data.mii_extension = manager.SetFromStoreData(mii);
593 tag_data.unknown = 0; 720 tag_data.unknown = 0;
@@ -601,18 +728,18 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
601 return Flush(); 728 return Flush();
602} 729}
603 730
604Result NfpDevice::RestoreAmiibo() { 731Result NfcDevice::RestoreAmiibo() {
605 if (device_state != DeviceState::TagMounted) { 732 if (device_state != DeviceState::TagMounted) {
606 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 733 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
607 if (device_state == DeviceState::TagRemoved) { 734 if (device_state == DeviceState::TagRemoved) {
608 return TagRemoved; 735 return ResultTagRemoved;
609 } 736 }
610 return WrongDeviceState; 737 return ResultWrongDeviceState;
611 } 738 }
612 739
613 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 740 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
614 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 741 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
615 return WrongDeviceState; 742 return ResultWrongDeviceState;
616 } 743 }
617 744
618 // TODO: Load amiibo from backup on system 745 // TODO: Load amiibo from backup on system
@@ -620,7 +747,7 @@ Result NfpDevice::RestoreAmiibo() {
620 return ResultSuccess; 747 return ResultSuccess;
621} 748}
622 749
623Result NfpDevice::Format() { 750Result NfcDevice::Format() {
624 auto result1 = DeleteApplicationArea(); 751 auto result1 = DeleteApplicationArea();
625 auto result2 = DeleteRegisterInfo(); 752 auto result2 = DeleteRegisterInfo();
626 753
@@ -635,28 +762,28 @@ Result NfpDevice::Format() {
635 return Flush(); 762 return Flush();
636} 763}
637 764
638Result NfpDevice::OpenApplicationArea(u32 access_id) { 765Result NfcDevice::OpenApplicationArea(u32 access_id) {
639 if (device_state != DeviceState::TagMounted) { 766 if (device_state != DeviceState::TagMounted) {
640 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 767 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
641 if (device_state == DeviceState::TagRemoved) { 768 if (device_state == DeviceState::TagRemoved) {
642 return TagRemoved; 769 return ResultTagRemoved;
643 } 770 }
644 return WrongDeviceState; 771 return ResultWrongDeviceState;
645 } 772 }
646 773
647 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 774 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
648 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 775 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
649 return WrongDeviceState; 776 return ResultWrongDeviceState;
650 } 777 }
651 778
652 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 779 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
653 LOG_WARNING(Service_NFP, "Application area is not initialized"); 780 LOG_WARNING(Service_NFP, "Application area is not initialized");
654 return ApplicationAreaIsNotInitialized; 781 return ResultApplicationAreaIsNotInitialized;
655 } 782 }
656 783
657 if (tag_data.application_area_id != access_id) { 784 if (tag_data.application_area_id != access_id) {
658 LOG_WARNING(Service_NFP, "Wrong application area id"); 785 LOG_WARNING(Service_NFP, "Wrong application area id");
659 return WrongApplicationAreaId; 786 return ResultWrongApplicationAreaId;
660 } 787 }
661 788
662 is_app_area_open = true; 789 is_app_area_open = true;
@@ -664,25 +791,25 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) {
664 return ResultSuccess; 791 return ResultSuccess;
665} 792}
666 793
667Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { 794Result NfcDevice::GetApplicationAreaId(u32& application_area_id) const {
668 application_area_id = {}; 795 application_area_id = {};
669 796
670 if (device_state != DeviceState::TagMounted) { 797 if (device_state != DeviceState::TagMounted) {
671 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 798 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
672 if (device_state == DeviceState::TagRemoved) { 799 if (device_state == DeviceState::TagRemoved) {
673 return TagRemoved; 800 return ResultTagRemoved;
674 } 801 }
675 return WrongDeviceState; 802 return ResultWrongDeviceState;
676 } 803 }
677 804
678 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 805 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
679 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 806 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
680 return WrongDeviceState; 807 return ResultWrongDeviceState;
681 } 808 }
682 809
683 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 810 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
684 LOG_WARNING(Service_NFP, "Application area is not initialized"); 811 LOG_WARNING(Service_NFP, "Application area is not initialized");
685 return ApplicationAreaIsNotInitialized; 812 return ResultApplicationAreaIsNotInitialized;
686 } 813 }
687 814
688 application_area_id = tag_data.application_area_id; 815 application_area_id = tag_data.application_area_id;
@@ -690,75 +817,73 @@ Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
690 return ResultSuccess; 817 return ResultSuccess;
691} 818}
692 819
693Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { 820Result NfcDevice::GetApplicationArea(std::span<u8> data) const {
694 if (device_state != DeviceState::TagMounted) { 821 if (device_state != DeviceState::TagMounted) {
695 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 822 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
696 if (device_state == DeviceState::TagRemoved) { 823 if (device_state == DeviceState::TagRemoved) {
697 return TagRemoved; 824 return ResultTagRemoved;
698 } 825 }
699 return WrongDeviceState; 826 return ResultWrongDeviceState;
700 } 827 }
701 828
702 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 829 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
703 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 830 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
704 return WrongDeviceState; 831 return ResultWrongDeviceState;
705 } 832 }
706 833
707 if (!is_app_area_open) { 834 if (!is_app_area_open) {
708 LOG_ERROR(Service_NFP, "Application area is not open"); 835 LOG_ERROR(Service_NFP, "Application area is not open");
709 return WrongDeviceState; 836 return ResultWrongDeviceState;
710 } 837 }
711 838
712 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 839 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
713 LOG_ERROR(Service_NFP, "Application area is not initialized"); 840 LOG_ERROR(Service_NFP, "Application area is not initialized");
714 return ApplicationAreaIsNotInitialized; 841 return ResultApplicationAreaIsNotInitialized;
715 }
716
717 if (data.size() > sizeof(ApplicationArea)) {
718 data.resize(sizeof(ApplicationArea));
719 } 842 }
720 843
721 memcpy(data.data(), tag_data.application_area.data(), data.size()); 844 memcpy(data.data(), tag_data.application_area.data(),
845 std::min(data.size(), sizeof(NFP::ApplicationArea)));
722 846
723 return ResultSuccess; 847 return ResultSuccess;
724} 848}
725 849
726Result NfpDevice::SetApplicationArea(std::span<const u8> data) { 850Result NfcDevice::SetApplicationArea(std::span<const u8> data) {
727 if (device_state != DeviceState::TagMounted) { 851 if (device_state != DeviceState::TagMounted) {
728 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 852 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
729 if (device_state == DeviceState::TagRemoved) { 853 if (device_state == DeviceState::TagRemoved) {
730 return TagRemoved; 854 return ResultTagRemoved;
731 } 855 }
732 return WrongDeviceState; 856 return ResultWrongDeviceState;
733 } 857 }
734 858
735 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 859 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
736 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 860 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
737 return WrongDeviceState; 861 return ResultWrongDeviceState;
738 } 862 }
739 863
740 if (!is_app_area_open) { 864 if (!is_app_area_open) {
741 LOG_ERROR(Service_NFP, "Application area is not open"); 865 LOG_ERROR(Service_NFP, "Application area is not open");
742 return WrongDeviceState; 866 return ResultWrongDeviceState;
743 } 867 }
744 868
745 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 869 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
746 LOG_ERROR(Service_NFP, "Application area is not initialized"); 870 LOG_ERROR(Service_NFP, "Application area is not initialized");
747 return ApplicationAreaIsNotInitialized; 871 return ResultApplicationAreaIsNotInitialized;
748 } 872 }
749 873
750 if (data.size() > sizeof(ApplicationArea)) { 874 if (data.size() > sizeof(NFP::ApplicationArea)) {
751 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size()); 875 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
752 return ResultUnknown; 876 return ResultUnknown;
753 } 877 }
754 878
755 Common::TinyMT rng{}; 879 Common::TinyMT rng{};
880 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
756 std::memcpy(tag_data.application_area.data(), data.data(), data.size()); 881 std::memcpy(tag_data.application_area.data(), data.data(), data.size());
757 // Fill remaining data with random numbers 882 // Fill remaining data with random numbers
758 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), 883 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
759 sizeof(ApplicationArea) - data.size()); 884 sizeof(NFP::ApplicationArea) - data.size());
760 885
761 if (tag_data.application_write_counter != counter_limit) { 886 if (tag_data.application_write_counter != NFP::counter_limit) {
762 tag_data.application_write_counter++; 887 tag_data.application_write_counter++;
763 } 888 }
764 889
@@ -767,64 +892,65 @@ Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
767 return ResultSuccess; 892 return ResultSuccess;
768} 893}
769 894
770Result NfpDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) { 895Result NfcDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
771 if (device_state != DeviceState::TagMounted) { 896 if (device_state != DeviceState::TagMounted) {
772 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 897 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
773 if (device_state == DeviceState::TagRemoved) { 898 if (device_state == DeviceState::TagRemoved) {
774 return TagRemoved; 899 return ResultTagRemoved;
775 } 900 }
776 return WrongDeviceState; 901 return ResultWrongDeviceState;
777 } 902 }
778 903
779 if (tag_data.settings.settings.appdata_initialized.Value() != 0) { 904 if (tag_data.settings.settings.appdata_initialized.Value() != 0) {
780 LOG_ERROR(Service_NFP, "Application area already exist"); 905 LOG_ERROR(Service_NFP, "Application area already exist");
781 return ApplicationAreaExist; 906 return ResultApplicationAreaExist;
782 } 907 }
783 908
784 return RecreateApplicationArea(access_id, data); 909 return RecreateApplicationArea(access_id, data);
785} 910}
786 911
787Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) { 912Result NfcDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
788 if (device_state != DeviceState::TagMounted) { 913 if (device_state != DeviceState::TagMounted) {
789 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 914 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
790 if (device_state == DeviceState::TagRemoved) { 915 if (device_state == DeviceState::TagRemoved) {
791 return TagRemoved; 916 return ResultTagRemoved;
792 } 917 }
793 return WrongDeviceState; 918 return ResultWrongDeviceState;
794 } 919 }
795 920
796 if (is_app_area_open) { 921 if (is_app_area_open) {
797 LOG_ERROR(Service_NFP, "Application area is open"); 922 LOG_ERROR(Service_NFP, "Application area is open");
798 return WrongDeviceState; 923 return ResultWrongDeviceState;
799 } 924 }
800 925
801 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 926 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
802 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 927 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
803 return WrongDeviceState; 928 return ResultWrongDeviceState;
804 } 929 }
805 930
806 if (data.size() > sizeof(ApplicationArea)) { 931 if (data.size() > sizeof(NFP::ApplicationArea)) {
807 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size()); 932 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
808 return WrongApplicationAreaSize; 933 return ResultWrongApplicationAreaSize;
809 } 934 }
810 935
811 Common::TinyMT rng{}; 936 Common::TinyMT rng{};
937 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
812 std::memcpy(tag_data.application_area.data(), data.data(), data.size()); 938 std::memcpy(tag_data.application_area.data(), data.data(), data.size());
813 // Fill remaining data with random numbers 939 // Fill remaining data with random numbers
814 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), 940 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
815 sizeof(ApplicationArea) - data.size()); 941 sizeof(NFP::ApplicationArea) - data.size());
816 942
817 if (tag_data.application_write_counter != counter_limit) { 943 if (tag_data.application_write_counter != NFP::counter_limit) {
818 tag_data.application_write_counter++; 944 tag_data.application_write_counter++;
819 } 945 }
820 946
821 const u64 application_id = system.GetApplicationProcessProgramID(); 947 const u64 application_id = system.GetApplicationProcessProgramID();
822 948
823 tag_data.application_id_byte = 949 tag_data.application_id_byte =
824 static_cast<u8>(application_id >> application_id_version_offset & 0xf); 950 static_cast<u8>(application_id >> NFP::application_id_version_offset & 0xf);
825 tag_data.application_id = 951 tag_data.application_id =
826 RemoveVersionByte(application_id) | 952 RemoveVersionByte(application_id) | (static_cast<u64>(NFP::AppAreaVersion::NintendoSwitch)
827 (static_cast<u64>(AppAreaVersion::NintendoSwitch) << application_id_version_offset); 953 << NFP::application_id_version_offset);
828 tag_data.settings.settings.appdata_initialized.Assign(1); 954 tag_data.settings.settings.appdata_initialized.Assign(1);
829 tag_data.application_area_id = access_id; 955 tag_data.application_area_id = access_id;
830 tag_data.unknown = {}; 956 tag_data.unknown = {};
@@ -835,30 +961,31 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat
835 return Flush(); 961 return Flush();
836} 962}
837 963
838Result NfpDevice::DeleteApplicationArea() { 964Result NfcDevice::DeleteApplicationArea() {
839 if (device_state != DeviceState::TagMounted) { 965 if (device_state != DeviceState::TagMounted) {
840 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 966 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
841 if (device_state == DeviceState::TagRemoved) { 967 if (device_state == DeviceState::TagRemoved) {
842 return TagRemoved; 968 return ResultTagRemoved;
843 } 969 }
844 return WrongDeviceState; 970 return ResultWrongDeviceState;
845 } 971 }
846 972
847 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 973 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
848 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 974 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
849 return WrongDeviceState; 975 return ResultWrongDeviceState;
850 } 976 }
851 977
852 if (tag_data.settings.settings.appdata_initialized == 0) { 978 if (tag_data.settings.settings.appdata_initialized == 0) {
853 return ApplicationAreaIsNotInitialized; 979 return ResultApplicationAreaIsNotInitialized;
854 } 980 }
855 981
856 if (tag_data.application_write_counter != counter_limit) { 982 if (tag_data.application_write_counter != NFP::counter_limit) {
857 tag_data.application_write_counter++; 983 tag_data.application_write_counter++;
858 } 984 }
859 985
860 Common::TinyMT rng{}; 986 Common::TinyMT rng{};
861 rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea)); 987 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
988 rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(NFP::ApplicationArea));
862 rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64)); 989 rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64));
863 rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32)); 990 rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
864 rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8)); 991 rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));
@@ -872,18 +999,18 @@ Result NfpDevice::DeleteApplicationArea() {
872 return Flush(); 999 return Flush();
873} 1000}
874 1001
875Result NfpDevice::ExistApplicationArea(bool& has_application_area) { 1002Result NfcDevice::ExistsApplicationArea(bool& has_application_area) const {
876 if (device_state != DeviceState::TagMounted) { 1003 if (device_state != DeviceState::TagMounted) {
877 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1004 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
878 if (device_state == DeviceState::TagRemoved) { 1005 if (device_state == DeviceState::TagRemoved) {
879 return TagRemoved; 1006 return ResultTagRemoved;
880 } 1007 }
881 return WrongDeviceState; 1008 return ResultWrongDeviceState;
882 } 1009 }
883 1010
884 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1011 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
885 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1012 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
886 return WrongDeviceState; 1013 return ResultWrongDeviceState;
887 } 1014 }
888 1015
889 has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0; 1016 has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0;
@@ -891,21 +1018,21 @@ Result NfpDevice::ExistApplicationArea(bool& has_application_area) {
891 return ResultSuccess; 1018 return ResultSuccess;
892} 1019}
893 1020
894Result NfpDevice::GetAll(NfpData& data) const { 1021Result NfcDevice::GetAll(NFP::NfpData& data) const {
895 if (device_state != DeviceState::TagMounted) { 1022 if (device_state != DeviceState::TagMounted) {
896 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1023 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
897 if (device_state == DeviceState::TagRemoved) { 1024 if (device_state == DeviceState::TagRemoved) {
898 return TagRemoved; 1025 return ResultTagRemoved;
899 } 1026 }
900 return WrongDeviceState; 1027 return ResultWrongDeviceState;
901 } 1028 }
902 1029
903 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1030 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
904 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1031 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
905 return WrongDeviceState; 1032 return ResultWrongDeviceState;
906 } 1033 }
907 1034
908 CommonInfo common_info{}; 1035 NFP::CommonInfo common_info{};
909 Service::Mii::MiiManager manager; 1036 Service::Mii::MiiManager manager;
910 const u64 application_id = tag_data.application_id; 1037 const u64 application_id = tag_data.application_id;
911 1038
@@ -930,8 +1057,8 @@ Result NfpDevice::GetAll(NfpData& data) const {
930 .settings_crc_counter = tag_data.settings.crc_counter, 1057 .settings_crc_counter = tag_data.settings.crc_counter,
931 .font_region = tag_data.settings.settings.font_region, 1058 .font_region = tag_data.settings.settings.font_region,
932 .tag_type = PackedTagType::Type2, 1059 .tag_type = PackedTagType::Type2,
933 .console_type = 1060 .console_type = static_cast<NFP::AppAreaVersion>(
934 static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf), 1061 application_id >> NFP::application_id_version_offset & 0xf),
935 .application_id_byte = tag_data.application_id_byte, 1062 .application_id_byte = tag_data.application_id_byte,
936 .application_area = tag_data.application_area, 1063 .application_area = tag_data.application_area,
937 }; 1064 };
@@ -939,18 +1066,18 @@ Result NfpDevice::GetAll(NfpData& data) const {
939 return ResultSuccess; 1066 return ResultSuccess;
940} 1067}
941 1068
942Result NfpDevice::SetAll(const NfpData& data) { 1069Result NfcDevice::SetAll(const NFP::NfpData& data) {
943 if (device_state != DeviceState::TagMounted) { 1070 if (device_state != DeviceState::TagMounted) {
944 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1071 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
945 if (device_state == DeviceState::TagRemoved) { 1072 if (device_state == DeviceState::TagRemoved) {
946 return TagRemoved; 1073 return ResultTagRemoved;
947 } 1074 }
948 return WrongDeviceState; 1075 return ResultWrongDeviceState;
949 } 1076 }
950 1077
951 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1078 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
952 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1079 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
953 return WrongDeviceState; 1080 return ResultWrongDeviceState;
954 } 1081 }
955 1082
956 tag_data.constant_value = data.magic; 1083 tag_data.constant_value = data.magic;
@@ -977,18 +1104,18 @@ Result NfpDevice::SetAll(const NfpData& data) {
977 return ResultSuccess; 1104 return ResultSuccess;
978} 1105}
979 1106
980Result NfpDevice::BreakTag(BreakType break_type) { 1107Result NfcDevice::BreakTag(NFP::BreakType break_type) {
981 if (device_state != DeviceState::TagMounted) { 1108 if (device_state != DeviceState::TagMounted) {
982 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1109 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
983 if (device_state == DeviceState::TagRemoved) { 1110 if (device_state == DeviceState::TagRemoved) {
984 return TagRemoved; 1111 return ResultTagRemoved;
985 } 1112 }
986 return WrongDeviceState; 1113 return ResultWrongDeviceState;
987 } 1114 }
988 1115
989 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1116 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
990 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1117 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
991 return WrongDeviceState; 1118 return ResultWrongDeviceState;
992 } 1119 }
993 1120
994 // TODO: Complete this implementation 1121 // TODO: Complete this implementation
@@ -996,28 +1123,28 @@ Result NfpDevice::BreakTag(BreakType break_type) {
996 return FlushWithBreak(break_type); 1123 return FlushWithBreak(break_type);
997} 1124}
998 1125
999Result NfpDevice::ReadBackupData() { 1126Result NfcDevice::ReadBackupData(std::span<u8> data) const {
1000 // Not implemented 1127 // Not implemented
1001 return ResultSuccess; 1128 return ResultSuccess;
1002} 1129}
1003 1130
1004Result NfpDevice::WriteBackupData() { 1131Result NfcDevice::WriteBackupData(std::span<const u8> data) {
1005 // Not implemented 1132 // Not implemented
1006 return ResultSuccess; 1133 return ResultSuccess;
1007} 1134}
1008 1135
1009Result NfpDevice::WriteNtf() { 1136Result NfcDevice::WriteNtf(std::span<const u8> data) {
1010 if (device_state != DeviceState::TagMounted) { 1137 if (device_state != DeviceState::TagMounted) {
1011 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1138 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
1012 if (device_state == DeviceState::TagRemoved) { 1139 if (device_state == DeviceState::TagRemoved) {
1013 return TagRemoved; 1140 return ResultTagRemoved;
1014 } 1141 }
1015 return WrongDeviceState; 1142 return ResultWrongDeviceState;
1016 } 1143 }
1017 1144
1018 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1145 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
1019 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1146 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
1020 return WrongDeviceState; 1147 return ResultWrongDeviceState;
1021 } 1148 }
1022 1149
1023 // Not implemented 1150 // Not implemented
@@ -1025,29 +1152,12 @@ Result NfpDevice::WriteNtf() {
1025 return ResultSuccess; 1152 return ResultSuccess;
1026} 1153}
1027 1154
1028u64 NfpDevice::GetHandle() const { 1155NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) const {
1029 // Generate a handle based of the npad id 1156 std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
1030 return static_cast<u64>(npad_id); 1157 NFP::AmiiboName amiibo_name{};
1031}
1032
1033u32 NfpDevice::GetApplicationAreaSize() const {
1034 return sizeof(ApplicationArea);
1035}
1036
1037DeviceState NfpDevice::GetCurrentState() const {
1038 return device_state;
1039}
1040
1041Core::HID::NpadIdType NfpDevice::GetNpadId() const {
1042 return npad_id;
1043}
1044
1045AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const {
1046 std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
1047 AmiiboName amiibo_name{};
1048 1158
1049 // Convert from big endian to little endian 1159 // Convert from big endian to little endian
1050 for (std::size_t i = 0; i < amiibo_name_length; i++) { 1160 for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
1051 settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]); 1161 settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
1052 } 1162 }
1053 1163
@@ -1058,8 +1168,8 @@ AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const {
1058 return amiibo_name; 1168 return amiibo_name;
1059} 1169}
1060 1170
1061void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name) { 1171void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) {
1062 std::array<char16_t, amiibo_name_length> settings_amiibo_name{}; 1172 std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
1063 1173
1064 // Convert from utf8 to utf16 1174 // Convert from utf8 to utf16
1065 const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data()); 1175 const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data());
@@ -1067,16 +1177,16 @@ void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo
1067 amiibo_name_utf16.size() * sizeof(char16_t)); 1177 amiibo_name_utf16.size() * sizeof(char16_t));
1068 1178
1069 // Convert from little endian to big endian 1179 // Convert from little endian to big endian
1070 for (std::size_t i = 0; i < amiibo_name_length; i++) { 1180 for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
1071 settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]); 1181 settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]);
1072 } 1182 }
1073} 1183}
1074 1184
1075AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const { 1185NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
1076 const auto& time_zone_manager = 1186 const auto& time_zone_manager =
1077 system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); 1187 system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
1078 Time::TimeZone::CalendarInfo calendar_info{}; 1188 Time::TimeZone::CalendarInfo calendar_info{};
1079 AmiiboDate amiibo_date{}; 1189 NFP::AmiiboDate amiibo_date{};
1080 1190
1081 amiibo_date.SetYear(2000); 1191 amiibo_date.SetYear(2000);
1082 amiibo_date.SetMonth(1); 1192 amiibo_date.SetMonth(1);
@@ -1091,14 +1201,19 @@ AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const {
1091 return amiibo_date; 1201 return amiibo_date;
1092} 1202}
1093 1203
1094u64 NfpDevice::RemoveVersionByte(u64 application_id) const { 1204u64 NfcDevice::GetCurrentPosixTime() const {
1095 return application_id & ~(0xfULL << application_id_version_offset); 1205 auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
1206 return standard_steady_clock.GetCurrentTimePoint(system).time_point;
1096} 1207}
1097 1208
1098void NfpDevice::UpdateSettingsCrc() { 1209u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
1210 return application_id & ~(0xfULL << NFP::application_id_version_offset);
1211}
1212
1213void NfcDevice::UpdateSettingsCrc() {
1099 auto& settings = tag_data.settings; 1214 auto& settings = tag_data.settings;
1100 1215
1101 if (settings.crc_counter != counter_limit) { 1216 if (settings.crc_counter != NFP::counter_limit) {
1102 settings.crc_counter++; 1217 settings.crc_counter++;
1103 } 1218 }
1104 1219
@@ -1109,7 +1224,7 @@ void NfpDevice::UpdateSettingsCrc() {
1109 settings.crc = crc.checksum(); 1224 settings.crc = crc.checksum();
1110} 1225}
1111 1226
1112void NfpDevice::UpdateRegisterInfoCrc() { 1227void NfcDevice::UpdateRegisterInfoCrc() {
1113#pragma pack(push, 1) 1228#pragma pack(push, 1)
1114 struct CrcData { 1229 struct CrcData {
1115 Mii::Ver3StoreData mii; 1230 Mii::Ver3StoreData mii;
@@ -1134,4 +1249,18 @@ void NfpDevice::UpdateRegisterInfoCrc() {
1134 tag_data.register_info_crc = crc.checksum(); 1249 tag_data.register_info_crc = crc.checksum();
1135} 1250}
1136 1251
1137} // namespace Service::NFP 1252u64 NfcDevice::GetHandle() const {
1253 // Generate a handle based of the npad id
1254 return static_cast<u64>(npad_id);
1255}
1256
1257DeviceState NfcDevice::GetCurrentState() const {
1258 return device_state;
1259}
1260
1261Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const {
1262 out_npad_id = npad_id;
1263 return ResultSuccess;
1264}
1265
1266} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
new file mode 100644
index 000000000..98e1945c1
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device.h
@@ -0,0 +1,138 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <span>
7
8#include "common/common_types.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/nfc/mifare_types.h"
11#include "core/hle/service/nfc/nfc_types.h"
12#include "core/hle/service/nfp/nfp_types.h"
13#include "core/hle/service/service.h"
14#include "core/hle/service/time/clock_types.h"
15
16namespace Kernel {
17class KEvent;
18class KReadableEvent;
19} // namespace Kernel
20
21namespace Core {
22class System;
23} // namespace Core
24
25namespace Core::HID {
26class EmulatedController;
27enum class ControllerTriggerType;
28enum class NpadIdType : u32;
29} // namespace Core::HID
30
31namespace Service::NFC {
32class NfcDevice {
33public:
34 NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
35 KernelHelpers::ServiceContext& service_context_,
36 Kernel::KEvent* availability_change_event_);
37 ~NfcDevice();
38
39 void Initialize();
40 void Finalize();
41
42 Result StartDetection(NfcProtocol allowed_protocol);
43 Result StopDetection();
44
45 Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const;
46
47 Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
48 std::span<MifareReadBlockData> read_block_data) const;
49 Result ReadMifare(const MifareReadBlockParameter& parameter,
50 MifareReadBlockData& read_block_data) const;
51
52 Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
53 Result WriteMifare(const MifareWriteBlockParameter& parameter);
54
55 Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
56 std::span<const u8> command_data, std::span<u8> out_data);
57
58 Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
59 Result Unmount();
60
61 Result Flush();
62 Result FlushDebug();
63 Result FlushWithBreak(NFP::BreakType break_type);
64 Result Restore();
65
66 Result GetCommonInfo(NFP::CommonInfo& common_info) const;
67 Result GetModelInfo(NFP::ModelInfo& model_info) const;
68 Result GetRegisterInfo(NFP::RegisterInfo& register_info) const;
69 Result GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const;
70 Result GetAdminInfo(NFP::AdminInfo& admin_info) const;
71
72 Result DeleteRegisterInfo();
73 Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info);
74 Result RestoreAmiibo();
75 Result Format();
76
77 Result OpenApplicationArea(u32 access_id);
78 Result GetApplicationAreaId(u32& application_area_id) const;
79 Result GetApplicationArea(std::span<u8> data) const;
80 Result SetApplicationArea(std::span<const u8> data);
81 Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
82 Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
83 Result DeleteApplicationArea();
84 Result ExistsApplicationArea(bool& has_application_area) const;
85
86 Result GetAll(NFP::NfpData& data) const;
87 Result SetAll(const NFP::NfpData& data);
88 Result BreakTag(NFP::BreakType break_type);
89 Result ReadBackupData(std::span<u8> data) const;
90 Result WriteBackupData(std::span<const u8> data);
91 Result WriteNtf(std::span<const u8> data);
92
93 u64 GetHandle() const;
94 DeviceState GetCurrentState() const;
95 Result GetNpadId(Core::HID::NpadIdType& out_npad_id) const;
96
97 Kernel::KReadableEvent& GetActivateEvent() const;
98 Kernel::KReadableEvent& GetDeactivateEvent() const;
99
100private:
101 void NpadUpdate(Core::HID::ControllerTriggerType type);
102 bool LoadNfcTag(std::span<const u8> data);
103 void CloseNfcTag();
104
105 NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
106 void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
107 NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
108 u64 GetCurrentPosixTime() const;
109 u64 RemoveVersionByte(u64 application_id) const;
110 void UpdateSettingsCrc();
111 void UpdateRegisterInfoCrc();
112
113 bool is_controller_set{};
114 int callback_key;
115 const Core::HID::NpadIdType npad_id;
116 Core::System& system;
117 Core::HID::EmulatedController* npad_device = nullptr;
118 KernelHelpers::ServiceContext& service_context;
119 Kernel::KEvent* activate_event = nullptr;
120 Kernel::KEvent* deactivate_event = nullptr;
121 Kernel::KEvent* availability_change_event = nullptr;
122
123 bool is_initalized{};
124 NfcProtocol allowed_protocols{};
125 DeviceState device_state{DeviceState::Unavailable};
126
127 // NFP data
128 bool is_data_moddified{};
129 bool is_app_area_open{};
130 bool is_plain_amiibo{};
131 NFP::MountTarget mount_target{NFP::MountTarget::None};
132
133 NFP::NTAG215File tag_data{};
134 std::vector<u8> mifare_data{};
135 NFP::EncryptedNTAG215File encrypted_tag_data{};
136};
137
138} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
new file mode 100644
index 000000000..d5deaaf27
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -0,0 +1,695 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/hid/hid_types.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfc/common/device.h"
10#include "core/hle/service/nfc/common/device_manager.h"
11#include "core/hle/service/nfc/nfc_result.h"
12#include "core/hle/service/time/clock_types.h"
13
14namespace Service::NFC {
15
16DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
17 : system{system_}, service_context{service_context_} {
18
19 availability_change_event =
20 service_context.CreateEvent("Nfc:DeviceManager:AvailabilityChangeEvent");
21
22 for (u32 device_index = 0; device_index < devices.size(); device_index++) {
23 devices[device_index] =
24 std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
25 service_context, availability_change_event);
26 }
27
28 is_initialized = false;
29}
30
31DeviceManager ::~DeviceManager() {
32 service_context.CloseEvent(availability_change_event);
33}
34
35Result DeviceManager::Initialize() {
36 for (auto& device : devices) {
37 device->Initialize();
38 }
39 is_initialized = true;
40 return ResultSuccess;
41}
42
43Result DeviceManager::Finalize() {
44 for (auto& device : devices) {
45 device->Finalize();
46 }
47 is_initialized = false;
48 return ResultSuccess;
49}
50
51Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices,
52 std::size_t max_allowed_devices) const {
53 for (auto& device : devices) {
54 if (nfp_devices.size() >= max_allowed_devices) {
55 continue;
56 }
57 if (device->GetCurrentState() != DeviceState::Unavailable) {
58 nfp_devices.push_back(device->GetHandle());
59 }
60 }
61
62 if (nfp_devices.empty()) {
63 return ResultDeviceNotFound;
64 }
65
66 return ResultSuccess;
67}
68
69DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
70 std::scoped_lock lock{mutex};
71
72 std::shared_ptr<NfcDevice> device = nullptr;
73 const auto result = GetDeviceFromHandle(device_handle, device, false);
74
75 if (result.IsSuccess()) {
76 return device->GetCurrentState();
77 }
78
79 return DeviceState::Unavailable;
80}
81
82Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const {
83 std::scoped_lock lock{mutex};
84
85 std::shared_ptr<NfcDevice> device = nullptr;
86 auto result = GetDeviceHandle(device_handle, device);
87
88 if (result.IsSuccess()) {
89 result = device->GetNpadId(npad_id);
90 result = VerifyDeviceResult(device, result);
91 }
92
93 return result;
94}
95
96Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const {
97 return availability_change_event->GetReadableEvent();
98}
99
100Result DeviceManager::StartDetection(u64 device_handle, NfcProtocol tag_protocol) {
101 std::scoped_lock lock{mutex};
102
103 std::shared_ptr<NfcDevice> device = nullptr;
104 auto result = GetDeviceHandle(device_handle, device);
105
106 if (result.IsSuccess()) {
107 result = device->StartDetection(tag_protocol);
108 result = VerifyDeviceResult(device, result);
109 }
110
111 return result;
112}
113
114Result DeviceManager::StopDetection(u64 device_handle) {
115 std::scoped_lock lock{mutex};
116
117 std::shared_ptr<NfcDevice> device = nullptr;
118 auto result = GetDeviceHandle(device_handle, device);
119
120 if (result.IsSuccess()) {
121 result = device->StopDetection();
122 result = VerifyDeviceResult(device, result);
123 }
124
125 return result;
126}
127
128Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const {
129 std::scoped_lock lock{mutex};
130
131 std::shared_ptr<NfcDevice> device = nullptr;
132 auto result = GetDeviceHandle(device_handle, device);
133
134 if (result.IsSuccess()) {
135 result = device->GetTagInfo(tag_info, is_mifare);
136 result = VerifyDeviceResult(device, result);
137 }
138
139 return result;
140}
141
142Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const {
143 std::scoped_lock lock{mutex};
144
145 std::shared_ptr<NfcDevice> device = nullptr;
146 GetDeviceFromHandle(device_handle, device, false);
147
148 // TODO: Return proper error code on failure
149 return device->GetActivateEvent();
150}
151
152Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const {
153 std::scoped_lock lock{mutex};
154
155 std::shared_ptr<NfcDevice> device = nullptr;
156 GetDeviceFromHandle(device_handle, device, false);
157
158 // TODO: Return proper error code on failure
159 return device->GetDeactivateEvent();
160}
161
162Result DeviceManager::ReadMifare(u64 device_handle,
163 std::span<const MifareReadBlockParameter> read_parameters,
164 std::span<MifareReadBlockData> read_data) {
165 std::scoped_lock lock{mutex};
166
167 std::shared_ptr<NfcDevice> device = nullptr;
168 auto result = GetDeviceHandle(device_handle, device);
169
170 if (result.IsSuccess()) {
171 result = device->ReadMifare(read_parameters, read_data);
172 result = VerifyDeviceResult(device, result);
173 }
174
175 return result;
176}
177
178Result DeviceManager::WriteMifare(u64 device_handle,
179 std::span<const MifareWriteBlockParameter> write_parameters) {
180 std::scoped_lock lock{mutex};
181
182 std::shared_ptr<NfcDevice> device = nullptr;
183 auto result = GetDeviceHandle(device_handle, device);
184
185 if (result.IsSuccess()) {
186 result = device->WriteMifare(write_parameters);
187 result = VerifyDeviceResult(device, result);
188 }
189
190 return result;
191}
192
193Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
194 const Time::Clock::TimeSpanType& timeout,
195 std::span<const u8> command_data,
196 std::span<u8> out_data) {
197 std::scoped_lock lock{mutex};
198
199 std::shared_ptr<NfcDevice> device = nullptr;
200 auto result = GetDeviceHandle(device_handle, device);
201
202 if (result.IsSuccess()) {
203 result = device->SendCommandByPassThrough(timeout, command_data, out_data);
204 result = VerifyDeviceResult(device, result);
205 }
206
207 return result;
208}
209
210Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type,
211 NFP::MountTarget mount_target) {
212 std::scoped_lock lock{mutex};
213
214 std::shared_ptr<NfcDevice> device = nullptr;
215 auto result = GetDeviceHandle(device_handle, device);
216
217 if (result.IsSuccess()) {
218 result = device->Mount(model_type, mount_target);
219 result = VerifyDeviceResult(device, result);
220 }
221
222 return result;
223}
224
225Result DeviceManager::Unmount(u64 device_handle) {
226 std::scoped_lock lock{mutex};
227
228 std::shared_ptr<NfcDevice> device = nullptr;
229 auto result = GetDeviceHandle(device_handle, device);
230
231 if (result.IsSuccess()) {
232 result = device->Unmount();
233 result = VerifyDeviceResult(device, result);
234 }
235
236 return result;
237}
238
239Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
240 std::scoped_lock lock{mutex};
241
242 std::shared_ptr<NfcDevice> device = nullptr;
243 auto result = GetDeviceHandle(device_handle, device);
244
245 if (result.IsSuccess()) {
246 result = device->OpenApplicationArea(access_id);
247 result = VerifyDeviceResult(device, result);
248 }
249
250 return result;
251}
252
253Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const {
254 std::scoped_lock lock{mutex};
255
256 std::shared_ptr<NfcDevice> device = nullptr;
257 auto result = GetDeviceHandle(device_handle, device);
258
259 if (result.IsSuccess()) {
260 result = device->GetApplicationArea(data);
261 result = VerifyDeviceResult(device, result);
262 }
263
264 return result;
265}
266
267Result DeviceManager::SetApplicationArea(u64 device_handle, std::span<const u8> data) {
268 std::scoped_lock lock{mutex};
269
270 std::shared_ptr<NfcDevice> device = nullptr;
271 auto result = GetDeviceHandle(device_handle, device);
272
273 if (result.IsSuccess()) {
274 result = device->SetApplicationArea(data);
275 result = VerifyDeviceResult(device, result);
276 }
277
278 return result;
279}
280
281Result DeviceManager::Flush(u64 device_handle) {
282 std::scoped_lock lock{mutex};
283
284 std::shared_ptr<NfcDevice> device = nullptr;
285 auto result = GetDeviceHandle(device_handle, device);
286
287 if (result.IsSuccess()) {
288 result = device->Flush();
289 result = VerifyDeviceResult(device, result);
290 }
291
292 return result;
293}
294
295Result DeviceManager::Restore(u64 device_handle) {
296 std::scoped_lock lock{mutex};
297
298 std::shared_ptr<NfcDevice> device = nullptr;
299 auto result = GetDeviceHandle(device_handle, device);
300
301 if (result.IsSuccess()) {
302 result = device->Restore();
303 result = VerifyDeviceResult(device, result);
304 }
305
306 return result;
307}
308
309Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
310 std::span<const u8> data) {
311 std::scoped_lock lock{mutex};
312
313 std::shared_ptr<NfcDevice> device = nullptr;
314 auto result = GetDeviceHandle(device_handle, device);
315
316 if (result.IsSuccess()) {
317 result = device->CreateApplicationArea(access_id, data);
318 result = VerifyDeviceResult(device, result);
319 }
320
321 return result;
322}
323
324Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const {
325 std::scoped_lock lock{mutex};
326
327 std::shared_ptr<NfcDevice> device = nullptr;
328 auto result = GetDeviceHandle(device_handle, device);
329
330 if (result.IsSuccess()) {
331 result = device->GetRegisterInfo(register_info);
332 result = VerifyDeviceResult(device, result);
333 }
334
335 return result;
336}
337
338Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const {
339 std::scoped_lock lock{mutex};
340
341 std::shared_ptr<NfcDevice> device = nullptr;
342 auto result = GetDeviceHandle(device_handle, device);
343
344 if (result.IsSuccess()) {
345 result = device->GetCommonInfo(common_info);
346 result = VerifyDeviceResult(device, result);
347 }
348
349 return result;
350}
351
352Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const {
353 std::scoped_lock lock{mutex};
354
355 std::shared_ptr<NfcDevice> device = nullptr;
356 auto result = GetDeviceHandle(device_handle, device);
357
358 if (result.IsSuccess()) {
359 result = device->GetModelInfo(model_info);
360 result = VerifyDeviceResult(device, result);
361 }
362
363 return result;
364}
365
366u32 DeviceManager::GetApplicationAreaSize() const {
367 return sizeof(NFP::ApplicationArea);
368}
369
370Result DeviceManager::RecreateApplicationArea(u64 device_handle, u32 access_id,
371 std::span<const u8> data) {
372 std::scoped_lock lock{mutex};
373
374 std::shared_ptr<NfcDevice> device = nullptr;
375 auto result = GetDeviceHandle(device_handle, device);
376
377 if (result.IsSuccess()) {
378 result = device->RecreateApplicationArea(access_id, data);
379 result = VerifyDeviceResult(device, result);
380 }
381
382 return result;
383}
384
385Result DeviceManager::Format(u64 device_handle) {
386 std::scoped_lock lock{mutex};
387
388 std::shared_ptr<NfcDevice> device = nullptr;
389 auto result = GetDeviceHandle(device_handle, device);
390
391 if (result.IsSuccess()) {
392 result = device->Format();
393 result = VerifyDeviceResult(device, result);
394 }
395
396 return result;
397}
398
399Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const {
400 std::scoped_lock lock{mutex};
401
402 std::shared_ptr<NfcDevice> device = nullptr;
403 auto result = GetDeviceHandle(device_handle, device);
404
405 if (result.IsSuccess()) {
406 result = device->GetAdminInfo(admin_info);
407 result = VerifyDeviceResult(device, result);
408 }
409
410 return result;
411}
412
413Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
414 NFP::RegisterInfoPrivate& register_info) const {
415 std::scoped_lock lock{mutex};
416
417 std::shared_ptr<NfcDevice> device = nullptr;
418 auto result = GetDeviceHandle(device_handle, device);
419
420 if (result.IsSuccess()) {
421 result = device->GetRegisterInfoPrivate(register_info);
422 result = VerifyDeviceResult(device, result);
423 }
424
425 return result;
426}
427
428Result DeviceManager::SetRegisterInfoPrivate(u64 device_handle,
429 const NFP::RegisterInfoPrivate& register_info) {
430 std::scoped_lock lock{mutex};
431
432 std::shared_ptr<NfcDevice> device = nullptr;
433 auto result = GetDeviceHandle(device_handle, device);
434
435 if (result.IsSuccess()) {
436 result = device->SetRegisterInfoPrivate(register_info);
437 result = VerifyDeviceResult(device, result);
438 }
439
440 return result;
441}
442
443Result DeviceManager::DeleteRegisterInfo(u64 device_handle) {
444 std::scoped_lock lock{mutex};
445
446 std::shared_ptr<NfcDevice> device = nullptr;
447 auto result = GetDeviceHandle(device_handle, device);
448
449 if (result.IsSuccess()) {
450 result = device->DeleteRegisterInfo();
451 result = VerifyDeviceResult(device, result);
452 }
453
454 return result;
455}
456
457Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
458 std::scoped_lock lock{mutex};
459
460 std::shared_ptr<NfcDevice> device = nullptr;
461 auto result = GetDeviceHandle(device_handle, device);
462
463 if (result.IsSuccess()) {
464 result = device->DeleteApplicationArea();
465 result = VerifyDeviceResult(device, result);
466 }
467
468 return result;
469}
470
471Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const {
472 std::scoped_lock lock{mutex};
473
474 std::shared_ptr<NfcDevice> device = nullptr;
475 auto result = GetDeviceHandle(device_handle, device);
476
477 if (result.IsSuccess()) {
478 result = device->ExistsApplicationArea(has_application_area);
479 result = VerifyDeviceResult(device, result);
480 }
481
482 return result;
483}
484
485Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const {
486 std::scoped_lock lock{mutex};
487
488 std::shared_ptr<NfcDevice> device = nullptr;
489 auto result = GetDeviceHandle(device_handle, device);
490
491 if (result.IsSuccess()) {
492 result = device->GetAll(nfp_data);
493 result = VerifyDeviceResult(device, result);
494 }
495
496 return result;
497}
498
499Result DeviceManager::SetAll(u64 device_handle, const NFP::NfpData& nfp_data) {
500 std::scoped_lock lock{mutex};
501
502 std::shared_ptr<NfcDevice> device = nullptr;
503 auto result = GetDeviceHandle(device_handle, device);
504
505 if (result.IsSuccess()) {
506 result = device->SetAll(nfp_data);
507 result = VerifyDeviceResult(device, result);
508 }
509
510 return result;
511}
512
513Result DeviceManager::FlushDebug(u64 device_handle) {
514 std::scoped_lock lock{mutex};
515
516 std::shared_ptr<NfcDevice> device = nullptr;
517 auto result = GetDeviceHandle(device_handle, device);
518
519 if (result.IsSuccess()) {
520 result = device->FlushDebug();
521 result = VerifyDeviceResult(device, result);
522 }
523
524 return result;
525}
526
527Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
528 std::scoped_lock lock{mutex};
529
530 std::shared_ptr<NfcDevice> device = nullptr;
531 auto result = GetDeviceHandle(device_handle, device);
532
533 if (result.IsSuccess()) {
534 result = device->BreakTag(break_type);
535 result = VerifyDeviceResult(device, result);
536 }
537
538 return result;
539}
540
541Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const {
542 std::scoped_lock lock{mutex};
543
544 std::shared_ptr<NfcDevice> device = nullptr;
545 auto result = GetDeviceHandle(device_handle, device);
546
547 if (result.IsSuccess()) {
548 result = device->ReadBackupData(data);
549 result = VerifyDeviceResult(device, result);
550 }
551
552 return result;
553}
554
555Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> data) {
556 std::scoped_lock lock{mutex};
557
558 std::shared_ptr<NfcDevice> device = nullptr;
559 auto result = GetDeviceHandle(device_handle, device);
560
561 if (result.IsSuccess()) {
562 result = device->WriteBackupData(data);
563 result = VerifyDeviceResult(device, result);
564 }
565
566 return result;
567}
568
569Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data) {
570 std::scoped_lock lock{mutex};
571
572 std::shared_ptr<NfcDevice> device = nullptr;
573 auto result = GetDeviceHandle(device_handle, device);
574
575 if (result.IsSuccess()) {
576 result = device->WriteNtf(data);
577 result = VerifyDeviceResult(device, result);
578 }
579
580 return result;
581}
582
583Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
584 bool check_state) const {
585 if (check_state) {
586 const Result is_parameter_set = IsNfcParameterSet();
587 if (is_parameter_set.IsError()) {
588 return is_parameter_set;
589 }
590 const Result is_enabled = IsNfcEnabled();
591 if (is_enabled.IsError()) {
592 return is_enabled;
593 }
594 const Result is_nfc_initialized = IsNfcInitialized();
595 if (is_nfc_initialized.IsError()) {
596 return is_nfc_initialized;
597 }
598 }
599
600 for (auto& device : devices) {
601 if (device->GetHandle() == handle) {
602 nfc_device = device;
603 return ResultSuccess;
604 }
605 }
606
607 return ResultDeviceNotFound;
608}
609
610std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) {
611 for (auto& device : devices) {
612 if (device->GetHandle() == handle) {
613 return device;
614 }
615 }
616 return std::nullopt;
617}
618
619const std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) const {
620 for (auto& device : devices) {
621 if (device->GetHandle() == handle) {
622 return device;
623 }
624 }
625 return std::nullopt;
626}
627
628Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const {
629 const auto result = GetDeviceFromHandle(handle, device, true);
630 if (result.IsError()) {
631 return result;
632 }
633 return CheckDeviceState(device);
634}
635
636Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
637 Result operation_result) const {
638 if (operation_result.IsSuccess()) {
639 return operation_result;
640 }
641
642 const Result is_parameter_set = IsNfcParameterSet();
643 if (is_parameter_set.IsError()) {
644 return is_parameter_set;
645 }
646 const Result is_enabled = IsNfcEnabled();
647 if (is_enabled.IsError()) {
648 return is_enabled;
649 }
650 const Result is_nfc_initialized = IsNfcInitialized();
651 if (is_nfc_initialized.IsError()) {
652 return is_nfc_initialized;
653 }
654 const Result device_state = CheckDeviceState(device);
655 if (device_state.IsError()) {
656 return device_state;
657 }
658
659 return operation_result;
660}
661
662Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const {
663 if (device == nullptr) {
664 return ResultInvalidArgument;
665 }
666
667 return ResultSuccess;
668}
669
670Result DeviceManager::IsNfcEnabled() const {
671 // TODO: This calls nn::settings::detail::GetNfcEnableFlag
672 const bool is_enabled = true;
673 if (!is_enabled) {
674 return ResultNfcDisabled;
675 }
676 return ResultSuccess;
677}
678
679Result DeviceManager::IsNfcParameterSet() const {
680 // TODO: This calls checks against a bool on offset 0x450
681 const bool is_set = true;
682 if (!is_set) {
683 return ResultUnknown76;
684 }
685 return ResultSuccess;
686}
687
688Result DeviceManager::IsNfcInitialized() const {
689 if (!is_initialized) {
690 return ResultNfcNotInitialized;
691 }
692 return ResultSuccess;
693}
694
695} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
new file mode 100644
index 000000000..2971e280f
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -0,0 +1,100 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <optional>
9#include <span>
10
11#include "core/hid/hid_types.h"
12#include "core/hle/service/kernel_helpers.h"
13#include "core/hle/service/nfc/mifare_types.h"
14#include "core/hle/service/nfc/nfc_types.h"
15#include "core/hle/service/nfp/nfp_types.h"
16#include "core/hle/service/service.h"
17#include "core/hle/service/time/clock_types.h"
18
19namespace Service::NFC {
20class NfcDevice;
21
22class DeviceManager {
23public:
24 explicit DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
25 ~DeviceManager();
26
27 // Nfc device manager
28 Result Initialize();
29 Result Finalize();
30 Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const;
31 DeviceState GetDeviceState(u64 device_handle) const;
32 Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const;
33 Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
34 Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
35 Result StopDetection(u64 device_handle);
36 Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const;
37 Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
38 Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
39 Result ReadMifare(u64 device_handle,
40 const std::span<const MifareReadBlockParameter> read_parameters,
41 std::span<MifareReadBlockData> read_data);
42 Result WriteMifare(u64 device_handle,
43 std::span<const MifareWriteBlockParameter> write_parameters);
44 Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
45 std::span<const u8> command_data, std::span<u8> out_data);
46
47 // Nfp device manager
48 Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);
49 Result Unmount(u64 device_handle);
50 Result OpenApplicationArea(u64 device_handle, u32 access_id);
51 Result GetApplicationArea(u64 device_handle, std::span<u8> data) const;
52 Result SetApplicationArea(u64 device_handle, std::span<const u8> data);
53 Result Flush(u64 device_handle);
54 Result Restore(u64 device_handle);
55 Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
56 Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const;
57 Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const;
58 Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const;
59 u32 GetApplicationAreaSize() const;
60 Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
61 Result Format(u64 device_handle);
62 Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const;
63 Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const;
64 Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info);
65 Result DeleteRegisterInfo(u64 device_handle);
66 Result DeleteApplicationArea(u64 device_handle);
67 Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const;
68 Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const;
69 Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data);
70 Result FlushDebug(u64 device_handle);
71 Result BreakTag(u64 device_handle, NFP::BreakType break_type);
72 Result ReadBackupData(u64 device_handle, std::span<u8> data) const;
73 Result WriteBackupData(u64 device_handle, std::span<const u8> data);
74 Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data);
75
76private:
77 Result IsNfcEnabled() const;
78 Result IsNfcParameterSet() const;
79 Result IsNfcInitialized() const;
80
81 Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device,
82 bool check_state) const;
83
84 Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const;
85 Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const;
86 Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const;
87
88 std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
89 const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
90
91 bool is_initialized = false;
92 mutable std::mutex mutex;
93 std::array<std::shared_ptr<NfcDevice>, 10> devices{};
94
95 Core::System& system;
96 KernelHelpers::ServiceContext service_context;
97 Kernel::KEvent* availability_change_event;
98};
99
100} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/mifare_result.h b/src/core/hle/service/nfc/mifare_result.h
new file mode 100644
index 000000000..4b60048a5
--- /dev/null
+++ b/src/core/hle/service/nfc/mifare_result.h
@@ -0,0 +1,17 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::NFC::Mifare {
9
10constexpr Result ResultDeviceNotFound(ErrorModule::NFCMifare, 64);
11constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
12constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
13constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
14constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
15constexpr Result ResultReadError(ErrorModule::NFCMifare, 288);
16
17} // namespace Service::NFC::Mifare
diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h
new file mode 100644
index 000000000..75b59f021
--- /dev/null
+++ b/src/core/hle/service/nfc/mifare_types.h
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace Service::NFC {
12
13enum class MifareCmd : u8 {
14 AuthA = 0x60,
15 AuthB = 0x61,
16 Read = 0x30,
17 Write = 0xA0,
18 Transfer = 0xB0,
19 Decrement = 0xC0,
20 Increment = 0xC1,
21 Store = 0xC2
22};
23
24using DataBlock = std::array<u8, 0x10>;
25using KeyData = std::array<u8, 0x6>;
26
27struct SectorKey {
28 MifareCmd command;
29 u8 unknown; // Usually 1
30 INSERT_PADDING_BYTES(0x6);
31 KeyData sector_key;
32 INSERT_PADDING_BYTES(0x2);
33};
34static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
35
36// This is nn::nfc::MifareReadBlockParameter
37struct MifareReadBlockParameter {
38 u8 sector_number;
39 INSERT_PADDING_BYTES(0x7);
40 SectorKey sector_key;
41};
42static_assert(sizeof(MifareReadBlockParameter) == 0x18,
43 "MifareReadBlockParameter is an invalid size");
44
45// This is nn::nfc::MifareReadBlockData
46struct MifareReadBlockData {
47 DataBlock data;
48 u8 sector_number;
49 INSERT_PADDING_BYTES(0x7);
50};
51static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
52
53// This is nn::nfc::MifareWriteBlockParameter
54struct MifareWriteBlockParameter {
55 DataBlock data;
56 u8 sector_number;
57 INSERT_PADDING_BYTES(0x7);
58 SectorKey sector_key;
59};
60static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
61 "MifareWriteBlockParameter is an invalid size");
62
63} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/mifare_user.cpp b/src/core/hle/service/nfc/mifare_user.cpp
deleted file mode 100644
index e0bbd46e1..000000000
--- a/src/core/hle/service/nfc/mifare_user.cpp
+++ /dev/null
@@ -1,400 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/hid/hid_types.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfc/mifare_user.h"
10#include "core/hle/service/nfc/nfc_device.h"
11#include "core/hle/service/nfc/nfc_result.h"
12
13namespace Service::NFC {
14
15MFIUser::MFIUser(Core::System& system_)
16 : ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} {
17 static const FunctionInfo functions[] = {
18 {0, &MFIUser::Initialize, "Initialize"},
19 {1, &MFIUser::Finalize, "Finalize"},
20 {2, &MFIUser::ListDevices, "ListDevices"},
21 {3, &MFIUser::StartDetection, "StartDetection"},
22 {4, &MFIUser::StopDetection, "StopDetection"},
23 {5, &MFIUser::Read, "Read"},
24 {6, &MFIUser::Write, "Write"},
25 {7, &MFIUser::GetTagInfo, "GetTagInfo"},
26 {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"},
27 {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"},
28 {10, &MFIUser::GetState, "GetState"},
29 {11, &MFIUser::GetDeviceState, "GetDeviceState"},
30 {12, &MFIUser::GetNpadId, "GetNpadId"},
31 {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"},
32 };
33 RegisterHandlers(functions);
34
35 availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent");
36
37 for (u32 device_index = 0; device_index < 10; device_index++) {
38 devices[device_index] =
39 std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
40 service_context, availability_change_event);
41 }
42}
43
44MFIUser ::~MFIUser() {
45 availability_change_event->Close();
46}
47
48void MFIUser::Initialize(HLERequestContext& ctx) {
49 LOG_INFO(Service_NFC, "called");
50
51 state = State::Initialized;
52
53 for (auto& device : devices) {
54 device->Initialize();
55 }
56
57 IPC::ResponseBuilder rb{ctx, 2, 0};
58 rb.Push(ResultSuccess);
59}
60
61void MFIUser::Finalize(HLERequestContext& ctx) {
62 LOG_INFO(Service_NFC, "called");
63
64 state = State::NonInitialized;
65
66 for (auto& device : devices) {
67 device->Finalize();
68 }
69
70 IPC::ResponseBuilder rb{ctx, 2};
71 rb.Push(ResultSuccess);
72}
73
74void MFIUser::ListDevices(HLERequestContext& ctx) {
75 LOG_DEBUG(Service_NFC, "called");
76
77 if (state == State::NonInitialized) {
78 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(MifareNfcDisabled);
80 return;
81 }
82
83 if (!ctx.CanWriteBuffer()) {
84 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(MifareInvalidArgument);
86 return;
87 }
88
89 if (ctx.GetWriteBufferSize() == 0) {
90 IPC::ResponseBuilder rb{ctx, 2};
91 rb.Push(MifareInvalidArgument);
92 return;
93 }
94
95 std::vector<u64> nfp_devices;
96 const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
97
98 for (const auto& device : devices) {
99 if (nfp_devices.size() >= max_allowed_devices) {
100 continue;
101 }
102 if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
103 nfp_devices.push_back(device->GetHandle());
104 }
105 }
106
107 if (nfp_devices.empty()) {
108 IPC::ResponseBuilder rb{ctx, 2};
109 rb.Push(MifareDeviceNotFound);
110 return;
111 }
112
113 ctx.WriteBuffer(nfp_devices);
114
115 IPC::ResponseBuilder rb{ctx, 3};
116 rb.Push(ResultSuccess);
117 rb.Push(static_cast<s32>(nfp_devices.size()));
118}
119
120void MFIUser::StartDetection(HLERequestContext& ctx) {
121 IPC::RequestParser rp{ctx};
122 const auto device_handle{rp.Pop<u64>()};
123 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
124
125 if (state == State::NonInitialized) {
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(MifareNfcDisabled);
128 return;
129 }
130
131 auto device = GetNfcDevice(device_handle);
132
133 if (!device.has_value()) {
134 IPC::ResponseBuilder rb{ctx, 2};
135 rb.Push(MifareDeviceNotFound);
136 return;
137 }
138
139 const auto result = device.value()->StartDetection(NFP::TagProtocol::All);
140 IPC::ResponseBuilder rb{ctx, 2};
141 rb.Push(result);
142}
143
144void MFIUser::StopDetection(HLERequestContext& ctx) {
145 IPC::RequestParser rp{ctx};
146 const auto device_handle{rp.Pop<u64>()};
147 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
148
149 if (state == State::NonInitialized) {
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(MifareNfcDisabled);
152 return;
153 }
154
155 auto device = GetNfcDevice(device_handle);
156
157 if (!device.has_value()) {
158 IPC::ResponseBuilder rb{ctx, 2};
159 rb.Push(MifareDeviceNotFound);
160 return;
161 }
162
163 const auto result = device.value()->StopDetection();
164 IPC::ResponseBuilder rb{ctx, 2};
165 rb.Push(result);
166}
167
168void MFIUser::Read(HLERequestContext& ctx) {
169 IPC::RequestParser rp{ctx};
170 const auto device_handle{rp.Pop<u64>()};
171 const auto buffer{ctx.ReadBuffer()};
172 const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()};
173 std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands);
174
175 memcpy(read_commands.data(), buffer.data(),
176 number_of_commands * sizeof(NFP::MifareReadBlockParameter));
177
178 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
179 device_handle, number_of_commands);
180
181 if (state == State::NonInitialized) {
182 IPC::ResponseBuilder rb{ctx, 2};
183 rb.Push(MifareNfcDisabled);
184 return;
185 }
186
187 auto device = GetNfcDevice(device_handle);
188
189 if (!device.has_value()) {
190 IPC::ResponseBuilder rb{ctx, 2};
191 rb.Push(MifareDeviceNotFound);
192 return;
193 }
194
195 Result result = ResultSuccess;
196 std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
197 for (std::size_t i = 0; i < number_of_commands; i++) {
198 result = device.value()->MifareRead(read_commands[i], out_data[i]);
199 if (result.IsError()) {
200 break;
201 }
202 }
203
204 ctx.WriteBuffer(out_data);
205 IPC::ResponseBuilder rb{ctx, 2};
206 rb.Push(result);
207}
208
209void MFIUser::Write(HLERequestContext& ctx) {
210 IPC::RequestParser rp{ctx};
211 const auto device_handle{rp.Pop<u64>()};
212 const auto buffer{ctx.ReadBuffer()};
213 const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()};
214 std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands);
215
216 memcpy(write_commands.data(), buffer.data(),
217 number_of_commands * sizeof(NFP::MifareWriteBlockParameter));
218
219 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
220 device_handle, number_of_commands);
221
222 if (state == State::NonInitialized) {
223 IPC::ResponseBuilder rb{ctx, 2};
224 rb.Push(MifareNfcDisabled);
225 return;
226 }
227
228 auto device = GetNfcDevice(device_handle);
229
230 if (!device.has_value()) {
231 IPC::ResponseBuilder rb{ctx, 2};
232 rb.Push(MifareDeviceNotFound);
233 return;
234 }
235
236 Result result = ResultSuccess;
237 std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
238 for (std::size_t i = 0; i < number_of_commands; i++) {
239 result = device.value()->MifareWrite(write_commands[i]);
240 if (result.IsError()) {
241 break;
242 }
243 }
244
245 if (result.IsSuccess()) {
246 result = device.value()->Flush();
247 }
248
249 IPC::ResponseBuilder rb{ctx, 2};
250 rb.Push(result);
251}
252
253void MFIUser::GetTagInfo(HLERequestContext& ctx) {
254 IPC::RequestParser rp{ctx};
255 const auto device_handle{rp.Pop<u64>()};
256 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
257
258 if (state == State::NonInitialized) {
259 IPC::ResponseBuilder rb{ctx, 2};
260 rb.Push(MifareNfcDisabled);
261 return;
262 }
263
264 auto device = GetNfcDevice(device_handle);
265
266 if (!device.has_value()) {
267 IPC::ResponseBuilder rb{ctx, 2};
268 rb.Push(MifareDeviceNotFound);
269 return;
270 }
271
272 NFP::TagInfo tag_info{};
273 const auto result = device.value()->GetTagInfo(tag_info, true);
274 ctx.WriteBuffer(tag_info);
275 IPC::ResponseBuilder rb{ctx, 2};
276 rb.Push(result);
277}
278
279void MFIUser::GetActivateEventHandle(HLERequestContext& ctx) {
280 IPC::RequestParser rp{ctx};
281 const auto device_handle{rp.Pop<u64>()};
282 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
283
284 if (state == State::NonInitialized) {
285 IPC::ResponseBuilder rb{ctx, 2};
286 rb.Push(MifareNfcDisabled);
287 return;
288 }
289
290 auto device = GetNfcDevice(device_handle);
291
292 if (!device.has_value()) {
293 IPC::ResponseBuilder rb{ctx, 2};
294 rb.Push(MifareDeviceNotFound);
295 return;
296 }
297
298 IPC::ResponseBuilder rb{ctx, 2, 1};
299 rb.Push(ResultSuccess);
300 rb.PushCopyObjects(device.value()->GetActivateEvent());
301}
302
303void MFIUser::GetDeactivateEventHandle(HLERequestContext& ctx) {
304 IPC::RequestParser rp{ctx};
305 const auto device_handle{rp.Pop<u64>()};
306 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
307
308 if (state == State::NonInitialized) {
309 IPC::ResponseBuilder rb{ctx, 2};
310 rb.Push(MifareNfcDisabled);
311 return;
312 }
313
314 auto device = GetNfcDevice(device_handle);
315
316 if (!device.has_value()) {
317 IPC::ResponseBuilder rb{ctx, 2};
318 rb.Push(MifareDeviceNotFound);
319 return;
320 }
321
322 IPC::ResponseBuilder rb{ctx, 2, 1};
323 rb.Push(ResultSuccess);
324 rb.PushCopyObjects(device.value()->GetDeactivateEvent());
325}
326
327void MFIUser::GetState(HLERequestContext& ctx) {
328 LOG_DEBUG(Service_NFC, "called");
329
330 IPC::ResponseBuilder rb{ctx, 3};
331 rb.Push(ResultSuccess);
332 rb.PushEnum(state);
333}
334
335void MFIUser::GetDeviceState(HLERequestContext& ctx) {
336 IPC::RequestParser rp{ctx};
337 const auto device_handle{rp.Pop<u64>()};
338 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
339
340 auto device = GetNfcDevice(device_handle);
341
342 if (!device.has_value()) {
343 IPC::ResponseBuilder rb{ctx, 2};
344 rb.Push(MifareDeviceNotFound);
345 return;
346 }
347
348 IPC::ResponseBuilder rb{ctx, 3};
349 rb.Push(ResultSuccess);
350 rb.PushEnum(device.value()->GetCurrentState());
351}
352
353void MFIUser::GetNpadId(HLERequestContext& ctx) {
354 IPC::RequestParser rp{ctx};
355 const auto device_handle{rp.Pop<u64>()};
356 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
357
358 if (state == State::NonInitialized) {
359 IPC::ResponseBuilder rb{ctx, 2};
360 rb.Push(MifareNfcDisabled);
361 return;
362 }
363
364 auto device = GetNfcDevice(device_handle);
365
366 if (!device.has_value()) {
367 IPC::ResponseBuilder rb{ctx, 2};
368 rb.Push(MifareDeviceNotFound);
369 return;
370 }
371
372 IPC::ResponseBuilder rb{ctx, 3};
373 rb.Push(ResultSuccess);
374 rb.PushEnum(device.value()->GetNpadId());
375}
376
377void MFIUser::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) {
378 LOG_INFO(Service_NFC, "called");
379
380 if (state == State::NonInitialized) {
381 IPC::ResponseBuilder rb{ctx, 2};
382 rb.Push(MifareNfcDisabled);
383 return;
384 }
385
386 IPC::ResponseBuilder rb{ctx, 2, 1};
387 rb.Push(ResultSuccess);
388 rb.PushCopyObjects(availability_change_event->GetReadableEvent());
389}
390
391std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) {
392 for (auto& device : devices) {
393 if (device->GetHandle() == handle) {
394 return device;
395 }
396 }
397 return std::nullopt;
398}
399
400} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/mifare_user.h b/src/core/hle/service/nfc/mifare_user.h
deleted file mode 100644
index 9701f1d7f..000000000
--- a/src/core/hle/service/nfc/mifare_user.h
+++ /dev/null
@@ -1,52 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <optional>
9
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/service.h"
12
13namespace Service::NFC {
14class NfcDevice;
15
16class MFIUser final : public ServiceFramework<MFIUser> {
17public:
18 explicit MFIUser(Core::System& system_);
19 ~MFIUser();
20
21private:
22 enum class State : u32 {
23 NonInitialized,
24 Initialized,
25 };
26
27 void Initialize(HLERequestContext& ctx);
28 void Finalize(HLERequestContext& ctx);
29 void ListDevices(HLERequestContext& ctx);
30 void StartDetection(HLERequestContext& ctx);
31 void StopDetection(HLERequestContext& ctx);
32 void Read(HLERequestContext& ctx);
33 void Write(HLERequestContext& ctx);
34 void GetTagInfo(HLERequestContext& ctx);
35 void GetActivateEventHandle(HLERequestContext& ctx);
36 void GetDeactivateEventHandle(HLERequestContext& ctx);
37 void GetState(HLERequestContext& ctx);
38 void GetDeviceState(HLERequestContext& ctx);
39 void GetNpadId(HLERequestContext& ctx);
40 void GetAvailabilityChangeEventHandle(HLERequestContext& ctx);
41
42 std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
43
44 KernelHelpers::ServiceContext service_context;
45
46 std::array<std::shared_ptr<NfcDevice>, 10> devices{};
47
48 State state{State::NonInitialized};
49 Kernel::KEvent* availability_change_event;
50};
51
52} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 6595e34ed..30ae989b9 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -6,14 +6,115 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "common/settings.h" 7#include "common/settings.h"
8#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfc/mifare_user.h"
10#include "core/hle/service/nfc/nfc.h" 9#include "core/hle/service/nfc/nfc.h"
11#include "core/hle/service/nfc/nfc_user.h" 10#include "core/hle/service/nfc/nfc_interface.h"
12#include "core/hle/service/server_manager.h" 11#include "core/hle/service/server_manager.h"
13#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
14 13
15namespace Service::NFC { 14namespace Service::NFC {
16 15
16class IUser final : public NfcInterface {
17public:
18 explicit IUser(Core::System& system_) : NfcInterface(system_, "NFC::IUser", BackendType::Nfc) {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, &NfcInterface::Initialize, "InitializeOld"},
22 {1, &NfcInterface::Finalize, "FinalizeOld"},
23 {2, &NfcInterface::GetState, "GetStateOld"},
24 {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
25 {400, &NfcInterface::Initialize, "Initialize"},
26 {401, &NfcInterface::Finalize, "Finalize"},
27 {402, &NfcInterface::GetState, "GetState"},
28 {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
29 {404, &NfcInterface::ListDevices, "ListDevices"},
30 {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
31 {406, &NfcInterface::GetNpadId, "GetNpadId"},
32 {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
33 {408, &NfcInterface::StartDetection, "StartDetection"},
34 {409, &NfcInterface::StopDetection, "StopDetection"},
35 {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
36 {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
37 {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
38 {1000, &NfcInterface::ReadMifare, "ReadMifare"},
39 {1001, &NfcInterface::WriteMifare ,"WriteMifare"},
40 {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
41 {1301, nullptr, "KeepPassThroughSession"},
42 {1302, nullptr, "ReleasePassThroughSession"},
43 };
44 // clang-format on
45
46 RegisterHandlers(functions);
47 }
48};
49
50class ISystem final : public NfcInterface {
51public:
52 explicit ISystem(Core::System& system_)
53 : NfcInterface{system_, "NFC::ISystem", BackendType::Nfc} {
54 // clang-format off
55 static const FunctionInfo functions[] = {
56 {0, &NfcInterface::Initialize, "InitializeOld"},
57 {1, &NfcInterface::Finalize, "FinalizeOld"},
58 {2, &NfcInterface::GetState, "GetStateOld"},
59 {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
60 {100, nullptr, "SetNfcEnabledOld"},
61 {400, &NfcInterface::Initialize, "Initialize"},
62 {401, &NfcInterface::Finalize, "Finalize"},
63 {402, &NfcInterface::GetState, "GetState"},
64 {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
65 {404, &NfcInterface::ListDevices, "ListDevices"},
66 {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
67 {406, &NfcInterface::GetNpadId, "GetNpadId"},
68 {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
69 {408, &NfcInterface::StartDetection, "StartDetection"},
70 {409, &NfcInterface::StopDetection, "StopDetection"},
71 {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
72 {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
73 {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
74 {500, nullptr, "SetNfcEnabled"},
75 {510, nullptr, "OutputTestWave"},
76 {1000, &NfcInterface::ReadMifare, "ReadMifare"},
77 {1001, &NfcInterface::WriteMifare, "WriteMifare"},
78 {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
79 {1301, nullptr, "KeepPassThroughSession"},
80 {1302, nullptr, "ReleasePassThroughSession"},
81 };
82 // clang-format on
83
84 RegisterHandlers(functions);
85 }
86};
87
88// MFInterface has an unique interface but it's identical to NfcInterface so we can keep the code
89// simpler
90using MFInterface = NfcInterface;
91class MFIUser final : public MFInterface {
92public:
93 explicit MFIUser(Core::System& system_)
94 : MFInterface{system_, "NFC::MFInterface", BackendType::Mifare} {
95 // clang-format off
96 static const FunctionInfoTyped<MFIUser> functions[] = {
97 {0, &MFIUser::Initialize, "Initialize"},
98 {1, &MFIUser::Finalize, "Finalize"},
99 {2, &MFIUser::ListDevices, "ListDevices"},
100 {3, &MFIUser::StartDetection, "StartDetection"},
101 {4, &MFIUser::StopDetection, "StopDetection"},
102 {5, &MFIUser::ReadMifare, "Read"},
103 {6, &MFIUser::WriteMifare, "Write"},
104 {7, &MFIUser::GetTagInfo, "GetTagInfo"},
105 {8, &MFIUser::AttachActivateEvent, "GetActivateEventHandle"},
106 {9, &MFIUser::AttachDeactivateEvent, "GetDeactivateEventHandle"},
107 {10, &MFIUser::GetState, "GetState"},
108 {11, &MFIUser::GetDeviceState, "GetDeviceState"},
109 {12, &MFIUser::GetNpadId, "GetNpadId"},
110 {13, &MFIUser::AttachAvailabilityChangeEvent, "GetAvailabilityChangeEventHandle"},
111 };
112 // clang-format on
113
114 RegisterHandlers(functions);
115 }
116};
117
17class IAm final : public ServiceFramework<IAm> { 118class IAm final : public ServiceFramework<IAm> {
18public: 119public:
19 explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} { 120 explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {
@@ -34,7 +135,7 @@ public:
34 explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} { 135 explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} {
35 // clang-format off 136 // clang-format off
36 static const FunctionInfo functions[] = { 137 static const FunctionInfo functions[] = {
37 {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"}, 138 {0, &NFC_AM::CreateAmNfcInterface, "CreateAmNfcInterface"},
38 }; 139 };
39 // clang-format on 140 // clang-format on
40 141
@@ -42,7 +143,7 @@ public:
42 } 143 }
43 144
44private: 145private:
45 void CreateAmInterface(HLERequestContext& ctx) { 146 void CreateAmNfcInterface(HLERequestContext& ctx) {
46 LOG_DEBUG(Service_NFC, "called"); 147 LOG_DEBUG(Service_NFC, "called");
47 148
48 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 149 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -56,7 +157,7 @@ public:
56 explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { 157 explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} {
57 // clang-format off 158 // clang-format off
58 static const FunctionInfo functions[] = { 159 static const FunctionInfo functions[] = {
59 {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"}, 160 {0, &NFC_MF_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
60 }; 161 };
61 // clang-format on 162 // clang-format on
62 163
@@ -64,7 +165,7 @@ public:
64 } 165 }
65 166
66private: 167private:
67 void CreateUserInterface(HLERequestContext& ctx) { 168 void CreateUserNfcInterface(HLERequestContext& ctx) {
68 LOG_DEBUG(Service_NFC, "called"); 169 LOG_DEBUG(Service_NFC, "called");
69 170
70 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 171 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -78,7 +179,7 @@ public:
78 explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} { 179 explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
79 // clang-format off 180 // clang-format off
80 static const FunctionInfo functions[] = { 181 static const FunctionInfo functions[] = {
81 {0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, 182 {0, &NFC_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
82 }; 183 };
83 // clang-format on 184 // clang-format on
84 185
@@ -86,7 +187,7 @@ public:
86 } 187 }
87 188
88private: 189private:
89 void CreateUserInterface(HLERequestContext& ctx) { 190 void CreateUserNfcInterface(HLERequestContext& ctx) {
90 LOG_DEBUG(Service_NFC, "called"); 191 LOG_DEBUG(Service_NFC, "called");
91 192
92 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 193 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -95,49 +196,12 @@ private:
95 } 196 }
96}; 197};
97 198
98class ISystem final : public ServiceFramework<ISystem> {
99public:
100 explicit ISystem(Core::System& system_) : ServiceFramework{system_, "ISystem"} {
101 // clang-format off
102 static const FunctionInfo functions[] = {
103 {0, nullptr, "Initialize"},
104 {1, nullptr, "Finalize"},
105 {2, nullptr, "GetStateOld"},
106 {3, nullptr, "IsNfcEnabledOld"},
107 {100, nullptr, "SetNfcEnabledOld"},
108 {400, nullptr, "InitializeSystem"},
109 {401, nullptr, "FinalizeSystem"},
110 {402, nullptr, "GetState"},
111 {403, nullptr, "IsNfcEnabled"},
112 {404, nullptr, "ListDevices"},
113 {405, nullptr, "GetDeviceState"},
114 {406, nullptr, "GetNpadId"},
115 {407, nullptr, "AttachAvailabilityChangeEvent"},
116 {408, nullptr, "StartDetection"},
117 {409, nullptr, "StopDetection"},
118 {410, nullptr, "GetTagInfo"},
119 {411, nullptr, "AttachActivateEvent"},
120 {412, nullptr, "AttachDeactivateEvent"},
121 {500, nullptr, "SetNfcEnabled"},
122 {510, nullptr, "OutputTestWave"},
123 {1000, nullptr, "ReadMifare"},
124 {1001, nullptr, "WriteMifare"},
125 {1300, nullptr, "SendCommandByPassThrough"},
126 {1301, nullptr, "KeepPassThroughSession"},
127 {1302, nullptr, "ReleasePassThroughSession"},
128 };
129 // clang-format on
130
131 RegisterHandlers(functions);
132 }
133};
134
135class NFC_SYS final : public ServiceFramework<NFC_SYS> { 199class NFC_SYS final : public ServiceFramework<NFC_SYS> {
136public: 200public:
137 explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} { 201 explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} {
138 // clang-format off 202 // clang-format off
139 static const FunctionInfo functions[] = { 203 static const FunctionInfo functions[] = {
140 {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"}, 204 {0, &NFC_SYS::CreateSystemNfcInterface, "CreateSystemNfcInterface"},
141 }; 205 };
142 // clang-format on 206 // clang-format on
143 207
@@ -145,7 +209,7 @@ public:
145 } 209 }
146 210
147private: 211private:
148 void CreateSystemInterface(HLERequestContext& ctx) { 212 void CreateSystemNfcInterface(HLERequestContext& ctx) {
149 LOG_DEBUG(Service_NFC, "called"); 213 LOG_DEBUG(Service_NFC, "called");
150 214
151 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 215 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -161,6 +225,7 @@ void LoopProcess(Core::System& system) {
161 server_manager->RegisterNamedService("nfc:mf:u", std::make_shared<NFC_MF_U>(system)); 225 server_manager->RegisterNamedService("nfc:mf:u", std::make_shared<NFC_MF_U>(system));
162 server_manager->RegisterNamedService("nfc:user", std::make_shared<NFC_U>(system)); 226 server_manager->RegisterNamedService("nfc:user", std::make_shared<NFC_U>(system));
163 server_manager->RegisterNamedService("nfc:sys", std::make_shared<NFC_SYS>(system)); 227 server_manager->RegisterNamedService("nfc:sys", std::make_shared<NFC_SYS>(system));
228
164 ServerManager::RunServer(std::move(server_manager)); 229 ServerManager::RunServer(std::move(server_manager));
165} 230}
166 231
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
deleted file mode 100644
index c7db74d14..000000000
--- a/src/core/hle/service/nfc/nfc_device.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/input.h"
5#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/hid/emulated_controller.h"
8#include "core/hid/hid_core.h"
9#include "core/hid/hid_types.h"
10#include "core/hle/kernel/k_event.h"
11#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/nfc/nfc_device.h"
13#include "core/hle/service/nfc/nfc_result.h"
14#include "core/hle/service/nfc/nfc_user.h"
15
16namespace Service::NFC {
17NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
18 KernelHelpers::ServiceContext& service_context_,
19 Kernel::KEvent* availability_change_event_)
20 : npad_id{npad_id_}, system{system_}, service_context{service_context_},
21 availability_change_event{availability_change_event_} {
22 activate_event = service_context.CreateEvent("IUser:NFCActivateEvent");
23 deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent");
24 npad_device = system.HIDCore().GetEmulatedController(npad_id);
25
26 Core::HID::ControllerUpdateCallback engine_callback{
27 .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
28 .is_npad_service = false,
29 };
30 is_controller_set = true;
31 callback_key = npad_device->SetCallback(engine_callback);
32}
33
34NfcDevice::~NfcDevice() {
35 activate_event->Close();
36 deactivate_event->Close();
37 if (!is_controller_set) {
38 return;
39 }
40 npad_device->DeleteCallback(callback_key);
41 is_controller_set = false;
42};
43
44void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
45 if (!is_initalized) {
46 return;
47 }
48
49 if (type == Core::HID::ControllerTriggerType::Connected) {
50 Initialize();
51 availability_change_event->Signal();
52 return;
53 }
54
55 if (type == Core::HID::ControllerTriggerType::Disconnected) {
56 device_state = NFP::DeviceState::Unavailable;
57 availability_change_event->Signal();
58 return;
59 }
60
61 if (type != Core::HID::ControllerTriggerType::Nfc) {
62 return;
63 }
64
65 if (!npad_device->IsConnected()) {
66 return;
67 }
68
69 const auto nfc_status = npad_device->GetNfc();
70 switch (nfc_status.state) {
71 case Common::Input::NfcState::NewAmiibo:
72 LoadNfcTag(nfc_status.data);
73 break;
74 case Common::Input::NfcState::AmiiboRemoved:
75 if (device_state != NFP::DeviceState::SearchingForTag) {
76 CloseNfcTag();
77 }
78 break;
79 default:
80 break;
81 }
82}
83
84bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
85 if (device_state != NFP::DeviceState::SearchingForTag) {
86 LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
87 return false;
88 }
89
90 if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
91 LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
92 return false;
93 }
94
95 tag_data.resize(data.size());
96 memcpy(tag_data.data(), data.data(), data.size());
97 memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
98
99 device_state = NFP::DeviceState::TagFound;
100 deactivate_event->GetReadableEvent().Clear();
101 activate_event->Signal();
102 return true;
103}
104
105void NfcDevice::CloseNfcTag() {
106 LOG_INFO(Service_NFC, "Remove nfc tag");
107
108 device_state = NFP::DeviceState::TagRemoved;
109 encrypted_tag_data = {};
110 activate_event->GetReadableEvent().Clear();
111 deactivate_event->Signal();
112}
113
114Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
115 return activate_event->GetReadableEvent();
116}
117
118Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
119 return deactivate_event->GetReadableEvent();
120}
121
122void NfcDevice::Initialize() {
123 device_state =
124 npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable;
125 encrypted_tag_data = {};
126 is_initalized = true;
127}
128
129void NfcDevice::Finalize() {
130 if (device_state == NFP::DeviceState::SearchingForTag ||
131 device_state == NFP::DeviceState::TagRemoved) {
132 StopDetection();
133 }
134 device_state = NFP::DeviceState::Unavailable;
135 is_initalized = false;
136}
137
138Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) {
139 if (device_state != NFP::DeviceState::Initialized &&
140 device_state != NFP::DeviceState::TagRemoved) {
141 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
142 return WrongDeviceState;
143 }
144
145 if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
146 Common::Input::PollingMode::NFC) !=
147 Common::Input::DriverResult::Success) {
148 LOG_ERROR(Service_NFC, "Nfc not supported");
149 return NfcDisabled;
150 }
151
152 device_state = NFP::DeviceState::SearchingForTag;
153 allowed_protocols = allowed_protocol;
154 return ResultSuccess;
155}
156
157Result NfcDevice::StopDetection() {
158 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
159 Common::Input::PollingMode::Active);
160
161 if (device_state == NFP::DeviceState::Initialized) {
162 return ResultSuccess;
163 }
164
165 if (device_state == NFP::DeviceState::TagFound ||
166 device_state == NFP::DeviceState::TagMounted) {
167 CloseNfcTag();
168 return ResultSuccess;
169 }
170 if (device_state == NFP::DeviceState::SearchingForTag ||
171 device_state == NFP::DeviceState::TagRemoved) {
172 device_state = NFP::DeviceState::Initialized;
173 return ResultSuccess;
174 }
175
176 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
177 return WrongDeviceState;
178}
179
180Result NfcDevice::Flush() {
181 if (device_state != NFP::DeviceState::TagFound &&
182 device_state != NFP::DeviceState::TagMounted) {
183 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
184 if (device_state == NFP::DeviceState::TagRemoved) {
185 return TagRemoved;
186 }
187 return WrongDeviceState;
188 }
189
190 if (!npad_device->WriteNfc(tag_data)) {
191 LOG_ERROR(Service_NFP, "Error writing to file");
192 return MifareReadError;
193 }
194
195 return ResultSuccess;
196}
197
198Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
199 if (device_state != NFP::DeviceState::TagFound &&
200 device_state != NFP::DeviceState::TagMounted) {
201 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
202 if (device_state == NFP::DeviceState::TagRemoved) {
203 return TagRemoved;
204 }
205 return WrongDeviceState;
206 }
207
208 if (is_mifare) {
209 tag_info = {
210 .uuid = encrypted_tag_data.uuid.uid,
211 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
212 .protocol = NFP::TagProtocol::TypeA,
213 .tag_type = NFP::TagType::Type4,
214 };
215 return ResultSuccess;
216 }
217
218 // Protocol and tag type may change here
219 tag_info = {
220 .uuid = encrypted_tag_data.uuid.uid,
221 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
222 .protocol = NFP::TagProtocol::TypeA,
223 .tag_type = NFP::TagType::Type2,
224 };
225
226 return ResultSuccess;
227}
228
229Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter,
230 NFP::MifareReadBlockData& read_block_data) {
231 const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
232 read_block_data.sector_number = parameter.sector_number;
233
234 if (device_state != NFP::DeviceState::TagFound &&
235 device_state != NFP::DeviceState::TagMounted) {
236 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
237 if (device_state == NFP::DeviceState::TagRemoved) {
238 return TagRemoved;
239 }
240 return WrongDeviceState;
241 }
242
243 if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
244 return MifareReadError;
245 }
246
247 // TODO: Use parameter.sector_key to read encrypted data
248 memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock));
249
250 return ResultSuccess;
251}
252
253Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) {
254 const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
255
256 if (device_state != NFP::DeviceState::TagFound &&
257 device_state != NFP::DeviceState::TagMounted) {
258 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
259 if (device_state == NFP::DeviceState::TagRemoved) {
260 return TagRemoved;
261 }
262 return WrongDeviceState;
263 }
264
265 if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
266 return MifareReadError;
267 }
268
269 // TODO: Use parameter.sector_key to encrypt the data
270 memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock));
271
272 return ResultSuccess;
273}
274
275u64 NfcDevice::GetHandle() const {
276 // Generate a handle based of the npad id
277 return static_cast<u64>(npad_id);
278}
279
280NFP::DeviceState NfcDevice::GetCurrentState() const {
281 return device_state;
282}
283
284Core::HID::NpadIdType NfcDevice::GetNpadId() const {
285 return npad_id;
286}
287
288} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h
deleted file mode 100644
index ea63f0537..000000000
--- a/src/core/hle/service/nfc/nfc_device.h
+++ /dev/null
@@ -1,78 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/nfp/nfp_types.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KEvent;
13class KReadableEvent;
14} // namespace Kernel
15
16namespace Core {
17class System;
18} // namespace Core
19
20namespace Core::HID {
21class EmulatedController;
22enum class ControllerTriggerType;
23enum class NpadIdType : u32;
24} // namespace Core::HID
25
26namespace Service::NFC {
27class NfcDevice {
28public:
29 NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
30 KernelHelpers::ServiceContext& service_context_,
31 Kernel::KEvent* availability_change_event_);
32 ~NfcDevice();
33
34 void Initialize();
35 void Finalize();
36
37 Result StartDetection(NFP::TagProtocol allowed_protocol);
38 Result StopDetection();
39 Result Flush();
40
41 Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const;
42
43 Result MifareRead(const NFP::MifareReadBlockParameter& parameter,
44 NFP::MifareReadBlockData& read_block_data);
45
46 Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter);
47
48 u64 GetHandle() const;
49 NFP::DeviceState GetCurrentState() const;
50 Core::HID::NpadIdType GetNpadId() const;
51
52 Kernel::KReadableEvent& GetActivateEvent() const;
53 Kernel::KReadableEvent& GetDeactivateEvent() const;
54
55private:
56 void NpadUpdate(Core::HID::ControllerTriggerType type);
57 bool LoadNfcTag(std::span<const u8> data);
58 void CloseNfcTag();
59
60 bool is_controller_set{};
61 int callback_key;
62 const Core::HID::NpadIdType npad_id;
63 Core::System& system;
64 Core::HID::EmulatedController* npad_device = nullptr;
65 KernelHelpers::ServiceContext& service_context;
66 Kernel::KEvent* activate_event = nullptr;
67 Kernel::KEvent* deactivate_event = nullptr;
68 Kernel::KEvent* availability_change_event = nullptr;
69
70 bool is_initalized{};
71 NFP::TagProtocol allowed_protocols{};
72 NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
73
74 NFP::EncryptedNTAG215File encrypted_tag_data{};
75 std::vector<u8> tag_data{};
76};
77
78} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
new file mode 100644
index 000000000..0fa29d398
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -0,0 +1,382 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/hid/hid_types.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfc/common/device.h"
10#include "core/hle/service/nfc/common/device_manager.h"
11#include "core/hle/service/nfc/mifare_result.h"
12#include "core/hle/service/nfc/mifare_types.h"
13#include "core/hle/service/nfc/nfc_interface.h"
14#include "core/hle/service/nfc/nfc_result.h"
15#include "core/hle/service/nfc/nfc_types.h"
16#include "core/hle/service/nfp/nfp_result.h"
17#include "core/hle/service/time/clock_types.h"
18
19namespace Service::NFC {
20
21NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
22 : ServiceFramework{system_, name}, service_context{system_, service_name},
23 backend_type{service_backend} {}
24
25NfcInterface ::~NfcInterface() = default;
26
27void NfcInterface::Initialize(HLERequestContext& ctx) {
28 LOG_INFO(Service_NFC, "called");
29
30 auto manager = GetManager();
31 auto result = manager->Initialize();
32
33 if (result.IsSuccess()) {
34 state = State::Initialized;
35 } else {
36 manager->Finalize();
37 }
38
39 IPC::ResponseBuilder rb{ctx, 2, 0};
40 rb.Push(result);
41}
42
43void NfcInterface::Finalize(HLERequestContext& ctx) {
44 LOG_INFO(Service_NFC, "called");
45
46 if (state != State::NonInitialized) {
47 if (GetBackendType() != BackendType::None) {
48 GetManager()->Finalize();
49 }
50 device_manager = nullptr;
51 state = State::NonInitialized;
52 }
53
54 IPC::ResponseBuilder rb{ctx, 2};
55 rb.Push(ResultSuccess);
56}
57
58void NfcInterface::GetState(HLERequestContext& ctx) {
59 LOG_DEBUG(Service_NFC, "called");
60
61 IPC::ResponseBuilder rb{ctx, 3};
62 rb.Push(ResultSuccess);
63 rb.PushEnum(state);
64}
65
66void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
67 LOG_DEBUG(Service_NFC, "called");
68
69 // TODO: This calls nn::settings::detail::GetNfcEnableFlag
70 const bool is_enabled = true;
71
72 IPC::ResponseBuilder rb{ctx, 3};
73 rb.Push(ResultSuccess);
74 rb.Push(is_enabled);
75}
76
77void NfcInterface::ListDevices(HLERequestContext& ctx) {
78 std::vector<u64> nfp_devices;
79 const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
80 LOG_DEBUG(Service_NFC, "called");
81
82 auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices);
83 result = TranslateResultToServiceError(result);
84
85 if (result.IsError()) {
86 IPC::ResponseBuilder rb{ctx, 2};
87 rb.Push(result);
88 return;
89 }
90
91 ctx.WriteBuffer(nfp_devices);
92
93 IPC::ResponseBuilder rb{ctx, 3};
94 rb.Push(ResultSuccess);
95 rb.Push(static_cast<s32>(nfp_devices.size()));
96}
97
98void NfcInterface::GetDeviceState(HLERequestContext& ctx) {
99 IPC::RequestParser rp{ctx};
100 const auto device_handle{rp.Pop<u64>()};
101 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
102
103 const auto device_state = GetManager()->GetDeviceState(device_handle);
104
105 if (device_state > DeviceState::Finalized) {
106 ASSERT_MSG(false, "Invalid device state");
107 }
108
109 IPC::ResponseBuilder rb{ctx, 3};
110 rb.Push(ResultSuccess);
111 rb.PushEnum(device_state);
112}
113
114void NfcInterface::GetNpadId(HLERequestContext& ctx) {
115 IPC::RequestParser rp{ctx};
116 const auto device_handle{rp.Pop<u64>()};
117 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
118
119 Core::HID::NpadIdType npad_id{};
120 auto result = GetManager()->GetNpadId(device_handle, npad_id);
121 result = TranslateResultToServiceError(result);
122
123 if (result.IsError()) {
124 IPC::ResponseBuilder rb{ctx, 2};
125 rb.Push(result);
126 return;
127 }
128
129 IPC::ResponseBuilder rb{ctx, 3};
130 rb.Push(ResultSuccess);
131 rb.PushEnum(npad_id);
132}
133
134void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
135 LOG_INFO(Service_NFC, "called");
136
137 IPC::ResponseBuilder rb{ctx, 2, 1};
138 rb.Push(ResultSuccess);
139 rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent());
140}
141
142void NfcInterface::StartDetection(HLERequestContext& ctx) {
143 IPC::RequestParser rp{ctx};
144 const auto device_handle{rp.Pop<u64>()};
145 const auto tag_protocol{rp.PopEnum<NfcProtocol>()};
146 LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
147
148 auto result = GetManager()->StartDetection(device_handle, tag_protocol);
149 result = TranslateResultToServiceError(result);
150
151 IPC::ResponseBuilder rb{ctx, 2};
152 rb.Push(result);
153}
154
155void NfcInterface::StopDetection(HLERequestContext& ctx) {
156 IPC::RequestParser rp{ctx};
157 const auto device_handle{rp.Pop<u64>()};
158 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
159
160 auto result = GetManager()->StopDetection(device_handle);
161 result = TranslateResultToServiceError(result);
162
163 IPC::ResponseBuilder rb{ctx, 2};
164 rb.Push(result);
165}
166
167void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
168 IPC::RequestParser rp{ctx};
169 const auto device_handle{rp.Pop<u64>()};
170 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
171
172 TagInfo tag_info{};
173 auto result =
174 GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
175 result = TranslateResultToServiceError(result);
176
177 if (result.IsSuccess()) {
178 ctx.WriteBuffer(tag_info);
179 }
180
181 IPC::ResponseBuilder rb{ctx, 2};
182 rb.Push(result);
183}
184
185void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
186 IPC::RequestParser rp{ctx};
187 const auto device_handle{rp.Pop<u64>()};
188 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
189
190 IPC::ResponseBuilder rb{ctx, 2, 1};
191 rb.Push(ResultSuccess);
192 rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle));
193}
194
195void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
196 IPC::RequestParser rp{ctx};
197 const auto device_handle{rp.Pop<u64>()};
198 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
199
200 IPC::ResponseBuilder rb{ctx, 2, 1};
201 rb.Push(ResultSuccess);
202 rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle));
203}
204
205void NfcInterface::ReadMifare(HLERequestContext& ctx) {
206 IPC::RequestParser rp{ctx};
207 const auto device_handle{rp.Pop<u64>()};
208 const auto buffer{ctx.ReadBuffer()};
209 const auto number_of_commands{ctx.GetReadBufferNumElements<MifareReadBlockParameter>()};
210 std::vector<MifareReadBlockParameter> read_commands(number_of_commands);
211
212 memcpy(read_commands.data(), buffer.data(),
213 number_of_commands * sizeof(MifareReadBlockParameter));
214
215 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
216 device_handle, number_of_commands);
217
218 std::vector<MifareReadBlockData> out_data(number_of_commands);
219 auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);
220 result = TranslateResultToServiceError(result);
221
222 if (result.IsSuccess()) {
223 ctx.WriteBuffer(out_data);
224 }
225
226 IPC::ResponseBuilder rb{ctx, 2};
227 rb.Push(result);
228}
229
230void NfcInterface::WriteMifare(HLERequestContext& ctx) {
231 IPC::RequestParser rp{ctx};
232 const auto device_handle{rp.Pop<u64>()};
233 const auto buffer{ctx.ReadBuffer()};
234 const auto number_of_commands{ctx.GetReadBufferNumElements<MifareWriteBlockParameter>()};
235 std::vector<MifareWriteBlockParameter> write_commands(number_of_commands);
236
237 memcpy(write_commands.data(), buffer.data(),
238 number_of_commands * sizeof(MifareWriteBlockParameter));
239
240 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
241 device_handle, number_of_commands);
242
243 auto result = GetManager()->WriteMifare(device_handle, write_commands);
244 result = TranslateResultToServiceError(result);
245
246 IPC::ResponseBuilder rb{ctx, 2};
247 rb.Push(result);
248}
249
250void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) {
251 IPC::RequestParser rp{ctx};
252 const auto device_handle{rp.Pop<u64>()};
253 const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
254 const auto command_data{ctx.ReadBuffer()};
255 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
256 device_handle, timeout.ToSeconds(), command_data.size());
257
258 std::vector<u8> out_data(1);
259 auto result =
260 GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data);
261 result = TranslateResultToServiceError(result);
262
263 if (result.IsError()) {
264 IPC::ResponseBuilder rb{ctx, 2};
265 rb.Push(result);
266 return;
267 }
268
269 ctx.WriteBuffer(out_data);
270
271 IPC::ResponseBuilder rb{ctx, 3};
272 rb.Push(ResultSuccess);
273 rb.Push(static_cast<u32>(out_data.size()));
274}
275
276std::shared_ptr<DeviceManager> NfcInterface::GetManager() {
277 if (device_manager == nullptr) {
278 device_manager = std::make_shared<DeviceManager>(system, service_context);
279 }
280 return device_manager;
281}
282
283BackendType NfcInterface::GetBackendType() const {
284 return backend_type;
285}
286
287Result NfcInterface::TranslateResultToServiceError(Result result) const {
288 const auto backend = GetBackendType();
289
290 if (result.IsSuccess()) {
291 return result;
292 }
293
294 if (result.module != ErrorModule::NFC) {
295 return result;
296 }
297
298 switch (backend) {
299 case BackendType::Mifare:
300 return TranslateResultToNfp(result);
301 case BackendType::Nfp: {
302 return TranslateResultToNfp(result);
303 }
304 default:
305 if (result != ResultUnknown216) {
306 return result;
307 }
308 return ResultUnknown74;
309 }
310}
311
312Result NfcInterface::TranslateResultToNfp(Result result) const {
313 if (result == ResultDeviceNotFound) {
314 return NFP::ResultDeviceNotFound;
315 }
316 if (result == ResultInvalidArgument) {
317 return NFP::ResultInvalidArgument;
318 }
319 if (result == ResultWrongApplicationAreaSize) {
320 return NFP::ResultWrongApplicationAreaSize;
321 }
322 if (result == ResultWrongDeviceState) {
323 return NFP::ResultWrongDeviceState;
324 }
325 if (result == ResultUnknown74) {
326 return NFP::ResultUnknown74;
327 }
328 if (result == ResultNfcDisabled) {
329 return NFP::ResultNfcDisabled;
330 }
331 if (result == ResultNfcNotInitialized) {
332 return NFP::ResultNfcDisabled;
333 }
334 if (result == ResultWriteAmiiboFailed) {
335 return NFP::ResultWriteAmiiboFailed;
336 }
337 if (result == ResultTagRemoved) {
338 return NFP::ResultTagRemoved;
339 }
340 if (result == ResultRegistrationIsNotInitialized) {
341 return NFP::ResultRegistrationIsNotInitialized;
342 }
343 if (result == ResultApplicationAreaIsNotInitialized) {
344 return NFP::ResultApplicationAreaIsNotInitialized;
345 }
346 if (result == ResultCorruptedData) {
347 return NFP::ResultCorruptedData;
348 }
349 if (result == ResultWrongApplicationAreaId) {
350 return NFP::ResultWrongApplicationAreaId;
351 }
352 if (result == ResultApplicationAreaExist) {
353 return NFP::ResultApplicationAreaExist;
354 }
355 if (result == ResultNotAnAmiibo) {
356 return NFP::ResultNotAnAmiibo;
357 }
358 LOG_WARNING(Service_NFC, "Result conversion not handled");
359 return result;
360}
361
362Result NfcInterface::TranslateResultToMifare(Result result) const {
363 if (result == ResultDeviceNotFound) {
364 return Mifare::ResultDeviceNotFound;
365 }
366 if (result == ResultInvalidArgument) {
367 return Mifare::ResultInvalidArgument;
368 }
369 if (result == ResultWrongDeviceState) {
370 return Mifare::ResultWrongDeviceState;
371 }
372 if (result == ResultNfcDisabled) {
373 return Mifare::ResultNfcDisabled;
374 }
375 if (result == ResultTagRemoved) {
376 return Mifare::ResultTagRemoved;
377 }
378 LOG_WARNING(Service_NFC, "Result conversion not handled");
379 return result;
380}
381
382} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.h b/src/core/hle/service/nfc/nfc_interface.h
index aee046ae8..08be174d8 100644
--- a/src/core/hle/service/nfc/nfc_user.h
+++ b/src/core/hle/service/nfc/nfc_interface.h
@@ -3,26 +3,17 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <array>
7#include <memory>
8#include <optional>
9
10#include "core/hle/service/kernel_helpers.h" 6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/nfc/nfc_types.h"
11#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
12 9
13namespace Service::NFC { 10namespace Service::NFC {
14class NfcDevice; 11class DeviceManager;
15 12
16class IUser final : public ServiceFramework<IUser> { 13class NfcInterface : public ServiceFramework<NfcInterface> {
17public: 14public:
18 explicit IUser(Core::System& system_); 15 explicit NfcInterface(Core::System& system_, const char* name, BackendType service_backend);
19 ~IUser(); 16 ~NfcInterface();
20
21private:
22 enum class State : u32 {
23 NonInitialized,
24 Initialized,
25 };
26 17
27 void Initialize(HLERequestContext& ctx); 18 void Initialize(HLERequestContext& ctx);
28 void Finalize(HLERequestContext& ctx); 19 void Finalize(HLERequestContext& ctx);
@@ -37,16 +28,22 @@ private:
37 void GetTagInfo(HLERequestContext& ctx); 28 void GetTagInfo(HLERequestContext& ctx);
38 void AttachActivateEvent(HLERequestContext& ctx); 29 void AttachActivateEvent(HLERequestContext& ctx);
39 void AttachDeactivateEvent(HLERequestContext& ctx); 30 void AttachDeactivateEvent(HLERequestContext& ctx);
31 void ReadMifare(HLERequestContext& ctx);
32 void WriteMifare(HLERequestContext& ctx);
40 void SendCommandByPassThrough(HLERequestContext& ctx); 33 void SendCommandByPassThrough(HLERequestContext& ctx);
41 34
42 std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); 35protected:
36 std::shared_ptr<DeviceManager> GetManager();
37 BackendType GetBackendType() const;
38 Result TranslateResultToServiceError(Result result) const;
39 Result TranslateResultToNfp(Result result) const;
40 Result TranslateResultToMifare(Result result) const;
43 41
44 KernelHelpers::ServiceContext service_context; 42 KernelHelpers::ServiceContext service_context;
45 43
46 std::array<std::shared_ptr<NfcDevice>, 10> devices{}; 44 BackendType backend_type;
47
48 State state{State::NonInitialized}; 45 State state{State::NonInitialized};
49 Kernel::KEvent* availability_change_event; 46 std::shared_ptr<DeviceManager> device_manager = nullptr;
50}; 47};
51 48
52} // namespace Service::NFC 49} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
index 146b8ba61..917d79ef8 100644
--- a/src/core/hle/service/nfc/nfc_result.h
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -1,5 +1,5 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#pragma once 4#pragma once
5 5
@@ -7,17 +7,22 @@
7 7
8namespace Service::NFC { 8namespace Service::NFC {
9 9
10constexpr Result DeviceNotFound(ErrorModule::NFC, 64); 10constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
11constexpr Result InvalidArgument(ErrorModule::NFC, 65); 11constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
12constexpr Result WrongDeviceState(ErrorModule::NFC, 73); 12constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
13constexpr Result NfcDisabled(ErrorModule::NFC, 80); 13constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
14constexpr Result TagRemoved(ErrorModule::NFC, 97); 14constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
15 15constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
16constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64); 16constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
17constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65); 17constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
18constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73); 18constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
19constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80); 19constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
20constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97); 20constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
21constexpr Result MifareReadError(ErrorModule::NFCMifare, 288); 21constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
22constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
23constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
24constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
25constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
26constexpr Result ResultUnknown216(ErrorModule::NFC, 216);
22 27
23} // namespace Service::NFC 28} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_types.h b/src/core/hle/service/nfc/nfc_types.h
new file mode 100644
index 000000000..c7ebd1fdb
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_types.h
@@ -0,0 +1,90 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace Service::NFC {
12enum class BackendType : u32 {
13 None,
14 Nfc,
15 Nfp,
16 Mifare,
17};
18
19// This is nn::nfc::DeviceState
20enum class DeviceState : u32 {
21 Initialized,
22 SearchingForTag,
23 TagFound,
24 TagRemoved,
25 TagMounted,
26 Unavailable,
27 Finalized,
28};
29
30// This is nn::nfc::State
31enum class State : u32 {
32 NonInitialized,
33 Initialized,
34};
35
36// This is nn::nfc::TagType
37enum class TagType : u32 {
38 None,
39 Type1, // ISO14443A RW 96-2k bytes 106kbit/s
40 Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
41 Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
42 Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
43 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
44};
45
46enum class PackedTagType : u8 {
47 None,
48 Type1, // ISO14443A RW 96-2k bytes 106kbit/s
49 Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
50 Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
51 Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
52 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
53};
54
55// This is nn::nfc::NfcProtocol
56// Verify this enum. It might be completely wrong default protocol is 0x48
57enum class NfcProtocol : u32 {
58 None,
59 TypeA = 1U << 0, // ISO14443A
60 TypeB = 1U << 1, // ISO14443B
61 TypeF = 1U << 2, // Sony FeliCa
62 Unknown1 = 1U << 3,
63 Unknown2 = 1U << 5,
64 All = 0xFFFFFFFFU,
65};
66
67// this is nn::nfc::TestWaveType
68enum class TestWaveType : u32 {
69 Unknown,
70};
71
72using UniqueSerialNumber = std::array<u8, 7>;
73using UniqueSerialNumberExtension = std::array<u8, 3>;
74
75// This is nn::nfc::DeviceHandle
76using DeviceHandle = u64;
77
78// This is nn::nfc::TagInfo
79struct TagInfo {
80 UniqueSerialNumber uuid;
81 UniqueSerialNumberExtension uuid_extension;
82 u8 uuid_length;
83 INSERT_PADDING_BYTES(0x15);
84 NfcProtocol protocol;
85 TagType tag_type;
86 INSERT_PADDING_BYTES(0x30);
87};
88static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
89
90} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp
deleted file mode 100644
index 7c162a4f3..000000000
--- a/src/core/hle/service/nfc/nfc_user.cpp
+++ /dev/null
@@ -1,365 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/hid/hid_types.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfc/nfc_device.h"
10#include "core/hle/service/nfc/nfc_result.h"
11#include "core/hle/service/nfc/nfc_user.h"
12#include "core/hle/service/time/clock_types.h"
13
14namespace Service::NFC {
15
16IUser::IUser(Core::System& system_)
17 : ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} {
18 static const FunctionInfo functions[] = {
19 {0, &IUser::Initialize, "InitializeOld"},
20 {1, &IUser::Finalize, "FinalizeOld"},
21 {2, &IUser::GetState, "GetStateOld"},
22 {3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"},
23 {400, &IUser::Initialize, "Initialize"},
24 {401, &IUser::Finalize, "Finalize"},
25 {402, &IUser::GetState, "GetState"},
26 {403, &IUser::IsNfcEnabled, "IsNfcEnabled"},
27 {404, &IUser::ListDevices, "ListDevices"},
28 {405, &IUser::GetDeviceState, "GetDeviceState"},
29 {406, &IUser::GetNpadId, "GetNpadId"},
30 {407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
31 {408, &IUser::StartDetection, "StartDetection"},
32 {409, &IUser::StopDetection, "StopDetection"},
33 {410, &IUser::GetTagInfo, "GetTagInfo"},
34 {411, &IUser::AttachActivateEvent, "AttachActivateEvent"},
35 {412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
36 {1000, nullptr, "ReadMifare"},
37 {1001, nullptr, "WriteMifare"},
38 {1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"},
39 {1301, nullptr, "KeepPassThroughSession"},
40 {1302, nullptr, "ReleasePassThroughSession"},
41 };
42 RegisterHandlers(functions);
43
44 availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
45
46 for (u32 device_index = 0; device_index < 10; device_index++) {
47 devices[device_index] =
48 std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
49 service_context, availability_change_event);
50 }
51}
52
53IUser ::~IUser() {
54 availability_change_event->Close();
55}
56
57void IUser::Initialize(HLERequestContext& ctx) {
58 LOG_INFO(Service_NFC, "called");
59
60 state = State::Initialized;
61
62 for (auto& device : devices) {
63 device->Initialize();
64 }
65
66 IPC::ResponseBuilder rb{ctx, 2, 0};
67 rb.Push(ResultSuccess);
68}
69
70void IUser::Finalize(HLERequestContext& ctx) {
71 LOG_INFO(Service_NFC, "called");
72
73 state = State::NonInitialized;
74
75 for (auto& device : devices) {
76 device->Finalize();
77 }
78
79 IPC::ResponseBuilder rb{ctx, 2};
80 rb.Push(ResultSuccess);
81}
82
83void IUser::GetState(HLERequestContext& ctx) {
84 LOG_DEBUG(Service_NFC, "called");
85
86 IPC::ResponseBuilder rb{ctx, 3};
87 rb.Push(ResultSuccess);
88 rb.PushEnum(state);
89}
90
91void IUser::IsNfcEnabled(HLERequestContext& ctx) {
92 LOG_DEBUG(Service_NFC, "called");
93
94 IPC::ResponseBuilder rb{ctx, 3};
95 rb.Push(ResultSuccess);
96 rb.Push(state != State::NonInitialized);
97}
98
99void IUser::ListDevices(HLERequestContext& ctx) {
100 LOG_DEBUG(Service_NFC, "called");
101
102 if (state == State::NonInitialized) {
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(NfcDisabled);
105 return;
106 }
107
108 if (!ctx.CanWriteBuffer()) {
109 IPC::ResponseBuilder rb{ctx, 2};
110 rb.Push(InvalidArgument);
111 return;
112 }
113
114 if (ctx.GetWriteBufferSize() == 0) {
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(InvalidArgument);
117 return;
118 }
119
120 std::vector<u64> nfp_devices;
121 const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
122
123 for (auto& device : devices) {
124 if (nfp_devices.size() >= max_allowed_devices) {
125 continue;
126 }
127 if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
128 nfp_devices.push_back(device->GetHandle());
129 }
130 }
131
132 if (nfp_devices.empty()) {
133 IPC::ResponseBuilder rb{ctx, 2};
134 rb.Push(DeviceNotFound);
135 return;
136 }
137
138 ctx.WriteBuffer(nfp_devices);
139
140 IPC::ResponseBuilder rb{ctx, 3};
141 rb.Push(ResultSuccess);
142 rb.Push(static_cast<s32>(nfp_devices.size()));
143}
144
145void IUser::GetDeviceState(HLERequestContext& ctx) {
146 IPC::RequestParser rp{ctx};
147 const auto device_handle{rp.Pop<u64>()};
148 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
149
150 auto device = GetNfcDevice(device_handle);
151
152 if (!device.has_value()) {
153 IPC::ResponseBuilder rb{ctx, 2};
154 rb.Push(DeviceNotFound);
155 return;
156 }
157
158 IPC::ResponseBuilder rb{ctx, 3};
159 rb.Push(ResultSuccess);
160 rb.PushEnum(device.value()->GetCurrentState());
161}
162
163void IUser::GetNpadId(HLERequestContext& ctx) {
164 IPC::RequestParser rp{ctx};
165 const auto device_handle{rp.Pop<u64>()};
166 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
167
168 if (state == State::NonInitialized) {
169 IPC::ResponseBuilder rb{ctx, 2};
170 rb.Push(NfcDisabled);
171 return;
172 }
173
174 auto device = GetNfcDevice(device_handle);
175
176 if (!device.has_value()) {
177 IPC::ResponseBuilder rb{ctx, 2};
178 rb.Push(DeviceNotFound);
179 return;
180 }
181
182 IPC::ResponseBuilder rb{ctx, 3};
183 rb.Push(ResultSuccess);
184 rb.PushEnum(device.value()->GetNpadId());
185}
186
187void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
188 LOG_INFO(Service_NFC, "called");
189
190 if (state == State::NonInitialized) {
191 IPC::ResponseBuilder rb{ctx, 2};
192 rb.Push(NfcDisabled);
193 return;
194 }
195
196 IPC::ResponseBuilder rb{ctx, 2, 1};
197 rb.Push(ResultSuccess);
198 rb.PushCopyObjects(availability_change_event->GetReadableEvent());
199}
200
201void IUser::StartDetection(HLERequestContext& ctx) {
202 IPC::RequestParser rp{ctx};
203 const auto device_handle{rp.Pop<u64>()};
204 const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()};
205 LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
206
207 if (state == State::NonInitialized) {
208 IPC::ResponseBuilder rb{ctx, 2};
209 rb.Push(NfcDisabled);
210 return;
211 }
212
213 auto device = GetNfcDevice(device_handle);
214
215 if (!device.has_value()) {
216 IPC::ResponseBuilder rb{ctx, 2};
217 rb.Push(DeviceNotFound);
218 return;
219 }
220
221 const auto result = device.value()->StartDetection(nfp_protocol);
222 IPC::ResponseBuilder rb{ctx, 2};
223 rb.Push(result);
224}
225
226void IUser::StopDetection(HLERequestContext& ctx) {
227 IPC::RequestParser rp{ctx};
228 const auto device_handle{rp.Pop<u64>()};
229 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
230
231 if (state == State::NonInitialized) {
232 IPC::ResponseBuilder rb{ctx, 2};
233 rb.Push(NfcDisabled);
234 return;
235 }
236
237 auto device = GetNfcDevice(device_handle);
238
239 if (!device.has_value()) {
240 IPC::ResponseBuilder rb{ctx, 2};
241 rb.Push(DeviceNotFound);
242 return;
243 }
244
245 const auto result = device.value()->StopDetection();
246 IPC::ResponseBuilder rb{ctx, 2};
247 rb.Push(result);
248}
249
250void IUser::GetTagInfo(HLERequestContext& ctx) {
251 IPC::RequestParser rp{ctx};
252 const auto device_handle{rp.Pop<u64>()};
253 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
254
255 if (state == State::NonInitialized) {
256 IPC::ResponseBuilder rb{ctx, 2};
257 rb.Push(NfcDisabled);
258 return;
259 }
260
261 auto device = GetNfcDevice(device_handle);
262
263 if (!device.has_value()) {
264 IPC::ResponseBuilder rb{ctx, 2};
265 rb.Push(DeviceNotFound);
266 return;
267 }
268
269 NFP::TagInfo tag_info{};
270 const auto result = device.value()->GetTagInfo(tag_info, false);
271 ctx.WriteBuffer(tag_info);
272 IPC::ResponseBuilder rb{ctx, 2};
273 rb.Push(result);
274}
275
276void IUser::AttachActivateEvent(HLERequestContext& ctx) {
277 IPC::RequestParser rp{ctx};
278 const auto device_handle{rp.Pop<u64>()};
279 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
280
281 if (state == State::NonInitialized) {
282 IPC::ResponseBuilder rb{ctx, 2};
283 rb.Push(NfcDisabled);
284 return;
285 }
286
287 auto device = GetNfcDevice(device_handle);
288
289 if (!device.has_value()) {
290 IPC::ResponseBuilder rb{ctx, 2};
291 rb.Push(DeviceNotFound);
292 return;
293 }
294
295 IPC::ResponseBuilder rb{ctx, 2, 1};
296 rb.Push(ResultSuccess);
297 rb.PushCopyObjects(device.value()->GetActivateEvent());
298}
299
300void IUser::AttachDeactivateEvent(HLERequestContext& ctx) {
301 IPC::RequestParser rp{ctx};
302 const auto device_handle{rp.Pop<u64>()};
303 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
304
305 if (state == State::NonInitialized) {
306 IPC::ResponseBuilder rb{ctx, 2};
307 rb.Push(NfcDisabled);
308 return;
309 }
310
311 auto device = GetNfcDevice(device_handle);
312
313 if (!device.has_value()) {
314 IPC::ResponseBuilder rb{ctx, 2};
315 rb.Push(DeviceNotFound);
316 return;
317 }
318
319 IPC::ResponseBuilder rb{ctx, 2, 1};
320 rb.Push(ResultSuccess);
321 rb.PushCopyObjects(device.value()->GetDeactivateEvent());
322}
323
324void IUser::SendCommandByPassThrough(HLERequestContext& ctx) {
325 IPC::RequestParser rp{ctx};
326 const auto device_handle{rp.Pop<u64>()};
327 const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
328 const auto command_data{ctx.ReadBuffer()};
329
330 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
331 device_handle, timeout.ToSeconds(), command_data.size());
332
333 if (state == State::NonInitialized) {
334 IPC::ResponseBuilder rb{ctx, 2};
335 rb.Push(NfcDisabled);
336 return;
337 }
338
339 auto device = GetNfcDevice(device_handle);
340
341 if (!device.has_value()) {
342 IPC::ResponseBuilder rb{ctx, 2};
343 rb.Push(DeviceNotFound);
344 return;
345 }
346
347 std::vector<u8> out_data(1);
348 // TODO: Request data from nfc device
349 ctx.WriteBuffer(out_data);
350
351 IPC::ResponseBuilder rb{ctx, 3};
352 rb.Push(ResultSuccess);
353 rb.Push(static_cast<u32>(out_data.size()));
354}
355
356std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
357 for (auto& device : devices) {
358 if (device->GetHandle() == handle) {
359 return device;
360 }
361 }
362 return std::nullopt;
363}
364
365} // namespace Service::NFC
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 2714f4bea..2eeabc138 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -13,7 +13,7 @@ class IUser final : public Interface {
13public: 13public:
14 explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") { 14 explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") {
15 // clang-format off 15 // clang-format off
16 static const FunctionInfo functions[] = { 16 static const FunctionInfoTyped<IUser> functions[] = {
17 {0, &IUser::Initialize, "Initialize"}, 17 {0, &IUser::Initialize, "Initialize"},
18 {1, &IUser::Finalize, "Finalize"}, 18 {1, &IUser::Finalize, "Finalize"},
19 {2, &IUser::ListDevices, "ListDevices"}, 19 {2, &IUser::ListDevices, "ListDevices"},
@@ -50,7 +50,7 @@ class ISystem final : public Interface {
50public: 50public:
51 explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") { 51 explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") {
52 // clang-format off 52 // clang-format off
53 static const FunctionInfo functions[] = { 53 static const FunctionInfoTyped<ISystem> functions[] = {
54 {0, &ISystem::InitializeSystem, "InitializeSystem"}, 54 {0, &ISystem::InitializeSystem, "InitializeSystem"},
55 {1, &ISystem::FinalizeSystem, "FinalizeSystem"}, 55 {1, &ISystem::FinalizeSystem, "FinalizeSystem"},
56 {2, &ISystem::ListDevices, "ListDevices"}, 56 {2, &ISystem::ListDevices, "ListDevices"},
@@ -89,7 +89,7 @@ class IDebug final : public Interface {
89public: 89public:
90 explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") { 90 explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") {
91 // clang-format off 91 // clang-format off
92 static const FunctionInfo functions[] = { 92 static const FunctionInfoTyped<IDebug> functions[] = {
93 {0, &IDebug::InitializeDebug, "InitializeDebug"}, 93 {0, &IDebug::InitializeDebug, "InitializeDebug"},
94 {1, &IDebug::FinalizeDebug, "FinalizeDebug"}, 94 {1, &IDebug::FinalizeDebug, "FinalizeDebug"},
95 {2, &IDebug::ListDevices, "ListDevices"}, 95 {2, &IDebug::ListDevices, "ListDevices"},
@@ -126,9 +126,9 @@ public:
126 {201, &IDebug::SetAll, "SetAll"}, 126 {201, &IDebug::SetAll, "SetAll"},
127 {202, &IDebug::FlushDebug, "FlushDebug"}, 127 {202, &IDebug::FlushDebug, "FlushDebug"},
128 {203, &IDebug::BreakTag, "BreakTag"}, 128 {203, &IDebug::BreakTag, "BreakTag"},
129 {204, nullptr, "ReadBackupData"}, 129 {204, &IDebug::ReadBackupData, "ReadBackupData"},
130 {205, nullptr, "WriteBackupData"}, 130 {205, &IDebug::WriteBackupData, "WriteBackupData"},
131 {206, nullptr, "WriteNtf"}, 131 {206, &IDebug::WriteNtf, "WriteNtf"},
132 }; 132 };
133 // clang-format on 133 // clang-format on
134 134
@@ -152,16 +152,10 @@ private:
152 void CreateUserInterface(HLERequestContext& ctx) { 152 void CreateUserInterface(HLERequestContext& ctx) {
153 LOG_DEBUG(Service_NFP, "called"); 153 LOG_DEBUG(Service_NFP, "called");
154 154
155 if (user_interface == nullptr) {
156 user_interface = std::make_shared<IUser>(system);
157 }
158
159 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 155 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
160 rb.Push(ResultSuccess); 156 rb.Push(ResultSuccess);
161 rb.PushIpcInterface<IUser>(user_interface); 157 rb.PushIpcInterface<IUser>(system);
162 } 158 }
163
164 std::shared_ptr<IUser> user_interface;
165}; 159};
166 160
167class ISystemManager final : public ServiceFramework<ISystemManager> { 161class ISystemManager final : public ServiceFramework<ISystemManager> {
@@ -180,16 +174,10 @@ private:
180 void CreateSystemInterface(HLERequestContext& ctx) { 174 void CreateSystemInterface(HLERequestContext& ctx) {
181 LOG_DEBUG(Service_NFP, "called"); 175 LOG_DEBUG(Service_NFP, "called");
182 176
183 if (system_interface == nullptr) {
184 system_interface = std::make_shared<ISystem>(system);
185 }
186
187 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 177 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
188 rb.Push(ResultSuccess); 178 rb.Push(ResultSuccess);
189 rb.PushIpcInterface<ISystem>(system_interface); 179 rb.PushIpcInterface<ISystem>(system);
190 } 180 }
191
192 std::shared_ptr<ISystem> system_interface;
193}; 181};
194 182
195class IDebugManager final : public ServiceFramework<IDebugManager> { 183class IDebugManager final : public ServiceFramework<IDebugManager> {
@@ -208,16 +196,10 @@ private:
208 void CreateDebugInterface(HLERequestContext& ctx) { 196 void CreateDebugInterface(HLERequestContext& ctx) {
209 LOG_DEBUG(Service_NFP, "called"); 197 LOG_DEBUG(Service_NFP, "called");
210 198
211 if (system_interface == nullptr) {
212 system_interface = std::make_shared<IDebug>(system);
213 }
214
215 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 199 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
216 rb.Push(ResultSuccess); 200 rb.Push(ResultSuccess);
217 rb.PushIpcInterface<IDebug>(system_interface); 201 rb.PushIpcInterface<IDebug>(system);
218 } 202 }
219
220 std::shared_ptr<IDebug> system_interface;
221}; 203};
222 204
223void LoopProcess(Core::System& system) { 205void LoopProcess(Core::System& system) {
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
deleted file mode 100644
index bab05538a..000000000
--- a/src/core/hle/service/nfp/nfp_device.h
+++ /dev/null
@@ -1,120 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <span>
7#include <vector>
8
9#include "common/common_types.h"
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/nfp/nfp_types.h"
12#include "core/hle/service/service.h"
13
14namespace Kernel {
15class KEvent;
16class KReadableEvent;
17} // namespace Kernel
18
19namespace Core {
20class System;
21} // namespace Core
22
23namespace Core::HID {
24class EmulatedController;
25enum class ControllerTriggerType;
26enum class NpadIdType : u32;
27} // namespace Core::HID
28
29namespace Service::NFP {
30class NfpDevice {
31public:
32 NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
33 KernelHelpers::ServiceContext& service_context_,
34 Kernel::KEvent* availability_change_event_);
35 ~NfpDevice();
36
37 void Initialize();
38 void Finalize();
39
40 Result StartDetection(TagProtocol allowed_protocol);
41 Result StopDetection();
42 Result Mount(MountTarget mount_target);
43 Result Unmount();
44
45 Result Flush();
46 Result FlushDebug();
47 Result FlushWithBreak(BreakType break_type);
48
49 Result GetTagInfo(TagInfo& tag_info) const;
50 Result GetCommonInfo(CommonInfo& common_info) const;
51 Result GetModelInfo(ModelInfo& model_info) const;
52 Result GetRegisterInfo(RegisterInfo& register_info) const;
53 Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const;
54 Result GetAdminInfo(AdminInfo& admin_info) const;
55
56 Result DeleteRegisterInfo();
57 Result SetRegisterInfoPrivate(const AmiiboName& amiibo_name);
58 Result RestoreAmiibo();
59 Result Format();
60
61 Result OpenApplicationArea(u32 access_id);
62 Result GetApplicationAreaId(u32& application_area_id) const;
63 Result GetApplicationArea(std::vector<u8>& data) const;
64 Result SetApplicationArea(std::span<const u8> data);
65 Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
66 Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
67 Result DeleteApplicationArea();
68 Result ExistApplicationArea(bool& has_application_area);
69
70 Result GetAll(NfpData& data) const;
71 Result SetAll(const NfpData& data);
72 Result BreakTag(BreakType break_type);
73 Result ReadBackupData();
74 Result WriteBackupData();
75 Result WriteNtf();
76
77 u64 GetHandle() const;
78 u32 GetApplicationAreaSize() const;
79 DeviceState GetCurrentState() const;
80 Core::HID::NpadIdType GetNpadId() const;
81
82 Kernel::KReadableEvent& GetActivateEvent() const;
83 Kernel::KReadableEvent& GetDeactivateEvent() const;
84
85private:
86 void NpadUpdate(Core::HID::ControllerTriggerType type);
87 bool LoadAmiibo(std::span<const u8> data);
88 void CloseAmiibo();
89
90 AmiiboName GetAmiiboName(const AmiiboSettings& settings) const;
91 void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name);
92 AmiiboDate GetAmiiboDate(s64 posix_time) const;
93 u64 RemoveVersionByte(u64 application_id) const;
94 void UpdateSettingsCrc();
95 void UpdateRegisterInfoCrc();
96
97 bool is_controller_set{};
98 int callback_key;
99 const Core::HID::NpadIdType npad_id;
100 Core::System& system;
101 Core::HID::EmulatedController* npad_device = nullptr;
102 KernelHelpers::ServiceContext& service_context;
103 Kernel::KEvent* activate_event = nullptr;
104 Kernel::KEvent* deactivate_event = nullptr;
105 Kernel::KEvent* availability_change_event = nullptr;
106
107 bool is_initalized{};
108 bool is_data_moddified{};
109 bool is_app_area_open{};
110 bool is_plain_amiibo{};
111 TagProtocol allowed_protocols{};
112 s64 current_posix_time{};
113 MountTarget mount_target{MountTarget::None};
114 DeviceState device_state{DeviceState::Unavailable};
115
116 NTAG215File tag_data{};
117 EncryptedNTAG215File encrypted_tag_data{};
118};
119
120} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp
index 2ed8bb1ba..21d159154 100644
--- a/src/core/hle/service/nfp/nfp_interface.cpp
+++ b/src/core/hle/service/nfp/nfp_interface.cpp
@@ -1,4 +1,4 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 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 "common/logging/log.h" 4#include "common/logging/log.h"
@@ -6,198 +6,34 @@
6#include "core/hid/hid_types.h" 6#include "core/hid/hid_types.h"
7#include "core/hle/kernel/k_event.h" 7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfp/nfp_device.h" 9#include "core/hle/service/nfc/common/device.h"
10#include "core/hle/service/nfc/common/device_manager.h"
11#include "core/hle/service/nfc/nfc_types.h"
10#include "core/hle/service/nfp/nfp_interface.h" 12#include "core/hle/service/nfp/nfp_interface.h"
11#include "core/hle/service/nfp/nfp_result.h" 13#include "core/hle/service/nfp/nfp_result.h"
14#include "core/hle/service/nfp/nfp_types.h"
12 15
13namespace Service::NFP { 16namespace Service::NFP {
14 17
15Interface::Interface(Core::System& system_, const char* name) 18Interface::Interface(Core::System& system_, const char* name)
16 : ServiceFramework{system_, name}, service_context{system_, service_name} { 19 : NfcInterface{system_, name, NFC::BackendType::Nfp} {}
17 availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
18 20
19 for (u32 device_index = 0; device_index < 10; device_index++) { 21Interface::~Interface() = default;
20 devices[device_index] =
21 std::make_shared<NfpDevice>(Core::HID::IndexToNpadIdType(device_index), system,
22 service_context, availability_change_event);
23 }
24}
25
26Interface::~Interface() {
27 availability_change_event->Close();
28}
29
30void Interface::Initialize(HLERequestContext& ctx) {
31 LOG_INFO(Service_NFP, "called");
32
33 state = State::Initialized;
34
35 for (auto& device : devices) {
36 device->Initialize();
37 }
38
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(ResultSuccess);
41}
42 22
43void Interface::InitializeSystem(HLERequestContext& ctx) { 23void Interface::InitializeSystem(HLERequestContext& ctx) {
44 LOG_INFO(Service_NFP, "called"); 24 Initialize(ctx);
45
46 state = State::Initialized;
47
48 for (auto& device : devices) {
49 device->Initialize();
50 }
51
52 IPC::ResponseBuilder rb{ctx, 2};
53 rb.Push(ResultSuccess);
54} 25}
55 26
56void Interface::InitializeDebug(HLERequestContext& ctx) { 27void Interface::InitializeDebug(HLERequestContext& ctx) {
57 LOG_INFO(Service_NFP, "called"); 28 Initialize(ctx);
58
59 state = State::Initialized;
60
61 for (auto& device : devices) {
62 device->Initialize();
63 }
64
65 IPC::ResponseBuilder rb{ctx, 2};
66 rb.Push(ResultSuccess);
67}
68
69void Interface::Finalize(HLERequestContext& ctx) {
70 LOG_INFO(Service_NFP, "called");
71
72 state = State::NonInitialized;
73
74 for (auto& device : devices) {
75 device->Finalize();
76 }
77
78 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(ResultSuccess);
80} 29}
81 30
82void Interface::FinalizeSystem(HLERequestContext& ctx) { 31void Interface::FinalizeSystem(HLERequestContext& ctx) {
83 LOG_INFO(Service_NFP, "called"); 32 Finalize(ctx);
84
85 state = State::NonInitialized;
86
87 for (auto& device : devices) {
88 device->Finalize();
89 }
90
91 IPC::ResponseBuilder rb{ctx, 2};
92 rb.Push(ResultSuccess);
93} 33}
94 34
95void Interface::FinalizeDebug(HLERequestContext& ctx) { 35void Interface::FinalizeDebug(HLERequestContext& ctx) {
96 LOG_INFO(Service_NFP, "called"); 36 Finalize(ctx);
97
98 state = State::NonInitialized;
99
100 for (auto& device : devices) {
101 device->Finalize();
102 }
103
104 IPC::ResponseBuilder rb{ctx, 2};
105 rb.Push(ResultSuccess);
106}
107
108void Interface::ListDevices(HLERequestContext& ctx) {
109 LOG_DEBUG(Service_NFP, "called");
110
111 if (state == State::NonInitialized) {
112 IPC::ResponseBuilder rb{ctx, 2};
113 rb.Push(NfcDisabled);
114 return;
115 }
116
117 if (!ctx.CanWriteBuffer()) {
118 IPC::ResponseBuilder rb{ctx, 2};
119 rb.Push(InvalidArgument);
120 return;
121 }
122
123 if (ctx.GetWriteBufferSize() == 0) {
124 IPC::ResponseBuilder rb{ctx, 2};
125 rb.Push(InvalidArgument);
126 return;
127 }
128
129 std::vector<u64> nfp_devices;
130 const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
131
132 for (const auto& device : devices) {
133 if (nfp_devices.size() >= max_allowed_devices) {
134 continue;
135 }
136 if (device->GetCurrentState() != DeviceState::Unavailable) {
137 nfp_devices.push_back(device->GetHandle());
138 }
139 }
140
141 if (nfp_devices.empty()) {
142 IPC::ResponseBuilder rb{ctx, 2};
143 rb.Push(DeviceNotFound);
144 return;
145 }
146
147 ctx.WriteBuffer(nfp_devices);
148
149 IPC::ResponseBuilder rb{ctx, 3};
150 rb.Push(ResultSuccess);
151 rb.Push(static_cast<s32>(nfp_devices.size()));
152}
153
154void Interface::StartDetection(HLERequestContext& ctx) {
155 IPC::RequestParser rp{ctx};
156 const auto device_handle{rp.Pop<u64>()};
157 const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
158 LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
159
160 if (state == State::NonInitialized) {
161 IPC::ResponseBuilder rb{ctx, 2};
162 rb.Push(NfcDisabled);
163 return;
164 }
165
166 auto device = GetNfpDevice(device_handle);
167
168 if (!device.has_value()) {
169 IPC::ResponseBuilder rb{ctx, 2};
170 rb.Push(DeviceNotFound);
171 return;
172 }
173
174 const auto result = device.value()->StartDetection(nfp_protocol);
175 IPC::ResponseBuilder rb{ctx, 2};
176 rb.Push(result);
177}
178
179void Interface::StopDetection(HLERequestContext& ctx) {
180 IPC::RequestParser rp{ctx};
181 const auto device_handle{rp.Pop<u64>()};
182 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
183
184 if (state == State::NonInitialized) {
185 IPC::ResponseBuilder rb{ctx, 2};
186 rb.Push(NfcDisabled);
187 return;
188 }
189
190 auto device = GetNfpDevice(device_handle);
191
192 if (!device.has_value()) {
193 IPC::ResponseBuilder rb{ctx, 2};
194 rb.Push(DeviceNotFound);
195 return;
196 }
197
198 const auto result = device.value()->StopDetection();
199 IPC::ResponseBuilder rb{ctx, 2};
200 rb.Push(result);
201} 37}
202 38
203void Interface::Mount(HLERequestContext& ctx) { 39void Interface::Mount(HLERequestContext& ctx) {
@@ -208,21 +44,9 @@ void Interface::Mount(HLERequestContext& ctx) {
208 LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle, 44 LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle,
209 model_type, mount_target); 45 model_type, mount_target);
210 46
211 if (state == State::NonInitialized) { 47 auto result = GetManager()->Mount(device_handle, model_type, mount_target);
212 IPC::ResponseBuilder rb{ctx, 2}; 48 result = TranslateResultToServiceError(result);
213 rb.Push(NfcDisabled);
214 return;
215 }
216
217 auto device = GetNfpDevice(device_handle);
218
219 if (!device.has_value()) {
220 IPC::ResponseBuilder rb{ctx, 2};
221 rb.Push(DeviceNotFound);
222 return;
223 }
224 49
225 const auto result = device.value()->Mount(mount_target);
226 IPC::ResponseBuilder rb{ctx, 2}; 50 IPC::ResponseBuilder rb{ctx, 2};
227 rb.Push(result); 51 rb.Push(result);
228} 52}
@@ -232,21 +56,9 @@ void Interface::Unmount(HLERequestContext& ctx) {
232 const auto device_handle{rp.Pop<u64>()}; 56 const auto device_handle{rp.Pop<u64>()};
233 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 57 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
234 58
235 if (state == State::NonInitialized) { 59 auto result = GetManager()->Unmount(device_handle);
236 IPC::ResponseBuilder rb{ctx, 2}; 60 result = TranslateResultToServiceError(result);
237 rb.Push(NfcDisabled);
238 return;
239 }
240
241 auto device = GetNfpDevice(device_handle);
242
243 if (!device.has_value()) {
244 IPC::ResponseBuilder rb{ctx, 2};
245 rb.Push(DeviceNotFound);
246 return;
247 }
248 61
249 const auto result = device.value()->Unmount();
250 IPC::ResponseBuilder rb{ctx, 2}; 62 IPC::ResponseBuilder rb{ctx, 2};
251 rb.Push(result); 63 rb.Push(result);
252} 64}
@@ -257,21 +69,9 @@ void Interface::OpenApplicationArea(HLERequestContext& ctx) {
257 const auto access_id{rp.Pop<u32>()}; 69 const auto access_id{rp.Pop<u32>()};
258 LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id); 70 LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id);
259 71
260 if (state == State::NonInitialized) { 72 auto result = GetManager()->OpenApplicationArea(device_handle, access_id);
261 IPC::ResponseBuilder rb{ctx, 2}; 73 result = TranslateResultToServiceError(result);
262 rb.Push(NfcDisabled);
263 return;
264 }
265
266 auto device = GetNfpDevice(device_handle);
267
268 if (!device.has_value()) {
269 IPC::ResponseBuilder rb{ctx, 2};
270 rb.Push(DeviceNotFound);
271 return;
272 }
273 74
274 const auto result = device.value()->OpenApplicationArea(access_id);
275 IPC::ResponseBuilder rb{ctx, 2}; 75 IPC::ResponseBuilder rb{ctx, 2};
276 rb.Push(result); 76 rb.Push(result);
277} 77}
@@ -282,28 +82,16 @@ void Interface::GetApplicationArea(HLERequestContext& ctx) {
282 const auto data_size = ctx.GetWriteBufferSize(); 82 const auto data_size = ctx.GetWriteBufferSize();
283 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 83 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
284 84
285 if (state == State::NonInitialized) { 85 std::vector<u8> data(data_size);
286 IPC::ResponseBuilder rb{ctx, 2}; 86 auto result = GetManager()->GetApplicationArea(device_handle, data);
287 rb.Push(NfcDisabled); 87 result = TranslateResultToServiceError(result);
288 return;
289 }
290
291 if (!ctx.CanWriteBuffer()) {
292 IPC::ResponseBuilder rb{ctx, 2};
293 rb.Push(InvalidArgument);
294 return;
295 }
296
297 auto device = GetNfpDevice(device_handle);
298 88
299 if (!device.has_value()) { 89 if (result.IsError()) {
300 IPC::ResponseBuilder rb{ctx, 2}; 90 IPC::ResponseBuilder rb{ctx, 2};
301 rb.Push(DeviceNotFound); 91 rb.Push(result);
302 return; 92 return;
303 } 93 }
304 94
305 std::vector<u8> data(data_size);
306 const auto result = device.value()->GetApplicationArea(data);
307 ctx.WriteBuffer(data); 95 ctx.WriteBuffer(data);
308 IPC::ResponseBuilder rb{ctx, 3}; 96 IPC::ResponseBuilder rb{ctx, 3};
309 rb.Push(result); 97 rb.Push(result);
@@ -316,27 +104,9 @@ void Interface::SetApplicationArea(HLERequestContext& ctx) {
316 const auto data{ctx.ReadBuffer()}; 104 const auto data{ctx.ReadBuffer()};
317 LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size()); 105 LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size());
318 106
319 if (state == State::NonInitialized) { 107 auto result = GetManager()->SetApplicationArea(device_handle, data);
320 IPC::ResponseBuilder rb{ctx, 2}; 108 result = TranslateResultToServiceError(result);
321 rb.Push(NfcDisabled);
322 return;
323 }
324
325 if (!ctx.CanReadBuffer()) {
326 IPC::ResponseBuilder rb{ctx, 2};
327 rb.Push(InvalidArgument);
328 return;
329 }
330
331 auto device = GetNfpDevice(device_handle);
332
333 if (!device.has_value()) {
334 IPC::ResponseBuilder rb{ctx, 2};
335 rb.Push(DeviceNotFound);
336 return;
337 }
338 109
339 const auto result = device.value()->SetApplicationArea(data);
340 IPC::ResponseBuilder rb{ctx, 2}; 110 IPC::ResponseBuilder rb{ctx, 2};
341 rb.Push(result); 111 rb.Push(result);
342} 112}
@@ -346,21 +116,9 @@ void Interface::Flush(HLERequestContext& ctx) {
346 const auto device_handle{rp.Pop<u64>()}; 116 const auto device_handle{rp.Pop<u64>()};
347 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 117 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
348 118
349 if (state == State::NonInitialized) { 119 auto result = GetManager()->Flush(device_handle);
350 IPC::ResponseBuilder rb{ctx, 2}; 120 result = TranslateResultToServiceError(result);
351 rb.Push(NfcDisabled);
352 return;
353 }
354
355 auto device = GetNfpDevice(device_handle);
356 121
357 if (!device.has_value()) {
358 IPC::ResponseBuilder rb{ctx, 2};
359 rb.Push(DeviceNotFound);
360 return;
361 }
362
363 const auto result = device.value()->Flush();
364 IPC::ResponseBuilder rb{ctx, 2}; 122 IPC::ResponseBuilder rb{ctx, 2};
365 rb.Push(result); 123 rb.Push(result);
366} 124}
@@ -370,21 +128,9 @@ void Interface::Restore(HLERequestContext& ctx) {
370 const auto device_handle{rp.Pop<u64>()}; 128 const auto device_handle{rp.Pop<u64>()};
371 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle); 129 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
372 130
373 if (state == State::NonInitialized) { 131 auto result = GetManager()->Restore(device_handle);
374 IPC::ResponseBuilder rb{ctx, 2}; 132 result = TranslateResultToServiceError(result);
375 rb.Push(NfcDisabled);
376 return;
377 }
378 133
379 auto device = GetNfpDevice(device_handle);
380
381 if (!device.has_value()) {
382 IPC::ResponseBuilder rb{ctx, 2};
383 rb.Push(DeviceNotFound);
384 return;
385 }
386
387 const auto result = device.value()->RestoreAmiibo();
388 IPC::ResponseBuilder rb{ctx, 2}; 134 IPC::ResponseBuilder rb{ctx, 2};
389 rb.Push(result); 135 rb.Push(result);
390} 136}
@@ -397,53 +143,9 @@ void Interface::CreateApplicationArea(HLERequestContext& ctx) {
397 LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle, 143 LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
398 access_id, data.size()); 144 access_id, data.size());
399 145
400 if (state == State::NonInitialized) { 146 auto result = GetManager()->CreateApplicationArea(device_handle, access_id, data);
401 IPC::ResponseBuilder rb{ctx, 2}; 147 result = TranslateResultToServiceError(result);
402 rb.Push(NfcDisabled);
403 return;
404 }
405
406 if (!ctx.CanReadBuffer()) {
407 IPC::ResponseBuilder rb{ctx, 2};
408 rb.Push(InvalidArgument);
409 return;
410 }
411
412 auto device = GetNfpDevice(device_handle);
413
414 if (!device.has_value()) {
415 IPC::ResponseBuilder rb{ctx, 2};
416 rb.Push(DeviceNotFound);
417 return;
418 }
419
420 const auto result = device.value()->CreateApplicationArea(access_id, data);
421 IPC::ResponseBuilder rb{ctx, 2};
422 rb.Push(result);
423}
424
425void Interface::GetTagInfo(HLERequestContext& ctx) {
426 IPC::RequestParser rp{ctx};
427 const auto device_handle{rp.Pop<u64>()};
428 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
429
430 if (state == State::NonInitialized) {
431 IPC::ResponseBuilder rb{ctx, 2};
432 rb.Push(NfcDisabled);
433 return;
434 }
435
436 auto device = GetNfpDevice(device_handle);
437
438 if (!device.has_value()) {
439 IPC::ResponseBuilder rb{ctx, 2};
440 rb.Push(DeviceNotFound);
441 return;
442 }
443 148
444 TagInfo tag_info{};
445 const auto result = device.value()->GetTagInfo(tag_info);
446 ctx.WriteBuffer(tag_info);
447 IPC::ResponseBuilder rb{ctx, 2}; 149 IPC::ResponseBuilder rb{ctx, 2};
448 rb.Push(result); 150 rb.Push(result);
449} 151}
@@ -453,23 +155,14 @@ void Interface::GetRegisterInfo(HLERequestContext& ctx) {
453 const auto device_handle{rp.Pop<u64>()}; 155 const auto device_handle{rp.Pop<u64>()};
454 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 156 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
455 157
456 if (state == State::NonInitialized) { 158 RegisterInfo register_info{};
457 IPC::ResponseBuilder rb{ctx, 2}; 159 auto result = GetManager()->GetRegisterInfo(device_handle, register_info);
458 rb.Push(NfcDisabled); 160 result = TranslateResultToServiceError(result);
459 return;
460 }
461
462 auto device = GetNfpDevice(device_handle);
463 161
464 if (!device.has_value()) { 162 if (result.IsSuccess()) {
465 IPC::ResponseBuilder rb{ctx, 2}; 163 ctx.WriteBuffer(register_info);
466 rb.Push(DeviceNotFound);
467 return;
468 } 164 }
469 165
470 RegisterInfo register_info{};
471 const auto result = device.value()->GetRegisterInfo(register_info);
472 ctx.WriteBuffer(register_info);
473 IPC::ResponseBuilder rb{ctx, 2}; 166 IPC::ResponseBuilder rb{ctx, 2};
474 rb.Push(result); 167 rb.Push(result);
475} 168}
@@ -479,23 +172,14 @@ void Interface::GetCommonInfo(HLERequestContext& ctx) {
479 const auto device_handle{rp.Pop<u64>()}; 172 const auto device_handle{rp.Pop<u64>()};
480 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 173 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
481 174
482 if (state == State::NonInitialized) { 175 CommonInfo common_info{};
483 IPC::ResponseBuilder rb{ctx, 2}; 176 auto result = GetManager()->GetCommonInfo(device_handle, common_info);
484 rb.Push(NfcDisabled); 177 result = TranslateResultToServiceError(result);
485 return;
486 }
487
488 auto device = GetNfpDevice(device_handle);
489 178
490 if (!device.has_value()) { 179 if (result.IsSuccess()) {
491 IPC::ResponseBuilder rb{ctx, 2}; 180 ctx.WriteBuffer(common_info);
492 rb.Push(DeviceNotFound);
493 return;
494 } 181 }
495 182
496 CommonInfo common_info{};
497 const auto result = device.value()->GetCommonInfo(common_info);
498 ctx.WriteBuffer(common_info);
499 IPC::ResponseBuilder rb{ctx, 2}; 183 IPC::ResponseBuilder rb{ctx, 2};
500 rb.Push(result); 184 rb.Push(result);
501} 185}
@@ -505,155 +189,26 @@ void Interface::GetModelInfo(HLERequestContext& ctx) {
505 const auto device_handle{rp.Pop<u64>()}; 189 const auto device_handle{rp.Pop<u64>()};
506 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 190 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
507 191
508 if (state == State::NonInitialized) { 192 ModelInfo model_info{};
509 IPC::ResponseBuilder rb{ctx, 2}; 193 auto result = GetManager()->GetModelInfo(device_handle, model_info);
510 rb.Push(NfcDisabled); 194 result = TranslateResultToServiceError(result);
511 return;
512 }
513
514 auto device = GetNfpDevice(device_handle);
515 195
516 if (!device.has_value()) { 196 if (result.IsSuccess()) {
517 IPC::ResponseBuilder rb{ctx, 2}; 197 ctx.WriteBuffer(model_info);
518 rb.Push(DeviceNotFound);
519 return;
520 } 198 }
521 199
522 ModelInfo model_info{};
523 const auto result = device.value()->GetModelInfo(model_info);
524 ctx.WriteBuffer(model_info);
525 IPC::ResponseBuilder rb{ctx, 2}; 200 IPC::ResponseBuilder rb{ctx, 2};
526 rb.Push(result); 201 rb.Push(result);
527} 202}
528 203
529void Interface::AttachActivateEvent(HLERequestContext& ctx) {
530 IPC::RequestParser rp{ctx};
531 const auto device_handle{rp.Pop<u64>()};
532 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
533
534 if (state == State::NonInitialized) {
535 IPC::ResponseBuilder rb{ctx, 2};
536 rb.Push(NfcDisabled);
537 return;
538 }
539
540 auto device = GetNfpDevice(device_handle);
541
542 if (!device.has_value()) {
543 IPC::ResponseBuilder rb{ctx, 2};
544 rb.Push(DeviceNotFound);
545 return;
546 }
547
548 IPC::ResponseBuilder rb{ctx, 2, 1};
549 rb.Push(ResultSuccess);
550 rb.PushCopyObjects(device.value()->GetActivateEvent());
551}
552
553void Interface::AttachDeactivateEvent(HLERequestContext& ctx) {
554 IPC::RequestParser rp{ctx};
555 const auto device_handle{rp.Pop<u64>()};
556 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
557
558 if (state == State::NonInitialized) {
559 IPC::ResponseBuilder rb{ctx, 2};
560 rb.Push(NfcDisabled);
561 return;
562 }
563
564 auto device = GetNfpDevice(device_handle);
565
566 if (!device.has_value()) {
567 IPC::ResponseBuilder rb{ctx, 2};
568 rb.Push(DeviceNotFound);
569 return;
570 }
571
572 IPC::ResponseBuilder rb{ctx, 2, 1};
573 rb.Push(ResultSuccess);
574 rb.PushCopyObjects(device.value()->GetDeactivateEvent());
575}
576
577void Interface::GetState(HLERequestContext& ctx) {
578 LOG_DEBUG(Service_NFP, "called");
579
580 IPC::ResponseBuilder rb{ctx, 3};
581 rb.Push(ResultSuccess);
582 rb.PushEnum(state);
583}
584
585void Interface::GetDeviceState(HLERequestContext& ctx) {
586 IPC::RequestParser rp{ctx};
587 const auto device_handle{rp.Pop<u64>()};
588 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
589
590 auto device = GetNfpDevice(device_handle);
591
592 if (!device.has_value()) {
593 IPC::ResponseBuilder rb{ctx, 2};
594 rb.Push(DeviceNotFound);
595 return;
596 }
597
598 IPC::ResponseBuilder rb{ctx, 3};
599 rb.Push(ResultSuccess);
600 rb.PushEnum(device.value()->GetCurrentState());
601}
602
603void Interface::GetNpadId(HLERequestContext& ctx) {
604 IPC::RequestParser rp{ctx};
605 const auto device_handle{rp.Pop<u64>()};
606 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
607
608 if (state == State::NonInitialized) {
609 IPC::ResponseBuilder rb{ctx, 2};
610 rb.Push(NfcDisabled);
611 return;
612 }
613
614 auto device = GetNfpDevice(device_handle);
615
616 if (!device.has_value()) {
617 IPC::ResponseBuilder rb{ctx, 2};
618 rb.Push(DeviceNotFound);
619 return;
620 }
621
622 IPC::ResponseBuilder rb{ctx, 3};
623 rb.Push(ResultSuccess);
624 rb.PushEnum(device.value()->GetNpadId());
625}
626
627void Interface::GetApplicationAreaSize(HLERequestContext& ctx) { 204void Interface::GetApplicationAreaSize(HLERequestContext& ctx) {
628 IPC::RequestParser rp{ctx}; 205 IPC::RequestParser rp{ctx};
629 const auto device_handle{rp.Pop<u64>()}; 206 const auto device_handle{rp.Pop<u64>()};
630 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 207 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
631 208
632 auto device = GetNfpDevice(device_handle);
633
634 if (!device.has_value()) {
635 IPC::ResponseBuilder rb{ctx, 2};
636 rb.Push(DeviceNotFound);
637 return;
638 }
639
640 IPC::ResponseBuilder rb{ctx, 3}; 209 IPC::ResponseBuilder rb{ctx, 3};
641 rb.Push(ResultSuccess); 210 rb.Push(ResultSuccess);
642 rb.Push(device.value()->GetApplicationAreaSize()); 211 rb.Push(GetManager()->GetApplicationAreaSize());
643}
644
645void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
646 LOG_INFO(Service_NFP, "called");
647
648 if (state == State::NonInitialized) {
649 IPC::ResponseBuilder rb{ctx, 2};
650 rb.Push(NfcDisabled);
651 return;
652 }
653
654 IPC::ResponseBuilder rb{ctx, 2, 1};
655 rb.Push(ResultSuccess);
656 rb.PushCopyObjects(availability_change_event->GetReadableEvent());
657} 212}
658 213
659void Interface::RecreateApplicationArea(HLERequestContext& ctx) { 214void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
@@ -664,21 +219,9 @@ void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
664 LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle, 219 LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
665 access_id, data.size()); 220 access_id, data.size());
666 221
667 if (state == State::NonInitialized) { 222 auto result = GetManager()->RecreateApplicationArea(device_handle, access_id, data);
668 IPC::ResponseBuilder rb{ctx, 2}; 223 result = TranslateResultToServiceError(result);
669 rb.Push(NfcDisabled);
670 return;
671 }
672 224
673 auto device = GetNfpDevice(device_handle);
674
675 if (!device.has_value()) {
676 IPC::ResponseBuilder rb{ctx, 2};
677 rb.Push(DeviceNotFound);
678 return;
679 }
680
681 const auto result = device.value()->RecreateApplicationArea(access_id, data);
682 IPC::ResponseBuilder rb{ctx, 2}; 225 IPC::ResponseBuilder rb{ctx, 2};
683 rb.Push(result); 226 rb.Push(result);
684} 227}
@@ -686,23 +229,11 @@ void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
686void Interface::Format(HLERequestContext& ctx) { 229void Interface::Format(HLERequestContext& ctx) {
687 IPC::RequestParser rp{ctx}; 230 IPC::RequestParser rp{ctx};
688 const auto device_handle{rp.Pop<u64>()}; 231 const auto device_handle{rp.Pop<u64>()};
689 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 232 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
690
691 if (state == State::NonInitialized) {
692 IPC::ResponseBuilder rb{ctx, 2};
693 rb.Push(NfcDisabled);
694 return;
695 }
696 233
697 auto device = GetNfpDevice(device_handle); 234 auto result = GetManager()->Format(device_handle);
235 result = TranslateResultToServiceError(result);
698 236
699 if (!device.has_value()) {
700 IPC::ResponseBuilder rb{ctx, 2};
701 rb.Push(DeviceNotFound);
702 return;
703 }
704
705 const auto result = device.value()->Format();
706 IPC::ResponseBuilder rb{ctx, 2}; 237 IPC::ResponseBuilder rb{ctx, 2};
707 rb.Push(result); 238 rb.Push(result);
708} 239}
@@ -712,23 +243,14 @@ void Interface::GetAdminInfo(HLERequestContext& ctx) {
712 const auto device_handle{rp.Pop<u64>()}; 243 const auto device_handle{rp.Pop<u64>()};
713 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 244 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
714 245
715 if (state == State::NonInitialized) { 246 AdminInfo admin_info{};
716 IPC::ResponseBuilder rb{ctx, 2}; 247 auto result = GetManager()->GetAdminInfo(device_handle, admin_info);
717 rb.Push(NfcDisabled); 248 result = TranslateResultToServiceError(result);
718 return;
719 }
720
721 auto device = GetNfpDevice(device_handle);
722 249
723 if (!device.has_value()) { 250 if (result.IsSuccess()) {
724 IPC::ResponseBuilder rb{ctx, 2}; 251 ctx.WriteBuffer(admin_info);
725 rb.Push(DeviceNotFound);
726 return;
727 } 252 }
728 253
729 AdminInfo admin_info{};
730 const auto result = device.value()->GetAdminInfo(admin_info);
731 ctx.WriteBuffer(admin_info);
732 IPC::ResponseBuilder rb{ctx, 2}; 254 IPC::ResponseBuilder rb{ctx, 2};
733 rb.Push(result); 255 rb.Push(result);
734} 256}
@@ -738,23 +260,14 @@ void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) {
738 const auto device_handle{rp.Pop<u64>()}; 260 const auto device_handle{rp.Pop<u64>()};
739 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 261 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
740 262
741 if (state == State::NonInitialized) { 263 RegisterInfoPrivate register_info{};
742 IPC::ResponseBuilder rb{ctx, 2}; 264 auto result = GetManager()->GetRegisterInfoPrivate(device_handle, register_info);
743 rb.Push(NfcDisabled); 265 result = TranslateResultToServiceError(result);
744 return;
745 }
746
747 auto device = GetNfpDevice(device_handle);
748 266
749 if (!device.has_value()) { 267 if (result.IsSuccess()) {
750 IPC::ResponseBuilder rb{ctx, 2}; 268 ctx.WriteBuffer(register_info);
751 rb.Push(DeviceNotFound);
752 return;
753 } 269 }
754 270
755 RegisterInfoPrivate register_info{};
756 const auto result = device.value()->GetRegisterInfoPrivate(register_info);
757 ctx.WriteBuffer(register_info);
758 IPC::ResponseBuilder rb{ctx, 2}; 271 IPC::ResponseBuilder rb{ctx, 2};
759 rb.Push(result); 272 rb.Push(result);
760} 273}
@@ -762,25 +275,15 @@ void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) {
762void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) { 275void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) {
763 IPC::RequestParser rp{ctx}; 276 IPC::RequestParser rp{ctx};
764 const auto device_handle{rp.Pop<u64>()}; 277 const auto device_handle{rp.Pop<u64>()};
765 const auto buffer{ctx.ReadBuffer()}; 278 const auto register_info_buffer{ctx.ReadBuffer()};
766 LOG_DEBUG(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle, 279 LOG_INFO(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle,
767 buffer.size()); 280 register_info_buffer.size());
768 281
769 if (state == State::NonInitialized) { 282 RegisterInfoPrivate register_info{};
770 IPC::ResponseBuilder rb{ctx, 2}; 283 memcpy(&register_info, register_info_buffer.data(), sizeof(RegisterInfoPrivate));
771 rb.Push(NfcDisabled); 284 auto result = GetManager()->SetRegisterInfoPrivate(device_handle, register_info);
772 return; 285 result = TranslateResultToServiceError(result);
773 }
774
775 auto device = GetNfpDevice(device_handle);
776
777 if (!device.has_value()) {
778 IPC::ResponseBuilder rb{ctx, 2};
779 rb.Push(DeviceNotFound);
780 return;
781 }
782 286
783 const auto result = device.value()->SetRegisterInfoPrivate({});
784 IPC::ResponseBuilder rb{ctx, 2}; 287 IPC::ResponseBuilder rb{ctx, 2};
785 rb.Push(result); 288 rb.Push(result);
786} 289}
@@ -788,23 +291,11 @@ void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) {
788void Interface::DeleteRegisterInfo(HLERequestContext& ctx) { 291void Interface::DeleteRegisterInfo(HLERequestContext& ctx) {
789 IPC::RequestParser rp{ctx}; 292 IPC::RequestParser rp{ctx};
790 const auto device_handle{rp.Pop<u64>()}; 293 const auto device_handle{rp.Pop<u64>()};
791 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 294 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
792
793 if (state == State::NonInitialized) {
794 IPC::ResponseBuilder rb{ctx, 2};
795 rb.Push(NfcDisabled);
796 return;
797 }
798 295
799 auto device = GetNfpDevice(device_handle); 296 auto result = GetManager()->DeleteRegisterInfo(device_handle);
297 result = TranslateResultToServiceError(result);
800 298
801 if (!device.has_value()) {
802 IPC::ResponseBuilder rb{ctx, 2};
803 rb.Push(DeviceNotFound);
804 return;
805 }
806
807 const auto result = device.value()->DeleteRegisterInfo();
808 IPC::ResponseBuilder rb{ctx, 2}; 299 IPC::ResponseBuilder rb{ctx, 2};
809 rb.Push(result); 300 rb.Push(result);
810} 301}
@@ -812,23 +303,11 @@ void Interface::DeleteRegisterInfo(HLERequestContext& ctx) {
812void Interface::DeleteApplicationArea(HLERequestContext& ctx) { 303void Interface::DeleteApplicationArea(HLERequestContext& ctx) {
813 IPC::RequestParser rp{ctx}; 304 IPC::RequestParser rp{ctx};
814 const auto device_handle{rp.Pop<u64>()}; 305 const auto device_handle{rp.Pop<u64>()};
815 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 306 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
816
817 if (state == State::NonInitialized) {
818 IPC::ResponseBuilder rb{ctx, 2};
819 rb.Push(NfcDisabled);
820 return;
821 }
822 307
823 auto device = GetNfpDevice(device_handle); 308 auto result = GetManager()->DeleteApplicationArea(device_handle);
309 result = TranslateResultToServiceError(result);
824 310
825 if (!device.has_value()) {
826 IPC::ResponseBuilder rb{ctx, 2};
827 rb.Push(DeviceNotFound);
828 return;
829 }
830
831 const auto result = device.value()->DeleteApplicationArea();
832 IPC::ResponseBuilder rb{ctx, 2}; 311 IPC::ResponseBuilder rb{ctx, 2};
833 rb.Push(result); 312 rb.Push(result);
834} 313}
@@ -836,24 +315,18 @@ void Interface::DeleteApplicationArea(HLERequestContext& ctx) {
836void Interface::ExistsApplicationArea(HLERequestContext& ctx) { 315void Interface::ExistsApplicationArea(HLERequestContext& ctx) {
837 IPC::RequestParser rp{ctx}; 316 IPC::RequestParser rp{ctx};
838 const auto device_handle{rp.Pop<u64>()}; 317 const auto device_handle{rp.Pop<u64>()};
839 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 318 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
840
841 if (state == State::NonInitialized) {
842 IPC::ResponseBuilder rb{ctx, 2};
843 rb.Push(NfcDisabled);
844 return;
845 }
846 319
847 auto device = GetNfpDevice(device_handle); 320 bool has_application_area = false;
321 auto result = GetManager()->ExistsApplicationArea(device_handle, has_application_area);
322 result = TranslateResultToServiceError(result);
848 323
849 if (!device.has_value()) { 324 if (result.IsError()) {
850 IPC::ResponseBuilder rb{ctx, 2}; 325 IPC::ResponseBuilder rb{ctx, 2};
851 rb.Push(DeviceNotFound); 326 rb.Push(result);
852 return; 327 return;
853 } 328 }
854 329
855 bool has_application_area = false;
856 const auto result = device.value()->ExistApplicationArea(has_application_area);
857 IPC::ResponseBuilder rb{ctx, 3}; 330 IPC::ResponseBuilder rb{ctx, 3};
858 rb.Push(result); 331 rb.Push(result);
859 rb.Push(has_application_area); 332 rb.Push(has_application_area);
@@ -862,27 +335,16 @@ void Interface::ExistsApplicationArea(HLERequestContext& ctx) {
862void Interface::GetAll(HLERequestContext& ctx) { 335void Interface::GetAll(HLERequestContext& ctx) {
863 IPC::RequestParser rp{ctx}; 336 IPC::RequestParser rp{ctx};
864 const auto device_handle{rp.Pop<u64>()}; 337 const auto device_handle{rp.Pop<u64>()};
865 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 338 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
866
867 if (state == State::NonInitialized) {
868 IPC::ResponseBuilder rb{ctx, 2};
869 rb.Push(NfcDisabled);
870 return;
871 }
872 339
873 auto device = GetNfpDevice(device_handle); 340 NfpData nfp_data{};
341 auto result = GetManager()->GetAll(device_handle, nfp_data);
342 result = TranslateResultToServiceError(result);
874 343
875 if (!device.has_value()) { 344 if (result.IsSuccess()) {
876 IPC::ResponseBuilder rb{ctx, 2}; 345 ctx.WriteBuffer(nfp_data);
877 rb.Push(DeviceNotFound);
878 return;
879 } 346 }
880 347
881 NfpData data{};
882 const auto result = device.value()->GetAll(data);
883
884 ctx.WriteBuffer(data);
885
886 IPC::ResponseBuilder rb{ctx, 2}; 348 IPC::ResponseBuilder rb{ctx, 2};
887 rb.Push(result); 349 rb.Push(result);
888} 350}
@@ -890,28 +352,15 @@ void Interface::GetAll(HLERequestContext& ctx) {
890void Interface::SetAll(HLERequestContext& ctx) { 352void Interface::SetAll(HLERequestContext& ctx) {
891 IPC::RequestParser rp{ctx}; 353 IPC::RequestParser rp{ctx};
892 const auto device_handle{rp.Pop<u64>()}; 354 const auto device_handle{rp.Pop<u64>()};
893 const auto nfp_data{ctx.ReadBuffer()}; 355 const auto nfp_data_buffer{ctx.ReadBuffer()};
894
895 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
896
897 if (state == State::NonInitialized) {
898 IPC::ResponseBuilder rb{ctx, 2};
899 rb.Push(NfcDisabled);
900 return;
901 }
902 356
903 auto device = GetNfpDevice(device_handle); 357 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
904
905 if (!device.has_value()) {
906 IPC::ResponseBuilder rb{ctx, 2};
907 rb.Push(DeviceNotFound);
908 return;
909 }
910 358
911 NfpData data{}; 359 NfpData nfp_data{};
912 memcpy(&data, nfp_data.data(), sizeof(NfpData)); 360 memcpy(&nfp_data, nfp_data_buffer.data(), sizeof(NfpData));
361 auto result = GetManager()->SetAll(device_handle, nfp_data);
362 result = TranslateResultToServiceError(result);
913 363
914 const auto result = device.value()->SetAll(data);
915 IPC::ResponseBuilder rb{ctx, 2}; 364 IPC::ResponseBuilder rb{ctx, 2};
916 rb.Push(result); 365 rb.Push(result);
917} 366}
@@ -919,23 +368,11 @@ void Interface::SetAll(HLERequestContext& ctx) {
919void Interface::FlushDebug(HLERequestContext& ctx) { 368void Interface::FlushDebug(HLERequestContext& ctx) {
920 IPC::RequestParser rp{ctx}; 369 IPC::RequestParser rp{ctx};
921 const auto device_handle{rp.Pop<u64>()}; 370 const auto device_handle{rp.Pop<u64>()};
922 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 371 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
923
924 if (state == State::NonInitialized) {
925 IPC::ResponseBuilder rb{ctx, 2};
926 rb.Push(NfcDisabled);
927 return;
928 }
929 372
930 auto device = GetNfpDevice(device_handle); 373 auto result = GetManager()->FlushDebug(device_handle);
374 result = TranslateResultToServiceError(result);
931 375
932 if (!device.has_value()) {
933 IPC::ResponseBuilder rb{ctx, 2};
934 rb.Push(DeviceNotFound);
935 return;
936 }
937
938 const auto result = device.value()->FlushDebug();
939 IPC::ResponseBuilder rb{ctx, 2}; 376 IPC::ResponseBuilder rb{ctx, 2};
940 rb.Push(result); 377 rb.Push(result);
941} 378}
@@ -944,23 +381,12 @@ void Interface::BreakTag(HLERequestContext& ctx) {
944 IPC::RequestParser rp{ctx}; 381 IPC::RequestParser rp{ctx};
945 const auto device_handle{rp.Pop<u64>()}; 382 const auto device_handle{rp.Pop<u64>()};
946 const auto break_type{rp.PopEnum<BreakType>()}; 383 const auto break_type{rp.PopEnum<BreakType>()};
947 LOG_DEBUG(Service_NFP, "called, device_handle={}, break_type={}", device_handle, break_type); 384 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, break_type={}", device_handle,
385 break_type);
948 386
949 if (state == State::NonInitialized) { 387 auto result = GetManager()->BreakTag(device_handle, break_type);
950 IPC::ResponseBuilder rb{ctx, 2}; 388 result = TranslateResultToServiceError(result);
951 rb.Push(NfcDisabled);
952 return;
953 }
954 389
955 auto device = GetNfpDevice(device_handle);
956
957 if (!device.has_value()) {
958 IPC::ResponseBuilder rb{ctx, 2};
959 rb.Push(DeviceNotFound);
960 return;
961 }
962
963 const auto result = device.value()->BreakTag(break_type);
964 IPC::ResponseBuilder rb{ctx, 2}; 390 IPC::ResponseBuilder rb{ctx, 2};
965 rb.Push(result); 391 rb.Push(result);
966} 392}
@@ -968,23 +394,16 @@ void Interface::BreakTag(HLERequestContext& ctx) {
968void Interface::ReadBackupData(HLERequestContext& ctx) { 394void Interface::ReadBackupData(HLERequestContext& ctx) {
969 IPC::RequestParser rp{ctx}; 395 IPC::RequestParser rp{ctx};
970 const auto device_handle{rp.Pop<u64>()}; 396 const auto device_handle{rp.Pop<u64>()};
971 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 397 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
972
973 if (state == State::NonInitialized) {
974 IPC::ResponseBuilder rb{ctx, 2};
975 rb.Push(NfcDisabled);
976 return;
977 }
978 398
979 auto device = GetNfpDevice(device_handle); 399 std::vector<u8> backup_data{};
400 auto result = GetManager()->ReadBackupData(device_handle, backup_data);
401 result = TranslateResultToServiceError(result);
980 402
981 if (!device.has_value()) { 403 if (result.IsSuccess()) {
982 IPC::ResponseBuilder rb{ctx, 2}; 404 ctx.WriteBuffer(backup_data);
983 rb.Push(DeviceNotFound);
984 return;
985 } 405 }
986 406
987 const auto result = device.value()->ReadBackupData();
988 IPC::ResponseBuilder rb{ctx, 2}; 407 IPC::ResponseBuilder rb{ctx, 2};
989 rb.Push(result); 408 rb.Push(result);
990} 409}
@@ -992,23 +411,12 @@ void Interface::ReadBackupData(HLERequestContext& ctx) {
992void Interface::WriteBackupData(HLERequestContext& ctx) { 411void Interface::WriteBackupData(HLERequestContext& ctx) {
993 IPC::RequestParser rp{ctx}; 412 IPC::RequestParser rp{ctx};
994 const auto device_handle{rp.Pop<u64>()}; 413 const auto device_handle{rp.Pop<u64>()};
995 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 414 const auto backup_data_buffer{ctx.ReadBuffer()};
996 415 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
997 if (state == State::NonInitialized) {
998 IPC::ResponseBuilder rb{ctx, 2};
999 rb.Push(NfcDisabled);
1000 return;
1001 }
1002
1003 auto device = GetNfpDevice(device_handle);
1004 416
1005 if (!device.has_value()) { 417 auto result = GetManager()->WriteBackupData(device_handle, backup_data_buffer);
1006 IPC::ResponseBuilder rb{ctx, 2}; 418 result = TranslateResultToServiceError(result);
1007 rb.Push(DeviceNotFound);
1008 return;
1009 }
1010 419
1011 const auto result = device.value()->WriteBackupData();
1012 IPC::ResponseBuilder rb{ctx, 2}; 420 IPC::ResponseBuilder rb{ctx, 2};
1013 rb.Push(result); 421 rb.Push(result);
1014} 422}
@@ -1016,34 +424,15 @@ void Interface::WriteBackupData(HLERequestContext& ctx) {
1016void Interface::WriteNtf(HLERequestContext& ctx) { 424void Interface::WriteNtf(HLERequestContext& ctx) {
1017 IPC::RequestParser rp{ctx}; 425 IPC::RequestParser rp{ctx};
1018 const auto device_handle{rp.Pop<u64>()}; 426 const auto device_handle{rp.Pop<u64>()};
1019 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 427 const auto write_type{rp.PopEnum<WriteType>()};
1020 428 const auto ntf_data_buffer{ctx.ReadBuffer()};
1021 if (state == State::NonInitialized) { 429 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
1022 IPC::ResponseBuilder rb{ctx, 2};
1023 rb.Push(NfcDisabled);
1024 return;
1025 }
1026 430
1027 auto device = GetNfpDevice(device_handle); 431 auto result = GetManager()->WriteNtf(device_handle, write_type, ntf_data_buffer);
432 result = TranslateResultToServiceError(result);
1028 433
1029 if (!device.has_value()) {
1030 IPC::ResponseBuilder rb{ctx, 2};
1031 rb.Push(DeviceNotFound);
1032 return;
1033 }
1034
1035 const auto result = device.value()->WriteNtf();
1036 IPC::ResponseBuilder rb{ctx, 2}; 434 IPC::ResponseBuilder rb{ctx, 2};
1037 rb.Push(result); 435 rb.Push(result);
1038} 436}
1039 437
1040std::optional<std::shared_ptr<NfpDevice>> Interface::GetNfpDevice(u64 handle) {
1041 for (auto& device : devices) {
1042 if (device->GetHandle() == handle) {
1043 return device;
1044 }
1045 }
1046 return std::nullopt;
1047}
1048
1049} // namespace Service::NFP 438} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_interface.h b/src/core/hle/service/nfp/nfp_interface.h
index 616c94b06..fa985b068 100644
--- a/src/core/hle/service/nfp/nfp_interface.h
+++ b/src/core/hle/service/nfp/nfp_interface.h
@@ -1,32 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#pragma once 4#pragma once
5 5
6#include <array>
7#include <memory>
8#include <optional>
9
10#include "core/hle/service/kernel_helpers.h" 6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/nfc/nfc_interface.h"
11#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
12 9
13namespace Service::NFP { 10namespace Service::NFP {
14class NfpDevice;
15 11
16class Interface : public ServiceFramework<Interface> { 12class Interface : public NFC::NfcInterface {
17public: 13public:
18 explicit Interface(Core::System& system_, const char* name); 14 explicit Interface(Core::System& system_, const char* name);
19 ~Interface() override; 15 ~Interface() override;
20 16
21 void Initialize(HLERequestContext& ctx);
22 void InitializeSystem(HLERequestContext& ctx); 17 void InitializeSystem(HLERequestContext& ctx);
23 void InitializeDebug(HLERequestContext& ctx); 18 void InitializeDebug(HLERequestContext& ctx);
24 void Finalize(HLERequestContext& ctx);
25 void FinalizeSystem(HLERequestContext& ctx); 19 void FinalizeSystem(HLERequestContext& ctx);
26 void FinalizeDebug(HLERequestContext& ctx); 20 void FinalizeDebug(HLERequestContext& ctx);
27 void ListDevices(HLERequestContext& ctx);
28 void StartDetection(HLERequestContext& ctx);
29 void StopDetection(HLERequestContext& ctx);
30 void Mount(HLERequestContext& ctx); 21 void Mount(HLERequestContext& ctx);
31 void Unmount(HLERequestContext& ctx); 22 void Unmount(HLERequestContext& ctx);
32 void OpenApplicationArea(HLERequestContext& ctx); 23 void OpenApplicationArea(HLERequestContext& ctx);
@@ -35,17 +26,10 @@ public:
35 void Flush(HLERequestContext& ctx); 26 void Flush(HLERequestContext& ctx);
36 void Restore(HLERequestContext& ctx); 27 void Restore(HLERequestContext& ctx);
37 void CreateApplicationArea(HLERequestContext& ctx); 28 void CreateApplicationArea(HLERequestContext& ctx);
38 void GetTagInfo(HLERequestContext& ctx);
39 void GetRegisterInfo(HLERequestContext& ctx); 29 void GetRegisterInfo(HLERequestContext& ctx);
40 void GetCommonInfo(HLERequestContext& ctx); 30 void GetCommonInfo(HLERequestContext& ctx);
41 void GetModelInfo(HLERequestContext& ctx); 31 void GetModelInfo(HLERequestContext& ctx);
42 void AttachActivateEvent(HLERequestContext& ctx);
43 void AttachDeactivateEvent(HLERequestContext& ctx);
44 void GetState(HLERequestContext& ctx);
45 void GetDeviceState(HLERequestContext& ctx);
46 void GetNpadId(HLERequestContext& ctx);
47 void GetApplicationAreaSize(HLERequestContext& ctx); 32 void GetApplicationAreaSize(HLERequestContext& ctx);
48 void AttachAvailabilityChangeEvent(HLERequestContext& ctx);
49 void RecreateApplicationArea(HLERequestContext& ctx); 33 void RecreateApplicationArea(HLERequestContext& ctx);
50 void Format(HLERequestContext& ctx); 34 void Format(HLERequestContext& ctx);
51 void GetAdminInfo(HLERequestContext& ctx); 35 void GetAdminInfo(HLERequestContext& ctx);
@@ -61,21 +45,6 @@ public:
61 void ReadBackupData(HLERequestContext& ctx); 45 void ReadBackupData(HLERequestContext& ctx);
62 void WriteBackupData(HLERequestContext& ctx); 46 void WriteBackupData(HLERequestContext& ctx);
63 void WriteNtf(HLERequestContext& ctx); 47 void WriteNtf(HLERequestContext& ctx);
64
65private:
66 enum class State : u32 {
67 NonInitialized,
68 Initialized,
69 };
70
71 std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle);
72
73 KernelHelpers::ServiceContext service_context;
74
75 std::array<std::shared_ptr<NfpDevice>, 10> devices{};
76
77 State state{State::NonInitialized};
78 Kernel::KEvent* availability_change_event;
79}; 48};
80 49
81} // namespace Service::NFP 50} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_result.h b/src/core/hle/service/nfp/nfp_result.h
index d8e4cf094..4c126cd81 100644
--- a/src/core/hle/service/nfp/nfp_result.h
+++ b/src/core/hle/service/nfp/nfp_result.h
@@ -1,5 +1,5 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#pragma once 4#pragma once
5 5
@@ -7,18 +7,19 @@
7 7
8namespace Service::NFP { 8namespace Service::NFP {
9 9
10constexpr Result DeviceNotFound(ErrorModule::NFP, 64); 10constexpr Result ResultDeviceNotFound(ErrorModule::NFP, 64);
11constexpr Result InvalidArgument(ErrorModule::NFP, 65); 11constexpr Result ResultInvalidArgument(ErrorModule::NFP, 65);
12constexpr Result WrongApplicationAreaSize(ErrorModule::NFP, 68); 12constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
13constexpr Result WrongDeviceState(ErrorModule::NFP, 73); 13constexpr Result ResultWrongDeviceState(ErrorModule::NFP, 73);
14constexpr Result NfcDisabled(ErrorModule::NFP, 80); 14constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
15constexpr Result WriteAmiiboFailed(ErrorModule::NFP, 88); 15constexpr Result ResultNfcDisabled(ErrorModule::NFP, 80);
16constexpr Result TagRemoved(ErrorModule::NFP, 97); 16constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
17constexpr Result RegistrationIsNotInitialized(ErrorModule::NFP, 120); 17constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
18constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); 18constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
19constexpr Result CorruptedData(ErrorModule::NFP, 144); 19constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
20constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152); 20constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
21constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168); 21constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
22constexpr Result NotAnAmiibo(ErrorModule::NFP, 178); 22constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
23constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
23 24
24} // namespace Service::NFP 25} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index 1ef047cee..7d36d5ee6 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -7,32 +7,19 @@
7 7
8#include "common/swap.h" 8#include "common/swap.h"
9#include "core/hle/service/mii/types.h" 9#include "core/hle/service/mii/types.h"
10#include "core/hle/service/nfc/nfc_types.h"
10 11
11namespace Service::NFP { 12namespace Service::NFP {
12static constexpr std::size_t amiibo_name_length = 0xA; 13static constexpr std::size_t amiibo_name_length = 0xA;
13static constexpr std::size_t application_id_version_offset = 0x1c; 14static constexpr std::size_t application_id_version_offset = 0x1c;
14static constexpr std::size_t counter_limit = 0xffff; 15static constexpr std::size_t counter_limit = 0xffff;
15 16
16enum class ServiceType : u32 { 17// This is nn::nfp::ModelType
17 User,
18 Debug,
19 System,
20};
21
22enum class DeviceState : u32 {
23 Initialized,
24 SearchingForTag,
25 TagFound,
26 TagRemoved,
27 TagMounted,
28 Unavailable,
29 Finalized,
30};
31
32enum class ModelType : u32 { 18enum class ModelType : u32 {
33 Amiibo, 19 Amiibo,
34}; 20};
35 21
22// This is nn::nfp::MountTarget
36enum class MountTarget : u32 { 23enum class MountTarget : u32 {
37 None, 24 None,
38 Rom, 25 Rom,
@@ -72,35 +59,6 @@ enum class AmiiboSeries : u8 {
72 Diablo, 59 Diablo,
73}; 60};
74 61
75enum class TagType : u32 {
76 None,
77 Type1, // ISO14443A RW 96-2k bytes 106kbit/s
78 Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
79 Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
80 Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
81 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
82};
83
84enum class PackedTagType : u8 {
85 None,
86 Type1, // ISO14443A RW 96-2k bytes 106kbit/s
87 Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
88 Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
89 Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
90 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
91};
92
93// Verify this enum. It might be completely wrong default protocol is 0x48
94enum class TagProtocol : u32 {
95 None,
96 TypeA = 1U << 0, // ISO14443A
97 TypeB = 1U << 1, // ISO14443B
98 TypeF = 1U << 2, // Sony Felica
99 Unknown1 = 1U << 3,
100 Unknown2 = 1U << 5,
101 All = 0xFFFFFFFFU,
102};
103
104enum class AppAreaVersion : u8 { 62enum class AppAreaVersion : u8 {
105 Nintendo3DS = 0, 63 Nintendo3DS = 0,
106 NintendoWiiU = 1, 64 NintendoWiiU = 1,
@@ -115,6 +73,11 @@ enum class BreakType : u32 {
115 Unknown2, 73 Unknown2,
116}; 74};
117 75
76enum class WriteType : u32 {
77 Unknown0,
78 Unknown1,
79};
80
118enum class CabinetMode : u8 { 81enum class CabinetMode : u8 {
119 StartNicknameAndOwnerSettings, 82 StartNicknameAndOwnerSettings,
120 StartGameDataEraser, 83 StartGameDataEraser,
@@ -122,27 +85,16 @@ enum class CabinetMode : u8 {
122 StartFormatter, 85 StartFormatter,
123}; 86};
124 87
125enum class MifareCmd : u8 {
126 AuthA = 0x60,
127 AuthB = 0x61,
128 Read = 0x30,
129 Write = 0xA0,
130 Transfer = 0xB0,
131 Decrement = 0xC0,
132 Increment = 0xC1,
133 Store = 0xC2
134};
135
136using UniqueSerialNumber = std::array<u8, 7>;
137using LockBytes = std::array<u8, 2>; 88using LockBytes = std::array<u8, 2>;
138using HashData = std::array<u8, 0x20>; 89using HashData = std::array<u8, 0x20>;
139using ApplicationArea = std::array<u8, 0xD8>; 90using ApplicationArea = std::array<u8, 0xD8>;
140using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; 91using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
141using DataBlock = std::array<u8, 0x10>; 92
142using KeyData = std::array<u8, 0x6>; 93// This is nn::nfp::TagInfo
94using TagInfo = NFC::TagInfo;
143 95
144struct TagUuid { 96struct TagUuid {
145 UniqueSerialNumber uid; 97 NFC::UniqueSerialNumber uid;
146 u8 nintendo_id; 98 u8 nintendo_id;
147 LockBytes lock_bytes; 99 LockBytes lock_bytes;
148}; 100};
@@ -243,7 +195,7 @@ struct AmiiboModelInfo {
243 AmiiboType amiibo_type; 195 AmiiboType amiibo_type;
244 u16_be model_number; 196 u16_be model_number;
245 AmiiboSeries series; 197 AmiiboSeries series;
246 PackedTagType tag_type; 198 NFC::PackedTagType tag_type;
247 INSERT_PADDING_BYTES(0x4); // Unknown 199 INSERT_PADDING_BYTES(0x4); // Unknown
248}; 200};
249static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size"); 201static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size");
@@ -298,7 +250,7 @@ struct NTAG215File {
298 u32_be register_info_crc; 250 u32_be register_info_crc;
299 ApplicationArea application_area; // Encrypted Game data 251 ApplicationArea application_area; // Encrypted Game data
300 HashData hmac_tag; // Hash 252 HashData hmac_tag; // Hash
301 UniqueSerialNumber uid; // Unique serial number 253 NFC::UniqueSerialNumber uid; // Unique serial number
302 u8 nintendo_id; // Tag UUID 254 u8 nintendo_id; // Tag UUID
303 AmiiboModelInfo model_info; 255 AmiiboModelInfo model_info;
304 HashData keygen_salt; // Salt 256 HashData keygen_salt; // Salt
@@ -326,17 +278,7 @@ static_assert(sizeof(EncryptedNTAG215File) == sizeof(NTAG215File),
326static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>, 278static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>,
327 "EncryptedNTAG215File must be trivially copyable."); 279 "EncryptedNTAG215File must be trivially copyable.");
328 280
329struct TagInfo { 281// This is nn::nfp::CommonInfo
330 UniqueSerialNumber uuid;
331 INSERT_PADDING_BYTES(0x3);
332 u8 uuid_length;
333 INSERT_PADDING_BYTES(0x15);
334 TagProtocol protocol;
335 TagType tag_type;
336 INSERT_PADDING_BYTES(0x30);
337};
338static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
339
340struct CommonInfo { 282struct CommonInfo {
341 WriteDate last_write_date; 283 WriteDate last_write_date;
342 u16 write_counter; 284 u16 write_counter;
@@ -347,6 +289,7 @@ struct CommonInfo {
347}; 289};
348static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); 290static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
349 291
292// This is nn::nfp::ModelInfo
350struct ModelInfo { 293struct ModelInfo {
351 u16 character_id; 294 u16 character_id;
352 u8 character_variant; 295 u8 character_variant;
@@ -357,6 +300,7 @@ struct ModelInfo {
357}; 300};
358static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); 301static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
359 302
303// This is nn::nfp::RegisterInfo
360struct RegisterInfo { 304struct RegisterInfo {
361 Service::Mii::CharInfo mii_char_info; 305 Service::Mii::CharInfo mii_char_info;
362 WriteDate creation_date; 306 WriteDate creation_date;
@@ -366,6 +310,7 @@ struct RegisterInfo {
366}; 310};
367static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); 311static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
368 312
313// This is nn::nfp::RegisterInfoPrivate
369struct RegisterInfoPrivate { 314struct RegisterInfoPrivate {
370 Service::Mii::MiiStoreData mii_store_data; 315 Service::Mii::MiiStoreData mii_store_data;
371 WriteDate creation_date; 316 WriteDate creation_date;
@@ -375,12 +320,13 @@ struct RegisterInfoPrivate {
375}; 320};
376static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size"); 321static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size");
377 322
323// This is nn::nfp::AdminInfo
378struct AdminInfo { 324struct AdminInfo {
379 u64 application_id; 325 u64 application_id;
380 u32 application_area_id; 326 u32 application_area_id;
381 u16 crc_change_counter; 327 u16 crc_change_counter;
382 u8 flags; 328 u8 flags;
383 PackedTagType tag_type; 329 NFC::PackedTagType tag_type;
384 AppAreaVersion app_area_version; 330 AppAreaVersion app_area_version;
385 INSERT_PADDING_BYTES(0x7); 331 INSERT_PADDING_BYTES(0x7);
386 INSERT_PADDING_BYTES(0x28); 332 INSERT_PADDING_BYTES(0x28);
@@ -411,7 +357,7 @@ struct NfpData {
411 u32 access_id; 357 u32 access_id;
412 u16 settings_crc_counter; 358 u16 settings_crc_counter;
413 u8 font_region; 359 u8 font_region;
414 PackedTagType tag_type; 360 NFC::PackedTagType tag_type;
415 AppAreaVersion console_type; 361 AppAreaVersion console_type;
416 u8 application_id_byte; 362 u8 application_id_byte;
417 INSERT_PADDING_BYTES(0x2E); 363 INSERT_PADDING_BYTES(0x2E);
@@ -420,37 +366,4 @@ struct NfpData {
420static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size"); 366static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size");
421#pragma pack() 367#pragma pack()
422 368
423struct SectorKey {
424 MifareCmd command;
425 u8 unknown; // Usually 1
426 INSERT_PADDING_BYTES(0x6);
427 KeyData sector_key;
428 INSERT_PADDING_BYTES(0x2);
429};
430static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
431
432struct MifareReadBlockParameter {
433 u8 sector_number;
434 INSERT_PADDING_BYTES(0x7);
435 SectorKey sector_key;
436};
437static_assert(sizeof(MifareReadBlockParameter) == 0x18,
438 "MifareReadBlockParameter is an invalid size");
439
440struct MifareReadBlockData {
441 DataBlock data;
442 u8 sector_number;
443 INSERT_PADDING_BYTES(0x7);
444};
445static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
446
447struct MifareWriteBlockParameter {
448 DataBlock data;
449 u8 sector_number;
450 INSERT_PADDING_BYTES(0x7);
451 SectorKey sector_key;
452};
453static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
454 "MifareWriteBlockParameter is an invalid size");
455
456} // namespace Service::NFP 369} // namespace Service::NFP
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 0c042f412..91d42853e 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -218,7 +218,7 @@ public:
218 218
219private: 219private:
220 void Submit(HLERequestContext& ctx) { 220 void Submit(HLERequestContext& ctx) {
221 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 221 LOG_DEBUG(Service_NIFM, "(STUBBED) called");
222 222
223 if (state == RequestState::NotSubmitted) { 223 if (state == RequestState::NotSubmitted) {
224 UpdateState(RequestState::OnHold); 224 UpdateState(RequestState::OnHold);
@@ -229,7 +229,7 @@ private:
229 } 229 }
230 230
231 void GetRequestState(HLERequestContext& ctx) { 231 void GetRequestState(HLERequestContext& ctx) {
232 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 232 LOG_DEBUG(Service_NIFM, "(STUBBED) called");
233 233
234 IPC::ResponseBuilder rb{ctx, 3}; 234 IPC::ResponseBuilder rb{ctx, 3};
235 rb.Push(ResultSuccess); 235 rb.Push(ResultSuccess);
@@ -237,7 +237,7 @@ private:
237 } 237 }
238 238
239 void GetResult(HLERequestContext& ctx) { 239 void GetResult(HLERequestContext& ctx) {
240 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 240 LOG_DEBUG(Service_NIFM, "(STUBBED) called");
241 241
242 const auto result = [this] { 242 const auto result = [this] {
243 const auto has_connection = Network::GetHostIPv4Address().has_value(); 243 const auto has_connection = Network::GetHostIPv4Address().has_value();
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index cd0a13094..b16f9933f 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -793,6 +793,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
793 std::scoped_lock lock{core->mutex}; 793 std::scoped_lock lock{core->mutex};
794 794
795 slots[slot] = {}; 795 slots[slot] = {};
796 slots[slot].fence = Fence::NoFence();
796 slots[slot].graphic_buffer = buffer; 797 slots[slot].graphic_buffer = buffer;
797 slots[slot].frame_number = 0; 798 slots[slot].frame_number = 0;
798 799
@@ -854,7 +855,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
854 status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage); 855 status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage);
855 856
856 parcel_out.Write(slot); 857 parcel_out.Write(slot);
857 parcel_out.WriteObject(&fence); 858 parcel_out.WriteFlattenedObject(&fence);
858 break; 859 break;
859 } 860 }
860 case TransactionId::RequestBuffer: { 861 case TransactionId::RequestBuffer: {
@@ -864,7 +865,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
864 865
865 status = RequestBuffer(slot, &buf); 866 status = RequestBuffer(slot, &buf);
866 867
867 parcel_out.WriteObject(buf); 868 parcel_out.WriteFlattenedObject(buf);
868 break; 869 break;
869 } 870 }
870 case TransactionId::QueueBuffer: { 871 case TransactionId::QueueBuffer: {
diff --git a/src/core/hle/service/nvnflinger/parcel.h b/src/core/hle/service/nvnflinger/parcel.h
index d1b6201e0..fb56d75d7 100644
--- a/src/core/hle/service/nvnflinger/parcel.h
+++ b/src/core/hle/service/nvnflinger/parcel.h
@@ -117,61 +117,67 @@ private:
117 117
118class OutputParcel final { 118class OutputParcel final {
119public: 119public:
120 static constexpr std::size_t DefaultBufferSize = 0x40; 120 OutputParcel() = default;
121
122 OutputParcel() : buffer(DefaultBufferSize) {}
123
124 template <typename T>
125 explicit OutputParcel(const T& out_data) : buffer(DefaultBufferSize) {
126 Write(out_data);
127 }
128 121
129 template <typename T> 122 template <typename T>
130 void Write(const T& val) { 123 void Write(const T& val) {
131 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable."); 124 this->WriteImpl(val, m_data_buffer);
132
133 if (buffer.size() < write_index + sizeof(T)) {
134 buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
135 }
136
137 std::memcpy(buffer.data() + write_index, &val, sizeof(T));
138 write_index += sizeof(T);
139 write_index = Common::AlignUp(write_index, 4);
140 } 125 }
141 126
142 template <typename T> 127 template <typename T>
143 void WriteObject(const T* ptr) { 128 void WriteFlattenedObject(const T* ptr) {
144 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
145
146 if (!ptr) { 129 if (!ptr) {
147 Write<u32>(0); 130 this->Write<u32>(0);
148 return; 131 return;
149 } 132 }
150 133
151 Write<u32>(1); 134 this->Write<u32>(1);
152 Write<s64>(sizeof(T)); 135 this->Write<s64>(sizeof(T));
153 Write(*ptr); 136 this->Write(*ptr);
154 } 137 }
155 138
156 template <typename T> 139 template <typename T>
157 void WriteObject(const std::shared_ptr<T> ptr) { 140 void WriteFlattenedObject(const std::shared_ptr<T> ptr) {
158 WriteObject(ptr.get()); 141 this->WriteFlattenedObject(ptr.get());
142 }
143
144 template <typename T>
145 void WriteInterface(const T& val) {
146 this->WriteImpl(val, m_data_buffer);
147 this->WriteImpl(0U, m_object_buffer);
159 } 148 }
160 149
161 std::vector<u8> Serialize() const { 150 std::vector<u8> Serialize() const {
151 std::vector<u8> output_buffer(sizeof(ParcelHeader) + m_data_buffer.size() +
152 m_object_buffer.size());
153
162 ParcelHeader header{}; 154 ParcelHeader header{};
163 header.data_size = static_cast<u32>(write_index - sizeof(ParcelHeader)); 155 header.data_size = static_cast<u32>(m_data_buffer.size());
164 header.data_offset = sizeof(ParcelHeader); 156 header.data_offset = sizeof(ParcelHeader);
165 header.objects_size = 4; 157 header.objects_size = static_cast<u32>(m_object_buffer.size());
166 header.objects_offset = static_cast<u32>(sizeof(ParcelHeader) + header.data_size); 158 header.objects_offset = header.data_offset + header.data_size;
167 std::memcpy(buffer.data(), &header, sizeof(ParcelHeader)); 159
160 std::memcpy(output_buffer.data(), &header, sizeof(header));
161 std::ranges::copy(m_data_buffer, output_buffer.data() + header.data_offset);
162 std::ranges::copy(m_object_buffer, output_buffer.data() + header.objects_offset);
163
164 return output_buffer;
165 }
166
167private:
168 template <typename T>
169 requires(std::is_trivially_copyable_v<T>)
170 void WriteImpl(const T& val, std::vector<u8>& buffer) {
171 const size_t aligned_size = Common::AlignUp(sizeof(T), 4);
172 const size_t old_size = buffer.size();
173 buffer.resize(old_size + aligned_size);
168 174
169 return buffer; 175 std::memcpy(buffer.data() + old_size, &val, sizeof(T));
170 } 176 }
171 177
172private: 178private:
173 mutable std::vector<u8> buffer; 179 std::vector<u8> m_data_buffer;
174 std::size_t write_index = sizeof(ParcelHeader); 180 std::vector<u8> m_object_buffer;
175}; 181};
176 182
177} // namespace Service::android 183} // namespace Service::android
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 0f79a1b7e..45b2c43b7 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -142,7 +142,8 @@ template <typename Self>
142class ServiceFramework : public ServiceFrameworkBase { 142class ServiceFramework : public ServiceFrameworkBase {
143protected: 143protected:
144 /// Contains information about a request type which is handled by the service. 144 /// Contains information about a request type which is handled by the service.
145 struct FunctionInfo : FunctionInfoBase { 145 template <typename T>
146 struct FunctionInfoTyped : FunctionInfoBase {
146 // TODO(yuriks): This function could be constexpr, but clang is the only compiler that 147 // TODO(yuriks): This function could be constexpr, but clang is the only compiler that
147 // doesn't emit an ICE or a wrong diagnostic because of the static_cast. 148 // doesn't emit an ICE or a wrong diagnostic because of the static_cast.
148 149
@@ -155,12 +156,13 @@ protected:
155 * the request 156 * the request
156 * @param name_ human-friendly name for the request. Used mostly for logging purposes. 157 * @param name_ human-friendly name for the request. Used mostly for logging purposes.
157 */ 158 */
158 FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_) 159 FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
159 : FunctionInfoBase{ 160 : FunctionInfoBase{
160 expected_header_, 161 expected_header_,
161 // Type-erase member function pointer by casting it down to the base class. 162 // Type-erase member function pointer by casting it down to the base class.
162 static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {} 163 static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
163 }; 164 };
165 using FunctionInfo = FunctionInfoTyped<Self>;
164 166
165 /** 167 /**
166 * Initializes the handler with no functions installed. 168 * Initializes the handler with no functions installed.
@@ -175,8 +177,8 @@ protected:
175 : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {} 177 : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
176 178
177 /// Registers handlers in the service. 179 /// Registers handlers in the service.
178 template <std::size_t N> 180 template <typename T = Self, std::size_t N>
179 void RegisterHandlers(const FunctionInfo (&functions)[N]) { 181 void RegisterHandlers(const FunctionInfoTyped<T> (&functions)[N]) {
180 RegisterHandlers(functions, N); 182 RegisterHandlers(functions, N);
181 } 183 }
182 184
@@ -184,13 +186,14 @@ protected:
184 * Registers handlers in the service. Usually prefer using the other RegisterHandlers 186 * Registers handlers in the service. Usually prefer using the other RegisterHandlers
185 * overload in order to avoid needing to specify the array size. 187 * overload in order to avoid needing to specify the array size.
186 */ 188 */
187 void RegisterHandlers(const FunctionInfo* functions, std::size_t n) { 189 template <typename T = Self>
190 void RegisterHandlers(const FunctionInfoTyped<T>* functions, std::size_t n) {
188 RegisterHandlersBase(functions, n); 191 RegisterHandlersBase(functions, n);
189 } 192 }
190 193
191 /// Registers handlers in the service. 194 /// Registers handlers in the service.
192 template <std::size_t N> 195 template <typename T = Self, std::size_t N>
193 void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) { 196 void RegisterHandlersTipc(const FunctionInfoTyped<T> (&functions)[N]) {
194 RegisterHandlersTipc(functions, N); 197 RegisterHandlersTipc(functions, N);
195 } 198 }
196 199
@@ -198,7 +201,8 @@ protected:
198 * Registers handlers in the service. Usually prefer using the other RegisterHandlers 201 * Registers handlers in the service. Usually prefer using the other RegisterHandlers
199 * overload in order to avoid needing to specify the array size. 202 * overload in order to avoid needing to specify the array size.
200 */ 203 */
201 void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) { 204 template <typename T = Self>
205 void RegisterHandlersTipc(const FunctionInfoTyped<T>* functions, std::size_t n) {
202 RegisterHandlersBaseTipc(functions, n); 206 RegisterHandlersBaseTipc(functions, n);
203 } 207 }
204 208
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h
index ed1eb5b2d..e6293ffb9 100644
--- a/src/core/hle/service/time/clock_types.h
+++ b/src/core/hle/service/time/clock_types.h
@@ -59,6 +59,18 @@ static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorre
59static_assert(std::is_trivially_copyable_v<SystemClockContext>, 59static_assert(std::is_trivially_copyable_v<SystemClockContext>,
60 "SystemClockContext must be trivially copyable"); 60 "SystemClockContext must be trivially copyable");
61 61
62struct ContinuousAdjustmentTimePoint {
63 s64 measurement_offset;
64 s64 diff_scale;
65 u32 shift_amount;
66 s64 lower;
67 s64 upper;
68 Common::UUID clock_source_id;
69};
70static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38);
71static_assert(std::is_trivially_copyable_v<ContinuousAdjustmentTimePoint>,
72 "ContinuousAdjustmentTimePoint must be trivially copyable");
73
62/// https://switchbrew.org/wiki/Glue_services#TimeSpanType 74/// https://switchbrew.org/wiki/Glue_services#TimeSpanType
63struct TimeSpanType { 75struct TimeSpanType {
64 s64 nanoseconds{}; 76 s64 nanoseconds{};
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index ff53a7d6f..ce1c85bcc 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -30,6 +30,25 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
30} 30}
31 31
32void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { 32void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
33 // lower and upper are related to the measurement point for the steady time point,
34 // and compare equal on boot
35 const s64 time_point_ns = context.steady_time_point.time_point * 1'000'000'000LL;
36
37 // This adjusts for some sort of time skew
38 // Both 0 on boot
39 const s64 diff_scale = 0;
40 const u32 shift_amount = 0;
41
42 const Clock::ContinuousAdjustmentTimePoint adjustment{
43 .measurement_offset = system.CoreTiming().GetGlobalTimeNs().count(),
44 .diff_scale = diff_scale,
45 .shift_amount = shift_amount,
46 .lower = time_point_ns,
47 .upper = time_point_ns,
48 .clock_source_id = context.steady_time_point.clock_source_id,
49 };
50
51 StoreToLockFreeAtomicType(&GetFormat()->continuous_adjustment_timepoint, adjustment);
33 StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context); 52 StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context);
34} 53}
35 54
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index 044a4d24e..c89be9765 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -65,14 +65,15 @@ public:
65 LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context; 65 LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context;
66 LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context; 66 LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context;
67 LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled; 67 LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled;
68 u32 format_version; 68 LockFreeAtomicType<Clock::ContinuousAdjustmentTimePoint> continuous_adjustment_timepoint;
69 }; 69 };
70 static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0); 70 static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0);
71 static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38); 71 static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38);
72 static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80); 72 static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80);
73 static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) == 73 static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) ==
74 0xc8); 74 0xc8);
75 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); 75 static_assert(offsetof(Format, continuous_adjustment_timepoint) == 0xd0);
76 static_assert(sizeof(Format) == 0x148, "Format is an invalid size");
76 77
77 void SetupStandardSteadyClock(const Common::UUID& clock_source_id, 78 void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
78 Clock::TimeSpanType current_time_point); 79 Clock::TimeSpanType current_time_point);
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 68eab5133..1b193f00c 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -64,8 +64,8 @@ public:
64private: 64private:
65 const u32 magic = 2; 65 const u32 magic = 2;
66 const u32 process_id = 1; 66 const u32 process_id = 1;
67 const u32 id; 67 const u64 id;
68 INSERT_PADDING_WORDS(3); 68 INSERT_PADDING_WORDS(2);
69 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'}; 69 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
70 INSERT_PADDING_WORDS(2); 70 INSERT_PADDING_WORDS(2);
71}; 71};
@@ -608,7 +608,9 @@ private:
608 return; 608 return;
609 } 609 }
610 610
611 const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}}; 611 android::OutputParcel parcel;
612 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
613
612 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); 614 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
613 615
614 IPC::ResponseBuilder rb{ctx, 4}; 616 IPC::ResponseBuilder rb{ctx, 4};
@@ -654,7 +656,9 @@ private:
654 return; 656 return;
655 } 657 }
656 658
657 const auto parcel = android::OutputParcel{NativeWindow{*buffer_queue_id}}; 659 android::OutputParcel parcel;
660 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
661
658 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize()); 662 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
659 663
660 IPC::ResponseBuilder rb{ctx, 6}; 664 IPC::ResponseBuilder rb{ctx, 6};
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index bf97b0ebc..75ac10a9c 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -356,7 +356,7 @@ NetworkInstance::~NetworkInstance() {
356std::optional<IPv4Address> GetHostIPv4Address() { 356std::optional<IPv4Address> GetHostIPv4Address() {
357 const auto network_interface = Network::GetSelectedNetworkInterface(); 357 const auto network_interface = Network::GetSelectedNetworkInterface();
358 if (!network_interface.has_value()) { 358 if (!network_interface.has_value()) {
359 LOG_ERROR(Network, "GetSelectedNetworkInterface returned no interface"); 359 LOG_DEBUG(Network, "GetSelectedNetworkInterface returned no interface");
360 return {}; 360 return {};
361 } 361 }
362 362
diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp
index 7b8e510a2..4c909a6d3 100644
--- a/src/core/internal_network/network_interface.cpp
+++ b/src/core/internal_network/network_interface.cpp
@@ -200,7 +200,7 @@ std::optional<NetworkInterface> GetSelectedNetworkInterface() {
200 }); 200 });
201 201
202 if (res == network_interfaces.end()) { 202 if (res == network_interfaces.end()) {
203 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); 203 LOG_DEBUG(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
204 return std::nullopt; 204 return std::nullopt;
205 } 205 }
206 206
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index a9667463f..514ba0d66 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -13,10 +13,12 @@
13#include "common/swap.h" 13#include "common/swap.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/device_memory.h" 15#include "core/device_memory.h"
16#include "core/hardware_properties.h"
16#include "core/hle/kernel/k_page_table.h" 17#include "core/hle/kernel/k_page_table.h"
17#include "core/hle/kernel/k_process.h" 18#include "core/hle/kernel/k_process.h"
18#include "core/memory.h" 19#include "core/memory.h"
19#include "video_core/gpu.h" 20#include "video_core/gpu.h"
21#include "video_core/rasterizer_download_area.h"
20 22
21namespace Core::Memory { 23namespace Core::Memory {
22 24
@@ -243,7 +245,7 @@ struct Memory::Impl {
243 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount, 245 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
244 const u8* const host_ptr) { 246 const u8* const host_ptr) {
245 if constexpr (!UNSAFE) { 247 if constexpr (!UNSAFE) {
246 system.GPU().FlushRegion(GetInteger(current_vaddr), copy_amount); 248 HandleRasterizerDownload(GetInteger(current_vaddr), copy_amount);
247 } 249 }
248 std::memcpy(dest_buffer, host_ptr, copy_amount); 250 std::memcpy(dest_buffer, host_ptr, copy_amount);
249 }, 251 },
@@ -334,7 +336,7 @@ struct Memory::Impl {
334 }, 336 },
335 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount, 337 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
336 u8* const host_ptr) { 338 u8* const host_ptr) {
337 system.GPU().FlushRegion(GetInteger(current_vaddr), copy_amount); 339 HandleRasterizerDownload(GetInteger(current_vaddr), copy_amount);
338 WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount); 340 WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount);
339 }, 341 },
340 [&](const std::size_t copy_amount) { 342 [&](const std::size_t copy_amount) {
@@ -373,7 +375,7 @@ struct Memory::Impl {
373 const std::size_t block_size) { 375 const std::size_t block_size) {
374 // dc ivac: Invalidate to point of coherency 376 // dc ivac: Invalidate to point of coherency
375 // GPU flush -> CPU invalidate 377 // GPU flush -> CPU invalidate
376 system.GPU().FlushRegion(GetInteger(current_vaddr), block_size); 378 HandleRasterizerDownload(GetInteger(current_vaddr), block_size);
377 }; 379 };
378 return PerformCacheOperation(process, dest_addr, size, on_rasterizer); 380 return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
379 } 381 }
@@ -462,7 +464,8 @@ struct Memory::Impl {
462 } 464 }
463 465
464 if (Settings::IsFastmemEnabled()) { 466 if (Settings::IsFastmemEnabled()) {
465 const bool is_read_enable = !Settings::IsGPULevelExtreme() || !cached; 467 const bool is_read_enable =
468 !Settings::values.use_reactive_flushing.GetValue() || !cached;
466 system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached); 469 system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
467 } 470 }
468 471
@@ -651,7 +654,7 @@ struct Memory::Impl {
651 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, 654 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8,
652 GetInteger(vaddr)); 655 GetInteger(vaddr));
653 }, 656 },
654 [&]() { system.GPU().FlushRegion(GetInteger(vaddr), sizeof(T)); }); 657 [&]() { HandleRasterizerDownload(GetInteger(vaddr), sizeof(T)); });
655 if (ptr) { 658 if (ptr) {
656 std::memcpy(&result, ptr, sizeof(T)); 659 std::memcpy(&result, ptr, sizeof(T));
657 } 660 }
@@ -712,7 +715,19 @@ struct Memory::Impl {
712 return true; 715 return true;
713 } 716 }
714 717
718 void HandleRasterizerDownload(VAddr address, size_t size) {
719 const size_t core = system.GetCurrentHostThreadID();
720 auto& current_area = rasterizer_areas[core];
721 const VAddr end_address = address + size;
722 if (current_area.start_address <= address && end_address <= current_area.end_address)
723 [[likely]] {
724 return;
725 }
726 current_area = system.GPU().OnCPURead(address, size);
727 }
728
715 Common::PageTable* current_page_table = nullptr; 729 Common::PageTable* current_page_table = nullptr;
730 std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> rasterizer_areas{};
716 Core::System& system; 731 Core::System& system;
717}; 732};
718 733
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 7f9e8dbb9..9a0439bb5 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -109,14 +109,37 @@ public:
109 } 109 }
110 110
111 bool RumblePlay(const Common::Input::VibrationStatus vibration) { 111 bool RumblePlay(const Common::Input::VibrationStatus vibration) {
112 constexpr u32 rumble_max_duration_ms = 1000; 112 constexpr u32 rumble_max_duration_ms = 2000;
113 constexpr f32 low_start_sensitivity_limit = 140.0;
114 constexpr f32 low_width_sensitivity_limit = 400.0;
115 constexpr f32 high_start_sensitivity_limit = 200.0;
116 constexpr f32 high_width_sensitivity_limit = 700.0;
117 // Try to provide some feeling of the frequency by reducing the amplitude depending on it.
118 f32 low_frequency_scale = 1.0;
119 if (vibration.low_frequency > low_start_sensitivity_limit) {
120 low_frequency_scale =
121 std::max(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) /
122 low_width_sensitivity_limit,
123 0.3f);
124 }
125 f32 low_amplitude = vibration.low_amplitude * low_frequency_scale;
126
127 f32 high_frequency_scale = 1.0;
128 if (vibration.high_frequency > high_start_sensitivity_limit) {
129 high_frequency_scale =
130 std::max(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) /
131 high_width_sensitivity_limit,
132 0.3f);
133 }
134 f32 high_amplitude = vibration.high_amplitude * high_frequency_scale;
135
113 if (sdl_controller) { 136 if (sdl_controller) {
114 return SDL_GameControllerRumble( 137 return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude),
115 sdl_controller.get(), static_cast<u16>(vibration.low_amplitude), 138 static_cast<u16>(high_amplitude),
116 static_cast<u16>(vibration.high_amplitude), rumble_max_duration_ms) != -1; 139 rumble_max_duration_ms) != -1;
117 } else if (sdl_joystick) { 140 } else if (sdl_joystick) {
118 return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(vibration.low_amplitude), 141 return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude),
119 static_cast<u16>(vibration.high_amplitude), 142 static_cast<u16>(high_amplitude),
120 rumble_max_duration_ms) != -1; 143 rumble_max_duration_ms) != -1;
121 } 144 }
122 145
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 2b42a4555..077d72cd0 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -236,13 +236,13 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
236 return DriverResult::Success; 236 return DriverResult::Success;
237} 237}
238 238
239DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, 239DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc,
240 std::span<const u8> buffer, 240 std::span<const u8> buffer,
241 MCUCommandResponse& output) { 241 MCUCommandResponse& output) {
242 SubCommandPacket packet{ 242 SubCommandPacket packet{
243 .output_report = OutputReport::MCU_DATA, 243 .output_report = OutputReport::MCU_DATA,
244 .packet_counter = GetCounter(), 244 .packet_counter = GetCounter(),
245 .sub_command = sc, 245 .mcu_sub_command = sc,
246 .command_data = {}, 246 .command_data = {},
247 }; 247 };
248 248
@@ -269,8 +269,7 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
269 std::size_t tries{}; 269 std::size_t tries{};
270 270
271 do { 271 do {
272 const std::vector<u8> mcu_data{static_cast<u8>(MCUMode::Standby)}; 272 const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
273 const auto result = SendMCUData(report_mode, SubCommand::STATE, mcu_data, output);
274 273
275 if (result != DriverResult::Success) { 274 if (result != DriverResult::Success) {
276 return result; 275 return result;
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 62cae739a..411ec018a 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -156,7 +156,7 @@ public:
156 * @param buffer data to be send 156 * @param buffer data to be send
157 * @returns output buffer containing the response 157 * @returns output buffer containing the response
158 */ 158 */
159 DriverResult SendMCUData(ReportMode report_mode, SubCommand sc, std::span<const u8> buffer, 159 DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer,
160 MCUCommandResponse& output); 160 MCUCommandResponse& output);
161 161
162 /** 162 /**
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index dcac0e422..1c8d294b0 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -394,6 +394,7 @@ enum class DriverResult {
394 InvalidHandle, 394 InvalidHandle,
395 NotSupported, 395 NotSupported,
396 Disabled, 396 Disabled,
397 Delayed,
397 Unknown, 398 Unknown,
398}; 399};
399 400
@@ -575,7 +576,6 @@ struct NFCPollingCommandData {
575static_assert(sizeof(NFCPollingCommandData) == 0x05, "NFCPollingCommandData is an invalid size"); 576static_assert(sizeof(NFCPollingCommandData) == 0x05, "NFCPollingCommandData is an invalid size");
576 577
577struct NFCRequestState { 578struct NFCRequestState {
578 MCUSubCommand sub_command;
579 NFCReadCommand command_argument; 579 NFCReadCommand command_argument;
580 u8 packet_id; 580 u8 packet_id;
581 INSERT_PADDING_BYTES(0x1); 581 INSERT_PADDING_BYTES(0x1);
@@ -587,6 +587,7 @@ struct NFCRequestState {
587 NFCPollingCommandData nfc_polling; 587 NFCPollingCommandData nfc_polling;
588 }; 588 };
589 u8 crc; 589 u8 crc;
590 INSERT_PADDING_BYTES(0x1);
590}; 591};
591static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size"); 592static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size");
592 593
@@ -659,7 +660,10 @@ struct SubCommandPacket {
659 OutputReport output_report; 660 OutputReport output_report;
660 u8 packet_counter; 661 u8 packet_counter;
661 INSERT_PADDING_BYTES(0x8); // This contains vibration data 662 INSERT_PADDING_BYTES(0x8); // This contains vibration data
662 SubCommand sub_command; 663 union {
664 SubCommand sub_command;
665 MCUSubCommand mcu_sub_command;
666 };
663 std::array<u8, 0x26> command_data; 667 std::array<u8, 0x26> command_data;
664}; 668};
665static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size"); 669static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size");
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp
index eeba82986..14818ae33 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -72,6 +72,11 @@ DriverResult NfcProtocol::StartNFCPollingMode() {
72} 72}
73 73
74DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { 74DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) {
75 if (update_counter++ < AMIIBO_UPDATE_DELAY) {
76 return DriverResult::Delayed;
77 }
78 update_counter = 0;
79
75 LOG_DEBUG(Input, "Start NFC pooling Mode"); 80 LOG_DEBUG(Input, "Start NFC pooling Mode");
76 ScopedSetBlocking sb(this); 81 ScopedSetBlocking sb(this);
77 DriverResult result{DriverResult::Success}; 82 DriverResult result{DriverResult::Success};
@@ -87,7 +92,7 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) {
87 result = WaitUntilNfcIsReady(); 92 result = WaitUntilNfcIsReady();
88 } 93 }
89 if (result == DriverResult::Success) { 94 if (result == DriverResult::Success) {
90 result = StartPolling(tag_data); 95 result = StartPolling(tag_data, 7);
91 } 96 }
92 if (result == DriverResult::Success) { 97 if (result == DriverResult::Success) {
93 result = GetAmiiboData(data); 98 result = GetAmiiboData(data);
@@ -129,9 +134,8 @@ DriverResult NfcProtocol::WaitUntilNfcIsReady() {
129 return DriverResult::Success; 134 return DriverResult::Success;
130} 135}
131 136
132DriverResult NfcProtocol::StartPolling(TagFoundData& data) { 137DriverResult NfcProtocol::StartPolling(TagFoundData& data, std::size_t timeout_limit) {
133 LOG_DEBUG(Input, "Start Polling for tag"); 138 LOG_DEBUG(Input, "Start Polling for tag");
134 constexpr std::size_t timeout_limit = 7;
135 MCUCommandResponse output{}; 139 MCUCommandResponse output{};
136 std::size_t tries = 0; 140 std::size_t tries = 0;
137 141
@@ -278,7 +282,6 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
278 282
279DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) { 283DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) {
280 NFCRequestState request{ 284 NFCRequestState request{
281 .sub_command = MCUSubCommand::ReadDeviceMode,
282 .command_argument = NFCReadCommand::StartPolling, 285 .command_argument = NFCReadCommand::StartPolling,
283 .packet_id = 0x0, 286 .packet_id = 0x0,
284 .packet_flag = MCUPacketFlag::LastCommandPacket, 287 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -296,13 +299,13 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) {
296 299
297 std::array<u8, sizeof(NFCRequestState)> request_data{}; 300 std::array<u8, sizeof(NFCRequestState)> request_data{};
298 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 301 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
299 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 302 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
300 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 303 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
304 output);
301} 305}
302 306
303DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { 307DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
304 NFCRequestState request{ 308 NFCRequestState request{
305 .sub_command = MCUSubCommand::ReadDeviceMode,
306 .command_argument = NFCReadCommand::StopPolling, 309 .command_argument = NFCReadCommand::StopPolling,
307 .packet_id = 0x0, 310 .packet_id = 0x0,
308 .packet_flag = MCUPacketFlag::LastCommandPacket, 311 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -313,13 +316,13 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
313 316
314 std::array<u8, sizeof(NFCRequestState)> request_data{}; 317 std::array<u8, sizeof(NFCRequestState)> request_data{};
315 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 318 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
316 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 319 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
317 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 320 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
321 output);
318} 322}
319 323
320DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) { 324DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) {
321 NFCRequestState request{ 325 NFCRequestState request{
322 .sub_command = MCUSubCommand::ReadDeviceMode,
323 .command_argument = NFCReadCommand::StartWaitingRecieve, 326 .command_argument = NFCReadCommand::StartWaitingRecieve,
324 .packet_id = 0x0, 327 .packet_id = 0x0,
325 .packet_flag = MCUPacketFlag::LastCommandPacket, 328 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -330,13 +333,13 @@ DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& out
330 333
331 std::vector<u8> request_data(sizeof(NFCRequestState)); 334 std::vector<u8> request_data(sizeof(NFCRequestState));
332 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 335 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
333 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 336 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
334 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 337 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
338 output);
335} 339}
336 340
337DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { 341DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {
338 NFCRequestState request{ 342 NFCRequestState request{
339 .sub_command = MCUSubCommand::ReadDeviceMode,
340 .command_argument = NFCReadCommand::Ntag, 343 .command_argument = NFCReadCommand::Ntag,
341 .packet_id = 0x0, 344 .packet_id = 0x0,
342 .packet_flag = MCUPacketFlag::LastCommandPacket, 345 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -355,8 +358,9 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
355 358
356 std::array<u8, sizeof(NFCRequestState)> request_data{}; 359 std::array<u8, sizeof(NFCRequestState)> request_data{};
357 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 360 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
358 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 361 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
359 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 362 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
363 output);
360} 364}
361 365
362NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(NFCPages pages) const { 366NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(NFCPages pages) const {
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h
index 11e263e07..4cb992d1d 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.h
+++ b/src/input_common/helpers/joycon_protocol/nfc.h
@@ -32,6 +32,9 @@ public:
32 bool IsEnabled() const; 32 bool IsEnabled() const;
33 33
34private: 34private:
35 // Number of times the function will be delayed until it outputs valid data
36 static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15;
37
35 struct TagFoundData { 38 struct TagFoundData {
36 u8 type; 39 u8 type;
37 std::vector<u8> uuid; 40 std::vector<u8> uuid;
@@ -39,7 +42,7 @@ private:
39 42
40 DriverResult WaitUntilNfcIsReady(); 43 DriverResult WaitUntilNfcIsReady();
41 44
42 DriverResult StartPolling(TagFoundData& data); 45 DriverResult StartPolling(TagFoundData& data, std::size_t timeout_limit = 1);
43 46
44 DriverResult ReadTag(const TagFoundData& data); 47 DriverResult ReadTag(const TagFoundData& data);
45 48
@@ -56,6 +59,7 @@ private:
56 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; 59 NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const;
57 60
58 bool is_enabled{}; 61 bool is_enabled{};
62 std::size_t update_counter{};
59}; 63};
60 64
61} // namespace InputCommon::Joycon 65} // namespace InputCommon::Joycon
diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp
index 49f5e7f54..91aa96aa7 100644
--- a/src/input_common/input_engine.cpp
+++ b/src/input_common/input_engine.cpp
@@ -58,8 +58,6 @@ 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;
63 { 61 {
64 std::scoped_lock lock{mutex}; 62 std::scoped_lock lock{mutex};
65 ControllerData& controller = controller_list.at(identifier); 63 ControllerData& controller = controller_list.at(identifier);
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 5c2c4a463..380a01542 100644
--- a/src/input_common/input_poller.cpp
+++ b/src/input_common/input_poller.cpp
@@ -667,7 +667,7 @@ public:
667 .raw_value = input_engine->GetAxis(identifier, axis_z), 667 .raw_value = input_engine->GetAxis(identifier, axis_z),
668 .properties = properties_z, 668 .properties = properties_z,
669 }; 669 };
670 status.delta_timestamp = 5000; 670 status.delta_timestamp = 1000;
671 status.force_update = true; 671 status.force_update = true;
672 return status; 672 return status;
673 } 673 }
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 fee510f7b..07c2b7b8a 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
@@ -339,9 +339,7 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
339 if (ctx.profile.support_vertex_instance_id) { 339 if (ctx.profile.support_vertex_instance_id) {
340 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id)); 340 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_id));
341 } else { 341 } else {
342 const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; 342 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index));
343 const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
344 return ctx.OpBitcast(ctx.F32[1], ctx.OpISub(ctx.U32[1], index, base));
345 } 343 }
346 case IR::Attribute::BaseInstance: 344 case IR::Attribute::BaseInstance:
347 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance)); 345 return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.base_instance));
@@ -386,9 +384,7 @@ Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) {
386 if (ctx.profile.support_vertex_instance_id) { 384 if (ctx.profile.support_vertex_instance_id) {
387 return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); 385 return ctx.OpLoad(ctx.U32[1], ctx.vertex_id);
388 } else { 386 } else {
389 const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; 387 return ctx.OpLoad(ctx.U32[1], ctx.vertex_index);
390 const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)};
391 return ctx.OpISub(ctx.U32[1], index, base);
392 } 388 }
393 case IR::Attribute::BaseInstance: 389 case IR::Attribute::BaseInstance:
394 return ctx.OpLoad(ctx.U32[1], ctx.base_instance); 390 return ctx.OpLoad(ctx.U32[1], ctx.base_instance);
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
index 639da1e9c..eeb49444f 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp
@@ -102,12 +102,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
102 } 102 }
103 IR::F32 value{v.ir.CompositeExtract(sample, element)}; 103 IR::F32 value{v.ir.CompositeExtract(sample, element)};
104 if (element < 2) { 104 if (element < 2) {
105 IR::U32 casted_value; 105 IR::U32 casted_value = v.ir.ConvertFToU(32, value);
106 if (element == 0) {
107 casted_value = v.ir.ConvertFToU(32, value);
108 } else {
109 casted_value = v.ir.ConvertFToS(16, value);
110 }
111 v.X(dest_reg, v.ir.ShiftLeftLogical(casted_value, v.ir.Imm32(8))); 106 v.X(dest_reg, v.ir.ShiftLeftLogical(casted_value, v.ir.Imm32(8)));
112 } else { 107 } else {
113 v.F(dest_reg, value); 108 v.F(dest_reg, value);
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp
index 3981907a2..618793668 100644
--- a/src/tests/video_core/memory_tracker.cpp
+++ b/src/tests/video_core/memory_tracker.cpp
@@ -535,12 +535,12 @@ TEST_CASE("MemoryTracker: Cached write downloads") {
535 memory_track->MarkRegionAsGpuModified(c + PAGE, PAGE); 535 memory_track->MarkRegionAsGpuModified(c + PAGE, PAGE);
536 int num = 0; 536 int num = 0;
537 memory_track->ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; }); 537 memory_track->ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; });
538 REQUIRE(num == 1); 538 REQUIRE(num == 0);
539 num = 0; 539 num = 0;
540 memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); 540 memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
541 REQUIRE(num == 0); 541 REQUIRE(num == 0);
542 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE)); 542 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE));
543 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); 543 REQUIRE(memory_track->IsRegionGpuModified(c + PAGE, PAGE));
544 memory_track->FlushCachedWrites(); 544 memory_track->FlushCachedWrites();
545 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); 545 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); 546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE));
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h
index 9cbd95c4b..0bb3bf8ae 100644
--- a/src/video_core/buffer_cache/buffer_base.h
+++ b/src/video_core/buffer_cache/buffer_base.h
@@ -18,6 +18,7 @@ namespace VideoCommon {
18enum class BufferFlagBits { 18enum class BufferFlagBits {
19 Picked = 1 << 0, 19 Picked = 1 << 0,
20 CachedWrites = 1 << 1, 20 CachedWrites = 1 << 1,
21 PreemtiveDownload = 1 << 2,
21}; 22};
22DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits) 23DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
23 24
@@ -54,6 +55,10 @@ public:
54 flags |= BufferFlagBits::Picked; 55 flags |= BufferFlagBits::Picked;
55 } 56 }
56 57
58 void MarkPreemtiveDownload() noexcept {
59 flags |= BufferFlagBits::PreemtiveDownload;
60 }
61
57 /// Unmark buffer as picked 62 /// Unmark buffer as picked
58 void Unpick() noexcept { 63 void Unpick() noexcept {
59 flags &= ~BufferFlagBits::Picked; 64 flags &= ~BufferFlagBits::Picked;
@@ -84,6 +89,10 @@ public:
84 return True(flags & BufferFlagBits::CachedWrites); 89 return True(flags & BufferFlagBits::CachedWrites);
85 } 90 }
86 91
92 bool IsPreemtiveDownload() const noexcept {
93 return True(flags & BufferFlagBits::PreemtiveDownload);
94 }
95
87 /// Returns the base CPU address of the buffer 96 /// Returns the base CPU address of the buffer
88 [[nodiscard]] VAddr CpuAddr() const noexcept { 97 [[nodiscard]] VAddr CpuAddr() const noexcept {
89 return cpu_addr; 98 return cpu_addr;
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index e534e1e9c..98756e4da 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -23,8 +23,6 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
23 common_ranges.clear(); 23 common_ranges.clear();
24 inline_buffer_id = NULL_BUFFER_ID; 24 inline_buffer_id = NULL_BUFFER_ID;
25 25
26 active_async_buffers = !Settings::IsGPULevelHigh();
27
28 if (!runtime.CanReportMemoryUsage()) { 26 if (!runtime.CanReportMemoryUsage()) {
29 minimum_memory = DEFAULT_EXPECTED_MEMORY; 27 minimum_memory = DEFAULT_EXPECTED_MEMORY;
30 critical_memory = DEFAULT_CRITICAL_MEMORY; 28 critical_memory = DEFAULT_CRITICAL_MEMORY;
@@ -75,8 +73,6 @@ void BufferCache<P>::TickFrame() {
75 uniform_cache_hits[0] = 0; 73 uniform_cache_hits[0] = 0;
76 uniform_cache_shots[0] = 0; 74 uniform_cache_shots[0] = 0;
77 75
78 active_async_buffers = !Settings::IsGPULevelHigh();
79
80 const bool skip_preferred = hits * 256 < shots * 251; 76 const bool skip_preferred = hits * 256 < shots * 251;
81 uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0; 77 uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0;
82 78
@@ -100,51 +96,50 @@ void BufferCache<P>::TickFrame() {
100 96
101template <class P> 97template <class P>
102void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) { 98void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) {
103 memory_tracker.MarkRegionAsCpuModified(cpu_addr, size);
104 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) { 99 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) {
105 const IntervalType subtract_interval{cpu_addr, cpu_addr + size}; 100 const IntervalType subtract_interval{cpu_addr, cpu_addr + size};
106 ClearDownload(subtract_interval); 101 ClearDownload(subtract_interval);
107 common_ranges.subtract(subtract_interval); 102 common_ranges.subtract(subtract_interval);
108 } 103 }
104 memory_tracker.MarkRegionAsCpuModified(cpu_addr, size);
109} 105}
110 106
111template <class P> 107template <class P>
112void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) { 108void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) {
113 memory_tracker.CachedCpuWrite(cpu_addr, size); 109 memory_tracker.CachedCpuWrite(cpu_addr, size);
114 const IntervalType add_interval{Common::AlignDown(cpu_addr, YUZU_PAGESIZE), 110}
115 Common::AlignUp(cpu_addr + size, YUZU_PAGESIZE)}; 111
116 cached_ranges.add(add_interval); 112template <class P>
113std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(VAddr cpu_addr,
114 u64 size) {
115 std::optional<VideoCore::RasterizerDownloadArea> area{};
116 area.emplace();
117 VAddr cpu_addr_start_aligned = Common::AlignDown(cpu_addr, Core::Memory::YUZU_PAGESIZE);
118 VAddr cpu_addr_end_aligned = Common::AlignUp(cpu_addr + size, Core::Memory::YUZU_PAGESIZE);
119 area->start_address = cpu_addr_start_aligned;
120 area->end_address = cpu_addr_end_aligned;
121 if (memory_tracker.IsRegionPreflushable(cpu_addr, size)) {
122 area->preemtive = true;
123 return area;
124 };
125 area->preemtive =
126 !IsRegionGpuModified(cpu_addr_start_aligned, cpu_addr_end_aligned - cpu_addr_start_aligned);
127 memory_tracker.MarkRegionAsPreflushable(cpu_addr_start_aligned,
128 cpu_addr_end_aligned - cpu_addr_start_aligned);
129 return area;
117} 130}
118 131
119template <class P> 132template <class P>
120void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) { 133void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
121 WaitOnAsyncFlushes(cpu_addr, size);
122 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) { 134 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) {
123 DownloadBufferMemory(buffer, cpu_addr, size); 135 DownloadBufferMemory(buffer, cpu_addr, size);
124 }); 136 });
125} 137}
126 138
127template <class P> 139template <class P>
128void BufferCache<P>::WaitOnAsyncFlushes(VAddr cpu_addr, u64 size) {
129 bool must_wait = false;
130 ForEachInOverlapCounter(async_downloads, cpu_addr, size,
131 [&](VAddr, VAddr, int) { must_wait = true; });
132 bool must_release = false;
133 ForEachInRangeSet(pending_ranges, cpu_addr, size, [&](VAddr, VAddr) { must_release = true; });
134 if (must_release) {
135 std::function<void()> tmp([]() {});
136 rasterizer.SignalFence(std::move(tmp));
137 }
138 if (must_wait || must_release) {
139 rasterizer.ReleaseFences();
140 }
141}
142
143template <class P>
144void BufferCache<P>::ClearDownload(IntervalType subtract_interval) { 140void BufferCache<P>::ClearDownload(IntervalType subtract_interval) {
145 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1024); 141 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1024);
146 uncommitted_ranges.subtract(subtract_interval); 142 uncommitted_ranges.subtract(subtract_interval);
147 pending_ranges.subtract(subtract_interval);
148 for (auto& interval_set : committed_ranges) { 143 for (auto& interval_set : committed_ranges) {
149 interval_set.subtract(subtract_interval); 144 interval_set.subtract(subtract_interval);
150 } 145 }
@@ -164,7 +159,6 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
164 } 159 }
165 160
166 const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount}; 161 const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount};
167 WaitOnAsyncFlushes(*cpu_src_address, static_cast<u32>(amount));
168 ClearDownload(subtract_interval); 162 ClearDownload(subtract_interval);
169 163
170 BufferId buffer_a; 164 BufferId buffer_a;
@@ -192,7 +186,6 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
192 const IntervalType add_interval{new_base_address, new_base_address + size}; 186 const IntervalType add_interval{new_base_address, new_base_address + size};
193 tmp_intervals.push_back(add_interval); 187 tmp_intervals.push_back(add_interval);
194 uncommitted_ranges.add(add_interval); 188 uncommitted_ranges.add(add_interval);
195 pending_ranges.add(add_interval);
196 }; 189 };
197 ForEachInRangeSet(common_ranges, *cpu_src_address, amount, mirror); 190 ForEachInRangeSet(common_ranges, *cpu_src_address, amount, mirror);
198 // This subtraction in this order is important for overlapping copies. 191 // This subtraction in this order is important for overlapping copies.
@@ -205,7 +198,7 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
205 if (has_new_downloads) { 198 if (has_new_downloads) {
206 memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); 199 memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount);
207 } 200 }
208 std::vector<u8> tmp_buffer(amount); 201 tmp_buffer.resize(amount);
209 cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount); 202 cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount);
210 cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount); 203 cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount);
211 return true; 204 return true;
@@ -441,9 +434,7 @@ void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_add
441 434
442template <class P> 435template <class P>
443void BufferCache<P>::FlushCachedWrites() { 436void BufferCache<P>::FlushCachedWrites() {
444 cached_write_buffer_ids.clear();
445 memory_tracker.FlushCachedWrites(); 437 memory_tracker.FlushCachedWrites();
446 cached_ranges.clear();
447} 438}
448 439
449template <class P> 440template <class P>
@@ -474,15 +465,13 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
474 465
475 if (committed_ranges.empty()) { 466 if (committed_ranges.empty()) {
476 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) { 467 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
477 if (active_async_buffers) { 468
478 async_buffers.emplace_back(std::optional<Async_Buffer>{}); 469 async_buffers.emplace_back(std::optional<Async_Buffer>{});
479 }
480 } 470 }
481 return; 471 return;
482 } 472 }
483 MICROPROFILE_SCOPE(GPU_DownloadMemory); 473 MICROPROFILE_SCOPE(GPU_DownloadMemory);
484 474
485 pending_ranges.clear();
486 auto it = committed_ranges.begin(); 475 auto it = committed_ranges.begin();
487 while (it != committed_ranges.end()) { 476 while (it != committed_ranges.end()) {
488 auto& current_intervals = *it; 477 auto& current_intervals = *it;
@@ -537,64 +526,65 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
537 committed_ranges.clear(); 526 committed_ranges.clear();
538 if (downloads.empty()) { 527 if (downloads.empty()) {
539 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) { 528 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
540 if (active_async_buffers) { 529
541 async_buffers.emplace_back(std::optional<Async_Buffer>{}); 530 async_buffers.emplace_back(std::optional<Async_Buffer>{});
542 }
543 } 531 }
544 return; 532 return;
545 } 533 }
546 if (active_async_buffers) { 534 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
547 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) { 535 auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes, true);
548 auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes, true); 536 boost::container::small_vector<BufferCopy, 4> normalized_copies;
549 boost::container::small_vector<BufferCopy, 4> normalized_copies; 537 IntervalSet new_async_range{};
550 IntervalSet new_async_range{}; 538 runtime.PreCopyBarrier();
551 runtime.PreCopyBarrier(); 539 for (auto& [copy, buffer_id] : downloads) {
552 for (auto& [copy, buffer_id] : downloads) { 540 copy.dst_offset += download_staging.offset;
553 copy.dst_offset += download_staging.offset; 541 const std::array copies{copy};
554 const std::array copies{copy}; 542 BufferCopy second_copy{copy};
555 BufferCopy second_copy{copy}; 543 Buffer& buffer = slot_buffers[buffer_id];
556 Buffer& buffer = slot_buffers[buffer_id]; 544 second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
557 second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset; 545 VAddr orig_cpu_addr = static_cast<VAddr>(second_copy.src_offset);
558 VAddr orig_cpu_addr = static_cast<VAddr>(second_copy.src_offset); 546 const IntervalType base_interval{orig_cpu_addr, orig_cpu_addr + copy.size};
559 const IntervalType base_interval{orig_cpu_addr, orig_cpu_addr + copy.size}; 547 async_downloads += std::make_pair(base_interval, 1);
560 async_downloads += std::make_pair(base_interval, 1); 548 runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
561 runtime.CopyBuffer(download_staging.buffer, buffer, copies, false); 549 normalized_copies.push_back(second_copy);
562 normalized_copies.push_back(second_copy);
563 }
564 runtime.PostCopyBarrier();
565 pending_downloads.emplace_back(std::move(normalized_copies));
566 async_buffers.emplace_back(download_staging);
567 } else {
568 committed_ranges.clear();
569 uncommitted_ranges.clear();
570 } 550 }
551 runtime.PostCopyBarrier();
552 pending_downloads.emplace_back(std::move(normalized_copies));
553 async_buffers.emplace_back(download_staging);
571 } else { 554 } else {
572 if constexpr (USE_MEMORY_MAPS) { 555 if (!Settings::IsGPULevelHigh()) {
573 auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes); 556 committed_ranges.clear();
574 runtime.PreCopyBarrier(); 557 uncommitted_ranges.clear();
575 for (auto& [copy, buffer_id] : downloads) {
576 // Have in mind the staging buffer offset for the copy
577 copy.dst_offset += download_staging.offset;
578 const std::array copies{copy};
579 runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies, false);
580 }
581 runtime.PostCopyBarrier();
582 runtime.Finish();
583 for (const auto& [copy, buffer_id] : downloads) {
584 const Buffer& buffer = slot_buffers[buffer_id];
585 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
586 // Undo the modified offset
587 const u64 dst_offset = copy.dst_offset - download_staging.offset;
588 const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset;
589 cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size);
590 }
591 } else { 558 } else {
592 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy); 559 if constexpr (USE_MEMORY_MAPS) {
593 for (const auto& [copy, buffer_id] : downloads) { 560 auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
594 Buffer& buffer = slot_buffers[buffer_id]; 561 runtime.PreCopyBarrier();
595 buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size)); 562 for (auto& [copy, buffer_id] : downloads) {
596 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; 563 // Have in mind the staging buffer offset for the copy
597 cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size); 564 copy.dst_offset += download_staging.offset;
565 const std::array copies{copy};
566 runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies,
567 false);
568 }
569 runtime.PostCopyBarrier();
570 runtime.Finish();
571 for (const auto& [copy, buffer_id] : downloads) {
572 const Buffer& buffer = slot_buffers[buffer_id];
573 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
574 // Undo the modified offset
575 const u64 dst_offset = copy.dst_offset - download_staging.offset;
576 const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset;
577 cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size);
578 }
579 } else {
580 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
581 for (const auto& [copy, buffer_id] : downloads) {
582 Buffer& buffer = slot_buffers[buffer_id];
583 buffer.ImmediateDownload(copy.src_offset,
584 immediate_buffer.subspan(0, copy.size));
585 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
586 cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size);
587 }
598 } 588 }
599 } 589 }
600 } 590 }
@@ -1213,16 +1203,14 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
1213 1203
1214template <class P> 1204template <class P>
1215void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) { 1205void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) {
1216 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
1217
1218 if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) { 1206 if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) {
1219 SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size); 1207 SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size);
1220 } 1208 }
1209 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
1221 1210
1222 const IntervalType base_interval{cpu_addr, cpu_addr + size}; 1211 const IntervalType base_interval{cpu_addr, cpu_addr + size};
1223 common_ranges.add(base_interval); 1212 common_ranges.add(base_interval);
1224 uncommitted_ranges.add(base_interval); 1213 uncommitted_ranges.add(base_interval);
1225 pending_ranges.add(base_interval);
1226} 1214}
1227 1215
1228template <class P> 1216template <class P>
@@ -1629,7 +1617,6 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
1629 replace(transform_feedback_buffers); 1617 replace(transform_feedback_buffers);
1630 replace(compute_uniform_buffers); 1618 replace(compute_uniform_buffers);
1631 replace(compute_storage_buffers); 1619 replace(compute_storage_buffers);
1632 std::erase(cached_write_buffer_ids, buffer_id);
1633 1620
1634 // Mark the whole buffer as CPU written to stop tracking CPU writes 1621 // Mark the whole buffer as CPU written to stop tracking CPU writes
1635 if (!do_not_mark) { 1622 if (!do_not_mark) {
@@ -1668,14 +1655,15 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
1668 const bool is_nvn_cbuf = cbuf_index == 0; 1655 const bool is_nvn_cbuf = cbuf_index == 0;
1669 // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size. 1656 // The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size.
1670 if (is_nvn_cbuf) { 1657 if (is_nvn_cbuf) {
1671 return gpu_memory->Read<u32>(ssbo_addr + 8); 1658 const u32 ssbo_size = gpu_memory->Read<u32>(ssbo_addr + 8);
1659 if (ssbo_size != 0) {
1660 return ssbo_size;
1661 }
1672 } 1662 }
1673 // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined 1663 // Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined
1674 // cbufs, which do not store the sizes adjacent to the addresses, so use the fully 1664 // cbufs, which do not store the sizes adjacent to the addresses, so use the fully
1675 // mapped buffer size for now. 1665 // mapped buffer size for now.
1676 const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr)); 1666 const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr));
1677 LOG_INFO(HW_GPU, "Binding storage buffer for cbuf index {}, MemoryLayoutSize 0x{:X}",
1678 cbuf_index, memory_layout_size);
1679 return memory_layout_size; 1667 return memory_layout_size;
1680 }(); 1668 }();
1681 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); 1669 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr);
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index 656baa550..ac00d4d9d 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -188,6 +188,8 @@ public:
188 188
189 void DownloadMemory(VAddr cpu_addr, u64 size); 189 void DownloadMemory(VAddr cpu_addr, u64 size);
190 190
191 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(VAddr cpu_addr, u64 size);
192
191 bool InlineMemory(VAddr dest_address, size_t copy_size, std::span<const u8> inlined_buffer); 193 bool InlineMemory(VAddr dest_address, size_t copy_size, std::span<const u8> inlined_buffer);
192 194
193 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size); 195 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size);
@@ -379,8 +381,6 @@ private:
379 381
380 void RunGarbageCollector(); 382 void RunGarbageCollector();
381 383
382 void WaitOnAsyncFlushes(VAddr cpu_addr, u64 size);
383
384 void BindHostIndexBuffer(); 384 void BindHostIndexBuffer();
385 385
386 void BindHostVertexBuffers(); 386 void BindHostVertexBuffers();
@@ -541,13 +541,10 @@ private:
541 std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>, Empty> 541 std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>, Empty>
542 uniform_buffer_binding_sizes{}; 542 uniform_buffer_binding_sizes{};
543 543
544 std::vector<BufferId> cached_write_buffer_ids;
545
546 MemoryTracker memory_tracker; 544 MemoryTracker memory_tracker;
547 IntervalSet uncommitted_ranges; 545 IntervalSet uncommitted_ranges;
548 IntervalSet common_ranges; 546 IntervalSet common_ranges;
549 IntervalSet cached_ranges; 547 IntervalSet cached_ranges;
550 IntervalSet pending_ranges;
551 std::deque<IntervalSet> committed_ranges; 548 std::deque<IntervalSet> committed_ranges;
552 549
553 // Async Buffers 550 // Async Buffers
@@ -572,9 +569,8 @@ private:
572 u64 critical_memory = 0; 569 u64 critical_memory = 0;
573 BufferId inline_buffer_id; 570 BufferId inline_buffer_id;
574 571
575 bool active_async_buffers = false;
576
577 std::array<BufferId, ((1ULL << 39) >> CACHING_PAGEBITS)> page_table; 572 std::array<BufferId, ((1ULL << 39) >> CACHING_PAGEBITS)> page_table;
573 std::vector<u8> tmp_buffer;
578}; 574};
579 575
580} // namespace VideoCommon 576} // namespace VideoCommon
diff --git a/src/video_core/buffer_cache/memory_tracker_base.h b/src/video_core/buffer_cache/memory_tracker_base.h
index dc4ebfcaa..6036b21c9 100644
--- a/src/video_core/buffer_cache/memory_tracker_base.h
+++ b/src/video_core/buffer_cache/memory_tracker_base.h
@@ -66,6 +66,14 @@ public:
66 }); 66 });
67 } 67 }
68 68
69 /// Returns true if a region has been marked as Preflushable
70 [[nodiscard]] bool IsRegionPreflushable(VAddr query_cpu_addr, u64 query_size) noexcept {
71 return IteratePages<false>(
72 query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
73 return manager->template IsRegionModified<Type::Preflushable>(offset, size);
74 });
75 }
76
69 /// Mark region as CPU modified, notifying the rasterizer about this change 77 /// Mark region as CPU modified, notifying the rasterizer about this change
70 void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) { 78 void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
71 IteratePages<true>(dirty_cpu_addr, query_size, 79 IteratePages<true>(dirty_cpu_addr, query_size,
@@ -93,6 +101,15 @@ public:
93 }); 101 });
94 } 102 }
95 103
104 /// Mark region as modified from the host GPU
105 void MarkRegionAsPreflushable(VAddr dirty_cpu_addr, u64 query_size) noexcept {
106 IteratePages<true>(dirty_cpu_addr, query_size,
107 [](Manager* manager, u64 offset, size_t size) {
108 manager->template ChangeRegionState<Type::Preflushable, true>(
109 manager->GetCpuAddr() + offset, size);
110 });
111 }
112
96 /// Unmark region as modified from the host GPU 113 /// Unmark region as modified from the host GPU
97 void UnmarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept { 114 void UnmarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept {
98 IteratePages<true>(dirty_cpu_addr, query_size, 115 IteratePages<true>(dirty_cpu_addr, query_size,
@@ -102,6 +119,15 @@ public:
102 }); 119 });
103 } 120 }
104 121
122 /// Unmark region as modified from the host GPU
123 void UnmarkRegionAsPreflushable(VAddr dirty_cpu_addr, u64 query_size) noexcept {
124 IteratePages<true>(dirty_cpu_addr, query_size,
125 [](Manager* manager, u64 offset, size_t size) {
126 manager->template ChangeRegionState<Type::Preflushable, false>(
127 manager->GetCpuAddr() + offset, size);
128 });
129 }
130
105 /// Mark region as modified from the CPU 131 /// Mark region as modified from the CPU
106 /// but don't mark it as modified until FlusHCachedWrites is called. 132 /// but don't mark it as modified until FlusHCachedWrites is called.
107 void CachedCpuWrite(VAddr dirty_cpu_addr, u64 query_size) { 133 void CachedCpuWrite(VAddr dirty_cpu_addr, u64 query_size) {
diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h
index a42455045..a336bde41 100644
--- a/src/video_core/buffer_cache/word_manager.h
+++ b/src/video_core/buffer_cache/word_manager.h
@@ -26,6 +26,7 @@ enum class Type {
26 GPU, 26 GPU,
27 CachedCPU, 27 CachedCPU,
28 Untracked, 28 Untracked,
29 Preflushable,
29}; 30};
30 31
31/// Vector tracking modified pages tightly packed with small vector optimization 32/// Vector tracking modified pages tightly packed with small vector optimization
@@ -55,17 +56,20 @@ struct Words {
55 gpu.stack.fill(0); 56 gpu.stack.fill(0);
56 cached_cpu.stack.fill(0); 57 cached_cpu.stack.fill(0);
57 untracked.stack.fill(~u64{0}); 58 untracked.stack.fill(~u64{0});
59 preflushable.stack.fill(0);
58 } else { 60 } else {
59 // Share allocation between CPU and GPU pages and set their default values 61 // Share allocation between CPU and GPU pages and set their default values
60 u64* const alloc = new u64[num_words * 4]; 62 u64* const alloc = new u64[num_words * 5];
61 cpu.heap = alloc; 63 cpu.heap = alloc;
62 gpu.heap = alloc + num_words; 64 gpu.heap = alloc + num_words;
63 cached_cpu.heap = alloc + num_words * 2; 65 cached_cpu.heap = alloc + num_words * 2;
64 untracked.heap = alloc + num_words * 3; 66 untracked.heap = alloc + num_words * 3;
67 preflushable.heap = alloc + num_words * 4;
65 std::fill_n(cpu.heap, num_words, ~u64{0}); 68 std::fill_n(cpu.heap, num_words, ~u64{0});
66 std::fill_n(gpu.heap, num_words, 0); 69 std::fill_n(gpu.heap, num_words, 0);
67 std::fill_n(cached_cpu.heap, num_words, 0); 70 std::fill_n(cached_cpu.heap, num_words, 0);
68 std::fill_n(untracked.heap, num_words, ~u64{0}); 71 std::fill_n(untracked.heap, num_words, ~u64{0});
72 std::fill_n(preflushable.heap, num_words, 0);
69 } 73 }
70 // Clean up tailing bits 74 // Clean up tailing bits
71 const u64 last_word_size = size_bytes % BYTES_PER_WORD; 75 const u64 last_word_size = size_bytes % BYTES_PER_WORD;
@@ -88,13 +92,14 @@ struct Words {
88 gpu = rhs.gpu; 92 gpu = rhs.gpu;
89 cached_cpu = rhs.cached_cpu; 93 cached_cpu = rhs.cached_cpu;
90 untracked = rhs.untracked; 94 untracked = rhs.untracked;
95 preflushable = rhs.preflushable;
91 rhs.cpu.heap = nullptr; 96 rhs.cpu.heap = nullptr;
92 return *this; 97 return *this;
93 } 98 }
94 99
95 Words(Words&& rhs) noexcept 100 Words(Words&& rhs) noexcept
96 : size_bytes{rhs.size_bytes}, num_words{rhs.num_words}, cpu{rhs.cpu}, gpu{rhs.gpu}, 101 : size_bytes{rhs.size_bytes}, num_words{rhs.num_words}, cpu{rhs.cpu}, gpu{rhs.gpu},
97 cached_cpu{rhs.cached_cpu}, untracked{rhs.untracked} { 102 cached_cpu{rhs.cached_cpu}, untracked{rhs.untracked}, preflushable{rhs.preflushable} {
98 rhs.cpu.heap = nullptr; 103 rhs.cpu.heap = nullptr;
99 } 104 }
100 105
@@ -129,6 +134,8 @@ struct Words {
129 return std::span<u64>(cached_cpu.Pointer(IsShort()), num_words); 134 return std::span<u64>(cached_cpu.Pointer(IsShort()), num_words);
130 } else if constexpr (type == Type::Untracked) { 135 } else if constexpr (type == Type::Untracked) {
131 return std::span<u64>(untracked.Pointer(IsShort()), num_words); 136 return std::span<u64>(untracked.Pointer(IsShort()), num_words);
137 } else if constexpr (type == Type::Preflushable) {
138 return std::span<u64>(preflushable.Pointer(IsShort()), num_words);
132 } 139 }
133 } 140 }
134 141
@@ -142,6 +149,8 @@ struct Words {
142 return std::span<const u64>(cached_cpu.Pointer(IsShort()), num_words); 149 return std::span<const u64>(cached_cpu.Pointer(IsShort()), num_words);
143 } else if constexpr (type == Type::Untracked) { 150 } else if constexpr (type == Type::Untracked) {
144 return std::span<const u64>(untracked.Pointer(IsShort()), num_words); 151 return std::span<const u64>(untracked.Pointer(IsShort()), num_words);
152 } else if constexpr (type == Type::Preflushable) {
153 return std::span<const u64>(preflushable.Pointer(IsShort()), num_words);
145 } 154 }
146 } 155 }
147 156
@@ -151,6 +160,7 @@ struct Words {
151 WordsArray<stack_words> gpu; 160 WordsArray<stack_words> gpu;
152 WordsArray<stack_words> cached_cpu; 161 WordsArray<stack_words> cached_cpu;
153 WordsArray<stack_words> untracked; 162 WordsArray<stack_words> untracked;
163 WordsArray<stack_words> preflushable;
154}; 164};
155 165
156template <class RasterizerInterface, size_t stack_words = 1> 166template <class RasterizerInterface, size_t stack_words = 1>
@@ -292,6 +302,9 @@ public:
292 (pending_pointer - pending_offset) * BYTES_PER_PAGE); 302 (pending_pointer - pending_offset) * BYTES_PER_PAGE);
293 }; 303 };
294 IterateWords(offset, size, [&](size_t index, u64 mask) { 304 IterateWords(offset, size, [&](size_t index, u64 mask) {
305 if constexpr (type == Type::GPU) {
306 mask &= ~untracked_words[index];
307 }
295 const u64 word = state_words[index] & mask; 308 const u64 word = state_words[index] & mask;
296 if constexpr (clear) { 309 if constexpr (clear) {
297 if constexpr (type == Type::CPU || type == Type::CachedCPU) { 310 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
@@ -340,8 +353,13 @@ public:
340 static_assert(type != Type::Untracked); 353 static_assert(type != Type::Untracked);
341 354
342 const std::span<const u64> state_words = words.template Span<type>(); 355 const std::span<const u64> state_words = words.template Span<type>();
356 [[maybe_unused]] const std::span<const u64> untracked_words =
357 words.template Span<Type::Untracked>();
343 bool result = false; 358 bool result = false;
344 IterateWords(offset, size, [&](size_t index, u64 mask) { 359 IterateWords(offset, size, [&](size_t index, u64 mask) {
360 if constexpr (type == Type::GPU) {
361 mask &= ~untracked_words[index];
362 }
345 const u64 word = state_words[index] & mask; 363 const u64 word = state_words[index] & mask;
346 if (word != 0) { 364 if (word != 0) {
347 result = true; 365 result = true;
@@ -362,9 +380,14 @@ public:
362 [[nodiscard]] std::pair<u64, u64> ModifiedRegion(u64 offset, u64 size) const noexcept { 380 [[nodiscard]] std::pair<u64, u64> ModifiedRegion(u64 offset, u64 size) const noexcept {
363 static_assert(type != Type::Untracked); 381 static_assert(type != Type::Untracked);
364 const std::span<const u64> state_words = words.template Span<type>(); 382 const std::span<const u64> state_words = words.template Span<type>();
383 [[maybe_unused]] const std::span<const u64> untracked_words =
384 words.template Span<Type::Untracked>();
365 u64 begin = std::numeric_limits<u64>::max(); 385 u64 begin = std::numeric_limits<u64>::max();
366 u64 end = 0; 386 u64 end = 0;
367 IterateWords(offset, size, [&](size_t index, u64 mask) { 387 IterateWords(offset, size, [&](size_t index, u64 mask) {
388 if constexpr (type == Type::GPU) {
389 mask &= ~untracked_words[index];
390 }
368 const u64 word = state_words[index] & mask; 391 const u64 word = state_words[index] & mask;
369 if (word == 0) { 392 if (word == 0) {
370 return; 393 return;
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index e68850dc5..ebe5536de 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -223,7 +223,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
223 write_buffer.resize_destructive(dst_size); 223 write_buffer.resize_destructive(dst_size);
224 224
225 memory_manager.ReadBlock(src_operand.address, read_buffer.data(), src_size); 225 memory_manager.ReadBlock(src_operand.address, read_buffer.data(), src_size);
226 memory_manager.ReadBlockUnsafe(dst_operand.address, write_buffer.data(), dst_size); 226 memory_manager.ReadBlock(dst_operand.address, write_buffer.data(), dst_size);
227 227
228 UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, 228 UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset,
229 src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, 229 src_params.origin.y, x_elements, regs.line_count, block_height, block_depth,
@@ -288,11 +288,7 @@ void MaxwellDMA::CopyPitchToBlockLinear() {
288 write_buffer.resize_destructive(dst_size); 288 write_buffer.resize_destructive(dst_size);
289 289
290 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); 290 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
291 if (Settings::IsGPULevelExtreme()) { 291 memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
292 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
293 } else {
294 memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
295 }
296 292
297 // If the input is linear and the output is tiled, swizzle the input and copy it over. 293 // If the input is linear and the output is tiled, swizzle the input and copy it over.
298 SwizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, 294 SwizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset,
diff --git a/src/video_core/engines/sw_blitter/blitter.cpp b/src/video_core/engines/sw_blitter/blitter.cpp
index 3c9f38559..ff88cd03d 100644
--- a/src/video_core/engines/sw_blitter/blitter.cpp
+++ b/src/video_core/engines/sw_blitter/blitter.cpp
@@ -5,6 +5,7 @@
5#include <cmath> 5#include <cmath>
6#include <vector> 6#include <vector>
7 7
8#include "common/scratch_buffer.h"
8#include "video_core/engines/sw_blitter/blitter.h" 9#include "video_core/engines/sw_blitter/blitter.h"
9#include "video_core/engines/sw_blitter/converter.h" 10#include "video_core/engines/sw_blitter/converter.h"
10#include "video_core/memory_manager.h" 11#include "video_core/memory_manager.h"
@@ -112,11 +113,11 @@ void Bilinear(std::span<const f32> input, std::span<f32> output, size_t src_widt
112} // namespace 113} // namespace
113 114
114struct SoftwareBlitEngine::BlitEngineImpl { 115struct SoftwareBlitEngine::BlitEngineImpl {
115 std::vector<u8> tmp_buffer; 116 Common::ScratchBuffer<u8> tmp_buffer;
116 std::vector<u8> src_buffer; 117 Common::ScratchBuffer<u8> src_buffer;
117 std::vector<u8> dst_buffer; 118 Common::ScratchBuffer<u8> dst_buffer;
118 std::vector<f32> intermediate_src; 119 Common::ScratchBuffer<f32> intermediate_src;
119 std::vector<f32> intermediate_dst; 120 Common::ScratchBuffer<f32> intermediate_dst;
120 ConverterFactory converter_factory; 121 ConverterFactory converter_factory;
121}; 122};
122 123
@@ -158,14 +159,14 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
158 const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); 159 const auto src_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
159 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format)); 160 const auto dst_bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(dst.format));
160 const size_t src_size = get_surface_size(src, src_bytes_per_pixel); 161 const size_t src_size = get_surface_size(src, src_bytes_per_pixel);
161 impl->tmp_buffer.resize(src_size); 162 impl->tmp_buffer.resize_destructive(src_size);
162 memory_manager.ReadBlock(src.Address(), impl->tmp_buffer.data(), src_size); 163 memory_manager.ReadBlock(src.Address(), impl->tmp_buffer.data(), src_size);
163 164
164 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel; 165 const size_t src_copy_size = src_extent_x * src_extent_y * src_bytes_per_pixel;
165 166
166 const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel; 167 const size_t dst_copy_size = dst_extent_x * dst_extent_y * dst_bytes_per_pixel;
167 168
168 impl->src_buffer.resize(src_copy_size); 169 impl->src_buffer.resize_destructive(src_copy_size);
169 170
170 const bool no_passthrough = 171 const bool no_passthrough =
171 src.format != dst.format || src_extent_x != dst_extent_x || src_extent_y != dst_extent_y; 172 src.format != dst.format || src_extent_x != dst_extent_x || src_extent_y != dst_extent_y;
@@ -177,8 +178,10 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
177 178
178 const auto convertion_phase_ir = [&]() { 179 const auto convertion_phase_ir = [&]() {
179 auto* input_converter = impl->converter_factory.GetFormatConverter(src.format); 180 auto* input_converter = impl->converter_factory.GetFormatConverter(src.format);
180 impl->intermediate_src.resize((src_copy_size / src_bytes_per_pixel) * ir_components); 181 impl->intermediate_src.resize_destructive((src_copy_size / src_bytes_per_pixel) *
181 impl->intermediate_dst.resize((dst_copy_size / dst_bytes_per_pixel) * ir_components); 182 ir_components);
183 impl->intermediate_dst.resize_destructive((dst_copy_size / dst_bytes_per_pixel) *
184 ir_components);
182 input_converter->ConvertTo(impl->src_buffer, impl->intermediate_src); 185 input_converter->ConvertTo(impl->src_buffer, impl->intermediate_src);
183 186
184 if (config.filter != Fermi2D::Filter::Bilinear) { 187 if (config.filter != Fermi2D::Filter::Bilinear) {
@@ -195,7 +198,7 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
195 198
196 // Do actual Blit 199 // Do actual Blit
197 200
198 impl->dst_buffer.resize(dst_copy_size); 201 impl->dst_buffer.resize_destructive(dst_copy_size);
199 if (src.linear == Fermi2D::MemoryLayout::BlockLinear) { 202 if (src.linear == Fermi2D::MemoryLayout::BlockLinear) {
200 UnswizzleSubrect(impl->src_buffer, impl->tmp_buffer, src_bytes_per_pixel, src.width, 203 UnswizzleSubrect(impl->src_buffer, impl->tmp_buffer, src_bytes_per_pixel, src.width,
201 src.height, src.depth, config.src_x0, config.src_y0, src_extent_x, 204 src.height, src.depth, config.src_x0, config.src_y0, src_extent_x,
@@ -218,7 +221,7 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst,
218 } 221 }
219 222
220 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel); 223 const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel);
221 impl->tmp_buffer.resize(dst_size); 224 impl->tmp_buffer.resize_destructive(dst_size);
222 memory_manager.ReadBlock(dst.Address(), impl->tmp_buffer.data(), dst_size); 225 memory_manager.ReadBlock(dst.Address(), impl->tmp_buffer.data(), dst_size);
223 226
224 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) { 227 if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) {
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index 3b2f6aab6..35d699bbf 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -59,6 +59,11 @@ public:
59 buffer_cache.AccumulateFlushes(); 59 buffer_cache.AccumulateFlushes();
60 } 60 }
61 61
62 void SignalReference() {
63 std::function<void()> do_nothing([] {});
64 SignalFence(std::move(do_nothing));
65 }
66
62 void SyncOperation(std::function<void()>&& func) { 67 void SyncOperation(std::function<void()>&& func) {
63 uncommitted_operations.emplace_back(std::move(func)); 68 uncommitted_operations.emplace_back(std::move(func));
64 } 69 }
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 2e7f9c5ed..295a416a8 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -283,6 +283,21 @@ struct GPU::Impl {
283 gpu_thread.FlushRegion(addr, size); 283 gpu_thread.FlushRegion(addr, size);
284 } 284 }
285 285
286 VideoCore::RasterizerDownloadArea OnCPURead(VAddr addr, u64 size) {
287 auto raster_area = rasterizer->GetFlushArea(addr, size);
288 if (raster_area.preemtive) {
289 return raster_area;
290 }
291 raster_area.preemtive = true;
292 const u64 fence = RequestSyncOperation([this, &raster_area]() {
293 rasterizer->FlushRegion(raster_area.start_address,
294 raster_area.end_address - raster_area.start_address);
295 });
296 gpu_thread.TickGPU();
297 WaitForSyncOperation(fence);
298 return raster_area;
299 }
300
286 /// Notify rasterizer that any caches of the specified region should be invalidated 301 /// Notify rasterizer that any caches of the specified region should be invalidated
287 void InvalidateRegion(VAddr addr, u64 size) { 302 void InvalidateRegion(VAddr addr, u64 size) {
288 gpu_thread.InvalidateRegion(addr, size); 303 gpu_thread.InvalidateRegion(addr, size);
@@ -538,6 +553,10 @@ void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
538 impl->SwapBuffers(framebuffer); 553 impl->SwapBuffers(framebuffer);
539} 554}
540 555
556VideoCore::RasterizerDownloadArea GPU::OnCPURead(VAddr addr, u64 size) {
557 return impl->OnCPURead(addr, size);
558}
559
541void GPU::FlushRegion(VAddr addr, u64 size) { 560void GPU::FlushRegion(VAddr addr, u64 size) {
542 impl->FlushRegion(addr, size); 561 impl->FlushRegion(addr, size);
543} 562}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 8a871593a..e49c40cf2 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -10,6 +10,7 @@
10#include "core/hle/service/nvdrv/nvdata.h" 10#include "core/hle/service/nvdrv/nvdata.h"
11#include "video_core/cdma_pusher.h" 11#include "video_core/cdma_pusher.h"
12#include "video_core/framebuffer_config.h" 12#include "video_core/framebuffer_config.h"
13#include "video_core/rasterizer_download_area.h"
13 14
14namespace Core { 15namespace Core {
15class System; 16class System;
@@ -241,6 +242,9 @@ public:
241 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer); 242 void SwapBuffers(const Tegra::FramebufferConfig* framebuffer);
242 243
243 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory 244 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
245 [[nodiscard]] VideoCore::RasterizerDownloadArea OnCPURead(VAddr addr, u64 size);
246
247 /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
244 void FlushRegion(VAddr addr, u64 size); 248 void FlushRegion(VAddr addr, u64 size);
245 249
246 /// Notify rasterizer that any caches of the specified region should be invalidated 250 /// Notify rasterizer that any caches of the specified region should be invalidated
diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp
index e87bd65fa..6ce179167 100644
--- a/src/video_core/host1x/codecs/h264.cpp
+++ b/src/video_core/host1x/codecs/h264.cpp
@@ -111,7 +111,7 @@ const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegist
111 writer.WriteUe(0); 111 writer.WriteUe(0);
112 112
113 writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag != 0); 113 writer.WriteBit(context.h264_parameter_set.entropy_coding_mode_flag != 0);
114 writer.WriteBit(false); 114 writer.WriteBit(context.h264_parameter_set.pic_order_present_flag != 0);
115 writer.WriteUe(0); 115 writer.WriteUe(0);
116 writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active); 116 writer.WriteUe(context.h264_parameter_set.num_refidx_l0_default_active);
117 writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active); 117 writer.WriteUe(context.h264_parameter_set.num_refidx_l1_default_active);
@@ -129,7 +129,7 @@ const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegist
129 writer.WriteBit(context.h264_parameter_set.redundant_pic_cnt_present_flag != 0); 129 writer.WriteBit(context.h264_parameter_set.redundant_pic_cnt_present_flag != 0);
130 writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0); 130 writer.WriteBit(context.h264_parameter_set.transform_8x8_mode_flag != 0);
131 131
132 writer.WriteBit(true); 132 writer.WriteBit(true); // pic_scaling_matrix_present_flag
133 133
134 for (s32 index = 0; index < 6; index++) { 134 for (s32 index = 0; index < 6; index++) {
135 writer.WriteBit(true); 135 writer.WriteBit(true);
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index 941de95c1..1528cc1dd 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -255,7 +255,6 @@ private:
255 if (!in_range(query)) { 255 if (!in_range(query)) {
256 continue; 256 continue;
257 } 257 }
258 rasterizer.UpdatePagesCachedCount(query.GetCpuAddr(), query.SizeInBytes(), -1);
259 AsyncJobId async_job_id = query.GetAsyncJob(); 258 AsyncJobId async_job_id = query.GetAsyncJob();
260 auto flush_result = query.Flush(async); 259 auto flush_result = query.Flush(async);
261 if (async_job_id == NULL_ASYNC_JOB_ID) { 260 if (async_job_id == NULL_ASYNC_JOB_ID) {
@@ -273,7 +272,6 @@ private:
273 272
274 /// Registers the passed parameters as cached and returns a pointer to the stored cached query. 273 /// Registers the passed parameters as cached and returns a pointer to the stored cached query.
275 CachedQuery* Register(VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr, bool timestamp) { 274 CachedQuery* Register(VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr, bool timestamp) {
276 rasterizer.UpdatePagesCachedCount(cpu_addr, CachedQuery::SizeInBytes(timestamp), 1);
277 const u64 page = static_cast<u64>(cpu_addr) >> YUZU_PAGEBITS; 275 const u64 page = static_cast<u64>(cpu_addr) >> YUZU_PAGEBITS;
278 return &cached_queries[page].emplace_back(static_cast<QueryCache&>(*this), type, cpu_addr, 276 return &cached_queries[page].emplace_back(static_cast<QueryCache&>(*this), type, cpu_addr,
279 host_ptr); 277 host_ptr);
diff --git a/src/video_core/rasterizer_download_area.h b/src/video_core/rasterizer_download_area.h
new file mode 100644
index 000000000..2d7425c79
--- /dev/null
+++ b/src/video_core/rasterizer_download_area.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace VideoCore {
9
10struct RasterizerDownloadArea {
11 VAddr start_address;
12 VAddr end_address;
13 bool preemtive;
14};
15
16} // namespace VideoCore \ No newline at end of file
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 33e2610bc..7566a8c4e 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -12,6 +12,7 @@
12#include "video_core/cache_types.h" 12#include "video_core/cache_types.h"
13#include "video_core/engines/fermi_2d.h" 13#include "video_core/engines/fermi_2d.h"
14#include "video_core/gpu.h" 14#include "video_core/gpu.h"
15#include "video_core/rasterizer_download_area.h"
15 16
16namespace Tegra { 17namespace Tegra {
17class MemoryManager; 18class MemoryManager;
@@ -95,6 +96,8 @@ public:
95 virtual bool MustFlushRegion(VAddr addr, u64 size, 96 virtual bool MustFlushRegion(VAddr addr, u64 size,
96 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0; 97 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0;
97 98
99 virtual RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) = 0;
100
98 /// Notify rasterizer that any caches of the specified region should be invalidated 101 /// Notify rasterizer that any caches of the specified region should be invalidated
99 virtual void InvalidateRegion(VAddr addr, u64 size, 102 virtual void InvalidateRegion(VAddr addr, u64 size,
100 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0; 103 VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0;
diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp
index 2b5c7defa..bf2ce4c49 100644
--- a/src/video_core/renderer_null/null_rasterizer.cpp
+++ b/src/video_core/renderer_null/null_rasterizer.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 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 "common/alignment.h"
5#include "core/memory.h"
4#include "video_core/host1x/host1x.h" 6#include "video_core/host1x/host1x.h"
5#include "video_core/memory_manager.h" 7#include "video_core/memory_manager.h"
6#include "video_core/renderer_null/null_rasterizer.h" 8#include "video_core/renderer_null/null_rasterizer.h"
@@ -46,6 +48,14 @@ bool RasterizerNull::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheTyp
46} 48}
47void RasterizerNull::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {} 49void RasterizerNull::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {}
48void RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {} 50void RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {}
51VideoCore::RasterizerDownloadArea RasterizerNull::GetFlushArea(VAddr addr, u64 size) {
52 VideoCore::RasterizerDownloadArea new_area{
53 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE),
54 .end_address = Common::AlignUp(addr + size, Core::Memory::YUZU_PAGESIZE),
55 .preemtive = true,
56 };
57 return new_area;
58}
49void RasterizerNull::InvalidateGPUCache() {} 59void RasterizerNull::InvalidateGPUCache() {}
50void RasterizerNull::UnmapMemory(VAddr addr, u64 size) {} 60void RasterizerNull::UnmapMemory(VAddr addr, u64 size) {}
51void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {} 61void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {}
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h
index 0c59e6a1f..a8d35d2c1 100644
--- a/src/video_core/renderer_null/null_rasterizer.h
+++ b/src/video_core/renderer_null/null_rasterizer.h
@@ -54,6 +54,7 @@ public:
54 void InvalidateRegion(VAddr addr, u64 size, 54 void InvalidateRegion(VAddr addr, u64 size,
55 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 55 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
56 void OnCPUWrite(VAddr addr, u64 size) override; 56 void OnCPUWrite(VAddr addr, u64 size) override;
57 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override;
57 void InvalidateGPUCache() override; 58 void InvalidateGPUCache() override;
58 void UnmapMemory(VAddr addr, u64 size) override; 59 void UnmapMemory(VAddr addr, u64 size) override;
59 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; 60 void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override;
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 22ed16ebf..400c21981 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -108,7 +108,8 @@ bool IsASTCSupported() {
108 108
109[[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) { 109[[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) {
110 const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED"); 110 const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
111 return nsight || HasExtension(extensions, "GL_EXT_debug_tool"); 111 return nsight || HasExtension(extensions, "GL_EXT_debug_tool") ||
112 Settings::values.renderer_debug.GetValue();
112} 113}
113} // Anonymous namespace 114} // Anonymous namespace
114 115
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 0089b4b27..f5baa0f3c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -433,6 +433,29 @@ bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheT
433 return false; 433 return false;
434} 434}
435 435
436VideoCore::RasterizerDownloadArea RasterizerOpenGL::GetFlushArea(VAddr addr, u64 size) {
437 {
438 std::scoped_lock lock{texture_cache.mutex};
439 auto area = texture_cache.GetFlushArea(addr, size);
440 if (area) {
441 return *area;
442 }
443 }
444 {
445 std::scoped_lock lock{buffer_cache.mutex};
446 auto area = buffer_cache.GetFlushArea(addr, size);
447 if (area) {
448 return *area;
449 }
450 }
451 VideoCore::RasterizerDownloadArea new_area{
452 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE),
453 .end_address = Common::AlignUp(addr + size, Core::Memory::YUZU_PAGESIZE),
454 .preemtive = true,
455 };
456 return new_area;
457}
458
436void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 459void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) {
437 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 460 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
438 if (addr == 0 || size == 0) { 461 if (addr == 0 || size == 0) {
@@ -1281,7 +1304,7 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
1281 const Tegra::DMA::BufferOperand& buffer_operand, 1304 const Tegra::DMA::BufferOperand& buffer_operand,
1282 const Tegra::DMA::ImageOperand& image_operand) { 1305 const Tegra::DMA::ImageOperand& image_operand) {
1283 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; 1306 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
1284 const auto image_id = texture_cache.DmaImageId(image_operand); 1307 const auto image_id = texture_cache.DmaImageId(image_operand, IS_IMAGE_UPLOAD);
1285 if (image_id == VideoCommon::NULL_IMAGE_ID) { 1308 if (image_id == VideoCommon::NULL_IMAGE_ID) {
1286 return false; 1309 return false;
1287 } 1310 }
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index ad6978bd0..410d8ffc5 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -95,6 +95,7 @@ public:
95 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 95 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
96 bool MustFlushRegion(VAddr addr, u64 size, 96 bool MustFlushRegion(VAddr addr, u64 size,
97 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 97 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
98 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override;
98 void InvalidateRegion(VAddr addr, u64 size, 99 void InvalidateRegion(VAddr addr, u64 size,
99 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 100 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
100 void OnCPUWrite(VAddr addr, u64 size) override; 101 void OnCPUWrite(VAddr addr, u64 size) override;
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 47cccd0e5..31118886f 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -231,7 +231,7 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
231 231
232[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime, 232[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
233 const VideoCommon::ImageInfo& info) { 233 const VideoCommon::ImageInfo& info) {
234 if (IsPixelFormatASTC(info.format) && !runtime.HasNativeASTC()) { 234 if (IsPixelFormatASTC(info.format) && info.size.depth == 1 && !runtime.HasNativeASTC()) {
235 return Settings::values.accelerate_astc.GetValue() && 235 return Settings::values.accelerate_astc.GetValue() &&
236 !Settings::values.async_astc.GetValue(); 236 !Settings::values.async_astc.GetValue();
237 } 237 }
@@ -1126,7 +1126,8 @@ bool Image::ScaleDown(bool ignore) {
1126 1126
1127ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, 1127ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
1128 ImageId image_id_, Image& image, const SlotVector<Image>&) 1128 ImageId image_id_, Image& image, const SlotVector<Image>&)
1129 : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} { 1129 : VideoCommon::ImageViewBase{info, image.info, image_id_, image.gpu_addr},
1130 views{runtime.null_image_views} {
1130 const Device& device = runtime.device; 1131 const Device& device = runtime.device;
1131 if (True(image.flags & ImageFlagBits::Converted)) { 1132 if (True(image.flags & ImageFlagBits::Converted)) {
1132 internal_format = IsPixelFormatSRGB(info.format) ? GL_SRGB8_ALPHA8 : GL_RGBA8; 1133 internal_format = IsPixelFormatSRGB(info.format) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
@@ -1217,12 +1218,12 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1217 1218
1218ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, 1219ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
1219 const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) 1220 const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_)
1220 : VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_}, 1221 : VideoCommon::ImageViewBase{info, view_info, gpu_addr_},
1221 buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {} 1222 buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {}
1222 1223
1223ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, 1224ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
1224 const VideoCommon::ImageViewInfo& view_info) 1225 const VideoCommon::ImageViewInfo& view_info)
1225 : VideoCommon::ImageViewBase{info, view_info} {} 1226 : VideoCommon::ImageViewBase{info, view_info, 0} {}
1226 1227
1227ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params) 1228ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params)
1228 : VideoCommon::ImageViewBase{params}, views{runtime.null_image_views} {} 1229 : VideoCommon::ImageViewBase{params}, views{runtime.null_image_views} {}
@@ -1282,7 +1283,7 @@ GLuint ImageView::MakeView(Shader::TextureType view_type, GLenum view_format) {
1282 ApplySwizzle(view.handle, format, casted_swizzle); 1283 ApplySwizzle(view.handle, format, casted_swizzle);
1283 } 1284 }
1284 if (set_object_label) { 1285 if (set_object_label) {
1285 const std::string name = VideoCommon::Name(*this); 1286 const std::string name = VideoCommon::Name(*this, gpu_addr);
1286 glObjectLabel(GL_TEXTURE, view.handle, static_cast<GLsizei>(name.size()), name.data()); 1287 glObjectLabel(GL_TEXTURE, view.handle, static_cast<GLsizei>(name.size()), name.data());
1287 } 1288 }
1288 return view.handle; 1289 return view.handle;
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 0dd039ed2..1190999a8 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -314,7 +314,6 @@ private:
314 std::unique_ptr<StorageViews> storage_views; 314 std::unique_ptr<StorageViews> storage_views;
315 GLenum internal_format = GL_NONE; 315 GLenum internal_format = GL_NONE;
316 GLuint default_handle = 0; 316 GLuint default_handle = 0;
317 GPUVAddr gpu_addr = 0;
318 u32 buffer_size = 0; 317 u32 buffer_size = 0;
319 GLuint original_texture = 0; 318 GLuint original_texture = 0;
320 int num_samples = 0; 319 int num_samples = 0;
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h
index 28b893e25..983e1c2e1 100644
--- a/src/video_core/renderer_vulkan/pipeline_helper.h
+++ b/src/video_core/renderer_vulkan/pipeline_helper.h
@@ -176,7 +176,7 @@ public:
176}; 176};
177 177
178inline void PushImageDescriptors(TextureCache& texture_cache, 178inline void PushImageDescriptors(TextureCache& texture_cache,
179 UpdateDescriptorQueue& update_descriptor_queue, 179 GuestDescriptorQueue& guest_descriptor_queue,
180 const Shader::Info& info, RescalingPushConstant& rescaling, 180 const Shader::Info& info, RescalingPushConstant& rescaling,
181 const VkSampler*& samplers, 181 const VkSampler*& samplers,
182 const VideoCommon::ImageViewInOut*& views) { 182 const VideoCommon::ImageViewInOut*& views) {
@@ -190,7 +190,7 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
190 const VkSampler sampler{*(samplers++)}; 190 const VkSampler sampler{*(samplers++)};
191 ImageView& image_view{texture_cache.GetImageView(image_view_id)}; 191 ImageView& image_view{texture_cache.GetImageView(image_view_id)};
192 const VkImageView vk_image_view{image_view.Handle(desc.type)}; 192 const VkImageView vk_image_view{image_view.Handle(desc.type)};
193 update_descriptor_queue.AddSampledImage(vk_image_view, sampler); 193 guest_descriptor_queue.AddSampledImage(vk_image_view, sampler);
194 rescaling.PushTexture(texture_cache.IsRescaling(image_view)); 194 rescaling.PushTexture(texture_cache.IsRescaling(image_view));
195 } 195 }
196 } 196 }
@@ -201,7 +201,7 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
201 texture_cache.MarkModification(image_view.image_id); 201 texture_cache.MarkModification(image_view.image_id);
202 } 202 }
203 const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)}; 203 const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)};
204 update_descriptor_queue.AddImage(vk_image_view); 204 guest_descriptor_queue.AddImage(vk_image_view);
205 rescaling.PushImage(texture_cache.IsRescaling(image_view)); 205 rescaling.PushImage(texture_cache.IsRescaling(image_view));
206 } 206 }
207 } 207 }
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 510602e8e..9627eb129 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -298,12 +298,14 @@ private:
298 298
299BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_allocator_, 299BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_allocator_,
300 Scheduler& scheduler_, StagingBufferPool& staging_pool_, 300 Scheduler& scheduler_, StagingBufferPool& staging_pool_,
301 UpdateDescriptorQueue& update_descriptor_queue_, 301 GuestDescriptorQueue& guest_descriptor_queue_,
302 ComputePassDescriptorQueue& compute_pass_descriptor_queue,
302 DescriptorPool& descriptor_pool) 303 DescriptorPool& descriptor_pool)
303 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, 304 : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
304 staging_pool{staging_pool_}, update_descriptor_queue{update_descriptor_queue_}, 305 staging_pool{staging_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
305 uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), 306 uint8_pass(device, scheduler, descriptor_pool, staging_pool, compute_pass_descriptor_queue),
306 quad_index_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue) { 307 quad_index_pass(device, scheduler, descriptor_pool, staging_pool,
308 compute_pass_descriptor_queue) {
307 quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_, 309 quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_,
308 scheduler_, staging_pool_); 310 scheduler_, staging_pool_);
309 quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_, 311 quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_,
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 879f1ed94..5e9602905 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -63,7 +63,8 @@ class BufferCacheRuntime {
63public: 63public:
64 explicit BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_manager_, 64 explicit BufferCacheRuntime(const Device& device_, MemoryAllocator& memory_manager_,
65 Scheduler& scheduler_, StagingBufferPool& staging_pool_, 65 Scheduler& scheduler_, StagingBufferPool& staging_pool_,
66 UpdateDescriptorQueue& update_descriptor_queue_, 66 GuestDescriptorQueue& guest_descriptor_queue,
67 ComputePassDescriptorQueue& compute_pass_descriptor_queue,
67 DescriptorPool& descriptor_pool); 68 DescriptorPool& descriptor_pool);
68 69
69 void Finish(); 70 void Finish();
@@ -116,12 +117,12 @@ public:
116 117
117 void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, 118 void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size,
118 VideoCore::Surface::PixelFormat format) { 119 VideoCore::Surface::PixelFormat format) {
119 update_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format)); 120 guest_descriptor_queue.AddTexelBuffer(buffer.View(offset, size, format));
120 } 121 }
121 122
122private: 123private:
123 void BindBuffer(VkBuffer buffer, u32 offset, u32 size) { 124 void BindBuffer(VkBuffer buffer, u32 offset, u32 size) {
124 update_descriptor_queue.AddBuffer(buffer, offset, size); 125 guest_descriptor_queue.AddBuffer(buffer, offset, size);
125 } 126 }
126 127
127 void ReserveNullBuffer(); 128 void ReserveNullBuffer();
@@ -130,7 +131,7 @@ private:
130 MemoryAllocator& memory_allocator; 131 MemoryAllocator& memory_allocator;
131 Scheduler& scheduler; 132 Scheduler& scheduler;
132 StagingBufferPool& staging_pool; 133 StagingBufferPool& staging_pool;
133 UpdateDescriptorQueue& update_descriptor_queue; 134 GuestDescriptorQueue& guest_descriptor_queue;
134 135
135 std::shared_ptr<QuadArrayIndexBuffer> quad_array_index_buffer; 136 std::shared_ptr<QuadArrayIndexBuffer> quad_array_index_buffer;
136 std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; 137 std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 1a316b6eb..3bc8553e1 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -200,12 +200,12 @@ ComputePass::~ComputePass() = default;
200 200
201Uint8Pass::Uint8Pass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool, 201Uint8Pass::Uint8Pass(const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool,
202 StagingBufferPool& staging_buffer_pool_, 202 StagingBufferPool& staging_buffer_pool_,
203 UpdateDescriptorQueue& update_descriptor_queue_) 203 ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
204 : ComputePass(device_, descriptor_pool, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS, 204 : ComputePass(device_, descriptor_pool, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
205 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, {}, 205 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, {},
206 VULKAN_UINT8_COMP_SPV), 206 VULKAN_UINT8_COMP_SPV),
207 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 207 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
208 update_descriptor_queue{update_descriptor_queue_} {} 208 compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
209 209
210Uint8Pass::~Uint8Pass() = default; 210Uint8Pass::~Uint8Pass() = default;
211 211
@@ -214,10 +214,10 @@ std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer
214 const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); 214 const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16));
215 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); 215 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal);
216 216
217 update_descriptor_queue.Acquire(); 217 compute_pass_descriptor_queue.Acquire();
218 update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); 218 compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices);
219 update_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size); 219 compute_pass_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size);
220 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 220 const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
221 221
222 scheduler.RequestOutsideRenderPassOperationContext(); 222 scheduler.RequestOutsideRenderPassOperationContext();
223 scheduler.Record([this, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) { 223 scheduler.Record([this, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) {
@@ -242,12 +242,12 @@ std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer
242QuadIndexedPass::QuadIndexedPass(const Device& device_, Scheduler& scheduler_, 242QuadIndexedPass::QuadIndexedPass(const Device& device_, Scheduler& scheduler_,
243 DescriptorPool& descriptor_pool_, 243 DescriptorPool& descriptor_pool_,
244 StagingBufferPool& staging_buffer_pool_, 244 StagingBufferPool& staging_buffer_pool_,
245 UpdateDescriptorQueue& update_descriptor_queue_) 245 ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
246 : ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS, 246 : ComputePass(device_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
247 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO, 247 INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO,
248 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(u32) * 3>, VULKAN_QUAD_INDEXED_COMP_SPV), 248 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(u32) * 3>, VULKAN_QUAD_INDEXED_COMP_SPV),
249 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 249 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
250 update_descriptor_queue{update_descriptor_queue_} {} 250 compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
251 251
252QuadIndexedPass::~QuadIndexedPass() = default; 252QuadIndexedPass::~QuadIndexedPass() = default;
253 253
@@ -272,10 +272,10 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
272 const std::size_t staging_size = num_tri_vertices * sizeof(u32); 272 const std::size_t staging_size = num_tri_vertices * sizeof(u32);
273 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); 273 const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal);
274 274
275 update_descriptor_queue.Acquire(); 275 compute_pass_descriptor_queue.Acquire();
276 update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); 276 compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size);
277 update_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size); 277 compute_pass_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size);
278 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 278 const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
279 279
280 scheduler.RequestOutsideRenderPassOperationContext(); 280 scheduler.RequestOutsideRenderPassOperationContext();
281 scheduler.Record([this, descriptor_data, num_tri_vertices, base_vertex, index_shift, 281 scheduler.Record([this, descriptor_data, num_tri_vertices, base_vertex, index_shift,
@@ -304,13 +304,14 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
304ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_, 304ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_,
305 DescriptorPool& descriptor_pool_, 305 DescriptorPool& descriptor_pool_,
306 StagingBufferPool& staging_buffer_pool_, 306 StagingBufferPool& staging_buffer_pool_,
307 UpdateDescriptorQueue& update_descriptor_queue_, 307 ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
308 MemoryAllocator& memory_allocator_) 308 MemoryAllocator& memory_allocator_)
309 : ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS, 309 : ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS,
310 ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO, 310 ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO,
311 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV), 311 COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV),
312 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}, 312 scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
313 update_descriptor_queue{update_descriptor_queue_}, memory_allocator{memory_allocator_} {} 313 compute_pass_descriptor_queue{compute_pass_descriptor_queue_}, memory_allocator{
314 memory_allocator_} {}
314 315
315ASTCDecoderPass::~ASTCDecoderPass() = default; 316ASTCDecoderPass::~ASTCDecoderPass() = default;
316 317
@@ -358,11 +359,11 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
358 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U); 359 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
359 const u32 num_dispatches_z = image.info.resources.layers; 360 const u32 num_dispatches_z = image.info.resources.layers;
360 361
361 update_descriptor_queue.Acquire(); 362 compute_pass_descriptor_queue.Acquire();
362 update_descriptor_queue.AddBuffer(map.buffer, input_offset, 363 compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
363 image.guest_size_bytes - swizzle.buffer_offset); 364 image.guest_size_bytes - swizzle.buffer_offset);
364 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level)); 365 compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
365 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 366 const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
366 367
367 // To unswizzle the ASTC data 368 // To unswizzle the ASTC data
368 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info); 369 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index c4c8fa081..dd3927376 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 11#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
12#include "video_core/renderer_vulkan/vk_update_descriptor.h"
12#include "video_core/vulkan_common/vulkan_memory_allocator.h" 13#include "video_core/vulkan_common/vulkan_memory_allocator.h"
13#include "video_core/vulkan_common/vulkan_wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
14 15
@@ -21,7 +22,6 @@ namespace Vulkan {
21class Device; 22class Device;
22class StagingBufferPool; 23class StagingBufferPool;
23class Scheduler; 24class Scheduler;
24class UpdateDescriptorQueue;
25class Image; 25class Image;
26struct StagingBufferRef; 26struct StagingBufferRef;
27 27
@@ -50,7 +50,7 @@ class Uint8Pass final : public ComputePass {
50public: 50public:
51 explicit Uint8Pass(const Device& device_, Scheduler& scheduler_, 51 explicit Uint8Pass(const Device& device_, Scheduler& scheduler_,
52 DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, 52 DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_,
53 UpdateDescriptorQueue& update_descriptor_queue_); 53 ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
54 ~Uint8Pass(); 54 ~Uint8Pass();
55 55
56 /// Assemble uint8 indices into an uint16 index buffer 56 /// Assemble uint8 indices into an uint16 index buffer
@@ -61,7 +61,7 @@ public:
61private: 61private:
62 Scheduler& scheduler; 62 Scheduler& scheduler;
63 StagingBufferPool& staging_buffer_pool; 63 StagingBufferPool& staging_buffer_pool;
64 UpdateDescriptorQueue& update_descriptor_queue; 64 ComputePassDescriptorQueue& compute_pass_descriptor_queue;
65}; 65};
66 66
67class QuadIndexedPass final : public ComputePass { 67class QuadIndexedPass final : public ComputePass {
@@ -69,7 +69,7 @@ public:
69 explicit QuadIndexedPass(const Device& device_, Scheduler& scheduler_, 69 explicit QuadIndexedPass(const Device& device_, Scheduler& scheduler_,
70 DescriptorPool& descriptor_pool_, 70 DescriptorPool& descriptor_pool_,
71 StagingBufferPool& staging_buffer_pool_, 71 StagingBufferPool& staging_buffer_pool_,
72 UpdateDescriptorQueue& update_descriptor_queue_); 72 ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
73 ~QuadIndexedPass(); 73 ~QuadIndexedPass();
74 74
75 std::pair<VkBuffer, VkDeviceSize> Assemble( 75 std::pair<VkBuffer, VkDeviceSize> Assemble(
@@ -79,7 +79,7 @@ public:
79private: 79private:
80 Scheduler& scheduler; 80 Scheduler& scheduler;
81 StagingBufferPool& staging_buffer_pool; 81 StagingBufferPool& staging_buffer_pool;
82 UpdateDescriptorQueue& update_descriptor_queue; 82 ComputePassDescriptorQueue& compute_pass_descriptor_queue;
83}; 83};
84 84
85class ASTCDecoderPass final : public ComputePass { 85class ASTCDecoderPass final : public ComputePass {
@@ -87,7 +87,7 @@ public:
87 explicit ASTCDecoderPass(const Device& device_, Scheduler& scheduler_, 87 explicit ASTCDecoderPass(const Device& device_, Scheduler& scheduler_,
88 DescriptorPool& descriptor_pool_, 88 DescriptorPool& descriptor_pool_,
89 StagingBufferPool& staging_buffer_pool_, 89 StagingBufferPool& staging_buffer_pool_,
90 UpdateDescriptorQueue& update_descriptor_queue_, 90 ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
91 MemoryAllocator& memory_allocator_); 91 MemoryAllocator& memory_allocator_);
92 ~ASTCDecoderPass(); 92 ~ASTCDecoderPass();
93 93
@@ -97,7 +97,7 @@ public:
97private: 97private:
98 Scheduler& scheduler; 98 Scheduler& scheduler;
99 StagingBufferPool& staging_buffer_pool; 99 StagingBufferPool& staging_buffer_pool;
100 UpdateDescriptorQueue& update_descriptor_queue; 100 ComputePassDescriptorQueue& compute_pass_descriptor_queue;
101 MemoryAllocator& memory_allocator; 101 MemoryAllocator& memory_allocator;
102}; 102};
103 103
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 2a0f0dbf0..733e70d9d 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -26,13 +26,13 @@ using Tegra::Texture::TexturePair;
26 26
27ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_, 27ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_,
28 DescriptorPool& descriptor_pool, 28 DescriptorPool& descriptor_pool,
29 UpdateDescriptorQueue& update_descriptor_queue_, 29 GuestDescriptorQueue& guest_descriptor_queue_,
30 Common::ThreadWorker* thread_worker, 30 Common::ThreadWorker* thread_worker,
31 PipelineStatistics* pipeline_statistics, 31 PipelineStatistics* pipeline_statistics,
32 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, 32 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,
33 vk::ShaderModule spv_module_) 33 vk::ShaderModule spv_module_)
34 : device{device_}, pipeline_cache(pipeline_cache_), 34 : device{device_},
35 update_descriptor_queue{update_descriptor_queue_}, info{info_}, 35 pipeline_cache(pipeline_cache_), guest_descriptor_queue{guest_descriptor_queue_}, info{info_},
36 spv_module(std::move(spv_module_)) { 36 spv_module(std::move(spv_module_)) {
37 if (shader_notify) { 37 if (shader_notify) {
38 shader_notify->MarkShaderBuilding(); 38 shader_notify->MarkShaderBuilding();
@@ -99,7 +99,7 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
99void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, 99void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
100 Tegra::MemoryManager& gpu_memory, Scheduler& scheduler, 100 Tegra::MemoryManager& gpu_memory, Scheduler& scheduler,
101 BufferCache& buffer_cache, TextureCache& texture_cache) { 101 BufferCache& buffer_cache, TextureCache& texture_cache) {
102 update_descriptor_queue.Acquire(); 102 guest_descriptor_queue.Acquire();
103 103
104 buffer_cache.SetComputeUniformBufferState(info.constant_buffer_mask, &uniform_buffer_sizes); 104 buffer_cache.SetComputeUniformBufferState(info.constant_buffer_mask, &uniform_buffer_sizes);
105 buffer_cache.UnbindComputeStorageBuffers(); 105 buffer_cache.UnbindComputeStorageBuffers();
@@ -194,7 +194,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
194 RescalingPushConstant rescaling; 194 RescalingPushConstant rescaling;
195 const VkSampler* samplers_it{samplers.data()}; 195 const VkSampler* samplers_it{samplers.data()};
196 const VideoCommon::ImageViewInOut* views_it{views.data()}; 196 const VideoCommon::ImageViewInOut* views_it{views.data()};
197 PushImageDescriptors(texture_cache, update_descriptor_queue, info, rescaling, samplers_it, 197 PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it,
198 views_it); 198 views_it);
199 199
200 if (!is_built.load(std::memory_order::relaxed)) { 200 if (!is_built.load(std::memory_order::relaxed)) {
@@ -204,7 +204,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
204 build_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); }); 204 build_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); });
205 }); 205 });
206 } 206 }
207 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 207 const void* const descriptor_data{guest_descriptor_queue.UpdateData()};
208 const bool is_rescaling = !info.texture_descriptors.empty() || !info.image_descriptors.empty(); 208 const bool is_rescaling = !info.texture_descriptors.empty() || !info.image_descriptors.empty();
209 scheduler.Record([this, descriptor_data, is_rescaling, 209 scheduler.Record([this, descriptor_data, is_rescaling,
210 rescaling_data = rescaling.Data()](vk::CommandBuffer cmdbuf) { 210 rescaling_data = rescaling.Data()](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
index 78d77027f..d1a1e2c46 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -30,7 +30,7 @@ class ComputePipeline {
30public: 30public:
31 explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache, 31 explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache,
32 DescriptorPool& descriptor_pool, 32 DescriptorPool& descriptor_pool,
33 UpdateDescriptorQueue& update_descriptor_queue, 33 GuestDescriptorQueue& guest_descriptor_queue,
34 Common::ThreadWorker* thread_worker, 34 Common::ThreadWorker* thread_worker,
35 PipelineStatistics* pipeline_statistics, 35 PipelineStatistics* pipeline_statistics,
36 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info, 36 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info,
@@ -48,7 +48,7 @@ public:
48private: 48private:
49 const Device& device; 49 const Device& device;
50 vk::PipelineCache& pipeline_cache; 50 vk::PipelineCache& pipeline_cache;
51 UpdateDescriptorQueue& update_descriptor_queue; 51 GuestDescriptorQueue& guest_descriptor_queue;
52 Shader::Info info; 52 Shader::Info info;
53 53
54 VideoCommon::ComputeUniformBufferSizes uniform_buffer_sizes{}; 54 VideoCommon::ComputeUniformBufferSizes uniform_buffer_sizes{};
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index baedc4424..f1bcd5cd6 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -236,13 +236,13 @@ GraphicsPipeline::GraphicsPipeline(
236 Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, 236 Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
237 vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify, 237 vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify,
238 const Device& device_, DescriptorPool& descriptor_pool, 238 const Device& device_, DescriptorPool& descriptor_pool,
239 UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, 239 GuestDescriptorQueue& guest_descriptor_queue_, Common::ThreadWorker* worker_thread,
240 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, 240 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
241 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages, 241 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
242 const std::array<const Shader::Info*, NUM_STAGES>& infos) 242 const std::array<const Shader::Info*, NUM_STAGES>& infos)
243 : key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, 243 : key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
244 pipeline_cache(pipeline_cache_), scheduler{scheduler_}, 244 pipeline_cache(pipeline_cache_), scheduler{scheduler_},
245 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} { 245 guest_descriptor_queue{guest_descriptor_queue_}, spv_modules{std::move(stages)} {
246 if (shader_notify) { 246 if (shader_notify) {
247 shader_notify->MarkShaderBuilding(); 247 shader_notify->MarkShaderBuilding();
248 } 248 }
@@ -449,7 +449,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
449 buffer_cache.UpdateGraphicsBuffers(is_indexed); 449 buffer_cache.UpdateGraphicsBuffers(is_indexed);
450 buffer_cache.BindHostGeometryBuffers(is_indexed); 450 buffer_cache.BindHostGeometryBuffers(is_indexed);
451 451
452 update_descriptor_queue.Acquire(); 452 guest_descriptor_queue.Acquire();
453 453
454 RescalingPushConstant rescaling; 454 RescalingPushConstant rescaling;
455 RenderAreaPushConstant render_area; 455 RenderAreaPushConstant render_area;
@@ -457,7 +457,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
457 const VideoCommon::ImageViewInOut* views_it{views.data()}; 457 const VideoCommon::ImageViewInOut* views_it{views.data()};
458 const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { 458 const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE {
459 buffer_cache.BindHostStageBuffers(stage); 459 buffer_cache.BindHostStageBuffers(stage);
460 PushImageDescriptors(texture_cache, update_descriptor_queue, stage_infos[stage], rescaling, 460 PushImageDescriptors(texture_cache, guest_descriptor_queue, stage_infos[stage], rescaling,
461 samplers_it, views_it); 461 samplers_it, views_it);
462 const auto& info{stage_infos[0]}; 462 const auto& info{stage_infos[0]};
463 if (info.uses_render_area) { 463 if (info.uses_render_area) {
@@ -499,7 +499,7 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
499 const bool is_rescaling{texture_cache.IsRescaling()}; 499 const bool is_rescaling{texture_cache.IsRescaling()};
500 const bool update_rescaling{scheduler.UpdateRescaling(is_rescaling)}; 500 const bool update_rescaling{scheduler.UpdateRescaling(is_rescaling)};
501 const bool bind_pipeline{scheduler.UpdateGraphicsPipeline(this)}; 501 const bool bind_pipeline{scheduler.UpdateGraphicsPipeline(this)};
502 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 502 const void* const descriptor_data{guest_descriptor_queue.UpdateData()};
503 scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(), 503 scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(),
504 is_rescaling, update_rescaling, 504 is_rescaling, update_rescaling,
505 uses_render_area = render_area.uses_render_area, 505 uses_render_area = render_area.uses_render_area,
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 67c657d0e..99e56e9ad 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -64,7 +64,6 @@ class RenderPassCache;
64class RescalingPushConstant; 64class RescalingPushConstant;
65class RenderAreaPushConstant; 65class RenderAreaPushConstant;
66class Scheduler; 66class Scheduler;
67class UpdateDescriptorQueue;
68 67
69class GraphicsPipeline { 68class GraphicsPipeline {
70 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 69 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
@@ -74,7 +73,7 @@ public:
74 Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, 73 Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache,
75 vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify, 74 vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify,
76 const Device& device, DescriptorPool& descriptor_pool, 75 const Device& device, DescriptorPool& descriptor_pool,
77 UpdateDescriptorQueue& update_descriptor_queue, Common::ThreadWorker* worker_thread, 76 GuestDescriptorQueue& guest_descriptor_queue, Common::ThreadWorker* worker_thread,
78 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, 77 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
79 const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages, 78 const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
80 const std::array<const Shader::Info*, NUM_STAGES>& infos); 79 const std::array<const Shader::Info*, NUM_STAGES>& infos);
@@ -133,7 +132,7 @@ private:
133 BufferCache& buffer_cache; 132 BufferCache& buffer_cache;
134 vk::PipelineCache& pipeline_cache; 133 vk::PipelineCache& pipeline_cache;
135 Scheduler& scheduler; 134 Scheduler& scheduler;
136 UpdateDescriptorQueue& update_descriptor_queue; 135 GuestDescriptorQueue& guest_descriptor_queue;
137 136
138 void (*configure_func)(GraphicsPipeline*, bool){}; 137 void (*configure_func)(GraphicsPipeline*, bool){};
139 138
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index e5219e7e0..66dfe5733 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -277,11 +277,11 @@ bool GraphicsPipelineCacheKey::operator==(const GraphicsPipelineCacheKey& rhs) c
277 277
278PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_, 278PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device_,
279 Scheduler& scheduler_, DescriptorPool& descriptor_pool_, 279 Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
280 UpdateDescriptorQueue& update_descriptor_queue_, 280 GuestDescriptorQueue& guest_descriptor_queue_,
281 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_, 281 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_,
282 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_) 282 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_)
283 : VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_}, 283 : VideoCommon::ShaderCache{rasterizer_}, device{device_}, scheduler{scheduler_},
284 descriptor_pool{descriptor_pool_}, update_descriptor_queue{update_descriptor_queue_}, 284 descriptor_pool{descriptor_pool_}, guest_descriptor_queue{guest_descriptor_queue_},
285 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_}, 285 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_},
286 texture_cache{texture_cache_}, shader_notify{shader_notify_}, 286 texture_cache{texture_cache_}, shader_notify{shader_notify_},
287 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, 287 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
@@ -643,7 +643,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
643 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 643 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
644 return std::make_unique<GraphicsPipeline>( 644 return std::make_unique<GraphicsPipeline>(
645 scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device, 645 scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device,
646 descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key, 646 descriptor_pool, guest_descriptor_queue, thread_worker, statistics, render_pass_cache, key,
647 std::move(modules), infos); 647 std::move(modules), infos);
648 648
649} catch (const Shader::Exception& exception) { 649} catch (const Shader::Exception& exception) {
@@ -723,7 +723,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
723 } 723 }
724 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 724 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
725 return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool, 725 return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool,
726 update_descriptor_queue, thread_worker, statistics, 726 guest_descriptor_queue, thread_worker, statistics,
727 &shader_notify, program.info, std::move(spv_module)); 727 &shader_notify, program.info, std::move(spv_module));
728 728
729} catch (const Shader::Exception& exception) { 729} catch (const Shader::Exception& exception) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 5171912d7..15aa7e224 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -82,7 +82,6 @@ class PipelineStatistics;
82class RasterizerVulkan; 82class RasterizerVulkan;
83class RenderPassCache; 83class RenderPassCache;
84class Scheduler; 84class Scheduler;
85class UpdateDescriptorQueue;
86 85
87using VideoCommon::ShaderInfo; 86using VideoCommon::ShaderInfo;
88 87
@@ -102,7 +101,7 @@ class PipelineCache : public VideoCommon::ShaderCache {
102public: 101public:
103 explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device, Scheduler& scheduler, 102 explicit PipelineCache(RasterizerVulkan& rasterizer, const Device& device, Scheduler& scheduler,
104 DescriptorPool& descriptor_pool, 103 DescriptorPool& descriptor_pool,
105 UpdateDescriptorQueue& update_descriptor_queue, 104 GuestDescriptorQueue& guest_descriptor_queue,
106 RenderPassCache& render_pass_cache, BufferCache& buffer_cache, 105 RenderPassCache& render_pass_cache, BufferCache& buffer_cache,
107 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_); 106 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_);
108 ~PipelineCache(); 107 ~PipelineCache();
@@ -144,7 +143,7 @@ private:
144 const Device& device; 143 const Device& device;
145 Scheduler& scheduler; 144 Scheduler& scheduler;
146 DescriptorPool& descriptor_pool; 145 DescriptorPool& descriptor_pool;
147 UpdateDescriptorQueue& update_descriptor_queue; 146 GuestDescriptorQueue& guest_descriptor_queue;
148 RenderPassCache& render_pass_cache; 147 RenderPassCache& render_pass_cache;
149 BufferCache& buffer_cache; 148 BufferCache& buffer_cache;
150 TextureCache& texture_cache; 149 TextureCache& texture_cache;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index d1489fc95..64bd2f6a5 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -160,17 +160,16 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
160 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_}, 160 : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, screen_info{screen_info_}, device{device_},
161 memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, 161 memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_},
162 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), 162 staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler),
163 update_descriptor_queue(device, scheduler), 163 guest_descriptor_queue(device, scheduler), compute_pass_descriptor_queue(device, scheduler),
164 blit_image(device, scheduler, state_tracker, descriptor_pool), 164 blit_image(device, scheduler, state_tracker, descriptor_pool), render_pass_cache(device),
165 render_pass_cache(device), texture_cache_runtime{device, scheduler, 165 texture_cache_runtime{
166 memory_allocator, staging_pool, 166 device, scheduler, memory_allocator, staging_pool,
167 blit_image, render_pass_cache, 167 blit_image, render_pass_cache, descriptor_pool, compute_pass_descriptor_queue},
168 descriptor_pool, update_descriptor_queue},
169 texture_cache(texture_cache_runtime, *this), 168 texture_cache(texture_cache_runtime, *this),
170 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool, 169 buffer_cache_runtime(device, memory_allocator, scheduler, staging_pool,
171 update_descriptor_queue, descriptor_pool), 170 guest_descriptor_queue, compute_pass_descriptor_queue, descriptor_pool),
172 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 171 buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
173 pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue, 172 pipeline_cache(*this, device, scheduler, descriptor_pool, guest_descriptor_queue,
174 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), 173 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),
175 query_cache{*this, cpu_memory_, device, scheduler}, 174 query_cache{*this, cpu_memory_, device, scheduler},
176 accelerate_dma(buffer_cache, texture_cache, scheduler), 175 accelerate_dma(buffer_cache, texture_cache, scheduler),
@@ -502,6 +501,22 @@ bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheT
502 return false; 501 return false;
503} 502}
504 503
504VideoCore::RasterizerDownloadArea RasterizerVulkan::GetFlushArea(VAddr addr, u64 size) {
505 {
506 std::scoped_lock lock{texture_cache.mutex};
507 auto area = texture_cache.GetFlushArea(addr, size);
508 if (area) {
509 return *area;
510 }
511 }
512 VideoCore::RasterizerDownloadArea new_area{
513 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE),
514 .end_address = Common::AlignUp(addr + size, Core::Memory::YUZU_PAGESIZE),
515 .preemtive = true,
516 };
517 return new_area;
518}
519
505void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 520void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) {
506 if (addr == 0 || size == 0) { 521 if (addr == 0 || size == 0) {
507 return; 522 return;
@@ -598,7 +613,7 @@ void RasterizerVulkan::SignalSyncPoint(u32 value) {
598} 613}
599 614
600void RasterizerVulkan::SignalReference() { 615void RasterizerVulkan::SignalReference() {
601 fence_manager.SignalOrdering(); 616 fence_manager.SignalReference();
602} 617}
603 618
604void RasterizerVulkan::ReleaseFences() { 619void RasterizerVulkan::ReleaseFences() {
@@ -631,7 +646,7 @@ void RasterizerVulkan::WaitForIdle() {
631 cmdbuf.SetEvent(event, flags); 646 cmdbuf.SetEvent(event, flags);
632 cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {}); 647 cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {});
633 }); 648 });
634 SignalReference(); 649 fence_manager.SignalOrdering();
635} 650}
636 651
637void RasterizerVulkan::FragmentBarrier() { 652void RasterizerVulkan::FragmentBarrier() {
@@ -653,7 +668,8 @@ void RasterizerVulkan::FlushCommands() {
653 668
654void RasterizerVulkan::TickFrame() { 669void RasterizerVulkan::TickFrame() {
655 draw_counter = 0; 670 draw_counter = 0;
656 update_descriptor_queue.TickFrame(); 671 guest_descriptor_queue.TickFrame();
672 compute_pass_descriptor_queue.TickFrame();
657 fence_manager.TickFrame(); 673 fence_manager.TickFrame();
658 staging_pool.TickFrame(); 674 staging_pool.TickFrame();
659 { 675 {
@@ -777,7 +793,7 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
777 const Tegra::DMA::BufferOperand& buffer_operand, 793 const Tegra::DMA::BufferOperand& buffer_operand,
778 const Tegra::DMA::ImageOperand& image_operand) { 794 const Tegra::DMA::ImageOperand& image_operand) {
779 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; 795 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
780 const auto image_id = texture_cache.DmaImageId(image_operand); 796 const auto image_id = texture_cache.DmaImageId(image_operand, IS_IMAGE_UPLOAD);
781 if (image_id == VideoCommon::NULL_IMAGE_ID) { 797 if (image_id == VideoCommon::NULL_IMAGE_ID) {
782 return false; 798 return false;
783 } 799 }
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 1659fbc13..b39710b3c 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -92,6 +92,7 @@ public:
92 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 92 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
93 bool MustFlushRegion(VAddr addr, u64 size, 93 bool MustFlushRegion(VAddr addr, u64 size,
94 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 94 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
95 VideoCore::RasterizerDownloadArea GetFlushArea(VAddr addr, u64 size) override;
95 void InvalidateRegion(VAddr addr, u64 size, 96 void InvalidateRegion(VAddr addr, u64 size,
96 VideoCommon::CacheType which = VideoCommon::CacheType::All) override; 97 VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
97 void InnerInvalidation(std::span<const std::pair<VAddr, std::size_t>> sequences) override; 98 void InnerInvalidation(std::span<const std::pair<VAddr, std::size_t>> sequences) override;
@@ -183,7 +184,8 @@ private:
183 184
184 StagingBufferPool staging_pool; 185 StagingBufferPool staging_pool;
185 DescriptorPool descriptor_pool; 186 DescriptorPool descriptor_pool;
186 UpdateDescriptorQueue update_descriptor_queue; 187 GuestDescriptorQueue guest_descriptor_queue;
188 ComputePassDescriptorQueue compute_pass_descriptor_queue;
187 BlitImageHelper blit_image; 189 BlitImageHelper blit_image;
188 RenderPassCache render_pass_cache; 190 RenderPassCache render_pass_cache;
189 191
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index d0a7d8f35..4d0481f2a 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -798,13 +798,13 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
798 BlitImageHelper& blit_image_helper_, 798 BlitImageHelper& blit_image_helper_,
799 RenderPassCache& render_pass_cache_, 799 RenderPassCache& render_pass_cache_,
800 DescriptorPool& descriptor_pool, 800 DescriptorPool& descriptor_pool,
801 UpdateDescriptorQueue& update_descriptor_queue) 801 ComputePassDescriptorQueue& compute_pass_descriptor_queue)
802 : device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_}, 802 : device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_},
803 staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_}, 803 staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_},
804 render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} { 804 render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} {
805 if (Settings::values.accelerate_astc) { 805 if (Settings::values.accelerate_astc) {
806 astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, 806 astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
807 update_descriptor_queue, memory_allocator); 807 compute_pass_descriptor_queue, memory_allocator);
808 } 808 }
809} 809}
810 810
@@ -1268,7 +1268,7 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
1268 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { 1268 if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
1269 if (Settings::values.async_astc.GetValue()) { 1269 if (Settings::values.async_astc.GetValue()) {
1270 flags |= VideoCommon::ImageFlagBits::AsynchronousDecode; 1270 flags |= VideoCommon::ImageFlagBits::AsynchronousDecode;
1271 } else if (Settings::values.accelerate_astc.GetValue()) { 1271 } else if (Settings::values.accelerate_astc.GetValue() && info.size.depth == 1) {
1272 flags |= VideoCommon::ImageFlagBits::AcceleratedUpload; 1272 flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
1273 } 1273 }
1274 flags |= VideoCommon::ImageFlagBits::Converted; 1274 flags |= VideoCommon::ImageFlagBits::Converted;
@@ -1584,8 +1584,9 @@ bool Image::NeedsScaleHelper() const {
1584 1584
1585ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, 1585ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
1586 ImageId image_id_, Image& image) 1586 ImageId image_id_, Image& image)
1587 : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, 1587 : VideoCommon::ImageViewBase{info, image.info, image_id_, image.gpu_addr},
1588 image_handle{image.Handle()}, samples(ConvertSampleCount(image.info.num_samples)) { 1588 device{&runtime.device}, image_handle{image.Handle()},
1589 samples(ConvertSampleCount(image.info.num_samples)) {
1589 using Shader::TextureType; 1590 using Shader::TextureType;
1590 1591
1591 const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); 1592 const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
@@ -1631,7 +1632,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1631 } 1632 }
1632 vk::ImageView handle = device->GetLogical().CreateImageView(ci); 1633 vk::ImageView handle = device->GetLogical().CreateImageView(ci);
1633 if (device->HasDebuggingToolAttached()) { 1634 if (device->HasDebuggingToolAttached()) {
1634 handle.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); 1635 handle.SetObjectNameEXT(VideoCommon::Name(*this, gpu_addr).c_str());
1635 } 1636 }
1636 image_views[static_cast<size_t>(tex_type)] = std::move(handle); 1637 image_views[static_cast<size_t>(tex_type)] = std::move(handle);
1637 }; 1638 };
@@ -1672,7 +1673,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1672 1673
1673ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, 1674ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
1674 const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) 1675 const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_)
1675 : VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_}, 1676 : VideoCommon::ImageViewBase{info, view_info, gpu_addr_},
1676 buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {} 1677 buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {}
1677 1678
1678ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams& params) 1679ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams& params)
@@ -1863,6 +1864,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
1863 num_layers = std::max(num_layers, color_buffer->range.extent.layers); 1864 num_layers = std::max(num_layers, color_buffer->range.extent.layers);
1864 images[num_images] = color_buffer->ImageHandle(); 1865 images[num_images] = color_buffer->ImageHandle();
1865 image_ranges[num_images] = MakeSubresourceRange(color_buffer); 1866 image_ranges[num_images] = MakeSubresourceRange(color_buffer);
1867 rt_map[index] = num_images;
1866 samples = color_buffer->Samples(); 1868 samples = color_buffer->Samples();
1867 ++num_images; 1869 ++num_images;
1868 } 1870 }
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index c656c5386..4166b3d20 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -34,7 +34,6 @@ class ImageView;
34class Framebuffer; 34class Framebuffer;
35class RenderPassCache; 35class RenderPassCache;
36class StagingBufferPool; 36class StagingBufferPool;
37class UpdateDescriptorQueue;
38class Scheduler; 37class Scheduler;
39 38
40class TextureCacheRuntime { 39class TextureCacheRuntime {
@@ -45,7 +44,7 @@ public:
45 BlitImageHelper& blit_image_helper_, 44 BlitImageHelper& blit_image_helper_,
46 RenderPassCache& render_pass_cache_, 45 RenderPassCache& render_pass_cache_,
47 DescriptorPool& descriptor_pool, 46 DescriptorPool& descriptor_pool,
48 UpdateDescriptorQueue& update_descriptor_queue); 47 ComputePassDescriptorQueue& compute_pass_descriptor_queue);
49 48
50 void Finish(); 49 void Finish();
51 50
@@ -265,7 +264,6 @@ private:
265 VkImage image_handle = VK_NULL_HANDLE; 264 VkImage image_handle = VK_NULL_HANDLE;
266 VkImageView render_target = VK_NULL_HANDLE; 265 VkImageView render_target = VK_NULL_HANDLE;
267 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; 266 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
268 GPUVAddr gpu_addr = 0;
269 u32 buffer_size = 0; 267 u32 buffer_size = 0;
270}; 268};
271 269
@@ -336,7 +334,7 @@ public:
336 } 334 }
337 335
338 [[nodiscard]] bool HasAspectColorBit(size_t index) const noexcept { 336 [[nodiscard]] bool HasAspectColorBit(size_t index) const noexcept {
339 return (image_ranges.at(index).aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0; 337 return (image_ranges.at(rt_map[index]).aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
340 } 338 }
341 339
342 [[nodiscard]] bool HasAspectDepthBit() const noexcept { 340 [[nodiscard]] bool HasAspectDepthBit() const noexcept {
@@ -356,6 +354,7 @@ private:
356 u32 num_images = 0; 354 u32 num_images = 0;
357 std::array<VkImage, 9> images{}; 355 std::array<VkImage, 9> images{};
358 std::array<VkImageSubresourceRange, 9> image_ranges{}; 356 std::array<VkImageSubresourceRange, 9> image_ranges{};
357 std::array<size_t, NUM_RT> rt_map{};
359 bool has_depth{}; 358 bool has_depth{};
360 bool has_stencil{}; 359 bool has_stencil{};
361}; 360};
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 1c1a7020b..310fb551a 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -32,7 +32,7 @@ class UpdateDescriptorQueue final {
32 // This should be plenty for the vast majority of cases. Most desktop platforms only 32 // This should be plenty for the vast majority of cases. Most desktop platforms only
33 // provide up to 3 swapchain images. 33 // provide up to 3 swapchain images.
34 static constexpr size_t FRAMES_IN_FLIGHT = 5; 34 static constexpr size_t FRAMES_IN_FLIGHT = 5;
35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x10000; 35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x20000;
36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT; 36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;
37 37
38public: 38public:
@@ -86,4 +86,8 @@ private:
86 std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload; 86 std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload;
87}; 87};
88 88
89// TODO: should these be separate classes instead?
90using GuestDescriptorQueue = UpdateDescriptorQueue;
91using ComputePassDescriptorQueue = UpdateDescriptorQueue;
92
89} // namespace Vulkan 93} // namespace Vulkan
diff --git a/src/video_core/texture_cache/formatter.cpp b/src/video_core/texture_cache/formatter.cpp
index 30f72361d..6279d8e9e 100644
--- a/src/video_core/texture_cache/formatter.cpp
+++ b/src/video_core/texture_cache/formatter.cpp
@@ -46,7 +46,7 @@ std::string Name(const ImageBase& image) {
46 return "Invalid"; 46 return "Invalid";
47} 47}
48 48
49std::string Name(const ImageViewBase& image_view) { 49std::string Name(const ImageViewBase& image_view, GPUVAddr addr) {
50 const u32 width = image_view.size.width; 50 const u32 width = image_view.size.width;
51 const u32 height = image_view.size.height; 51 const u32 height = image_view.size.height;
52 const u32 depth = image_view.size.depth; 52 const u32 depth = image_view.size.depth;
@@ -56,23 +56,25 @@ std::string Name(const ImageViewBase& image_view) {
56 const std::string level = num_levels > 1 ? fmt::format(":{}", num_levels) : ""; 56 const std::string level = num_levels > 1 ? fmt::format(":{}", num_levels) : "";
57 switch (image_view.type) { 57 switch (image_view.type) {
58 case ImageViewType::e1D: 58 case ImageViewType::e1D:
59 return fmt::format("ImageView 1D {}{}", width, level); 59 return fmt::format("ImageView 1D 0x{:X} {}{}", addr, width, level);
60 case ImageViewType::e2D: 60 case ImageViewType::e2D:
61 return fmt::format("ImageView 2D {}x{}{}", width, height, level); 61 return fmt::format("ImageView 2D 0x{:X} {}x{}{}", addr, width, height, level);
62 case ImageViewType::Cube: 62 case ImageViewType::Cube:
63 return fmt::format("ImageView Cube {}x{}{}", width, height, level); 63 return fmt::format("ImageView Cube 0x{:X} {}x{}{}", addr, width, height, level);
64 case ImageViewType::e3D: 64 case ImageViewType::e3D:
65 return fmt::format("ImageView 3D {}x{}x{}{}", width, height, depth, level); 65 return fmt::format("ImageView 3D 0x{:X} {}x{}x{}{}", addr, width, height, depth, level);
66 case ImageViewType::e1DArray: 66 case ImageViewType::e1DArray:
67 return fmt::format("ImageView 1DArray {}{}|{}", width, level, num_layers); 67 return fmt::format("ImageView 1DArray 0x{:X} {}{}|{}", addr, width, level, num_layers);
68 case ImageViewType::e2DArray: 68 case ImageViewType::e2DArray:
69 return fmt::format("ImageView 2DArray {}x{}{}|{}", width, height, level, num_layers); 69 return fmt::format("ImageView 2DArray 0x{:X} {}x{}{}|{}", addr, width, height, level,
70 num_layers);
70 case ImageViewType::CubeArray: 71 case ImageViewType::CubeArray:
71 return fmt::format("ImageView CubeArray {}x{}{}|{}", width, height, level, num_layers); 72 return fmt::format("ImageView CubeArray 0x{:X} {}x{}{}|{}", addr, width, height, level,
73 num_layers);
72 case ImageViewType::Rect: 74 case ImageViewType::Rect:
73 return fmt::format("ImageView Rect {}x{}{}", width, height, level); 75 return fmt::format("ImageView Rect 0x{:X} {}x{}{}", addr, width, height, level);
74 case ImageViewType::Buffer: 76 case ImageViewType::Buffer:
75 return fmt::format("BufferView {}", width); 77 return fmt::format("BufferView 0x{:X} {}", addr, width);
76 } 78 }
77 return "Invalid"; 79 return "Invalid";
78} 80}
diff --git a/src/video_core/texture_cache/formatter.h b/src/video_core/texture_cache/formatter.h
index b97147797..9ee57a076 100644
--- a/src/video_core/texture_cache/formatter.h
+++ b/src/video_core/texture_cache/formatter.h
@@ -274,7 +274,7 @@ struct RenderTargets;
274 274
275[[nodiscard]] std::string Name(const ImageBase& image); 275[[nodiscard]] std::string Name(const ImageBase& image);
276 276
277[[nodiscard]] std::string Name(const ImageViewBase& image_view); 277[[nodiscard]] std::string Name(const ImageViewBase& image_view, GPUVAddr addr);
278 278
279[[nodiscard]] std::string Name(const RenderTargets& render_targets); 279[[nodiscard]] std::string Name(const RenderTargets& render_targets);
280 280
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp
index 11f3f78a1..e8ddde691 100644
--- a/src/video_core/texture_cache/image_info.cpp
+++ b/src/video_core/texture_cache/image_info.cpp
@@ -4,6 +4,7 @@
4#include <fmt/format.h> 4#include <fmt/format.h>
5 5
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/settings.h"
7#include "video_core/surface.h" 8#include "video_core/surface.h"
8#include "video_core/texture_cache/format_lookup_table.h" 9#include "video_core/texture_cache/format_lookup_table.h"
9#include "video_core/texture_cache/image_info.h" 10#include "video_core/texture_cache/image_info.h"
@@ -22,6 +23,8 @@ using VideoCore::Surface::PixelFormat;
22using VideoCore::Surface::SurfaceType; 23using VideoCore::Surface::SurfaceType;
23 24
24ImageInfo::ImageInfo(const TICEntry& config) noexcept { 25ImageInfo::ImageInfo(const TICEntry& config) noexcept {
26 forced_flushed = config.IsPitchLinear() && !Settings::values.use_reactive_flushing.GetValue();
27 dma_downloaded = forced_flushed;
25 format = PixelFormatFromTextureInfo(config.format, config.r_type, config.g_type, config.b_type, 28 format = PixelFormatFromTextureInfo(config.format, config.r_type, config.g_type, config.b_type,
26 config.a_type, config.srgb_conversion); 29 config.a_type, config.srgb_conversion);
27 num_samples = NumSamples(config.msaa_mode); 30 num_samples = NumSamples(config.msaa_mode);
@@ -117,6 +120,9 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
117 120
118ImageInfo::ImageInfo(const Maxwell3D::Regs::RenderTargetConfig& ct, 121ImageInfo::ImageInfo(const Maxwell3D::Regs::RenderTargetConfig& ct,
119 Tegra::Texture::MsaaMode msaa_mode) noexcept { 122 Tegra::Texture::MsaaMode msaa_mode) noexcept {
123 forced_flushed =
124 ct.tile_mode.is_pitch_linear && !Settings::values.use_reactive_flushing.GetValue();
125 dma_downloaded = forced_flushed;
120 format = VideoCore::Surface::PixelFormatFromRenderTargetFormat(ct.format); 126 format = VideoCore::Surface::PixelFormatFromRenderTargetFormat(ct.format);
121 rescaleable = false; 127 rescaleable = false;
122 if (ct.tile_mode.is_pitch_linear) { 128 if (ct.tile_mode.is_pitch_linear) {
@@ -155,6 +161,9 @@ ImageInfo::ImageInfo(const Maxwell3D::Regs::RenderTargetConfig& ct,
155 161
156ImageInfo::ImageInfo(const Maxwell3D::Regs::Zeta& zt, const Maxwell3D::Regs::ZetaSize& zt_size, 162ImageInfo::ImageInfo(const Maxwell3D::Regs::Zeta& zt, const Maxwell3D::Regs::ZetaSize& zt_size,
157 Tegra::Texture::MsaaMode msaa_mode) noexcept { 163 Tegra::Texture::MsaaMode msaa_mode) noexcept {
164 forced_flushed =
165 zt.tile_mode.is_pitch_linear && !Settings::values.use_reactive_flushing.GetValue();
166 dma_downloaded = forced_flushed;
158 format = VideoCore::Surface::PixelFormatFromDepthFormat(zt.format); 167 format = VideoCore::Surface::PixelFormatFromDepthFormat(zt.format);
159 size.width = zt_size.width; 168 size.width = zt_size.width;
160 size.height = zt_size.height; 169 size.height = zt_size.height;
@@ -195,6 +204,9 @@ ImageInfo::ImageInfo(const Maxwell3D::Regs::Zeta& zt, const Maxwell3D::Regs::Zet
195 204
196ImageInfo::ImageInfo(const Fermi2D::Surface& config) noexcept { 205ImageInfo::ImageInfo(const Fermi2D::Surface& config) noexcept {
197 UNIMPLEMENTED_IF_MSG(config.layer != 0, "Surface layer is not zero"); 206 UNIMPLEMENTED_IF_MSG(config.layer != 0, "Surface layer is not zero");
207 forced_flushed = config.linear == Fermi2D::MemoryLayout::Pitch &&
208 !Settings::values.use_reactive_flushing.GetValue();
209 dma_downloaded = forced_flushed;
198 format = VideoCore::Surface::PixelFormatFromRenderTargetFormat(config.format); 210 format = VideoCore::Surface::PixelFormatFromRenderTargetFormat(config.format);
199 rescaleable = false; 211 rescaleable = false;
200 if (config.linear == Fermi2D::MemoryLayout::Pitch) { 212 if (config.linear == Fermi2D::MemoryLayout::Pitch) {
diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h
index 4b7dfa315..8a4cb0cbd 100644
--- a/src/video_core/texture_cache/image_info.h
+++ b/src/video_core/texture_cache/image_info.h
@@ -39,6 +39,8 @@ struct ImageInfo {
39 u32 tile_width_spacing = 0; 39 u32 tile_width_spacing = 0;
40 bool rescaleable = false; 40 bool rescaleable = false;
41 bool downscaleable = false; 41 bool downscaleable = false;
42 bool forced_flushed = false;
43 bool dma_downloaded = false;
42}; 44};
43 45
44} // namespace VideoCommon 46} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/image_view_base.cpp b/src/video_core/texture_cache/image_view_base.cpp
index 04fb84bfa..d134b6738 100644
--- a/src/video_core/texture_cache/image_view_base.cpp
+++ b/src/video_core/texture_cache/image_view_base.cpp
@@ -4,7 +4,6 @@
4#include <algorithm> 4#include <algorithm>
5 5
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/settings.h"
8#include "video_core/compatible_formats.h" 7#include "video_core/compatible_formats.h"
9#include "video_core/surface.h" 8#include "video_core/surface.h"
10#include "video_core/texture_cache/formatter.h" 9#include "video_core/texture_cache/formatter.h"
@@ -16,8 +15,8 @@
16namespace VideoCommon { 15namespace VideoCommon {
17 16
18ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_info, 17ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_info,
19 ImageId image_id_) 18 ImageId image_id_, GPUVAddr addr)
20 : image_id{image_id_}, format{info.format}, type{info.type}, range{info.range}, 19 : image_id{image_id_}, gpu_addr{addr}, format{info.format}, type{info.type}, range{info.range},
21 size{ 20 size{
22 .width = std::max(image_info.size.width >> range.base.level, 1u), 21 .width = std::max(image_info.size.width >> range.base.level, 1u),
23 .height = std::max(image_info.size.height >> range.base.level, 1u), 22 .height = std::max(image_info.size.height >> range.base.level, 1u),
@@ -26,8 +25,7 @@ ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_i
26 ASSERT_MSG(VideoCore::Surface::IsViewCompatible(image_info.format, info.format, false, true), 25 ASSERT_MSG(VideoCore::Surface::IsViewCompatible(image_info.format, info.format, false, true),
27 "Image view format {} is incompatible with image format {}", info.format, 26 "Image view format {} is incompatible with image format {}", info.format,
28 image_info.format); 27 image_info.format);
29 const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue(); 28 if (image_info.forced_flushed) {
30 if (image_info.type == ImageType::Linear && is_async) {
31 flags |= ImageViewFlagBits::PreemtiveDownload; 29 flags |= ImageViewFlagBits::PreemtiveDownload;
32 } 30 }
33 if (image_info.type == ImageType::e3D && info.type != ImageViewType::e3D) { 31 if (image_info.type == ImageType::e3D && info.type != ImageViewType::e3D) {
@@ -35,8 +33,8 @@ ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_i
35 } 33 }
36} 34}
37 35
38ImageViewBase::ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_info) 36ImageViewBase::ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_info, GPUVAddr addr)
39 : image_id{NULL_IMAGE_ID}, format{info.format}, type{ImageViewType::Buffer}, 37 : image_id{NULL_IMAGE_ID}, gpu_addr{addr}, format{info.format}, type{ImageViewType::Buffer},
40 size{ 38 size{
41 .width = info.size.width, 39 .width = info.size.width,
42 .height = 1, 40 .height = 1,
diff --git a/src/video_core/texture_cache/image_view_base.h b/src/video_core/texture_cache/image_view_base.h
index 69c9776e7..a25ae1d4a 100644
--- a/src/video_core/texture_cache/image_view_base.h
+++ b/src/video_core/texture_cache/image_view_base.h
@@ -24,9 +24,9 @@ enum class ImageViewFlagBits : u16 {
24DECLARE_ENUM_FLAG_OPERATORS(ImageViewFlagBits) 24DECLARE_ENUM_FLAG_OPERATORS(ImageViewFlagBits)
25 25
26struct ImageViewBase { 26struct ImageViewBase {
27 explicit ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_info, 27 explicit ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_info, ImageId image_id,
28 ImageId image_id); 28 GPUVAddr addr);
29 explicit ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_info); 29 explicit ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_info, GPUVAddr addr);
30 explicit ImageViewBase(const NullImageViewParams&); 30 explicit ImageViewBase(const NullImageViewParams&);
31 31
32 [[nodiscard]] bool IsBuffer() const noexcept { 32 [[nodiscard]] bool IsBuffer() const noexcept {
@@ -34,6 +34,7 @@ struct ImageViewBase {
34 } 34 }
35 35
36 ImageId image_id{}; 36 ImageId image_id{};
37 GPUVAddr gpu_addr = 0;
37 PixelFormat format{}; 38 PixelFormat format{};
38 ImageViewType type{}; 39 ImageViewType type{};
39 SubresourceRange range; 40 SubresourceRange range;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index f335009d0..b24086fce 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -491,6 +491,32 @@ void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) {
491} 491}
492 492
493template <class P> 493template <class P>
494std::optional<VideoCore::RasterizerDownloadArea> TextureCache<P>::GetFlushArea(VAddr cpu_addr,
495 u64 size) {
496 std::optional<VideoCore::RasterizerDownloadArea> area{};
497 ForEachImageInRegion(cpu_addr, size, [&](ImageId, ImageBase& image) {
498 if (False(image.flags & ImageFlagBits::GpuModified)) {
499 return;
500 }
501 if (!area) {
502 area.emplace();
503 area->start_address = cpu_addr;
504 area->end_address = cpu_addr + size;
505 area->preemtive = true;
506 }
507 area->start_address = std::min(area->start_address, image.cpu_addr);
508 area->end_address = std::max(area->end_address, image.cpu_addr_end);
509 for (auto image_view_id : image.image_view_ids) {
510 auto& image_view = slot_image_views[image_view_id];
511 image_view.flags |= ImageViewFlagBits::PreemtiveDownload;
512 }
513 area->preemtive &= image.info.forced_flushed;
514 image.info.forced_flushed = true;
515 });
516 return area;
517}
518
519template <class P>
494void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { 520void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) {
495 std::vector<ImageId> deleted_images; 521 std::vector<ImageId> deleted_images;
496 ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); }); 522 ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); });
@@ -683,6 +709,7 @@ void TextureCache<P>::CommitAsyncFlushes() {
683 download_info.async_buffer_id = last_async_buffer_id; 709 download_info.async_buffer_id = last_async_buffer_id;
684 } 710 }
685 } 711 }
712
686 if (any_none_dma) { 713 if (any_none_dma) {
687 auto download_map = runtime.DownloadStagingBuffer(total_size_bytes, true); 714 auto download_map = runtime.DownloadStagingBuffer(total_size_bytes, true);
688 for (const PendingDownload& download_info : download_ids) { 715 for (const PendingDownload& download_info : download_ids) {
@@ -695,6 +722,7 @@ void TextureCache<P>::CommitAsyncFlushes() {
695 } 722 }
696 uncommitted_async_buffers.emplace_back(download_map); 723 uncommitted_async_buffers.emplace_back(download_map);
697 } 724 }
725
698 async_buffers.emplace_back(std::move(uncommitted_async_buffers)); 726 async_buffers.emplace_back(std::move(uncommitted_async_buffers));
699 uncommitted_async_buffers.clear(); 727 uncommitted_async_buffers.clear();
700 } 728 }
@@ -783,17 +811,22 @@ void TextureCache<P>::PopAsyncFlushes() {
783} 811}
784 812
785template <class P> 813template <class P>
786ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand) { 814ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand, bool is_upload) {
787 const ImageInfo dst_info(operand); 815 const ImageInfo dst_info(operand);
788 const ImageId dst_id = FindDMAImage(dst_info, operand.address); 816 const ImageId dst_id = FindDMAImage(dst_info, operand.address);
789 if (!dst_id) { 817 if (!dst_id) {
790 return NULL_IMAGE_ID; 818 return NULL_IMAGE_ID;
791 } 819 }
792 const auto& image = slot_images[dst_id]; 820 auto& image = slot_images[dst_id];
793 if (False(image.flags & ImageFlagBits::GpuModified)) { 821 if (False(image.flags & ImageFlagBits::GpuModified)) {
794 // No need to waste time on an image that's synced with guest 822 // No need to waste time on an image that's synced with guest
795 return NULL_IMAGE_ID; 823 return NULL_IMAGE_ID;
796 } 824 }
825 if (!is_upload && !image.info.dma_downloaded) {
826 // Force a full sync.
827 image.info.dma_downloaded = true;
828 return NULL_IMAGE_ID;
829 }
797 const auto base = image.TryFindBase(operand.address); 830 const auto base = image.TryFindBase(operand.address);
798 if (!base) { 831 if (!base) {
799 return NULL_IMAGE_ID; 832 return NULL_IMAGE_ID;
@@ -1290,7 +1323,6 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
1290 all_siblings.push_back(overlap_id); 1323 all_siblings.push_back(overlap_id);
1291 } else { 1324 } else {
1292 bad_overlap_ids.push_back(overlap_id); 1325 bad_overlap_ids.push_back(overlap_id);
1293 overlap.flags |= ImageFlagBits::BadOverlap;
1294 } 1326 }
1295 }; 1327 };
1296 ForEachImageInRegion(cpu_addr, size_bytes, region_check); 1328 ForEachImageInRegion(cpu_addr, size_bytes, region_check);
@@ -1359,6 +1391,12 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
1359 ScaleDown(new_image); 1391 ScaleDown(new_image);
1360 } 1392 }
1361 1393
1394 std::ranges::sort(overlap_ids, [this](const ImageId lhs, const ImageId rhs) {
1395 const ImageBase& lhs_image = slot_images[lhs];
1396 const ImageBase& rhs_image = slot_images[rhs];
1397 return lhs_image.modification_tick < rhs_image.modification_tick;
1398 });
1399
1362 for (const ImageId overlap_id : overlap_ids) { 1400 for (const ImageId overlap_id : overlap_ids) {
1363 Image& overlap = slot_images[overlap_id]; 1401 Image& overlap = slot_images[overlap_id];
1364 if (True(overlap.flags & ImageFlagBits::GpuModified)) { 1402 if (True(overlap.flags & ImageFlagBits::GpuModified)) {
@@ -1395,7 +1433,12 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
1395 ImageBase& aliased = slot_images[aliased_id]; 1433 ImageBase& aliased = slot_images[aliased_id];
1396 aliased.overlapping_images.push_back(new_image_id); 1434 aliased.overlapping_images.push_back(new_image_id);
1397 new_image.overlapping_images.push_back(aliased_id); 1435 new_image.overlapping_images.push_back(aliased_id);
1398 new_image.flags |= ImageFlagBits::BadOverlap; 1436 if (aliased.info.resources.levels == 1 && aliased.overlapping_images.size() > 1) {
1437 aliased.flags |= ImageFlagBits::BadOverlap;
1438 }
1439 if (new_image.info.resources.levels == 1 && new_image.overlapping_images.size() > 1) {
1440 new_image.flags |= ImageFlagBits::BadOverlap;
1441 }
1399 } 1442 }
1400 RegisterImage(new_image_id); 1443 RegisterImage(new_image_id);
1401 return new_image_id; 1444 return new_image_id;
@@ -1426,7 +1469,7 @@ std::optional<typename TextureCache<P>::BlitImages> TextureCache<P>::GetBlitImag
1426 if (!copy.must_accelerate) { 1469 if (!copy.must_accelerate) {
1427 do { 1470 do {
1428 if (!src_id && !dst_id) { 1471 if (!src_id && !dst_id) {
1429 return std::nullopt; 1472 break;
1430 } 1473 }
1431 if (src_id && True(slot_images[src_id].flags & ImageFlagBits::GpuModified)) { 1474 if (src_id && True(slot_images[src_id].flags & ImageFlagBits::GpuModified)) {
1432 break; 1475 break;
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 758b7e212..0720494e5 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -179,6 +179,8 @@ public:
179 /// Download contents of host images to guest memory in a region 179 /// Download contents of host images to guest memory in a region
180 void DownloadMemory(VAddr cpu_addr, size_t size); 180 void DownloadMemory(VAddr cpu_addr, size_t size);
181 181
182 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(VAddr cpu_addr, u64 size);
183
182 /// Remove images in a region 184 /// Remove images in a region
183 void UnmapMemory(VAddr cpu_addr, size_t size); 185 void UnmapMemory(VAddr cpu_addr, size_t size);
184 186
@@ -205,7 +207,7 @@ public:
205 /// Pop asynchronous downloads 207 /// Pop asynchronous downloads
206 void PopAsyncFlushes(); 208 void PopAsyncFlushes();
207 209
208 [[nodiscard]] ImageId DmaImageId(const Tegra::DMA::ImageOperand& operand); 210 [[nodiscard]] ImageId DmaImageId(const Tegra::DMA::ImageOperand& operand, bool is_upload);
209 211
210 [[nodiscard]] std::pair<Image*, BufferImageCopy> DmaBufferImageCopy( 212 [[nodiscard]] std::pair<Image*, BufferImageCopy> DmaBufferImageCopy(
211 const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::BufferOperand& buffer_operand, 213 const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::BufferOperand& buffer_operand,
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index de37db684..f1071aa23 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -896,11 +896,11 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
896 ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width)); 896 ASSERT(copy.buffer_row_length == Common::AlignUp(mip_size.width, tile_size.width));
897 ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height)); 897 ASSERT(copy.buffer_image_height == Common::AlignUp(mip_size.height, tile_size.height));
898 if (IsPixelFormatASTC(info.format)) { 898 if (IsPixelFormatASTC(info.format)) {
899 ASSERT(copy.image_extent.depth == 1); 899 Tegra::Texture::ASTC::Decompress(
900 Tegra::Texture::ASTC::Decompress(input.subspan(copy.buffer_offset), 900 input.subspan(copy.buffer_offset), copy.image_extent.width,
901 copy.image_extent.width, copy.image_extent.height, 901 copy.image_extent.height,
902 copy.image_subresource.num_layers, tile_size.width, 902 copy.image_subresource.num_layers * copy.image_extent.depth, tile_size.width,
903 tile_size.height, output.subspan(output_offset)); 903 tile_size.height, output.subspan(output_offset));
904 } else { 904 } else {
905 DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent, 905 DecompressBC4(input.subspan(copy.buffer_offset), copy.image_extent,
906 output.subspan(output_offset)); 906 output.subspan(output_offset));
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 6ffca2af2..161f050b8 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1009,6 +1009,8 @@ void Device::CollectPhysicalMemoryInfo() {
1009 device_access_memory += mem_properties.memoryHeaps[element].size; 1009 device_access_memory += mem_properties.memoryHeaps[element].size;
1010 } 1010 }
1011 if (!is_integrated) { 1011 if (!is_integrated) {
1012 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
1013 device_access_memory -= reserve_memory;
1012 return; 1014 return;
1013 } 1015 }
1014 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage); 1016 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 7d5018151..5f1c63ff9 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -10,6 +10,7 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/settings.h"
13#include "video_core/vulkan_common/vulkan_wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
14 15
15// Define all features which may be used by the implementation here. 16// Define all features which may be used by the implementation here.
@@ -510,7 +511,7 @@ public:
510 511
511 /// Returns true when a known debugging tool is attached. 512 /// Returns true when a known debugging tool is attached.
512 bool HasDebuggingToolAttached() const { 513 bool HasDebuggingToolAttached() const {
513 return has_renderdoc || has_nsight_graphics; 514 return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue();
514 } 515 }
515 516
516 /// Returns true when the device does not properly support cube compatibility. 517 /// Returns true when the device does not properly support cube compatibility.
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 1732866e0..e28a556f8 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -147,7 +147,7 @@ public:
147 147
148 /// Returns whether this allocation is compatible with the arguments. 148 /// Returns whether this allocation is compatible with the arguments.
149 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { 149 [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const {
150 return (flags & property_flags) == property_flags && (type_mask & shifted_memory_type) != 0; 150 return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0;
151 } 151 }
152 152
153private: 153private:
diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp
index 4559df5b1..4988fcc83 100644
--- a/src/yuzu/applets/qt_amiibo_settings.cpp
+++ b/src/yuzu/applets/qt_amiibo_settings.cpp
@@ -8,7 +8,7 @@
8 8
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/string_util.h" 10#include "common/string_util.h"
11#include "core/hle/service/nfp/nfp_device.h" 11#include "core/hle/service/nfc/common/device.h"
12#include "core/hle/service/nfp/nfp_result.h" 12#include "core/hle/service/nfp/nfp_result.h"
13#include "input_common/drivers/virtual_amiibo.h" 13#include "input_common/drivers/virtual_amiibo.h"
14#include "input_common/main.h" 14#include "input_common/main.h"
@@ -22,7 +22,7 @@
22QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent, 22QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent,
23 Core::Frontend::CabinetParameters parameters_, 23 Core::Frontend::CabinetParameters parameters_,
24 InputCommon::InputSubsystem* input_subsystem_, 24 InputCommon::InputSubsystem* input_subsystem_,
25 std::shared_ptr<Service::NFP::NfpDevice> nfp_device_) 25 std::shared_ptr<Service::NFC::NfcDevice> nfp_device_)
26 : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()), 26 : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()),
27 input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)}, 27 input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)},
28 parameters(std::move(parameters_)) { 28 parameters(std::move(parameters_)) {
@@ -52,11 +52,11 @@ void QtAmiiboSettingsDialog::LoadInfo() {
52 return; 52 return;
53 } 53 }
54 54
55 if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && 55 if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
56 nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { 56 nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
57 return; 57 return;
58 } 58 }
59 nfp_device->Mount(Service::NFP::MountTarget::All); 59 nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
60 60
61 LoadAmiiboInfo(); 61 LoadAmiiboInfo();
62 LoadAmiiboData(); 62 LoadAmiiboData();
@@ -261,7 +261,7 @@ void QtAmiiboSettings::Close() const {
261void QtAmiiboSettings::ShowCabinetApplet( 261void QtAmiiboSettings::ShowCabinetApplet(
262 const Core::Frontend::CabinetCallback& callback_, 262 const Core::Frontend::CabinetCallback& callback_,
263 const Core::Frontend::CabinetParameters& parameters, 263 const Core::Frontend::CabinetParameters& parameters,
264 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { 264 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
265 callback = std::move(callback_); 265 callback = std::move(callback_);
266 emit MainWindowShowAmiiboSettings(parameters, nfp_device); 266 emit MainWindowShowAmiiboSettings(parameters, nfp_device);
267} 267}
diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h
index bc389a33f..ee66a0255 100644
--- a/src/yuzu/applets/qt_amiibo_settings.h
+++ b/src/yuzu/applets/qt_amiibo_settings.h
@@ -23,9 +23,9 @@ namespace Ui {
23class QtAmiiboSettingsDialog; 23class QtAmiiboSettingsDialog;
24} 24}
25 25
26namespace Service::NFP { 26namespace Service::NFC {
27class NfpDevice; 27class NfcDevice;
28} // namespace Service::NFP 28} // namespace Service::NFC
29 29
30class QtAmiiboSettingsDialog final : public QDialog { 30class QtAmiiboSettingsDialog final : public QDialog {
31 Q_OBJECT 31 Q_OBJECT
@@ -33,7 +33,7 @@ class QtAmiiboSettingsDialog final : public QDialog {
33public: 33public:
34 explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_, 34 explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_,
35 InputCommon::InputSubsystem* input_subsystem_, 35 InputCommon::InputSubsystem* input_subsystem_,
36 std::shared_ptr<Service::NFP::NfpDevice> nfp_device_); 36 std::shared_ptr<Service::NFC::NfcDevice> nfp_device_);
37 ~QtAmiiboSettingsDialog() override; 37 ~QtAmiiboSettingsDialog() override;
38 38
39 int exec() override; 39 int exec() override;
@@ -52,7 +52,7 @@ private:
52 std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui; 52 std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui;
53 53
54 InputCommon::InputSubsystem* input_subsystem; 54 InputCommon::InputSubsystem* input_subsystem;
55 std::shared_ptr<Service::NFP::NfpDevice> nfp_device; 55 std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
56 56
57 // Parameters sent in from the backend HLE applet. 57 // Parameters sent in from the backend HLE applet.
58 Core::Frontend::CabinetParameters parameters; 58 Core::Frontend::CabinetParameters parameters;
@@ -71,11 +71,11 @@ public:
71 void Close() const override; 71 void Close() const override;
72 void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_, 72 void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_,
73 const Core::Frontend::CabinetParameters& parameters, 73 const Core::Frontend::CabinetParameters& parameters,
74 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; 74 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
75 75
76signals: 76signals:
77 void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters, 77 void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters,
78 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const; 78 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const;
79 void MainWindowRequestExit() const; 79 void MainWindowRequestExit() const;
80 80
81private: 81private:
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp
index 2448e46b6..1f3f23038 100644
--- a/src/yuzu/applets/qt_profile_select.cpp
+++ b/src/yuzu/applets/qt_profile_select.cpp
@@ -95,6 +95,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(
95 scroll_area->setLayout(layout); 95 scroll_area->setLayout(layout);
96 96
97 connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser); 97 connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser);
98 connect(tree_view, &QTreeView::doubleClicked, this, &QtProfileSelectionDialog::accept);
98 connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, 99 connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
99 [this](Qt::Key key) { 100 [this](Qt::Key key) {
100 if (!this->isActiveWindow()) { 101 if (!this->isActiveWindow()) {
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 4276be82b..b7b9d4141 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -8,7 +8,6 @@
8#include <cstddef> 8#include <cstddef>
9#include <memory> 9#include <memory>
10#include <mutex> 10#include <mutex>
11#include <stop_token>
12#include <utility> 11#include <utility>
13#include <vector> 12#include <vector>
14 13
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index b52203ff1..70737c54e 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -443,6 +443,7 @@ void Config::ReadControlValues() {
443 ReadBasicSetting(Settings::values.mouse_panning_sensitivity); 443 ReadBasicSetting(Settings::values.mouse_panning_sensitivity);
444 ReadBasicSetting(Settings::values.enable_joycon_driver); 444 ReadBasicSetting(Settings::values.enable_joycon_driver);
445 ReadBasicSetting(Settings::values.enable_procon_driver); 445 ReadBasicSetting(Settings::values.enable_procon_driver);
446 ReadBasicSetting(Settings::values.random_amiibo_id);
446 447
447 ReadBasicSetting(Settings::values.tas_enable); 448 ReadBasicSetting(Settings::values.tas_enable);
448 ReadBasicSetting(Settings::values.tas_loop); 449 ReadBasicSetting(Settings::values.tas_loop);
@@ -710,6 +711,7 @@ void Config::ReadRendererValues() {
710 ReadGlobalSetting(Settings::values.nvdec_emulation); 711 ReadGlobalSetting(Settings::values.nvdec_emulation);
711 ReadGlobalSetting(Settings::values.accelerate_astc); 712 ReadGlobalSetting(Settings::values.accelerate_astc);
712 ReadGlobalSetting(Settings::values.async_astc); 713 ReadGlobalSetting(Settings::values.async_astc);
714 ReadGlobalSetting(Settings::values.use_reactive_flushing);
713 ReadGlobalSetting(Settings::values.shader_backend); 715 ReadGlobalSetting(Settings::values.shader_backend);
714 ReadGlobalSetting(Settings::values.use_asynchronous_shaders); 716 ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
715 ReadGlobalSetting(Settings::values.use_fast_gpu_time); 717 ReadGlobalSetting(Settings::values.use_fast_gpu_time);
@@ -1150,6 +1152,7 @@ void Config::SaveControlValues() {
1150 WriteBasicSetting(Settings::values.enable_raw_input); 1152 WriteBasicSetting(Settings::values.enable_raw_input);
1151 WriteBasicSetting(Settings::values.enable_joycon_driver); 1153 WriteBasicSetting(Settings::values.enable_joycon_driver);
1152 WriteBasicSetting(Settings::values.enable_procon_driver); 1154 WriteBasicSetting(Settings::values.enable_procon_driver);
1155 WriteBasicSetting(Settings::values.random_amiibo_id);
1153 WriteBasicSetting(Settings::values.keyboard_enabled); 1156 WriteBasicSetting(Settings::values.keyboard_enabled);
1154 WriteBasicSetting(Settings::values.emulate_analog_keyboard); 1157 WriteBasicSetting(Settings::values.emulate_analog_keyboard);
1155 WriteBasicSetting(Settings::values.mouse_panning_sensitivity); 1158 WriteBasicSetting(Settings::values.mouse_panning_sensitivity);
@@ -1356,6 +1359,7 @@ void Config::SaveRendererValues() {
1356 Settings::values.nvdec_emulation.UsingGlobal()); 1359 Settings::values.nvdec_emulation.UsingGlobal());
1357 WriteGlobalSetting(Settings::values.accelerate_astc); 1360 WriteGlobalSetting(Settings::values.accelerate_astc);
1358 WriteGlobalSetting(Settings::values.async_astc); 1361 WriteGlobalSetting(Settings::values.async_astc);
1362 WriteGlobalSetting(Settings::values.use_reactive_flushing);
1359 WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), 1363 WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()),
1360 static_cast<u32>(Settings::values.shader_backend.GetValue(global)), 1364 static_cast<u32>(Settings::values.shader_backend.GetValue(global)),
1361 static_cast<u32>(Settings::values.shader_backend.GetDefault()), 1365 static_cast<u32>(Settings::values.shader_backend.GetDefault()),
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 7a11db89b..1f3e489d0 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -23,6 +23,7 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
23 23
24void ConfigureGraphicsAdvanced::SetConfiguration() { 24void ConfigureGraphicsAdvanced::SetConfiguration() {
25 const bool runtime_lock = !system.IsPoweredOn(); 25 const bool runtime_lock = !system.IsPoweredOn();
26 ui->use_reactive_flushing->setEnabled(runtime_lock);
26 ui->async_present->setEnabled(runtime_lock); 27 ui->async_present->setEnabled(runtime_lock);
27 ui->renderer_force_max_clock->setEnabled(runtime_lock); 28 ui->renderer_force_max_clock->setEnabled(runtime_lock);
28 ui->async_astc->setEnabled(runtime_lock); 29 ui->async_astc->setEnabled(runtime_lock);
@@ -32,6 +33,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
32 33
33 ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); 34 ui->async_present->setChecked(Settings::values.async_presentation.GetValue());
34 ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); 35 ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue());
36 ui->use_reactive_flushing->setChecked(Settings::values.use_reactive_flushing.GetValue());
35 ui->async_astc->setChecked(Settings::values.async_astc.GetValue()); 37 ui->async_astc->setChecked(Settings::values.async_astc.GetValue());
36 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); 38 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
37 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); 39 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
@@ -65,6 +67,8 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
65 renderer_force_max_clock); 67 renderer_force_max_clock);
66 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, 68 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
67 ui->anisotropic_filtering_combobox); 69 ui->anisotropic_filtering_combobox);
70 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_reactive_flushing,
71 ui->use_reactive_flushing, use_reactive_flushing);
68 ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc, 72 ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc,
69 async_astc); 73 async_astc);
70 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, 74 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
@@ -99,6 +103,7 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
99 ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal()); 103 ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal());
100 ui->renderer_force_max_clock->setEnabled( 104 ui->renderer_force_max_clock->setEnabled(
101 Settings::values.renderer_force_max_clock.UsingGlobal()); 105 Settings::values.renderer_force_max_clock.UsingGlobal());
106 ui->use_reactive_flushing->setEnabled(Settings::values.use_reactive_flushing.UsingGlobal());
102 ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal()); 107 ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal());
103 ui->use_asynchronous_shaders->setEnabled( 108 ui->use_asynchronous_shaders->setEnabled(
104 Settings::values.use_asynchronous_shaders.UsingGlobal()); 109 Settings::values.use_asynchronous_shaders.UsingGlobal());
@@ -118,6 +123,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
118 ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock, 123 ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock,
119 Settings::values.renderer_force_max_clock, 124 Settings::values.renderer_force_max_clock,
120 renderer_force_max_clock); 125 renderer_force_max_clock);
126 ConfigurationShared::SetColoredTristate(
127 ui->use_reactive_flushing, Settings::values.use_reactive_flushing, use_reactive_flushing);
121 ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc, 128 ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc,
122 async_astc); 129 async_astc);
123 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, 130 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders,
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 2d8c7fd2d..1c7b636b9 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -42,6 +42,7 @@ private:
42 ConfigurationShared::CheckState renderer_force_max_clock; 42 ConfigurationShared::CheckState renderer_force_max_clock;
43 ConfigurationShared::CheckState use_vsync; 43 ConfigurationShared::CheckState use_vsync;
44 ConfigurationShared::CheckState async_astc; 44 ConfigurationShared::CheckState async_astc;
45 ConfigurationShared::CheckState use_reactive_flushing;
45 ConfigurationShared::CheckState use_asynchronous_shaders; 46 ConfigurationShared::CheckState use_asynchronous_shaders;
46 ConfigurationShared::CheckState use_fast_gpu_time; 47 ConfigurationShared::CheckState use_fast_gpu_time;
47 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; 48 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache;
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index a222d294b..9ef7c8e8f 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -97,6 +97,16 @@
97 </widget> 97 </widget>
98 </item> 98 </item>
99 <item> 99 <item>
100 <widget class="QCheckBox" name="use_reactive_flushing">
101 <property name="toolTip">
102 <string>Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.</string>
103 </property>
104 <property name="text">
105 <string>Enable Reactive Flushing</string>
106 </property>
107 </widget>
108 </item>
109 <item>
100 <widget class="QCheckBox" name="use_asynchronous_shaders"> 110 <widget class="QCheckBox" name="use_asynchronous_shaders">
101 <property name="toolTip"> 111 <property name="toolTip">
102 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string> 112 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 8d81322f3..f13156434 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -140,6 +140,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
140 Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked(); 140 Settings::values.enable_ir_sensor = ui->enable_ir_sensor->isChecked();
141 Settings::values.enable_joycon_driver = ui->enable_joycon_driver->isChecked(); 141 Settings::values.enable_joycon_driver = ui->enable_joycon_driver->isChecked();
142 Settings::values.enable_procon_driver = ui->enable_procon_driver->isChecked(); 142 Settings::values.enable_procon_driver = ui->enable_procon_driver->isChecked();
143 Settings::values.random_amiibo_id = ui->random_amiibo_id->isChecked();
143} 144}
144 145
145void ConfigureInputAdvanced::LoadConfiguration() { 146void ConfigureInputAdvanced::LoadConfiguration() {
@@ -176,6 +177,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
176 ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue()); 177 ui->enable_ir_sensor->setChecked(Settings::values.enable_ir_sensor.GetValue());
177 ui->enable_joycon_driver->setChecked(Settings::values.enable_joycon_driver.GetValue()); 178 ui->enable_joycon_driver->setChecked(Settings::values.enable_joycon_driver.GetValue());
178 ui->enable_procon_driver->setChecked(Settings::values.enable_procon_driver.GetValue()); 179 ui->enable_procon_driver->setChecked(Settings::values.enable_procon_driver.GetValue());
180 ui->random_amiibo_id->setChecked(Settings::values.random_amiibo_id.GetValue());
179 181
180 UpdateUIEnabled(); 182 UpdateUIEnabled();
181} 183}
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
index 0eb2b34bc..2e8b13660 100644
--- a/src/yuzu/configuration/configure_input_advanced.ui
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -2728,6 +2728,22 @@
2728 </widget> 2728 </widget>
2729 </item> 2729 </item>
2730 <item row="7" column="0"> 2730 <item row="7" column="0">
2731 <widget class="QCheckBox" name="random_amiibo_id">
2732 <property name="toolTip">
2733 <string>Allows unlimited uses of the same Amiibo in games that would otherwise limit you to one use.</string>
2734 </property>
2735 <property name="minimumSize">
2736 <size>
2737 <width>0</width>
2738 <height>23</height>
2739 </size>
2740 </property>
2741 <property name="text">
2742 <string>Use random Amiibo ID</string>
2743 </property>
2744 </widget>
2745 </item>
2746 <item row="8" column="0">
2731 <widget class="QCheckBox" name="mouse_panning"> 2747 <widget class="QCheckBox" name="mouse_panning">
2732 <property name="minimumSize"> 2748 <property name="minimumSize">
2733 <size> 2749 <size>
@@ -2740,7 +2756,7 @@
2740 </property> 2756 </property>
2741 </widget> 2757 </widget>
2742 </item> 2758 </item>
2743 <item row="7" column="2"> 2759 <item row="8" column="2">
2744 <widget class="QSpinBox" name="mouse_panning_sensitivity"> 2760 <widget class="QSpinBox" name="mouse_panning_sensitivity">
2745 <property name="toolTip"> 2761 <property name="toolTip">
2746 <string>Mouse sensitivity</string> 2762 <string>Mouse sensitivity</string>
@@ -2762,14 +2778,14 @@
2762 </property> 2778 </property>
2763 </widget> 2779 </widget>
2764 </item> 2780 </item>
2765 <item row="8" column="0"> 2781 <item row="9" column="0">
2766 <widget class="QLabel" name="motion_touch"> 2782 <widget class="QLabel" name="motion_touch">
2767 <property name="text"> 2783 <property name="text">
2768 <string>Motion / Touch</string> 2784 <string>Motion / Touch</string>
2769 </property> 2785 </property>
2770 </widget> 2786 </widget>
2771 </item> 2787 </item>
2772 <item row="8" column="2"> 2788 <item row="9" column="2">
2773 <widget class="QPushButton" name="buttonMotionTouch"> 2789 <widget class="QPushButton" name="buttonMotionTouch">
2774 <property name="text"> 2790 <property name="text">
2775 <string>Configure</string> 2791 <string>Configure</string>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 561a08dc5..2c2e7e47b 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -479,6 +479,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
479 param.Set("threshold", new_threshold / 1000.0f); 479 param.Set("threshold", new_threshold / 1000.0f);
480 emulated_controller->SetMotionParam(motion_id, param); 480 emulated_controller->SetMotionParam(motion_id, param);
481 }); 481 });
482 context_menu.addAction(tr("Calibrate sensor"), [&] {
483 emulated_controller->StartMotionCalibration();
484 });
482 } 485 }
483 context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location)); 486 context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location));
484 }); 487 });
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index fe1ee2289..a188eef92 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -582,9 +582,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
582 using namespace Settings::NativeMotion; 582 using namespace Settings::NativeMotion;
583 p.setPen(colors.outline); 583 p.setPen(colors.outline);
584 p.setBrush(colors.transparent); 584 p.setBrush(colors.transparent);
585 Draw3dCube(p, center + QPointF(-180, -5), 585 Draw3dCube(p, center + QPointF(-180, 90),
586 motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f); 586 motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
587 Draw3dCube(p, center + QPointF(180, -5), 587 Draw3dCube(p, center + QPointF(180, 90),
588 motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f); 588 motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
589 } 589 }
590 590
@@ -2926,14 +2926,14 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di
2926void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler, 2926void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler,
2927 float size) { 2927 float size) {
2928 std::array<Common::Vec3f, 8> cube{ 2928 std::array<Common::Vec3f, 8> cube{
2929 Common::Vec3f{-1, -1, -1}, 2929 Common::Vec3f{-0.7f, -1, -0.5f},
2930 {-1, 1, -1}, 2930 {-0.7f, 1, -0.5f},
2931 {1, 1, -1}, 2931 {0.7f, 1, -0.5f},
2932 {1, -1, -1}, 2932 {0.7f, -1, -0.5f},
2933 {-1, -1, 1}, 2933 {-0.7f, -1, 0.5f},
2934 {-1, 1, 1}, 2934 {-0.7f, 1, 0.5f},
2935 {1, 1, 1}, 2935 {0.7f, 1, 0.5f},
2936 {1, -1, 1}, 2936 {0.7f, -1, 0.5f},
2937 }; 2937 };
2938 2938
2939 for (Common::Vec3f& point : cube) { 2939 for (Common::Vec3f& point : cube) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index ba9eece1d..d932e33a7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -571,8 +571,8 @@ void GMainWindow::RegisterMetaTypes() {
571 571
572 // Cabinet Applet 572 // Cabinet Applet
573 qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters"); 573 qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
574 qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>( 574 qRegisterMetaType<std::shared_ptr<Service::NFC::NfcDevice>>(
575 "std::shared_ptr<Service::NFP::NfpDevice>"); 575 "std::shared_ptr<Service::NFC::NfcDevice>");
576 576
577 // Controller Applet 577 // Controller Applet
578 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); 578 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
@@ -600,7 +600,7 @@ void GMainWindow::RegisterMetaTypes() {
600} 600}
601 601
602void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, 602void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
603 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) { 603 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) {
604 cabinet_applet = 604 cabinet_applet =
605 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); 605 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device);
606 SCOPE_EXIT({ 606 SCOPE_EXIT({
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 3bbc31ada..7b23f2a59 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -93,9 +93,9 @@ enum class SwkbdReplyType : u32;
93enum class WebExitReason : u32; 93enum class WebExitReason : u32;
94} // namespace Service::AM::Applets 94} // namespace Service::AM::Applets
95 95
96namespace Service::NFP { 96namespace Service::NFC {
97class NfpDevice; 97class NfcDevice;
98} // namespace Service::NFP 98} // namespace Service::NFC
99 99
100namespace Ui { 100namespace Ui {
101class MainWindow; 101class MainWindow;
@@ -188,7 +188,7 @@ public slots:
188 void OnExit(); 188 void OnExit();
189 void OnSaveConfig(); 189 void OnSaveConfig();
190 void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, 190 void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
191 std::shared_ptr<Service::NFP::NfpDevice> nfp_device); 191 std::shared_ptr<Service::NFC::NfcDevice> nfp_device);
192 void AmiiboSettingsRequestExit(); 192 void AmiiboSettingsRequestExit();
193 void ControllerSelectorReconfigureControllers( 193 void ControllerSelectorReconfigureControllers(
194 const Core::Frontend::ControllerParameters& parameters); 194 const Core::Frontend::ControllerParameters& parameters);
diff --git a/src/yuzu/qt_common.cpp b/src/yuzu/qt_common.cpp
index 5ac9fe310..5d0fd7674 100644
--- a/src/yuzu/qt_common.cpp
+++ b/src/yuzu/qt_common.cpp
@@ -8,7 +8,7 @@
8#include "core/frontend/emu_window.h" 8#include "core/frontend/emu_window.h"
9#include "yuzu/qt_common.h" 9#include "yuzu/qt_common.h"
10 10
11#ifdef __linux__ 11#if !defined(WIN32) && !defined(__APPLE__)
12#include <qpa/qplatformnativeinterface.h> 12#include <qpa/qplatformnativeinterface.h>
13#endif 13#endif
14 14
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index a6418e693..dc9a3d68f 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -169,6 +169,7 @@ void Config::ReadValues() {
169 ReadSetting("ControlsGeneral", Settings::values.enable_raw_input); 169 ReadSetting("ControlsGeneral", Settings::values.enable_raw_input);
170 ReadSetting("ControlsGeneral", Settings::values.enable_joycon_driver); 170 ReadSetting("ControlsGeneral", Settings::values.enable_joycon_driver);
171 ReadSetting("ControlsGeneral", Settings::values.enable_procon_driver); 171 ReadSetting("ControlsGeneral", Settings::values.enable_procon_driver);
172 ReadSetting("ControlsGeneral", Settings::values.random_amiibo_id);
172 ReadSetting("ControlsGeneral", Settings::values.emulate_analog_keyboard); 173 ReadSetting("ControlsGeneral", Settings::values.emulate_analog_keyboard);
173 ReadSetting("ControlsGeneral", Settings::values.vibration_enabled); 174 ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
174 ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations); 175 ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
@@ -312,6 +313,7 @@ void Config::ReadValues() {
312 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); 313 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
313 ReadSetting("Renderer", Settings::values.vsync_mode); 314 ReadSetting("Renderer", Settings::values.vsync_mode);
314 ReadSetting("Renderer", Settings::values.shader_backend); 315 ReadSetting("Renderer", Settings::values.shader_backend);
316 ReadSetting("Renderer", Settings::values.use_reactive_flushing);
315 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); 317 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
316 ReadSetting("Renderer", Settings::values.nvdec_emulation); 318 ReadSetting("Renderer", Settings::values.nvdec_emulation);
317 ReadSetting("Renderer", Settings::values.accelerate_astc); 319 ReadSetting("Renderer", Settings::values.accelerate_astc);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 086ed4cfa..5e7c3ac04 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -340,6 +340,10 @@ use_vsync =
340# 0: GLSL, 1 (default): GLASM, 2: SPIR-V 340# 0: GLSL, 1 (default): GLASM, 2: SPIR-V
341shader_backend = 341shader_backend =
342 342
343# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.
344# 0: Off, 1 (default): On
345use_reactive_flushing =
346
343# Whether to allow asynchronous shader building. 347# Whether to allow asynchronous shader building.
344# 0 (default): Off, 1: On 348# 0 (default): Off, 1: On
345use_asynchronous_shaders = 349use_asynchronous_shaders =