summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.lgtm.yml13
-rw-r--r--dist/languages/ca.ts4
-rw-r--r--dist/languages/cs.ts2
-rw-r--r--dist/languages/da.ts4
-rw-r--r--dist/languages/de.ts4
-rw-r--r--dist/languages/el.ts4
-rw-r--r--dist/languages/es.ts94
-rw-r--r--dist/languages/fr.ts28
-rw-r--r--dist/languages/id.ts4
-rw-r--r--dist/languages/it.ts14
-rw-r--r--dist/languages/ja_JP.ts4
-rw-r--r--dist/languages/ko_KR.ts4
-rw-r--r--dist/languages/nb.ts4
-rw-r--r--dist/languages/nl.ts1916
-rw-r--r--dist/languages/pl.ts4
-rw-r--r--dist/languages/pt_BR.ts4
-rw-r--r--dist/languages/pt_PT.ts4
-rw-r--r--dist/languages/ru_RU.ts175
-rw-r--r--dist/languages/sv.ts70
-rw-r--r--dist/languages/tr_TR.ts4
-rw-r--r--dist/languages/uk.ts4
-rw-r--r--dist/languages/zh_CN.ts4
-rw-r--r--dist/languages/zh_TW.ts4
m---------externals/dynarmic0
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/audio_core/renderer/system.cpp5
-rw-r--r--src/audio_core/sink/sdl2_sink.cpp11
-rw-r--r--src/common/address_space.inc4
-rw-r--r--src/common/input.h2
-rw-r--r--src/common/intrusive_list.h631
-rw-r--r--src/common/settings.cpp10
-rw-r--r--src/common/settings.h16
-rw-r--r--src/common/vector_math.h14
-rw-r--r--src/core/CMakeLists.txt21
-rw-r--r--src/core/core.cpp11
-rw-r--r--src/core/core.h2
-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.cpp45
-rw-r--r--src/core/hid/emulated_controller.h9
-rw-r--r--src/core/hid/input_converter.cpp10
-rw-r--r--src/core/hid/motion_input.cpp57
-rw-r--r--src/core/hid/motion_input.h13
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp7
-rw-r--r--src/core/hle/kernel/k_auto_object.h4
-rw-r--r--src/core/hle/kernel/k_event_info.h5
-rw-r--r--src/core/hle/kernel/k_object_name.h8
-rw-r--r--src/core/hle/kernel/k_server_port.h4
-rw-r--r--src/core/hle/kernel/k_server_session.h7
-rw-r--r--src/core/hle/kernel/k_session_request.h4
-rw-r--r--src/core/hle/kernel/k_shared_memory_info.h4
-rw-r--r--src/core/hle/kernel/k_thread.h13
-rw-r--r--src/core/hle/kernel/kernel.cpp31
-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/hid/controllers/npad.cpp4
-rw-r--r--src/core/hle/service/ipc_helpers.h1
-rw-r--r--src/core/hle/service/kernel_helpers.cpp3
-rw-r--r--src/core/hle/service/mutex.cpp3
-rw-r--r--src/core/hle/service/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)672
-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/server_manager.cpp6
-rw-r--r--src/core/hle/service/service.h20
-rw-r--r--src/core/hle/service/sm/sm.cpp3
-rw-r--r--src/core/hle/service/sm/sm_controller.cpp3
-rw-r--r--src/core/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/core/telemetry_session.cpp17
-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.h7
-rw-r--r--src/input_common/helpers/joycon_protocol/nfc.cpp24
-rw-r--r--src/input_common/input_mapping.cpp3
-rw-r--r--src/input_common/input_poller.cpp3
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp3
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp3
-rw-r--r--src/tests/CMakeLists.txt2
-rw-r--r--src/tests/video_core/buffer_base.cpp549
-rw-r--r--src/tests/video_core/memory_tracker.cpp549
-rw-r--r--src/video_core/CMakeLists.txt7
-rw-r--r--src/video_core/buffer_cache/buffer_base.h527
-rw-r--r--src/video_core/buffer_cache/buffer_cache.cpp4
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h1007
-rw-r--r--src/video_core/buffer_cache/buffer_cache_base.h579
-rw-r--r--src/video_core/buffer_cache/memory_tracker_base.h299
-rw-r--r--src/video_core/buffer_cache/word_manager.h485
-rw-r--r--src/video_core/compatible_formats.cpp20
-rw-r--r--src/video_core/engines/maxwell_dma.cpp8
-rw-r--r--src/video_core/fence_manager.h148
-rw-r--r--src/video_core/gpu.cpp19
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/memory_manager.cpp13
-rw-r--r--src/video_core/memory_manager.h4
-rw-r--r--src/video_core/query_cache.h139
-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_buffer_cache.h4
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache_base.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_fence_manager.h12
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_query_cache.h6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp27
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h1
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h1
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h3
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp3
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp53
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp224
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h34
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache_base.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h11
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.cpp457
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.h83
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp28
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h6
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp124
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h37
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h10
-rw-r--r--src/video_core/shader_cache.cpp4
-rw-r--r--src/video_core/shader_environment.cpp16
-rw-r--r--src/video_core/shader_environment.h6
-rw-r--r--src/video_core/surface.cpp5
-rw-r--r--src/video_core/surface.h12
-rw-r--r--src/video_core/texture_cache/format_lookup_table.cpp6
-rw-r--r--src/video_core/texture_cache/formatter.cpp22
-rw-r--r--src/video_core/texture_cache/formatter.h8
-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.cpp4
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h3
-rw-r--r--src/video_core/vulkan_common/vulkan_surface.cpp6
-rw-r--r--src/video_core/vulkan_common/vulkan_surface.h9
-rw-r--r--src/yuzu/CMakeLists.txt2
-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.cpp90
-rw-r--r--src/yuzu/bootmanager.h25
-rw-r--r--src/yuzu/configuration/config.cpp20
-rw-r--r--src/yuzu/configuration/configure_general.cpp9
-rw-r--r--src/yuzu/configuration/configure_general.h1
-rw-r--r--src/yuzu/configuration/configure_general.ui7
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp168
-rw-r--r--src/yuzu/configuration/configure_graphics.h23
-rw-r--r--src/yuzu/configuration/configure_graphics.ui40
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp27
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h3
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui35
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp14
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp91
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h5
-rw-r--r--src/yuzu/configuration/configure_system.cpp10
-rw-r--r--src/yuzu/configuration/configure_system.h1
-rw-r--r--src/yuzu/configuration/configure_system.ui7
-rw-r--r--src/yuzu/main.cpp39
-rw-r--r--src/yuzu/main.h9
-rw-r--r--src/yuzu/qt_common.cpp55
-rw-r--r--src/yuzu/qt_common.h15
-rw-r--r--src/yuzu_cmd/config.cpp19
-rw-r--r--src/yuzu_cmd/default_ini.h26
-rw-r--r--vcpkg.json2
208 files changed, 8725 insertions, 6191 deletions
diff --git a/.lgtm.yml b/.lgtm.yml
deleted file mode 100644
index 7cd3f9926..000000000
--- a/.lgtm.yml
+++ /dev/null
@@ -1,13 +0,0 @@
1# SPDX-FileCopyrightText: 2020 yuzu Emulator Project
2# SPDX-License-Identifier: GPL-2.0-or-later
3
4path_classifiers:
5 library: "externals"
6extraction:
7 cpp:
8 prepare:
9 packages:
10 - "libsdl2-dev"
11 - "qtmultimedia5-dev"
12 - "libtbb-dev"
13 - "libjack-jackd2-dev"
diff --git a/dist/languages/ca.ts b/dist/languages/ca.ts
index b4e77d029..6978a4536 100644
--- a/dist/languages/ca.ts
+++ b/dist/languages/ca.ts
@@ -1372,8 +1372,8 @@ This would ban both their forum username and their IP address.</source>
1372 </message> 1372 </message>
1373 <message> 1373 <message>
1374 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1374 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1375 <source>Extended memory layout (6GB DRAM)</source> 1375 <source>Extended memory layout (8GB DRAM)</source>
1376 <translation>Interfície de memòria ampliada (6GB DRAM)</translation> 1376 <translation type="unfinished"/>
1377 </message> 1377 </message>
1378 <message> 1378 <message>
1379 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1379 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/cs.ts b/dist/languages/cs.ts
index b1b12c019..c7f77b15d 100644
--- a/dist/languages/cs.ts
+++ b/dist/languages/cs.ts
@@ -1364,7 +1364,7 @@ Tato možnost zlepšuje rychlost díky závislosti na sémantice cmpxchg pro zaj
1364 </message> 1364 </message>
1365 <message> 1365 <message>
1366 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1366 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1367 <source>Extended memory layout (6GB DRAM)</source> 1367 <source>Extended memory layout (8GB DRAM)</source>
1368 <translation type="unfinished"/> 1368 <translation type="unfinished"/>
1369 </message> 1369 </message>
1370 <message> 1370 <message>
diff --git a/dist/languages/da.ts b/dist/languages/da.ts
index 7c43ff7df..4bb799f90 100644
--- a/dist/languages/da.ts
+++ b/dist/languages/da.ts
@@ -1380,8 +1380,8 @@ Dette vil bandlyse både vedkommendes forum-brugernavn og IP-adresse.</translati
1380 </message> 1380 </message>
1381 <message> 1381 <message>
1382 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1382 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1383 <source>Extended memory layout (6GB DRAM)</source> 1383 <source>Extended memory layout (8GB DRAM)</source>
1384 <translation>Udvidet hukommelsesopsætning (6GB DRAM)</translation> 1384 <translation type="unfinished"/>
1385 </message> 1385 </message>
1386 <message> 1386 <message>
1387 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1387 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/de.ts b/dist/languages/de.ts
index a455a3e78..47def0166 100644
--- a/dist/languages/de.ts
+++ b/dist/languages/de.ts
@@ -1360,8 +1360,8 @@ This would ban both their forum username and their IP address.</source>
1360 </message> 1360 </message>
1361 <message> 1361 <message>
1362 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1362 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1363 <source>Extended memory layout (6GB DRAM)</source> 1363 <source>Extended memory layout (8GB DRAM)</source>
1364 <translation>Erweitertes Speicherlayout (6GB DRAM)</translation> 1364 <translation type="unfinished"/>
1365 </message> 1365 </message>
1366 <message> 1366 <message>
1367 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1367 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/el.ts b/dist/languages/el.ts
index 023cf4825..19abc7939 100644
--- a/dist/languages/el.ts
+++ b/dist/languages/el.ts
@@ -1364,8 +1364,8 @@ This would ban both their forum username and their IP address.</source>
1364 </message> 1364 </message>
1365 <message> 1365 <message>
1366 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1366 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1367 <source>Extended memory layout (6GB DRAM)</source> 1367 <source>Extended memory layout (8GB DRAM)</source>
1368 <translation>Διάταξη εκτεταμένης μνήμης (6GB DRAM)</translation> 1368 <translation type="unfinished"/>
1369 </message> 1369 </message>
1370 <message> 1370 <message>
1371 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1371 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/es.ts b/dist/languages/es.ts
index fb5ade667..7c7f97397 100644
--- a/dist/languages/es.ts
+++ b/dist/languages/es.ts
@@ -381,17 +381,17 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
381 <message> 381 <message>
382 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/> 382 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/>
383 <source>Output Device:</source> 383 <source>Output Device:</source>
384 <translation type="unfinished"/> 384 <translation>Dispositivo de salida:</translation>
385 </message> 385 </message>
386 <message> 386 <message>
387 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/> 387 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/>
388 <source>Input Device:</source> 388 <source>Input Device:</source>
389 <translation type="unfinished"/> 389 <translation>Dispositivo de entrada:</translation>
390 </message> 390 </message>
391 <message> 391 <message>
392 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/> 392 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/>
393 <source>Sound Output Mode:</source> 393 <source>Sound Output Mode:</source>
394 <translation type="unfinished"/> 394 <translation>Método de salida de sonido:</translation>
395 </message> 395 </message>
396 <message> 396 <message>
397 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/> 397 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/>
@@ -1383,8 +1383,8 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
1383 </message> 1383 </message>
1384 <message> 1384 <message>
1385 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1385 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1386 <source>Extended memory layout (6GB DRAM)</source> 1386 <source>Extended memory layout (8GB DRAM)</source>
1387 <translation>Interfaz de memoria extendida (6GB DRAM)</translation> 1387 <translation>Interfaz de memoria extendida (8GB DRAM)</translation>
1388 </message> 1388 </message>
1389 <message> 1389 <message>
1390 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1390 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
@@ -1638,7 +1638,7 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
1638 <message> 1638 <message>
1639 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="463"/> 1639 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="463"/>
1640 <source>AMD FidelityFXâ„¢ï¸ Super Resolution</source> 1640 <source>AMD FidelityFXâ„¢ï¸ Super Resolution</source>
1641 <translation type="unfinished"/> 1641 <translation>AMD FidelityFXâ„¢ï¸ Super Resolution</translation>
1642 </message> 1642 </message>
1643 <message> 1643 <message>
1644 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="489"/> 1644 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="489"/>
@@ -1753,12 +1753,12 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
1753 <message> 1753 <message>
1754 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/> 1754 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
1755 <source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source> 1755 <source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source>
1756 <translation type="unfinished"/> 1756 <translation>Activa la decodificación de texturas asíncrona de ASTC, lo cuál podría reducir la duración de los parones. Esta función es experimental.</translation>
1757 </message> 1757 </message>
1758 <message> 1758 <message>
1759 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/> 1759 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/>
1760 <source>Decode ASTC textures asynchronously (Hack)</source> 1760 <source>Decode ASTC textures asynchronously (Hack)</source>
1761 <translation type="unfinished"/> 1761 <translation>Decodificar texturas ASTC de manera asíncrona (Hack)</translation>
1762 </message> 1762 </message>
1763 <message> 1763 <message>
1764 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/> 1764 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/>
@@ -2268,12 +2268,12 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
2268 <message> 2268 <message>
2269 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2710"/> 2269 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2710"/>
2270 <source>Enable direct JoyCon driver</source> 2270 <source>Enable direct JoyCon driver</source>
2271 <translation type="unfinished"/> 2271 <translation>Activar driver directo JoyCon</translation>
2272 </message> 2272 </message>
2273 <message> 2273 <message>
2274 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/> 2274 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/>
2275 <source>Enable direct Pro Controller driver [EXPERIMENTAL]</source> 2275 <source>Enable direct Pro Controller driver [EXPERIMENTAL]</source>
2276 <translation type="unfinished"/> 2276 <translation>Activar driver directo Pro Controller [EXPERIMENTAL]</translation>
2277 </message> 2277 </message>
2278 <message> 2278 <message>
2279 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/> 2279 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/>
@@ -2637,7 +2637,7 @@ Esto banearía su nombre del foro y su dirección IP.</translation>
2637 <message> 2637 <message>
2638 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="399"/> 2638 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="399"/>
2639 <source>Turbo button</source> 2639 <source>Turbo button</source>
2640 <translation type="unfinished"/> 2640 <translation>Botón Turbo</translation>
2641 </message> 2641 </message>
2642 <message> 2642 <message>
2643 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="407"/> 2643 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="407"/>
@@ -3339,7 +3339,7 @@ UUID: %2</translation>
3339 <message> 3339 <message>
3340 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="52"/> 3340 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="52"/>
3341 <source>Virtual Ring Sensor Parameters</source> 3341 <source>Virtual Ring Sensor Parameters</source>
3342 <translation type="unfinished"/> 3342 <translation>Parámetros del sensor Ring virtual</translation>
3343 </message> 3343 </message>
3344 <message> 3344 <message>
3345 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/> 3345 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/>
@@ -3361,29 +3361,29 @@ UUID: %2</translation>
3361 <message> 3361 <message>
3362 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="233"/> 3362 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="233"/>
3363 <source>Direct Joycon Driver</source> 3363 <source>Direct Joycon Driver</source>
3364 <translation type="unfinished"/> 3364 <translation>Driver directo del JoyCon</translation>
3365 </message> 3365 </message>
3366 <message> 3366 <message>
3367 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="293"/> 3367 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="293"/>
3368 <source>Enable Ring Input</source> 3368 <source>Enable Ring Input</source>
3369 <translation type="unfinished"/> 3369 <translation>Activar entrada del Ring</translation>
3370 </message> 3370 </message>
3371 <message> 3371 <message>
3372 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/> 3372 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/>
3373 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/> 3373 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/>
3374 <source>Enable</source> 3374 <source>Enable</source>
3375 <translation type="unfinished"/> 3375 <translation>Activar</translation>
3376 </message> 3376 </message>
3377 <message> 3377 <message>
3378 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/> 3378 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/>
3379 <source>Ring Sensor Value</source> 3379 <source>Ring Sensor Value</source>
3380 <translation type="unfinished"/> 3380 <translation>Valor del sensor Ring</translation>
3381 </message> 3381 </message>
3382 <message> 3382 <message>
3383 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="314"/> 3383 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="314"/>
3384 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="282"/> 3384 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="282"/>
3385 <source>Not connected</source> 3385 <source>Not connected</source>
3386 <translation type="unfinished"/> 3386 <translation>No conectado</translation>
3387 </message> 3387 </message>
3388 <message> 3388 <message>
3389 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="344"/> 3389 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="344"/>
@@ -3414,12 +3414,12 @@ UUID: %2</translation>
3414 <message> 3414 <message>
3415 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="279"/> 3415 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="279"/>
3416 <source>Error enabling ring input</source> 3416 <source>Error enabling ring input</source>
3417 <translation type="unfinished"/> 3417 <translation>Error al activar la entrada del Ring</translation>
3418 </message> 3418 </message>
3419 <message> 3419 <message>
3420 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="285"/> 3420 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="285"/>
3421 <source>Direct Joycon driver is not enabled</source> 3421 <source>Direct Joycon driver is not enabled</source>
3422 <translation type="unfinished"/> 3422 <translation>El driver directo JoyCon no está activo.</translation>
3423 </message> 3423 </message>
3424 <message> 3424 <message>
3425 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="290"/> 3425 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="290"/>
@@ -3429,17 +3429,17 @@ UUID: %2</translation>
3429 <message> 3429 <message>
3430 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="302"/> 3430 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="302"/>
3431 <source>The current mapped device doesn&apos;t support the ring controller</source> 3431 <source>The current mapped device doesn&apos;t support the ring controller</source>
3432 <translation type="unfinished"/> 3432 <translation>El dispositivo de entrada actual no soporta el control Ring.</translation>
3433 </message> 3433 </message>
3434 <message> 3434 <message>
3435 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="306"/> 3435 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="306"/>
3436 <source>The current mapped device doesn&apos;t have a ring attached</source> 3436 <source>The current mapped device doesn&apos;t have a ring attached</source>
3437 <translation type="unfinished"/> 3437 <translation>El dispositivo de entrada actual no tiene puesto el Ring</translation>
3438 </message> 3438 </message>
3439 <message> 3439 <message>
3440 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="310"/> 3440 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="310"/>
3441 <source>Unexpected driver result %1</source> 3441 <source>Unexpected driver result %1</source>
3442 <translation type="unfinished"/> 3442 <translation>Resultado inesperado del driver %1</translation>
3443 </message> 3443 </message>
3444 <message> 3444 <message>
3445 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="333"/> 3445 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="333"/>
@@ -4498,12 +4498,12 @@ Arrastra los puntos para cambiar de posición, o haz doble clic en las celdas de
4498 <message> 4498 <message>
4499 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="47"/> 4499 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="47"/>
4500 <source>Server Address</source> 4500 <source>Server Address</source>
4501 <translation type="unfinished"/> 4501 <translation>Dirección del Servidor</translation>
4502 </message> 4502 </message>
4503 <message> 4503 <message>
4504 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="54"/> 4504 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="54"/>
4505 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Server address of the host&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 4505 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Server address of the host&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
4506 <translation type="unfinished"/> 4506 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Dirección del servidor del anfitrión&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
4507 </message> 4507 </message>
4508 <message> 4508 <message>
4509 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="64"/> 4509 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="64"/>
@@ -4617,12 +4617,12 @@ Arrastra los puntos para cambiar de posición, o haz doble clic en las celdas de
4617 <message> 4617 <message>
4618 <location filename="../../src/yuzu/main.cpp" line="1230"/> 4618 <location filename="../../src/yuzu/main.cpp" line="1230"/>
4619 <source>Emulated mouse is enabled</source> 4619 <source>Emulated mouse is enabled</source>
4620 <translation type="unfinished"/> 4620 <translation>El ratón emulado está activado</translation>
4621 </message> 4621 </message>
4622 <message> 4622 <message>
4623 <location filename="../../src/yuzu/main.cpp" line="1231"/> 4623 <location filename="../../src/yuzu/main.cpp" line="1231"/>
4624 <source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source> 4624 <source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source>
4625 <translation type="unfinished"/> 4625 <translation>La entrada de un ratón real y la panoramización del ratón son incompatibles. Por favor, desactive el ratón emulado en la configuración avanzada de entrada para permitir así la panoramización del ratón.</translation>
4626 </message> 4626 </message>
4627 <message> 4627 <message>
4628 <location filename="../../src/yuzu/main.cpp" line="1453"/> 4628 <location filename="../../src/yuzu/main.cpp" line="1453"/>
@@ -5489,13 +5489,13 @@ Por favor, utiliza esta función sólo para instalar actualizaciones y DLCs.</tr
5489 <message> 5489 <message>
5490 <location filename="../../src/yuzu/main.cpp" line="4069"/> 5490 <location filename="../../src/yuzu/main.cpp" line="4069"/>
5491 <source>VOLUME: MUTE</source> 5491 <source>VOLUME: MUTE</source>
5492 <translation type="unfinished"/> 5492 <translation>VOLUMEN: SILENCIO</translation>
5493 </message> 5493 </message>
5494 <message> 5494 <message>
5495 <location filename="../../src/yuzu/main.cpp" line="4072"/> 5495 <location filename="../../src/yuzu/main.cpp" line="4072"/>
5496 <source>VOLUME: %1%</source> 5496 <source>VOLUME: %1%</source>
5497 <comment>Volume percentage (e.g. 50%)</comment> 5497 <comment>Volume percentage (e.g. 50%)</comment>
5498 <translation type="unfinished"/> 5498 <translation>VOLUMEN: %1%</translation>
5499 </message> 5499 </message>
5500 <message> 5500 <message>
5501 <location filename="../../src/yuzu/main.cpp" line="4153"/> 5501 <location filename="../../src/yuzu/main.cpp" line="4153"/>
@@ -6227,7 +6227,7 @@ Mensaje de depuración: </translation>
6227 <message> 6227 <message>
6228 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="83"/> 6228 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="83"/>
6229 <source>Hide Empty Rooms</source> 6229 <source>Hide Empty Rooms</source>
6230 <translation type="unfinished"/> 6230 <translation>Ocultar salas vacías</translation>
6231 </message> 6231 </message>
6232 <message> 6232 <message>
6233 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="90"/> 6233 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="90"/>
@@ -7152,12 +7152,12 @@ p, li { white-space: pre-wrap; }
7152 <message> 7152 <message>
7153 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="78"/> 7153 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="78"/>
7154 <source>Stick L</source> 7154 <source>Stick L</source>
7155 <translation type="unfinished"/> 7155 <translation>Palanca L</translation>
7156 </message> 7156 </message>
7157 <message> 7157 <message>
7158 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="80"/> 7158 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="80"/>
7159 <source>Stick R</source> 7159 <source>Stick R</source>
7160 <translation type="unfinished"/> 7160 <translation>Palanca R</translation>
7161 </message> 7161 </message>
7162 <message> 7162 <message>
7163 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/> 7163 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
@@ -7214,19 +7214,19 @@ p, li { white-space: pre-wrap; }
7214 <message> 7214 <message>
7215 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="191"/> 7215 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="191"/>
7216 <source>%1%2%3%4</source> 7216 <source>%1%2%3%4</source>
7217 <translation type="unfinished"/> 7217 <translation>%1%2%3%4</translation>
7218 </message> 7218 </message>
7219 <message> 7219 <message>
7220 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="205"/> 7220 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="205"/>
7221 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="229"/> 7221 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="229"/>
7222 <source>%1%2%3Hat %4</source> 7222 <source>%1%2%3Hat %4</source>
7223 <translation type="unfinished"/> 7223 <translation>%1%2%3Rotación %4</translation>
7224 </message> 7224 </message>
7225 <message> 7225 <message>
7226 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="223"/> 7226 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="223"/>
7227 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="238"/> 7227 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="238"/>
7228 <source>%1%2%3Button %4</source> 7228 <source>%1%2%3Button %4</source>
7229 <translation type="unfinished"/> 7229 <translation>%1%2%3Botón %4</translation>
7230 </message> 7230 </message>
7231</context> 7231</context>
7232<context> 7232<context>
@@ -7647,7 +7647,7 @@ Por favor, inténtalo de nuevo o contacta con el desarrollador del software.</tr
7647 <message> 7647 <message>
7648 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/> 7648 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/>
7649 <source>Profile Creator</source> 7649 <source>Profile Creator</source>
7650 <translation type="unfinished"/> 7650 <translation>Creador de perfil</translation>
7651 </message> 7651 </message>
7652 <message> 7652 <message>
7653 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/> 7653 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/>
@@ -7658,57 +7658,57 @@ Por favor, inténtalo de nuevo o contacta con el desarrollador del software.</tr
7658 <message> 7658 <message>
7659 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/> 7659 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/>
7660 <source>Profile Icon Editor</source> 7660 <source>Profile Icon Editor</source>
7661 <translation type="unfinished"/> 7661 <translation>Editor de icono de perfil</translation>
7662 </message> 7662 </message>
7663 <message> 7663 <message>
7664 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/> 7664 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/>
7665 <source>Profile Nickname Editor</source> 7665 <source>Profile Nickname Editor</source>
7666 <translation type="unfinished"/> 7666 <translation>Editor de nombre de perfil</translation>
7667 </message> 7667 </message>
7668 <message> 7668 <message>
7669 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/> 7669 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/>
7670 <source>Who will receive the points?</source> 7670 <source>Who will receive the points?</source>
7671 <translation type="unfinished"/> 7671 <translation>¿Quién recibirá los puntos?</translation>
7672 </message> 7672 </message>
7673 <message> 7673 <message>
7674 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/> 7674 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/>
7675 <source>Who is using Nintendo eShop?</source> 7675 <source>Who is using Nintendo eShop?</source>
7676 <translation type="unfinished"/> 7676 <translation>¿Quién va a utilizar Nintendo eShop?</translation>
7677 </message> 7677 </message>
7678 <message> 7678 <message>
7679 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/> 7679 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/>
7680 <source>Who is making this purchase?</source> 7680 <source>Who is making this purchase?</source>
7681 <translation type="unfinished"/> 7681 <translation>¿Quién está haciendo la compra?</translation>
7682 </message> 7682 </message>
7683 <message> 7683 <message>
7684 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/> 7684 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/>
7685 <source>Who is posting?</source> 7685 <source>Who is posting?</source>
7686 <translation type="unfinished"/> 7686 <translation>¿Quién está publicando esto?</translation>
7687 </message> 7687 </message>
7688 <message> 7688 <message>
7689 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/> 7689 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/>
7690 <source>Select a user to link to a Nintendo Account.</source> 7690 <source>Select a user to link to a Nintendo Account.</source>
7691 <translation type="unfinished"/> 7691 <translation>Elige un usuario para vincularlo a una Cuenta Nintendo.</translation>
7692 </message> 7692 </message>
7693 <message> 7693 <message>
7694 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/> 7694 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/>
7695 <source>Change settings for which user?</source> 7695 <source>Change settings for which user?</source>
7696 <translation type="unfinished"/> 7696 <translation>¿Para qué usuario desea cambiar la configuración?</translation>
7697 </message> 7697 </message>
7698 <message> 7698 <message>
7699 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/> 7699 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/>
7700 <source>Format data for which user?</source> 7700 <source>Format data for which user?</source>
7701 <translation type="unfinished"/> 7701 <translation>¿Para qué usuario se borrarán sus datos?</translation>
7702 </message> 7702 </message>
7703 <message> 7703 <message>
7704 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/> 7704 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/>
7705 <source>Which user will be transferred to another console?</source> 7705 <source>Which user will be transferred to another console?</source>
7706 <translation type="unfinished"/> 7706 <translation>¿Qué usuario será transferido a otra consola?</translation>
7707 </message> 7707 </message>
7708 <message> 7708 <message>
7709 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/> 7709 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/>
7710 <source>Send save data for which user?</source> 7710 <source>Send save data for which user?</source>
7711 <translation type="unfinished"/> 7711 <translation>¿A qué usuario se le enviarán los datos de guardado?</translation>
7712 </message> 7712 </message>
7713 <message> 7713 <message>
7714 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/> 7714 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/>
@@ -7774,7 +7774,7 @@ p, li { white-space: pre-wrap; }
7774 <message> 7774 <message>
7775 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/> 7775 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/>
7776 <source>[%1] %2</source> 7776 <source>[%1] %2</source>
7777 <translation type="unfinished"/> 7777 <translation>[%1] %2</translation>
7778 </message> 7778 </message>
7779 <message> 7779 <message>
7780 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/> 7780 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/>
diff --git a/dist/languages/fr.ts b/dist/languages/fr.ts
index 7730208b7..606a8816e 100644
--- a/dist/languages/fr.ts
+++ b/dist/languages/fr.ts
@@ -1382,8 +1382,8 @@ Cette option améliore la vitesse en réduisant la précision des instructions f
1382 </message> 1382 </message>
1383 <message> 1383 <message>
1384 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1384 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1385 <source>Extended memory layout (6GB DRAM)</source> 1385 <source>Extended memory layout (8GB DRAM)</source>
1386 <translation>Disposition de la mémoire étendue (6GB DRAM)</translation> 1386 <translation>Disposition de la mémoire étendue (8 Go de DRAM)</translation>
1387 </message> 1387 </message>
1388 <message> 1388 <message>
1389 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1389 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
@@ -7637,7 +7637,7 @@ Veuillez essayer à nouveau ou contactez le développeur du logiciel.</translati
7637 <message> 7637 <message>
7638 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/> 7638 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/>
7639 <source>Profile Creator</source> 7639 <source>Profile Creator</source>
7640 <translation type="unfinished"/> 7640 <translation>Créateur de profil</translation>
7641 </message> 7641 </message>
7642 <message> 7642 <message>
7643 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/> 7643 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/>
@@ -7648,57 +7648,57 @@ Veuillez essayer à nouveau ou contactez le développeur du logiciel.</translati
7648 <message> 7648 <message>
7649 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/> 7649 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/>
7650 <source>Profile Icon Editor</source> 7650 <source>Profile Icon Editor</source>
7651 <translation type="unfinished"/> 7651 <translation>Éditeur d&apos;icônes de profil</translation>
7652 </message> 7652 </message>
7653 <message> 7653 <message>
7654 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/> 7654 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/>
7655 <source>Profile Nickname Editor</source> 7655 <source>Profile Nickname Editor</source>
7656 <translation type="unfinished"/> 7656 <translation>Éditeur de surnom de profil</translation>
7657 </message> 7657 </message>
7658 <message> 7658 <message>
7659 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/> 7659 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/>
7660 <source>Who will receive the points?</source> 7660 <source>Who will receive the points?</source>
7661 <translation type="unfinished"/> 7661 <translation>Qui recevra les points ?</translation>
7662 </message> 7662 </message>
7663 <message> 7663 <message>
7664 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/> 7664 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/>
7665 <source>Who is using Nintendo eShop?</source> 7665 <source>Who is using Nintendo eShop?</source>
7666 <translation type="unfinished"/> 7666 <translation>Qui utilise le Nintendo eShop ?</translation>
7667 </message> 7667 </message>
7668 <message> 7668 <message>
7669 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/> 7669 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/>
7670 <source>Who is making this purchase?</source> 7670 <source>Who is making this purchase?</source>
7671 <translation type="unfinished"/> 7671 <translation>Qui effectue cet achat ?</translation>
7672 </message> 7672 </message>
7673 <message> 7673 <message>
7674 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/> 7674 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/>
7675 <source>Who is posting?</source> 7675 <source>Who is posting?</source>
7676 <translation type="unfinished"/> 7676 <translation>Qui publie ?</translation>
7677 </message> 7677 </message>
7678 <message> 7678 <message>
7679 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/> 7679 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/>
7680 <source>Select a user to link to a Nintendo Account.</source> 7680 <source>Select a user to link to a Nintendo Account.</source>
7681 <translation type="unfinished"/> 7681 <translation>Sélectionnez un utilisateur à associer à un compte Nintendo.</translation>
7682 </message> 7682 </message>
7683 <message> 7683 <message>
7684 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/> 7684 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/>
7685 <source>Change settings for which user?</source> 7685 <source>Change settings for which user?</source>
7686 <translation type="unfinished"/> 7686 <translation>Modifier les paramètres pour quel utilisateur ?</translation>
7687 </message> 7687 </message>
7688 <message> 7688 <message>
7689 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/> 7689 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/>
7690 <source>Format data for which user?</source> 7690 <source>Format data for which user?</source>
7691 <translation type="unfinished"/> 7691 <translation>Formater les données pour quel utilisateur ?</translation>
7692 </message> 7692 </message>
7693 <message> 7693 <message>
7694 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/> 7694 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/>
7695 <source>Which user will be transferred to another console?</source> 7695 <source>Which user will be transferred to another console?</source>
7696 <translation type="unfinished"/> 7696 <translation>Quel utilisateur sera transféré sur une autre console ?</translation>
7697 </message> 7697 </message>
7698 <message> 7698 <message>
7699 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/> 7699 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/>
7700 <source>Send save data for which user?</source> 7700 <source>Send save data for which user?</source>
7701 <translation type="unfinished"/> 7701 <translation>Envoyer les données de sauvegarde pour quel utilisateur ?</translation>
7702 </message> 7702 </message>
7703 <message> 7703 <message>
7704 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/> 7704 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/>
diff --git a/dist/languages/id.ts b/dist/languages/id.ts
index 15054a333..a6831d7e5 100644
--- a/dist/languages/id.ts
+++ b/dist/languages/id.ts
@@ -1339,8 +1339,8 @@ Memungkinkan berbagai macam optimasi IR.</translation>
1339 </message> 1339 </message>
1340 <message> 1340 <message>
1341 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1341 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1342 <source>Extended memory layout (6GB DRAM)</source> 1342 <source>Extended memory layout (8GB DRAM)</source>
1343 <translation>Tata letak memori yang diperluas (6GB DRAM)</translation> 1343 <translation type="unfinished"/>
1344 </message> 1344 </message>
1345 <message> 1345 <message>
1346 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1346 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/it.ts b/dist/languages/it.ts
index 688a071e7..8c76842b5 100644
--- a/dist/languages/it.ts
+++ b/dist/languages/it.ts
@@ -1368,8 +1368,8 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.</trans
1368 </message> 1368 </message>
1369 <message> 1369 <message>
1370 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1370 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1371 <source>Extended memory layout (6GB DRAM)</source> 1371 <source>Extended memory layout (8GB DRAM)</source>
1372 <translation>Layout di memoria esteso (6GB DRAM)</translation> 1372 <translation type="unfinished"/>
1373 </message> 1373 </message>
1374 <message> 1374 <message>
1375 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1375 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
@@ -1846,7 +1846,7 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.</trans
1846 <message> 1846 <message>
1847 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="52"/> 1847 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="52"/>
1848 <source>Restore Defaults</source> 1848 <source>Restore Defaults</source>
1849 <translation>Ripristina predefiniti</translation> 1849 <translation>Ripristina predefinite</translation>
1850 </message> 1850 </message>
1851 <message> 1851 <message>
1852 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/> 1852 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/>
@@ -1894,7 +1894,7 @@ Questo bannerà sia il suo nome utente del forum che il suo indirizzo IP.</trans
1894 <message> 1894 <message>
1895 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="343"/> 1895 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="343"/>
1896 <source>Restore Default</source> 1896 <source>Restore Default</source>
1897 <translation>Ripristina predefinito</translation> 1897 <translation>Ripristina predefinita</translation>
1898 </message> 1898 </message>
1899 <message> 1899 <message>
1900 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="344"/> 1900 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="344"/>
@@ -3886,7 +3886,7 @@ UUID: %2</translation>
3886 <message> 3886 <message>
3887 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="77"/> 3887 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="77"/>
3888 <source>Pause execution during loads</source> 3888 <source>Pause execution during loads</source>
3889 <translation type="unfinished"/> 3889 <translation>Metti in pausa l&apos;esecuzione durante i caricamenti</translation>
3890 </message> 3890 </message>
3891 <message> 3891 <message>
3892 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="91"/> 3892 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="91"/>
@@ -5352,7 +5352,7 @@ Configurazione &amp;gt; Web.</translation>
5352 <location filename="../../src/yuzu/main.cpp" line="3949"/> 5352 <location filename="../../src/yuzu/main.cpp" line="3949"/>
5353 <source>Scale: %1x</source> 5353 <source>Scale: %1x</source>
5354 <comment>%1 is the resolution scaling factor</comment> 5354 <comment>%1 is the resolution scaling factor</comment>
5355 <translation type="unfinished"/> 5355 <translation>Risoluzione: %1x</translation>
5356 </message> 5356 </message>
5357 <message> 5357 <message>
5358 <location filename="../../src/yuzu/main.cpp" line="3952"/> 5358 <location filename="../../src/yuzu/main.cpp" line="3952"/>
@@ -5601,7 +5601,7 @@ Desideri uscire comunque?</translation>
5601 <message> 5601 <message>
5602 <location filename="../../src/yuzu/bootmanager.cpp" line="992"/> 5602 <location filename="../../src/yuzu/bootmanager.cpp" line="992"/>
5603 <source>yuzu has not been compiled with OpenGL support.</source> 5603 <source>yuzu has not been compiled with OpenGL support.</source>
5604 <translation>yuzu non è stato compilato con il supporto OpenGL.</translation> 5604 <translation>yuzu è stato compilato senza il supporto a OpenGL.</translation>
5605 </message> 5605 </message>
5606 <message> 5606 <message>
5607 <location filename="../../src/yuzu/bootmanager.cpp" line="1016"/> 5607 <location filename="../../src/yuzu/bootmanager.cpp" line="1016"/>
diff --git a/dist/languages/ja_JP.ts b/dist/languages/ja_JP.ts
index 66c09d493..e61137ac7 100644
--- a/dist/languages/ja_JP.ts
+++ b/dist/languages/ja_JP.ts
@@ -1383,8 +1383,8 @@ This would ban both their forum username and their IP address.</source>
1383 </message> 1383 </message>
1384 <message> 1384 <message>
1385 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1385 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1386 <source>Extended memory layout (6GB DRAM)</source> 1386 <source>Extended memory layout (8GB DRAM)</source>
1387 <translation>拡張メモリレイアウト(6GB DRAM)</translation> 1387 <translation type="unfinished"/>
1388 </message> 1388 </message>
1389 <message> 1389 <message>
1390 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1390 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/ko_KR.ts b/dist/languages/ko_KR.ts
index bd5e8fa18..ed0a9334b 100644
--- a/dist/languages/ko_KR.ts
+++ b/dist/languages/ko_KR.ts
@@ -1384,8 +1384,8 @@ This would ban both their forum username and their IP address.</source>
1384 </message> 1384 </message>
1385 <message> 1385 <message>
1386 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1386 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1387 <source>Extended memory layout (6GB DRAM)</source> 1387 <source>Extended memory layout (8GB DRAM)</source>
1388 <translation>확장 메모리 ë ˆì´ì•„웃(6GB DRAM)</translation> 1388 <translation type="unfinished"/>
1389 </message> 1389 </message>
1390 <message> 1390 <message>
1391 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1391 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/nb.ts b/dist/languages/nb.ts
index 5aec4a1cc..86cd4ea85 100644
--- a/dist/languages/nb.ts
+++ b/dist/languages/nb.ts
@@ -1355,8 +1355,8 @@ This would ban both their forum username and their IP address.</source>
1355 </message> 1355 </message>
1356 <message> 1356 <message>
1357 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1357 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1358 <source>Extended memory layout (6GB DRAM)</source> 1358 <source>Extended memory layout (8GB DRAM)</source>
1359 <translation>Utvidet minneutforming (6GB DRAM)</translation> 1359 <translation type="unfinished"/>
1360 </message> 1360 </message>
1361 <message> 1361 <message>
1362 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1362 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/nl.ts b/dist/languages/nl.ts
index 074742e39..7f7ba6da2 100644
--- a/dist/languages/nl.ts
+++ b/dist/languages/nl.ts
@@ -25,7 +25,13 @@ p, li { white-space: pre-wrap; }
25&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv3.0+.&lt;/span&gt;&lt;/p&gt; 25&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:12pt;&quot;&gt;yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv3.0+.&lt;/span&gt;&lt;/p&gt;
26&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt; 26&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
27&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 27&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;This software should not be used to play games you have not legally obtained.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
28 <translation type="unfinished"/> 28 <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
29&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
30p, li { white-space: pre-wrap; }
31&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
32&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;yuzu is een experimentele open-source emulator voor de Nintendo Switch met een licentie onder GPLv3.0+.&lt;/span&gt;&lt;/p&gt;
33&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
34&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:12pt;&quot;&gt;Deze software mag niet worden gebruikt om spellen te spelen die je niet legaal hebt verkregen.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
29 </message> 35 </message>
30 <message> 36 <message>
31 <location filename="../../src/yuzu/aboutdialog.ui" line="130"/> 37 <location filename="../../src/yuzu/aboutdialog.ui" line="130"/>
@@ -48,17 +54,17 @@ p, li { white-space: pre-wrap; }
48 <message> 54 <message>
49 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="24"/> 55 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="24"/>
50 <source>Cancel</source> 56 <source>Cancel</source>
51 <translation>Annuleren</translation> 57 <translation>Annuleer</translation>
52 </message> 58 </message>
53 <message> 59 <message>
54 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="43"/> 60 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="43"/>
55 <source>Touch the top left corner &lt;br&gt;of your touchpad.</source> 61 <source>Touch the top left corner &lt;br&gt;of your touchpad.</source>
56 <translation>Raak de linkerbovenhoek &lt;br&gt; van uw touchpad aan.</translation> 62 <translation>Raak de linkerbovenhoek &lt;br&gt; van je touchpad aan.</translation>
57 </message> 63 </message>
58 <message> 64 <message>
59 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="46"/> 65 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="46"/>
60 <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source> 66 <source>Now touch the bottom right corner &lt;br&gt;of your touchpad.</source>
61 <translation>klik nu op toets &lt;br&gt; op je toetsenbord</translation> 67 <translation>Raak nu de rechterbenedenhoek &lt;br&gt;van je touchpad aan.</translation>
62 </message> 68 </message>
63 <message> 69 <message>
64 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="49"/> 70 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="49"/>
@@ -76,17 +82,17 @@ p, li { white-space: pre-wrap; }
76 <message> 82 <message>
77 <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="14"/> 83 <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="14"/>
78 <source>Room Window</source> 84 <source>Room Window</source>
79 <translation type="unfinished"/> 85 <translation>Kamerraam</translation>
80 </message> 86 </message>
81 <message> 87 <message>
82 <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="40"/> 88 <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="40"/>
83 <source>Send Chat Message</source> 89 <source>Send Chat Message</source>
84 <translation>Stuur Chatbericht</translation> 90 <translation>Verzend Chatbericht</translation>
85 </message> 91 </message>
86 <message> 92 <message>
87 <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="47"/> 93 <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="47"/>
88 <source>Send Message</source> 94 <source>Send Message</source>
89 <translation>Stuur Bericht</translation> 95 <translation>Verzend Bericht</translation>
90 </message> 96 </message>
91 <message> 97 <message>
92 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="181"/> 98 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="181"/>
@@ -106,7 +112,7 @@ p, li { white-space: pre-wrap; }
106 <message> 112 <message>
107 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="324"/> 113 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="324"/>
108 <source>%1 has been kicked</source> 114 <source>%1 has been kicked</source>
109 <translation>%1 is verwijderd</translation> 115 <translation>%1 is kicked</translation>
110 </message> 116 </message>
111 <message> 117 <message>
112 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="327"/> 118 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="327"/>
@@ -116,55 +122,57 @@ p, li { white-space: pre-wrap; }
116 <message> 122 <message>
117 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="330"/> 123 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="330"/>
118 <source>%1 has been unbanned</source> 124 <source>%1 has been unbanned</source>
119 <translation>%1&apos;s ban is ongedaan gemaakt</translation> 125 <translation>Ban van %1 is ongedaan gemaakt</translation>
120 </message> 126 </message>
121 <message> 127 <message>
122 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="446"/> 128 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="446"/>
123 <source>View Profile</source> 129 <source>View Profile</source>
124 <translation>Profiel Bekijken</translation> 130 <translation>Bekijk Profiel</translation>
125 </message> 131 </message>
126 <message> 132 <message>
127 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="459"/> 133 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="459"/>
128 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="469"/> 134 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="469"/>
129 <source>Block Player</source> 135 <source>Block Player</source>
130 <translation>Speler Blokkeren</translation> 136 <translation>Blokkeer Speler</translation>
131 </message> 137 </message>
132 <message> 138 <message>
133 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="470"/> 139 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="470"/>
134 <source>When you block a player, you will no longer receive chat messages from them.&lt;br&gt;&lt;br&gt;Are you sure you would like to block %1?</source> 140 <source>When you block a player, you will no longer receive chat messages from them.&lt;br&gt;&lt;br&gt;Are you sure you would like to block %1?</source>
135 <translation type="unfinished"/> 141 <translation>Als je een speler blokkeert, ontvang je geen chatberichten meer van ze.&lt;br&gt;&lt;br&gt;Weet je zeker dat je %1 wilt blokkeren?</translation>
136 </message> 142 </message>
137 <message> 143 <message>
138 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="483"/> 144 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="483"/>
139 <source>Kick</source> 145 <source>Kick</source>
140 <translation>Verwijderen</translation> 146 <translation>Kick</translation>
141 </message> 147 </message>
142 <message> 148 <message>
143 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="484"/> 149 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="484"/>
144 <source>Ban</source> 150 <source>Ban</source>
145 <translation>Verwijderen</translation> 151 <translation>Ban</translation>
146 </message> 152 </message>
147 <message> 153 <message>
148 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="488"/> 154 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="488"/>
149 <source>Kick Player</source> 155 <source>Kick Player</source>
150 <translation>Speler verwijderen</translation> 156 <translation>Kick Speler</translation>
151 </message> 157 </message>
152 <message> 158 <message>
153 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="489"/> 159 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="489"/>
154 <source>Are you sure you would like to &lt;b&gt;kick&lt;/b&gt; %1?</source> 160 <source>Are you sure you would like to &lt;b&gt;kick&lt;/b&gt; %1?</source>
155 <translation>Weet je zeker dat je %1 wil &lt;b&gt;verwijderen&lt;/b&gt;?</translation> 161 <translation>Weet je zeker dat je %1 wil &lt;b&gt;kicken&lt;/b&gt;?</translation>
156 </message> 162 </message>
157 <message> 163 <message>
158 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="497"/> 164 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="497"/>
159 <source>Ban Player</source> 165 <source>Ban Player</source>
160 <translation>Speler Verbannen</translation> 166 <translation>Ban Speler</translation>
161 </message> 167 </message>
162 <message> 168 <message>
163 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="498"/> 169 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="498"/>
164 <source>Are you sure you would like to &lt;b&gt;kick and ban&lt;/b&gt; %1? 170 <source>Are you sure you would like to &lt;b&gt;kick and ban&lt;/b&gt; %1?
165 171
166This would ban both their forum username and their IP address.</source> 172This would ban both their forum username and their IP address.</source>
167 <translation type="unfinished"/> 173 <translation>Weet je zeker dat je %1 wilt &lt;b&gt;kicken en bannen&lt;/b&gt;?
174
175Dit zou zowel hun forum gebruikersnaam als hun IP-adres verbannen.</translation>
168 </message> 176 </message>
169</context> 177</context>
170<context> 178<context>
@@ -172,12 +180,12 @@ This would ban both their forum username and their IP address.</source>
172 <message> 180 <message>
173 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="14"/> 181 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="14"/>
174 <source>Room Window</source> 182 <source>Room Window</source>
175 <translation type="unfinished"/> 183 <translation>Kamervenster</translation>
176 </message> 184 </message>
177 <message> 185 <message>
178 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="27"/> 186 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="27"/>
179 <source>Room Description</source> 187 <source>Room Description</source>
180 <translation>Kamer Beschrijving</translation> 188 <translation>Kamerbeschrijving</translation>
181 </message> 189 </message>
182 <message> 190 <message>
183 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="47"/> 191 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="47"/>
@@ -187,7 +195,7 @@ This would ban both their forum username and their IP address.</source>
187 <message> 195 <message>
188 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="57"/> 196 <location filename="../../src/yuzu/multiplayer/client_room.ui" line="57"/>
189 <source>Leave Room</source> 197 <source>Leave Room</source>
190 <translation type="unfinished"/> 198 <translation>Verlaat Kamer</translation>
191 </message> 199 </message>
192</context> 200</context>
193<context> 201<context>
@@ -200,12 +208,12 @@ This would ban both their forum username and their IP address.</source>
200 <message> 208 <message>
201 <location filename="../../src/yuzu/multiplayer/client_room.cpp" line="87"/> 209 <location filename="../../src/yuzu/multiplayer/client_room.cpp" line="87"/>
202 <source>Disconnected</source> 210 <source>Disconnected</source>
203 <translation type="unfinished"/> 211 <translation>Verbinding verbroken</translation>
204 </message> 212 </message>
205 <message> 213 <message>
206 <location filename="../../src/yuzu/multiplayer/client_room.cpp" line="100"/> 214 <location filename="../../src/yuzu/multiplayer/client_room.cpp" line="100"/>
207 <source>%1 - %2 (%3/%4 members) - connected</source> 215 <source>%1 - %2 (%3/%4 members) - connected</source>
208 <translation type="unfinished"/> 216 <translation>%1 - %2 (%3/%4 leden) - verbonden</translation>
209 </message> 217 </message>
210</context> 218</context>
211<context> 219<context>
@@ -224,112 +232,112 @@ This would ban both their forum username and their IP address.</source>
224 <location filename="../../src/yuzu/compatdb.ui" line="271"/> 232 <location filename="../../src/yuzu/compatdb.ui" line="271"/>
225 <location filename="../../src/yuzu/compatdb.ui" line="330"/> 233 <location filename="../../src/yuzu/compatdb.ui" line="330"/>
226 <source>Report Game Compatibility</source> 234 <source>Report Game Compatibility</source>
227 <translation>Rapporteer Game Compatibiliteit</translation> 235 <translation>Rapporteer Spelcompatibiliteit</translation>
228 </message> 236 </message>
229 <message> 237 <message>
230 <location filename="../../src/yuzu/compatdb.ui" line="36"/> 238 <location filename="../../src/yuzu/compatdb.ui" line="36"/>
231 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source> 239 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Should you choose to submit a test case to the &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu Compatibility List&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, The following information will be collected and displayed on the site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Information (CPU / GPU / Operating System)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Which version of yuzu you are running&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The connected yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</source>
232 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Als je kiest een test case op te sturen naar de &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu compatibiliteitslijst&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, zal de volgende informatie worden verzameld en getoond op de site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware Informatie (CPU / GPU / Besturingssysteem)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Welke versie van yuzu je draait&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Het verbonden yuzu account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation> 240 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Als je kiest een test case op te sturen naar de &lt;/span&gt;&lt;a href=&quot;https://yuzu-emu.org/game/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;yuzu-compatibiliteitslijst&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, zal de volgende informatie worden verzameld en getoond op de site:&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Hardware-informatie (CPU / GPU / Besturingssysteem)&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Welke versie van yuzu je draait&lt;/li&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Het verbonden yuzu-account&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</translation>
233 </message> 241 </message>
234 <message> 242 <message>
235 <location filename="../../src/yuzu/compatdb.ui" line="77"/> 243 <location filename="../../src/yuzu/compatdb.ui" line="77"/>
236 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game boot?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 244 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game boot?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
237 <translation type="unfinished"/> 245 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Start het spel op?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
238 </message> 246 </message>
239 <message> 247 <message>
240 <location filename="../../src/yuzu/compatdb.ui" line="100"/> 248 <location filename="../../src/yuzu/compatdb.ui" line="100"/>
241 <source>Yes The game starts to output video or audio</source> 249 <source>Yes The game starts to output video or audio</source>
242 <translation type="unfinished"/> 250 <translation>Ja Het spel begint video of audio te produceren</translation>
243 </message> 251 </message>
244 <message> 252 <message>
245 <location filename="../../src/yuzu/compatdb.ui" line="107"/> 253 <location filename="../../src/yuzu/compatdb.ui" line="107"/>
246 <source>No The game doesn&apos;t get past the &quot;Launching...&quot; screen</source> 254 <source>No The game doesn&apos;t get past the &quot;Launching...&quot; screen</source>
247 <translation type="unfinished"/> 255 <translation>Nee Het spel komt niet voorbij het &quot;Starten...&quot; scherm</translation>
248 </message> 256 </message>
249 <message> 257 <message>
250 <location filename="../../src/yuzu/compatdb.ui" line="124"/> 258 <location filename="../../src/yuzu/compatdb.ui" line="124"/>
251 <source>Yes The game gets past the intro/menu and into gameplay</source> 259 <source>Yes The game gets past the intro/menu and into gameplay</source>
252 <translation type="unfinished"/> 260 <translation>Ja Het spel komt voorbij het intro/menu en begint met het spel</translation>
253 </message> 261 </message>
254 <message> 262 <message>
255 <location filename="../../src/yuzu/compatdb.ui" line="131"/> 263 <location filename="../../src/yuzu/compatdb.ui" line="131"/>
256 <source>No The game crashes or freezes while loading or using the menu</source> 264 <source>No The game crashes or freezes while loading or using the menu</source>
257 <translation type="unfinished"/> 265 <translation>Nee Het spel loopt vast tijdens het laden of gebruik van het menu</translation>
258 </message> 266 </message>
259 <message> 267 <message>
260 <location filename="../../src/yuzu/compatdb.ui" line="143"/> 268 <location filename="../../src/yuzu/compatdb.ui" line="143"/>
261 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game reach gameplay?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 269 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game reach gameplay?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
262 <translation type="unfinished"/> 270 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Bereikt het spel de gameplay?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
263 </message> 271 </message>
264 <message> 272 <message>
265 <location filename="../../src/yuzu/compatdb.ui" line="176"/> 273 <location filename="../../src/yuzu/compatdb.ui" line="176"/>
266 <source>Yes The game works without crashes</source> 274 <source>Yes The game works without crashes</source>
267 <translation type="unfinished"/> 275 <translation>Ja Het spel werkt zonder crashes</translation>
268 </message> 276 </message>
269 <message> 277 <message>
270 <location filename="../../src/yuzu/compatdb.ui" line="183"/> 278 <location filename="../../src/yuzu/compatdb.ui" line="183"/>
271 <source>No The game crashes or freezes during gameplay</source> 279 <source>No The game crashes or freezes during gameplay</source>
272 <translation type="unfinished"/> 280 <translation>Nee Het spel loopt vast of loopt vast tijdens het spelen</translation>
273 </message> 281 </message>
274 <message> 282 <message>
275 <location filename="../../src/yuzu/compatdb.ui" line="195"/> 283 <location filename="../../src/yuzu/compatdb.ui" line="195"/>
276 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game work without crashing, freezing or locking up during gameplay?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 284 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game work without crashing, freezing or locking up during gameplay?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
277 <translation type="unfinished"/> 285 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Werkt het spel zonder te crashen, te bevriezen of vast te lopen tijdens het spelen?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
278 </message> 286 </message>
279 <message> 287 <message>
280 <location filename="../../src/yuzu/compatdb.ui" line="228"/> 288 <location filename="../../src/yuzu/compatdb.ui" line="228"/>
281 <source>Yes The game can be finished without any workarounds</source> 289 <source>Yes The game can be finished without any workarounds</source>
282 <translation type="unfinished"/> 290 <translation>Ja Het spel kan zonder omwegen worden uitgespeeld</translation>
283 </message> 291 </message>
284 <message> 292 <message>
285 <location filename="../../src/yuzu/compatdb.ui" line="235"/> 293 <location filename="../../src/yuzu/compatdb.ui" line="235"/>
286 <source>No The game can&apos;t progress past a certain area</source> 294 <source>No The game can&apos;t progress past a certain area</source>
287 <translation type="unfinished"/> 295 <translation>Nee Het spel kan niet verder dan een bepaald gebied</translation>
288 </message> 296 </message>
289 <message> 297 <message>
290 <location filename="../../src/yuzu/compatdb.ui" line="247"/> 298 <location filename="../../src/yuzu/compatdb.ui" line="247"/>
291 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Is the game completely playable from start to finish?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 299 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Is the game completely playable from start to finish?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
292 <translation type="unfinished"/> 300 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Is het spel volledig speelbaar van begin tot eind?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
293 </message> 301 </message>
294 <message> 302 <message>
295 <location filename="../../src/yuzu/compatdb.ui" line="280"/> 303 <location filename="../../src/yuzu/compatdb.ui" line="280"/>
296 <source>Major The game has major graphical errors</source> 304 <source>Major The game has major graphical errors</source>
297 <translation type="unfinished"/> 305 <translation>Major Het spel heeft aanzienlijke grafische fouten</translation>
298 </message> 306 </message>
299 <message> 307 <message>
300 <location filename="../../src/yuzu/compatdb.ui" line="287"/> 308 <location filename="../../src/yuzu/compatdb.ui" line="287"/>
301 <source>Minor The game has minor graphical errors</source> 309 <source>Minor The game has minor graphical errors</source>
302 <translation type="unfinished"/> 310 <translation>Minor Het spel heeft lichte grafische fouten</translation>
303 </message> 311 </message>
304 <message> 312 <message>
305 <location filename="../../src/yuzu/compatdb.ui" line="294"/> 313 <location filename="../../src/yuzu/compatdb.ui" line="294"/>
306 <source>None Everything is rendered as it looks on the Nintendo Switch</source> 314 <source>None Everything is rendered as it looks on the Nintendo Switch</source>
307 <translation type="unfinished"/> 315 <translation>Geen Alles wordt weergegeven zoals het eruit ziet op de Nintendo Switch</translation>
308 </message> 316 </message>
309 <message> 317 <message>
310 <location filename="../../src/yuzu/compatdb.ui" line="306"/> 318 <location filename="../../src/yuzu/compatdb.ui" line="306"/>
311 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game have any graphical glitches?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 319 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game have any graphical glitches?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
312 <translation type="unfinished"/> 320 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Heeft het spel grafische glitches?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
313 </message> 321 </message>
314 <message> 322 <message>
315 <location filename="../../src/yuzu/compatdb.ui" line="339"/> 323 <location filename="../../src/yuzu/compatdb.ui" line="339"/>
316 <source>Major The game has major audio errors</source> 324 <source>Major The game has major audio errors</source>
317 <translation type="unfinished"/> 325 <translation>Major Het spel heeft aanzienlijke audiofouten</translation>
318 </message> 326 </message>
319 <message> 327 <message>
320 <location filename="../../src/yuzu/compatdb.ui" line="346"/> 328 <location filename="../../src/yuzu/compatdb.ui" line="346"/>
321 <source>Minor The game has minor audio errors</source> 329 <source>Minor The game has minor audio errors</source>
322 <translation type="unfinished"/> 330 <translation>Minor Het spel heeft lichte audiofouten</translation>
323 </message> 331 </message>
324 <message> 332 <message>
325 <location filename="../../src/yuzu/compatdb.ui" line="353"/> 333 <location filename="../../src/yuzu/compatdb.ui" line="353"/>
326 <source>None Audio is played perfectly</source> 334 <source>None Audio is played perfectly</source>
327 <translation type="unfinished"/> 335 <translation>Geen Audio wordt perfect afgespeeld</translation>
328 </message> 336 </message>
329 <message> 337 <message>
330 <location filename="../../src/yuzu/compatdb.ui" line="365"/> 338 <location filename="../../src/yuzu/compatdb.ui" line="365"/>
331 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game have any audio glitches / missing effects?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 339 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game have any audio glitches / missing effects?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
332 <translation type="unfinished"/> 340 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Heeft het spel audio-glitches / ontbrekende effecten?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
333 </message> 341 </message>
334 <message> 342 <message>
335 <location filename="../../src/yuzu/compatdb.ui" line="389"/> 343 <location filename="../../src/yuzu/compatdb.ui" line="389"/>
@@ -363,27 +371,27 @@ This would ban both their forum username and their IP address.</source>
363 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="14"/> 371 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="14"/>
364 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="20"/> 372 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="20"/>
365 <source>Audio</source> 373 <source>Audio</source>
366 <translation>Geluid</translation> 374 <translation>Audio</translation>
367 </message> 375 </message>
368 <message> 376 <message>
369 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="28"/> 377 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="28"/>
370 <source>Output Engine:</source> 378 <source>Output Engine:</source>
371 <translation>Output Engine:</translation> 379 <translation>Uitvoer-engine:</translation>
372 </message> 380 </message>
373 <message> 381 <message>
374 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/> 382 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/>
375 <source>Output Device:</source> 383 <source>Output Device:</source>
376 <translation type="unfinished"/> 384 <translation>Uitvoerapparaat:</translation>
377 </message> 385 </message>
378 <message> 386 <message>
379 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/> 387 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/>
380 <source>Input Device:</source> 388 <source>Input Device:</source>
381 <translation type="unfinished"/> 389 <translation>Invoerapparaat:</translation>
382 </message> 390 </message>
383 <message> 391 <message>
384 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/> 392 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/>
385 <source>Sound Output Mode:</source> 393 <source>Sound Output Mode:</source>
386 <translation type="unfinished"/> 394 <translation>Geluidsuitvoermodus:</translation>
387 </message> 395 </message>
388 <message> 396 <message>
389 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/> 397 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/>
@@ -408,7 +416,7 @@ This would ban both their forum username and their IP address.</source>
408 <message> 416 <message>
409 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="119"/> 417 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="119"/>
410 <source>Set volume:</source> 418 <source>Set volume:</source>
411 <translation>stel volume in:</translation> 419 <translation>Stel volume in:</translation>
412 </message> 420 </message>
413 <message> 421 <message>
414 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="127"/> 422 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="127"/>
@@ -423,7 +431,7 @@ This would ban both their forum username and their IP address.</source>
423 <message> 431 <message>
424 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="187"/> 432 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="187"/>
425 <source>Mute audio when in background</source> 433 <source>Mute audio when in background</source>
426 <translation type="unfinished"/> 434 <translation>Demp audio op de achtergrond</translation>
427 </message> 435 </message>
428 <message> 436 <message>
429 <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="115"/> 437 <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="115"/>
@@ -437,37 +445,37 @@ This would ban both their forum username and their IP address.</source>
437 <message> 445 <message>
438 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="14"/> 446 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="14"/>
439 <source>Configure Infrared Camera</source> 447 <source>Configure Infrared Camera</source>
440 <translation type="unfinished"/> 448 <translation>Configureer Infraroodcamera</translation>
441 </message> 449 </message>
442 <message> 450 <message>
443 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="26"/> 451 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="26"/>
444 <source>Select where the image of the emulated camera comes from. It may be a virtual camera or a real camera.</source> 452 <source>Select where the image of the emulated camera comes from. It may be a virtual camera or a real camera.</source>
445 <translation type="unfinished"/> 453 <translation>Selecteer waar het beeld van de geëmuleerde camera vandaan komt. Het kan een virtuele camera of een echte camera zijn.</translation>
446 </message> 454 </message>
447 <message> 455 <message>
448 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="52"/> 456 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="52"/>
449 <source>Camera Image Source:</source> 457 <source>Camera Image Source:</source>
450 <translation type="unfinished"/> 458 <translation>Camera Beeldbron:</translation>
451 </message> 459 </message>
452 <message> 460 <message>
453 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="71"/> 461 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="71"/>
454 <source>Input device:</source> 462 <source>Input device:</source>
455 <translation type="unfinished"/> 463 <translation>Invoerapparaat:</translation>
456 </message> 464 </message>
457 <message> 465 <message>
458 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="96"/> 466 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="96"/>
459 <source>Preview</source> 467 <source>Preview</source>
460 <translation type="unfinished"/> 468 <translation>Preview</translation>
461 </message> 469 </message>
462 <message> 470 <message>
463 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="108"/> 471 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="108"/>
464 <source>Resolution: 320*240</source> 472 <source>Resolution: 320*240</source>
465 <translation type="unfinished"/> 473 <translation>Resolutie: 320*240</translation>
466 </message> 474 </message>
467 <message> 475 <message>
468 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="115"/> 476 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="115"/>
469 <source>Click to preview</source> 477 <source>Click to preview</source>
470 <translation type="unfinished"/> 478 <translation>Klik om een preview te zien</translation>
471 </message> 479 </message>
472 <message> 480 <message>
473 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="140"/> 481 <location filename="../../src/yuzu/configuration/configure_camera.ui" line="140"/>
@@ -500,7 +508,7 @@ This would ban both their forum username and their IP address.</source>
500 <message> 508 <message>
501 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="34"/> 509 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="34"/>
502 <source>Accuracy:</source> 510 <source>Accuracy:</source>
503 <translation>Accuratie:</translation> 511 <translation>Nauwkeurigheid:</translation>
504 </message> 512 </message>
505 <message> 513 <message>
506 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="42"/> 514 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="42"/>
@@ -520,7 +528,7 @@ This would ban both their forum username and their IP address.</source>
520 <message> 528 <message>
521 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="57"/> 529 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="57"/>
522 <source>Paranoid (disables most optimizations)</source> 530 <source>Paranoid (disables most optimizations)</source>
523 <translation type="unfinished"/> 531 <translation>Paranoid (schakelt de meeste optimalisaties uit)</translation>
524 </message> 532 </message>
525 <message> 533 <message>
526 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="68"/> 534 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="68"/>
@@ -530,7 +538,7 @@ This would ban both their forum username and their IP address.</source>
530 <message> 538 <message>
531 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="85"/> 539 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="85"/>
532 <source>Unsafe CPU Optimization Settings</source> 540 <source>Unsafe CPU Optimization Settings</source>
533 <translation>Onveilige CPU optimalisatie instellingen</translation> 541 <translation>Onveilige CPU-optimalisatie-instellingen</translation>
534 </message> 542 </message>
535 <message> 543 <message>
536 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/> 544 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/>
@@ -543,8 +551,7 @@ This would ban both their forum username and their IP address.</source>
543 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt; 551 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
544 </source> 552 </source>
545 <translation> 553 <translation>
546&lt;div&gt;Deze optie verbeterd de prestatie door de accuratie van fused-multiply-add instructies te verminderen op CPU&apos;s zonder native FMA support.&lt;/div&gt; 554&lt;div&gt;Deze optie verbeterd de prestatie door de accuratie van fused-multiply-add-instructies te verminderen op CPU&apos;s zonder native FMA support.&lt;/div&gt;</translation>
547</translation>
548 </message> 555 </message>
549 <message> 556 <message>
550 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/> 557 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
@@ -570,13 +577,12 @@ This would ban both their forum username and their IP address.</source>
570 &lt;div&gt;This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.&lt;/div&gt; 577 &lt;div&gt;This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.&lt;/div&gt;
571 </source> 578 </source>
572 <translation> 579 <translation>
573&lt;div&gt;Deze optie verbetert de snelheid of 32-bit ASIMD floating-point functies door incorrecte afronding modellen te gebruiken.&lt;/div&gt; 580&lt;div&gt;Deze optie verbetert de snelheid of 32-bit ASIMD floating-point functies door incorrecte afronding modellen te gebruiken.&lt;/div&gt;</translation>
574</translation>
575 </message> 581 </message>
576 <message> 582 <message>
577 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="130"/> 583 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="130"/>
578 <source>Faster ASIMD instructions (32 bits only)</source> 584 <source>Faster ASIMD instructions (32 bits only)</source>
579 <translation type="unfinished"/> 585 <translation>Snellere ASIMD-instructies (alleen 32-bits)</translation>
580 </message> 586 </message>
581 <message> 587 <message>
582 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="137"/> 588 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="137"/>
@@ -589,36 +595,38 @@ This would ban both their forum username and their IP address.</source>
589 <message> 595 <message>
590 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="142"/> 596 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="142"/>
591 <source>Inaccurate NaN handling</source> 597 <source>Inaccurate NaN handling</source>
592 <translation>Onnauwkeurige verwerking van NaN</translation> 598 <translation>Onnauwkeurige NaN-verwerking</translation>
593 </message> 599 </message>
594 <message> 600 <message>
595 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="149"/> 601 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="149"/>
596 <source> 602 <source>
597 &lt;div&gt;This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.&lt;/div&gt; 603 &lt;div&gt;This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.&lt;/div&gt;
598 </source> 604 </source>
599 <translation type="unfinished"/> 605 <translation>
606&lt;div&gt;Deze optie verbetert de snelheid door het elimineren van een veiligheidscontrole voor elk geheugen lezen/schrijven in de gast. Door deze optie uit te schakelen kan een spel het geheugen van de emulator lezen/schrijven.&lt;/div&gt;</translation>
600 </message> 607 </message>
601 <message> 608 <message>
602 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="154"/> 609 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="154"/>
603 <source>Disable address space checks</source> 610 <source>Disable address space checks</source>
604 <translation type="unfinished"/> 611 <translation>Schakel adresruimtecontroles uit</translation>
605 </message> 612 </message>
606 <message> 613 <message>
607 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="161"/> 614 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="161"/>
608 <source> 615 <source>
609 &lt;div&gt;This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.&lt;/div&gt; 616 &lt;div&gt;This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.&lt;/div&gt;
610 </source> 617 </source>
611 <translation type="unfinished"/> 618 <translation>
619&lt;div&gt;Deze optie verbetert de snelheid door alleen de semantiek van cmpxchg te gebruiken om de veiligheid van exclusieve toegangsinstructies te garanderen. Dit kan resulteren in deadlocks en andere &quot;race conditions&quot;.&lt;/div&gt;</translation>
612 </message> 620 </message>
613 <message> 621 <message>
614 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="166"/> 622 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="166"/>
615 <source>Ignore global monitor</source> 623 <source>Ignore global monitor</source>
616 <translation type="unfinished"/> 624 <translation>Negeer globale monitor</translation>
617 </message> 625 </message>
618 <message> 626 <message>
619 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="191"/> 627 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="191"/>
620 <source>CPU settings are available only when game is not running.</source> 628 <source>CPU settings are available only when game is not running.</source>
621 <translation>CPU settings zijn alleen toegankelijk als er geen spel draait</translation> 629 <translation>CPU-instellingen zijn alleen toegankelijk als er geen spel draait.</translation>
622 </message> 630 </message>
623</context> 631</context>
624<context> 632<context>
@@ -626,13 +634,12 @@ This would ban both their forum username and their IP address.</source>
626 <message> 634 <message>
627 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/> 635 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/>
628 <source>Form</source> 636 <source>Form</source>
629 <translation>Formulier</translation> 637 <translation>Vorm</translation>
630 </message> 638 </message>
631 <message> 639 <message>
632 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="17"/> 640 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="17"/>
633 <source>CPU</source> 641 <source>CPU</source>
634 <translation>CPU 642 <translation>CPU</translation>
635</translation>
636 </message> 643 </message>
637 <message> 644 <message>
638 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="25"/> 645 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="25"/>
@@ -642,7 +649,7 @@ This would ban both their forum username and their IP address.</source>
642 <message> 649 <message>
643 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/> 650 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/>
644 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;For debugging only.&lt;/span&gt;&lt;br/&gt;If you&apos;re not sure what these do, keep all of these enabled. &lt;br/&gt;These settings, when disabled, only take effect when CPU Debugging is enabled. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 651 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;For debugging only.&lt;/span&gt;&lt;br/&gt;If you&apos;re not sure what these do, keep all of these enabled. &lt;br/&gt;These settings, when disabled, only take effect when CPU Debugging is enabled. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
645 <translation type="unfinished"/> 652 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Alleen voor debugging.&lt;/span&gt;&lt;br/&gt; Als u niet zeker weet wat deze doen, laat ze dan allemaal ingeschakeld. &lt;br/&gt;Deze instellingen, indien uitgeschakeld, hebben alleen effect wanneer CPU Debugging is ingeschakeld.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
646 </message> 653 </message>
647 <message> 654 <message>
648 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="41"/> 655 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="41"/>
@@ -652,14 +659,14 @@ This would ban both their forum username and their IP address.</source>
652 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt; 659 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
653 </source> 660 </source>
654 <translation> 661 <translation>
655&lt;div style=&quot;white-space: nowrap&quot;&gt;Deze optimazie versneld geheugen toegang door het gastprogramma.&lt;/div&gt; 662&lt;div style=&quot;white-space: nowrap&quot;&gt;Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.&lt;/div&gt;
656&lt;div style=&quot;white-space: nowrap&quot;&gt;Door dit aan te leggen geeft toegang tot PageTable::pointers in uitgezonden code.&lt;/div&gt; 663&lt;div style=&quot;white-space: nowrap&quot;&gt;Inschakelen zorgt ervoor dat exclusieve geheugenlees/schrijfacties van de gast rechtstreeks in het geheugen plaatsvinden en gebruik maken van de MMU van de host.&lt;/div&gt;
657&lt;div style=&quot;white-space: nowrap&quot;&gt;Door dit uit te leggen forceerd u alle geheugen toegang door Memory::Read/Memory::Write functies te gaan.&lt;/div&gt;</translation> 664&lt;div style=&quot;white-space: nowrap&quot;&gt;Uitschakelen forceert het gebruik van Software MMU-emulatie voor alle exclusieve geheugentoepassingen.&lt;/div&gt;</translation>
658 </message> 665 </message>
659 <message> 666 <message>
660 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="48"/> 667 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="48"/>
661 <source>Enable inline page tables</source> 668 <source>Enable inline page tables</source>
662 <translation>Schakel inlijne pagina tafles in</translation> 669 <translation>Schakel inline paginatabellen in</translation>
663 </message> 670 </message>
664 <message> 671 <message>
665 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="55"/> 672 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="55"/>
@@ -672,7 +679,7 @@ This would ban both their forum username and their IP address.</source>
672 <message> 679 <message>
673 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/> 680 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
674 <source>Enable block linking</source> 681 <source>Enable block linking</source>
675 <translation>Schakel block linking in</translation> 682 <translation>Schakel blocklinking in</translation>
676 </message> 683 </message>
677 <message> 684 <message>
678 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="67"/> 685 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="67"/>
@@ -680,13 +687,12 @@ This would ban both their forum username and their IP address.</source>
680 &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt; 687 &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
681 </source> 688 </source>
682 <translation> 689 <translation>
683&lt;div&gt;Deze optimalisatie vermijdt het opzoeken van dispatchers door potentiële retouradressen van BL-instructies bij te houden. Dit benadert wat er gebeurt met een retourstackbuffer op een echte CPU.&lt;/div&gt;</translation> 690&lt;div&gt;Deze optimalisatie vermijdt dispatcher lookups door potentiële terugkeeradressen van BL-instructies bij te houden. Dit benadert wat er gebeurt met een return stack buffer op een echte CPU.&lt;/div&gt;</translation>
684 </message> 691 </message>
685 <message> 692 <message>
686 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/> 693 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
687 <source>Enable return stack buffer</source> 694 <source>Enable return stack buffer</source>
688 <translation>Return-stackbuffer inschakelen 695 <translation>Schakel return-stackbuffer in</translation>
689 </translation>
690 </message> 696 </message>
691 <message> 697 <message>
692 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="79"/> 698 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="79"/>
@@ -699,7 +705,7 @@ This would ban both their forum username and their IP address.</source>
699 <message> 705 <message>
700 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/> 706 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
701 <source>Enable fast dispatcher</source> 707 <source>Enable fast dispatcher</source>
702 <translation>Shakel snelle dispatcher in</translation> 708 <translation>Schakel snelle dispatcher in</translation>
703 </message> 709 </message>
704 <message> 710 <message>
705 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="91"/> 711 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="91"/>
@@ -712,7 +718,7 @@ This would ban both their forum username and their IP address.</source>
712 <message> 718 <message>
713 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/> 719 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
714 <source>Enable context elimination</source> 720 <source>Enable context elimination</source>
715 <translation>Shakel context eliminatie in</translation> 721 <translation>Schakel context eliminatie in</translation>
716 </message> 722 </message>
717 <message> 723 <message>
718 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="103"/> 724 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="103"/>
@@ -725,7 +731,7 @@ This would ban both their forum username and their IP address.</source>
725 <message> 731 <message>
726 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/> 732 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
727 <source>Enable constant propagation</source> 733 <source>Enable constant propagation</source>
728 <translation>Constante verspreiding inschakelen</translation> 734 <translation>Schakel constante verspreiding in</translation>
729 </message> 735 </message>
730 <message> 736 <message>
731 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="115"/> 737 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="115"/>
@@ -738,7 +744,7 @@ This would ban both their forum username and their IP address.</source>
738 <message> 744 <message>
739 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/> 745 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
740 <source>Enable miscellaneous optimizations</source> 746 <source>Enable miscellaneous optimizations</source>
741 <translation>Diverse optimalisaties inschakelen</translation> 747 <translation>Schakel diverse optimalisaties in</translation>
742 </message> 748 </message>
743 <message> 749 <message>
744 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="127"/> 750 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="127"/>
@@ -753,7 +759,7 @@ This would ban both their forum username and their IP address.</source>
753 <message> 759 <message>
754 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="133"/> 760 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="133"/>
755 <source>Enable misalignment check reduction</source> 761 <source>Enable misalignment check reduction</source>
756 <translation>Schakel verkeerde uitlijning vermindering in</translation> 762 <translation>Schakel verkeerde uitlijningsvermindering in</translation>
757 </message> 763 </message>
758 <message> 764 <message>
759 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="140"/> 765 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="140"/>
@@ -763,14 +769,14 @@ This would ban both their forum username and their IP address.</source>
763 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt; 769 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt;
764 </source> 770 </source>
765 <translation> 771 <translation>
766&lt;div style=&quot;white-space: nowrap&quot;&gt;Deze optimazie versneld geheugen toegang door het gastprogramma.&lt;/div&gt; 772&lt;div style=&quot;white-space: nowrap&quot;&gt;Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.&lt;/div&gt;
767&lt;div style=&quot;white-space: nowrap&quot;&gt;Door dit aan te leggen geeft toegang tot PageTable::pointers in uitgezonden code.&lt;/div&gt; 773&lt;div style=&quot;white-space: nowrap&quot;&gt;Inschakelen zorgt ervoor dat geheugenlees/schrijfacties rechtstreeks in het geheugen plaatsvinden en gebruik maken van de MMU van de host.&lt;/div&gt;
768&lt;div style=&quot;white-space: nowrap&quot;&gt;Door dit uit te leggen forceerd u alle geheugen toegang door Memory::Read/Memory::Write functies te gaan.&lt;/div&gt;</translation> 774&lt;div style=&quot;white-space: nowrap&quot;&gt;Uitschakelen forceert het gebruik van Software MMU-emulatie voor alle exclusieve geheugentoepassingen.&lt;/div&gt;</translation>
769 </message> 775 </message>
770 <message> 776 <message>
771 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="147"/> 777 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="147"/>
772 <source>Enable Host MMU Emulation (general memory instructions)</source> 778 <source>Enable Host MMU Emulation (general memory instructions)</source>
773 <translation type="unfinished"/> 779 <translation>Schakel Host MMU-emulatie in (algemene geheugeninstructies)</translation>
774 </message> 780 </message>
775 <message> 781 <message>
776 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="154"/> 782 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="154"/>
@@ -779,12 +785,15 @@ This would ban both their forum username and their IP address.</source>
779 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt; 785 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt;
780 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all exclusive memory accesses to use Software MMU Emulation.&lt;/div&gt; 786 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all exclusive memory accesses to use Software MMU Emulation.&lt;/div&gt;
781 </source> 787 </source>
782 <translation type="unfinished"/> 788 <translation>
789&lt;div style=&quot;white-space: nowrap&quot;&gt;Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.&lt;/div&gt;
790&lt;div style=&quot;white-space: nowrap&quot;&gt;Inschakelen zorgt ervoor dat exclusieve geheugenlees/schrijfacties van de gast rechtstreeks in het geheugen plaatsvinden en gebruik maken van de MMU van de host.&lt;/div&gt;
791&lt;div style=&quot;white-space: nowrap&quot;&gt;Uitschakelen forceert het gebruik van Software MMU-emulatie voor alle exclusieve geheugentoepassingen.&lt;/div&gt;</translation>
783 </message> 792 </message>
784 <message> 793 <message>
785 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="161"/> 794 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="161"/>
786 <source>Enable Host MMU Emulation (exclusive memory instructions)</source> 795 <source>Enable Host MMU Emulation (exclusive memory instructions)</source>
787 <translation type="unfinished"/> 796 <translation>Schakel Host MMU-emulatie in (exclusieve geheugeninstructies)</translation>
788 </message> 797 </message>
789 <message> 798 <message>
790 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="168"/> 799 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="168"/>
@@ -792,12 +801,14 @@ This would ban both their forum username and their IP address.</source>
792 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up exclusive memory accesses by the guest program.&lt;/div&gt; 801 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up exclusive memory accesses by the guest program.&lt;/div&gt;
793 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.&lt;/div&gt; 802 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.&lt;/div&gt;
794 </source> 803 </source>
795 <translation type="unfinished"/> 804 <translation>
805&lt;div style=&quot;white-space: nowrap&quot;&gt;Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.&lt;/div&gt;
806&lt;div style=&quot;white-space: nowrap&quot;&gt;Het inschakelen ervan vermindert de overhead van fastmem falen van exclusieve geheugentoegang.&lt;/div&gt;</translation>
796 </message> 807 </message>
797 <message> 808 <message>
798 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="174"/> 809 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="174"/>
799 <source>Enable recompilation of exclusive memory instructions</source> 810 <source>Enable recompilation of exclusive memory instructions</source>
800 <translation type="unfinished"/> 811 <translation>Schakel hercompilatie van exclusieve geheugeninstructies in</translation>
801 </message> 812 </message>
802 <message> 813 <message>
803 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="181"/> 814 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="181"/>
@@ -805,12 +816,14 @@ This would ban both their forum username and their IP address.</source>
805 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.&lt;/div&gt; 816 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.&lt;/div&gt;
806 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.&lt;/div&gt; 817 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.&lt;/div&gt;
807 </source> 818 </source>
808 <translation type="unfinished"/> 819 <translation>
820&lt;div style=&quot;white-space: nowrap&quot;&gt;Deze optimalisering versnelt geheugentoepassingen door ongeldige geheugentoepassingen te laten slagen.&lt;/div&gt;
821&lt;div style=&quot;white-space: nowrap&quot;&gt;Het inschakelen ervan vermindert de overhead van alle geheugentoepassingen en heeft geen invloed op programma&apos;s die geen ongeldig geheugen gebruiken.&lt;/div&gt;</translation>
809 </message> 822 </message>
810 <message> 823 <message>
811 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="187"/> 824 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="187"/>
812 <source>Enable fallbacks for invalid memory accesses</source> 825 <source>Enable fallbacks for invalid memory accesses</source>
813 <translation type="unfinished"/> 826 <translation>Schakel fallbacks in voor ongeldige geheugentoegang</translation>
814 </message> 827 </message>
815 <message> 828 <message>
816 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="212"/> 829 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="212"/>
@@ -823,12 +836,12 @@ This would ban both their forum username and their IP address.</source>
823 <message> 836 <message>
824 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="15"/> 837 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="15"/>
825 <source>Debugger</source> 838 <source>Debugger</source>
826 <translation type="unfinished"/> 839 <translation>Debugger</translation>
827 </message> 840 </message>
828 <message> 841 <message>
829 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="23"/> 842 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="23"/>
830 <source>Enable GDB Stub</source> 843 <source>Enable GDB Stub</source>
831 <translation>GDB Stub Aanzetten</translation> 844 <translation>Schakel GDB Stub in</translation>
832 </message> 845 </message>
833 <message> 846 <message>
834 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="43"/> 847 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="43"/>
@@ -848,12 +861,12 @@ This would ban both their forum username and their IP address.</source>
848 <message> 861 <message>
849 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="87"/> 862 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="87"/>
850 <source>Show Log in Console</source> 863 <source>Show Log in Console</source>
851 <translation>Laat Log Venster Zien</translation> 864 <translation>Toon Login-console</translation>
852 </message> 865 </message>
853 <message> 866 <message>
854 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="94"/> 867 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="94"/>
855 <source>Open Log Location</source> 868 <source>Open Log Location</source>
856 <translation>Open Log Locatie</translation> 869 <translation>Open Loglocatie</translation>
857 </message> 870 </message>
858 <message> 871 <message>
859 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="104"/> 872 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="104"/>
@@ -863,7 +876,7 @@ This would ban both their forum username and their IP address.</source>
863 <message> 876 <message>
864 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="107"/> 877 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="107"/>
865 <source>Enable Extended Logging**</source> 878 <source>Enable Extended Logging**</source>
866 <translation>Activeer Uitgebreid Loggen**</translation> 879 <translation>Schakel Uitgebreid Loggen** in</translation>
867 </message> 880 </message>
868 <message> 881 <message>
869 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="117"/> 882 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="117"/>
@@ -873,7 +886,7 @@ This would ban both their forum username and their IP address.</source>
873 <message> 886 <message>
874 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="125"/> 887 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="125"/>
875 <source>Arguments String</source> 888 <source>Arguments String</source>
876 <translation>Argumenten Rij</translation> 889 <translation>Argumentenrij</translation>
877 </message> 890 </message>
878 <message> 891 <message>
879 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="140"/> 892 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="140"/>
@@ -888,42 +901,42 @@ This would ban both their forum username and their IP address.</source>
888 <message> 901 <message>
889 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="152"/> 902 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="152"/>
890 <source>Enable Graphics Debugging</source> 903 <source>Enable Graphics Debugging</source>
891 <translation>Grafische foutopsporing inschakelen</translation> 904 <translation>Schakel Graphics Foutopsporing in</translation>
892 </message> 905 </message>
893 <message> 906 <message>
894 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="159"/> 907 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="159"/>
895 <source>When checked, it enables Nsight Aftermath crash dumps</source> 908 <source>When checked, it enables Nsight Aftermath crash dumps</source>
896 <translation type="unfinished"/> 909 <translation>Indien aangevinkt schakelt het Nsight Aftermath crashdumps in</translation>
897 </message> 910 </message>
898 <message> 911 <message>
899 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="162"/> 912 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="162"/>
900 <source>Enable Nsight Aftermath</source> 913 <source>Enable Nsight Aftermath</source>
901 <translation type="unfinished"/> 914 <translation>Schakel Nsight Aftermath in</translation>
902 </message> 915 </message>
903 <message> 916 <message>
904 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="172"/> 917 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="172"/>
905 <source>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</source> 918 <source>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</source>
906 <translation type="unfinished"/> 919 <translation>Indien aangevinkt, zal het alle originele assembler shaders van de disk shader cache of het gevonden spel dumpen</translation>
907 </message> 920 </message>
908 <message> 921 <message>
909 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="175"/> 922 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="175"/>
910 <source>Dump Game Shaders</source> 923 <source>Dump Game Shaders</source>
911 <translation type="unfinished"/> 924 <translation>Dump Spel-shaders</translation>
912 </message> 925 </message>
913 <message> 926 <message>
914 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="185"/> 927 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="185"/>
915 <source>When checked, it will dump all the macro programs of the GPU</source> 928 <source>When checked, it will dump all the macro programs of the GPU</source>
916 <translation type="unfinished"/> 929 <translation>Indien aangevinkt, worden alle macroprogramma&apos;s van de GPU gedumpt</translation>
917 </message> 930 </message>
918 <message> 931 <message>
919 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/> 932 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/>
920 <source>Dump Maxwell Macros</source> 933 <source>Dump Maxwell Macros</source>
921 <translation type="unfinished"/> 934 <translation>Dump Maxwell-macro&apos;s</translation>
922 </message> 935 </message>
923 <message> 936 <message>
924 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="198"/> 937 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="198"/>
925 <source>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</source> 938 <source>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</source>
926 <translation>Indien aangevinkt, wordt de macro Just In Time-compiler uitgeschakeld. Als u dit inschakelt, worden games langzamer</translation> 939 <translation>Indien aangevinkt, wordt de macro Just In Time-compiler uitgeschakeld. Als je dit inschakelt, worden spellen langzamer</translation>
927 </message> 940 </message>
928 <message> 941 <message>
929 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/> 942 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
@@ -933,32 +946,32 @@ This would ban both their forum username and their IP address.</source>
933 <message> 946 <message>
934 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="211"/> 947 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="211"/>
935 <source>When checked, it disables the macro HLE functions. Enabling this makes games run slower</source> 948 <source>When checked, it disables the macro HLE functions. Enabling this makes games run slower</source>
936 <translation type="unfinished"/> 949 <translation>Indien aangevinkt, schakelt het de macro HLE functies uit. Inschakelen maakt spellen langzamer</translation>
937 </message> 950 </message>
938 <message> 951 <message>
939 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="214"/> 952 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="214"/>
940 <source>Disable Macro HLE</source> 953 <source>Disable Macro HLE</source>
941 <translation type="unfinished"/> 954 <translation>Schakel Macro HLE uit</translation>
942 </message> 955 </message>
943 <message> 956 <message>
944 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="221"/> 957 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="221"/>
945 <source>When checked, yuzu will log statistics about the compiled pipeline cache</source> 958 <source>When checked, yuzu will log statistics about the compiled pipeline cache</source>
946 <translation type="unfinished"/> 959 <translation>Indien aangevinkt, zal yuzu statistieken registreren over de gecompileerde pijplijn-cache</translation>
947 </message> 960 </message>
948 <message> 961 <message>
949 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="224"/> 962 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="224"/>
950 <source>Enable Shader Feedback</source> 963 <source>Enable Shader Feedback</source>
951 <translation type="unfinished"/> 964 <translation>Schakel Shader Feedback in</translation>
952 </message> 965 </message>
953 <message> 966 <message>
954 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="231"/> 967 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="231"/>
955 <source>When checked, it executes shaders without loop logic changes</source> 968 <source>When checked, it executes shaders without loop logic changes</source>
956 <translation type="unfinished"/> 969 <translation>Indien aangevinkt, voert het shaders uit zonder wijzigingen in de luslogica</translation>
957 </message> 970 </message>
958 <message> 971 <message>
959 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="234"/> 972 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="234"/>
960 <source>Disable Loop safety checks</source> 973 <source>Disable Loop safety checks</source>
961 <translation type="unfinished"/> 974 <translation>Schakel Lusveiligheidscontroles uit</translation>
962 </message> 975 </message>
963 <message> 976 <message>
964 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="244"/> 977 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="244"/>
@@ -968,27 +981,27 @@ This would ban both their forum username and their IP address.</source>
968 <message> 981 <message>
969 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="250"/> 982 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="250"/>
970 <source>Enable Verbose Reporting Services**</source> 983 <source>Enable Verbose Reporting Services**</source>
971 <translation type="unfinished"/> 984 <translation>Schakel Verbose Reporting Services** in</translation>
972 </message> 985 </message>
973 <message> 986 <message>
974 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="257"/> 987 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="257"/>
975 <source>Enable FS Access Log</source> 988 <source>Enable FS Access Log</source>
976 <translation type="unfinished"/> 989 <translation>Schakel FS-toegangslogboek in</translation>
977 </message> 990 </message>
978 <message> 991 <message>
979 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="264"/> 992 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="264"/>
980 <source>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</source> 993 <source>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</source>
981 <translation type="unfinished"/> 994 <translation>Zet dit aan om de laatst gegenereerde audio commandolijst naar de console te sturen. Alleen van invloed op spellen die de audio renderer gebruiken.</translation>
982 </message> 995 </message>
983 <message> 996 <message>
984 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="267"/> 997 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="267"/>
985 <source>Dump Audio Commands To Console**</source> 998 <source>Dump Audio Commands To Console**</source>
986 <translation type="unfinished"/> 999 <translation>Dump Audio-opdrachten naar Console**</translation>
987 </message> 1000 </message>
988 <message> 1001 <message>
989 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="274"/> 1002 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="274"/>
990 <source>Create Minidump After Crash</source> 1003 <source>Create Minidump After Crash</source>
991 <translation type="unfinished"/> 1004 <translation>Maak Minidump na Crash</translation>
992 </message> 1005 </message>
993 <message> 1006 <message>
994 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="284"/> 1007 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="284"/>
@@ -998,42 +1011,42 @@ This would ban both their forum username and their IP address.</source>
998 <message> 1011 <message>
999 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="290"/> 1012 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="290"/>
1000 <source>Kiosk (Quest) Mode</source> 1013 <source>Kiosk (Quest) Mode</source>
1001 <translation>Kiosk (Quest) Modus</translation> 1014 <translation>Kiosk-modus (Quest)</translation>
1002 </message> 1015 </message>
1003 <message> 1016 <message>
1004 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="297"/> 1017 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="297"/>
1005 <source>Enable CPU Debugging</source> 1018 <source>Enable CPU Debugging</source>
1006 <translation type="unfinished"/> 1019 <translation>Schakel CPU-foutopsporing in</translation>
1007 </message> 1020 </message>
1008 <message> 1021 <message>
1009 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="304"/> 1022 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="304"/>
1010 <source>Enable Debug Asserts</source> 1023 <source>Enable Debug Asserts</source>
1011 <translation>Schakel Debug asserties in</translation> 1024 <translation>Schakel Debug-asserts in</translation>
1012 </message> 1025 </message>
1013 <message> 1026 <message>
1014 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="311"/> 1027 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="311"/>
1015 <source>Enable Auto-Stub**</source> 1028 <source>Enable Auto-Stub**</source>
1016 <translation type="unfinished"/> 1029 <translation>Schakel Auto-Stub** in</translation>
1017 </message> 1030 </message>
1018 <message> 1031 <message>
1019 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="318"/> 1032 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="318"/>
1020 <source>Enable All Controller Types</source> 1033 <source>Enable All Controller Types</source>
1021 <translation type="unfinished"/> 1034 <translation>Schakel Alle Controler-soorten in</translation>
1022 </message> 1035 </message>
1023 <message> 1036 <message>
1024 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="325"/> 1037 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="325"/>
1025 <source>Disable Web Applet</source> 1038 <source>Disable Web Applet</source>
1026 <translation type="unfinished"/> 1039 <translation>Schakel Webapplet uit</translation>
1027 </message> 1040 </message>
1028 <message> 1041 <message>
1029 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="332"/> 1042 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="332"/>
1030 <source>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</source> 1043 <source>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</source>
1031 <translation type="unfinished"/> 1044 <translation>Laat yuzu controleren op een werkende Vulkan-omgeving wanneer het programma opstart. Schakel dit uit als dit problemen veroorzaakt met externe programma&apos;s die yuzu zien.</translation>
1032 </message> 1045 </message>
1033 <message> 1046 <message>
1034 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="335"/> 1047 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="335"/>
1035 <source>Perform Startup Vulkan Check</source> 1048 <source>Perform Startup Vulkan Check</source>
1036 <translation type="unfinished"/> 1049 <translation>Voer Vulkan-controle bij het opstarten uit</translation>
1037 </message> 1050 </message>
1038 <message> 1051 <message>
1039 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="350"/> 1052 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="350"/>
@@ -1043,22 +1056,22 @@ This would ban both their forum username and their IP address.</source>
1043 <message> 1056 <message>
1044 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="35"/> 1057 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="35"/>
1045 <source>Restart Required</source> 1058 <source>Restart Required</source>
1046 <translation type="unfinished"/> 1059 <translation>Herstart Vereist</translation>
1047 </message> 1060 </message>
1048 <message> 1061 <message>
1049 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="36"/> 1062 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="36"/>
1050 <source>yuzu is required to restart in order to apply this setting.</source> 1063 <source>yuzu is required to restart in order to apply this setting.</source>
1051 <translation type="unfinished"/> 1064 <translation>yuzu moet opnieuw opstarten om deze instelling toe te passen.</translation>
1052 </message> 1065 </message>
1053 <message> 1066 <message>
1054 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="88"/> 1067 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="88"/>
1055 <source>Web applet not compiled</source> 1068 <source>Web applet not compiled</source>
1056 <translation type="unfinished"/> 1069 <translation>Webapplet niet gecompileerd</translation>
1057 </message> 1070 </message>
1058 <message> 1071 <message>
1059 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="95"/> 1072 <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="95"/>
1060 <source>MiniDump creation not compiled</source> 1073 <source>MiniDump creation not compiled</source>
1061 <translation type="unfinished"/> 1074 <translation>MiniDump-creatie niet gecompileerd</translation>
1062 </message> 1075 </message>
1063</context> 1076</context>
1064<context> 1077<context>
@@ -1066,12 +1079,12 @@ This would ban both their forum username and their IP address.</source>
1066 <message> 1079 <message>
1067 <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/> 1080 <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/>
1068 <source>Configure Debug Controller</source> 1081 <source>Configure Debug Controller</source>
1069 <translation>Debug-controller configureren</translation> 1082 <translation>Configureer Debug-controller</translation>
1070 </message> 1083 </message>
1071 <message> 1084 <message>
1072 <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/> 1085 <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/>
1073 <source>Clear</source> 1086 <source>Clear</source>
1074 <translation>Verwijder</translation> 1087 <translation>Wis</translation>
1075 </message> 1088 </message>
1076 <message> 1089 <message>
1077 <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/> 1090 <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/>
@@ -1084,7 +1097,7 @@ This would ban both their forum username and their IP address.</source>
1084 <message> 1097 <message>
1085 <location filename="../../src/yuzu/configuration/configure_debug_tab.ui" line="14"/> 1098 <location filename="../../src/yuzu/configuration/configure_debug_tab.ui" line="14"/>
1086 <source>Form</source> 1099 <source>Form</source>
1087 <translation>Formulier</translation> 1100 <translation>Vorm</translation>
1088 </message> 1101 </message>
1089 <message> 1102 <message>
1090 <location filename="../../src/yuzu/configuration/configure_debug_tab.ui" line="17"/> 1103 <location filename="../../src/yuzu/configuration/configure_debug_tab.ui" line="17"/>
@@ -1095,8 +1108,7 @@ This would ban both their forum username and their IP address.</source>
1095 <message> 1108 <message>
1096 <location filename="../../src/yuzu/configuration/configure_debug_tab.cpp" line="17"/> 1109 <location filename="../../src/yuzu/configuration/configure_debug_tab.cpp" line="17"/>
1097 <source>CPU</source> 1110 <source>CPU</source>
1098 <translation>CPU 1111 <translation>CPU</translation>
1099</translation>
1100 </message> 1112 </message>
1101</context> 1113</context>
1102<context> 1114<context>
@@ -1104,13 +1116,13 @@ This would ban both their forum username and their IP address.</source>
1104 <message> 1116 <message>
1105 <location filename="../../src/yuzu/configuration/configure.ui" line="20"/> 1117 <location filename="../../src/yuzu/configuration/configure.ui" line="20"/>
1106 <source>yuzu Configuration</source> 1118 <source>yuzu Configuration</source>
1107 <translation>yuzu Configuratie</translation> 1119 <translation>yuzu-configuratie</translation>
1108 </message> 1120 </message>
1109 <message> 1121 <message>
1110 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="52"/> 1122 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="52"/>
1111 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="155"/> 1123 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="155"/>
1112 <source>Audio</source> 1124 <source>Audio</source>
1113 <translation>Geluid</translation> 1125 <translation>Audio</translation>
1114 </message> 1126 </message>
1115 <message> 1127 <message>
1116 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="53"/> 1128 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="53"/>
@@ -1138,12 +1150,12 @@ This would ban both their forum username and their IP address.</source>
1138 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="57"/> 1150 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="57"/>
1139 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="154"/> 1151 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="154"/>
1140 <source>Graphics</source> 1152 <source>Graphics</source>
1141 <translation>Grafisch</translation> 1153 <translation>Graphics</translation>
1142 </message> 1154 </message>
1143 <message> 1155 <message>
1144 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="58"/> 1156 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="58"/>
1145 <source>GraphicsAdvanced</source> 1157 <source>GraphicsAdvanced</source>
1146 <translation>GeAdvanceerdeGrafisch</translation> 1158 <translation>Geavanceerde Graphics</translation>
1147 </message> 1159 </message>
1148 <message> 1160 <message>
1149 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="59"/> 1161 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="59"/>
@@ -1164,7 +1176,7 @@ This would ban both their forum username and their IP address.</source>
1164 <message> 1176 <message>
1165 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="62"/> 1177 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="62"/>
1166 <source>Network</source> 1178 <source>Network</source>
1167 <translation type="unfinished"/> 1179 <translation>Netwerk</translation>
1168 </message> 1180 </message>
1169 <message> 1181 <message>
1170 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="63"/> 1182 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="63"/>
@@ -1175,7 +1187,7 @@ This would ban both their forum username and their IP address.</source>
1175 <message> 1187 <message>
1176 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="64"/> 1188 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="64"/>
1177 <source>Game List</source> 1189 <source>Game List</source>
1178 <translation>Game Lijst</translation> 1190 <translation>Spellijst</translation>
1179 </message> 1191 </message>
1180 <message> 1192 <message>
1181 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="65"/> 1193 <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="65"/>
@@ -1198,7 +1210,7 @@ This would ban both their forum username and their IP address.</source>
1198 <message> 1210 <message>
1199 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="25"/> 1211 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="25"/>
1200 <source>Storage Directories</source> 1212 <source>Storage Directories</source>
1201 <translation>Opslag Folders</translation> 1213 <translation>Opslagmappen</translation>
1202 </message> 1214 </message>
1203 <message> 1215 <message>
1204 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="31"/> 1216 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="31"/>
@@ -1217,12 +1229,12 @@ This would ban both their forum username and their IP address.</source>
1217 <message> 1229 <message>
1218 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="51"/> 1230 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="51"/>
1219 <source>SD Card</source> 1231 <source>SD Card</source>
1220 <translation>SD Kaart</translation> 1232 <translation>SD-kaart</translation>
1221 </message> 1233 </message>
1222 <message> 1234 <message>
1223 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="84"/> 1235 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="84"/>
1224 <source>Gamecard</source> 1236 <source>Gamecard</source>
1225 <translation>Gamekaart</translation> 1237 <translation>Spelkaart</translation>
1226 </message> 1238 </message>
1227 <message> 1239 <message>
1228 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="90"/> 1240 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="90"/>
@@ -1232,7 +1244,7 @@ This would ban both their forum username and their IP address.</source>
1232 <message> 1244 <message>
1233 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="100"/> 1245 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="100"/>
1234 <source>Inserted</source> 1246 <source>Inserted</source>
1235 <translation>Ingevoerd</translation> 1247 <translation>Geplaatst</translation>
1236 </message> 1248 </message>
1237 <message> 1249 <message>
1238 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="107"/> 1250 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="107"/>
@@ -1242,7 +1254,7 @@ This would ban both their forum username and their IP address.</source>
1242 <message> 1254 <message>
1243 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="124"/> 1255 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="124"/>
1244 <source>Patch Manager</source> 1256 <source>Patch Manager</source>
1245 <translation>Patch Beheer</translation> 1257 <translation>Patch-beheer</translation>
1246 </message> 1258 </message>
1247 <message> 1259 <message>
1248 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="152"/> 1260 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="152"/>
@@ -1272,7 +1284,7 @@ This would ban both their forum username and their IP address.</source>
1272 <message> 1284 <message>
1273 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="209"/> 1285 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="209"/>
1274 <source>Cache Game List Metadata</source> 1286 <source>Cache Game List Metadata</source>
1275 <translation>Cache Spel Lijst Metadata</translation> 1287 <translation>Cache Metagegevens van Spellijst</translation>
1276 </message> 1288 </message>
1277 <message> 1289 <message>
1278 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="216"/> 1290 <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="216"/>
@@ -1280,37 +1292,37 @@ This would ban both their forum username and their IP address.</source>
1280 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="135"/> 1292 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="135"/>
1281 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="140"/> 1293 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="140"/>
1282 <source>Reset Metadata Cache</source> 1294 <source>Reset Metadata Cache</source>
1283 <translation>Herstel Metadata Cache</translation> 1295 <translation>Herstel Metagegevenscache</translation>
1284 </message> 1296 </message>
1285 <message> 1297 <message>
1286 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="93"/> 1298 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="93"/>
1287 <source>Select Emulated NAND Directory...</source> 1299 <source>Select Emulated NAND Directory...</source>
1288 <translation>Selecteer Geëmuleerde NAND Folder</translation> 1300 <translation>Selecteer Geëmuleerde NAND-map...</translation>
1289 </message> 1301 </message>
1290 <message> 1302 <message>
1291 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="96"/> 1303 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="96"/>
1292 <source>Select Emulated SD Directory...</source> 1304 <source>Select Emulated SD Directory...</source>
1293 <translation>Selecteer Geëmuleerde SD Folder</translation> 1305 <translation>Selecteer Geëmuleerde SD-map...</translation>
1294 </message> 1306 </message>
1295 <message> 1307 <message>
1296 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="99"/> 1308 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="99"/>
1297 <source>Select Gamecard Path...</source> 1309 <source>Select Gamecard Path...</source>
1298 <translation>Selecteer Gamekaart Pad</translation> 1310 <translation>Selecteer Spelkaartpad...</translation>
1299 </message> 1311 </message>
1300 <message> 1312 <message>
1301 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="102"/> 1313 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="102"/>
1302 <source>Select Dump Directory...</source> 1314 <source>Select Dump Directory...</source>
1303 <translation>Selecteer Dump Folder</translation> 1315 <translation>Selecteer Dump-map...</translation>
1304 </message> 1316 </message>
1305 <message> 1317 <message>
1306 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="105"/> 1318 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="105"/>
1307 <source>Select Mod Load Directory...</source> 1319 <source>Select Mod Load Directory...</source>
1308 <translation>Selecteer Mod Laad Folder</translation> 1320 <translation>Selecteer Mod-laadmap...</translation>
1309 </message> 1321 </message>
1310 <message> 1322 <message>
1311 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="132"/> 1323 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="132"/>
1312 <source>The metadata cache is already empty.</source> 1324 <source>The metadata cache is already empty.</source>
1313 <translation>De metadata cache is al leeg.</translation> 1325 <translation>De metagegevenscache is al leeg.</translation>
1314 </message> 1326 </message>
1315 <message> 1327 <message>
1316 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="136"/> 1328 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="136"/>
@@ -1320,7 +1332,7 @@ This would ban both their forum username and their IP address.</source>
1320 <message> 1332 <message>
1321 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="141"/> 1333 <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="141"/>
1322 <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source> 1334 <source>The metadata cache couldn&apos;t be deleted. It might be in use or non-existent.</source>
1323 <translation>De metadata cache kon niet worden verwijderd. Het wordt mogelijk gebruikt of bestaat niet.</translation> 1335 <translation>De metagegevenscache kon niet worden verwijderd. Het wordt mogelijk gebruikt of bestaat niet.</translation>
1324 </message> 1336 </message>
1325</context> 1337</context>
1326<context> 1338<context>
@@ -1339,7 +1351,7 @@ This would ban both their forum username and their IP address.</source>
1339 <message> 1351 <message>
1340 <location filename="../../src/yuzu/configuration/configure_general.ui" line="35"/> 1352 <location filename="../../src/yuzu/configuration/configure_general.ui" line="35"/>
1341 <source>Limit Speed Percent</source> 1353 <source>Limit Speed Percent</source>
1342 <translation>Limiteer Snelheid Percentage</translation> 1354 <translation>Beperk Snelheidspercentage</translation>
1343 </message> 1355 </message>
1344 <message> 1356 <message>
1345 <location filename="../../src/yuzu/configuration/configure_general.ui" line="42"/> 1357 <location filename="../../src/yuzu/configuration/configure_general.ui" line="42"/>
@@ -1349,12 +1361,12 @@ This would ban both their forum username and their IP address.</source>
1349 <message> 1361 <message>
1350 <location filename="../../src/yuzu/configuration/configure_general.ui" line="60"/> 1362 <location filename="../../src/yuzu/configuration/configure_general.ui" line="60"/>
1351 <source>Multicore CPU Emulation</source> 1363 <source>Multicore CPU Emulation</source>
1352 <translation>Multicore CPU Emulatie</translation> 1364 <translation>Multicore CPU-emulatie</translation>
1353 </message> 1365 </message>
1354 <message> 1366 <message>
1355 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1367 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1356 <source>Extended memory layout (6GB DRAM)</source> 1368 <source>Extended memory layout (8GB DRAM)</source>
1357 <translation type="unfinished"/> 1369 <translation>Uitgebreide geheugenindeling (8 GB DRAM)</translation>
1358 </message> 1370 </message>
1359 <message> 1371 <message>
1360 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1372 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
@@ -1364,22 +1376,22 @@ This would ban both their forum username and their IP address.</source>
1364 <message> 1376 <message>
1365 <location filename="../../src/yuzu/configuration/configure_general.ui" line="81"/> 1377 <location filename="../../src/yuzu/configuration/configure_general.ui" line="81"/>
1366 <source>Prompt for user on game boot</source> 1378 <source>Prompt for user on game boot</source>
1367 <translation>Vraag voor gebruiker bij het opstartten van het spel.</translation> 1379 <translation>Vraag aan gebruiker bij opstarten van het spel</translation>
1368 </message> 1380 </message>
1369 <message> 1381 <message>
1370 <location filename="../../src/yuzu/configuration/configure_general.ui" line="88"/> 1382 <location filename="../../src/yuzu/configuration/configure_general.ui" line="88"/>
1371 <source>Pause emulation when in background</source> 1383 <source>Pause emulation when in background</source>
1372 <translation>Pauzeer Emulatie wanneer yuzu op de achtergrond openstaat</translation> 1384 <translation>Emulatie onderbreken op de achtergrond</translation>
1373 </message> 1385 </message>
1374 <message> 1386 <message>
1375 <location filename="../../src/yuzu/configuration/configure_general.ui" line="95"/> 1387 <location filename="../../src/yuzu/configuration/configure_general.ui" line="95"/>
1376 <source>Hide mouse on inactivity</source> 1388 <source>Hide mouse on inactivity</source>
1377 <translation>Verstop muis wanneer inactief</translation> 1389 <translation>Verberg muis wanneer inactief</translation>
1378 </message> 1390 </message>
1379 <message> 1391 <message>
1380 <location filename="../../src/yuzu/configuration/configure_general.ui" line="137"/> 1392 <location filename="../../src/yuzu/configuration/configure_general.ui" line="137"/>
1381 <source>Reset All Settings</source> 1393 <source>Reset All Settings</source>
1382 <translation>Reset alle instellingen</translation> 1394 <translation>Reset Alle Instellingen</translation>
1383 </message> 1395 </message>
1384 <message> 1396 <message>
1385 <location filename="../../src/yuzu/configuration/configure_general.cpp" line="67"/> 1397 <location filename="../../src/yuzu/configuration/configure_general.cpp" line="67"/>
@@ -1402,17 +1414,17 @@ This would ban both their forum username and their IP address.</source>
1402 <message> 1414 <message>
1403 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="17"/> 1415 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="17"/>
1404 <source>Graphics</source> 1416 <source>Graphics</source>
1405 <translation>Grafisch</translation> 1417 <translation>Graphics</translation>
1406 </message> 1418 </message>
1407 <message> 1419 <message>
1408 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="25"/> 1420 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="25"/>
1409 <source>API Settings</source> 1421 <source>API Settings</source>
1410 <translation>API instellingen</translation> 1422 <translation>API-instellingen</translation>
1411 </message> 1423 </message>
1412 <message> 1424 <message>
1413 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="64"/> 1425 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="64"/>
1414 <source>Shader Backend:</source> 1426 <source>Shader Backend:</source>
1415 <translation type="unfinished"/> 1427 <translation>Shader Backend:</translation>
1416 </message> 1428 </message>
1417 <message> 1429 <message>
1418 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="92"/> 1430 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="92"/>
@@ -1438,37 +1450,37 @@ This would ban both their forum username and their IP address.</source>
1438 <message> 1450 <message>
1439 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="173"/> 1451 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="173"/>
1440 <source>Use disk pipeline cache</source> 1452 <source>Use disk pipeline cache</source>
1441 <translation type="unfinished"/> 1453 <translation>Gebruik schijfpijplijn-cache</translation>
1442 </message> 1454 </message>
1443 <message> 1455 <message>
1444 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="180"/> 1456 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="180"/>
1445 <source>Use asynchronous GPU emulation</source> 1457 <source>Use asynchronous GPU emulation</source>
1446 <translation>Gebruik asynchroon GPU emulatie</translation> 1458 <translation>Gebruik asynchrone GPU-emulatie</translation>
1447 </message> 1459 </message>
1448 <message> 1460 <message>
1449 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="187"/> 1461 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="187"/>
1450 <source>Accelerate ASTC texture decoding</source> 1462 <source>Accelerate ASTC texture decoding</source>
1451 <translation type="unfinished"/> 1463 <translation>Versnel ASTC-textuurdecodering</translation>
1452 </message> 1464 </message>
1453 <message> 1465 <message>
1454 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="209"/> 1466 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="209"/>
1455 <source>NVDEC emulation:</source> 1467 <source>NVDEC emulation:</source>
1456 <translation type="unfinished"/> 1468 <translation>NVDEC-emulatie:</translation>
1457 </message> 1469 </message>
1458 <message> 1470 <message>
1459 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="217"/> 1471 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="217"/>
1460 <source>No Video Output</source> 1472 <source>No Video Output</source>
1461 <translation type="unfinished"/> 1473 <translation>Geen Video-uitvoer</translation>
1462 </message> 1474 </message>
1463 <message> 1475 <message>
1464 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="222"/> 1476 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="222"/>
1465 <source>CPU Video Decoding</source> 1477 <source>CPU Video Decoding</source>
1466 <translation type="unfinished"/> 1478 <translation>CPU Videodecodering</translation>
1467 </message> 1479 </message>
1468 <message> 1480 <message>
1469 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="227"/> 1481 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="227"/>
1470 <source>GPU Video Decoding (Default)</source> 1482 <source>GPU Video Decoding (Default)</source>
1471 <translation type="unfinished"/> 1483 <translation>GPU Videodecodering (Standaard)</translation>
1472 </message> 1484 </message>
1473 <message> 1485 <message>
1474 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="253"/> 1486 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="253"/>
@@ -1478,7 +1490,7 @@ This would ban both their forum username and their IP address.</source>
1478 <message> 1490 <message>
1479 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="261"/> 1491 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="261"/>
1480 <source>Borderless Windowed</source> 1492 <source>Borderless Windowed</source>
1481 <translation>BoordLoos Venster</translation> 1493 <translation>Randloos Venster</translation>
1482 </message> 1494 </message>
1483 <message> 1495 <message>
1484 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="266"/> 1496 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="266"/>
@@ -1508,142 +1520,142 @@ This would ban both their forum username and their IP address.</source>
1508 <message> 1520 <message>
1509 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="315"/> 1521 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="315"/>
1510 <source>Force 16:10</source> 1522 <source>Force 16:10</source>
1511 <translation type="unfinished"/> 1523 <translation>Forceer 16:10</translation>
1512 </message> 1524 </message>
1513 <message> 1525 <message>
1514 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="320"/> 1526 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="320"/>
1515 <source>Stretch to Window</source> 1527 <source>Stretch to Window</source>
1516 <translation>Rek naar Venster</translation> 1528 <translation>Uitrekken naar Venster</translation>
1517 </message> 1529 </message>
1518 <message> 1530 <message>
1519 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="346"/> 1531 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="346"/>
1520 <source>Resolution:</source> 1532 <source>Resolution:</source>
1521 <translation type="unfinished"/> 1533 <translation>Resolutie:</translation>
1522 </message> 1534 </message>
1523 <message> 1535 <message>
1524 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="354"/> 1536 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="354"/>
1525 <source>0.5X (360p/540p) [EXPERIMENTAL]</source> 1537 <source>0.5X (360p/540p) [EXPERIMENTAL]</source>
1526 <translation type="unfinished"/> 1538 <translation>0.5X (360p/540p) [EXPERIMENTEEL]</translation>
1527 </message> 1539 </message>
1528 <message> 1540 <message>
1529 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="359"/> 1541 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="359"/>
1530 <source>0.75X (540p/810p) [EXPERIMENTAL]</source> 1542 <source>0.75X (540p/810p) [EXPERIMENTAL]</source>
1531 <translation type="unfinished"/> 1543 <translation>0.75X (540p/810p) [EXPERIMENTEEL]</translation>
1532 </message> 1544 </message>
1533 <message> 1545 <message>
1534 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="364"/> 1546 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="364"/>
1535 <source>1X (720p/1080p)</source> 1547 <source>1X (720p/1080p)</source>
1536 <translation type="unfinished"/> 1548 <translation>1X (720p/1080p)</translation>
1537 </message> 1549 </message>
1538 <message> 1550 <message>
1539 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="369"/> 1551 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="369"/>
1540 <source>1.5X (1080p/1620p) [EXPERIMENTAL]</source> 1552 <source>1.5X (1080p/1620p) [EXPERIMENTAL]</source>
1541 <translation type="unfinished"/> 1553 <translation>1.5X (1080p/1620p) [EXPERIMENTEEL]</translation>
1542 </message> 1554 </message>
1543 <message> 1555 <message>
1544 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="374"/> 1556 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="374"/>
1545 <source>2X (1440p/2160p)</source> 1557 <source>2X (1440p/2160p)</source>
1546 <translation type="unfinished"/> 1558 <translation>2X (1440p/2160p)</translation>
1547 </message> 1559 </message>
1548 <message> 1560 <message>
1549 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="379"/> 1561 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="379"/>
1550 <source>3X (2160p/3240p)</source> 1562 <source>3X (2160p/3240p)</source>
1551 <translation type="unfinished"/> 1563 <translation>3X (2160p/3240p)</translation>
1552 </message> 1564 </message>
1553 <message> 1565 <message>
1554 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="384"/> 1566 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="384"/>
1555 <source>4X (2880p/4320p)</source> 1567 <source>4X (2880p/4320p)</source>
1556 <translation type="unfinished"/> 1568 <translation>4X (2880p/4320p)</translation>
1557 </message> 1569 </message>
1558 <message> 1570 <message>
1559 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="389"/> 1571 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="389"/>
1560 <source>5X (3600p/5400p)</source> 1572 <source>5X (3600p/5400p)</source>
1561 <translation type="unfinished"/> 1573 <translation>5X (3600p/5400p)</translation>
1562 </message> 1574 </message>
1563 <message> 1575 <message>
1564 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="394"/> 1576 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="394"/>
1565 <source>6X (4320p/6480p)</source> 1577 <source>6X (4320p/6480p)</source>
1566 <translation type="unfinished"/> 1578 <translation>6X (4320p/6480p)</translation>
1567 </message> 1579 </message>
1568 <message> 1580 <message>
1569 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="399"/> 1581 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="399"/>
1570 <source>7X (5040p/7560p)</source> 1582 <source>7X (5040p/7560p)</source>
1571 <translation type="unfinished"/> 1583 <translation>7X (5040p/7560p)</translation>
1572 </message> 1584 </message>
1573 <message> 1585 <message>
1574 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="404"/> 1586 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="404"/>
1575 <source>8X (5760p/8640p)</source> 1587 <source>8X (5760p/8640p)</source>
1576 <translation type="unfinished"/> 1588 <translation>8X (5760p/8640p)</translation>
1577 </message> 1589 </message>
1578 <message> 1590 <message>
1579 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="430"/> 1591 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="430"/>
1580 <source>Window Adapting Filter:</source> 1592 <source>Window Adapting Filter:</source>
1581 <translation type="unfinished"/> 1593 <translation>Window Adapting Filter:</translation>
1582 </message> 1594 </message>
1583 <message> 1595 <message>
1584 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="438"/> 1596 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="438"/>
1585 <source>Nearest Neighbor</source> 1597 <source>Nearest Neighbor</source>
1586 <translation type="unfinished"/> 1598 <translation>Nearest Neighbor</translation>
1587 </message> 1599 </message>
1588 <message> 1600 <message>
1589 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="443"/> 1601 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="443"/>
1590 <source>Bilinear</source> 1602 <source>Bilinear</source>
1591 <translation type="unfinished"/> 1603 <translation>Bilinear</translation>
1592 </message> 1604 </message>
1593 <message> 1605 <message>
1594 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="448"/> 1606 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="448"/>
1595 <source>Bicubic</source> 1607 <source>Bicubic</source>
1596 <translation type="unfinished"/> 1608 <translation>Bicubic</translation>
1597 </message> 1609 </message>
1598 <message> 1610 <message>
1599 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="453"/> 1611 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="453"/>
1600 <source>Gaussian</source> 1612 <source>Gaussian</source>
1601 <translation type="unfinished"/> 1613 <translation>Gaussian</translation>
1602 </message> 1614 </message>
1603 <message> 1615 <message>
1604 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="458"/> 1616 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="458"/>
1605 <source>ScaleForce</source> 1617 <source>ScaleForce</source>
1606 <translation type="unfinished"/> 1618 <translation>ScaleForce</translation>
1607 </message> 1619 </message>
1608 <message> 1620 <message>
1609 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="463"/> 1621 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="463"/>
1610 <source>AMD FidelityFXâ„¢ï¸ Super Resolution</source> 1622 <source>AMD FidelityFXâ„¢ï¸ Super Resolution</source>
1611 <translation type="unfinished"/> 1623 <translation>AMD FidelityFXâ„¢ï¸ Super Resolution</translation>
1612 </message> 1624 </message>
1613 <message> 1625 <message>
1614 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="489"/> 1626 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="489"/>
1615 <source>Anti-Aliasing Method:</source> 1627 <source>Anti-Aliasing Method:</source>
1616 <translation type="unfinished"/> 1628 <translation>Antialiasing-methode:</translation>
1617 </message> 1629 </message>
1618 <message> 1630 <message>
1619 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="502"/> 1631 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="502"/>
1620 <source>FXAA</source> 1632 <source>FXAA</source>
1621 <translation type="unfinished"/> 1633 <translation>FXAA</translation>
1622 </message> 1634 </message>
1623 <message> 1635 <message>
1624 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="507"/> 1636 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="507"/>
1625 <source>SMAA</source> 1637 <source>SMAA</source>
1626 <translation type="unfinished"/> 1638 <translation>SMAA</translation>
1627 </message> 1639 </message>
1628 <message> 1640 <message>
1629 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="563"/> 1641 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="563"/>
1630 <source>Use global FSR Sharpness</source> 1642 <source>Use global FSR Sharpness</source>
1631 <translation type="unfinished"/> 1643 <translation>Gebruik globale FSR-scherpte</translation>
1632 </message> 1644 </message>
1633 <message> 1645 <message>
1634 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="568"/> 1646 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="568"/>
1635 <source>Set FSR Sharpness</source> 1647 <source>Set FSR Sharpness</source>
1636 <translation type="unfinished"/> 1648 <translation>Stel FSR-scherpte in</translation>
1637 </message> 1649 </message>
1638 <message> 1650 <message>
1639 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="582"/> 1651 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="582"/>
1640 <source>FSR Sharpness:</source> 1652 <source>FSR Sharpness:</source>
1641 <translation type="unfinished"/> 1653 <translation>FSR-scherpte:</translation>
1642 </message> 1654 </message>
1643 <message> 1655 <message>
1644 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="649"/> 1656 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="649"/>
1645 <source>100%</source> 1657 <source>100%</source>
1646 <translation type="unfinished"/> 1658 <translation>100%</translation>
1647 </message> 1659 </message>
1648 <message> 1660 <message>
1649 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="688"/> 1661 <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="688"/>
@@ -1664,12 +1676,12 @@ This would ban both their forum username and their IP address.</source>
1664 <message> 1676 <message>
1665 <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="33"/> 1677 <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="33"/>
1666 <source>GLASM (Assembly Shaders, NVIDIA Only)</source> 1678 <source>GLASM (Assembly Shaders, NVIDIA Only)</source>
1667 <translation type="unfinished"/> 1679 <translation>GLASM (Assembly Shaders, alleen NVIDIA)</translation>
1668 </message> 1680 </message>
1669 <message> 1681 <message>
1670 <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="34"/> 1682 <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="34"/>
1671 <source>SPIR-V (Experimental, Mesa Only)</source> 1683 <source>SPIR-V (Experimental, Mesa Only)</source>
1672 <translation type="unfinished"/> 1684 <translation>SPIR-V (Experimenteel, alleen Mesa)</translation>
1673 </message> 1685 </message>
1674 <message> 1686 <message>
1675 <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="178"/> 1687 <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="178"/>
@@ -1683,12 +1695,12 @@ This would ban both their forum username and their IP address.</source>
1683 <message> 1695 <message>
1684 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/> 1696 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/>
1685 <source>Form</source> 1697 <source>Form</source>
1686 <translation>Formulier</translation> 1698 <translation>Vorm</translation>
1687 </message> 1699 </message>
1688 <message> 1700 <message>
1689 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="17"/> 1701 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="17"/>
1690 <source>Advanced</source> 1702 <source>Advanced</source>
1691 <translation>Gedadvanceerd</translation> 1703 <translation>Geavanceerd</translation>
1692 </message> 1704 </message>
1693 <message> 1705 <message>
1694 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="25"/> 1706 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="25"/>
@@ -1703,12 +1715,12 @@ This would ban both their forum username and their IP address.</source>
1703 <message> 1715 <message>
1704 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/> 1716 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/>
1705 <source>Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed.</source> 1717 <source>Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed.</source>
1706 <translation type="unfinished"/> 1718 <translation>Werkt op de achtergrond terwijl er wordt gewacht op grafische opdrachten om te voorkomen dat de GPU zijn kloksnelheid verlaagt.</translation>
1707 </message> 1719 </message>
1708 <message> 1720 <message>
1709 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="78"/> 1721 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="78"/>
1710 <source>Force maximum clocks (Vulkan only)</source> 1722 <source>Force maximum clocks (Vulkan only)</source>
1711 <translation type="unfinished"/> 1723 <translation>Forceer maximale klokken (alleen Vulkan)</translation>
1712 </message> 1724 </message>
1713 <message> 1725 <message>
1714 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/> 1726 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/>
@@ -1718,17 +1730,17 @@ This would ban both their forum username and their IP address.</source>
1718 <message> 1730 <message>
1719 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="88"/> 1731 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="88"/>
1720 <source>Use VSync</source> 1732 <source>Use VSync</source>
1721 <translation type="unfinished"/> 1733 <translation>Gebruik VSync</translation>
1722 </message> 1734 </message>
1723 <message> 1735 <message>
1724 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/> 1736 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
1725 <source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source> 1737 <source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source>
1726 <translation type="unfinished"/> 1738 <translation>Maakt asynchrone ASTC-textuurdecodering mogelijk, waardoor de laadtijd minder stottert. Deze functie is experimenteel.</translation>
1727 </message> 1739 </message>
1728 <message> 1740 <message>
1729 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/> 1741 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/>
1730 <source>Decode ASTC textures asynchronously (Hack)</source> 1742 <source>Decode ASTC textures asynchronously (Hack)</source>
1731 <translation type="unfinished"/> 1743 <translation>Decodeer ASTC-texturen asynchroon (Hack)</translation>
1732 </message> 1744 </message>
1733 <message> 1745 <message>
1734 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/> 1746 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/>
@@ -1738,37 +1750,37 @@ This would ban both their forum username and their IP address.</source>
1738 <message> 1750 <message>
1739 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="108"/> 1751 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="108"/>
1740 <source>Use asynchronous shader building (Hack)</source> 1752 <source>Use asynchronous shader building (Hack)</source>
1741 <translation type="unfinished"/> 1753 <translation>Gebruik asynchrone shaderbouw (Hack)</translation>
1742 </message> 1754 </message>
1743 <message> 1755 <message>
1744 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="115"/> 1756 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="115"/>
1745 <source>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</source> 1757 <source>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</source>
1746 <translation type="unfinished"/> 1758 <translation>Schakelt Snelle GPU-tijd in. Deze optie forceert de meeste games om op hun hoogste native resolutie te draaien.</translation>
1747 </message> 1759 </message>
1748 <message> 1760 <message>
1749 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="118"/> 1761 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="118"/>
1750 <source>Use Fast GPU Time (Hack)</source> 1762 <source>Use Fast GPU Time (Hack)</source>
1751 <translation type="unfinished"/> 1763 <translation>Gebruik Snelle GPU-tijd (Hack)</translation>
1752 </message> 1764 </message>
1753 <message> 1765 <message>
1754 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="125"/> 1766 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="125"/>
1755 <source>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</source> 1767 <source>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</source>
1756 <translation type="unfinished"/> 1768 <translation>Schakelt pessimistische bufferschoonmaakacties in. Deze optie forceert het schoonmaken van ongewijzigde buffers, wat prestaties kan kosten.</translation>
1757 </message> 1769 </message>
1758 <message> 1770 <message>
1759 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="128"/> 1771 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="128"/>
1760 <source>Use pessimistic buffer flushes (Hack)</source> 1772 <source>Use pessimistic buffer flushes (Hack)</source>
1761 <translation type="unfinished"/> 1773 <translation>Gebruik pessimistische bufferleegmaakacties (Hack)</translation>
1762 </message> 1774 </message>
1763 <message> 1775 <message>
1764 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="135"/> 1776 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="135"/>
1765 <source>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</source> 1777 <source>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</source>
1766 <translation type="unfinished"/> 1778 <translation>Schakelt GPU-leverancier-specifieke pijplijn-cache in. Deze optie kan de laadtijd van shaders aanzienlijk verbeteren in gevallen waarin het Vulkan-stuurprogramma de pijplijncachebestanden niet intern opslaat.</translation>
1767 </message> 1779 </message>
1768 <message> 1780 <message>
1769 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="138"/> 1781 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="138"/>
1770 <source>Use Vulkan pipeline cache</source> 1782 <source>Use Vulkan pipeline cache</source>
1771 <translation type="unfinished"/> 1783 <translation>Gebruik Vulkan-pijplijn-cache</translation>
1772 </message> 1784 </message>
1773 <message> 1785 <message>
1774 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="160"/> 1786 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="160"/>
@@ -1778,7 +1790,7 @@ This would ban both their forum username and their IP address.</source>
1778 <message> 1790 <message>
1779 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="168"/> 1791 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="168"/>
1780 <source>Automatic</source> 1792 <source>Automatic</source>
1781 <translation type="unfinished"/> 1793 <translation>Automatisch</translation>
1782 </message> 1794 </message>
1783 <message> 1795 <message>
1784 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="173"/> 1796 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="173"/>
@@ -1811,7 +1823,7 @@ This would ban both their forum username and their IP address.</source>
1811 <message> 1823 <message>
1812 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/> 1824 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/>
1813 <source>Hotkey Settings</source> 1825 <source>Hotkey Settings</source>
1814 <translation>Sneltoets Instellingen</translation> 1826 <translation>Sneltoets-instellingen</translation>
1815 </message> 1827 </message>
1816 <message> 1828 <message>
1817 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="17"/> 1829 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="17"/>
@@ -1821,7 +1833,7 @@ This would ban both their forum username and their IP address.</source>
1821 <message> 1833 <message>
1822 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="25"/> 1834 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="25"/>
1823 <source>Double-click on a binding to change it.</source> 1835 <source>Double-click on a binding to change it.</source>
1824 <translation>Dubbel-klik op een binding om het te veranderen.</translation> 1836 <translation>Dubbelklik op een instelling om deze te wijzigen.</translation>
1825 </message> 1837 </message>
1826 <message> 1838 <message>
1827 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="45"/> 1839 <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="45"/>
@@ -1846,14 +1858,14 @@ This would ban both their forum username and their IP address.</source>
1846 <message> 1858 <message>
1847 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/> 1859 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/>
1848 <source>Controller Hotkey</source> 1860 <source>Controller Hotkey</source>
1849 <translation type="unfinished"/> 1861 <translation>Controller-sneltoets</translation>
1850 </message> 1862 </message>
1851 <message> 1863 <message>
1852 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="138"/> 1864 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="138"/>
1853 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="164"/> 1865 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="164"/>
1854 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="379"/> 1866 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="379"/>
1855 <source>Conflicting Key Sequence</source> 1867 <source>Conflicting Key Sequence</source>
1856 <translation>Ongeldige Toets Volgorde</translation> 1868 <translation>Ongeldige Toetsvolgorde</translation>
1857 </message> 1869 </message>
1858 <message> 1870 <message>
1859 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="139"/> 1871 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="139"/>
@@ -1864,7 +1876,7 @@ This would ban both their forum username and their IP address.</source>
1864 <message> 1876 <message>
1865 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="158"/> 1877 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="158"/>
1866 <source>Home+%1</source> 1878 <source>Home+%1</source>
1867 <translation type="unfinished"/> 1879 <translation>Home+%1</translation>
1868 </message> 1880 </message>
1869 <message> 1881 <message>
1870 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/> 1882 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/>
@@ -1874,7 +1886,7 @@ This would ban both their forum username and their IP address.</source>
1874 <message> 1886 <message>
1875 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="242"/> 1887 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="242"/>
1876 <source>Invalid</source> 1888 <source>Invalid</source>
1877 <translation type="unfinished"/> 1889 <translation>Ongeldig</translation>
1878 </message> 1890 </message>
1879 <message> 1891 <message>
1880 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="343"/> 1892 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="343"/>
@@ -1884,17 +1896,17 @@ This would ban both their forum username and their IP address.</source>
1884 <message> 1896 <message>
1885 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="344"/> 1897 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="344"/>
1886 <source>Clear</source> 1898 <source>Clear</source>
1887 <translation>Verwijder</translation> 1899 <translation>Wis</translation>
1888 </message> 1900 </message>
1889 <message> 1901 <message>
1890 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="365"/> 1902 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="365"/>
1891 <source>Conflicting Button Sequence</source> 1903 <source>Conflicting Button Sequence</source>
1892 <translation type="unfinished"/> 1904 <translation>Conflicterende Knoppencombinatie</translation>
1893 </message> 1905 </message>
1894 <message> 1906 <message>
1895 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="366"/> 1907 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="366"/>
1896 <source>The default button sequence is already assigned to: %1</source> 1908 <source>The default button sequence is already assigned to: %1</source>
1897 <translation type="unfinished"/> 1909 <translation>De standaard knoppencombinatie is al toegewezen aan: %1</translation>
1898 </message> 1910 </message>
1899 <message> 1911 <message>
1900 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="380"/> 1912 <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="380"/>
@@ -1966,17 +1978,17 @@ This would ban both their forum username and their IP address.</source>
1966 <message> 1978 <message>
1967 <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/> 1979 <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/>
1968 <source>Console Mode</source> 1980 <source>Console Mode</source>
1969 <translation>Console ID:</translation> 1981 <translation>Console-modus:</translation>
1970 </message> 1982 </message>
1971 <message> 1983 <message>
1972 <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/> 1984 <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/>
1973 <source>Docked</source> 1985 <source>Docked</source>
1974 <translation>GeDocked</translation> 1986 <translation>Docked</translation>
1975 </message> 1987 </message>
1976 <message> 1988 <message>
1977 <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/> 1989 <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/>
1978 <source>Handheld</source> 1990 <source>Handheld</source>
1979 <translation>Mobiel</translation> 1991 <translation>Handheld</translation>
1980 </message> 1992 </message>
1981 <message> 1993 <message>
1982 <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/> 1994 <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/>
@@ -2052,7 +2064,7 @@ This would ban both their forum username and their IP address.</source>
2052 <message> 2064 <message>
2053 <location filename="../../src/yuzu/configuration/configure_input.ui" line="537"/> 2065 <location filename="../../src/yuzu/configuration/configure_input.ui" line="537"/>
2054 <source>Clear</source> 2066 <source>Clear</source>
2055 <translation>Verwijder</translation> 2067 <translation>Wis</translation>
2056 </message> 2068 </message>
2057</context> 2069</context>
2058<context> 2070<context>
@@ -2065,7 +2077,7 @@ This would ban both their forum username and their IP address.</source>
2065 <message> 2077 <message>
2066 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/> 2078 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/>
2067 <source>Joycon Colors</source> 2079 <source>Joycon Colors</source>
2068 <translation>Joycon Kleuren</translation> 2080 <translation>Joycon-kleuren</translation>
2069 </message> 2081 </message>
2070 <message> 2082 <message>
2071 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/> 2083 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/>
@@ -2082,7 +2094,7 @@ This would ban both their forum username and their IP address.</source>
2082 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/> 2094 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/>
2083 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/> 2095 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/>
2084 <source>L Body</source> 2096 <source>L Body</source>
2085 <translation>L lichaam</translation> 2097 <translation>L-lichaam</translation>
2086 </message> 2098 </message>
2087 <message> 2099 <message>
2088 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/> 2100 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/>
@@ -2094,7 +2106,7 @@ This would ban both their forum username and their IP address.</source>
2094 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/> 2106 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/>
2095 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/> 2107 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/>
2096 <source>L Button</source> 2108 <source>L Button</source>
2097 <translation>L Knop</translation> 2109 <translation>L-knop</translation>
2098 </message> 2110 </message>
2099 <message> 2111 <message>
2100 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/> 2112 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/>
@@ -2106,7 +2118,7 @@ This would ban both their forum username and their IP address.</source>
2106 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/> 2118 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/>
2107 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/> 2119 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/>
2108 <source>R Body</source> 2120 <source>R Body</source>
2109 <translation>R lichaam</translation> 2121 <translation>R-lichaam</translation>
2110 </message> 2122 </message>
2111 <message> 2123 <message>
2112 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/> 2124 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/>
@@ -2118,7 +2130,7 @@ This would ban both their forum username and their IP address.</source>
2118 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/> 2130 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/>
2119 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/> 2131 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/>
2120 <source>R Button</source> 2132 <source>R Button</source>
2121 <translation>R Knop</translation> 2133 <translation>R-knop</translation>
2122 </message> 2134 </message>
2123 <message> 2135 <message>
2124 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/> 2136 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/>
@@ -2158,7 +2170,7 @@ This would ban both their forum username and their IP address.</source>
2158 <message> 2170 <message>
2159 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/> 2171 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/>
2160 <source>Emulated Devices</source> 2172 <source>Emulated Devices</source>
2161 <translation type="unfinished"/> 2173 <translation>Geëmuleerde Apparaten</translation>
2162 </message> 2174 </message>
2163 <message> 2175 <message>
2164 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/> 2176 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/>
@@ -2178,12 +2190,12 @@ This would ban both their forum username and their IP address.</source>
2178 <message> 2190 <message>
2179 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2588"/> 2191 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2588"/>
2180 <source>Advanced</source> 2192 <source>Advanced</source>
2181 <translation>Gedadvanceerd</translation> 2193 <translation>Geavanceerd</translation>
2182 </message> 2194 </message>
2183 <message> 2195 <message>
2184 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/> 2196 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/>
2185 <source>Debug Controller</source> 2197 <source>Debug Controller</source>
2186 <translation>Debug Controller</translation> 2198 <translation>Debug-controller</translation>
2187 </message> 2199 </message>
2188 <message> 2200 <message>
2189 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/> 2201 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/>
@@ -2196,12 +2208,12 @@ This would ban both their forum username and their IP address.</source>
2196 <message> 2208 <message>
2197 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/> 2209 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/>
2198 <source>Ring Controller</source> 2210 <source>Ring Controller</source>
2199 <translation type="unfinished"/> 2211 <translation>Ring Controller</translation>
2200 </message> 2212 </message>
2201 <message> 2213 <message>
2202 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/> 2214 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/>
2203 <source>Infrared Camera</source> 2215 <source>Infrared Camera</source>
2204 <translation type="unfinished"/> 2216 <translation>Infraroodcamera</translation>
2205 </message> 2217 </message>
2206 <message> 2218 <message>
2207 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2640"/> 2219 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2640"/>
@@ -2211,49 +2223,49 @@ This would ban both their forum username and their IP address.</source>
2211 <message> 2223 <message>
2212 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2652"/> 2224 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2652"/>
2213 <source>Emulate Analog with Keyboard Input</source> 2225 <source>Emulate Analog with Keyboard Input</source>
2214 <translation>Emuleer Anolooge invoer met toetsenbord</translation> 2226 <translation>Emuleer Analoog met Toetsenbordinvoer</translation>
2215 </message> 2227 </message>
2216 <message> 2228 <message>
2217 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2659"/> 2229 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2659"/>
2218 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2701"/> 2230 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2701"/>
2219 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2717"/> 2231 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2717"/>
2220 <source>Requires restarting yuzu</source> 2232 <source>Requires restarting yuzu</source>
2221 <translation type="unfinished"/> 2233 <translation>Vereist het herstarten van yuzu</translation>
2222 </message> 2234 </message>
2223 <message> 2235 <message>
2224 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2668"/> 2236 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2668"/>
2225 <source>Enable XInput 8 player support (disables web applet)</source> 2237 <source>Enable XInput 8 player support (disables web applet)</source>
2226 <translation type="unfinished"/> 2238 <translation>Schakel ondersteuning voor XInput 8-speler in (schakelt webapplet uit)</translation>
2227 </message> 2239 </message>
2228 <message> 2240 <message>
2229 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2681"/> 2241 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2681"/>
2230 <source>Enable UDP controllers (not needed for motion)</source> 2242 <source>Enable UDP controllers (not needed for motion)</source>
2231 <translation type="unfinished"/> 2243 <translation>Schakel UDP-controllers in (niet nodig voor beweging)</translation>
2232 </message> 2244 </message>
2233 <message> 2245 <message>
2234 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2694"/> 2246 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2694"/>
2235 <source>Controller navigation</source> 2247 <source>Controller navigation</source>
2236 <translation type="unfinished"/> 2248 <translation>Controller-navigering</translation>
2237 </message> 2249 </message>
2238 <message> 2250 <message>
2239 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2710"/> 2251 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2710"/>
2240 <source>Enable direct JoyCon driver</source> 2252 <source>Enable direct JoyCon driver</source>
2241 <translation type="unfinished"/> 2253 <translation>Schakel JoyCon-stuurprogramma in</translation>
2242 </message> 2254 </message>
2243 <message> 2255 <message>
2244 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/> 2256 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/>
2245 <source>Enable direct Pro Controller driver [EXPERIMENTAL]</source> 2257 <source>Enable direct Pro Controller driver [EXPERIMENTAL]</source>
2246 <translation type="unfinished"/> 2258 <translation>Schakel Pro Controller-stuurprogramma in [EXPERIMENTEEL]</translation>
2247 </message> 2259 </message>
2248 <message> 2260 <message>
2249 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/> 2261 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/>
2250 <source>Enable mouse panning</source> 2262 <source>Enable mouse panning</source>
2251 <translation>Schakel muis panning in</translation> 2263 <translation>Schakel muispanning in</translation>
2252 </message> 2264 </message>
2253 <message> 2265 <message>
2254 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2746"/> 2266 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2746"/>
2255 <source>Mouse sensitivity</source> 2267 <source>Mouse sensitivity</source>
2256 <translation>Muis Gevoeligheid</translation> 2268 <translation>Muisgevoeligheid</translation>
2257 </message> 2269 </message>
2258 <message> 2270 <message>
2259 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2752"/> 2271 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2752"/>
@@ -2271,67 +2283,67 @@ This would ban both their forum username and their IP address.</source>
2271 <message> 2283 <message>
2272 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="14"/> 2284 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="14"/>
2273 <source>Form</source> 2285 <source>Form</source>
2274 <translation>Formulier</translation> 2286 <translation>Vorm</translation>
2275 </message> 2287 </message>
2276 <message> 2288 <message>
2277 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="17"/> 2289 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="17"/>
2278 <source>Graphics</source> 2290 <source>Graphics</source>
2279 <translation>Grafisch</translation> 2291 <translation>Graphics</translation>
2280 </message> 2292 </message>
2281 <message> 2293 <message>
2282 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="28"/> 2294 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="28"/>
2283 <source>Input Profiles</source> 2295 <source>Input Profiles</source>
2284 <translation type="unfinished"/> 2296 <translation>Invoerprofielen</translation>
2285 </message> 2297 </message>
2286 <message> 2298 <message>
2287 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="49"/> 2299 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="49"/>
2288 <source>Player 1 Profile</source> 2300 <source>Player 1 Profile</source>
2289 <translation type="unfinished"/> 2301 <translation>Profiel Speler 1 </translation>
2290 </message> 2302 </message>
2291 <message> 2303 <message>
2292 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="84"/> 2304 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="84"/>
2293 <source>Player 2 Profile</source> 2305 <source>Player 2 Profile</source>
2294 <translation type="unfinished"/> 2306 <translation>Profiel Speler 2</translation>
2295 </message> 2307 </message>
2296 <message> 2308 <message>
2297 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="119"/> 2309 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="119"/>
2298 <source>Player 3 Profile</source> 2310 <source>Player 3 Profile</source>
2299 <translation type="unfinished"/> 2311 <translation>Profiel Speler 3</translation>
2300 </message> 2312 </message>
2301 <message> 2313 <message>
2302 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="154"/> 2314 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="154"/>
2303 <source>Player 4 Profile</source> 2315 <source>Player 4 Profile</source>
2304 <translation type="unfinished"/> 2316 <translation>Profiel Speler 4</translation>
2305 </message> 2317 </message>
2306 <message> 2318 <message>
2307 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="189"/> 2319 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="189"/>
2308 <source>Player 5 Profile</source> 2320 <source>Player 5 Profile</source>
2309 <translation type="unfinished"/> 2321 <translation>Profiel Speler 5</translation>
2310 </message> 2322 </message>
2311 <message> 2323 <message>
2312 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="224"/> 2324 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="224"/>
2313 <source>Player 6 Profile</source> 2325 <source>Player 6 Profile</source>
2314 <translation type="unfinished"/> 2326 <translation>Profiel Speler 6</translation>
2315 </message> 2327 </message>
2316 <message> 2328 <message>
2317 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="259"/> 2329 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="259"/>
2318 <source>Player 7 Profile</source> 2330 <source>Player 7 Profile</source>
2319 <translation type="unfinished"/> 2331 <translation>Profiel Speler 7</translation>
2320 </message> 2332 </message>
2321 <message> 2333 <message>
2322 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="294"/> 2334 <location filename="../../src/yuzu/configuration/configure_input_per_game.ui" line="294"/>
2323 <source>Player 8 Profile</source> 2335 <source>Player 8 Profile</source>
2324 <translation type="unfinished"/> 2336 <translation>Profiel Speler 8</translation>
2325 </message> 2337 </message>
2326 <message> 2338 <message>
2327 <location filename="../../src/yuzu/configuration/configure_input_per_game.cpp" line="35"/> 2339 <location filename="../../src/yuzu/configuration/configure_input_per_game.cpp" line="35"/>
2328 <source>Use global input configuration</source> 2340 <source>Use global input configuration</source>
2329 <translation type="unfinished"/> 2341 <translation>Gebruik globale invoerconfiguratie</translation>
2330 </message> 2342 </message>
2331 <message> 2343 <message>
2332 <location filename="../../src/yuzu/configuration/configure_input_per_game.cpp" line="47"/> 2344 <location filename="../../src/yuzu/configuration/configure_input_per_game.cpp" line="47"/>
2333 <source>Player %1 profile</source> 2345 <source>Player %1 profile</source>
2334 <translation type="unfinished"/> 2346 <translation>Profiel Speler %1 </translation>
2335 </message> 2347 </message>
2336</context> 2348</context>
2337<context> 2349<context>
@@ -2344,12 +2356,12 @@ This would ban both their forum username and their IP address.</source>
2344 <message> 2356 <message>
2345 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/> 2357 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/>
2346 <source>Connect Controller</source> 2358 <source>Connect Controller</source>
2347 <translation>Verbindt Controller</translation> 2359 <translation>Verbind Controller</translation>
2348 </message> 2360 </message>
2349 <message> 2361 <message>
2350 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="100"/> 2362 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="100"/>
2351 <source>Input Device</source> 2363 <source>Input Device</source>
2352 <translation>Invoer Apparaat</translation> 2364 <translation>Invoerapparaat</translation>
2353 </message> 2365 </message>
2354 <message> 2366 <message>
2355 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="137"/> 2367 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="137"/>
@@ -2385,7 +2397,7 @@ This would ban both their forum username and their IP address.</source>
2385 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2564"/> 2397 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2564"/>
2386 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2603"/> 2398 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2603"/>
2387 <source>Up</source> 2399 <source>Up</source>
2388 <translation>Boven:</translation> 2400 <translation>Omhoog</translation>
2389 </message> 2401 </message>
2390 <message> 2402 <message>
2391 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="403"/> 2403 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="403"/>
@@ -2396,7 +2408,7 @@ This would ban both their forum username and their IP address.</source>
2396 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2634"/> 2408 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2634"/>
2397 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2673"/> 2409 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2673"/>
2398 <source>Left</source> 2410 <source>Left</source>
2399 <translation>Links:</translation> 2411 <translation>Links</translation>
2400 </message> 2412 </message>
2401 <message> 2413 <message>
2402 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="452"/> 2414 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="452"/>
@@ -2407,7 +2419,7 @@ This would ban both their forum username and their IP address.</source>
2407 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2683"/> 2419 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2683"/>
2408 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2722"/> 2420 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2722"/>
2409 <source>Right</source> 2421 <source>Right</source>
2410 <translation>Rechts:</translation> 2422 <translation>Rechts</translation>
2411 </message> 2423 </message>
2412 <message> 2424 <message>
2413 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="534"/> 2425 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="534"/>
@@ -2417,7 +2429,7 @@ This would ban both their forum username and their IP address.</source>
2417 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2765"/> 2429 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2765"/>
2418 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2804"/> 2430 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2804"/>
2419 <source>Down</source> 2431 <source>Down</source>
2420 <translation>Beneden:</translation> 2432 <translation>Omlaag</translation>
2421 </message> 2433 </message>
2422 <message> 2434 <message>
2423 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="604"/> 2435 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="604"/>
@@ -2425,7 +2437,7 @@ This would ban both their forum username and their IP address.</source>
2425 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2835"/> 2437 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2835"/>
2426 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2874"/> 2438 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2874"/>
2427 <source>Pressed</source> 2439 <source>Pressed</source>
2428 <translation>Ingedrukt:</translation> 2440 <translation>Ingedrukt</translation>
2429 </message> 2441 </message>
2430 <message> 2442 <message>
2431 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="653"/> 2443 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="653"/>
@@ -2433,13 +2445,13 @@ This would ban both their forum username and their IP address.</source>
2433 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2884"/> 2445 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2884"/>
2434 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/> 2446 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2923"/>
2435 <source>Modifier</source> 2447 <source>Modifier</source>
2436 <translation>Modificatie:</translation> 2448 <translation>Modificator</translation>
2437 </message> 2449 </message>
2438 <message> 2450 <message>
2439 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="702"/> 2451 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="702"/>
2440 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2933"/> 2452 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2933"/>
2441 <source>Range</source> 2453 <source>Range</source>
2442 <translation>Berijk</translation> 2454 <translation>Bereik</translation>
2443 </message> 2455 </message>
2444 <message> 2456 <message>
2445 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="735"/> 2457 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="735"/>
@@ -2457,7 +2469,7 @@ This would ban both their forum username and their IP address.</source>
2457 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="802"/> 2469 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="802"/>
2458 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="3030"/> 2470 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="3030"/>
2459 <source>Modifier Range: 0%</source> 2471 <source>Modifier Range: 0%</source>
2460 <translation>Bewerk Range: 0%</translation> 2472 <translation>Modificatorbereik: 0%</translation>
2461 </message> 2473 </message>
2462 <message> 2474 <message>
2463 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="848"/> 2475 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="848"/>
@@ -2495,13 +2507,13 @@ This would ban both their forum username and their IP address.</source>
2495 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1565"/> 2507 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1565"/>
2496 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1310"/> 2508 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1310"/>
2497 <source>Plus</source> 2509 <source>Plus</source>
2498 <translation>Plus:</translation> 2510 <translation>Plus</translation>
2499 </message> 2511 </message>
2500 <message> 2512 <message>
2501 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1575"/> 2513 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1575"/>
2502 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1614"/> 2514 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1614"/>
2503 <source>Home</source> 2515 <source>Home</source>
2504 <translation>Home:</translation> 2516 <translation>Home</translation>
2505 </message> 2517 </message>
2506 <message> 2518 <message>
2507 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1679"/> 2519 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1679"/>
@@ -2509,7 +2521,7 @@ This would ban both their forum username and their IP address.</source>
2509 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1313"/> 2521 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1313"/>
2510 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1320"/> 2522 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1320"/>
2511 <source>R</source> 2523 <source>R</source>
2512 <translation>R:</translation> 2524 <translation>R</translation>
2513 </message> 2525 </message>
2514 <message> 2526 <message>
2515 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/> 2527 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1734"/>
@@ -2543,7 +2555,7 @@ This would ban both their forum username and their IP address.</source>
2543 <message> 2555 <message>
2544 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2151"/> 2556 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2151"/>
2545 <source>Face Buttons</source> 2557 <source>Face Buttons</source>
2546 <translation>Gezicht Knoppen</translation> 2558 <translation>Gezichtsknoppen</translation>
2547 </message> 2559 </message>
2548 <message> 2560 <message>
2549 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2209"/> 2561 <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2209"/>
@@ -2581,7 +2593,7 @@ This would ban both their forum username and their IP address.</source>
2581 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="556"/> 2593 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="556"/>
2582 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="651"/> 2594 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="651"/>
2583 <source>Clear</source> 2595 <source>Clear</source>
2584 <translation>Verwijder</translation> 2596 <translation>Wis</translation>
2585 </message> 2597 </message>
2586 <message> 2598 <message>
2587 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="384"/> 2599 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="384"/>
@@ -2596,64 +2608,64 @@ This would ban both their forum username and their IP address.</source>
2596 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="387"/> 2608 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="387"/>
2597 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="665"/> 2609 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="665"/>
2598 <source>Invert button</source> 2610 <source>Invert button</source>
2599 <translation type="unfinished"/> 2611 <translation>Knop omkeren</translation>
2600 </message> 2612 </message>
2601 <message> 2613 <message>
2602 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="393"/> 2614 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="393"/>
2603 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="656"/> 2615 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="656"/>
2604 <source>Toggle button</source> 2616 <source>Toggle button</source>
2605 <translation>Shakel Knop</translation> 2617 <translation>Schakel-knop</translation>
2606 </message> 2618 </message>
2607 <message> 2619 <message>
2608 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="399"/> 2620 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="399"/>
2609 <source>Turbo button</source> 2621 <source>Turbo button</source>
2610 <translation type="unfinished"/> 2622 <translation>Turbo-knop</translation>
2611 </message> 2623 </message>
2612 <message> 2624 <message>
2613 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="407"/> 2625 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="407"/>
2614 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="607"/> 2626 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="607"/>
2615 <source>Invert axis</source> 2627 <source>Invert axis</source>
2616 <translation>Spiegel As</translation> 2628 <translation>Spiegel as</translation>
2617 </message> 2629 </message>
2618 <message> 2630 <message>
2619 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="413"/> 2631 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="413"/>
2620 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="417"/> 2632 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="417"/>
2621 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="470"/> 2633 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="470"/>
2622 <source>Set threshold</source> 2634 <source>Set threshold</source>
2623 <translation type="unfinished"/> 2635 <translation>Stel drempel in</translation>
2624 </message> 2636 </message>
2625 <message> 2637 <message>
2626 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="417"/> 2638 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="417"/>
2627 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="470"/> 2639 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="470"/>
2628 <source>Choose a value between 0% and 100%</source> 2640 <source>Choose a value between 0% and 100%</source>
2629 <translation type="unfinished"/> 2641 <translation>Kies een waarde tussen 0% en 100%</translation>
2630 </message> 2642 </message>
2631 <message> 2643 <message>
2632 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="429"/> 2644 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="429"/>
2633 <source>Toggle axis</source> 2645 <source>Toggle axis</source>
2634 <translation type="unfinished"/> 2646 <translation>Schakel as</translation>
2635 </message> 2647 </message>
2636 <message> 2648 <message>
2637 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="466"/> 2649 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="466"/>
2638 <source>Set gyro threshold</source> 2650 <source>Set gyro threshold</source>
2639 <translation type="unfinished"/> 2651 <translation>Stel gyro-drempel in</translation>
2640 </message> 2652 </message>
2641 <message> 2653 <message>
2642 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="512"/> 2654 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="512"/>
2643 <source>Map Analog Stick</source> 2655 <source>Map Analog Stick</source>
2644 <translation>Zet Analoge Stick</translation> 2656 <translation> Analoge Stick Toewijzen</translation>
2645 </message> 2657 </message>
2646 <message> 2658 <message>
2647 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="513"/> 2659 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="513"/>
2648 <source>After pressing OK, first move your joystick horizontally, and then vertically. 2660 <source>After pressing OK, first move your joystick horizontally, and then vertically.
2649To invert the axes, first move your joystick vertically, and then horizontally.</source> 2661To invert the axes, first move your joystick vertically, and then horizontally.</source>
2650 <translation>Na OK in te drukken, beweeg je joystick eerst horizontaal en dan verticaal. 2662 <translation>Nadat je op OK hebt gedrukt, beweeg je de joystick eerst horizontaal en vervolgens verticaal.
2651Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.</translation> 2663Om de assen om te keren, beweeg je de joystick eerst verticaal en vervolgens horizontaal.</translation>
2652 </message> 2664 </message>
2653 <message> 2665 <message>
2654 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="581"/> 2666 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="581"/>
2655 <source>Center axis</source> 2667 <source>Center axis</source>
2656 <translation type="unfinished"/> 2668 <translation>Midden as</translation>
2657 </message> 2669 </message>
2658 <message> 2670 <message>
2659 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="689"/> 2671 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="689"/>
@@ -2665,7 +2677,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2665 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="698"/> 2677 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="698"/>
2666 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1044"/> 2678 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1044"/>
2667 <source>Modifier Range: %1%</source> 2679 <source>Modifier Range: %1%</source>
2668 <translation>Bewerk Range: %1%</translation> 2680 <translation>Modificatorbereik: %1%</translation>
2669 </message> 2681 </message>
2670 <message> 2682 <message>
2671 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="724"/> 2683 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="724"/>
@@ -2691,42 +2703,42 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2691 <message> 2703 <message>
2692 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1085"/> 2704 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1085"/>
2693 <source>Handheld</source> 2705 <source>Handheld</source>
2694 <translation>Mobiel</translation> 2706 <translation>Handheld</translation>
2695 </message> 2707 </message>
2696 <message> 2708 <message>
2697 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1089"/> 2709 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1089"/>
2698 <source>GameCube Controller</source> 2710 <source>GameCube Controller</source>
2699 <translation>GameCube Controller</translation> 2711 <translation>GameCube-controller</translation>
2700 </message> 2712 </message>
2701 <message> 2713 <message>
2702 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1098"/> 2714 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1098"/>
2703 <source>Poke Ball Plus</source> 2715 <source>Poke Ball Plus</source>
2704 <translation type="unfinished"/> 2716 <translation>Poke Ball Plus</translation>
2705 </message> 2717 </message>
2706 <message> 2718 <message>
2707 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1102"/> 2719 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1102"/>
2708 <source>NES Controller</source> 2720 <source>NES Controller</source>
2709 <translation type="unfinished"/> 2721 <translation>NES-controller</translation>
2710 </message> 2722 </message>
2711 <message> 2723 <message>
2712 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1106"/> 2724 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1106"/>
2713 <source>SNES Controller</source> 2725 <source>SNES Controller</source>
2714 <translation type="unfinished"/> 2726 <translation>SNES-controller</translation>
2715 </message> 2727 </message>
2716 <message> 2728 <message>
2717 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1110"/> 2729 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1110"/>
2718 <source>N64 Controller</source> 2730 <source>N64 Controller</source>
2719 <translation type="unfinished"/> 2731 <translation>N64-controller</translation>
2720 </message> 2732 </message>
2721 <message> 2733 <message>
2722 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1114"/> 2734 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1114"/>
2723 <source>Sega Genesis</source> 2735 <source>Sega Genesis</source>
2724 <translation type="unfinished"/> 2736 <translation>Sega Genesis</translation>
2725 </message> 2737 </message>
2726 <message> 2738 <message>
2727 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1318"/> 2739 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1318"/>
2728 <source>Start / Pause</source> 2740 <source>Start / Pause</source>
2729 <translation>Start / Pauze</translation> 2741 <translation>Begin / Onderbreken</translation>
2730 </message> 2742 </message>
2731 <message> 2743 <message>
2732 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1321"/> 2744 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1321"/>
@@ -2746,7 +2758,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2746 <message> 2758 <message>
2747 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1424"/> 2759 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1424"/>
2748 <source>Shake!</source> 2760 <source>Shake!</source>
2749 <translation>Shudden!</translation> 2761 <translation>Schud!</translation>
2750 </message> 2762 </message>
2751 <message> 2763 <message>
2752 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1426"/> 2764 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1426"/>
@@ -2761,53 +2773,53 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2761 <message> 2773 <message>
2762 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1521"/> 2774 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1521"/>
2763 <source>Enter a profile name:</source> 2775 <source>Enter a profile name:</source>
2764 <translation>Voer nieuwe gebruikersnaam in:</translation> 2776 <translation>Voer een profielnaam in:</translation>
2765 </message> 2777 </message>
2766 <message> 2778 <message>
2767 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1529"/> 2779 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1529"/>
2768 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1537"/> 2780 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1537"/>
2769 <source>Create Input Profile</source> 2781 <source>Create Input Profile</source>
2770 <translation>Creëer een nieuw Invoer Profiel</translation> 2782 <translation>Maak Invoerprofiel</translation>
2771 </message> 2783 </message>
2772 <message> 2784 <message>
2773 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1530"/> 2785 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1530"/>
2774 <source>The given profile name is not valid!</source> 2786 <source>The given profile name is not valid!</source>
2775 <translation>De ingevoerde Profiel naam is niet geldig</translation> 2787 <translation>De ingevoerde profielnaam is niet geldig!</translation>
2776 </message> 2788 </message>
2777 <message> 2789 <message>
2778 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1538"/> 2790 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1538"/>
2779 <source>Failed to create the input profile &quot;%1&quot;</source> 2791 <source>Failed to create the input profile &quot;%1&quot;</source>
2780 <translation>Het is mislukt om Invoer Profiel &quot;%1 te Creëer</translation> 2792 <translation>Kon invoerprofiel &quot;%1&quot; niet maken</translation>
2781 </message> 2793 </message>
2782 <message> 2794 <message>
2783 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1558"/> 2795 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1558"/>
2784 <source>Delete Input Profile</source> 2796 <source>Delete Input Profile</source>
2785 <translation>Verwijder invoer profiel</translation> 2797 <translation>Verwijder Invoerprofiel</translation>
2786 </message> 2798 </message>
2787 <message> 2799 <message>
2788 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1559"/> 2800 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1559"/>
2789 <source>Failed to delete the input profile &quot;%1&quot;</source> 2801 <source>Failed to delete the input profile &quot;%1&quot;</source>
2790 <translation>Het is mislukt om Invoer Profiel &quot;%1 te Verwijderen</translation> 2802 <translation>Kon invoerprofiel &quot;%1&quot; niet verwijderen</translation>
2791 </message> 2803 </message>
2792 <message> 2804 <message>
2793 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1581"/> 2805 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1581"/>
2794 <source>Load Input Profile</source> 2806 <source>Load Input Profile</source>
2795 <translation>Laad invoer profiel</translation> 2807 <translation>Laad Invoerprofiel</translation>
2796 </message> 2808 </message>
2797 <message> 2809 <message>
2798 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1582"/> 2810 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1582"/>
2799 <source>Failed to load the input profile &quot;%1&quot;</source> 2811 <source>Failed to load the input profile &quot;%1&quot;</source>
2800 <translation>Het is mislukt om Invoer Profiel &quot;%1 te Laden</translation> 2812 <translation>Kon invoerprofiel &quot;%1&quot; niet laden</translation>
2801 </message> 2813 </message>
2802 <message> 2814 <message>
2803 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1607"/> 2815 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1607"/>
2804 <source>Save Input Profile</source> 2816 <source>Save Input Profile</source>
2805 <translation>Sla Invoer profiel op</translation> 2817 <translation>Sla Invoerprofiel op</translation>
2806 </message> 2818 </message>
2807 <message> 2819 <message>
2808 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1608"/> 2820 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1608"/>
2809 <source>Failed to save the input profile &quot;%1&quot;</source> 2821 <source>Failed to save the input profile &quot;%1&quot;</source>
2810 <translation>Het is mislukt om Invoer Profiel &quot;%1 Op te slaan</translation> 2822 <translation>Kon invoerprofiel &quot;%1&quot; niet opslaan</translation>
2811 </message> 2823 </message>
2812</context> 2824</context>
2813<context> 2825<context>
@@ -2815,12 +2827,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2815 <message> 2827 <message>
2816 <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="14"/> 2828 <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="14"/>
2817 <source>Create Input Profile</source> 2829 <source>Create Input Profile</source>
2818 <translation>Maak Invoer Profiel</translation> 2830 <translation>Maak Invoerprofiel</translation>
2819 </message> 2831 </message>
2820 <message> 2832 <message>
2821 <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="40"/> 2833 <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="40"/>
2822 <source>Clear</source> 2834 <source>Clear</source>
2823 <translation>Verwijder</translation> 2835 <translation>Wis</translation>
2824 </message> 2836 </message>
2825 <message> 2837 <message>
2826 <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="47"/> 2838 <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="47"/>
@@ -2843,7 +2855,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2843 <message> 2855 <message>
2844 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="23"/> 2856 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="23"/>
2845 <source>UDP Calibration:</source> 2857 <source>UDP Calibration:</source>
2846 <translation>UDP Calibratie:</translation> 2858 <translation>UDP-calibratie:</translation>
2847 </message> 2859 </message>
2848 <message> 2860 <message>
2849 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="30"/> 2861 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="30"/>
@@ -2860,17 +2872,17 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2860 <message> 2872 <message>
2861 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="57"/> 2873 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="57"/>
2862 <source>Touch from button profile:</source> 2874 <source>Touch from button profile:</source>
2863 <translation type="unfinished"/> 2875 <translation>Raak van knop-profiel:</translation>
2864 </message> 2876 </message>
2865 <message> 2877 <message>
2866 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="85"/> 2878 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="85"/>
2867 <source>CemuhookUDP Config</source> 2879 <source>CemuhookUDP Config</source>
2868 <translation>CemuhookUDP Configuratie</translation> 2880 <translation>CemuhookUDP-configuratie</translation>
2869 </message> 2881 </message>
2870 <message> 2882 <message>
2871 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="91"/> 2883 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="91"/>
2872 <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source> 2884 <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source>
2873 <translation>U kunt elke Cemuhook-compatibele UDP-invoerbron gebruiken voor bewegings- en aanraakinvoer.</translation> 2885 <translation>Je kunt elke Cemuhook-compatibele UDP-invoerbron gebruiken om beweging en aanraking in te voeren.</translation>
2874 </message> 2886 </message>
2875 <message> 2887 <message>
2876 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="134"/> 2888 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="134"/>
@@ -2885,7 +2897,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2885 <message> 2897 <message>
2886 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="188"/> 2898 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="188"/>
2887 <source>Learn More</source> 2899 <source>Learn More</source>
2888 <translation>Leer Meer</translation> 2900 <translation>Meer Info</translation>
2889 </message> 2901 </message>
2890 <message> 2902 <message>
2891 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="201"/> 2903 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="201"/>
@@ -2901,12 +2913,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2901 <message> 2913 <message>
2902 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/> 2914 <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/>
2903 <source>Remove Server</source> 2915 <source>Remove Server</source>
2904 <translation>Externe Server</translation> 2916 <translation>Verwijder Server</translation>
2905 </message> 2917 </message>
2906 <message> 2918 <message>
2907 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="87"/> 2919 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="87"/>
2908 <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source> 2920 <source>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn More&lt;/span&gt;&lt;/a&gt;</source>
2909 <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Leer Meer&lt;/span&gt;&lt;/a&gt;</translation> 2921 <translation>&lt;a href=&apos;https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Meer Info&lt;/span&gt;&lt;/a&gt;</translation>
2910 </message> 2922 </message>
2911 <message> 2923 <message>
2912 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="168"/> 2924 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="168"/>
@@ -2921,7 +2933,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2921 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="193"/> 2933 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="193"/>
2922 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="287"/> 2934 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="287"/>
2923 <source>yuzu</source> 2935 <source>yuzu</source>
2924 <translation>Yuzu</translation> 2936 <translation>yuzu</translation>
2925 </message> 2937 </message>
2926 <message> 2938 <message>
2927 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="173"/> 2939 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="173"/>
@@ -2936,12 +2948,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2936 <message> 2948 <message>
2937 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="181"/> 2949 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="181"/>
2938 <source>IP address is not valid</source> 2950 <source>IP address is not valid</source>
2939 <translation>IP adress is niet geldig</translation> 2951 <translation>IP-adress is niet geldig</translation>
2940 </message> 2952 </message>
2941 <message> 2953 <message>
2942 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="187"/> 2954 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="187"/>
2943 <source>This UDP server already exists</source> 2955 <source>This UDP server already exists</source>
2944 <translation>Deze UDP server bestaat al</translation> 2956 <translation>Deze UDP-server bestaat al</translation>
2945 </message> 2957 </message>
2946 <message> 2958 <message>
2947 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="193"/> 2959 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="193"/>
@@ -2961,7 +2973,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2961 <message> 2973 <message>
2962 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="256"/> 2974 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="256"/>
2963 <source>Test Successful</source> 2975 <source>Test Successful</source>
2964 <translation>Test Succesvol</translation> 2976 <translation>Test Succesvol</translation>
2965 </message> 2977 </message>
2966 <message> 2978 <message>
2967 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="257"/> 2979 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="257"/>
@@ -2976,12 +2988,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2976 <message> 2988 <message>
2977 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="260"/> 2989 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="260"/>
2978 <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source> 2990 <source>Could not receive valid data from the server.&lt;br&gt;Please verify that the server is set up correctly and the address and port are correct.</source>
2979 <translation>Kan niet de juiste data van de server ontvangen.&lt;br&gt;Verifieer dat de server is goed opgezet en dat het adres en poort correct zijn.</translation> 2991 <translation>Kan niet de juiste data van de server ontvangen.&lt;br&gt;Controleer of de server correct is ingesteld en of het adres en de poort correct zijn.</translation>
2980 </message> 2992 </message>
2981 <message> 2993 <message>
2982 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="288"/> 2994 <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="288"/>
2983 <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source> 2995 <source>UDP Test or calibration configuration is in progress.&lt;br&gt;Please wait for them to finish.</source>
2984 <translation>UDP Test of calibratie configuratie is bezig.&lt;br&gt;Wacht alstublieft totdat het voltooid is.</translation> 2996 <translation>UDP-test of kalibratieconfiguratie is bezig.&lt;br&gt;Wacht tot ze klaar zijn.</translation>
2985 </message> 2997 </message>
2986</context> 2998</context>
2987<context> 2999<context>
@@ -2989,12 +3001,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
2989 <message> 3001 <message>
2990 <location filename="../../src/yuzu/configuration/configure_network.ui" line="14"/> 3002 <location filename="../../src/yuzu/configuration/configure_network.ui" line="14"/>
2991 <source>Form</source> 3003 <source>Form</source>
2992 <translation>Formulier</translation> 3004 <translation>Vorm</translation>
2993 </message> 3005 </message>
2994 <message> 3006 <message>
2995 <location filename="../../src/yuzu/configuration/configure_network.ui" line="17"/> 3007 <location filename="../../src/yuzu/configuration/configure_network.ui" line="17"/>
2996 <source>Network</source> 3008 <source>Network</source>
2997 <translation type="unfinished"/> 3009 <translation>Netwerk</translation>
2998 </message> 3010 </message>
2999 <message> 3011 <message>
3000 <location filename="../../src/yuzu/configuration/configure_network.ui" line="25"/> 3012 <location filename="../../src/yuzu/configuration/configure_network.ui" line="25"/>
@@ -3004,7 +3016,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3004 <message> 3016 <message>
3005 <location filename="../../src/yuzu/configuration/configure_network.ui" line="34"/> 3017 <location filename="../../src/yuzu/configuration/configure_network.ui" line="34"/>
3006 <source>Network Interface</source> 3018 <source>Network Interface</source>
3007 <translation type="unfinished"/> 3019 <translation>Netwerkinterface</translation>
3008 </message> 3020 </message>
3009 <message> 3021 <message>
3010 <location filename="../../src/yuzu/configuration/configure_network.cpp" line="15"/> 3022 <location filename="../../src/yuzu/configuration/configure_network.cpp" line="15"/>
@@ -3032,7 +3044,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3032 <message> 3044 <message>
3033 <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="92"/> 3045 <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="92"/>
3034 <source>Title ID</source> 3046 <source>Title ID</source>
3035 <translation>Titel ID</translation> 3047 <translation>Titel-ID</translation>
3036 </message> 3048 </message>
3037 <message> 3049 <message>
3038 <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="129"/> 3050 <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="129"/>
@@ -3082,22 +3094,22 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3082 <message> 3094 <message>
3083 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="62"/> 3095 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="62"/>
3084 <source>Graphics</source> 3096 <source>Graphics</source>
3085 <translation>Grafisch</translation> 3097 <translation>Graphics</translation>
3086 </message> 3098 </message>
3087 <message> 3099 <message>
3088 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="63"/> 3100 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="63"/>
3089 <source>Adv. Graphics</source> 3101 <source>Adv. Graphics</source>
3090 <translation>Adv. Grafisch</translation> 3102 <translation>Adv. Graphics</translation>
3091 </message> 3103 </message>
3092 <message> 3104 <message>
3093 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="64"/> 3105 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="64"/>
3094 <source>Audio</source> 3106 <source>Audio</source>
3095 <translation>Geluid</translation> 3107 <translation>Audio</translation>
3096 </message> 3108 </message>
3097 <message> 3109 <message>
3098 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="65"/> 3110 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="65"/>
3099 <source>Input Profiles</source> 3111 <source>Input Profiles</source>
3100 <translation type="unfinished"/> 3112 <translation>Invoerprofielen</translation>
3101 </message> 3113 </message>
3102 <message> 3114 <message>
3103 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="68"/> 3115 <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="68"/>
@@ -3115,7 +3127,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3115 <message> 3127 <message>
3116 <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/> 3128 <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/>
3117 <source>Form</source> 3129 <source>Form</source>
3118 <translation>Formulier</translation> 3130 <translation>Vorm</translation>
3119 </message> 3131 </message>
3120 <message> 3132 <message>
3121 <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="17"/> 3133 <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="17"/>
@@ -3125,7 +3137,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3125 <message> 3137 <message>
3126 <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="46"/> 3138 <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="46"/>
3127 <source>Patch Name</source> 3139 <source>Patch Name</source>
3128 <translation>Patch Naam</translation> 3140 <translation>Patch-naam</translation>
3129 </message> 3141 </message>
3130 <message> 3142 <message>
3131 <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="47"/> 3143 <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="47"/>
@@ -3148,7 +3160,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3148 <message> 3160 <message>
3149 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="25"/> 3161 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="25"/>
3150 <source>Profile Manager</source> 3162 <source>Profile Manager</source>
3151 <translation>Profiel Beheer</translation> 3163 <translation>Profielbeheer</translation>
3152 </message> 3164 </message>
3153 <message> 3165 <message>
3154 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="42"/> 3166 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="42"/>
@@ -3163,12 +3175,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3163 <message> 3175 <message>
3164 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="116"/> 3176 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="116"/>
3165 <source>Set Image</source> 3177 <source>Set Image</source>
3166 <translation>Selecteer Afbeelding</translation> 3178 <translation>Stel Afbeelding In</translation>
3167 </message> 3179 </message>
3168 <message> 3180 <message>
3169 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="136"/> 3181 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="136"/>
3170 <source>Add</source> 3182 <source>Add</source>
3171 <translation>Voeg Toe</translation> 3183 <translation>Toevoegen</translation>
3172 </message> 3184 </message>
3173 <message> 3185 <message>
3174 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="146"/> 3186 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="146"/>
@@ -3183,7 +3195,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3183 <message> 3195 <message>
3184 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="168"/> 3196 <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="168"/>
3185 <source>Profile management is available only when game is not running.</source> 3197 <source>Profile management is available only when game is not running.</source>
3186 <translation>Profiel beheer is alleen beschikbaar wanneer het spel niet bezig is.</translation> 3198 <translation>Profielbeheer is alleen beschikbaar wanneer het spel niet bezig is.</translation>
3187 </message> 3199 </message>
3188 <message> 3200 <message>
3189 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="55"/> 3201 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="55"/>
@@ -3196,7 +3208,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3196 <message> 3208 <message>
3197 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="73"/> 3209 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="73"/>
3198 <source>Enter Username</source> 3210 <source>Enter Username</source>
3199 <translation>Voer een Gebruikersnaam in</translation> 3211 <translation>Voer Gebruikersnaam in</translation>
3200 </message> 3212 </message>
3201 <message> 3213 <message>
3202 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="139"/> 3214 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="139"/>
@@ -3216,12 +3228,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3216 <message> 3228 <message>
3217 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="271"/> 3229 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="271"/>
3218 <source>Select User Image</source> 3230 <source>Select User Image</source>
3219 <translation>Selecteer gebruiker&apos;s foto</translation> 3231 <translation>Selecteer Gebruikersfoto</translation>
3220 </message> 3232 </message>
3221 <message> 3233 <message>
3222 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="272"/> 3234 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="272"/>
3223 <source>JPEG Images (*.jpg *.jpeg)</source> 3235 <source>JPEG Images (*.jpg *.jpeg)</source>
3224 <translation>JPEG foto&apos;s (*.jpg *.jpeg)</translation> 3236 <translation>JPEG-foto&apos;s (*.jpg *.jpeg)</translation>
3225 </message> 3237 </message>
3226 <message> 3238 <message>
3227 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="281"/> 3239 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="281"/>
@@ -3266,12 +3278,12 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3266 <message> 3278 <message>
3267 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="314"/> 3279 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="314"/>
3268 <source>Error resizing user image</source> 3280 <source>Error resizing user image</source>
3269 <translation type="unfinished"/> 3281 <translation>Fout bij het aanpassen van grootte van gebruikersafbeelding</translation>
3270 </message> 3282 </message>
3271 <message> 3283 <message>
3272 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="315"/> 3284 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="315"/>
3273 <source>Unable to resize image</source> 3285 <source>Unable to resize image</source>
3274 <translation type="unfinished"/> 3286 <translation>Kon de grootte van de afbeelding niet wijzigen</translation>
3275 </message> 3287 </message>
3276</context> 3288</context>
3277<context> 3289<context>
@@ -3279,7 +3291,7 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3279 <message> 3291 <message>
3280 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="332"/> 3292 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="332"/>
3281 <source>Delete this user? All of the user&apos;s save data will be deleted.</source> 3293 <source>Delete this user? All of the user&apos;s save data will be deleted.</source>
3282 <translation type="unfinished"/> 3294 <translation>Deze gebruiker verwijderen? Alle opgeslagen gegevens van de gebruiker worden verwijderd.</translation>
3283 </message> 3295 </message>
3284 <message> 3296 <message>
3285 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="344"/> 3297 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="344"/>
@@ -3290,7 +3302,8 @@ Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.
3290 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="360"/> 3302 <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="360"/>
3291 <source>Name: %1 3303 <source>Name: %1
3292UUID: %2</source> 3304UUID: %2</source>
3293 <translation type="unfinished"/> 3305 <translation>Naam: %1
3306UUID: %2</translation>
3294 </message> 3307 </message>
3295</context> 3308</context>
3296<context> 3309<context>
@@ -3298,29 +3311,29 @@ UUID: %2</source>
3298 <message> 3311 <message>
3299 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="14"/> 3312 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="14"/>
3300 <source>Configure Ring Controller</source> 3313 <source>Configure Ring Controller</source>
3301 <translation type="unfinished"/> 3314 <translation>Configureer Ring-controller</translation>
3302 </message> 3315 </message>
3303 <message> 3316 <message>
3304 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="26"/> 3317 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="26"/>
3305 <source>If you want to use this controller configure player 1 as right controller and player 2 as dual joycon before starting the game to allow this controller to be detected properly.</source> 3318 <source>If you want to use this controller configure player 1 as right controller and player 2 as dual joycon before starting the game to allow this controller to be detected properly.</source>
3306 <translation type="unfinished"/> 3319 <translation>Als je deze controller wilt gebruiken, configureer dan speler 1 als rechter controller en speler 2 als dual joycon voordat je het spel start, zodat deze controller goed wordt gedetecteerd.</translation>
3307 </message> 3320 </message>
3308 <message> 3321 <message>
3309 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="52"/> 3322 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="52"/>
3310 <source>Virtual Ring Sensor Parameters</source> 3323 <source>Virtual Ring Sensor Parameters</source>
3311 <translation type="unfinished"/> 3324 <translation>Parameters Virtuele Ringsensor</translation>
3312 </message> 3325 </message>
3313 <message> 3326 <message>
3314 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/> 3327 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/>
3315 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="123"/> 3328 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="123"/>
3316 <source>Pull</source> 3329 <source>Pull</source>
3317 <translation type="unfinished"/> 3330 <translation>Trek</translation>
3318 </message> 3331 </message>
3319 <message> 3332 <message>
3320 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="133"/> 3333 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="133"/>
3321 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="172"/> 3334 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="172"/>
3322 <source>Push</source> 3335 <source>Push</source>
3323 <translation type="unfinished"/> 3336 <translation>Duw</translation>
3324 </message> 3337 </message>
3325 <message> 3338 <message>
3326 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="206"/> 3339 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="206"/>
@@ -3330,29 +3343,29 @@ UUID: %2</source>
3330 <message> 3343 <message>
3331 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="233"/> 3344 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="233"/>
3332 <source>Direct Joycon Driver</source> 3345 <source>Direct Joycon Driver</source>
3333 <translation type="unfinished"/> 3346 <translation>Direct Joycon-driver</translation>
3334 </message> 3347 </message>
3335 <message> 3348 <message>
3336 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="293"/> 3349 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="293"/>
3337 <source>Enable Ring Input</source> 3350 <source>Enable Ring Input</source>
3338 <translation type="unfinished"/> 3351 <translation>Schakel Ringinvoer in</translation>
3339 </message> 3352 </message>
3340 <message> 3353 <message>
3341 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/> 3354 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/>
3342 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/> 3355 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/>
3343 <source>Enable</source> 3356 <source>Enable</source>
3344 <translation type="unfinished"/> 3357 <translation>Inschakelen</translation>
3345 </message> 3358 </message>
3346 <message> 3359 <message>
3347 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/> 3360 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/>
3348 <source>Ring Sensor Value</source> 3361 <source>Ring Sensor Value</source>
3349 <translation type="unfinished"/> 3362 <translation>Ringsensorwaarde</translation>
3350 </message> 3363 </message>
3351 <message> 3364 <message>
3352 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="314"/> 3365 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="314"/>
3353 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="282"/> 3366 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="282"/>
3354 <source>Not connected</source> 3367 <source>Not connected</source>
3355 <translation type="unfinished"/> 3368 <translation>Niet verbonden</translation>
3356 </message> 3369 </message>
3357 <message> 3370 <message>
3358 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="344"/> 3371 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="344"/>
@@ -3362,7 +3375,7 @@ UUID: %2</source>
3362 <message> 3375 <message>
3363 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="168"/> 3376 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="168"/>
3364 <source>Clear</source> 3377 <source>Clear</source>
3365 <translation>Verwijder</translation> 3378 <translation>Wis</translation>
3366 </message> 3379 </message>
3367 <message> 3380 <message>
3368 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="170"/> 3381 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="170"/>
@@ -3372,7 +3385,7 @@ UUID: %2</source>
3372 <message> 3385 <message>
3373 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="172"/> 3386 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="172"/>
3374 <source>Invert axis</source> 3387 <source>Invert axis</source>
3375 <translation>Spiegel As</translation> 3388 <translation>Spiegel as</translation>
3376 </message> 3389 </message>
3377 <message> 3390 <message>
3378 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="191"/> 3391 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="191"/>
@@ -3383,12 +3396,12 @@ UUID: %2</source>
3383 <message> 3396 <message>
3384 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="279"/> 3397 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="279"/>
3385 <source>Error enabling ring input</source> 3398 <source>Error enabling ring input</source>
3386 <translation type="unfinished"/> 3399 <translation>Fout tijdens inschakelen van ringinvoer</translation>
3387 </message> 3400 </message>
3388 <message> 3401 <message>
3389 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="285"/> 3402 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="285"/>
3390 <source>Direct Joycon driver is not enabled</source> 3403 <source>Direct Joycon driver is not enabled</source>
3391 <translation type="unfinished"/> 3404 <translation>Direct Joycon-driver niet ingeschakeld</translation>
3392 </message> 3405 </message>
3393 <message> 3406 <message>
3394 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="290"/> 3407 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="290"/>
@@ -3398,17 +3411,17 @@ UUID: %2</source>
3398 <message> 3411 <message>
3399 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="302"/> 3412 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="302"/>
3400 <source>The current mapped device doesn&apos;t support the ring controller</source> 3413 <source>The current mapped device doesn&apos;t support the ring controller</source>
3401 <translation type="unfinished"/> 3414 <translation>Het huidige apparaat ondersteunt de ringcontroller niet</translation>
3402 </message> 3415 </message>
3403 <message> 3416 <message>
3404 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="306"/> 3417 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="306"/>
3405 <source>The current mapped device doesn&apos;t have a ring attached</source> 3418 <source>The current mapped device doesn&apos;t have a ring attached</source>
3406 <translation type="unfinished"/> 3419 <translation>Het huidige apparaat heeft geen ring</translation>
3407 </message> 3420 </message>
3408 <message> 3421 <message>
3409 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="310"/> 3422 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="310"/>
3410 <source>Unexpected driver result %1</source> 3423 <source>Unexpected driver result %1</source>
3411 <translation type="unfinished"/> 3424 <translation>Onverwacht driverresultaat %1</translation>
3412 </message> 3425 </message>
3413 <message> 3426 <message>
3414 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="333"/> 3427 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="333"/>
@@ -3441,7 +3454,7 @@ UUID: %2</source>
3441 <message> 3454 <message>
3442 <location filename="../../src/yuzu/configuration/configure_system.ui" line="41"/> 3455 <location filename="../../src/yuzu/configuration/configure_system.ui" line="41"/>
3443 <source>Auto</source> 3456 <source>Auto</source>
3444 <translation>Automatisch</translation> 3457 <translation>Auto</translation>
3445 </message> 3458 </message>
3446 <message> 3459 <message>
3447 <location filename="../../src/yuzu/configuration/configure_system.ui" line="46"/> 3460 <location filename="../../src/yuzu/configuration/configure_system.ui" line="46"/>
@@ -3702,12 +3715,12 @@ UUID: %2</source>
3702 <message> 3715 <message>
3703 <location filename="../../src/yuzu/configuration/configure_system.ui" line="313"/> 3716 <location filename="../../src/yuzu/configuration/configure_system.ui" line="313"/>
3704 <source>Time Zone:</source> 3717 <source>Time Zone:</source>
3705 <translation>Tijd Zone:</translation> 3718 <translation>Tijdzone:</translation>
3706 </message> 3719 </message>
3707 <message> 3720 <message>
3708 <location filename="../../src/yuzu/configuration/configure_system.ui" line="320"/> 3721 <location filename="../../src/yuzu/configuration/configure_system.ui" line="320"/>
3709 <source>Note: this can be overridden when region setting is auto-select</source> 3722 <source>Note: this can be overridden when region setting is auto-select</source>
3710 <translation>Noot: dit kan worden overschreven wanneer de regio instelling op automatisch selecteren staat.</translation> 3723 <translation>Opmerking: dit kan worden overschreven wanneer de regio-instelling automatisch wordt geselecteerd</translation>
3711 </message> 3724 </message>
3712 <message> 3725 <message>
3713 <location filename="../../src/yuzu/configuration/configure_system.ui" line="324"/> 3726 <location filename="../../src/yuzu/configuration/configure_system.ui" line="324"/>
@@ -3717,7 +3730,7 @@ UUID: %2</source>
3717 <message> 3730 <message>
3718 <location filename="../../src/yuzu/configuration/configure_system.ui" line="329"/> 3731 <location filename="../../src/yuzu/configuration/configure_system.ui" line="329"/>
3719 <source>American English</source> 3732 <source>American English</source>
3720 <translation type="unfinished"/> 3733 <translation>Amerikaans-Engels</translation>
3721 </message> 3734 </message>
3722 <message> 3735 <message>
3723 <location filename="../../src/yuzu/configuration/configure_system.ui" line="334"/> 3736 <location filename="../../src/yuzu/configuration/configure_system.ui" line="334"/>
@@ -3742,7 +3755,7 @@ UUID: %2</source>
3742 <message> 3755 <message>
3743 <location filename="../../src/yuzu/configuration/configure_system.ui" line="354"/> 3756 <location filename="../../src/yuzu/configuration/configure_system.ui" line="354"/>
3744 <source>Chinese</source> 3757 <source>Chinese</source>
3745 <translation>Chinees (正體中文 / 简体中文)</translation> 3758 <translation>Chinees</translation>
3746 </message> 3759 </message>
3747 <message> 3760 <message>
3748 <location filename="../../src/yuzu/configuration/configure_system.ui" line="359"/> 3761 <location filename="../../src/yuzu/configuration/configure_system.ui" line="359"/>
@@ -3772,17 +3785,17 @@ UUID: %2</source>
3772 <message> 3785 <message>
3773 <location filename="../../src/yuzu/configuration/configure_system.ui" line="384"/> 3786 <location filename="../../src/yuzu/configuration/configure_system.ui" line="384"/>
3774 <source>British English</source> 3787 <source>British English</source>
3775 <translation>Brits Engels</translation> 3788 <translation>Brits-Engels</translation>
3776 </message> 3789 </message>
3777 <message> 3790 <message>
3778 <location filename="../../src/yuzu/configuration/configure_system.ui" line="389"/> 3791 <location filename="../../src/yuzu/configuration/configure_system.ui" line="389"/>
3779 <source>Canadian French</source> 3792 <source>Canadian French</source>
3780 <translation>Canadees Frans</translation> 3793 <translation>Canadees-Frans</translation>
3781 </message> 3794 </message>
3782 <message> 3795 <message>
3783 <location filename="../../src/yuzu/configuration/configure_system.ui" line="394"/> 3796 <location filename="../../src/yuzu/configuration/configure_system.ui" line="394"/>
3784 <source>Latin American Spanish</source> 3797 <source>Latin American Spanish</source>
3785 <translation>Latijns Amerikaans Spaans</translation> 3798 <translation>Latijns-Amerikaans Spaans</translation>
3786 </message> 3799 </message>
3787 <message> 3800 <message>
3788 <location filename="../../src/yuzu/configuration/configure_system.ui" line="399"/> 3801 <location filename="../../src/yuzu/configuration/configure_system.ui" line="399"/>
@@ -3797,12 +3810,12 @@ UUID: %2</source>
3797 <message> 3810 <message>
3798 <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/> 3811 <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/>
3799 <source>Brazilian Portuguese (português do Brasil)</source> 3812 <source>Brazilian Portuguese (português do Brasil)</source>
3800 <translation type="unfinished"/> 3813 <translation>Braziliaans-Portugees (português do Brasil)</translation>
3801 </message> 3814 </message>
3802 <message> 3815 <message>
3803 <location filename="../../src/yuzu/configuration/configure_system.ui" line="417"/> 3816 <location filename="../../src/yuzu/configuration/configure_system.ui" line="417"/>
3804 <source>Custom RTC</source> 3817 <source>Custom RTC</source>
3805 <translation>Handmatige RTC</translation> 3818 <translation>Aangepaste RTC</translation>
3806 </message> 3819 </message>
3807 <message> 3820 <message>
3808 <location filename="../../src/yuzu/configuration/configure_system.ui" line="424"/> 3821 <location filename="../../src/yuzu/configuration/configure_system.ui" line="424"/>
@@ -3817,7 +3830,7 @@ UUID: %2</source>
3817 <message> 3830 <message>
3818 <location filename="../../src/yuzu/configuration/configure_system.ui" line="438"/> 3831 <location filename="../../src/yuzu/configuration/configure_system.ui" line="438"/>
3819 <source>Device Name</source> 3832 <source>Device Name</source>
3820 <translation type="unfinished"/> 3833 <translation>Apparaatnaam</translation>
3821 </message> 3834 </message>
3822 <message> 3835 <message>
3823 <location filename="../../src/yuzu/configuration/configure_system.ui" line="512"/> 3836 <location filename="../../src/yuzu/configuration/configure_system.ui" line="512"/>
@@ -3827,7 +3840,7 @@ UUID: %2</source>
3827 <message> 3840 <message>
3828 <location filename="../../src/yuzu/configuration/configure_system.cpp" line="67"/> 3841 <location filename="../../src/yuzu/configuration/configure_system.cpp" line="67"/>
3829 <source>Warning: &quot;%1&quot; is not a valid language for region &quot;%2&quot;</source> 3842 <source>Warning: &quot;%1&quot; is not a valid language for region &quot;%2&quot;</source>
3830 <translation type="unfinished"/> 3843 <translation>Waarschuwing: &quot;%1&quot; is geen geldige taal voor regio &quot;%2&quot;</translation>
3831 </message> 3844 </message>
3832</context> 3845</context>
3833<context> 3846<context>
@@ -3835,47 +3848,47 @@ UUID: %2</source>
3835 <message> 3848 <message>
3836 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="11"/> 3849 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="11"/>
3837 <source>TAS</source> 3850 <source>TAS</source>
3838 <translation type="unfinished"/> 3851 <translation>TAS</translation>
3839 </message> 3852 </message>
3840 <message> 3853 <message>
3841 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="17"/> 3854 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="17"/>
3842 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reads controller input from scripts in the same format as TAS-nx scripts.&lt;br/&gt;For a more detailed explanation, please consult the &lt;a href=&quot;https://yuzu-emu.org/help/feature/tas/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;help page&lt;/span&gt;&lt;/a&gt; on the yuzu website.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 3855 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reads controller input from scripts in the same format as TAS-nx scripts.&lt;br/&gt;For a more detailed explanation, please consult the &lt;a href=&quot;https://yuzu-emu.org/help/feature/tas/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;help page&lt;/span&gt;&lt;/a&gt; on the yuzu website.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
3843 <translation type="unfinished"/> 3856 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Leest controller-invoer van scripts in hetzelfde formaat als TAS-nx-scripts.&lt;br/&gt;Voor een meer gedetailleerde uitleg kunt u de&lt;a href=&quot;https://yuzu-emu.org/help/feature/tas/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#039be5;&quot;&gt;help-pagina&lt;/span&gt;&lt;/a&gt;op de yuzu-website raadplegen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
3844 </message> 3857 </message>
3845 <message> 3858 <message>
3846 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="27"/> 3859 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="27"/>
3847 <source>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -&gt; General -&gt; Hotkeys).</source> 3860 <source>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -&gt; General -&gt; Hotkeys).</source>
3848 <translation type="unfinished"/> 3861 <translation>Om te controleren welke sneltoetsen het afspelen/opnemen regelen, raadpleeg de sneltoetsinstellingen (Configuratie -&gt; Algemeen -&gt; Sneltoetsen).</translation>
3849 </message> 3862 </message>
3850 <message> 3863 <message>
3851 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="37"/> 3864 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="37"/>
3852 <source>WARNING: This is an experimental feature.&lt;br/&gt;It will not play back scripts frame perfectly with the current, imperfect syncing method.</source> 3865 <source>WARNING: This is an experimental feature.&lt;br/&gt;It will not play back scripts frame perfectly with the current, imperfect syncing method.</source>
3853 <translation type="unfinished"/> 3866 <translation>WAARSCHUWING: Dit is een experimentele functie.&lt;br/&gt;Met de huidige, onvolmaakte synchronisatiemethode worden scripts niet perfect afgespeeld.</translation>
3854 </message> 3867 </message>
3855 <message> 3868 <message>
3856 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="54"/> 3869 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="54"/>
3857 <source>Settings</source> 3870 <source>Settings</source>
3858 <translation type="unfinished"/> 3871 <translation>Instellingen</translation>
3859 </message> 3872 </message>
3860 <message> 3873 <message>
3861 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="60"/> 3874 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="60"/>
3862 <source>Enable TAS features</source> 3875 <source>Enable TAS features</source>
3863 <translation type="unfinished"/> 3876 <translation>Schakel TAS-functies in</translation>
3864 </message> 3877 </message>
3865 <message> 3878 <message>
3866 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="67"/> 3879 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="67"/>
3867 <source>Loop script</source> 3880 <source>Loop script</source>
3868 <translation type="unfinished"/> 3881 <translation>Lus script</translation>
3869 </message> 3882 </message>
3870 <message> 3883 <message>
3871 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="77"/> 3884 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="77"/>
3872 <source>Pause execution during loads</source> 3885 <source>Pause execution during loads</source>
3873 <translation type="unfinished"/> 3886 <translation>Onderbreek de uitvoering tijdens ladingen</translation>
3874 </message> 3887 </message>
3875 <message> 3888 <message>
3876 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="91"/> 3889 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="91"/>
3877 <source>Script Directory</source> 3890 <source>Script Directory</source>
3878 <translation type="unfinished"/> 3891 <translation>Script-map</translation>
3879 </message> 3892 </message>
3880 <message> 3893 <message>
3881 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="97"/> 3894 <location filename="../../src/yuzu/configuration/configure_tas.ui" line="97"/>
@@ -3893,12 +3906,12 @@ UUID: %2</source>
3893 <message> 3906 <message>
3894 <location filename="../../src/yuzu/configuration/configure_tas.cpp" line="19"/> 3907 <location filename="../../src/yuzu/configuration/configure_tas.cpp" line="19"/>
3895 <source>TAS Configuration</source> 3908 <source>TAS Configuration</source>
3896 <translation type="unfinished"/> 3909 <translation>TAS-configuratie</translation>
3897 </message> 3910 </message>
3898 <message> 3911 <message>
3899 <location filename="../../src/yuzu/configuration/configure_tas.cpp" line="49"/> 3912 <location filename="../../src/yuzu/configuration/configure_tas.cpp" line="49"/>
3900 <source>Select TAS Load Directory...</source> 3913 <source>Select TAS Load Directory...</source>
3901 <translation type="unfinished"/> 3914 <translation>Selecteer TAS-laadmap...</translation>
3902 </message> 3915 </message>
3903</context> 3916</context>
3904<context> 3917<context>
@@ -3906,12 +3919,12 @@ UUID: %2</source>
3906 <message> 3919 <message>
3907 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/> 3920 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/>
3908 <source>Configure Touchscreen Mappings</source> 3921 <source>Configure Touchscreen Mappings</source>
3909 <translation>Touchscreen Mappings Configureren</translation> 3922 <translation>Configureer Touchscreen-toewijzingen</translation>
3910 </message> 3923 </message>
3911 <message> 3924 <message>
3912 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/> 3925 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/>
3913 <source>Mapping:</source> 3926 <source>Mapping:</source>
3914 <translation>Mapping:</translation> 3927 <translation>Toewijzing:</translation>
3915 </message> 3928 </message>
3916 <message> 3929 <message>
3917 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/> 3930 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/>
@@ -3926,14 +3939,14 @@ UUID: %2</source>
3926 <message> 3939 <message>
3927 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/> 3940 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/>
3928 <source>Rename</source> 3941 <source>Rename</source>
3929 <translation>Hernoemen</translation> 3942 <translation>Hernoem</translation>
3930 </message> 3943 </message>
3931 <message> 3944 <message>
3932 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/> 3945 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/>
3933 <source>Click the bottom area to add a point, then press a button to bind. 3946 <source>Click the bottom area to add a point, then press a button to bind.
3934Drag points to change position, or double-click table cells to edit values.</source> 3947Drag points to change position, or double-click table cells to edit values.</source>
3935 <translation>Klik in de onderste vlakte op een punt toe te voegen, daarna druk op een knop om het te verbinden. 3948 <translation>Klik op het onderste gebied om een punt toe te voegen en druk vervolgens op een knop om toe te wijzen.
3936Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen om de waardes te veranderen.</translation> 3949Versleep punten om de positie te veranderen, of dubbelklik op tabelcellen om waarden te bewerken.</translation>
3937 </message> 3950 </message>
3938 <message> 3951 <message>
3939 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/> 3952 <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/>
@@ -3975,7 +3988,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
3975 <message> 3988 <message>
3976 <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="206"/> 3989 <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="206"/>
3977 <source>Delete profile %1?</source> 3990 <source>Delete profile %1?</source>
3978 <translation>Verwijder Profiel %1?</translation> 3991 <translation>Verwijder profiel %1?</translation>
3979 </message> 3992 </message>
3980 <message> 3993 <message>
3981 <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="219"/> 3994 <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="219"/>
@@ -4003,22 +4016,22 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4003 <message> 4016 <message>
4004 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/> 4017 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/>
4005 <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source> 4018 <source>Warning: The settings in this page affect the inner workings of yuzu&apos;s emulated touchscreen. Changing them may result in undesirable behavior, such as the touchscreen partially or not working. You should only use this page if you know what you are doing.</source>
4006 <translation>Waarschuwing: Instellingen in deze pagina hebben invloed op de interne werking van yuzu&apos;s geemuleerde touchscreen. Veranderingen kunnen ongewenste resultaten hebben, zoals ervoor zorgen dat het touchscreen half of niet werkt. Gebruik deze pagina enkel als je weet wat je doet.</translation> 4019 <translation>Waarschuwing: De instellingen in deze pagina beïnvloeden de innerlijke werking van yuzu&apos;s geëmuleerde touchscreen. Het veranderen ervan kan leiden tot ongewenst gedrag, zoals het gedeeltelijk of niet werken van het touchscreen. Je moet deze pagina alleen gebruiken als je weet wat je doet.</translation>
4007 </message> 4020 </message>
4008 <message> 4021 <message>
4009 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/> 4022 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/>
4010 <source>Touch Parameters</source> 4023 <source>Touch Parameters</source>
4011 <translation>Touch Parameters</translation> 4024 <translation>Aanraakparameters</translation>
4012 </message> 4025 </message>
4013 <message> 4026 <message>
4014 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/> 4027 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/>
4015 <source>Touch Diameter Y</source> 4028 <source>Touch Diameter Y</source>
4016 <translation>Touch Diameter Y</translation> 4029 <translation>Aanraakdiameter Y</translation>
4017 </message> 4030 </message>
4018 <message> 4031 <message>
4019 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="91"/> 4032 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="91"/>
4020 <source>Touch Diameter X</source> 4033 <source>Touch Diameter X</source>
4021 <translation>Touch Diameter X</translation> 4034 <translation>Aanraakdiameter X</translation>
4022 </message> 4035 </message>
4023 <message> 4036 <message>
4024 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/> 4037 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/>
@@ -4028,7 +4041,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4028 <message> 4041 <message>
4029 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="132"/> 4042 <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="132"/>
4030 <source>Restore Defaults</source> 4043 <source>Restore Defaults</source>
4031 <translation>Herstel Standaardwaardes</translation> 4044 <translation>Herstel Standaardwaarden</translation>
4032 </message> 4045 </message>
4033</context> 4046</context>
4034<context> 4047<context>
@@ -4043,37 +4056,37 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4043 <message> 4056 <message>
4044 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="21"/> 4057 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="21"/>
4045 <source>Small (32x32)</source> 4058 <source>Small (32x32)</source>
4046 <translation type="unfinished"/> 4059 <translation>Klein (32x32)</translation>
4047 </message> 4060 </message>
4048 <message> 4061 <message>
4049 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="22"/> 4062 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="22"/>
4050 <source>Standard (64x64)</source> 4063 <source>Standard (64x64)</source>
4051 <translation type="unfinished"/> 4064 <translation>Standaard (64x64)</translation>
4052 </message> 4065 </message>
4053 <message> 4066 <message>
4054 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="23"/> 4067 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="23"/>
4055 <source>Large (128x128)</source> 4068 <source>Large (128x128)</source>
4056 <translation type="unfinished"/> 4069 <translation>Groot (128x128)</translation>
4057 </message> 4070 </message>
4058 <message> 4071 <message>
4059 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="24"/> 4072 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="24"/>
4060 <source>Full Size (256x256)</source> 4073 <source>Full Size (256x256)</source>
4061 <translation type="unfinished"/> 4074 <translation>Volledige Grootte (256x256)</translation>
4062 </message> 4075 </message>
4063 <message> 4076 <message>
4064 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="29"/> 4077 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="29"/>
4065 <source>Small (24x24)</source> 4078 <source>Small (24x24)</source>
4066 <translation type="unfinished"/> 4079 <translation>Klein (24x24)</translation>
4067 </message> 4080 </message>
4068 <message> 4081 <message>
4069 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="30"/> 4082 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="30"/>
4070 <source>Standard (48x48)</source> 4083 <source>Standard (48x48)</source>
4071 <translation type="unfinished"/> 4084 <translation>Standaard (48x48)</translation>
4072 </message> 4085 </message>
4073 <message> 4086 <message>
4074 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="31"/> 4087 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="31"/>
4075 <source>Large (72x72)</source> 4088 <source>Large (72x72)</source>
4076 <translation type="unfinished"/> 4089 <translation>Groot (72x72)</translation>
4077 </message> 4090 </message>
4078 <message> 4091 <message>
4079 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="36"/> 4092 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="36"/>
@@ -4083,17 +4096,17 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4083 <message> 4096 <message>
4084 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="37"/> 4097 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="37"/>
4085 <source>Filetype</source> 4098 <source>Filetype</source>
4086 <translation type="unfinished"/> 4099 <translation>Bestandstype</translation>
4087 </message> 4100 </message>
4088 <message> 4101 <message>
4089 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="38"/> 4102 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="38"/>
4090 <source>Title ID</source> 4103 <source>Title ID</source>
4091 <translation>Titel ID</translation> 4104 <translation>Titel-ID</translation>
4092 </message> 4105 </message>
4093 <message> 4106 <message>
4094 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="39"/> 4107 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="39"/>
4095 <source>Title Name</source> 4108 <source>Title Name</source>
4096 <translation type="unfinished"/> 4109 <translation>Titelnaam</translation>
4097 </message> 4110 </message>
4098</context> 4111</context>
4099<context> 4112<context>
@@ -4116,12 +4129,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4116 <message> 4129 <message>
4117 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="31"/> 4130 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="31"/>
4118 <source>Note: Changing language will apply your configuration.</source> 4131 <source>Note: Changing language will apply your configuration.</source>
4119 <translation>Notitie: De taal veranderen past uw configuratie toe.</translation> 4132 <translation>Opmerking: Als je de taal wijzigt, wordt je configuratie toegepast.</translation>
4120 </message> 4133 </message>
4121 <message> 4134 <message>
4122 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="43"/> 4135 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="43"/>
4123 <source>Interface language:</source> 4136 <source>Interface language:</source>
4124 <translation>Interface taal:</translation> 4137 <translation>Interfacetaal:</translation>
4125 </message> 4138 </message>
4126 <message> 4139 <message>
4127 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="57"/> 4140 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="57"/>
@@ -4131,47 +4144,47 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4131 <message> 4144 <message>
4132 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="74"/> 4145 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="74"/>
4133 <source>Game List</source> 4146 <source>Game List</source>
4134 <translation>Game Lijst</translation> 4147 <translation>Spellijst</translation>
4135 </message> 4148 </message>
4136 <message> 4149 <message>
4137 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="82"/> 4150 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="82"/>
4138 <source>Show Compatibility List</source> 4151 <source>Show Compatibility List</source>
4139 <translation type="unfinished"/> 4152 <translation>Toon Compatibiliteitslijst</translation>
4140 </message> 4153 </message>
4141 <message> 4154 <message>
4142 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="89"/> 4155 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="89"/>
4143 <source>Show Add-Ons Column</source> 4156 <source>Show Add-Ons Column</source>
4144 <translation>Toon Add-Ons Kolom</translation> 4157 <translation>Toon Kolom Add-Ons</translation>
4145 </message> 4158 </message>
4146 <message> 4159 <message>
4147 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="96"/> 4160 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="96"/>
4148 <source>Show Size Column</source> 4161 <source>Show Size Column</source>
4149 <translation type="unfinished"/> 4162 <translation>Toon Kolomgrootte</translation>
4150 </message> 4163 </message>
4151 <message> 4164 <message>
4152 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="103"/> 4165 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="103"/>
4153 <source>Show File Types Column</source> 4166 <source>Show File Types Column</source>
4154 <translation type="unfinished"/> 4167 <translation>Toon Kolom Bestandstypen</translation>
4155 </message> 4168 </message>
4156 <message> 4169 <message>
4157 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="112"/> 4170 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="112"/>
4158 <source>Game Icon Size:</source> 4171 <source>Game Icon Size:</source>
4159 <translation type="unfinished"/> 4172 <translation>Grootte Spelicoon:</translation>
4160 </message> 4173 </message>
4161 <message> 4174 <message>
4162 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="126"/> 4175 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="126"/>
4163 <source>Folder Icon Size:</source> 4176 <source>Folder Icon Size:</source>
4164 <translation type="unfinished"/> 4177 <translation>Grootte Mapicoon:</translation>
4165 </message> 4178 </message>
4166 <message> 4179 <message>
4167 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="140"/> 4180 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="140"/>
4168 <source>Row 1 Text:</source> 4181 <source>Row 1 Text:</source>
4169 <translation>Rij 1 Text:</translation> 4182 <translation>Rij 1 Tekst:</translation>
4170 </message> 4183 </message>
4171 <message> 4184 <message>
4172 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="154"/> 4185 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="154"/>
4173 <source>Row 2 Text:</source> 4186 <source>Row 2 Text:</source>
4174 <translation>Rij 2 Text:</translation> 4187 <translation>Rij 2 Tekst:</translation>
4175 </message> 4188 </message>
4176 <message> 4189 <message>
4177 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="171"/> 4190 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="171"/>
@@ -4181,12 +4194,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4181 <message> 4194 <message>
4182 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="179"/> 4195 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="179"/>
4183 <source>Ask Where To Save Screenshots (Windows Only)</source> 4196 <source>Ask Where To Save Screenshots (Windows Only)</source>
4184 <translation type="unfinished"/> 4197 <translation>Vraag waar schermafbeeldingen moeten worden opgeslagen (alleen Windows)</translation>
4185 </message> 4198 </message>
4186 <message> 4199 <message>
4187 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="188"/> 4200 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="188"/>
4188 <source>Screenshots Path: </source> 4201 <source>Screenshots Path: </source>
4189 <translation type="unfinished"/> 4202 <translation>Schermafbeeldingspad:</translation>
4190 </message> 4203 </message>
4191 <message> 4204 <message>
4192 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="198"/> 4205 <location filename="../../src/yuzu/configuration/configure_ui.ui" line="198"/>
@@ -4196,7 +4209,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4196 <message> 4209 <message>
4197 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="96"/> 4210 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="96"/>
4198 <source>Select Screenshots Path...</source> 4211 <source>Select Screenshots Path...</source>
4199 <translation type="unfinished"/> 4212 <translation>Selecteer Schermafbeeldingspad...</translation>
4200 </message> 4213 </message>
4201 <message> 4214 <message>
4202 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="225"/> 4215 <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="225"/>
@@ -4209,12 +4222,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4209 <message> 4222 <message>
4210 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="14"/> 4223 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="14"/>
4211 <source>Configure Vibration</source> 4224 <source>Configure Vibration</source>
4212 <translation type="unfinished"/> 4225 <translation>Configureer Trilling</translation>
4213 </message> 4226 </message>
4214 <message> 4227 <message>
4215 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="23"/> 4228 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="23"/>
4216 <source>Press any controller button to vibrate the controller.</source> 4229 <source>Press any controller button to vibrate the controller.</source>
4217 <translation type="unfinished"/> 4230 <translation>Druk op een willekeurige knop om de controller te laten trillen.</translation>
4218 </message> 4231 </message>
4219 <message> 4232 <message>
4220 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="30"/> 4233 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="30"/>
@@ -4276,12 +4289,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4276 <message> 4289 <message>
4277 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="503"/> 4290 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="503"/>
4278 <source>Settings</source> 4291 <source>Settings</source>
4279 <translation type="unfinished"/> 4292 <translation>Instellingen</translation>
4280 </message> 4293 </message>
4281 <message> 4294 <message>
4282 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="509"/> 4295 <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="509"/>
4283 <source>Enable Accurate Vibration</source> 4296 <source>Enable Accurate Vibration</source>
4284 <translation type="unfinished"/> 4297 <translation>Schakel Nauwkeurige Trillingen In</translation>
4285 </message> 4298 </message>
4286</context> 4299</context>
4287<context> 4300<context>
@@ -4299,12 +4312,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4299 <message> 4312 <message>
4300 <location filename="../../src/yuzu/configuration/configure_web.ui" line="25"/> 4313 <location filename="../../src/yuzu/configuration/configure_web.ui" line="25"/>
4301 <source>yuzu Web Service</source> 4314 <source>yuzu Web Service</source>
4302 <translation>yuzu Web Service</translation> 4315 <translation>yuzu-webservice</translation>
4303 </message> 4316 </message>
4304 <message> 4317 <message>
4305 <location filename="../../src/yuzu/configuration/configure_web.ui" line="31"/> 4318 <location filename="../../src/yuzu/configuration/configure_web.ui" line="31"/>
4306 <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source> 4319 <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source>
4307 <translation>Door je gebruikersnaam en token te geven, ga je akkoord dat yuzu extra gebruiksdata verzameld, waaronder mogelijk gebruikersidentificatie-informatie.</translation> 4320 <translation>Door je gebruikersnaam en token op te geven, ga je ermee akkoord dat yuzu aanvullende gebruiksgegevens verzamelt, die informatie ter identificatie van de gebruiker kunnen bevatten.</translation>
4308 </message> 4321 </message>
4309 <message> 4322 <message>
4310 <location filename="../../src/yuzu/configuration/configure_web.ui" line="49"/> 4323 <location filename="../../src/yuzu/configuration/configure_web.ui" line="49"/>
@@ -4335,7 +4348,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4335 <message> 4348 <message>
4336 <location filename="../../src/yuzu/configuration/configure_web.ui" line="118"/> 4349 <location filename="../../src/yuzu/configuration/configure_web.ui" line="118"/>
4337 <source>Web Service configuration can only be changed when a public room isn&apos;t being hosted.</source> 4350 <source>Web Service configuration can only be changed when a public room isn&apos;t being hosted.</source>
4338 <translation type="unfinished"/> 4351 <translation>De configuratie van de webservice kan alleen worden gewijzigd als er geen openbare ruimte wordt gehost.</translation>
4339 </message> 4352 </message>
4340 <message> 4353 <message>
4341 <location filename="../../src/yuzu/configuration/configure_web.ui" line="128"/> 4354 <location filename="../../src/yuzu/configuration/configure_web.ui" line="128"/>
@@ -4345,17 +4358,17 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4345 <message> 4358 <message>
4346 <location filename="../../src/yuzu/configuration/configure_web.ui" line="134"/> 4359 <location filename="../../src/yuzu/configuration/configure_web.ui" line="134"/>
4347 <source>Share anonymous usage data with the yuzu team</source> 4360 <source>Share anonymous usage data with the yuzu team</source>
4348 <translation>Deel anonieme gebruiksdata met het yuzu team</translation> 4361 <translation>Deel anonieme gebruiksdata met het yuzu-team</translation>
4349 </message> 4362 </message>
4350 <message> 4363 <message>
4351 <location filename="../../src/yuzu/configuration/configure_web.ui" line="141"/> 4364 <location filename="../../src/yuzu/configuration/configure_web.ui" line="141"/>
4352 <source>Learn more</source> 4365 <source>Learn more</source>
4353 <translation>Leer meer</translation> 4366 <translation>Meer info</translation>
4354 </message> 4367 </message>
4355 <message> 4368 <message>
4356 <location filename="../../src/yuzu/configuration/configure_web.ui" line="150"/> 4369 <location filename="../../src/yuzu/configuration/configure_web.ui" line="150"/>
4357 <source>Telemetry ID:</source> 4370 <source>Telemetry ID:</source>
4358 <translation>Telemetrie ID:</translation> 4371 <translation>Telemetrie-ID:</translation>
4359 </message> 4372 </message>
4360 <message> 4373 <message>
4361 <location filename="../../src/yuzu/configuration/configure_web.ui" line="166"/> 4374 <location filename="../../src/yuzu/configuration/configure_web.ui" line="166"/>
@@ -4365,17 +4378,17 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4365 <message> 4378 <message>
4366 <location filename="../../src/yuzu/configuration/configure_web.ui" line="180"/> 4379 <location filename="../../src/yuzu/configuration/configure_web.ui" line="180"/>
4367 <source>Discord Presence</source> 4380 <source>Discord Presence</source>
4368 <translation>Discord Presence</translation> 4381 <translation>Aanwezigheid in Discord</translation>
4369 </message> 4382 </message>
4370 <message> 4383 <message>
4371 <location filename="../../src/yuzu/configuration/configure_web.ui" line="186"/> 4384 <location filename="../../src/yuzu/configuration/configure_web.ui" line="186"/>
4372 <source>Show Current Game in your Discord Status</source> 4385 <source>Show Current Game in your Discord Status</source>
4373 <translation>Toon huidige game in je Discord status</translation> 4386 <translation>Toon huidige game in uw Discord-status</translation>
4374 </message> 4387 </message>
4375 <message> 4388 <message>
4376 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="68"/> 4389 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="68"/>
4377 <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source> 4390 <source>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Learn more&lt;/span&gt;&lt;/a&gt;</source>
4378 <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Leer meer&lt;/span&gt;&lt;/a&gt;</translation> 4391 <translation>&lt;a href=&apos;https://yuzu-emu.org/help/feature/telemetry/&apos;&gt;&lt;span style=&quot;text-decoration: underline; color:#039be5;&quot;&gt;Meer info&lt;/span&gt;&lt;/a&gt;</translation>
4379 </message> 4392 </message>
4380 <message> 4393 <message>
4381 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="72"/> 4394 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="72"/>
@@ -4391,7 +4404,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4391 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="80"/> 4404 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="80"/>
4392 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="125"/> 4405 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="125"/>
4393 <source>Telemetry ID: 0x%1</source> 4406 <source>Telemetry ID: 0x%1</source>
4394 <translation>Telemetrie ID: 0x%1</translation> 4407 <translation>Telemetrie-ID: 0x%1</translation>
4395 </message> 4408 </message>
4396 <message> 4409 <message>
4397 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="91"/> 4410 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="91"/>
@@ -4413,7 +4426,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4413 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="141"/> 4426 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="141"/>
4414 <source>Unverified, please click Verify before saving configuration</source> 4427 <source>Unverified, please click Verify before saving configuration</source>
4415 <comment>Tooltip</comment> 4428 <comment>Tooltip</comment>
4416 <translation type="unfinished"/> 4429 <translation>Niet geverifieerd, klik op Verifiëren voordat je de configuratie opslaat</translation>
4417 </message> 4430 </message>
4418 <message> 4431 <message>
4419 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="147"/> 4432 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="147"/>
@@ -4425,7 +4438,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4425 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="164"/> 4438 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="164"/>
4426 <source>Verified</source> 4439 <source>Verified</source>
4427 <comment>Tooltip</comment> 4440 <comment>Tooltip</comment>
4428 <translation type="unfinished"/> 4441 <translation>Geverifiëerd</translation>
4429 </message> 4442 </message>
4430 <message> 4443 <message>
4431 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="169"/> 4444 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="169"/>
@@ -4441,7 +4454,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4441 <message> 4454 <message>
4442 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="172"/> 4455 <location filename="../../src/yuzu/configuration/configure_web.cpp" line="172"/>
4443 <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source> 4456 <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source>
4444 <translation>Verificatie mislukt. Check dat uw token correct is en dat uw internet werkt.</translation> 4457 <translation>Verificatie mislukt. Controleer of je je token correct hebt ingevoerd en of je internetverbinding werkt.</translation>
4445 </message> 4458 </message>
4446</context> 4459</context>
4447<context> 4460<context>
@@ -4449,12 +4462,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4449 <message> 4462 <message>
4450 <location filename="../../src/yuzu/debugger/controller.cpp" line="20"/> 4463 <location filename="../../src/yuzu/debugger/controller.cpp" line="20"/>
4451 <source>Controller P1</source> 4464 <source>Controller P1</source>
4452 <translation type="unfinished"/> 4465 <translation>Controller P1</translation>
4453 </message> 4466 </message>
4454 <message> 4467 <message>
4455 <location filename="../../src/yuzu/debugger/controller.cpp" line="58"/> 4468 <location filename="../../src/yuzu/debugger/controller.cpp" line="58"/>
4456 <source>&amp;Controller P1</source> 4469 <source>&amp;Controller P1</source>
4457 <translation type="unfinished"/> 4470 <translation>&amp;Controller P1</translation>
4458 </message> 4471 </message>
4459</context> 4472</context>
4460<context> 4473<context>
@@ -4462,42 +4475,42 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4462 <message> 4475 <message>
4463 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="14"/> 4476 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="14"/>
4464 <source>Direct Connect</source> 4477 <source>Direct Connect</source>
4465 <translation type="unfinished"/> 4478 <translation>Directe Verbinding</translation>
4466 </message> 4479 </message>
4467 <message> 4480 <message>
4468 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="47"/> 4481 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="47"/>
4469 <source>Server Address</source> 4482 <source>Server Address</source>
4470 <translation type="unfinished"/> 4483 <translation>Serveradres</translation>
4471 </message> 4484 </message>
4472 <message> 4485 <message>
4473 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="54"/> 4486 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="54"/>
4474 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Server address of the host&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 4487 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Server address of the host&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
4475 <translation type="unfinished"/> 4488 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Serveradres van de host&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
4476 </message> 4489 </message>
4477 <message> 4490 <message>
4478 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="64"/> 4491 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="64"/>
4479 <source>Port</source> 4492 <source>Port</source>
4480 <translation type="unfinished"/> 4493 <translation>Poort</translation>
4481 </message> 4494 </message>
4482 <message> 4495 <message>
4483 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="71"/> 4496 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="71"/>
4484 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Port number the host is listening on&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 4497 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Port number the host is listening on&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
4485 <translation type="unfinished"/> 4498 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Poortnummer waarop de host luistert&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
4486 </message> 4499 </message>
4487 <message> 4500 <message>
4488 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="97"/> 4501 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="97"/>
4489 <source>Nickname</source> 4502 <source>Nickname</source>
4490 <translation type="unfinished"/> 4503 <translation>Gebruikersnaam</translation>
4491 </message> 4504 </message>
4492 <message> 4505 <message>
4493 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="111"/> 4506 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="111"/>
4494 <source>Password</source> 4507 <source>Password</source>
4495 <translation type="unfinished"/> 4508 <translation>Wachtwoord</translation>
4496 </message> 4509 </message>
4497 <message> 4510 <message>
4498 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="153"/> 4511 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="153"/>
4499 <source>Connect</source> 4512 <source>Connect</source>
4500 <translation type="unfinished"/> 4513 <translation>Verbind</translation>
4501 </message> 4514 </message>
4502</context> 4515</context>
4503<context> 4516<context>
@@ -4505,12 +4518,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4505 <message> 4518 <message>
4506 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="120"/> 4519 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="120"/>
4507 <source>Connecting</source> 4520 <source>Connecting</source>
4508 <translation type="unfinished"/> 4521 <translation>Verbinden</translation>
4509 </message> 4522 </message>
4510 <message> 4523 <message>
4511 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="125"/> 4524 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="125"/>
4512 <source>Connect</source> 4525 <source>Connect</source>
4513 <translation type="unfinished"/> 4526 <translation>Verbind</translation>
4514 </message> 4527 </message>
4515</context> 4528</context>
4516<context> 4529<context>
@@ -4528,12 +4541,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4528 <message> 4541 <message>
4529 <location filename="../../src/yuzu/main.cpp" line="432"/> 4542 <location filename="../../src/yuzu/main.cpp" line="432"/>
4530 <source>Broken Vulkan Installation Detected</source> 4543 <source>Broken Vulkan Installation Detected</source>
4531 <translation type="unfinished"/> 4544 <translation>Beschadigde Vulkan-installatie gedetecteerd</translation>
4532 </message> 4545 </message>
4533 <message> 4546 <message>
4534 <location filename="../../src/yuzu/main.cpp" line="433"/> 4547 <location filename="../../src/yuzu/main.cpp" line="433"/>
4535 <source>Vulkan initialization failed during boot.&lt;br&gt;&lt;br&gt;Click &lt;a href=&apos;https://yuzu-emu.org/wiki/faq/#yuzu-starts-with-the-error-broken-vulkan-installation-detected&apos;&gt;here for instructions to fix the issue&lt;/a&gt;.</source> 4548 <source>Vulkan initialization failed during boot.&lt;br&gt;&lt;br&gt;Click &lt;a href=&apos;https://yuzu-emu.org/wiki/faq/#yuzu-starts-with-the-error-broken-vulkan-installation-detected&apos;&gt;here for instructions to fix the issue&lt;/a&gt;.</source>
4536 <translation type="unfinished"/> 4549 <translation>Vulkan-initialisatie mislukt tijdens het opstarten.&lt;br&gt;&lt;br&gt;Klik &lt;a href=&apos;https://yuzu-emu.org/wiki/faq/#yuzu-starts-with-the-error-broken-vulkan-installation-detected&apos;&gt;hier voor instructies om het probleem op te lossen&lt;/a&gt;.</translation>
4537 </message> 4550 </message>
4538 <message> 4551 <message>
4539 <location filename="../../src/yuzu/main.cpp" line="824"/> 4552 <location filename="../../src/yuzu/main.cpp" line="824"/>
@@ -4544,79 +4557,80 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4544 <location filename="../../src/yuzu/main.cpp" line="874"/> 4557 <location filename="../../src/yuzu/main.cpp" line="874"/>
4545 <location filename="../../src/yuzu/main.cpp" line="877"/> 4558 <location filename="../../src/yuzu/main.cpp" line="877"/>
4546 <source>Disable Web Applet</source> 4559 <source>Disable Web Applet</source>
4547 <translation type="unfinished"/> 4560 <translation>Schakel Webapplet uit</translation>
4548 </message> 4561 </message>
4549 <message> 4562 <message>
4550 <location filename="../../src/yuzu/main.cpp" line="878"/> 4563 <location filename="../../src/yuzu/main.cpp" line="878"/>
4551 <source>Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet? 4564 <source>Disabling the web applet can lead to undefined behavior and should only be used with Super Mario 3D All-Stars. Are you sure you want to disable the web applet?
4552(This can be re-enabled in the Debug settings.)</source> 4565(This can be re-enabled in the Debug settings.)</source>
4553 <translation type="unfinished"/> 4566 <translation>Het uitschakelen van de webapplet kan leiden tot ongedefinieerd gedrag en mag alleen gebruikt worden met Super Mario 3D All-Stars. Weet je zeker dat je de webapplet wilt uitschakelen?
4567(Deze kan opnieuw worden ingeschakeld in de Debug-instellingen).</translation>
4554 </message> 4568 </message>
4555 <message> 4569 <message>
4556 <location filename="../../src/yuzu/main.cpp" line="994"/> 4570 <location filename="../../src/yuzu/main.cpp" line="994"/>
4557 <source>The amount of shaders currently being built</source> 4571 <source>The amount of shaders currently being built</source>
4558 <translation type="unfinished"/> 4572 <translation>Het aantal shaders dat momenteel wordt gebouwd</translation>
4559 </message> 4573 </message>
4560 <message> 4574 <message>
4561 <location filename="../../src/yuzu/main.cpp" line="996"/> 4575 <location filename="../../src/yuzu/main.cpp" line="996"/>
4562 <source>The current selected resolution scaling multiplier.</source> 4576 <source>The current selected resolution scaling multiplier.</source>
4563 <translation type="unfinished"/> 4577 <translation>De huidige geselecteerde resolutieschaalmultiplier.</translation>
4564 </message> 4578 </message>
4565 <message> 4579 <message>
4566 <location filename="../../src/yuzu/main.cpp" line="999"/> 4580 <location filename="../../src/yuzu/main.cpp" line="999"/>
4567 <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source> 4581 <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source>
4568 <translation>Huidige emulatie snelheid. Waardes hoger of lager dan 100% betekent dat de emulatie sneller of langzamer loopt dan de Switch.</translation> 4582 <translation>Huidige emulatiesnelheid. Waarden hoger of lager dan 100% geven aan dat de emulatie sneller of langzamer werkt dan een Switch.</translation>
4569 </message> 4583 </message>
4570 <message> 4584 <message>
4571 <location filename="../../src/yuzu/main.cpp" line="1002"/> 4585 <location filename="../../src/yuzu/main.cpp" line="1002"/>
4572 <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source> 4586 <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source>
4573 <translation>Hoeveel frames per seconde de game op dit moment weergeeft. Dit zal veranderen van game naar game en van scène naar scène.</translation> 4587 <translation>Hoeveel beelden per seconde het spel momenteel weergeeft. Dit varieert van spel tot spel en van scène tot scène.</translation>
4574 </message> 4588 </message>
4575 <message> 4589 <message>
4576 <location filename="../../src/yuzu/main.cpp" line="1006"/> 4590 <location filename="../../src/yuzu/main.cpp" line="1006"/>
4577 <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source> 4591 <source>Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For full-speed emulation this should be at most 16.67 ms.</source>
4578 <translation>Tijd gebruikt om een frame van de Switch te emuleren, waarbij framelimiteren of v-sync niet wordt meegerekend. Voor emulatie op volledige snelheid zou dit maximaal 16.67 ms zijn.</translation> 4592 <translation>Tijd die nodig is om een Switch-beeld te emuleren, beeldbeperking of v-sync niet meegerekend. Voor emulatie op volle snelheid mag dit maximaal 16,67 ms zijn.</translation>
4579 </message> 4593 </message>
4580 <message> 4594 <message>
4581 <location filename="../../src/yuzu/main.cpp" line="1156"/> 4595 <location filename="../../src/yuzu/main.cpp" line="1156"/>
4582 <source>&amp;Clear Recent Files</source> 4596 <source>&amp;Clear Recent Files</source>
4583 <translation type="unfinished"/> 4597 <translation>&amp;Wis Recente Bestanden</translation>
4584 </message> 4598 </message>
4585 <message> 4599 <message>
4586 <location filename="../../src/yuzu/main.cpp" line="1230"/> 4600 <location filename="../../src/yuzu/main.cpp" line="1230"/>
4587 <source>Emulated mouse is enabled</source> 4601 <source>Emulated mouse is enabled</source>
4588 <translation type="unfinished"/> 4602 <translation>Geëmuleerde muis is ingeschakeld</translation>
4589 </message> 4603 </message>
4590 <message> 4604 <message>
4591 <location filename="../../src/yuzu/main.cpp" line="1231"/> 4605 <location filename="../../src/yuzu/main.cpp" line="1231"/>
4592 <source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source> 4606 <source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source>
4593 <translation type="unfinished"/> 4607 <translation>Echte muisinvoer en muispanning zijn niet compatibel. Schakel de geëmuleerde muis uit in de geavanceerde invoerinstellingen om muispanning mogelijk te maken.</translation>
4594 </message> 4608 </message>
4595 <message> 4609 <message>
4596 <location filename="../../src/yuzu/main.cpp" line="1453"/> 4610 <location filename="../../src/yuzu/main.cpp" line="1453"/>
4597 <source>&amp;Continue</source> 4611 <source>&amp;Continue</source>
4598 <translation type="unfinished"/> 4612 <translation>&amp;Doorgaan</translation>
4599 </message> 4613 </message>
4600 <message> 4614 <message>
4601 <location filename="../../src/yuzu/main.cpp" line="1455"/> 4615 <location filename="../../src/yuzu/main.cpp" line="1455"/>
4602 <source>&amp;Pause</source> 4616 <source>&amp;Pause</source>
4603 <translation>&amp;Pauzeren</translation> 4617 <translation>&amp;Onderbreken</translation>
4604 </message> 4618 </message>
4605 <message> 4619 <message>
4606 <location filename="../../src/yuzu/main.cpp" line="1535"/> 4620 <location filename="../../src/yuzu/main.cpp" line="1535"/>
4607 <source>yuzu is running a game</source> 4621 <source>yuzu is running a game</source>
4608 <extracomment>TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping</extracomment> 4622 <extracomment>TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping</extracomment>
4609 <translation type="unfinished"/> 4623 <translation>yuzu is een spel aan het uitvoeren</translation>
4610 </message> 4624 </message>
4611 <message> 4625 <message>
4612 <location filename="../../src/yuzu/main.cpp" line="1668"/> 4626 <location filename="../../src/yuzu/main.cpp" line="1668"/>
4613 <source>Warning Outdated Game Format</source> 4627 <source>Warning Outdated Game Format</source>
4614 <translation>Waarschuwing Verouderd Spel Formaat</translation> 4628 <translation>Waarschuwing Verouderd Spelformaat</translation>
4615 </message> 4629 </message>
4616 <message> 4630 <message>
4617 <location filename="../../src/yuzu/main.cpp" line="1669"/> 4631 <location filename="../../src/yuzu/main.cpp" line="1669"/>
4618 <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source> 4632 <source>You are using the deconstructed ROM directory format for this game, which is an outdated format that has been superseded by others such as NCA, NAX, XCI, or NSP. Deconstructed ROM directories lack icons, metadata, and update support.&lt;br&gt;&lt;br&gt;For an explanation of the various Switch formats yuzu supports, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;check out our wiki&lt;/a&gt;. This message will not be shown again.</source>
4619 <translation>Je gebruikt gedeconstrueerd ROM map formaat voor dit Spel, dit is een verouderd formaat en is vervangen door formaten zoals NCA, NAX, XCI of NSP. Gedeconstrueerd ROM map heeft geen iconen, metadata en update understeuning.&lt;br&gt;&lt;br&gt;Voor een uitleg over welke Switch formaten yuzu ondersteund, &lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt;kijk op onze wiki&lt;/a&gt;. Dit bericht word niet nog een keer weergegeven.</translation> 4633 <translation>Je gebruikt het gedeconstrueerde ROM-mapformaat voor dit spel, wat een verouderd formaat is dat vervangen is door andere zoals NCA, NAX, XCI, of NSP. Deconstructed ROM-mappen missen iconen, metadata, en update-ondersteuning.&lt;br&gt;&lt;br&gt;Voor een uitleg van de verschillende Switch-formaten die yuzu ondersteunt,&lt;a href=&apos;https://yuzu-emu.org/wiki/overview-of-switch-game-formats&apos;&gt; bekijk onze wiki&lt;/a&gt;. Dit bericht wordt niet meer getoond.</translation>
4620 </message> 4634 </message>
4621 <message> 4635 <message>
4622 <location filename="../../src/yuzu/main.cpp" line="1681"/> 4636 <location filename="../../src/yuzu/main.cpp" line="1681"/>
@@ -4627,7 +4641,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4627 <message> 4641 <message>
4628 <location filename="../../src/yuzu/main.cpp" line="1682"/> 4642 <location filename="../../src/yuzu/main.cpp" line="1682"/>
4629 <source>The ROM format is not supported.</source> 4643 <source>The ROM format is not supported.</source>
4630 <translation>Het formaat van de ROM is niet ondersteunt.</translation> 4644 <translation>Het ROM-formaat wordt niet ondersteund.</translation>
4631 </message> 4645 </message>
4632 <message> 4646 <message>
4633 <location filename="../../src/yuzu/main.cpp" line="1686"/> 4647 <location filename="../../src/yuzu/main.cpp" line="1686"/>
@@ -4637,19 +4651,19 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4637 <message> 4651 <message>
4638 <location filename="../../src/yuzu/main.cpp" line="1687"/> 4652 <location filename="../../src/yuzu/main.cpp" line="1687"/>
4639 <source>yuzu has encountered an error while running the video core. This is usually caused by outdated GPU drivers, including integrated ones. Please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://yuzu-emu.org/help/reference/log-files/&apos;&gt;How to Upload the Log File&lt;/a&gt;. </source> 4653 <source>yuzu has encountered an error while running the video core. This is usually caused by outdated GPU drivers, including integrated ones. Please see the log for more details. For more information on accessing the log, please see the following page: &lt;a href=&apos;https://yuzu-emu.org/help/reference/log-files/&apos;&gt;How to Upload the Log File&lt;/a&gt;. </source>
4640 <translation type="unfinished"/> 4654 <translation>yuzu is een fout tegengekomen tijdens het uitvoeren van de videokern. Dit wordt meestal veroorzaakt door verouderde GPU-drivers, inclusief geïntegreerde. Zie het logboek voor meer details. Voor meer informatie over toegang tot het log, zie de volgende pagina: &lt;a href=&apos;https://yuzu-emu.org/help/reference/log-files/&apos;&gt;Hoe upload je het logbestand&lt;/a&gt;. </translation>
4641 </message> 4655 </message>
4642 <message> 4656 <message>
4643 <location filename="../../src/yuzu/main.cpp" line="1702"/> 4657 <location filename="../../src/yuzu/main.cpp" line="1702"/>
4644 <source>Error while loading ROM! %1</source> 4658 <source>Error while loading ROM! %1</source>
4645 <comment>%1 signifies a numeric error code.</comment> 4659 <comment>%1 signifies a numeric error code.</comment>
4646 <translation type="unfinished"/> 4660 <translation>Fout tijdens het laden van ROM! %1</translation>
4647 </message> 4661 </message>
4648 <message> 4662 <message>
4649 <location filename="../../src/yuzu/main.cpp" line="1705"/> 4663 <location filename="../../src/yuzu/main.cpp" line="1705"/>
4650 <source>%1&lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to redump your files.&lt;br&gt;You can refer to the yuzu wiki&lt;/a&gt; or the yuzu Discord&lt;/a&gt; for help.</source> 4664 <source>%1&lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to redump your files.&lt;br&gt;You can refer to the yuzu wiki&lt;/a&gt; or the yuzu Discord&lt;/a&gt; for help.</source>
4651 <comment>%1 signifies an error string.</comment> 4665 <comment>%1 signifies an error string.</comment>
4652 <translation type="unfinished"/> 4666 <translation>%1&lt;br&gt;Volg de &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;yuzu snelstartgids&lt;/a&gt; om je bestanden te redumpen.&lt;br&gt;Je kunt de yuzu-wiki&lt;/a&gt;of de yuzu-Discord&lt;/a&gt; raadplegen voor hulp.</translation>
4653 </message> 4667 </message>
4654 <message> 4668 <message>
4655 <location filename="../../src/yuzu/main.cpp" line="1716"/> 4669 <location filename="../../src/yuzu/main.cpp" line="1716"/>
@@ -4659,23 +4673,23 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4659 <message> 4673 <message>
4660 <location filename="../../src/yuzu/main.cpp" line="1858"/> 4674 <location filename="../../src/yuzu/main.cpp" line="1858"/>
4661 <source>(64-bit)</source> 4675 <source>(64-bit)</source>
4662 <translation type="unfinished"/> 4676 <translation>(64-bit)</translation>
4663 </message> 4677 </message>
4664 <message> 4678 <message>
4665 <location filename="../../src/yuzu/main.cpp" line="1858"/> 4679 <location filename="../../src/yuzu/main.cpp" line="1858"/>
4666 <source>(32-bit)</source> 4680 <source>(32-bit)</source>
4667 <translation type="unfinished"/> 4681 <translation>(32-bit)</translation>
4668 </message> 4682 </message>
4669 <message> 4683 <message>
4670 <location filename="../../src/yuzu/main.cpp" line="1859"/> 4684 <location filename="../../src/yuzu/main.cpp" line="1859"/>
4671 <source>%1 %2</source> 4685 <source>%1 %2</source>
4672 <comment>%1 is the title name. %2 indicates if the title is 64-bit or 32-bit</comment> 4686 <comment>%1 is the title name. %2 indicates if the title is 64-bit or 32-bit</comment>
4673 <translation type="unfinished"/> 4687 <translation>%1 %2</translation>
4674 </message> 4688 </message>
4675 <message> 4689 <message>
4676 <location filename="../../src/yuzu/main.cpp" line="1917"/> 4690 <location filename="../../src/yuzu/main.cpp" line="1917"/>
4677 <source>Closing software...</source> 4691 <source>Closing software...</source>
4678 <translation type="unfinished"/> 4692 <translation>Software sluiten...</translation>
4679 </message> 4693 </message>
4680 <message> 4694 <message>
4681 <location filename="../../src/yuzu/main.cpp" line="2066"/> 4695 <location filename="../../src/yuzu/main.cpp" line="2066"/>
@@ -4690,58 +4704,58 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4690 <message> 4704 <message>
4691 <location filename="../../src/yuzu/main.cpp" line="2135"/> 4705 <location filename="../../src/yuzu/main.cpp" line="2135"/>
4692 <source>Error Opening %1 Folder</source> 4706 <source>Error Opening %1 Folder</source>
4693 <translation>Fout tijdens het openen van %1 folder</translation> 4707 <translation>Fout tijdens het openen van %1 map</translation>
4694 </message> 4708 </message>
4695 <message> 4709 <message>
4696 <location filename="../../src/yuzu/main.cpp" line="2136"/> 4710 <location filename="../../src/yuzu/main.cpp" line="2136"/>
4697 <location filename="../../src/yuzu/main.cpp" line="2718"/> 4711 <location filename="../../src/yuzu/main.cpp" line="2718"/>
4698 <source>Folder does not exist!</source> 4712 <source>Folder does not exist!</source>
4699 <translation>Folder bestaat niet!</translation> 4713 <translation>Map bestaat niet!</translation>
4700 </message> 4714 </message>
4701 <message> 4715 <message>
4702 <location filename="../../src/yuzu/main.cpp" line="2148"/> 4716 <location filename="../../src/yuzu/main.cpp" line="2148"/>
4703 <source>Error Opening Transferable Shader Cache</source> 4717 <source>Error Opening Transferable Shader Cache</source>
4704 <translation>Fout Bij Het Openen Van Overdraagbare Shader Cache</translation> 4718 <translation>Fout bij het openen van overdraagbare shader-cache</translation>
4705 </message> 4719 </message>
4706 <message> 4720 <message>
4707 <location filename="../../src/yuzu/main.cpp" line="2149"/> 4721 <location filename="../../src/yuzu/main.cpp" line="2149"/>
4708 <source>Failed to create the shader cache directory for this title.</source> 4722 <source>Failed to create the shader cache directory for this title.</source>
4709 <translation type="unfinished"/> 4723 <translation>Kon de shader-cache-map voor dit spel niet aanmaken.</translation>
4710 </message> 4724 </message>
4711 <message> 4725 <message>
4712 <location filename="../../src/yuzu/main.cpp" line="2200"/> 4726 <location filename="../../src/yuzu/main.cpp" line="2200"/>
4713 <source>Error Removing Contents</source> 4727 <source>Error Removing Contents</source>
4714 <translation type="unfinished"/> 4728 <translation>Fout bij het verwijderen van de inhoud</translation>
4715 </message> 4729 </message>
4716 <message> 4730 <message>
4717 <location filename="../../src/yuzu/main.cpp" line="2202"/> 4731 <location filename="../../src/yuzu/main.cpp" line="2202"/>
4718 <source>Error Removing Update</source> 4732 <source>Error Removing Update</source>
4719 <translation type="unfinished"/> 4733 <translation>Fout bij het verwijderen van de update</translation>
4720 </message> 4734 </message>
4721 <message> 4735 <message>
4722 <location filename="../../src/yuzu/main.cpp" line="2204"/> 4736 <location filename="../../src/yuzu/main.cpp" line="2204"/>
4723 <source>Error Removing DLC</source> 4737 <source>Error Removing DLC</source>
4724 <translation type="unfinished"/> 4738 <translation>Fout bij het verwijderen van DLC</translation>
4725 </message> 4739 </message>
4726 <message> 4740 <message>
4727 <location filename="../../src/yuzu/main.cpp" line="2213"/> 4741 <location filename="../../src/yuzu/main.cpp" line="2213"/>
4728 <source>Remove Installed Game Contents?</source> 4742 <source>Remove Installed Game Contents?</source>
4729 <translation type="unfinished"/> 4743 <translation>Geïnstalleerde Spelinhoud Verwijderen?</translation>
4730 </message> 4744 </message>
4731 <message> 4745 <message>
4732 <location filename="../../src/yuzu/main.cpp" line="2215"/> 4746 <location filename="../../src/yuzu/main.cpp" line="2215"/>
4733 <source>Remove Installed Game Update?</source> 4747 <source>Remove Installed Game Update?</source>
4734 <translation type="unfinished"/> 4748 <translation>Geïnstalleerde Spel-update Verwijderen?</translation>
4735 </message> 4749 </message>
4736 <message> 4750 <message>
4737 <location filename="../../src/yuzu/main.cpp" line="2217"/> 4751 <location filename="../../src/yuzu/main.cpp" line="2217"/>
4738 <source>Remove Installed Game DLC?</source> 4752 <source>Remove Installed Game DLC?</source>
4739 <translation type="unfinished"/> 4753 <translation>Geïnstalleerde Spel-DLC Verwijderen?</translation>
4740 </message> 4754 </message>
4741 <message> 4755 <message>
4742 <location filename="../../src/yuzu/main.cpp" line="2223"/> 4756 <location filename="../../src/yuzu/main.cpp" line="2223"/>
4743 <source>Remove Entry</source> 4757 <source>Remove Entry</source>
4744 <translation type="unfinished"/> 4758 <translation>Verwijder Invoer</translation>
4745 </message> 4759 </message>
4746 <message> 4760 <message>
4747 <location filename="../../src/yuzu/main.cpp" line="2254"/> 4761 <location filename="../../src/yuzu/main.cpp" line="2254"/>
@@ -4751,147 +4765,147 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4751 <location filename="../../src/yuzu/main.cpp" line="2398"/> 4765 <location filename="../../src/yuzu/main.cpp" line="2398"/>
4752 <location filename="../../src/yuzu/main.cpp" line="2421"/> 4766 <location filename="../../src/yuzu/main.cpp" line="2421"/>
4753 <source>Successfully Removed</source> 4767 <source>Successfully Removed</source>
4754 <translation type="unfinished"/> 4768 <translation>Met Succes Verwijderd</translation>
4755 </message> 4769 </message>
4756 <message> 4770 <message>
4757 <location filename="../../src/yuzu/main.cpp" line="2255"/> 4771 <location filename="../../src/yuzu/main.cpp" line="2255"/>
4758 <source>Successfully removed the installed base game.</source> 4772 <source>Successfully removed the installed base game.</source>
4759 <translation type="unfinished"/> 4773 <translation>Het geïnstalleerde basisspel is succesvol verwijderd.</translation>
4760 </message> 4774 </message>
4761 <message> 4775 <message>
4762 <location filename="../../src/yuzu/main.cpp" line="2259"/> 4776 <location filename="../../src/yuzu/main.cpp" line="2259"/>
4763 <source>The base game is not installed in the NAND and cannot be removed.</source> 4777 <source>The base game is not installed in the NAND and cannot be removed.</source>
4764 <translation type="unfinished"/> 4778 <translation>Het basisspel is niet geïnstalleerd in de NAND en kan niet worden verwijderd.</translation>
4765 </message> 4779 </message>
4766 <message> 4780 <message>
4767 <location filename="../../src/yuzu/main.cpp" line="2271"/> 4781 <location filename="../../src/yuzu/main.cpp" line="2271"/>
4768 <source>Successfully removed the installed update.</source> 4782 <source>Successfully removed the installed update.</source>
4769 <translation type="unfinished"/> 4783 <translation>De geïnstalleerde update is succesvol verwijderd.</translation>
4770 </message> 4784 </message>
4771 <message> 4785 <message>
4772 <location filename="../../src/yuzu/main.cpp" line="2274"/> 4786 <location filename="../../src/yuzu/main.cpp" line="2274"/>
4773 <source>There is no update installed for this title.</source> 4787 <source>There is no update installed for this title.</source>
4774 <translation type="unfinished"/> 4788 <translation>Er is geen update geïnstalleerd voor dit spel.</translation>
4775 </message> 4789 </message>
4776 <message> 4790 <message>
4777 <location filename="../../src/yuzu/main.cpp" line="2297"/> 4791 <location filename="../../src/yuzu/main.cpp" line="2297"/>
4778 <source>There are no DLC installed for this title.</source> 4792 <source>There are no DLC installed for this title.</source>
4779 <translation type="unfinished"/> 4793 <translation>Er is geen DLC geïnstalleerd voor dit spel.</translation>
4780 </message> 4794 </message>
4781 <message> 4795 <message>
4782 <location filename="../../src/yuzu/main.cpp" line="2302"/> 4796 <location filename="../../src/yuzu/main.cpp" line="2302"/>
4783 <source>Successfully removed %1 installed DLC.</source> 4797 <source>Successfully removed %1 installed DLC.</source>
4784 <translation type="unfinished"/> 4798 <translation>%1 geïnstalleerde DLC met succes verwijderd.</translation>
4785 </message> 4799 </message>
4786 <message> 4800 <message>
4787 <location filename="../../src/yuzu/main.cpp" line="2310"/> 4801 <location filename="../../src/yuzu/main.cpp" line="2310"/>
4788 <source>Delete OpenGL Transferable Shader Cache?</source> 4802 <source>Delete OpenGL Transferable Shader Cache?</source>
4789 <translation type="unfinished"/> 4803 <translation>Overdraagbare OpenGL-shader-cache Verwijderen?</translation>
4790 </message> 4804 </message>
4791 <message> 4805 <message>
4792 <location filename="../../src/yuzu/main.cpp" line="2312"/> 4806 <location filename="../../src/yuzu/main.cpp" line="2312"/>
4793 <source>Delete Vulkan Transferable Shader Cache?</source> 4807 <source>Delete Vulkan Transferable Shader Cache?</source>
4794 <translation type="unfinished"/> 4808 <translation>Overdraagbare Vulkan-shader-cache Verwijderen?</translation>
4795 </message> 4809 </message>
4796 <message> 4810 <message>
4797 <location filename="../../src/yuzu/main.cpp" line="2314"/> 4811 <location filename="../../src/yuzu/main.cpp" line="2314"/>
4798 <source>Delete All Transferable Shader Caches?</source> 4812 <source>Delete All Transferable Shader Caches?</source>
4799 <translation type="unfinished"/> 4813 <translation>Alle Overdraagbare Shader-caches Verwijderen?</translation>
4800 </message> 4814 </message>
4801 <message> 4815 <message>
4802 <location filename="../../src/yuzu/main.cpp" line="2316"/> 4816 <location filename="../../src/yuzu/main.cpp" line="2316"/>
4803 <source>Remove Custom Game Configuration?</source> 4817 <source>Remove Custom Game Configuration?</source>
4804 <translation type="unfinished"/> 4818 <translation>Aangepaste Spelconfiguratie Verwijderen?</translation>
4805 </message> 4819 </message>
4806 <message> 4820 <message>
4807 <location filename="../../src/yuzu/main.cpp" line="2322"/> 4821 <location filename="../../src/yuzu/main.cpp" line="2322"/>
4808 <source>Remove File</source> 4822 <source>Remove File</source>
4809 <translation type="unfinished"/> 4823 <translation>Verwijder Bestand</translation>
4810 </message> 4824 </message>
4811 <message> 4825 <message>
4812 <location filename="../../src/yuzu/main.cpp" line="2359"/> 4826 <location filename="../../src/yuzu/main.cpp" line="2359"/>
4813 <location filename="../../src/yuzu/main.cpp" line="2367"/> 4827 <location filename="../../src/yuzu/main.cpp" line="2367"/>
4814 <source>Error Removing Transferable Shader Cache</source> 4828 <source>Error Removing Transferable Shader Cache</source>
4815 <translation type="unfinished"/> 4829 <translation>Fout bij het verwijderen van Overdraagbare Shader-cache</translation>
4816 </message> 4830 </message>
4817 <message> 4831 <message>
4818 <location filename="../../src/yuzu/main.cpp" line="2360"/> 4832 <location filename="../../src/yuzu/main.cpp" line="2360"/>
4819 <location filename="../../src/yuzu/main.cpp" line="2394"/> 4833 <location filename="../../src/yuzu/main.cpp" line="2394"/>
4820 <source>A shader cache for this title does not exist.</source> 4834 <source>A shader cache for this title does not exist.</source>
4821 <translation>Er bestaat geen shader cache voor deze game</translation> 4835 <translation>Er bestaat geen shader-cache voor dit spel.</translation>
4822 </message> 4836 </message>
4823 <message> 4837 <message>
4824 <location filename="../../src/yuzu/main.cpp" line="2365"/> 4838 <location filename="../../src/yuzu/main.cpp" line="2365"/>
4825 <source>Successfully removed the transferable shader cache.</source> 4839 <source>Successfully removed the transferable shader cache.</source>
4826 <translation type="unfinished"/> 4840 <translation>De overdraagbare shader-cache is verwijderd.</translation>
4827 </message> 4841 </message>
4828 <message> 4842 <message>
4829 <location filename="../../src/yuzu/main.cpp" line="2368"/> 4843 <location filename="../../src/yuzu/main.cpp" line="2368"/>
4830 <source>Failed to remove the transferable shader cache.</source> 4844 <source>Failed to remove the transferable shader cache.</source>
4831 <translation type="unfinished"/> 4845 <translation>Kon de overdraagbare shader-cache niet verwijderen.</translation>
4832 </message> 4846 </message>
4833 <message> 4847 <message>
4834 <location filename="../../src/yuzu/main.cpp" line="2383"/> 4848 <location filename="../../src/yuzu/main.cpp" line="2383"/>
4835 <source>Error Removing Vulkan Driver Pipeline Cache</source> 4849 <source>Error Removing Vulkan Driver Pipeline Cache</source>
4836 <translation type="unfinished"/> 4850 <translation>Fout bij het verwijderen van Pijplijn-cache van Vulkan-driver</translation>
4837 </message> 4851 </message>
4838 <message> 4852 <message>
4839 <location filename="../../src/yuzu/main.cpp" line="2384"/> 4853 <location filename="../../src/yuzu/main.cpp" line="2384"/>
4840 <source>Failed to remove the driver pipeline cache.</source> 4854 <source>Failed to remove the driver pipeline cache.</source>
4841 <translation type="unfinished"/> 4855 <translation>Kon de pijplijn-cache van de driver niet verwijderen.</translation>
4842 </message> 4856 </message>
4843 <message> 4857 <message>
4844 <location filename="../../src/yuzu/main.cpp" line="2393"/> 4858 <location filename="../../src/yuzu/main.cpp" line="2393"/>
4845 <location filename="../../src/yuzu/main.cpp" line="2401"/> 4859 <location filename="../../src/yuzu/main.cpp" line="2401"/>
4846 <source>Error Removing Transferable Shader Caches</source> 4860 <source>Error Removing Transferable Shader Caches</source>
4847 <translation type="unfinished"/> 4861 <translation>Fout bij het verwijderen van overdraagbare shader-caches</translation>
4848 </message> 4862 </message>
4849 <message> 4863 <message>
4850 <location filename="../../src/yuzu/main.cpp" line="2399"/> 4864 <location filename="../../src/yuzu/main.cpp" line="2399"/>
4851 <source>Successfully removed the transferable shader caches.</source> 4865 <source>Successfully removed the transferable shader caches.</source>
4852 <translation type="unfinished"/> 4866 <translation>De overdraagbare shader-caches zijn verwijderd.</translation>
4853 </message> 4867 </message>
4854 <message> 4868 <message>
4855 <location filename="../../src/yuzu/main.cpp" line="2402"/> 4869 <location filename="../../src/yuzu/main.cpp" line="2402"/>
4856 <source>Failed to remove the transferable shader cache directory.</source> 4870 <source>Failed to remove the transferable shader cache directory.</source>
4857 <translation type="unfinished"/> 4871 <translation>Kon de overdraagbare shader-cache-map niet verwijderen.</translation>
4858 </message> 4872 </message>
4859 <message> 4873 <message>
4860 <location filename="../../src/yuzu/main.cpp" line="2415"/> 4874 <location filename="../../src/yuzu/main.cpp" line="2415"/>
4861 <location filename="../../src/yuzu/main.cpp" line="2424"/> 4875 <location filename="../../src/yuzu/main.cpp" line="2424"/>
4862 <source>Error Removing Custom Configuration</source> 4876 <source>Error Removing Custom Configuration</source>
4863 <translation type="unfinished"/> 4877 <translation>Fout bij het verwijderen van aangepaste configuratie</translation>
4864 </message> 4878 </message>
4865 <message> 4879 <message>
4866 <location filename="../../src/yuzu/main.cpp" line="2416"/> 4880 <location filename="../../src/yuzu/main.cpp" line="2416"/>
4867 <source>A custom configuration for this title does not exist.</source> 4881 <source>A custom configuration for this title does not exist.</source>
4868 <translation type="unfinished"/> 4882 <translation>Er bestaat geen aangepaste configuratie voor dit spel.</translation>
4869 </message> 4883 </message>
4870 <message> 4884 <message>
4871 <location filename="../../src/yuzu/main.cpp" line="2422"/> 4885 <location filename="../../src/yuzu/main.cpp" line="2422"/>
4872 <source>Successfully removed the custom game configuration.</source> 4886 <source>Successfully removed the custom game configuration.</source>
4873 <translation type="unfinished"/> 4887 <translation>De aangepaste spelconfiguratie is verwijderd.</translation>
4874 </message> 4888 </message>
4875 <message> 4889 <message>
4876 <location filename="../../src/yuzu/main.cpp" line="2425"/> 4890 <location filename="../../src/yuzu/main.cpp" line="2425"/>
4877 <source>Failed to remove the custom game configuration.</source> 4891 <source>Failed to remove the custom game configuration.</source>
4878 <translation type="unfinished"/> 4892 <translation>Kon de aangepaste spelconfiguratie niet verwijderen.</translation>
4879 </message> 4893 </message>
4880 <message> 4894 <message>
4881 <location filename="../../src/yuzu/main.cpp" line="2432"/> 4895 <location filename="../../src/yuzu/main.cpp" line="2432"/>
4882 <location filename="../../src/yuzu/main.cpp" line="2511"/> 4896 <location filename="../../src/yuzu/main.cpp" line="2511"/>
4883 <source>RomFS Extraction Failed!</source> 4897 <source>RomFS Extraction Failed!</source>
4884 <translation>RomFS Extractie Mislukt!</translation> 4898 <translation>RomFS-extractie Mislukt!</translation>
4885 </message> 4899 </message>
4886 <message> 4900 <message>
4887 <location filename="../../src/yuzu/main.cpp" line="2433"/> 4901 <location filename="../../src/yuzu/main.cpp" line="2433"/>
4888 <source>There was an error copying the RomFS files or the user cancelled the operation.</source> 4902 <source>There was an error copying the RomFS files or the user cancelled the operation.</source>
4889 <translation>Er was een fout tijdens het kopiëren van de RomFS bestanden of de gebruiker heeft de operatie geannuleerd.</translation> 4903 <translation>Er is een fout opgetreden bij het kopiëren van de RomFS-bestanden of de gebruiker heeft de bewerking geannuleerd.</translation>
4890 </message> 4904 </message>
4891 <message> 4905 <message>
4892 <location filename="../../src/yuzu/main.cpp" line="2491"/> 4906 <location filename="../../src/yuzu/main.cpp" line="2491"/>
4893 <source>Full</source> 4907 <source>Full</source>
4894 <translation>Vol</translation> 4908 <translation>Volledig</translation>
4895 </message> 4909 </message>
4896 <message> 4910 <message>
4897 <location filename="../../src/yuzu/main.cpp" line="2491"/> 4911 <location filename="../../src/yuzu/main.cpp" line="2491"/>
@@ -4901,17 +4915,17 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4901 <message> 4915 <message>
4902 <location filename="../../src/yuzu/main.cpp" line="2493"/> 4916 <location filename="../../src/yuzu/main.cpp" line="2493"/>
4903 <source>Select RomFS Dump Mode</source> 4917 <source>Select RomFS Dump Mode</source>
4904 <translation>Selecteer RomFS Dump Mode</translation> 4918 <translation>Selecteer RomFS-dumpmodus</translation>
4905 </message> 4919 </message>
4906 <message> 4920 <message>
4907 <location filename="../../src/yuzu/main.cpp" line="2494"/> 4921 <location filename="../../src/yuzu/main.cpp" line="2494"/>
4908 <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source> 4922 <source>Please select the how you would like the RomFS dumped.&lt;br&gt;Full will copy all of the files into the new directory while &lt;br&gt;skeleton will only create the directory structure.</source>
4909 <translation>Selecteer alstublieft hoe je de RomFS wilt dumpen.&lt;br&gt;Volledig kopieërd alle bestanden in een map terwijl &lt;br&gt; skelet maakt alleen het map structuur.</translation> 4923 <translation>Selecteer hoe je de RomFS gedumpt wilt hebben.&lt;br&gt;Volledig zal alle bestanden naar de nieuwe map kopiëren, terwijl &lt;br&gt;Skelet alleen de mapstructuur zal aanmaken.</translation>
4910 </message> 4924 </message>
4911 <message> 4925 <message>
4912 <location filename="../../src/yuzu/main.cpp" line="2512"/> 4926 <location filename="../../src/yuzu/main.cpp" line="2512"/>
4913 <source>There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation &gt; Configure &gt; System &gt; Filesystem &gt; Dump Root</source> 4927 <source>There is not enough free space at %1 to extract the RomFS. Please free up space or select a different dump directory at Emulation &gt; Configure &gt; System &gt; Filesystem &gt; Dump Root</source>
4914 <translation type="unfinished"/> 4928 <translation>Er is niet genoeg vrije ruimte op %1 om de RomFS uit te pakken. Maak ruimte vrij of kies een andere dumpmap bij Emulatie &gt; Configuratie &gt; Systeem &gt; Bestandssysteem &gt; Dump Root.</translation>
4915 </message> 4929 </message>
4916 <message> 4930 <message>
4917 <location filename="../../src/yuzu/main.cpp" line="2519"/> 4931 <location filename="../../src/yuzu/main.cpp" line="2519"/>
@@ -4927,12 +4941,12 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4927 <message> 4941 <message>
4928 <location filename="../../src/yuzu/main.cpp" line="2526"/> 4942 <location filename="../../src/yuzu/main.cpp" line="2526"/>
4929 <source>RomFS Extraction Succeeded!</source> 4943 <source>RomFS Extraction Succeeded!</source>
4930 <translation>RomFS Extractie Geslaagd!</translation> 4944 <translation>RomFS-extractie Geslaagd!</translation>
4931 </message> 4945 </message>
4932 <message> 4946 <message>
4933 <location filename="../../src/yuzu/main.cpp" line="2527"/> 4947 <location filename="../../src/yuzu/main.cpp" line="2527"/>
4934 <source>The operation completed successfully.</source> 4948 <source>The operation completed successfully.</source>
4935 <translation>De operatie is succesvol voltooid.</translation> 4949 <translation>De bewerking is succesvol voltooid.</translation>
4936 </message> 4950 </message>
4937 <message> 4951 <message>
4938 <location filename="../../src/yuzu/main.cpp" line="2571"/> 4952 <location filename="../../src/yuzu/main.cpp" line="2571"/>
@@ -4941,47 +4955,47 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
4941 <location filename="../../src/yuzu/main.cpp" line="2687"/> 4955 <location filename="../../src/yuzu/main.cpp" line="2687"/>
4942 <location filename="../../src/yuzu/main.cpp" line="2695"/> 4956 <location filename="../../src/yuzu/main.cpp" line="2695"/>
4943 <source>Create Shortcut</source> 4957 <source>Create Shortcut</source>
4944 <translation type="unfinished"/> 4958 <translation>Maak Snelkoppeling</translation>
4945 </message> 4959 </message>
4946 <message> 4960 <message>
4947 <location filename="../../src/yuzu/main.cpp" line="2572"/> 4961 <location filename="../../src/yuzu/main.cpp" line="2572"/>
4948 <source>This will create a shortcut to the current AppImage. This may not work well if you update. Continue?</source> 4962 <source>This will create a shortcut to the current AppImage. This may not work well if you update. Continue?</source>
4949 <translation type="unfinished"/> 4963 <translation>Dit maakt een snelkoppeling naar de huidige AppImage. Dit werkt mogelijk niet goed als je een update uitvoert. Doorgaan?</translation>
4950 </message> 4964 </message>
4951 <message> 4965 <message>
4952 <location filename="../../src/yuzu/main.cpp" line="2596"/> 4966 <location filename="../../src/yuzu/main.cpp" line="2596"/>
4953 <source>Cannot create shortcut on desktop. Path &quot;%1&quot; does not exist.</source> 4967 <source>Cannot create shortcut on desktop. Path &quot;%1&quot; does not exist.</source>
4954 <translation type="unfinished"/> 4968 <translation>Kan geen snelkoppeling op het bureaublad maken. Pad &quot;%1&quot; bestaat niet.</translation>
4955 </message> 4969 </message>
4956 <message> 4970 <message>
4957 <location filename="../../src/yuzu/main.cpp" line="2606"/> 4971 <location filename="../../src/yuzu/main.cpp" line="2606"/>
4958 <source>Cannot create shortcut in applications menu. Path &quot;%1&quot; does not exist and cannot be created.</source> 4972 <source>Cannot create shortcut in applications menu. Path &quot;%1&quot; does not exist and cannot be created.</source>
4959 <translation type="unfinished"/> 4973 <translation>Kan geen snelkoppeling maken in toepassingen menu. Pad &quot;%1&quot; bestaat niet en kan niet worden aangemaakt.</translation>
4960 </message> 4974 </message>
4961 <message> 4975 <message>
4962 <location filename="../../src/yuzu/main.cpp" line="2623"/> 4976 <location filename="../../src/yuzu/main.cpp" line="2623"/>
4963 <source>Create Icon</source> 4977 <source>Create Icon</source>
4964 <translation type="unfinished"/> 4978 <translation>Maak Icoon</translation>
4965 </message> 4979 </message>
4966 <message> 4980 <message>
4967 <location filename="../../src/yuzu/main.cpp" line="2624"/> 4981 <location filename="../../src/yuzu/main.cpp" line="2624"/>
4968 <source>Cannot create icon file. Path &quot;%1&quot; does not exist and cannot be created.</source> 4982 <source>Cannot create icon file. Path &quot;%1&quot; does not exist and cannot be created.</source>
4969 <translation type="unfinished"/> 4983 <translation>Kan geen icoonbestand maken. Pad &quot;%1&quot; bestaat niet en kan niet worden aangemaakt.</translation>
4970 </message> 4984 </message>
4971 <message> 4985 <message>
4972 <location filename="../../src/yuzu/main.cpp" line="2675"/> 4986 <location filename="../../src/yuzu/main.cpp" line="2675"/>
4973 <source>Start %1 with the yuzu Emulator</source> 4987 <source>Start %1 with the yuzu Emulator</source>
4974 <translation type="unfinished"/> 4988 <translation>Voer %1 uiit met de yuzu-emulator</translation>
4975 </message> 4989 </message>
4976 <message> 4990 <message>
4977 <location filename="../../src/yuzu/main.cpp" line="2688"/> 4991 <location filename="../../src/yuzu/main.cpp" line="2688"/>
4978 <source>Failed to create a shortcut at %1</source> 4992 <source>Failed to create a shortcut at %1</source>
4979 <translation type="unfinished"/> 4993 <translation>Er is geen snelkoppeling gemaakt op %1</translation>
4980 </message> 4994 </message>
4981 <message> 4995 <message>
4982 <location filename="../../src/yuzu/main.cpp" line="2696"/> 4996 <location filename="../../src/yuzu/main.cpp" line="2696"/>
4983 <source>Successfully created a shortcut to %1</source> 4997 <source>Successfully created a shortcut to %1</source>
4984 <translation type="unfinished"/> 4998 <translation>Succesvol een snelkoppeling naar %1 gemaakt</translation>
4985 </message> 4999 </message>
4986 <message> 5000 <message>
4987 <location filename="../../src/yuzu/main.cpp" line="2717"/> 5001 <location filename="../../src/yuzu/main.cpp" line="2717"/>
@@ -5001,13 +5015,13 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
5001 <message> 5015 <message>
5002 <location filename="../../src/yuzu/main.cpp" line="2756"/> 5016 <location filename="../../src/yuzu/main.cpp" line="2756"/>
5003 <source>The game properties could not be loaded.</source> 5017 <source>The game properties could not be loaded.</source>
5004 <translation>De eigenschappen van de game kunnen niet geladen worden.</translation> 5018 <translation>De speleigenschappen kunnen niet geladen worden.</translation>
5005 </message> 5019 </message>
5006 <message> 5020 <message>
5007 <location filename="../../src/yuzu/main.cpp" line="2773"/> 5021 <location filename="../../src/yuzu/main.cpp" line="2773"/>
5008 <source>Switch Executable (%1);;All Files (*.*)</source> 5022 <source>Switch Executable (%1);;All Files (*.*)</source>
5009 <comment>%1 is an identifier for the Switch executable file extensions.</comment> 5023 <comment>%1 is an identifier for the Switch executable file extensions.</comment>
5010 <translation>Switch Executable (%1);;Alle bestanden (*.*)</translation> 5024 <translation>Switch Executable (%1);;Alle Bestanden (*.*)</translation>
5011 </message> 5025 </message>
5012 <message> 5026 <message>
5013 <location filename="../../src/yuzu/main.cpp" line="2777"/> 5027 <location filename="../../src/yuzu/main.cpp" line="2777"/>
@@ -5017,7 +5031,7 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
5017 <message> 5031 <message>
5018 <location filename="../../src/yuzu/main.cpp" line="2790"/> 5032 <location filename="../../src/yuzu/main.cpp" line="2790"/>
5019 <source>Open Extracted ROM Directory</source> 5033 <source>Open Extracted ROM Directory</source>
5020 <translation>Open Gedecomprimeerd ROM Map</translation> 5034 <translation>Open Uitgepakte ROM-map</translation>
5021 </message> 5035 </message>
5022 <message> 5036 <message>
5023 <location filename="../../src/yuzu/main.cpp" line="2801"/> 5037 <location filename="../../src/yuzu/main.cpp" line="2801"/>
@@ -5027,22 +5041,22 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
5027 <message> 5041 <message>
5028 <location filename="../../src/yuzu/main.cpp" line="2802"/> 5042 <location filename="../../src/yuzu/main.cpp" line="2802"/>
5029 <source>The directory you have selected does not contain a &apos;main&apos; file.</source> 5043 <source>The directory you have selected does not contain a &apos;main&apos; file.</source>
5030 <translation>De map die je hebt geselecteerd bevat geen &apos;main&apos; bestand.</translation> 5044 <translation>De map die je hebt geselecteerd bevat geen &apos;main&apos;-bestand.</translation>
5031 </message> 5045 </message>
5032 <message> 5046 <message>
5033 <location filename="../../src/yuzu/main.cpp" line="2812"/> 5047 <location filename="../../src/yuzu/main.cpp" line="2812"/>
5034 <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source> 5048 <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source>
5035 <translation type="unfinished"/> 5049 <translation>Installeerbaar Switch-bestand (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</translation>
5036 </message> 5050 </message>
5037 <message> 5051 <message>
5038 <location filename="../../src/yuzu/main.cpp" line="2817"/> 5052 <location filename="../../src/yuzu/main.cpp" line="2817"/>
5039 <source>Install Files</source> 5053 <source>Install Files</source>
5040 <translation type="unfinished"/> 5054 <translation>Installeer Bestanden</translation>
5041 </message> 5055 </message>
5042 <message numerus="yes"> 5056 <message numerus="yes">
5043 <location filename="../../src/yuzu/main.cpp" line="2863"/> 5057 <location filename="../../src/yuzu/main.cpp" line="2863"/>
5044 <source>%n file(s) remaining</source> 5058 <source>%n file(s) remaining</source>
5045 <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> 5059 <translation><numerusform>%n bestand(en) resterend</numerusform><numerusform>%n bestand(en) resterend</numerusform></translation>
5046 </message> 5060 </message>
5047 <message> 5061 <message>
5048 <location filename="../../src/yuzu/main.cpp" line="2865"/> 5062 <location filename="../../src/yuzu/main.cpp" line="2865"/>
@@ -5053,71 +5067,78 @@ Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen
5053 <location filename="../../src/yuzu/main.cpp" line="2911"/> 5067 <location filename="../../src/yuzu/main.cpp" line="2911"/>
5054 <location filename="../../src/yuzu/main.cpp" line="2925"/> 5068 <location filename="../../src/yuzu/main.cpp" line="2925"/>
5055 <source>Install Results</source> 5069 <source>Install Results</source>
5056 <translation type="unfinished"/> 5070 <translation>Installeerresultaten</translation>
5057 </message> 5071 </message>
5058 <message> 5072 <message>
5059 <location filename="../../src/yuzu/main.cpp" line="2912"/> 5073 <location filename="../../src/yuzu/main.cpp" line="2912"/>
5060 <source>To avoid possible conflicts, we discourage users from installing base games to the NAND. 5074 <source>To avoid possible conflicts, we discourage users from installing base games to the NAND.
5061Please, only use this feature to install updates and DLC.</source> 5075Please, only use this feature to install updates and DLC.</source>
5062 <translation type="unfinished"/> 5076 <translation>Om mogelijke conflicten te voorkomen, raden we gebruikers af om basisgames te installeren op de NAND.
5077Gebruik deze functie alleen om updates en DLC te installeren.</translation>
5063 </message> 5078 </message>
5064 <message numerus="yes"> 5079 <message numerus="yes">
5065 <location filename="../../src/yuzu/main.cpp" line="2918"/> 5080 <location filename="../../src/yuzu/main.cpp" line="2918"/>
5066 <source>%n file(s) were newly installed 5081 <source>%n file(s) were newly installed
5067</source> 5082</source>
5068 <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> 5083 <translation><numerusform>%n bestand(en) zijn recent geïnstalleerd
5084</numerusform><numerusform>%n bestand(en) zijn recent geïnstalleerd
5085</numerusform></translation>
5069 </message> 5086 </message>
5070 <message numerus="yes"> 5087 <message numerus="yes">
5071 <location filename="../../src/yuzu/main.cpp" line="2921"/> 5088 <location filename="../../src/yuzu/main.cpp" line="2921"/>
5072 <source>%n file(s) were overwritten 5089 <source>%n file(s) were overwritten
5073</source> 5090</source>
5074 <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> 5091 <translation><numerusform>%n bestand(en) werden overschreven
5092</numerusform><numerusform>%n bestand(en) werden overschreven
5093</numerusform></translation>
5075 </message> 5094 </message>
5076 <message numerus="yes"> 5095 <message numerus="yes">
5077 <location filename="../../src/yuzu/main.cpp" line="2923"/> 5096 <location filename="../../src/yuzu/main.cpp" line="2923"/>
5078 <source>%n file(s) failed to install 5097 <source>%n file(s) failed to install
5079</source> 5098</source>
5080 <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> 5099 <translation><numerusform>%n bestand(en) niet geïnstalleerd
5100</numerusform><numerusform>%n bestand(en) niet geïnstalleerd
5101</numerusform></translation>
5081 </message> 5102 </message>
5082 <message> 5103 <message>
5083 <location filename="../../src/yuzu/main.cpp" line="3024"/> 5104 <location filename="../../src/yuzu/main.cpp" line="3024"/>
5084 <source>System Application</source> 5105 <source>System Application</source>
5085 <translation>Systeem Applicatie</translation> 5106 <translation>Systeemapplicatie</translation>
5086 </message> 5107 </message>
5087 <message> 5108 <message>
5088 <location filename="../../src/yuzu/main.cpp" line="3025"/> 5109 <location filename="../../src/yuzu/main.cpp" line="3025"/>
5089 <source>System Archive</source> 5110 <source>System Archive</source>
5090 <translation>Systeem Archief</translation> 5111 <translation>Systeemarchief</translation>
5091 </message> 5112 </message>
5092 <message> 5113 <message>
5093 <location filename="../../src/yuzu/main.cpp" line="3026"/> 5114 <location filename="../../src/yuzu/main.cpp" line="3026"/>
5094 <source>System Application Update</source> 5115 <source>System Application Update</source>
5095 <translation>Systeem Applicatie Update</translation> 5116 <translation>Systeemapplicatie-update</translation>
5096 </message> 5117 </message>
5097 <message> 5118 <message>
5098 <location filename="../../src/yuzu/main.cpp" line="3027"/> 5119 <location filename="../../src/yuzu/main.cpp" line="3027"/>
5099 <source>Firmware Package (Type A)</source> 5120 <source>Firmware Package (Type A)</source>
5100 <translation>Filmware Pakket (Type A)</translation> 5121 <translation>Filmware-pakket (Type A)</translation>
5101 </message> 5122 </message>
5102 <message> 5123 <message>
5103 <location filename="../../src/yuzu/main.cpp" line="3028"/> 5124 <location filename="../../src/yuzu/main.cpp" line="3028"/>
5104 <source>Firmware Package (Type B)</source> 5125 <source>Firmware Package (Type B)</source>
5105 <translation>Filmware Pakket (Type B)</translation> 5126 <translation>Filmware-pakket (Type B)</translation>
5106 </message> 5127 </message>
5107 <message> 5128 <message>
5108 <location filename="../../src/yuzu/main.cpp" line="3029"/> 5129 <location filename="../../src/yuzu/main.cpp" line="3029"/>
5109 <source>Game</source> 5130 <source>Game</source>
5110 <translation>Game</translation> 5131 <translation>Spel</translation>
5111 </message> 5132 </message>
5112 <message> 5133 <message>
5113 <location filename="../../src/yuzu/main.cpp" line="3030"/> 5134 <location filename="../../src/yuzu/main.cpp" line="3030"/>
5114 <source>Game Update</source> 5135 <source>Game Update</source>
5115 <translation>Game Update</translation> 5136 <translation>Spelupdate</translation>
5116 </message> 5137 </message>
5117 <message> 5138 <message>
5118 <location filename="../../src/yuzu/main.cpp" line="3031"/> 5139 <location filename="../../src/yuzu/main.cpp" line="3031"/>
5119 <source>Game DLC</source> 5140 <source>Game DLC</source>
5120 <translation>Game DLC</translation> 5141 <translation>Spel-DLC</translation>
5121 </message> 5142 </message>
5122 <message> 5143 <message>
5123 <location filename="../../src/yuzu/main.cpp" line="3032"/> 5144 <location filename="../../src/yuzu/main.cpp" line="3032"/>
@@ -5127,14 +5148,14 @@ Please, only use this feature to install updates and DLC.</source>
5127 <message> 5148 <message>
5128 <location filename="../../src/yuzu/main.cpp" line="3035"/> 5149 <location filename="../../src/yuzu/main.cpp" line="3035"/>
5129 <source>Select NCA Install Type...</source> 5150 <source>Select NCA Install Type...</source>
5130 <translation>Selecteer NCA Installatie Type...</translation> 5151 <translation>Selecteer NCA-installatiesoort...</translation>
5131 </message> 5152 </message>
5132 <message> 5153 <message>
5133 <location filename="../../src/yuzu/main.cpp" line="3036"/> 5154 <location filename="../../src/yuzu/main.cpp" line="3036"/>
5134 <source>Please select the type of title you would like to install this NCA as: 5155 <source>Please select the type of title you would like to install this NCA as:
5135(In most instances, the default &apos;Game&apos; is fine.)</source> 5156(In most instances, the default &apos;Game&apos; is fine.)</source>
5136 <translation>Selecteer het type titel hoe je wilt dat deze NCA installeerd: 5157 <translation>Selecteer het type titel waarin je deze NCA wilt installeren:
5137(In de meeste gevallen is de standaard &apos;Game&apos; juist.)</translation> 5158(In de meeste gevallen is de standaard &quot;Spel&quot; prima).</translation>
5138 </message> 5159 </message>
5139 <message> 5160 <message>
5140 <location filename="../../src/yuzu/main.cpp" line="3042"/> 5161 <location filename="../../src/yuzu/main.cpp" line="3042"/>
@@ -5144,7 +5165,7 @@ Please, only use this feature to install updates and DLC.</source>
5144 <message> 5165 <message>
5145 <location filename="../../src/yuzu/main.cpp" line="3043"/> 5166 <location filename="../../src/yuzu/main.cpp" line="3043"/>
5146 <source>The title type you selected for the NCA is invalid.</source> 5167 <source>The title type you selected for the NCA is invalid.</source>
5147 <translation>Het type title dat je hebt geselecteerd voor de NCA is ongeldig.</translation> 5168 <translation>Het soort title dat je hebt geselecteerd voor de NCA is ongeldig.</translation>
5148 </message> 5169 </message>
5149 <message> 5170 <message>
5150 <location filename="../../src/yuzu/main.cpp" line="3078"/> 5171 <location filename="../../src/yuzu/main.cpp" line="3078"/>
@@ -5165,81 +5186,81 @@ Please, only use this feature to install updates and DLC.</source>
5165 <location filename="../../src/yuzu/main.cpp" line="3182"/> 5186 <location filename="../../src/yuzu/main.cpp" line="3182"/>
5166 <location filename="../../src/yuzu/main.cpp" line="3201"/> 5187 <location filename="../../src/yuzu/main.cpp" line="3201"/>
5167 <source>Hardware requirements not met</source> 5188 <source>Hardware requirements not met</source>
5168 <translation type="unfinished"/> 5189 <translation>Er is niet voldaan aan de hardwarevereisten</translation>
5169 </message> 5190 </message>
5170 <message> 5191 <message>
5171 <location filename="../../src/yuzu/main.cpp" line="3183"/> 5192 <location filename="../../src/yuzu/main.cpp" line="3183"/>
5172 <location filename="../../src/yuzu/main.cpp" line="3202"/> 5193 <location filename="../../src/yuzu/main.cpp" line="3202"/>
5173 <source>Your system does not meet the recommended hardware requirements. Compatibility reporting has been disabled.</source> 5194 <source>Your system does not meet the recommended hardware requirements. Compatibility reporting has been disabled.</source>
5174 <translation type="unfinished"/> 5195 <translation>Je systeem voldoet niet aan de aanbevolen hardwarevereisten. Compatibiliteitsrapportage is uitgeschakeld.</translation>
5175 </message> 5196 </message>
5176 <message> 5197 <message>
5177 <location filename="../../src/yuzu/main.cpp" line="3194"/> 5198 <location filename="../../src/yuzu/main.cpp" line="3194"/>
5178 <source>Missing yuzu Account</source> 5199 <source>Missing yuzu Account</source>
5179 <translation>Je yuzu account mist</translation> 5200 <translation>yuzu-account Ontbreekt</translation>
5180 </message> 5201 </message>
5181 <message> 5202 <message>
5182 <location filename="../../src/yuzu/main.cpp" line="3195"/> 5203 <location filename="../../src/yuzu/main.cpp" line="3195"/>
5183 <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source> 5204 <source>In order to submit a game compatibility test case, you must link your yuzu account.&lt;br&gt;&lt;br/&gt;To link your yuzu account, go to Emulation &amp;gt; Configuration &amp;gt; Web.</source>
5184 <translation>Om game campatibiliteit te raporteren, moet je je yuzu account koppelen.&lt;br&gt;&lt;br/&gt; Om je yuzu account te koppelen, ga naar Emulatie &amp;gt; Configuratie &amp;gt; Web.</translation> 5205 <translation>Om een spelcompatibiliteitstest in te dienen, moet je je yuzu-account koppelen.&lt;br&gt;&lt;br/&gt;Om je yuzu-account te koppelen, ga naar Emulatie &amp;gt; Configuratie &amp;gt; Web.</translation>
5185 </message> 5206 </message>
5186 <message> 5207 <message>
5187 <location filename="../../src/yuzu/main.cpp" line="3210"/> 5208 <location filename="../../src/yuzu/main.cpp" line="3210"/>
5188 <source>Error opening URL</source> 5209 <source>Error opening URL</source>
5189 <translation type="unfinished"/> 5210 <translation>Fout bij het openen van URL</translation>
5190 </message> 5211 </message>
5191 <message> 5212 <message>
5192 <location filename="../../src/yuzu/main.cpp" line="3211"/> 5213 <location filename="../../src/yuzu/main.cpp" line="3211"/>
5193 <source>Unable to open the URL &quot;%1&quot;.</source> 5214 <source>Unable to open the URL &quot;%1&quot;.</source>
5194 <translation type="unfinished"/> 5215 <translation>Kan de URL &quot;%1&quot; niet openen.</translation>
5195 </message> 5216 </message>
5196 <message> 5217 <message>
5197 <location filename="../../src/yuzu/main.cpp" line="3514"/> 5218 <location filename="../../src/yuzu/main.cpp" line="3514"/>
5198 <source>TAS Recording</source> 5219 <source>TAS Recording</source>
5199 <translation type="unfinished"/> 5220 <translation>TAS-opname</translation>
5200 </message> 5221 </message>
5201 <message> 5222 <message>
5202 <location filename="../../src/yuzu/main.cpp" line="3515"/> 5223 <location filename="../../src/yuzu/main.cpp" line="3515"/>
5203 <source>Overwrite file of player 1?</source> 5224 <source>Overwrite file of player 1?</source>
5204 <translation type="unfinished"/> 5225 <translation>Het bestand van speler 1 overschrijven?</translation>
5205 </message> 5226 </message>
5206 <message> 5227 <message>
5207 <location filename="../../src/yuzu/main.cpp" line="3541"/> 5228 <location filename="../../src/yuzu/main.cpp" line="3541"/>
5208 <source>Invalid config detected</source> 5229 <source>Invalid config detected</source>
5209 <translation type="unfinished"/> 5230 <translation>Ongeldige configuratie gedetecteerd</translation>
5210 </message> 5231 </message>
5211 <message> 5232 <message>
5212 <location filename="../../src/yuzu/main.cpp" line="3542"/> 5233 <location filename="../../src/yuzu/main.cpp" line="3542"/>
5213 <source>Handheld controller can&apos;t be used on docked mode. Pro controller will be selected.</source> 5234 <source>Handheld controller can&apos;t be used on docked mode. Pro controller will be selected.</source>
5214 <translation type="unfinished"/> 5235 <translation>Handheld-controller kan niet gebruikt worden in docked-modus. Pro controller wordt geselecteerd.</translation>
5215 </message> 5236 </message>
5216 <message> 5237 <message>
5217 <location filename="../../src/yuzu/main.cpp" line="3712"/> 5238 <location filename="../../src/yuzu/main.cpp" line="3712"/>
5218 <location filename="../../src/yuzu/main.cpp" line="3740"/> 5239 <location filename="../../src/yuzu/main.cpp" line="3740"/>
5219 <source>Amiibo</source> 5240 <source>Amiibo</source>
5220 <translation type="unfinished"/> 5241 <translation>Amiibo</translation>
5221 </message> 5242 </message>
5222 <message> 5243 <message>
5223 <location filename="../../src/yuzu/main.cpp" line="3712"/> 5244 <location filename="../../src/yuzu/main.cpp" line="3712"/>
5224 <location filename="../../src/yuzu/main.cpp" line="3740"/> 5245 <location filename="../../src/yuzu/main.cpp" line="3740"/>
5225 <source>The current amiibo has been removed</source> 5246 <source>The current amiibo has been removed</source>
5226 <translation type="unfinished"/> 5247 <translation>De huidige amiibo is verwijderd</translation>
5227 </message> 5248 </message>
5228 <message> 5249 <message>
5229 <location filename="../../src/yuzu/main.cpp" line="3717"/> 5250 <location filename="../../src/yuzu/main.cpp" line="3717"/>
5230 <source>Error</source> 5251 <source>Error</source>
5231 <translation type="unfinished"/> 5252 <translation>Fout</translation>
5232 </message> 5253 </message>
5233 <message> 5254 <message>
5234 <location filename="../../src/yuzu/main.cpp" line="3717"/> 5255 <location filename="../../src/yuzu/main.cpp" line="3717"/>
5235 <location filename="../../src/yuzu/main.cpp" line="3752"/> 5256 <location filename="../../src/yuzu/main.cpp" line="3752"/>
5236 <source>The current game is not looking for amiibos</source> 5257 <source>The current game is not looking for amiibos</source>
5237 <translation type="unfinished"/> 5258 <translation>Het huidige spel is niet op zoek naar amiibo&apos;s</translation>
5238 </message> 5259 </message>
5239 <message> 5260 <message>
5240 <location filename="../../src/yuzu/main.cpp" line="3723"/> 5261 <location filename="../../src/yuzu/main.cpp" line="3723"/>
5241 <source>Amiibo File (%1);; All Files (*.*)</source> 5262 <source>Amiibo File (%1);; All Files (*.*)</source>
5242 <translation>Amiibo Bestand (%1);; Alle Bestanden (*.*)</translation> 5263 <translation>Amiibo-bestand (%1);; Alle Bestanden (*.*)</translation>
5243 </message> 5264 </message>
5244 <message> 5265 <message>
5245 <location filename="../../src/yuzu/main.cpp" line="3724"/> 5266 <location filename="../../src/yuzu/main.cpp" line="3724"/>
@@ -5249,57 +5270,57 @@ Please, only use this feature to install updates and DLC.</source>
5249 <message> 5270 <message>
5250 <location filename="../../src/yuzu/main.cpp" line="3736"/> 5271 <location filename="../../src/yuzu/main.cpp" line="3736"/>
5251 <source>Error loading Amiibo data</source> 5272 <source>Error loading Amiibo data</source>
5252 <translation>Fout tijdens het laden van de Amiibo data</translation> 5273 <translation>Fout tijdens het laden van de Amiibo-gegevens</translation>
5253 </message> 5274 </message>
5254 <message> 5275 <message>
5255 <location filename="../../src/yuzu/main.cpp" line="3746"/> 5276 <location filename="../../src/yuzu/main.cpp" line="3746"/>
5256 <source>The selected file is not a valid amiibo</source> 5277 <source>The selected file is not a valid amiibo</source>
5257 <translation type="unfinished"/> 5278 <translation>Het geselecteerde bestand is geen geldige amiibo</translation>
5258 </message> 5279 </message>
5259 <message> 5280 <message>
5260 <location filename="../../src/yuzu/main.cpp" line="3749"/> 5281 <location filename="../../src/yuzu/main.cpp" line="3749"/>
5261 <source>The selected file is already on use</source> 5282 <source>The selected file is already on use</source>
5262 <translation type="unfinished"/> 5283 <translation>Het geselecteerde bestand is al in gebruik</translation>
5263 </message> 5284 </message>
5264 <message> 5285 <message>
5265 <location filename="../../src/yuzu/main.cpp" line="3755"/> 5286 <location filename="../../src/yuzu/main.cpp" line="3755"/>
5266 <source>An unknown error occurred</source> 5287 <source>An unknown error occurred</source>
5267 <translation type="unfinished"/> 5288 <translation>Er is een onbekende fout opgetreden</translation>
5268 </message> 5289 </message>
5269 <message> 5290 <message>
5270 <location filename="../../src/yuzu/main.cpp" line="3807"/> 5291 <location filename="../../src/yuzu/main.cpp" line="3807"/>
5271 <source>Capture Screenshot</source> 5292 <source>Capture Screenshot</source>
5272 <translation>Screenshot Vastleggen</translation> 5293 <translation>Leg Schermafbeelding Vast</translation>
5273 </message> 5294 </message>
5274 <message> 5295 <message>
5275 <location filename="../../src/yuzu/main.cpp" line="3808"/> 5296 <location filename="../../src/yuzu/main.cpp" line="3808"/>
5276 <source>PNG Image (*.png)</source> 5297 <source>PNG Image (*.png)</source>
5277 <translation>PNG afbeelding (*.png)</translation> 5298 <translation>PNG-afbeelding (*.png)</translation>
5278 </message> 5299 </message>
5279 <message> 5300 <message>
5280 <location filename="../../src/yuzu/main.cpp" line="3891"/> 5301 <location filename="../../src/yuzu/main.cpp" line="3891"/>
5281 <source>TAS state: Running %1/%2</source> 5302 <source>TAS state: Running %1/%2</source>
5282 <translation type="unfinished"/> 5303 <translation>TAS-status: %1/%2 In werking</translation>
5283 </message> 5304 </message>
5284 <message> 5305 <message>
5285 <location filename="../../src/yuzu/main.cpp" line="3895"/> 5306 <location filename="../../src/yuzu/main.cpp" line="3895"/>
5286 <source>TAS state: Recording %1</source> 5307 <source>TAS state: Recording %1</source>
5287 <translation type="unfinished"/> 5308 <translation>TAS-status: %1 Aan het opnemen</translation>
5288 </message> 5309 </message>
5289 <message> 5310 <message>
5290 <location filename="../../src/yuzu/main.cpp" line="3897"/> 5311 <location filename="../../src/yuzu/main.cpp" line="3897"/>
5291 <source>TAS state: Idle %1/%2</source> 5312 <source>TAS state: Idle %1/%2</source>
5292 <translation type="unfinished"/> 5313 <translation>TAS-status: %1/%2 Inactief</translation>
5293 </message> 5314 </message>
5294 <message> 5315 <message>
5295 <location filename="../../src/yuzu/main.cpp" line="3901"/> 5316 <location filename="../../src/yuzu/main.cpp" line="3901"/>
5296 <source>TAS State: Invalid</source> 5317 <source>TAS State: Invalid</source>
5297 <translation type="unfinished"/> 5318 <translation>TAS-status: Ongeldig</translation>
5298 </message> 5319 </message>
5299 <message> 5320 <message>
5300 <location filename="../../src/yuzu/main.cpp" line="3915"/> 5321 <location filename="../../src/yuzu/main.cpp" line="3915"/>
5301 <source>&amp;Stop Running</source> 5322 <source>&amp;Stop Running</source>
5302 <translation type="unfinished"/> 5323 <translation>&amp;Stop Uitvoering</translation>
5303 </message> 5324 </message>
5304 <message> 5325 <message>
5305 <location filename="../../src/yuzu/main.cpp" line="3915"/> 5326 <location filename="../../src/yuzu/main.cpp" line="3915"/>
@@ -5309,23 +5330,23 @@ Please, only use this feature to install updates and DLC.</source>
5309 <message> 5330 <message>
5310 <location filename="../../src/yuzu/main.cpp" line="3916"/> 5331 <location filename="../../src/yuzu/main.cpp" line="3916"/>
5311 <source>Stop R&amp;ecording</source> 5332 <source>Stop R&amp;ecording</source>
5312 <translation type="unfinished"/> 5333 <translation>Stop Opname</translation>
5313 </message> 5334 </message>
5314 <message> 5335 <message>
5315 <location filename="../../src/yuzu/main.cpp" line="3916"/> 5336 <location filename="../../src/yuzu/main.cpp" line="3916"/>
5316 <source>R&amp;ecord</source> 5337 <source>R&amp;ecord</source>
5317 <translation type="unfinished"/> 5338 <translation>Opnemen</translation>
5318 </message> 5339 </message>
5319 <message numerus="yes"> 5340 <message numerus="yes">
5320 <location filename="../../src/yuzu/main.cpp" line="3940"/> 5341 <location filename="../../src/yuzu/main.cpp" line="3940"/>
5321 <source>Building: %n shader(s)</source> 5342 <source>Building: %n shader(s)</source>
5322 <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> 5343 <translation><numerusform>Bouwen: %n shader(s)</numerusform><numerusform>Bouwen: %n shader(s)</numerusform></translation>
5323 </message> 5344 </message>
5324 <message> 5345 <message>
5325 <location filename="../../src/yuzu/main.cpp" line="3949"/> 5346 <location filename="../../src/yuzu/main.cpp" line="3949"/>
5326 <source>Scale: %1x</source> 5347 <source>Scale: %1x</source>
5327 <comment>%1 is the resolution scaling factor</comment> 5348 <comment>%1 is the resolution scaling factor</comment>
5328 <translation type="unfinished"/> 5349 <translation>Schaal: %1x</translation>
5329 </message> 5350 </message>
5330 <message> 5351 <message>
5331 <location filename="../../src/yuzu/main.cpp" line="3952"/> 5352 <location filename="../../src/yuzu/main.cpp" line="3952"/>
@@ -5340,7 +5361,7 @@ Please, only use this feature to install updates and DLC.</source>
5340 <message> 5361 <message>
5341 <location filename="../../src/yuzu/main.cpp" line="3960"/> 5362 <location filename="../../src/yuzu/main.cpp" line="3960"/>
5342 <source>Game: %1 FPS (Unlocked)</source> 5363 <source>Game: %1 FPS (Unlocked)</source>
5343 <translation type="unfinished"/> 5364 <translation>Spel: %1 FPS (Ontgrendeld)</translation>
5344 </message> 5365 </message>
5345 <message> 5366 <message>
5346 <location filename="../../src/yuzu/main.cpp" line="3963"/> 5367 <location filename="../../src/yuzu/main.cpp" line="3963"/>
@@ -5355,110 +5376,110 @@ Please, only use this feature to install updates and DLC.</source>
5355 <message> 5376 <message>
5356 <location filename="../../src/yuzu/main.cpp" line="3976"/> 5377 <location filename="../../src/yuzu/main.cpp" line="3976"/>
5357 <source>GPU NORMAL</source> 5378 <source>GPU NORMAL</source>
5358 <translation type="unfinished"/> 5379 <translation>GPU NORMAAL</translation>
5359 </message> 5380 </message>
5360 <message> 5381 <message>
5361 <location filename="../../src/yuzu/main.cpp" line="3981"/> 5382 <location filename="../../src/yuzu/main.cpp" line="3981"/>
5362 <source>GPU HIGH</source> 5383 <source>GPU HIGH</source>
5363 <translation type="unfinished"/> 5384 <translation>GPU HOOG</translation>
5364 </message> 5385 </message>
5365 <message> 5386 <message>
5366 <location filename="../../src/yuzu/main.cpp" line="3986"/> 5387 <location filename="../../src/yuzu/main.cpp" line="3986"/>
5367 <source>GPU EXTREME</source> 5388 <source>GPU EXTREME</source>
5368 <translation type="unfinished"/> 5389 <translation>GPU EXTREEM</translation>
5369 </message> 5390 </message>
5370 <message> 5391 <message>
5371 <location filename="../../src/yuzu/main.cpp" line="3991"/> 5392 <location filename="../../src/yuzu/main.cpp" line="3991"/>
5372 <source>GPU ERROR</source> 5393 <source>GPU ERROR</source>
5373 <translation type="unfinished"/> 5394 <translation>GPU FOUT</translation>
5374 </message> 5395 </message>
5375 <message> 5396 <message>
5376 <location filename="../../src/yuzu/main.cpp" line="4001"/> 5397 <location filename="../../src/yuzu/main.cpp" line="4001"/>
5377 <source>DOCKED</source> 5398 <source>DOCKED</source>
5378 <translation type="unfinished"/> 5399 <translation>DOCKED</translation>
5379 </message> 5400 </message>
5380 <message> 5401 <message>
5381 <location filename="../../src/yuzu/main.cpp" line="4001"/> 5402 <location filename="../../src/yuzu/main.cpp" line="4001"/>
5382 <source>HANDHELD</source> 5403 <source>HANDHELD</source>
5383 <translation type="unfinished"/> 5404 <translation>HANDHELD</translation>
5384 </message> 5405 </message>
5385 <message> 5406 <message>
5386 <location filename="../../src/yuzu/main.cpp" line="4008"/> 5407 <location filename="../../src/yuzu/main.cpp" line="4008"/>
5387 <source>OPENGL</source> 5408 <source>OPENGL</source>
5388 <translation type="unfinished"/> 5409 <translation>OPENGL</translation>
5389 </message> 5410 </message>
5390 <message> 5411 <message>
5391 <location filename="../../src/yuzu/main.cpp" line="4011"/> 5412 <location filename="../../src/yuzu/main.cpp" line="4011"/>
5392 <source>VULKAN</source> 5413 <source>VULKAN</source>
5393 <translation type="unfinished"/> 5414 <translation>VULKAN</translation>
5394 </message> 5415 </message>
5395 <message> 5416 <message>
5396 <location filename="../../src/yuzu/main.cpp" line="4014"/> 5417 <location filename="../../src/yuzu/main.cpp" line="4014"/>
5397 <source>NULL</source> 5418 <source>NULL</source>
5398 <translation type="unfinished"/> 5419 <translation>NULL</translation>
5399 </message> 5420 </message>
5400 <message> 5421 <message>
5401 <location filename="../../src/yuzu/main.cpp" line="4023"/> 5422 <location filename="../../src/yuzu/main.cpp" line="4023"/>
5402 <source>NEAREST</source> 5423 <source>NEAREST</source>
5403 <translation type="unfinished"/> 5424 <translation>NEAREST</translation>
5404 </message> 5425 </message>
5405 <message> 5426 <message>
5406 <location filename="../../src/yuzu/main.cpp" line="4026"/> 5427 <location filename="../../src/yuzu/main.cpp" line="4026"/>
5407 <location filename="../../src/yuzu/main.cpp" line="4041"/> 5428 <location filename="../../src/yuzu/main.cpp" line="4041"/>
5408 <source>BILINEAR</source> 5429 <source>BILINEAR</source>
5409 <translation type="unfinished"/> 5430 <translation>BILINEAR</translation>
5410 </message> 5431 </message>
5411 <message> 5432 <message>
5412 <location filename="../../src/yuzu/main.cpp" line="4029"/> 5433 <location filename="../../src/yuzu/main.cpp" line="4029"/>
5413 <source>BICUBIC</source> 5434 <source>BICUBIC</source>
5414 <translation type="unfinished"/> 5435 <translation>BICUBIC</translation>
5415 </message> 5436 </message>
5416 <message> 5437 <message>
5417 <location filename="../../src/yuzu/main.cpp" line="4032"/> 5438 <location filename="../../src/yuzu/main.cpp" line="4032"/>
5418 <source>GAUSSIAN</source> 5439 <source>GAUSSIAN</source>
5419 <translation type="unfinished"/> 5440 <translation>GAUSSIAN</translation>
5420 </message> 5441 </message>
5421 <message> 5442 <message>
5422 <location filename="../../src/yuzu/main.cpp" line="4035"/> 5443 <location filename="../../src/yuzu/main.cpp" line="4035"/>
5423 <source>SCALEFORCE</source> 5444 <source>SCALEFORCE</source>
5424 <translation type="unfinished"/> 5445 <translation>SCALEFORCE</translation>
5425 </message> 5446 </message>
5426 <message> 5447 <message>
5427 <location filename="../../src/yuzu/main.cpp" line="4038"/> 5448 <location filename="../../src/yuzu/main.cpp" line="4038"/>
5428 <source>FSR</source> 5449 <source>FSR</source>
5429 <translation type="unfinished"/> 5450 <translation>FSR</translation>
5430 </message> 5451 </message>
5431 <message> 5452 <message>
5432 <location filename="../../src/yuzu/main.cpp" line="4050"/> 5453 <location filename="../../src/yuzu/main.cpp" line="4050"/>
5433 <location filename="../../src/yuzu/main.cpp" line="4059"/> 5454 <location filename="../../src/yuzu/main.cpp" line="4059"/>
5434 <source>NO AA</source> 5455 <source>NO AA</source>
5435 <translation type="unfinished"/> 5456 <translation>GEEN AA</translation>
5436 </message> 5457 </message>
5437 <message> 5458 <message>
5438 <location filename="../../src/yuzu/main.cpp" line="4053"/> 5459 <location filename="../../src/yuzu/main.cpp" line="4053"/>
5439 <source>FXAA</source> 5460 <source>FXAA</source>
5440 <translation type="unfinished"/> 5461 <translation>FXAA</translation>
5441 </message> 5462 </message>
5442 <message> 5463 <message>
5443 <location filename="../../src/yuzu/main.cpp" line="4056"/> 5464 <location filename="../../src/yuzu/main.cpp" line="4056"/>
5444 <source>SMAA</source> 5465 <source>SMAA</source>
5445 <translation type="unfinished"/> 5466 <translation>SMAA</translation>
5446 </message> 5467 </message>
5447 <message> 5468 <message>
5448 <location filename="../../src/yuzu/main.cpp" line="4069"/> 5469 <location filename="../../src/yuzu/main.cpp" line="4069"/>
5449 <source>VOLUME: MUTE</source> 5470 <source>VOLUME: MUTE</source>
5450 <translation type="unfinished"/> 5471 <translation>VOLUME: GEDEMPT</translation>
5451 </message> 5472 </message>
5452 <message> 5473 <message>
5453 <location filename="../../src/yuzu/main.cpp" line="4072"/> 5474 <location filename="../../src/yuzu/main.cpp" line="4072"/>
5454 <source>VOLUME: %1%</source> 5475 <source>VOLUME: %1%</source>
5455 <comment>Volume percentage (e.g. 50%)</comment> 5476 <comment>Volume percentage (e.g. 50%)</comment>
5456 <translation type="unfinished"/> 5477 <translation>VOLUME: %1%</translation>
5457 </message> 5478 </message>
5458 <message> 5479 <message>
5459 <location filename="../../src/yuzu/main.cpp" line="4153"/> 5480 <location filename="../../src/yuzu/main.cpp" line="4153"/>
5460 <source>Confirm Key Rederivation</source> 5481 <source>Confirm Key Rederivation</source>
5461 <translation>Bevestig Sleutel Herafleiding</translation> 5482 <translation>Bevestig Sleutelherhaling</translation>
5462 </message> 5483 </message>
5463 <message> 5484 <message>
5464 <location filename="../../src/yuzu/main.cpp" line="4154"/> 5485 <location filename="../../src/yuzu/main.cpp" line="4154"/>
@@ -5469,61 +5490,62 @@ Please make sure this is what you want
5469and optionally make backups. 5490and optionally make backups.
5470 5491
5471This will delete your autogenerated key files and re-run the key derivation module.</source> 5492This will delete your autogenerated key files and re-run the key derivation module.</source>
5472 <translation>Je bent op het punt al je sleutels geforceerd opnieuw te verkrijgen. 5493 <translation>Je staat op het punt om al je sleutels te forceren.
5473Als je niet weet wat dit doet of wat je aan het doen bent, 5494Als je niet weet wat dit betekent of wat je doet,
5474dit is potentieel een vernietigende actie. 5495is dit een potentieel destructieve actie.
5475Zorg ervoor dat je zeker weet dat dit is wat je wilt doen 5496Zorg ervoor dat dit is wat je wilt
5476en optioneel maak backups. 5497en maak eventueel back-ups.
5477 5498
5478Dit zal je automatisch gegenereerde sleutel bestanden verwijderen en de sleutel verkrijger module opnieuw starten</translation> 5499Dit zal je automatisch gegenereerde sleutelbestanden verwijderen en de sleutelafleidingsmodule opnieuw uitvoeren.</translation>
5479 </message> 5500 </message>
5480 <message> 5501 <message>
5481 <location filename="../../src/yuzu/main.cpp" line="4186"/> 5502 <location filename="../../src/yuzu/main.cpp" line="4186"/>
5482 <source>Missing fuses</source> 5503 <source>Missing fuses</source>
5483 <translation type="unfinished"/> 5504 <translation>Missing fuses</translation>
5484 </message> 5505 </message>
5485 <message> 5506 <message>
5486 <location filename="../../src/yuzu/main.cpp" line="4189"/> 5507 <location filename="../../src/yuzu/main.cpp" line="4189"/>
5487 <source> - Missing BOOT0</source> 5508 <source> - Missing BOOT0</source>
5488 <translation type="unfinished"/> 5509 <translation> - BOOT0 Ontbreekt</translation>
5489 </message> 5510 </message>
5490 <message> 5511 <message>
5491 <location filename="../../src/yuzu/main.cpp" line="4192"/> 5512 <location filename="../../src/yuzu/main.cpp" line="4192"/>
5492 <source> - Missing BCPKG2-1-Normal-Main</source> 5513 <source> - Missing BCPKG2-1-Normal-Main</source>
5493 <translation type="unfinished"/> 5514 <translation> - BCPKG2-1-Normal-Main Ontbreekt</translation>
5494 </message> 5515 </message>
5495 <message> 5516 <message>
5496 <location filename="../../src/yuzu/main.cpp" line="4195"/> 5517 <location filename="../../src/yuzu/main.cpp" line="4195"/>
5497 <source> - Missing PRODINFO</source> 5518 <source> - Missing PRODINFO</source>
5498 <translation type="unfinished"/> 5519 <translation> - PRODINFO Ontbreekt</translation>
5499 </message> 5520 </message>
5500 <message> 5521 <message>
5501 <location filename="../../src/yuzu/main.cpp" line="4199"/> 5522 <location filename="../../src/yuzu/main.cpp" line="4199"/>
5502 <source>Derivation Components Missing</source> 5523 <source>Derivation Components Missing</source>
5503 <translation type="unfinished"/> 5524 <translation>Afleidingscomponenten ontbreken</translation>
5504 </message> 5525 </message>
5505 <message> 5526 <message>
5506 <location filename="../../src/yuzu/main.cpp" line="4200"/> 5527 <location filename="../../src/yuzu/main.cpp" line="4200"/>
5507 <source>Encryption keys are missing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys, firmware and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source> 5528 <source>Encryption keys are missing. &lt;br&gt;Please follow &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;the yuzu quickstart guide&lt;/a&gt; to get all your keys, firmware and games.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</source>
5508 <translation type="unfinished"/> 5529 <translation>Encryptiesleutels ontbreken. &lt;br&gt;Volg &lt;a href=&apos;https://yuzu-emu.org/help/quickstart/&apos;&gt;de yuzu-snelstartgids&lt;/a&gt; om al je sleutels, firmware en spellen te krijgen.&lt;br&gt;&lt;br&gt;&lt;small&gt;(%1)&lt;/small&gt;</translation>
5509 </message> 5530 </message>
5510 <message> 5531 <message>
5511 <location filename="../../src/yuzu/main.cpp" line="4209"/> 5532 <location filename="../../src/yuzu/main.cpp" line="4209"/>
5512 <source>Deriving keys... 5533 <source>Deriving keys...
5513This may take up to a minute depending 5534This may take up to a minute depending
5514on your system&apos;s performance.</source> 5535on your system&apos;s performance.</source>
5515 <translation>Dit zal misschien een paar minuten duren gebaseerd 5536 <translation>Sleutels afleiden...
5516op je systeem&apos;s performatie.</translation> 5537Dit kan tot een minuut duren,
5538afhankelijk van de prestaties van je systeem.</translation>
5517 </message> 5539 </message>
5518 <message> 5540 <message>
5519 <location filename="../../src/yuzu/main.cpp" line="4211"/> 5541 <location filename="../../src/yuzu/main.cpp" line="4211"/>
5520 <source>Deriving Keys</source> 5542 <source>Deriving Keys</source>
5521 <translation>Sleutels afleiden</translation> 5543 <translation>Sleutels Afleiden</translation>
5522 </message> 5544 </message>
5523 <message> 5545 <message>
5524 <location filename="../../src/yuzu/main.cpp" line="4256"/> 5546 <location filename="../../src/yuzu/main.cpp" line="4256"/>
5525 <source>Select RomFS Dump Target</source> 5547 <source>Select RomFS Dump Target</source>
5526 <translation>Selecteer RomFS Dump Doel</translation> 5548 <translation>Selecteer RomFS-dumpdoel</translation>
5527 </message> 5549 </message>
5528 <message> 5550 <message>
5529 <location filename="../../src/yuzu/main.cpp" line="4257"/> 5551 <location filename="../../src/yuzu/main.cpp" line="4257"/>
@@ -5545,7 +5567,7 @@ op je systeem&apos;s performatie.</translation>
5545 <message> 5567 <message>
5546 <location filename="../../src/yuzu/main.cpp" line="4369"/> 5568 <location filename="../../src/yuzu/main.cpp" line="4369"/>
5547 <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source> 5569 <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source>
5548 <translation>Weet je zeker dat je de emulatie wilt stoppen? Alle onopgeslagen voortgang will verloren gaan.</translation> 5570 <translation>Weet je zeker dat je de emulatie wilt stoppen? Alle niet opgeslagen voortgang zal verloren gaan.</translation>
5549 </message> 5571 </message>
5550 <message> 5572 <message>
5551 <location filename="../../src/yuzu/main.cpp" line="4378"/> 5573 <location filename="../../src/yuzu/main.cpp" line="4378"/>
@@ -5554,7 +5576,7 @@ op je systeem&apos;s performatie.</translation>
5554Would you like to bypass this and exit anyway?</source> 5576Would you like to bypass this and exit anyway?</source>
5555 <translation>De momenteel actieve toepassing heeft yuzu gevraagd om niet af te sluiten. 5577 <translation>De momenteel actieve toepassing heeft yuzu gevraagd om niet af te sluiten.
5556 5578
5557Wilt u dit omzeilen en toch afsluiten?</translation> 5579Wil je toch afsluiten?</translation>
5558 </message> 5580 </message>
5559</context> 5581</context>
5560<context> 5582<context>
@@ -5563,43 +5585,43 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5563 <location filename="../../src/yuzu/bootmanager.cpp" line="974"/> 5585 <location filename="../../src/yuzu/bootmanager.cpp" line="974"/>
5564 <location filename="../../src/yuzu/bootmanager.cpp" line="991"/> 5586 <location filename="../../src/yuzu/bootmanager.cpp" line="991"/>
5565 <source>OpenGL not available!</source> 5587 <source>OpenGL not available!</source>
5566 <translation type="unfinished"/> 5588 <translation>OpenGL niet beschikbaar!</translation>
5567 </message> 5589 </message>
5568 <message> 5590 <message>
5569 <location filename="../../src/yuzu/bootmanager.cpp" line="975"/> 5591 <location filename="../../src/yuzu/bootmanager.cpp" line="975"/>
5570 <source>OpenGL shared contexts are not supported.</source> 5592 <source>OpenGL shared contexts are not supported.</source>
5571 <translation type="unfinished"/> 5593 <translation>OpenGL gedeelde contexten worden niet ondersteund.</translation>
5572 </message> 5594 </message>
5573 <message> 5595 <message>
5574 <location filename="../../src/yuzu/bootmanager.cpp" line="992"/> 5596 <location filename="../../src/yuzu/bootmanager.cpp" line="992"/>
5575 <source>yuzu has not been compiled with OpenGL support.</source> 5597 <source>yuzu has not been compiled with OpenGL support.</source>
5576 <translation type="unfinished"/> 5598 <translation>yuzu is niet gecompileerd met OpenGL-ondersteuning.</translation>
5577 </message> 5599 </message>
5578 <message> 5600 <message>
5579 <location filename="../../src/yuzu/bootmanager.cpp" line="1016"/> 5601 <location filename="../../src/yuzu/bootmanager.cpp" line="1016"/>
5580 <location filename="../../src/yuzu/bootmanager.cpp" line="1036"/> 5602 <location filename="../../src/yuzu/bootmanager.cpp" line="1036"/>
5581 <source>Error while initializing OpenGL!</source> 5603 <source>Error while initializing OpenGL!</source>
5582 <translation type="unfinished"/> 5604 <translation>Fout tijdens het initialiseren van OpenGL!</translation>
5583 </message> 5605 </message>
5584 <message> 5606 <message>
5585 <location filename="../../src/yuzu/bootmanager.cpp" line="1017"/> 5607 <location filename="../../src/yuzu/bootmanager.cpp" line="1017"/>
5586 <source>Your GPU may not support OpenGL, or you do not have the latest graphics driver.</source> 5608 <source>Your GPU may not support OpenGL, or you do not have the latest graphics driver.</source>
5587 <translation type="unfinished"/> 5609 <translation>Je GPU ondersteunt mogelijk geen OpenGL, of je hebt niet de laatste grafische stuurprogramma.</translation>
5588 </message> 5610 </message>
5589 <message> 5611 <message>
5590 <location filename="../../src/yuzu/bootmanager.cpp" line="1026"/> 5612 <location filename="../../src/yuzu/bootmanager.cpp" line="1026"/>
5591 <source>Error while initializing OpenGL 4.6!</source> 5613 <source>Error while initializing OpenGL 4.6!</source>
5592 <translation type="unfinished"/> 5614 <translation>Fout tijdens het initialiseren van OpenGL 4.6!</translation>
5593 </message> 5615 </message>
5594 <message> 5616 <message>
5595 <location filename="../../src/yuzu/bootmanager.cpp" line="1027"/> 5617 <location filename="../../src/yuzu/bootmanager.cpp" line="1027"/>
5596 <source>Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.&lt;br&gt;&lt;br&gt;GL Renderer:&lt;br&gt;%1</source> 5618 <source>Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.&lt;br&gt;&lt;br&gt;GL Renderer:&lt;br&gt;%1</source>
5597 <translation type="unfinished"/> 5619 <translation>Je GPU ondersteunt mogelijk OpenGL 4.6 niet, of je hebt niet het laatste grafische stuurprogramma.&lt;br&gt;&lt;br&gt;GL Renderer:&lt;br&gt;%1</translation>
5598 </message> 5620 </message>
5599 <message> 5621 <message>
5600 <location filename="../../src/yuzu/bootmanager.cpp" line="1037"/> 5622 <location filename="../../src/yuzu/bootmanager.cpp" line="1037"/>
5601 <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;GL Renderer:&lt;br&gt;%1&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;%2</source> 5623 <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.&lt;br&gt;&lt;br&gt;GL Renderer:&lt;br&gt;%1&lt;br&gt;&lt;br&gt;Unsupported extensions:&lt;br&gt;%2</source>
5602 <translation type="unfinished"/> 5624 <translation>Je GPU ondersteunt mogelijk een of meer vereiste OpenGL-extensies niet. Zorg ervoor dat je het laatste grafische stuurprogramma hebt.&lt;br&gt;&lt;br&gt;GL Renderer:&lt;br&gt;%1&lt;br&gt;&lt;br&gt;Ondersteunde extensies:&lt;br&gt;%2</translation>
5603 </message> 5625 </message>
5604</context> 5626</context>
5605<context> 5627<context>
@@ -5607,32 +5629,32 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5607 <message> 5629 <message>
5608 <location filename="../../src/yuzu/game_list.cpp" line="532"/> 5630 <location filename="../../src/yuzu/game_list.cpp" line="532"/>
5609 <source>Favorite</source> 5631 <source>Favorite</source>
5610 <translation type="unfinished"/> 5632 <translation>Favoriet</translation>
5611 </message> 5633 </message>
5612 <message> 5634 <message>
5613 <location filename="../../src/yuzu/game_list.cpp" line="534"/> 5635 <location filename="../../src/yuzu/game_list.cpp" line="534"/>
5614 <source>Start Game</source> 5636 <source>Start Game</source>
5615 <translation type="unfinished"/> 5637 <translation>Start Spel</translation>
5616 </message> 5638 </message>
5617 <message> 5639 <message>
5618 <location filename="../../src/yuzu/game_list.cpp" line="536"/> 5640 <location filename="../../src/yuzu/game_list.cpp" line="536"/>
5619 <source>Start Game without Custom Configuration</source> 5641 <source>Start Game without Custom Configuration</source>
5620 <translation type="unfinished"/> 5642 <translation>Start Spel zonder Aangepaste Configuratie</translation>
5621 </message> 5643 </message>
5622 <message> 5644 <message>
5623 <location filename="../../src/yuzu/game_list.cpp" line="538"/> 5645 <location filename="../../src/yuzu/game_list.cpp" line="538"/>
5624 <source>Open Save Data Location</source> 5646 <source>Open Save Data Location</source>
5625 <translation>Open Locatie Van Save Gegevens </translation> 5647 <translation>Open Locatie van Save-data</translation>
5626 </message> 5648 </message>
5627 <message> 5649 <message>
5628 <location filename="../../src/yuzu/game_list.cpp" line="539"/> 5650 <location filename="../../src/yuzu/game_list.cpp" line="539"/>
5629 <source>Open Mod Data Location</source> 5651 <source>Open Mod Data Location</source>
5630 <translation>Open Mod Data Locatie</translation> 5652 <translation>Open Locatie van Mod-data</translation>
5631 </message> 5653 </message>
5632 <message> 5654 <message>
5633 <location filename="../../src/yuzu/game_list.cpp" line="541"/> 5655 <location filename="../../src/yuzu/game_list.cpp" line="541"/>
5634 <source>Open Transferable Pipeline Cache</source> 5656 <source>Open Transferable Pipeline Cache</source>
5635 <translation type="unfinished"/> 5657 <translation>Open Overdraagbare Pijplijn-cache</translation>
5636 </message> 5658 </message>
5637 <message> 5659 <message>
5638 <location filename="../../src/yuzu/game_list.cpp" line="543"/> 5660 <location filename="../../src/yuzu/game_list.cpp" line="543"/>
@@ -5642,37 +5664,37 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5642 <message> 5664 <message>
5643 <location filename="../../src/yuzu/game_list.cpp" line="544"/> 5665 <location filename="../../src/yuzu/game_list.cpp" line="544"/>
5644 <source>Remove Installed Update</source> 5666 <source>Remove Installed Update</source>
5645 <translation type="unfinished"/> 5667 <translation>Verwijder Geïnstalleerde Update</translation>
5646 </message> 5668 </message>
5647 <message> 5669 <message>
5648 <location filename="../../src/yuzu/game_list.cpp" line="545"/> 5670 <location filename="../../src/yuzu/game_list.cpp" line="545"/>
5649 <source>Remove All Installed DLC</source> 5671 <source>Remove All Installed DLC</source>
5650 <translation type="unfinished"/> 5672 <translation>Verwijder Alle Geïnstalleerde DLC&apos;s</translation>
5651 </message> 5673 </message>
5652 <message> 5674 <message>
5653 <location filename="../../src/yuzu/game_list.cpp" line="546"/> 5675 <location filename="../../src/yuzu/game_list.cpp" line="546"/>
5654 <source>Remove Custom Configuration</source> 5676 <source>Remove Custom Configuration</source>
5655 <translation type="unfinished"/> 5677 <translation>Verwijder Aangepaste Configuraties</translation>
5656 </message> 5678 </message>
5657 <message> 5679 <message>
5658 <location filename="../../src/yuzu/game_list.cpp" line="547"/> 5680 <location filename="../../src/yuzu/game_list.cpp" line="547"/>
5659 <source>Remove OpenGL Pipeline Cache</source> 5681 <source>Remove OpenGL Pipeline Cache</source>
5660 <translation type="unfinished"/> 5682 <translation>Verwijder OpenGL-pijplijn-cache</translation>
5661 </message> 5683 </message>
5662 <message> 5684 <message>
5663 <location filename="../../src/yuzu/game_list.cpp" line="548"/> 5685 <location filename="../../src/yuzu/game_list.cpp" line="548"/>
5664 <source>Remove Vulkan Pipeline Cache</source> 5686 <source>Remove Vulkan Pipeline Cache</source>
5665 <translation type="unfinished"/> 5687 <translation>Verwijder Vulkan-pijplijn-cache</translation>
5666 </message> 5688 </message>
5667 <message> 5689 <message>
5668 <location filename="../../src/yuzu/game_list.cpp" line="550"/> 5690 <location filename="../../src/yuzu/game_list.cpp" line="550"/>
5669 <source>Remove All Pipeline Caches</source> 5691 <source>Remove All Pipeline Caches</source>
5670 <translation type="unfinished"/> 5692 <translation>Verwijder Alle Pijplijn-caches</translation>
5671 </message> 5693 </message>
5672 <message> 5694 <message>
5673 <location filename="../../src/yuzu/game_list.cpp" line="551"/> 5695 <location filename="../../src/yuzu/game_list.cpp" line="551"/>
5674 <source>Remove All Installed Contents</source> 5696 <source>Remove All Installed Contents</source>
5675 <translation type="unfinished"/> 5697 <translation>Verwijder Alle Geïnstalleerde Inhoud</translation>
5676 </message> 5698 </message>
5677 <message> 5699 <message>
5678 <location filename="../../src/yuzu/game_list.cpp" line="552"/> 5700 <location filename="../../src/yuzu/game_list.cpp" line="552"/>
@@ -5683,32 +5705,32 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5683 <message> 5705 <message>
5684 <location filename="../../src/yuzu/game_list.cpp" line="554"/> 5706 <location filename="../../src/yuzu/game_list.cpp" line="554"/>
5685 <source>Dump RomFS to SDMC</source> 5707 <source>Dump RomFS to SDMC</source>
5686 <translation type="unfinished"/> 5708 <translation>Dump RomFS naar SDMC</translation>
5687 </message> 5709 </message>
5688 <message> 5710 <message>
5689 <location filename="../../src/yuzu/game_list.cpp" line="555"/> 5711 <location filename="../../src/yuzu/game_list.cpp" line="555"/>
5690 <source>Copy Title ID to Clipboard</source> 5712 <source>Copy Title ID to Clipboard</source>
5691 <translation>Kopieer Titel ID naar Klembord</translation> 5713 <translation>Kopiëer Titel-ID naar Klembord</translation>
5692 </message> 5714 </message>
5693 <message> 5715 <message>
5694 <location filename="../../src/yuzu/game_list.cpp" line="556"/> 5716 <location filename="../../src/yuzu/game_list.cpp" line="556"/>
5695 <source>Navigate to GameDB entry</source> 5717 <source>Navigate to GameDB entry</source>
5696 <translation>Navigeer naar GameDB inzending</translation> 5718 <translation>Navigeer naar GameDB-invoer</translation>
5697 </message> 5719 </message>
5698 <message> 5720 <message>
5699 <location filename="../../src/yuzu/game_list.cpp" line="558"/> 5721 <location filename="../../src/yuzu/game_list.cpp" line="558"/>
5700 <source>Create Shortcut</source> 5722 <source>Create Shortcut</source>
5701 <translation type="unfinished"/> 5723 <translation>Maak Snelkoppeling</translation>
5702 </message> 5724 </message>
5703 <message> 5725 <message>
5704 <location filename="../../src/yuzu/game_list.cpp" line="559"/> 5726 <location filename="../../src/yuzu/game_list.cpp" line="559"/>
5705 <source>Add to Desktop</source> 5727 <source>Add to Desktop</source>
5706 <translation type="unfinished"/> 5728 <translation>Toevoegen aan Bureaublad</translation>
5707 </message> 5729 </message>
5708 <message> 5730 <message>
5709 <location filename="../../src/yuzu/game_list.cpp" line="561"/> 5731 <location filename="../../src/yuzu/game_list.cpp" line="561"/>
5710 <source>Add to Applications Menu</source> 5732 <source>Add to Applications Menu</source>
5711 <translation type="unfinished"/> 5733 <translation>Toevoegen aan menu Toepassingen</translation>
5712 </message> 5734 </message>
5713 <message> 5735 <message>
5714 <location filename="../../src/yuzu/game_list.cpp" line="564"/> 5736 <location filename="../../src/yuzu/game_list.cpp" line="564"/>
@@ -5718,27 +5740,27 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5718 <message> 5740 <message>
5719 <location filename="../../src/yuzu/game_list.cpp" line="644"/> 5741 <location filename="../../src/yuzu/game_list.cpp" line="644"/>
5720 <source>Scan Subfolders</source> 5742 <source>Scan Subfolders</source>
5721 <translation>Scan Subfolders</translation> 5743 <translation>Scan Submappen</translation>
5722 </message> 5744 </message>
5723 <message> 5745 <message>
5724 <location filename="../../src/yuzu/game_list.cpp" line="645"/> 5746 <location filename="../../src/yuzu/game_list.cpp" line="645"/>
5725 <source>Remove Game Directory</source> 5747 <source>Remove Game Directory</source>
5726 <translation>Verwijder Game Directory</translation> 5748 <translation>Verwijder Spelmap</translation>
5727 </message> 5749 </message>
5728 <message> 5750 <message>
5729 <location filename="../../src/yuzu/game_list.cpp" line="664"/> 5751 <location filename="../../src/yuzu/game_list.cpp" line="664"/>
5730 <source>â–² Move Up</source> 5752 <source>â–² Move Up</source>
5731 <translation type="unfinished"/> 5753 <translation>â–² Omhoog</translation>
5732 </message> 5754 </message>
5733 <message> 5755 <message>
5734 <location filename="../../src/yuzu/game_list.cpp" line="665"/> 5756 <location filename="../../src/yuzu/game_list.cpp" line="665"/>
5735 <source>â–¼ Move Down</source> 5757 <source>â–¼ Move Down</source>
5736 <translation type="unfinished"/> 5758 <translation>â–¼ Omlaag</translation>
5737 </message> 5759 </message>
5738 <message> 5760 <message>
5739 <location filename="../../src/yuzu/game_list.cpp" line="666"/> 5761 <location filename="../../src/yuzu/game_list.cpp" line="666"/>
5740 <source>Open Directory Location</source> 5762 <source>Open Directory Location</source>
5741 <translation>Open Directory Locatie</translation> 5763 <translation>Open Maplocatie</translation>
5742 </message> 5764 </message>
5743 <message> 5765 <message>
5744 <location filename="../../src/yuzu/game_list.cpp" line="711"/> 5766 <location filename="../../src/yuzu/game_list.cpp" line="711"/>
@@ -5758,12 +5780,12 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5758 <message> 5780 <message>
5759 <location filename="../../src/yuzu/game_list.cpp" line="777"/> 5781 <location filename="../../src/yuzu/game_list.cpp" line="777"/>
5760 <source>Add-ons</source> 5782 <source>Add-ons</source>
5761 <translation>Toevoegingen</translation> 5783 <translation>Add-ons</translation>
5762 </message> 5784 </message>
5763 <message> 5785 <message>
5764 <location filename="../../src/yuzu/game_list.cpp" line="778"/> 5786 <location filename="../../src/yuzu/game_list.cpp" line="778"/>
5765 <source>File type</source> 5787 <source>File type</source>
5766 <translation>Bestands type</translation> 5788 <translation>Bestandssoort</translation>
5767 </message> 5789 </message>
5768 <message> 5790 <message>
5769 <location filename="../../src/yuzu/game_list.cpp" line="779"/> 5791 <location filename="../../src/yuzu/game_list.cpp" line="779"/>
@@ -5776,12 +5798,12 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5776 <message> 5798 <message>
5777 <location filename="../../src/yuzu/game_list_p.h" line="149"/> 5799 <location filename="../../src/yuzu/game_list_p.h" line="149"/>
5778 <source>Ingame</source> 5800 <source>Ingame</source>
5779 <translation type="unfinished"/> 5801 <translation>In het spel</translation>
5780 </message> 5802 </message>
5781 <message> 5803 <message>
5782 <location filename="../../src/yuzu/game_list_p.h" line="149"/> 5804 <location filename="../../src/yuzu/game_list_p.h" line="149"/>
5783 <source>Game starts, but crashes or major glitches prevent it from being completed.</source> 5805 <source>Game starts, but crashes or major glitches prevent it from being completed.</source>
5784 <translation type="unfinished"/> 5806 <translation>Het spel start, maar crashes of grote glitches voorkomen dat het wordt voltooid.</translation>
5785 </message> 5807 </message>
5786 <message> 5808 <message>
5787 <location filename="../../src/yuzu/game_list_p.h" line="151"/> 5809 <location filename="../../src/yuzu/game_list_p.h" line="151"/>
@@ -5791,17 +5813,17 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5791 <message> 5813 <message>
5792 <location filename="../../src/yuzu/game_list_p.h" line="151"/> 5814 <location filename="../../src/yuzu/game_list_p.h" line="151"/>
5793 <source>Game can be played without issues.</source> 5815 <source>Game can be played without issues.</source>
5794 <translation type="unfinished"/> 5816 <translation>Het spel kan zonder problemen gespeeld worden.</translation>
5795 </message> 5817 </message>
5796 <message> 5818 <message>
5797 <location filename="../../src/yuzu/game_list_p.h" line="152"/> 5819 <location filename="../../src/yuzu/game_list_p.h" line="152"/>
5798 <source>Playable</source> 5820 <source>Playable</source>
5799 <translation type="unfinished"/> 5821 <translation>Speelbaar</translation>
5800 </message> 5822 </message>
5801 <message> 5823 <message>
5802 <location filename="../../src/yuzu/game_list_p.h" line="152"/> 5824 <location filename="../../src/yuzu/game_list_p.h" line="152"/>
5803 <source>Game functions with minor graphical or audio glitches and is playable from start to finish.</source> 5825 <source>Game functions with minor graphical or audio glitches and is playable from start to finish.</source>
5804 <translation type="unfinished"/> 5826 <translation>Het spel werkt met kleine grafische of audiofouten en is speelbaar van begin tot eind.</translation>
5805 </message> 5827 </message>
5806 <message> 5828 <message>
5807 <location filename="../../src/yuzu/game_list_p.h" line="155"/> 5829 <location filename="../../src/yuzu/game_list_p.h" line="155"/>
@@ -5811,17 +5833,17 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5811 <message> 5833 <message>
5812 <location filename="../../src/yuzu/game_list_p.h" line="155"/> 5834 <location filename="../../src/yuzu/game_list_p.h" line="155"/>
5813 <source>Game loads, but is unable to progress past the Start Screen.</source> 5835 <source>Game loads, but is unable to progress past the Start Screen.</source>
5814 <translation type="unfinished"/> 5836 <translation>Het spel wordt geladen, maar komt niet verder dan het startscherm.</translation>
5815 </message> 5837 </message>
5816 <message> 5838 <message>
5817 <location filename="../../src/yuzu/game_list_p.h" line="156"/> 5839 <location filename="../../src/yuzu/game_list_p.h" line="156"/>
5818 <source>Won&apos;t Boot</source> 5840 <source>Won&apos;t Boot</source>
5819 <translation>Start Niet</translation> 5841 <translation>Start niet op</translation>
5820 </message> 5842 </message>
5821 <message> 5843 <message>
5822 <location filename="../../src/yuzu/game_list_p.h" line="156"/> 5844 <location filename="../../src/yuzu/game_list_p.h" line="156"/>
5823 <source>The game crashes when attempting to startup.</source> 5845 <source>The game crashes when attempting to startup.</source>
5824 <translation>De Game crasht wanneer hij probeert op te starten.</translation> 5846 <translation>Het spel loopt vast bij het opstarten.</translation>
5825 </message> 5847 </message>
5826 <message> 5848 <message>
5827 <location filename="../../src/yuzu/game_list_p.h" line="157"/> 5849 <location filename="../../src/yuzu/game_list_p.h" line="157"/>
@@ -5831,7 +5853,7 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5831 <message> 5853 <message>
5832 <location filename="../../src/yuzu/game_list_p.h" line="157"/> 5854 <location filename="../../src/yuzu/game_list_p.h" line="157"/>
5833 <source>The game has not yet been tested.</source> 5855 <source>The game has not yet been tested.</source>
5834 <translation>Deze Game is nog niet getest.</translation> 5856 <translation>Het spel is nog niet getest.</translation>
5835 </message> 5857 </message>
5836</context> 5858</context>
5837<context> 5859<context>
@@ -5839,7 +5861,7 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5839 <message> 5861 <message>
5840 <location filename="../../src/yuzu/game_list.cpp" line="952"/> 5862 <location filename="../../src/yuzu/game_list.cpp" line="952"/>
5841 <source>Double-click to add a new folder to the game list</source> 5863 <source>Double-click to add a new folder to the game list</source>
5842 <translation>Dubbel-klik om een ​​nieuwe map toe te voegen aan de lijst met games</translation> 5864 <translation>Dubbel-klik om een ​​nieuwe map toe te voegen aan de spellijst</translation>
5843 </message> 5865 </message>
5844</context> 5866</context>
5845<context> 5867<context>
@@ -5847,7 +5869,7 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5847 <message numerus="yes"> 5869 <message numerus="yes">
5848 <location filename="../../src/yuzu/game_list.cpp" line="86"/> 5870 <location filename="../../src/yuzu/game_list.cpp" line="86"/>
5849 <source>%1 of %n result(s)</source> 5871 <source>%1 of %n result(s)</source>
5850 <translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> 5872 <translation><numerusform>%1 van %n resultaat(en)</numerusform><numerusform>%1 van %n resultaat(en)</numerusform></translation>
5851 </message> 5873 </message>
5852 <message> 5874 <message>
5853 <location filename="../../src/yuzu/game_list.cpp" line="791"/> 5875 <location filename="../../src/yuzu/game_list.cpp" line="791"/>
@@ -5857,7 +5879,7 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5857 <message> 5879 <message>
5858 <location filename="../../src/yuzu/game_list.cpp" line="792"/> 5880 <location filename="../../src/yuzu/game_list.cpp" line="792"/>
5859 <source>Enter pattern to filter</source> 5881 <source>Enter pattern to filter</source>
5860 <translation>Voer patroon in om te filteren:</translation> 5882 <translation>Voer patroon in om te filteren</translation>
5861 </message> 5883 </message>
5862</context> 5884</context>
5863<context> 5885<context>
@@ -5865,22 +5887,22 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5865 <message> 5887 <message>
5866 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="14"/> 5888 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="14"/>
5867 <source>Create Room</source> 5889 <source>Create Room</source>
5868 <translation type="unfinished"/> 5890 <translation>Maak Kamer</translation>
5869 </message> 5891 </message>
5870 <message> 5892 <message>
5871 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="37"/> 5893 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="37"/>
5872 <source>Room Name</source> 5894 <source>Room Name</source>
5873 <translation type="unfinished"/> 5895 <translation>Kamernaam</translation>
5874 </message> 5896 </message>
5875 <message> 5897 <message>
5876 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="51"/> 5898 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="51"/>
5877 <source>Preferred Game</source> 5899 <source>Preferred Game</source>
5878 <translation type="unfinished"/> 5900 <translation>Voorkeursspel</translation>
5879 </message> 5901 </message>
5880 <message> 5902 <message>
5881 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="61"/> 5903 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="61"/>
5882 <source>Max Players</source> 5904 <source>Max Players</source>
5883 <translation type="unfinished"/> 5905 <translation>Maximum Spelers</translation>
5884 </message> 5906 </message>
5885 <message> 5907 <message>
5886 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="91"/> 5908 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="91"/>
@@ -5890,42 +5912,42 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5890 <message> 5912 <message>
5891 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="101"/> 5913 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="101"/>
5892 <source>(Leave blank for open game)</source> 5914 <source>(Leave blank for open game)</source>
5893 <translation type="unfinished"/> 5915 <translation>(Laat leeg voor open spel)</translation>
5894 </message> 5916 </message>
5895 <message> 5917 <message>
5896 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="118"/> 5918 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="118"/>
5897 <source>Password</source> 5919 <source>Password</source>
5898 <translation type="unfinished"/> 5920 <translation>Wachtwoord</translation>
5899 </message> 5921 </message>
5900 <message> 5922 <message>
5901 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="125"/> 5923 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="125"/>
5902 <source>Port</source> 5924 <source>Port</source>
5903 <translation type="unfinished"/> 5925 <translation>Poort</translation>
5904 </message> 5926 </message>
5905 <message> 5927 <message>
5906 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="139"/> 5928 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="139"/>
5907 <source>Room Description</source> 5929 <source>Room Description</source>
5908 <translation>Kamer Beschrijving</translation> 5930 <translation>Kamerbeschrijving</translation>
5909 </message> 5931 </message>
5910 <message> 5932 <message>
5911 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="153"/> 5933 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="153"/>
5912 <source>Load Previous Ban List</source> 5934 <source>Load Previous Ban List</source>
5913 <translation type="unfinished"/> 5935 <translation>Laad Vorige Banlijst</translation>
5914 </message> 5936 </message>
5915 <message> 5937 <message>
5916 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="184"/> 5938 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="184"/>
5917 <source>Public</source> 5939 <source>Public</source>
5918 <translation type="unfinished"/> 5940 <translation>Openbaar</translation>
5919 </message> 5941 </message>
5920 <message> 5942 <message>
5921 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="189"/> 5943 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="189"/>
5922 <source>Unlisted</source> 5944 <source>Unlisted</source>
5923 <translation type="unfinished"/> 5945 <translation>Niet Vermeld</translation>
5924 </message> 5946 </message>
5925 <message> 5947 <message>
5926 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="197"/> 5948 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="197"/>
5927 <source>Host Room</source> 5949 <source>Host Room</source>
5928 <translation type="unfinished"/> 5950 <translation>Hostkamer</translation>
5929 </message> 5951 </message>
5930</context> 5952</context>
5931<context> 5953<context>
@@ -5933,13 +5955,14 @@ Wilt u dit omzeilen en toch afsluiten?</translation>
5933 <message> 5955 <message>
5934 <location filename="../../src/yuzu/multiplayer/host_room.cpp" line="182"/> 5956 <location filename="../../src/yuzu/multiplayer/host_room.cpp" line="182"/>
5935 <source>Error</source> 5957 <source>Error</source>
5936 <translation type="unfinished"/> 5958 <translation>Fout</translation>
5937 </message> 5959 </message>
5938 <message> 5960 <message>
5939 <location filename="../../src/yuzu/multiplayer/host_room.cpp" line="183"/> 5961 <location filename="../../src/yuzu/multiplayer/host_room.cpp" line="183"/>
5940 <source>Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid yuzu account configured in Emulation -&gt; Configure -&gt; Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. 5962 <source>Failed to announce the room to the public lobby. In order to host a room publicly, you must have a valid yuzu account configured in Emulation -&gt; Configure -&gt; Web. If you do not want to publish a room in the public lobby, then select Unlisted instead.
5941Debug Message: </source> 5963Debug Message: </source>
5942 <translation type="unfinished"/> 5964 <translation>Het is niet gelukt om de kamer aan te kondigen in de openbare lobby. Om een kamer openbaar te hosten, moet je een geldige yuzu-account geconfigureerd hebben in Emulatie -&gt; Configuratie -&gt; Web. Als je geen kamer wilt publiceren in de openbare lobby, selecteer dan in plaats daarvan Niet Vermeld.
5965Debug-bericht: </translation>
5943 </message> 5966 </message>
5944</context> 5967</context>
5945<context> 5968<context>
@@ -5947,7 +5970,7 @@ Debug Message: </source>
5947 <message> 5970 <message>
5948 <location filename="../../src/yuzu/configuration/config.cpp" line="73"/> 5971 <location filename="../../src/yuzu/configuration/config.cpp" line="73"/>
5949 <source>Audio Mute/Unmute</source> 5972 <source>Audio Mute/Unmute</source>
5950 <translation type="unfinished"/> 5973 <translation>Audio Dempen/Dempen Opheffen</translation>
5951 </message> 5974 </message>
5952 <message> 5975 <message>
5953 <location filename="../../src/yuzu/configuration/config.cpp" line="73"/> 5976 <location filename="../../src/yuzu/configuration/config.cpp" line="73"/>
@@ -5973,52 +5996,52 @@ Debug Message: </source>
5973 <location filename="../../src/yuzu/configuration/config.cpp" line="93"/> 5996 <location filename="../../src/yuzu/configuration/config.cpp" line="93"/>
5974 <location filename="../../src/yuzu/configuration/config.cpp" line="94"/> 5997 <location filename="../../src/yuzu/configuration/config.cpp" line="94"/>
5975 <source>Main Window</source> 5998 <source>Main Window</source>
5976 <translation type="unfinished"/> 5999 <translation>Hoofdvenster</translation>
5977 </message> 6000 </message>
5978 <message> 6001 <message>
5979 <location filename="../../src/yuzu/configuration/config.cpp" line="74"/> 6002 <location filename="../../src/yuzu/configuration/config.cpp" line="74"/>
5980 <source>Audio Volume Down</source> 6003 <source>Audio Volume Down</source>
5981 <translation type="unfinished"/> 6004 <translation>Audiovolume Omlaag</translation>
5982 </message> 6005 </message>
5983 <message> 6006 <message>
5984 <location filename="../../src/yuzu/configuration/config.cpp" line="75"/> 6007 <location filename="../../src/yuzu/configuration/config.cpp" line="75"/>
5985 <source>Audio Volume Up</source> 6008 <source>Audio Volume Up</source>
5986 <translation type="unfinished"/> 6009 <translation>Audiovolume Omhoog</translation>
5987 </message> 6010 </message>
5988 <message> 6011 <message>
5989 <location filename="../../src/yuzu/configuration/config.cpp" line="76"/> 6012 <location filename="../../src/yuzu/configuration/config.cpp" line="76"/>
5990 <source>Capture Screenshot</source> 6013 <source>Capture Screenshot</source>
5991 <translation>Screenshot Vastleggen</translation> 6014 <translation>Leg Schermafbeelding Vast</translation>
5992 </message> 6015 </message>
5993 <message> 6016 <message>
5994 <location filename="../../src/yuzu/configuration/config.cpp" line="77"/> 6017 <location filename="../../src/yuzu/configuration/config.cpp" line="77"/>
5995 <source>Change Adapting Filter</source> 6018 <source>Change Adapting Filter</source>
5996 <translation type="unfinished"/> 6019 <translation>Wijzig Aanpassingsfilter</translation>
5997 </message> 6020 </message>
5998 <message> 6021 <message>
5999 <location filename="../../src/yuzu/configuration/config.cpp" line="78"/> 6022 <location filename="../../src/yuzu/configuration/config.cpp" line="78"/>
6000 <source>Change Docked Mode</source> 6023 <source>Change Docked Mode</source>
6001 <translation type="unfinished"/> 6024 <translation>Wijzig Docked-modus</translation>
6002 </message> 6025 </message>
6003 <message> 6026 <message>
6004 <location filename="../../src/yuzu/configuration/config.cpp" line="79"/> 6027 <location filename="../../src/yuzu/configuration/config.cpp" line="79"/>
6005 <source>Change GPU Accuracy</source> 6028 <source>Change GPU Accuracy</source>
6006 <translation type="unfinished"/> 6029 <translation>Wijzig GPU-nauwkeurigheid</translation>
6007 </message> 6030 </message>
6008 <message> 6031 <message>
6009 <location filename="../../src/yuzu/configuration/config.cpp" line="80"/> 6032 <location filename="../../src/yuzu/configuration/config.cpp" line="80"/>
6010 <source>Continue/Pause Emulation</source> 6033 <source>Continue/Pause Emulation</source>
6011 <translation type="unfinished"/> 6034 <translation>Emulatie Doorgaan/Onderbreken</translation>
6012 </message> 6035 </message>
6013 <message> 6036 <message>
6014 <location filename="../../src/yuzu/configuration/config.cpp" line="81"/> 6037 <location filename="../../src/yuzu/configuration/config.cpp" line="81"/>
6015 <source>Exit Fullscreen</source> 6038 <source>Exit Fullscreen</source>
6016 <translation type="unfinished"/> 6039 <translation>Volledig Scherm Afsluiten</translation>
6017 </message> 6040 </message>
6018 <message> 6041 <message>
6019 <location filename="../../src/yuzu/configuration/config.cpp" line="82"/> 6042 <location filename="../../src/yuzu/configuration/config.cpp" line="82"/>
6020 <source>Exit yuzu</source> 6043 <source>Exit yuzu</source>
6021 <translation type="unfinished"/> 6044 <translation>yuzu afsluiten</translation>
6022 </message> 6045 </message>
6023 <message> 6046 <message>
6024 <location filename="../../src/yuzu/configuration/config.cpp" line="83"/> 6047 <location filename="../../src/yuzu/configuration/config.cpp" line="83"/>
@@ -6033,52 +6056,52 @@ Debug Message: </source>
6033 <message> 6056 <message>
6034 <location filename="../../src/yuzu/configuration/config.cpp" line="85"/> 6057 <location filename="../../src/yuzu/configuration/config.cpp" line="85"/>
6035 <source>Load/Remove Amiibo</source> 6058 <source>Load/Remove Amiibo</source>
6036 <translation type="unfinished"/> 6059 <translation>Laad/Verwijder Amiibo</translation>
6037 </message> 6060 </message>
6038 <message> 6061 <message>
6039 <location filename="../../src/yuzu/configuration/config.cpp" line="86"/> 6062 <location filename="../../src/yuzu/configuration/config.cpp" line="86"/>
6040 <source>Restart Emulation</source> 6063 <source>Restart Emulation</source>
6041 <translation type="unfinished"/> 6064 <translation>Herstart Emulatie</translation>
6042 </message> 6065 </message>
6043 <message> 6066 <message>
6044 <location filename="../../src/yuzu/configuration/config.cpp" line="87"/> 6067 <location filename="../../src/yuzu/configuration/config.cpp" line="87"/>
6045 <source>Stop Emulation</source> 6068 <source>Stop Emulation</source>
6046 <translation type="unfinished"/> 6069 <translation>Stop Emulatie</translation>
6047 </message> 6070 </message>
6048 <message> 6071 <message>
6049 <location filename="../../src/yuzu/configuration/config.cpp" line="88"/> 6072 <location filename="../../src/yuzu/configuration/config.cpp" line="88"/>
6050 <source>TAS Record</source> 6073 <source>TAS Record</source>
6051 <translation type="unfinished"/> 6074 <translation>TAS Opname</translation>
6052 </message> 6075 </message>
6053 <message> 6076 <message>
6054 <location filename="../../src/yuzu/configuration/config.cpp" line="89"/> 6077 <location filename="../../src/yuzu/configuration/config.cpp" line="89"/>
6055 <source>TAS Reset</source> 6078 <source>TAS Reset</source>
6056 <translation type="unfinished"/> 6079 <translation>TAS Reset</translation>
6057 </message> 6080 </message>
6058 <message> 6081 <message>
6059 <location filename="../../src/yuzu/configuration/config.cpp" line="90"/> 6082 <location filename="../../src/yuzu/configuration/config.cpp" line="90"/>
6060 <source>TAS Start/Stop</source> 6083 <source>TAS Start/Stop</source>
6061 <translation type="unfinished"/> 6084 <translation>TAS Start/Stop</translation>
6062 </message> 6085 </message>
6063 <message> 6086 <message>
6064 <location filename="../../src/yuzu/configuration/config.cpp" line="91"/> 6087 <location filename="../../src/yuzu/configuration/config.cpp" line="91"/>
6065 <source>Toggle Filter Bar</source> 6088 <source>Toggle Filter Bar</source>
6066 <translation type="unfinished"/> 6089 <translation>Schakel Filterbalk</translation>
6067 </message> 6090 </message>
6068 <message> 6091 <message>
6069 <location filename="../../src/yuzu/configuration/config.cpp" line="92"/> 6092 <location filename="../../src/yuzu/configuration/config.cpp" line="92"/>
6070 <source>Toggle Framerate Limit</source> 6093 <source>Toggle Framerate Limit</source>
6071 <translation type="unfinished"/> 6094 <translation>Schakel Frameratelimiet</translation>
6072 </message> 6095 </message>
6073 <message> 6096 <message>
6074 <location filename="../../src/yuzu/configuration/config.cpp" line="93"/> 6097 <location filename="../../src/yuzu/configuration/config.cpp" line="93"/>
6075 <source>Toggle Mouse Panning</source> 6098 <source>Toggle Mouse Panning</source>
6076 <translation type="unfinished"/> 6099 <translation>Schakel Muispanning</translation>
6077 </message> 6100 </message>
6078 <message> 6101 <message>
6079 <location filename="../../src/yuzu/configuration/config.cpp" line="94"/> 6102 <location filename="../../src/yuzu/configuration/config.cpp" line="94"/>
6080 <source>Toggle Status Bar</source> 6103 <source>Toggle Status Bar</source>
6081 <translation type="unfinished"/> 6104 <translation>Schakel Statusbalk</translation>
6082 </message> 6105 </message>
6083</context> 6106</context>
6084<context> 6107<context>
@@ -6086,17 +6109,17 @@ Debug Message: </source>
6086 <message> 6109 <message>
6087 <location filename="../../src/yuzu/install_dialog.cpp" line="29"/> 6110 <location filename="../../src/yuzu/install_dialog.cpp" line="29"/>
6088 <source>Please confirm these are the files you wish to install.</source> 6111 <source>Please confirm these are the files you wish to install.</source>
6089 <translation type="unfinished"/> 6112 <translation>Bevestig dat dit de bestanden zijn die je wilt installeren.</translation>
6090 </message> 6113 </message>
6091 <message> 6114 <message>
6092 <location filename="../../src/yuzu/install_dialog.cpp" line="32"/> 6115 <location filename="../../src/yuzu/install_dialog.cpp" line="32"/>
6093 <source>Installing an Update or DLC will overwrite the previously installed one.</source> 6116 <source>Installing an Update or DLC will overwrite the previously installed one.</source>
6094 <translation type="unfinished"/> 6117 <translation>Het installeren van een Update of DLC overschrijft de eerder geïnstalleerde.</translation>
6095 </message> 6118 </message>
6096 <message> 6119 <message>
6097 <location filename="../../src/yuzu/install_dialog.cpp" line="36"/> 6120 <location filename="../../src/yuzu/install_dialog.cpp" line="36"/>
6098 <source>Install</source> 6121 <source>Install</source>
6099 <translation>Installeren</translation> 6122 <translation>Installeer</translation>
6100 </message> 6123 </message>
6101 <message> 6124 <message>
6102 <location filename="../../src/yuzu/install_dialog.cpp" line="49"/> 6125 <location filename="../../src/yuzu/install_dialog.cpp" line="49"/>
@@ -6110,7 +6133,8 @@ Debug Message: </source>
6110 <location filename="../../src/yuzu/util/limitable_input_dialog.cpp" line="59"/> 6133 <location filename="../../src/yuzu/util/limitable_input_dialog.cpp" line="59"/>
6111 <source>The text can't contain any of the following characters: 6134 <source>The text can't contain any of the following characters:
6112%1</source> 6135%1</source>
6113 <translation type="unfinished"/> 6136 <translation>De tekst kan geen van de volgende tekens bevatten:
6137%1</translation>
6114 </message> 6138 </message>
6115</context> 6139</context>
6116<context> 6140<context>
@@ -6118,12 +6142,12 @@ Debug Message: </source>
6118 <message> 6142 <message>
6119 <location filename="../../src/yuzu/loading_screen.ui" line="84"/> 6143 <location filename="../../src/yuzu/loading_screen.ui" line="84"/>
6120 <source>Loading Shaders 387 / 1628</source> 6144 <source>Loading Shaders 387 / 1628</source>
6121 <translation>Shaders Laden 387 / 1628</translation> 6145 <translation>Shaders Laden 387 / 1628</translation>
6122 </message> 6146 </message>
6123 <message> 6147 <message>
6124 <location filename="../../src/yuzu/loading_screen.ui" line="121"/> 6148 <location filename="../../src/yuzu/loading_screen.ui" line="121"/>
6125 <source>Loading Shaders %v out of %m</source> 6149 <source>Loading Shaders %v out of %m</source>
6126 <translation>%v Shaders Laden van de %m</translation> 6150 <translation>Shaders Laden %v van %m</translation>
6127 </message> 6151 </message>
6128 <message> 6152 <message>
6129 <location filename="../../src/yuzu/loading_screen.ui" line="135"/> 6153 <location filename="../../src/yuzu/loading_screen.ui" line="135"/>
@@ -6138,7 +6162,7 @@ Debug Message: </source>
6138 <message> 6162 <message>
6139 <location filename="../../src/yuzu/loading_screen.cpp" line="84"/> 6163 <location filename="../../src/yuzu/loading_screen.cpp" line="84"/>
6140 <source>Loading Shaders %1 / %2</source> 6164 <source>Loading Shaders %1 / %2</source>
6141 <translation>Shaders Laden %1 / %2</translation> 6165 <translation>Shaders Laden %1 / %2</translation>
6142 </message> 6166 </message>
6143 <message> 6167 <message>
6144 <location filename="../../src/yuzu/loading_screen.cpp" line="85"/> 6168 <location filename="../../src/yuzu/loading_screen.cpp" line="85"/>
@@ -6156,53 +6180,53 @@ Debug Message: </source>
6156 <message> 6180 <message>
6157 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="14"/> 6181 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="14"/>
6158 <source>Public Room Browser</source> 6182 <source>Public Room Browser</source>
6159 <translation type="unfinished"/> 6183 <translation>Browser voor Openbare Ruimten</translation>
6160 </message> 6184 </message>
6161 <message> 6185 <message>
6162 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="32"/> 6186 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="32"/>
6163 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="39"/> 6187 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="39"/>
6164 <source>Nickname</source> 6188 <source>Nickname</source>
6165 <translation type="unfinished"/> 6189 <translation>Gebruikersnaam</translation>
6166 </message> 6190 </message>
6167 <message> 6191 <message>
6168 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="59"/> 6192 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="59"/>
6169 <source>Filters</source> 6193 <source>Filters</source>
6170 <translation type="unfinished"/> 6194 <translation>Filters</translation>
6171 </message> 6195 </message>
6172 <message> 6196 <message>
6173 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="66"/> 6197 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="66"/>
6174 <source>Search</source> 6198 <source>Search</source>
6175 <translation type="unfinished"/> 6199 <translation>Zoek</translation>
6176 </message> 6200 </message>
6177 <message> 6201 <message>
6178 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="76"/> 6202 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="76"/>
6179 <source>Games I Own</source> 6203 <source>Games I Own</source>
6180 <translation type="unfinished"/> 6204 <translation>Spellen die ik bezit</translation>
6181 </message> 6205 </message>
6182 <message> 6206 <message>
6183 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="83"/> 6207 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="83"/>
6184 <source>Hide Empty Rooms</source> 6208 <source>Hide Empty Rooms</source>
6185 <translation type="unfinished"/> 6209 <translation>Verberg Lege Kamers</translation>
6186 </message> 6210 </message>
6187 <message> 6211 <message>
6188 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="90"/> 6212 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="90"/>
6189 <source>Hide Full Rooms</source> 6213 <source>Hide Full Rooms</source>
6190 <translation type="unfinished"/> 6214 <translation>Verberg Volle Kamers</translation>
6191 </message> 6215 </message>
6192 <message> 6216 <message>
6193 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="110"/> 6217 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="110"/>
6194 <source>Refresh Lobby</source> 6218 <source>Refresh Lobby</source>
6195 <translation type="unfinished"/> 6219 <translation>Vernieuw Lobby</translation>
6196 </message> 6220 </message>
6197 <message> 6221 <message>
6198 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="113"/> 6222 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="113"/>
6199 <source>Password Required to Join</source> 6223 <source>Password Required to Join</source>
6200 <translation type="unfinished"/> 6224 <translation>Wachtwoord vereist om toegang te krijgen</translation>
6201 </message> 6225 </message>
6202 <message> 6226 <message>
6203 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="113"/> 6227 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="113"/>
6204 <source>Password:</source> 6228 <source>Password:</source>
6205 <translation type="unfinished"/> 6229 <translation>Wachtwoord:</translation>
6206 </message> 6230 </message>
6207 <message> 6231 <message>
6208 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="216"/> 6232 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="216"/>
@@ -6212,27 +6236,27 @@ Debug Message: </source>
6212 <message> 6236 <message>
6213 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="217"/> 6237 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="217"/>
6214 <source>Room Name</source> 6238 <source>Room Name</source>
6215 <translation type="unfinished"/> 6239 <translation>Kamernaam</translation>
6216 </message> 6240 </message>
6217 <message> 6241 <message>
6218 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="218"/> 6242 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="218"/>
6219 <source>Preferred Game</source> 6243 <source>Preferred Game</source>
6220 <translation type="unfinished"/> 6244 <translation>Voorkeursspel</translation>
6221 </message> 6245 </message>
6222 <message> 6246 <message>
6223 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="219"/> 6247 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="219"/>
6224 <source>Host</source> 6248 <source>Host</source>
6225 <translation type="unfinished"/> 6249 <translation>Host</translation>
6226 </message> 6250 </message>
6227 <message> 6251 <message>
6228 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="226"/> 6252 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="226"/>
6229 <source>Refreshing</source> 6253 <source>Refreshing</source>
6230 <translation type="unfinished"/> 6254 <translation>Vernieuwen</translation>
6231 </message> 6255 </message>
6232 <message> 6256 <message>
6233 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="283"/> 6257 <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="283"/>
6234 <source>Refresh List</source> 6258 <source>Refresh List</source>
6235 <translation type="unfinished"/> 6259 <translation>Vernieuw Lijst</translation>
6236 </message> 6260 </message>
6237</context> 6261</context>
6238<context> 6262<context>
@@ -6250,7 +6274,7 @@ Debug Message: </source>
6250 <message> 6274 <message>
6251 <location filename="../../src/yuzu/main.ui" line="48"/> 6275 <location filename="../../src/yuzu/main.ui" line="48"/>
6252 <source>&amp;Recent Files</source> 6276 <source>&amp;Recent Files</source>
6253 <translation type="unfinished"/> 6277 <translation>&amp;Recente Bestanden</translation>
6254 </message> 6278 </message>
6255 <message> 6279 <message>
6256 <location filename="../../src/yuzu/main.ui" line="66"/> 6280 <location filename="../../src/yuzu/main.ui" line="66"/>
@@ -6265,57 +6289,57 @@ Debug Message: </source>
6265 <message> 6289 <message>
6266 <location filename="../../src/yuzu/main.ui" line="81"/> 6290 <location filename="../../src/yuzu/main.ui" line="81"/>
6267 <source>&amp;Reset Window Size</source> 6291 <source>&amp;Reset Window Size</source>
6268 <translation type="unfinished"/> 6292 <translation>&amp;Herstel Venstergrootte</translation>
6269 </message> 6293 </message>
6270 <message> 6294 <message>
6271 <location filename="../../src/yuzu/main.ui" line="86"/> 6295 <location filename="../../src/yuzu/main.ui" line="86"/>
6272 <source>&amp;Debugging</source> 6296 <source>&amp;Debugging</source>
6273 <translation type="unfinished"/> 6297 <translation>&amp;Debuggen</translation>
6274 </message> 6298 </message>
6275 <message> 6299 <message>
6276 <location filename="../../src/yuzu/main.ui" line="91"/> 6300 <location filename="../../src/yuzu/main.ui" line="91"/>
6277 <source>Reset Window Size to &amp;720p</source> 6301 <source>Reset Window Size to &amp;720p</source>
6278 <translation type="unfinished"/> 6302 <translation>Herstel Venstergrootte naar &amp;720p</translation>
6279 </message> 6303 </message>
6280 <message> 6304 <message>
6281 <location filename="../../src/yuzu/main.ui" line="94"/> 6305 <location filename="../../src/yuzu/main.ui" line="94"/>
6282 <source>Reset Window Size to 720p</source> 6306 <source>Reset Window Size to 720p</source>
6283 <translation type="unfinished"/> 6307 <translation>Herstel Venstergrootte naar 720p</translation>
6284 </message> 6308 </message>
6285 <message> 6309 <message>
6286 <location filename="../../src/yuzu/main.ui" line="99"/> 6310 <location filename="../../src/yuzu/main.ui" line="99"/>
6287 <source>Reset Window Size to &amp;900p</source> 6311 <source>Reset Window Size to &amp;900p</source>
6288 <translation type="unfinished"/> 6312 <translation>Herstel Venstergrootte naar &amp;900p</translation>
6289 </message> 6313 </message>
6290 <message> 6314 <message>
6291 <location filename="../../src/yuzu/main.ui" line="102"/> 6315 <location filename="../../src/yuzu/main.ui" line="102"/>
6292 <source>Reset Window Size to 900p</source> 6316 <source>Reset Window Size to 900p</source>
6293 <translation type="unfinished"/> 6317 <translation>Herstel Venstergrootte naar 900p</translation>
6294 </message> 6318 </message>
6295 <message> 6319 <message>
6296 <location filename="../../src/yuzu/main.ui" line="107"/> 6320 <location filename="../../src/yuzu/main.ui" line="107"/>
6297 <source>Reset Window Size to &amp;1080p</source> 6321 <source>Reset Window Size to &amp;1080p</source>
6298 <translation type="unfinished"/> 6322 <translation>Herstel Venstergrootte naar &amp;1080p</translation>
6299 </message> 6323 </message>
6300 <message> 6324 <message>
6301 <location filename="../../src/yuzu/main.ui" line="110"/> 6325 <location filename="../../src/yuzu/main.ui" line="110"/>
6302 <source>Reset Window Size to 1080p</source> 6326 <source>Reset Window Size to 1080p</source>
6303 <translation type="unfinished"/> 6327 <translation>Herstel Venstergrootte naar 1080p</translation>
6304 </message> 6328 </message>
6305 <message> 6329 <message>
6306 <location filename="../../src/yuzu/main.ui" line="127"/> 6330 <location filename="../../src/yuzu/main.ui" line="127"/>
6307 <source>&amp;Multiplayer</source> 6331 <source>&amp;Multiplayer</source>
6308 <translation type="unfinished"/> 6332 <translation>&amp;Multiplayer</translation>
6309 </message> 6333 </message>
6310 <message> 6334 <message>
6311 <location filename="../../src/yuzu/main.ui" line="138"/> 6335 <location filename="../../src/yuzu/main.ui" line="138"/>
6312 <source>&amp;Tools</source> 6336 <source>&amp;Tools</source>
6313 <translation type="unfinished"/> 6337 <translation>&amp;Tools</translation>
6314 </message> 6338 </message>
6315 <message> 6339 <message>
6316 <location filename="../../src/yuzu/main.ui" line="142"/> 6340 <location filename="../../src/yuzu/main.ui" line="142"/>
6317 <source>&amp;TAS</source> 6341 <source>&amp;TAS</source>
6318 <translation type="unfinished"/> 6342 <translation>&amp;TAS</translation>
6319 </message> 6343 </message>
6320 <message> 6344 <message>
6321 <location filename="../../src/yuzu/main.ui" line="157"/> 6345 <location filename="../../src/yuzu/main.ui" line="157"/>
@@ -6325,17 +6349,17 @@ Debug Message: </source>
6325 <message> 6349 <message>
6326 <location filename="../../src/yuzu/main.ui" line="178"/> 6350 <location filename="../../src/yuzu/main.ui" line="178"/>
6327 <source>&amp;Install Files to NAND...</source> 6351 <source>&amp;Install Files to NAND...</source>
6328 <translation type="unfinished"/> 6352 <translation>&amp;Installeer Bestanden naar NAND...</translation>
6329 </message> 6353 </message>
6330 <message> 6354 <message>
6331 <location filename="../../src/yuzu/main.ui" line="183"/> 6355 <location filename="../../src/yuzu/main.ui" line="183"/>
6332 <source>L&amp;oad File...</source> 6356 <source>L&amp;oad File...</source>
6333 <translation type="unfinished"/> 6357 <translation>L&amp;aad Bestand...</translation>
6334 </message> 6358 </message>
6335 <message> 6359 <message>
6336 <location filename="../../src/yuzu/main.ui" line="188"/> 6360 <location filename="../../src/yuzu/main.ui" line="188"/>
6337 <source>Load &amp;Folder...</source> 6361 <source>Load &amp;Folder...</source>
6338 <translation type="unfinished"/> 6362 <translation>Laad &amp;Map...</translation>
6339 </message> 6363 </message>
6340 <message> 6364 <message>
6341 <location filename="../../src/yuzu/main.ui" line="193"/> 6365 <location filename="../../src/yuzu/main.ui" line="193"/>
@@ -6345,7 +6369,7 @@ Debug Message: </source>
6345 <message> 6369 <message>
6346 <location filename="../../src/yuzu/main.ui" line="201"/> 6370 <location filename="../../src/yuzu/main.ui" line="201"/>
6347 <source>&amp;Pause</source> 6371 <source>&amp;Pause</source>
6348 <translation>&amp;Pauzeren</translation> 6372 <translation>&amp;Onderbreken</translation>
6349 </message> 6373 </message>
6350 <message> 6374 <message>
6351 <location filename="../../src/yuzu/main.ui" line="209"/> 6375 <location filename="../../src/yuzu/main.ui" line="209"/>
@@ -6355,122 +6379,122 @@ Debug Message: </source>
6355 <message> 6379 <message>
6356 <location filename="../../src/yuzu/main.ui" line="214"/> 6380 <location filename="../../src/yuzu/main.ui" line="214"/>
6357 <source>&amp;Reinitialize keys...</source> 6381 <source>&amp;Reinitialize keys...</source>
6358 <translation type="unfinished"/> 6382 <translation>&amp;Herinitialiseer toetsen...</translation>
6359 </message> 6383 </message>
6360 <message> 6384 <message>
6361 <location filename="../../src/yuzu/main.ui" line="219"/> 6385 <location filename="../../src/yuzu/main.ui" line="219"/>
6362 <source>&amp;About yuzu</source> 6386 <source>&amp;About yuzu</source>
6363 <translation type="unfinished"/> 6387 <translation>&amp;Over yuzu</translation>
6364 </message> 6388 </message>
6365 <message> 6389 <message>
6366 <location filename="../../src/yuzu/main.ui" line="227"/> 6390 <location filename="../../src/yuzu/main.ui" line="227"/>
6367 <source>Single &amp;Window Mode</source> 6391 <source>Single &amp;Window Mode</source>
6368 <translation type="unfinished"/> 6392 <translation>Modus Enkel Venster</translation>
6369 </message> 6393 </message>
6370 <message> 6394 <message>
6371 <location filename="../../src/yuzu/main.ui" line="232"/> 6395 <location filename="../../src/yuzu/main.ui" line="232"/>
6372 <source>Con&amp;figure...</source> 6396 <source>Con&amp;figure...</source>
6373 <translation type="unfinished"/> 6397 <translation>Con&amp;figureer...</translation>
6374 </message> 6398 </message>
6375 <message> 6399 <message>
6376 <location filename="../../src/yuzu/main.ui" line="243"/> 6400 <location filename="../../src/yuzu/main.ui" line="243"/>
6377 <source>Display D&amp;ock Widget Headers</source> 6401 <source>Display D&amp;ock Widget Headers</source>
6378 <translation type="unfinished"/> 6402 <translation>Toon Dock Widget Kopteksten</translation>
6379 </message> 6403 </message>
6380 <message> 6404 <message>
6381 <location filename="../../src/yuzu/main.ui" line="251"/> 6405 <location filename="../../src/yuzu/main.ui" line="251"/>
6382 <source>Show &amp;Filter Bar</source> 6406 <source>Show &amp;Filter Bar</source>
6383 <translation type="unfinished"/> 6407 <translation>Toon &amp;Filterbalk</translation>
6384 </message> 6408 </message>
6385 <message> 6409 <message>
6386 <location filename="../../src/yuzu/main.ui" line="259"/> 6410 <location filename="../../src/yuzu/main.ui" line="259"/>
6387 <source>Show &amp;Status Bar</source> 6411 <source>Show &amp;Status Bar</source>
6388 <translation type="unfinished"/> 6412 <translation>Toon &amp;Statusbalk</translation>
6389 </message> 6413 </message>
6390 <message> 6414 <message>
6391 <location filename="../../src/yuzu/main.ui" line="262"/> 6415 <location filename="../../src/yuzu/main.ui" line="262"/>
6392 <source>Show Status Bar</source> 6416 <source>Show Status Bar</source>
6393 <translation>Laat status balk zien</translation> 6417 <translation>Toon Statusbalk</translation>
6394 </message> 6418 </message>
6395 <message> 6419 <message>
6396 <location filename="../../src/yuzu/main.ui" line="270"/> 6420 <location filename="../../src/yuzu/main.ui" line="270"/>
6397 <source>&amp;Browse Public Game Lobby</source> 6421 <source>&amp;Browse Public Game Lobby</source>
6398 <translation type="unfinished"/> 6422 <translation>&amp;Bladeren door Openbare Spellobby</translation>
6399 </message> 6423 </message>
6400 <message> 6424 <message>
6401 <location filename="../../src/yuzu/main.ui" line="278"/> 6425 <location filename="../../src/yuzu/main.ui" line="278"/>
6402 <source>&amp;Create Room</source> 6426 <source>&amp;Create Room</source>
6403 <translation type="unfinished"/> 6427 <translation>&amp;Maak Kamer</translation>
6404 </message> 6428 </message>
6405 <message> 6429 <message>
6406 <location filename="../../src/yuzu/main.ui" line="286"/> 6430 <location filename="../../src/yuzu/main.ui" line="286"/>
6407 <source>&amp;Leave Room</source> 6431 <source>&amp;Leave Room</source>
6408 <translation type="unfinished"/> 6432 <translation>&amp;Verlaat Kamer</translation>
6409 </message> 6433 </message>
6410 <message> 6434 <message>
6411 <location filename="../../src/yuzu/main.ui" line="291"/> 6435 <location filename="../../src/yuzu/main.ui" line="291"/>
6412 <source>&amp;Direct Connect to Room</source> 6436 <source>&amp;Direct Connect to Room</source>
6413 <translation type="unfinished"/> 6437 <translation>&amp;Directe Verbinding met Kamer</translation>
6414 </message> 6438 </message>
6415 <message> 6439 <message>
6416 <location filename="../../src/yuzu/main.ui" line="299"/> 6440 <location filename="../../src/yuzu/main.ui" line="299"/>
6417 <source>&amp;Show Current Room</source> 6441 <source>&amp;Show Current Room</source>
6418 <translation type="unfinished"/> 6442 <translation>&amp;Toon Huidige Kamer</translation>
6419 </message> 6443 </message>
6420 <message> 6444 <message>
6421 <location filename="../../src/yuzu/main.ui" line="307"/> 6445 <location filename="../../src/yuzu/main.ui" line="307"/>
6422 <source>F&amp;ullscreen</source> 6446 <source>F&amp;ullscreen</source>
6423 <translation type="unfinished"/> 6447 <translation>Volledig Scherm</translation>
6424 </message> 6448 </message>
6425 <message> 6449 <message>
6426 <location filename="../../src/yuzu/main.ui" line="315"/> 6450 <location filename="../../src/yuzu/main.ui" line="315"/>
6427 <source>&amp;Restart</source> 6451 <source>&amp;Restart</source>
6428 <translation type="unfinished"/> 6452 <translation>&amp;Herstart</translation>
6429 </message> 6453 </message>
6430 <message> 6454 <message>
6431 <location filename="../../src/yuzu/main.ui" line="323"/> 6455 <location filename="../../src/yuzu/main.ui" line="323"/>
6432 <source>Load/Remove &amp;Amiibo...</source> 6456 <source>Load/Remove &amp;Amiibo...</source>
6433 <translation type="unfinished"/> 6457 <translation>Laad/Verwijder &amp;Amiibo...</translation>
6434 </message> 6458 </message>
6435 <message> 6459 <message>
6436 <location filename="../../src/yuzu/main.ui" line="331"/> 6460 <location filename="../../src/yuzu/main.ui" line="331"/>
6437 <source>&amp;Report Compatibility</source> 6461 <source>&amp;Report Compatibility</source>
6438 <translation type="unfinished"/> 6462 <translation>&amp;Rapporteer Compatibiliteit</translation>
6439 </message> 6463 </message>
6440 <message> 6464 <message>
6441 <location filename="../../src/yuzu/main.ui" line="339"/> 6465 <location filename="../../src/yuzu/main.ui" line="339"/>
6442 <source>Open &amp;Mods Page</source> 6466 <source>Open &amp;Mods Page</source>
6443 <translation type="unfinished"/> 6467 <translation>Open &amp;Mod-pagina</translation>
6444 </message> 6468 </message>
6445 <message> 6469 <message>
6446 <location filename="../../src/yuzu/main.ui" line="344"/> 6470 <location filename="../../src/yuzu/main.ui" line="344"/>
6447 <source>Open &amp;Quickstart Guide</source> 6471 <source>Open &amp;Quickstart Guide</source>
6448 <translation type="unfinished"/> 6472 <translation>Open &amp;Snelstartgids</translation>
6449 </message> 6473 </message>
6450 <message> 6474 <message>
6451 <location filename="../../src/yuzu/main.ui" line="349"/> 6475 <location filename="../../src/yuzu/main.ui" line="349"/>
6452 <source>&amp;FAQ</source> 6476 <source>&amp;FAQ</source>
6453 <translation type="unfinished"/> 6477 <translation>&amp;FAQ</translation>
6454 </message> 6478 </message>
6455 <message> 6479 <message>
6456 <location filename="../../src/yuzu/main.ui" line="354"/> 6480 <location filename="../../src/yuzu/main.ui" line="354"/>
6457 <source>Open &amp;yuzu Folder</source> 6481 <source>Open &amp;yuzu Folder</source>
6458 <translation type="unfinished"/> 6482 <translation>Open &amp;yuzu-map</translation>
6459 </message> 6483 </message>
6460 <message> 6484 <message>
6461 <location filename="../../src/yuzu/main.ui" line="362"/> 6485 <location filename="../../src/yuzu/main.ui" line="362"/>
6462 <source>&amp;Capture Screenshot</source> 6486 <source>&amp;Capture Screenshot</source>
6463 <translation type="unfinished"/> 6487 <translation>&amp;Leg Schermafbeelding Vast</translation>
6464 </message> 6488 </message>
6465 <message> 6489 <message>
6466 <location filename="../../src/yuzu/main.ui" line="367"/> 6490 <location filename="../../src/yuzu/main.ui" line="367"/>
6467 <source>&amp;Configure TAS...</source> 6491 <source>&amp;Configure TAS...</source>
6468 <translation type="unfinished"/> 6492 <translation>&amp;Configureer TAS...</translation>
6469 </message> 6493 </message>
6470 <message> 6494 <message>
6471 <location filename="../../src/yuzu/main.ui" line="378"/> 6495 <location filename="../../src/yuzu/main.ui" line="378"/>
6472 <source>Configure C&amp;urrent Game...</source> 6496 <source>Configure C&amp;urrent Game...</source>
6473 <translation type="unfinished"/> 6497 <translation>Configureer Huidig Spel...</translation>
6474 </message> 6498 </message>
6475 <message> 6499 <message>
6476 <location filename="../../src/yuzu/main.ui" line="389"/> 6500 <location filename="../../src/yuzu/main.ui" line="389"/>
@@ -6480,12 +6504,12 @@ Debug Message: </source>
6480 <message> 6504 <message>
6481 <location filename="../../src/yuzu/main.ui" line="397"/> 6505 <location filename="../../src/yuzu/main.ui" line="397"/>
6482 <source>&amp;Reset</source> 6506 <source>&amp;Reset</source>
6483 <translation type="unfinished"/> 6507 <translation>&amp;Herstel</translation>
6484 </message> 6508 </message>
6485 <message> 6509 <message>
6486 <location filename="../../src/yuzu/main.ui" line="405"/> 6510 <location filename="../../src/yuzu/main.ui" line="405"/>
6487 <source>R&amp;ecord</source> 6511 <source>R&amp;ecord</source>
6488 <translation type="unfinished"/> 6512 <translation>Opnemen</translation>
6489 </message> 6513 </message>
6490</context> 6514</context>
6491<context> 6515<context>
@@ -6493,7 +6517,7 @@ Debug Message: </source>
6493 <message> 6517 <message>
6494 <location filename="../../src/yuzu/debugger/profiler.cpp" line="50"/> 6518 <location filename="../../src/yuzu/debugger/profiler.cpp" line="50"/>
6495 <source>&amp;MicroProfile</source> 6519 <source>&amp;MicroProfile</source>
6496 <translation type="unfinished"/> 6520 <translation>&amp;MicroProfile</translation>
6497 </message> 6521 </message>
6498</context> 6522</context>
6499<context> 6523<context>
@@ -6501,48 +6525,48 @@ Debug Message: </source>
6501 <message> 6525 <message>
6502 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="6"/> 6526 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="6"/>
6503 <source>Moderation</source> 6527 <source>Moderation</source>
6504 <translation type="unfinished"/> 6528 <translation>Moderatie</translation>
6505 </message> 6529 </message>
6506 <message> 6530 <message>
6507 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="20"/> 6531 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="20"/>
6508 <source>Ban List</source> 6532 <source>Ban List</source>
6509 <translation type="unfinished"/> 6533 <translation>Banlijst</translation>
6510 </message> 6534 </message>
6511 <message> 6535 <message>
6512 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="41"/> 6536 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="41"/>
6513 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="73"/> 6537 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="73"/>
6514 <source>Refreshing</source> 6538 <source>Refreshing</source>
6515 <translation type="unfinished"/> 6539 <translation>Vernieuwen</translation>
6516 </message> 6540 </message>
6517 <message> 6541 <message>
6518 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="51"/> 6542 <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="51"/>
6519 <source>Unban</source> 6543 <source>Unban</source>
6520 <translation type="unfinished"/> 6544 <translation>Ontban</translation>
6521 </message> 6545 </message>
6522 <message> 6546 <message>
6523 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="40"/> 6547 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="40"/>
6524 <source>Subject</source> 6548 <source>Subject</source>
6525 <translation type="unfinished"/> 6549 <translation>Onderwerp</translation>
6526 </message> 6550 </message>
6527 <message> 6551 <message>
6528 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="41"/> 6552 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="41"/>
6529 <source>Type</source> 6553 <source>Type</source>
6530 <translation type="unfinished"/> 6554 <translation>Soort</translation>
6531 </message> 6555 </message>
6532 <message> 6556 <message>
6533 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="83"/> 6557 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="83"/>
6534 <source>Forum Username</source> 6558 <source>Forum Username</source>
6535 <translation type="unfinished"/> 6559 <translation>Forum Gebruikersnaam</translation>
6536 </message> 6560 </message>
6537 <message> 6561 <message>
6538 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="88"/> 6562 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="88"/>
6539 <source>IP Address</source> 6563 <source>IP Address</source>
6540 <translation type="unfinished"/> 6564 <translation>IP-adres</translation>
6541 </message> 6565 </message>
6542 <message> 6566 <message>
6543 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="95"/> 6567 <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="95"/>
6544 <source>Refresh</source> 6568 <source>Refresh</source>
6545 <translation type="unfinished"/> 6569 <translation>Vernieuw</translation>
6546 </message> 6570 </message>
6547</context> 6571</context>
6548<context> 6572<context>
@@ -6550,17 +6574,17 @@ Debug Message: </source>
6550 <message> 6574 <message>
6551 <location filename="../../src/yuzu/multiplayer/state.cpp" line="90"/> 6575 <location filename="../../src/yuzu/multiplayer/state.cpp" line="90"/>
6552 <source>Current connection status</source> 6576 <source>Current connection status</source>
6553 <translation type="unfinished"/> 6577 <translation>Huidige verbindingsstatus</translation>
6554 </message> 6578 </message>
6555 <message> 6579 <message>
6556 <location filename="../../src/yuzu/multiplayer/state.cpp" line="117"/> 6580 <location filename="../../src/yuzu/multiplayer/state.cpp" line="117"/>
6557 <source>Not Connected. Click here to find a room!</source> 6581 <source>Not Connected. Click here to find a room!</source>
6558 <translation type="unfinished"/> 6582 <translation>Niet Verbonden. Klik hier om een kamer te vinden!</translation>
6559 </message> 6583 </message>
6560 <message> 6584 <message>
6561 <location filename="../../src/yuzu/multiplayer/state.cpp" line="123"/> 6585 <location filename="../../src/yuzu/multiplayer/state.cpp" line="123"/>
6562 <source>Not Connected</source> 6586 <source>Not Connected</source>
6563 <translation type="unfinished"/> 6587 <translation>Niet Verbonden</translation>
6564 </message> 6588 </message>
6565 <message> 6589 <message>
6566 <location filename="../../src/yuzu/multiplayer/state.cpp" line="129"/> 6590 <location filename="../../src/yuzu/multiplayer/state.cpp" line="129"/>
@@ -6570,18 +6594,19 @@ Debug Message: </source>
6570 <message> 6594 <message>
6571 <location filename="../../src/yuzu/multiplayer/state.cpp" line="136"/> 6595 <location filename="../../src/yuzu/multiplayer/state.cpp" line="136"/>
6572 <source>New Messages Received</source> 6596 <source>New Messages Received</source>
6573 <translation type="unfinished"/> 6597 <translation>Nieuwe Berichten Ontvangen</translation>
6574 </message> 6598 </message>
6575 <message> 6599 <message>
6576 <location filename="../../src/yuzu/multiplayer/state.cpp" line="207"/> 6600 <location filename="../../src/yuzu/multiplayer/state.cpp" line="207"/>
6577 <source>Error</source> 6601 <source>Error</source>
6578 <translation type="unfinished"/> 6602 <translation>Fout</translation>
6579 </message> 6603 </message>
6580 <message> 6604 <message>
6581 <location filename="../../src/yuzu/multiplayer/state.cpp" line="208"/> 6605 <location filename="../../src/yuzu/multiplayer/state.cpp" line="208"/>
6582 <source>Failed to update the room information. Please check your Internet connection and try hosting the room again. 6606 <source>Failed to update the room information. Please check your Internet connection and try hosting the room again.
6583Debug Message: </source> 6607Debug Message: </source>
6584 <translation type="unfinished"/> 6608 <translation>Het is niet gelukt om de kamerinformatie bij te werken. Controleer je internetverbinding en probeer de kamer opnieuw te hosten.
6609Debug-bericht: </translation>
6585 </message> 6610 </message>
6586</context> 6611</context>
6587<context> 6612<context>
@@ -6589,135 +6614,138 @@ Debug Message: </source>
6589 <message> 6614 <message>
6590 <location filename="../../src/yuzu/multiplayer/message.cpp" line="11"/> 6615 <location filename="../../src/yuzu/multiplayer/message.cpp" line="11"/>
6591 <source>Username is not valid. Must be 4 to 20 alphanumeric characters.</source> 6616 <source>Username is not valid. Must be 4 to 20 alphanumeric characters.</source>
6592 <translation type="unfinished"/> 6617 <translation>Gebruikersnaam is niet geldig. Moet bestaan uit 4 tot 20 alfanumerieke tekens.</translation>
6593 </message> 6618 </message>
6594 <message> 6619 <message>
6595 <location filename="../../src/yuzu/multiplayer/message.cpp" line="13"/> 6620 <location filename="../../src/yuzu/multiplayer/message.cpp" line="13"/>
6596 <source>Room name is not valid. Must be 4 to 20 alphanumeric characters.</source> 6621 <source>Room name is not valid. Must be 4 to 20 alphanumeric characters.</source>
6597 <translation type="unfinished"/> 6622 <translation>Kamernaam is niet geldig. Moet bestaan uit 4 tot 20 alfanumerieke tekens.</translation>
6598 </message> 6623 </message>
6599 <message> 6624 <message>
6600 <location filename="../../src/yuzu/multiplayer/message.cpp" line="15"/> 6625 <location filename="../../src/yuzu/multiplayer/message.cpp" line="15"/>
6601 <source>Username is already in use or not valid. Please choose another.</source> 6626 <source>Username is already in use or not valid. Please choose another.</source>
6602 <translation type="unfinished"/> 6627 <translation>Gebruikersnaam is al in gebruik of niet geldig. Kies een andere.</translation>
6603 </message> 6628 </message>
6604 <message> 6629 <message>
6605 <location filename="../../src/yuzu/multiplayer/message.cpp" line="17"/> 6630 <location filename="../../src/yuzu/multiplayer/message.cpp" line="17"/>
6606 <source>IP is not a valid IPv4 address.</source> 6631 <source>IP is not a valid IPv4 address.</source>
6607 <translation type="unfinished"/> 6632 <translation>IP is geen geldig IPv4-adres.</translation>
6608 </message> 6633 </message>
6609 <message> 6634 <message>
6610 <location filename="../../src/yuzu/multiplayer/message.cpp" line="19"/> 6635 <location filename="../../src/yuzu/multiplayer/message.cpp" line="19"/>
6611 <source>Port must be a number between 0 to 65535.</source> 6636 <source>Port must be a number between 0 to 65535.</source>
6612 <translation type="unfinished"/> 6637 <translation>De poort moet een getal zijn tussen 0 en 65535.</translation>
6613 </message> 6638 </message>
6614 <message> 6639 <message>
6615 <location filename="../../src/yuzu/multiplayer/message.cpp" line="20"/> 6640 <location filename="../../src/yuzu/multiplayer/message.cpp" line="20"/>
6616 <source>You must choose a Preferred Game to host a room. If you do not have any games in your game list yet, add a game folder by clicking on the plus icon in the game list.</source> 6641 <source>You must choose a Preferred Game to host a room. If you do not have any games in your game list yet, add a game folder by clicking on the plus icon in the game list.</source>
6617 <translation type="unfinished"/> 6642 <translation>Je moet een Voorkeursspel kiezen om een kamer te hosten. Als je nog geen spellen in je spellenlijst hebt, voeg dan een spellenmap toe door op het plus-icoon in de spellenlijst te klikken.</translation>
6618 </message> 6643 </message>
6619 <message> 6644 <message>
6620 <location filename="../../src/yuzu/multiplayer/message.cpp" line="24"/> 6645 <location filename="../../src/yuzu/multiplayer/message.cpp" line="24"/>
6621 <source>Unable to find an internet connection. Check your internet settings.</source> 6646 <source>Unable to find an internet connection. Check your internet settings.</source>
6622 <translation type="unfinished"/> 6647 <translation>Kan geen internetverbinding vinden. Controleer je Internetinstellingen.</translation>
6623 </message> 6648 </message>
6624 <message> 6649 <message>
6625 <location filename="../../src/yuzu/multiplayer/message.cpp" line="26"/> 6650 <location filename="../../src/yuzu/multiplayer/message.cpp" line="26"/>
6626 <source>Unable to connect to the host. Verify that the connection settings are correct. If you still cannot connect, contact the room host and verify that the host is properly configured with the external port forwarded.</source> 6651 <source>Unable to connect to the host. Verify that the connection settings are correct. If you still cannot connect, contact the room host and verify that the host is properly configured with the external port forwarded.</source>
6627 <translation type="unfinished"/> 6652 <translation>Kan geen verbinding maken met de host. Controleer of de verbindingsinstellingen correct zijn. Als je nog steeds geen verbinding kunt maken, neem dan contact op met de ruimtehost en controleer of de host correct is geconfigureerd met de externe poort doorgestuurd.</translation>
6628 </message> 6653 </message>
6629 <message> 6654 <message>
6630 <location filename="../../src/yuzu/multiplayer/message.cpp" line="30"/> 6655 <location filename="../../src/yuzu/multiplayer/message.cpp" line="30"/>
6631 <source>Unable to connect to the room because it is already full.</source> 6656 <source>Unable to connect to the room because it is already full.</source>
6632 <translation type="unfinished"/> 6657 <translation>Kan geen verbinding maken met de kamer omdat deze al vol is.</translation>
6633 </message> 6658 </message>
6634 <message> 6659 <message>
6635 <location filename="../../src/yuzu/multiplayer/message.cpp" line="32"/> 6660 <location filename="../../src/yuzu/multiplayer/message.cpp" line="32"/>
6636 <source>Creating a room failed. Please retry. Restarting yuzu might be necessary.</source> 6661 <source>Creating a room failed. Please retry. Restarting yuzu might be necessary.</source>
6637 <translation type="unfinished"/> 6662 <translation>Het aanmaken van een kamer is mislukt. Probeer het opnieuw. Het herstarten van yuzu kan nodig zijn.</translation>
6638 </message> 6663 </message>
6639 <message> 6664 <message>
6640 <location filename="../../src/yuzu/multiplayer/message.cpp" line="34"/> 6665 <location filename="../../src/yuzu/multiplayer/message.cpp" line="34"/>
6641 <source>The host of the room has banned you. Speak with the host to unban you or try a different room.</source> 6666 <source>The host of the room has banned you. Speak with the host to unban you or try a different room.</source>
6642 <translation type="unfinished"/> 6667 <translation>De host van de kamer heeft je verbannen. Praat met de host om je ban op te heffen of probeer een andere kamer.</translation>
6643 </message> 6668 </message>
6644 <message> 6669 <message>
6645 <location filename="../../src/yuzu/multiplayer/message.cpp" line="37"/> 6670 <location filename="../../src/yuzu/multiplayer/message.cpp" line="37"/>
6646 <source>Version mismatch! Please update to the latest version of yuzu. If the problem persists, contact the room host and ask them to update the server.</source> 6671 <source>Version mismatch! Please update to the latest version of yuzu. If the problem persists, contact the room host and ask them to update the server.</source>
6647 <translation type="unfinished"/> 6672 <translation>Versie komt niet overeen! Update naar de laatste versie van yuzu. Als het probleem aanhoudt, neem dan contact op met de room host en vraag hen om de server bij te werken.</translation>
6648 </message> 6673 </message>
6649 <message> 6674 <message>
6650 <location filename="../../src/yuzu/multiplayer/message.cpp" line="39"/> 6675 <location filename="../../src/yuzu/multiplayer/message.cpp" line="39"/>
6651 <source>Incorrect password.</source> 6676 <source>Incorrect password.</source>
6652 <translation type="unfinished"/> 6677 <translation>Verkeerd wachtwoord.</translation>
6653 </message> 6678 </message>
6654 <message> 6679 <message>
6655 <location filename="../../src/yuzu/multiplayer/message.cpp" line="40"/> 6680 <location filename="../../src/yuzu/multiplayer/message.cpp" line="40"/>
6656 <source>An unknown error occurred. If this error continues to occur, please open an issue</source> 6681 <source>An unknown error occurred. If this error continues to occur, please open an issue</source>
6657 <translation type="unfinished"/> 6682 <translation>Er is een onbekende fout opgetreden. Als deze fout zich blijft voordoen, open dan een ticket</translation>
6658 </message> 6683 </message>
6659 <message> 6684 <message>
6660 <location filename="../../src/yuzu/multiplayer/message.cpp" line="43"/> 6685 <location filename="../../src/yuzu/multiplayer/message.cpp" line="43"/>
6661 <source>Connection to room lost. Try to reconnect.</source> 6686 <source>Connection to room lost. Try to reconnect.</source>
6662 <translation type="unfinished"/> 6687 <translation>Verbinding met kamer verloren. Probeer opnieuw verbinding te maken.</translation>
6663 </message> 6688 </message>
6664 <message> 6689 <message>
6665 <location filename="../../src/yuzu/multiplayer/message.cpp" line="45"/> 6690 <location filename="../../src/yuzu/multiplayer/message.cpp" line="45"/>
6666 <source>You have been kicked by the room host.</source> 6691 <source>You have been kicked by the room host.</source>
6667 <translation type="unfinished"/> 6692 <translation>Je bent gekickt door de kamerhost.</translation>
6668 </message> 6693 </message>
6669 <message> 6694 <message>
6670 <location filename="../../src/yuzu/multiplayer/message.cpp" line="47"/> 6695 <location filename="../../src/yuzu/multiplayer/message.cpp" line="47"/>
6671 <source>IP address is already in use. Please choose another.</source> 6696 <source>IP address is already in use. Please choose another.</source>
6672 <translation type="unfinished"/> 6697 <translation>Het IP-adres is al in gebruik. Kies een ander.</translation>
6673 </message> 6698 </message>
6674 <message> 6699 <message>
6675 <location filename="../../src/yuzu/multiplayer/message.cpp" line="49"/> 6700 <location filename="../../src/yuzu/multiplayer/message.cpp" line="49"/>
6676 <source>You do not have enough permission to perform this action.</source> 6701 <source>You do not have enough permission to perform this action.</source>
6677 <translation type="unfinished"/> 6702 <translation>Je hebt niet genoeg rechten om deze actie uit te voeren.</translation>
6678 </message> 6703 </message>
6679 <message> 6704 <message>
6680 <location filename="../../src/yuzu/multiplayer/message.cpp" line="50"/> 6705 <location filename="../../src/yuzu/multiplayer/message.cpp" line="50"/>
6681 <source>The user you are trying to kick/ban could not be found. 6706 <source>The user you are trying to kick/ban could not be found.
6682They may have left the room.</source> 6707They may have left the room.</source>
6683 <translation type="unfinished"/> 6708 <translation>De gebruiker die je probeert te kicken/bannen kon niet gevonden worden.
6709Ze kunnen de ruimte hebben verlaten.</translation>
6684 </message> 6710 </message>
6685 <message> 6711 <message>
6686 <location filename="../../src/yuzu/multiplayer/message.cpp" line="52"/> 6712 <location filename="../../src/yuzu/multiplayer/message.cpp" line="52"/>
6687 <source>No valid network interface is selected. 6713 <source>No valid network interface is selected.
6688Please go to Configure -&gt; System -&gt; Network and make a selection.</source> 6714Please go to Configure -&gt; System -&gt; Network and make a selection.</source>
6689 <translation type="unfinished"/> 6715 <translation>Er is geen geldige netwerkinterface geselecteerd.
6716Ga naar Configuratie -&gt; Systeem -&gt; Netwerk en maak een selectie.</translation>
6690 </message> 6717 </message>
6691 <message> 6718 <message>
6692 <location filename="../../src/yuzu/multiplayer/message.cpp" line="68"/> 6719 <location filename="../../src/yuzu/multiplayer/message.cpp" line="68"/>
6693 <source>Game already running</source> 6720 <source>Game already running</source>
6694 <translation type="unfinished"/> 6721 <translation>Het spel draait al</translation>
6695 </message> 6722 </message>
6696 <message> 6723 <message>
6697 <location filename="../../src/yuzu/multiplayer/message.cpp" line="69"/> 6724 <location filename="../../src/yuzu/multiplayer/message.cpp" line="69"/>
6698 <source>Joining a room when the game is already running is discouraged and can cause the room feature not to work correctly. 6725 <source>Joining a room when the game is already running is discouraged and can cause the room feature not to work correctly.
6699Proceed anyway?</source> 6726Proceed anyway?</source>
6700 <translation type="unfinished"/> 6727 <translation>Het wordt afgeraden om aan een kamer deel te nemen als het spel al bezig is en kan ervoor zorgen dat de kamerfunctie niet correct werkt.
6728Toch doorgaan?</translation>
6701 </message> 6729 </message>
6702 <message> 6730 <message>
6703 <location filename="../../src/yuzu/multiplayer/message.cpp" line="75"/> 6731 <location filename="../../src/yuzu/multiplayer/message.cpp" line="75"/>
6704 <source>Leave Room</source> 6732 <source>Leave Room</source>
6705 <translation type="unfinished"/> 6733 <translation>Verlaat Kamer</translation>
6706 </message> 6734 </message>
6707 <message> 6735 <message>
6708 <location filename="../../src/yuzu/multiplayer/message.cpp" line="76"/> 6736 <location filename="../../src/yuzu/multiplayer/message.cpp" line="76"/>
6709 <source>You are about to close the room. Any network connections will be closed.</source> 6737 <source>You are about to close the room. Any network connections will be closed.</source>
6710 <translation type="unfinished"/> 6738 <translation>Je staat op het punt de kamer te sluiten. Alle netwerkverbindingen worden afgesloten.</translation>
6711 </message> 6739 </message>
6712 <message> 6740 <message>
6713 <location filename="../../src/yuzu/multiplayer/message.cpp" line="81"/> 6741 <location filename="../../src/yuzu/multiplayer/message.cpp" line="81"/>
6714 <source>Disconnect</source> 6742 <source>Disconnect</source>
6715 <translation type="unfinished"/> 6743 <translation>Verbinding Verbreken</translation>
6716 </message> 6744 </message>
6717 <message> 6745 <message>
6718 <location filename="../../src/yuzu/multiplayer/message.cpp" line="82"/> 6746 <location filename="../../src/yuzu/multiplayer/message.cpp" line="82"/>
6719 <source>You are about to leave the room. Any network connections will be closed.</source> 6747 <source>You are about to leave the room. Any network connections will be closed.</source>
6720 <translation type="unfinished"/> 6748 <translation>Je staat op het punt de kamer te verlaten. Alle netwerkverbindingen worden afgesloten.</translation>
6721 </message> 6749 </message>
6722</context> 6750</context>
6723<context> 6751<context>
@@ -6725,7 +6753,7 @@ Proceed anyway?</source>
6725 <message> 6753 <message>
6726 <location filename="../../src/yuzu/multiplayer/message.cpp" line="63"/> 6754 <location filename="../../src/yuzu/multiplayer/message.cpp" line="63"/>
6727 <source>Error</source> 6755 <source>Error</source>
6728 <translation type="unfinished"/> 6756 <translation>Fout</translation>
6729 </message> 6757 </message>
6730</context> 6758</context>
6731<context> 6759<context>
@@ -6754,7 +6782,11 @@ Proceed anyway?</source>
6754p, li { white-space: pre-wrap; } 6782p, li { white-space: pre-wrap; }
6755&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;&quot;&gt; 6783&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;&quot;&gt;
6756&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 6784&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
6757 <translation type="unfinished"/> 6785 <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
6786&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
6787p, li { white-space: pre-wrap; }
6788&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:18pt; font-weight:400; font-style:normal;&quot;&gt;
6789&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
6758 </message> 6790 </message>
6759</context> 6791</context>
6760<context> 6792<context>
@@ -6762,7 +6794,7 @@ p, li { white-space: pre-wrap; }
6762 <message> 6794 <message>
6763 <location filename="../../src/yuzu/configuration/configure_input_player_widget.cpp" line="1579"/> 6795 <location filename="../../src/yuzu/configuration/configure_input_player_widget.cpp" line="1579"/>
6764 <source>START/PAUSE</source> 6796 <source>START/PAUSE</source>
6765 <translation type="unfinished"/> 6797 <translation>START/ONDERBREKEN</translation>
6766 </message> 6798 </message>
6767</context> 6799</context>
6768<context> 6800<context>
@@ -6770,42 +6802,42 @@ p, li { white-space: pre-wrap; }
6770 <message> 6802 <message>
6771 <location filename="../../src/yuzu/multiplayer/lobby_p.h" line="236"/> 6803 <location filename="../../src/yuzu/multiplayer/lobby_p.h" line="236"/>
6772 <source>%1 is not playing a game</source> 6804 <source>%1 is not playing a game</source>
6773 <translation type="unfinished"/> 6805 <translation>%1 speelt geen spel</translation>
6774 </message> 6806 </message>
6775 <message> 6807 <message>
6776 <location filename="../../src/yuzu/multiplayer/lobby_p.h" line="238"/> 6808 <location filename="../../src/yuzu/multiplayer/lobby_p.h" line="238"/>
6777 <source>%1 is playing %2</source> 6809 <source>%1 is playing %2</source>
6778 <translation type="unfinished"/> 6810 <translation>%1 speelt %2</translation>
6779 </message> 6811 </message>
6780 <message> 6812 <message>
6781 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="142"/> 6813 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="142"/>
6782 <source>Not playing a game</source> 6814 <source>Not playing a game</source>
6783 <translation type="unfinished"/> 6815 <translation>Geen spel aan het spelen</translation>
6784 </message> 6816 </message>
6785 <message> 6817 <message>
6786 <location filename="../../src/yuzu/game_list_p.h" line="244"/> 6818 <location filename="../../src/yuzu/game_list_p.h" line="244"/>
6787 <source>Installed SD Titles</source> 6819 <source>Installed SD Titles</source>
6788 <translation>Geïnstalleerde SD Titels</translation> 6820 <translation>Geïnstalleerde SD-titels</translation>
6789 </message> 6821 </message>
6790 <message> 6822 <message>
6791 <location filename="../../src/yuzu/game_list_p.h" line="252"/> 6823 <location filename="../../src/yuzu/game_list_p.h" line="252"/>
6792 <source>Installed NAND Titles</source> 6824 <source>Installed NAND Titles</source>
6793 <translation>Geïnstalleerde NAND Titels</translation> 6825 <translation>Geïnstalleerde NAND-titels</translation>
6794 </message> 6826 </message>
6795 <message> 6827 <message>
6796 <location filename="../../src/yuzu/game_list_p.h" line="260"/> 6828 <location filename="../../src/yuzu/game_list_p.h" line="260"/>
6797 <source>System Titles</source> 6829 <source>System Titles</source>
6798 <translation>Systeem Titels</translation> 6830 <translation>Systeemtitels</translation>
6799 </message> 6831 </message>
6800 <message> 6832 <message>
6801 <location filename="../../src/yuzu/game_list_p.h" line="303"/> 6833 <location filename="../../src/yuzu/game_list_p.h" line="303"/>
6802 <source>Add New Game Directory</source> 6834 <source>Add New Game Directory</source>
6803 <translation>Voeg Nieuwe Game Map Toe</translation> 6835 <translation>Voeg Nieuwe Spelmap Toe</translation>
6804 </message> 6836 </message>
6805 <message> 6837 <message>
6806 <location filename="../../src/yuzu/game_list_p.h" line="326"/> 6838 <location filename="../../src/yuzu/game_list_p.h" line="326"/>
6807 <source>Favorites</source> 6839 <source>Favorites</source>
6808 <translation type="unfinished"/> 6840 <translation>Favorieten</translation>
6809 </message> 6841 </message>
6810 <message> 6842 <message>
6811 <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="21"/> 6843 <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="21"/>
@@ -6876,28 +6908,28 @@ p, li { white-space: pre-wrap; }
6876 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="56"/> 6908 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="56"/>
6877 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="144"/> 6909 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="144"/>
6878 <source>Left</source> 6910 <source>Left</source>
6879 <translation>Links:</translation> 6911 <translation>Links</translation>
6880 </message> 6912 </message>
6881 <message> 6913 <message>
6882 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="49"/> 6914 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="49"/>
6883 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="58"/> 6915 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="58"/>
6884 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/> 6916 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="147"/>
6885 <source>Right</source> 6917 <source>Right</source>
6886 <translation>Rechts:</translation> 6918 <translation>Rechts</translation>
6887 </message> 6919 </message>
6888 <message> 6920 <message>
6889 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="51"/> 6921 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="51"/>
6890 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="60"/> 6922 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="60"/>
6891 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="153"/> 6923 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="153"/>
6892 <source>Down</source> 6924 <source>Down</source>
6893 <translation>Beneden:</translation> 6925 <translation>Omlaag</translation>
6894 </message> 6926 </message>
6895 <message> 6927 <message>
6896 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="53"/> 6928 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="53"/>
6897 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="62"/> 6929 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="62"/>
6898 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="150"/> 6930 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="150"/>
6899 <source>Up</source> 6931 <source>Up</source>
6900 <translation>Boven:</translation> 6932 <translation>Omhoog</translation>
6901 </message> 6933 </message>
6902 <message> 6934 <message>
6903 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="55"/> 6935 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="55"/>
@@ -6909,7 +6941,7 @@ p, li { white-space: pre-wrap; }
6909 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="57"/> 6941 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="57"/>
6910 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="66"/> 6942 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="66"/>
6911 <source>R</source> 6943 <source>R</source>
6912 <translation>R:</translation> 6944 <translation>R</translation>
6913 </message> 6945 </message>
6914 <message> 6946 <message>
6915 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="59"/> 6947 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="59"/>
@@ -6951,79 +6983,79 @@ p, li { white-space: pre-wrap; }
6951 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="71"/> 6983 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="71"/>
6952 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/> 6984 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/>
6953 <source>L1</source> 6985 <source>L1</source>
6954 <translation type="unfinished"/> 6986 <translation>L1</translation>
6955 </message> 6987 </message>
6956 <message> 6988 <message>
6957 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="73"/> 6989 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="73"/>
6958 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/> 6990 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/>
6959 <source>L2</source> 6991 <source>L2</source>
6960 <translation type="unfinished"/> 6992 <translation>L2</translation>
6961 </message> 6993 </message>
6962 <message> 6994 <message>
6963 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="75"/> 6995 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="75"/>
6964 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/> 6996 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/>
6965 <source>L3</source> 6997 <source>L3</source>
6966 <translation type="unfinished"/> 6998 <translation>L3</translation>
6967 </message> 6999 </message>
6968 <message> 7000 <message>
6969 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="77"/> 7001 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="77"/>
6970 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="106"/> 7002 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="106"/>
6971 <source>R1</source> 7003 <source>R1</source>
6972 <translation type="unfinished"/> 7004 <translation>R1</translation>
6973 </message> 7005 </message>
6974 <message> 7006 <message>
6975 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="79"/> 7007 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="79"/>
6976 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="108"/> 7008 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="108"/>
6977 <source>R2</source> 7009 <source>R2</source>
6978 <translation type="unfinished"/> 7010 <translation>R2</translation>
6979 </message> 7011 </message>
6980 <message> 7012 <message>
6981 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="81"/> 7013 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="81"/>
6982 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="110"/> 7014 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="110"/>
6983 <source>R3</source> 7015 <source>R3</source>
6984 <translation type="unfinished"/> 7016 <translation>R3</translation>
6985 </message> 7017 </message>
6986 <message> 7018 <message>
6987 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="83"/> 7019 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="83"/>
6988 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="112"/> 7020 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="112"/>
6989 <source>Circle</source> 7021 <source>Circle</source>
6990 <translation type="unfinished"/> 7022 <translation>Cirkel</translation>
6991 </message> 7023 </message>
6992 <message> 7024 <message>
6993 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="85"/> 7025 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="85"/>
6994 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="114"/> 7026 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="114"/>
6995 <source>Cross</source> 7027 <source>Cross</source>
6996 <translation type="unfinished"/> 7028 <translation>Kruis</translation>
6997 </message> 7029 </message>
6998 <message> 7030 <message>
6999 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="87"/> 7031 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="87"/>
7000 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="116"/> 7032 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="116"/>
7001 <source>Square</source> 7033 <source>Square</source>
7002 <translation type="unfinished"/> 7034 <translation>Vierkant</translation>
7003 </message> 7035 </message>
7004 <message> 7036 <message>
7005 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="89"/> 7037 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="89"/>
7006 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="118"/> 7038 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="118"/>
7007 <source>Triangle</source> 7039 <source>Triangle</source>
7008 <translation type="unfinished"/> 7040 <translation>Driehoek</translation>
7009 </message> 7041 </message>
7010 <message> 7042 <message>
7011 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="91"/> 7043 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="91"/>
7012 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="120"/> 7044 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="120"/>
7013 <source>Share</source> 7045 <source>Share</source>
7014 <translation type="unfinished"/> 7046 <translation>Deel</translation>
7015 </message> 7047 </message>
7016 <message> 7048 <message>
7017 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="93"/> 7049 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="93"/>
7018 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="122"/> 7050 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="122"/>
7019 <source>Options</source> 7051 <source>Options</source>
7020 <translation type="unfinished"/> 7052 <translation>Opties</translation>
7021 </message> 7053 </message>
7022 <message> 7054 <message>
7023 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="95"/> 7055 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="95"/>
7024 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="138"/> 7056 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="138"/>
7025 <source>[undefined]</source> 7057 <source>[undefined]</source>
7026 <translation type="unfinished"/> 7058 <translation>[ongedefinieerd]</translation>
7027 </message> 7059 </message>
7028 <message> 7060 <message>
7029 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="399"/> 7061 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="399"/>
@@ -7034,13 +7066,13 @@ p, li { white-space: pre-wrap; }
7034 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="403"/> 7066 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="403"/>
7035 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="195"/> 7067 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="195"/>
7036 <source>[invalid]</source> 7068 <source>[invalid]</source>
7037 <translation type="unfinished"/> 7069 <translation>[ongeldig]</translation>
7038 </message> 7070 </message>
7039 <message> 7071 <message>
7040 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="413"/> 7072 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="413"/>
7041 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="437"/> 7073 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="437"/>
7042 <source>%1%2Hat %3</source> 7074 <source>%1%2Hat %3</source>
7043 <translation type="unfinished"/> 7075 <translation>%1%2Hat %3</translation>
7044 </message> 7076 </message>
7045 <message> 7077 <message>
7046 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="417"/> 7078 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="417"/>
@@ -7050,25 +7082,25 @@ p, li { white-space: pre-wrap; }
7050 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="232"/> 7082 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="232"/>
7051 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="235"/> 7083 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="235"/>
7052 <source>%1%2Axis %3</source> 7084 <source>%1%2Axis %3</source>
7053 <translation type="unfinished"/> 7085 <translation>%1%2As %3</translation>
7054 </message> 7086 </message>
7055 <message> 7087 <message>
7056 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="423"/> 7088 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="423"/>
7057 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="215"/> 7089 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="215"/>
7058 <source>%1%2Axis %3,%4,%5</source> 7090 <source>%1%2Axis %3,%4,%5</source>
7059 <translation type="unfinished"/> 7091 <translation>%1%2As %3,%4,%5</translation>
7060 </message> 7092 </message>
7061 <message> 7093 <message>
7062 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="427"/> 7094 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="427"/>
7063 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="219"/> 7095 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="219"/>
7064 <source>%1%2Motion %3</source> 7096 <source>%1%2Motion %3</source>
7065 <translation type="unfinished"/> 7097 <translation>%1%2Beweging %3</translation>
7066 </message> 7098 </message>
7067 <message> 7099 <message>
7068 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="431"/> 7100 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="431"/>
7069 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="446"/> 7101 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="446"/>
7070 <source>%1%2Button %3</source> 7102 <source>%1%2Button %3</source>
7071 <translation type="unfinished"/> 7103 <translation>%1%2Knop %3</translation>
7072 </message> 7104 </message>
7073 <message> 7105 <message>
7074 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="473"/> 7106 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="473"/>
@@ -7099,17 +7131,17 @@ p, li { white-space: pre-wrap; }
7099 <message> 7131 <message>
7100 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="78"/> 7132 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="78"/>
7101 <source>Stick L</source> 7133 <source>Stick L</source>
7102 <translation type="unfinished"/> 7134 <translation>Stick L</translation>
7103 </message> 7135 </message>
7104 <message> 7136 <message>
7105 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="80"/> 7137 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="80"/>
7106 <source>Stick R</source> 7138 <source>Stick R</source>
7107 <translation type="unfinished"/> 7139 <translation>Stick R</translation>
7108 </message> 7140 </message>
7109 <message> 7141 <message>
7110 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/> 7142 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/>
7111 <source>Plus</source> 7143 <source>Plus</source>
7112 <translation>Plus:</translation> 7144 <translation>Plus</translation>
7113 </message> 7145 </message>
7114 <message> 7146 <message>
7115 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/> 7147 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/>
@@ -7120,7 +7152,7 @@ p, li { white-space: pre-wrap; }
7120 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/> 7152 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/>
7121 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="124"/> 7153 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="124"/>
7122 <source>Home</source> 7154 <source>Home</source>
7123 <translation>Home:</translation> 7155 <translation>Home</translation>
7124 </message> 7156 </message>
7125 <message> 7157 <message>
7126 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/> 7158 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/>
@@ -7136,44 +7168,44 @@ p, li { white-space: pre-wrap; }
7136 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="128"/> 7168 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="128"/>
7137 <source>Wheel</source> 7169 <source>Wheel</source>
7138 <comment>Indicates the mouse wheel</comment> 7170 <comment>Indicates the mouse wheel</comment>
7139 <translation type="unfinished"/> 7171 <translation>Wiel</translation>
7140 </message> 7172 </message>
7141 <message> 7173 <message>
7142 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="130"/> 7174 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="130"/>
7143 <source>Backward</source> 7175 <source>Backward</source>
7144 <translation type="unfinished"/> 7176 <translation>Achteruit</translation>
7145 </message> 7177 </message>
7146 <message> 7178 <message>
7147 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="132"/> 7179 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="132"/>
7148 <source>Forward</source> 7180 <source>Forward</source>
7149 <translation type="unfinished"/> 7181 <translation>Vooruit</translation>
7150 </message> 7182 </message>
7151 <message> 7183 <message>
7152 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="134"/> 7184 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="134"/>
7153 <source>Task</source> 7185 <source>Task</source>
7154 <translation type="unfinished"/> 7186 <translation>Taak</translation>
7155 </message> 7187 </message>
7156 <message> 7188 <message>
7157 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="136"/> 7189 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="136"/>
7158 <source>Extra</source> 7190 <source>Extra</source>
7159 <translation type="unfinished"/> 7191 <translation>Extra</translation>
7160 </message> 7192 </message>
7161 <message> 7193 <message>
7162 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="191"/> 7194 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="191"/>
7163 <source>%1%2%3%4</source> 7195 <source>%1%2%3%4</source>
7164 <translation type="unfinished"/> 7196 <translation>%1%2%3%4</translation>
7165 </message> 7197 </message>
7166 <message> 7198 <message>
7167 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="205"/> 7199 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="205"/>
7168 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="229"/> 7200 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="229"/>
7169 <source>%1%2%3Hat %4</source> 7201 <source>%1%2%3Hat %4</source>
7170 <translation type="unfinished"/> 7202 <translation>%1%2%3Hat %4</translation>
7171 </message> 7203 </message>
7172 <message> 7204 <message>
7173 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="223"/> 7205 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="223"/>
7174 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="238"/> 7206 <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="238"/>
7175 <source>%1%2%3Button %4</source> 7207 <source>%1%2%3Button %4</source>
7176 <translation type="unfinished"/> 7208 <translation>%1%2%3Knop %4</translation>
7177 </message> 7209 </message>
7178</context> 7210</context>
7179<context> 7211<context>
@@ -7181,22 +7213,22 @@ p, li { white-space: pre-wrap; }
7181 <message> 7213 <message>
7182 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="14"/> 7214 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="14"/>
7183 <source>Amiibo Settings</source> 7215 <source>Amiibo Settings</source>
7184 <translation type="unfinished"/> 7216 <translation>Amiibo-instellingen</translation>
7185 </message> 7217 </message>
7186 <message> 7218 <message>
7187 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="169"/> 7219 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="169"/>
7188 <source>Amiibo Info</source> 7220 <source>Amiibo Info</source>
7189 <translation type="unfinished"/> 7221 <translation>Amiibo-info</translation>
7190 </message> 7222 </message>
7191 <message> 7223 <message>
7192 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="177"/> 7224 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="177"/>
7193 <source>Series</source> 7225 <source>Series</source>
7194 <translation type="unfinished"/> 7226 <translation>Serie</translation>
7195 </message> 7227 </message>
7196 <message> 7228 <message>
7197 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="197"/> 7229 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="197"/>
7198 <source>Type</source> 7230 <source>Type</source>
7199 <translation type="unfinished"/> 7231 <translation>Soort</translation>
7200 </message> 7232 </message>
7201 <message> 7233 <message>
7202 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="217"/> 7234 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="217"/>
@@ -7206,52 +7238,52 @@ p, li { white-space: pre-wrap; }
7206 <message> 7238 <message>
7207 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="242"/> 7239 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="242"/>
7208 <source>Amiibo Data</source> 7240 <source>Amiibo Data</source>
7209 <translation type="unfinished"/> 7241 <translation>Amiibo-gegevens</translation>
7210 </message> 7242 </message>
7211 <message> 7243 <message>
7212 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="250"/> 7244 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="250"/>
7213 <source>Custom Name</source> 7245 <source>Custom Name</source>
7214 <translation type="unfinished"/> 7246 <translation>Aangepaste Naam</translation>
7215 </message> 7247 </message>
7216 <message> 7248 <message>
7217 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="270"/> 7249 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="270"/>
7218 <source>Owner</source> 7250 <source>Owner</source>
7219 <translation type="unfinished"/> 7251 <translation>Eigenaar</translation>
7220 </message> 7252 </message>
7221 <message> 7253 <message>
7222 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="290"/> 7254 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="290"/>
7223 <source>Creation Date</source> 7255 <source>Creation Date</source>
7224 <translation type="unfinished"/> 7256 <translation>Aanmaakdatum</translation>
7225 </message> 7257 </message>
7226 <message> 7258 <message>
7227 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="307"/> 7259 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="307"/>
7228 <source>dd/MM/yyyy</source> 7260 <source>dd/MM/yyyy</source>
7229 <translation type="unfinished"/> 7261 <translation>dd/MM/yyyy</translation>
7230 </message> 7262 </message>
7231 <message> 7263 <message>
7232 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="314"/> 7264 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="314"/>
7233 <source>Modification Date</source> 7265 <source>Modification Date</source>
7234 <translation type="unfinished"/> 7266 <translation>Modificatiedatum</translation>
7235 </message> 7267 </message>
7236 <message> 7268 <message>
7237 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="331"/> 7269 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="331"/>
7238 <source>dd/MM/yyyy </source> 7270 <source>dd/MM/yyyy </source>
7239 <translation type="unfinished"/> 7271 <translation>dd/MM/yyyy </translation>
7240 </message> 7272 </message>
7241 <message> 7273 <message>
7242 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="349"/> 7274 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="349"/>
7243 <source>Game Data</source> 7275 <source>Game Data</source>
7244 <translation type="unfinished"/> 7276 <translation>Spelgegevens</translation>
7245 </message> 7277 </message>
7246 <message> 7278 <message>
7247 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="355"/> 7279 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="355"/>
7248 <source>Game Id</source> 7280 <source>Game Id</source>
7249 <translation type="unfinished"/> 7281 <translation>Spel-ID</translation>
7250 </message> 7282 </message>
7251 <message> 7283 <message>
7252 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="384"/> 7284 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="384"/>
7253 <source>Mount Amiibo</source> 7285 <source>Mount Amiibo</source>
7254 <translation type="unfinished"/> 7286 <translation>Gebruik Amiibo</translation>
7255 </message> 7287 </message>
7256 <message> 7288 <message>
7257 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="390"/> 7289 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="390"/>
@@ -7261,32 +7293,32 @@ p, li { white-space: pre-wrap; }
7261 <message> 7293 <message>
7262 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="413"/> 7294 <location filename="../../src/yuzu/applets/qt_amiibo_settings.ui" line="413"/>
7263 <source>File Path</source> 7295 <source>File Path</source>
7264 <translation type="unfinished"/> 7296 <translation>Bestandspad</translation>
7265 </message> 7297 </message>
7266 <message> 7298 <message>
7267 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="191"/> 7299 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="191"/>
7268 <source>No game data present</source> 7300 <source>No game data present</source>
7269 <translation type="unfinished"/> 7301 <translation>Geen spelgegevens aanwezig</translation>
7270 </message> 7302 </message>
7271 <message> 7303 <message>
7272 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="231"/> 7304 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="231"/>
7273 <source>The following amiibo data will be formatted:</source> 7305 <source>The following amiibo data will be formatted:</source>
7274 <translation type="unfinished"/> 7306 <translation>De volgende amiibo-gegevens worden zo geformatteerd:</translation>
7275 </message> 7307 </message>
7276 <message> 7308 <message>
7277 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="234"/> 7309 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="234"/>
7278 <source>The following game data will removed:</source> 7310 <source>The following game data will removed:</source>
7279 <translation type="unfinished"/> 7311 <translation>De volgende spelgegevens worden verwijderd:</translation>
7280 </message> 7312 </message>
7281 <message> 7313 <message>
7282 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="237"/> 7314 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="237"/>
7283 <source>Set nickname and owner:</source> 7315 <source>Set nickname and owner:</source>
7284 <translation type="unfinished"/> 7316 <translation>Stel gebruikersnaam en eigenaar in:</translation>
7285 </message> 7317 </message>
7286 <message> 7318 <message>
7287 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="240"/> 7319 <location filename="../../src/yuzu/applets/qt_amiibo_settings.cpp" line="240"/>
7288 <source>Do you wish to restore this amiibo?</source> 7320 <source>Do you wish to restore this amiibo?</source>
7289 <translation type="unfinished"/> 7321 <translation>Wil je deze amiibo herstellen?</translation>
7290 </message> 7322 </message>
7291</context> 7323</context>
7292<context> 7324<context>
@@ -7294,27 +7326,27 @@ p, li { white-space: pre-wrap; }
7294 <message> 7326 <message>
7295 <location filename="../../src/yuzu/applets/qt_controller.ui" line="14"/> 7327 <location filename="../../src/yuzu/applets/qt_controller.ui" line="14"/>
7296 <source>Controller Applet</source> 7328 <source>Controller Applet</source>
7297 <translation type="unfinished"/> 7329 <translation>Controller Applet</translation>
7298 </message> 7330 </message>
7299 <message> 7331 <message>
7300 <location filename="../../src/yuzu/applets/qt_controller.ui" line="129"/> 7332 <location filename="../../src/yuzu/applets/qt_controller.ui" line="129"/>
7301 <source>Supported Controller Types:</source> 7333 <source>Supported Controller Types:</source>
7302 <translation type="unfinished"/> 7334 <translation>Ondersteunde Controller-typen:</translation>
7303 </message> 7335 </message>
7304 <message> 7336 <message>
7305 <location filename="../../src/yuzu/applets/qt_controller.ui" line="282"/> 7337 <location filename="../../src/yuzu/applets/qt_controller.ui" line="282"/>
7306 <source>Players:</source> 7338 <source>Players:</source>
7307 <translation type="unfinished"/> 7339 <translation>Spelers:</translation>
7308 </message> 7340 </message>
7309 <message> 7341 <message>
7310 <location filename="../../src/yuzu/applets/qt_controller.ui" line="300"/> 7342 <location filename="../../src/yuzu/applets/qt_controller.ui" line="300"/>
7311 <source>1 - 8</source> 7343 <source>1 - 8</source>
7312 <translation type="unfinished"/> 7344 <translation>1 - 8</translation>
7313 </message> 7345 </message>
7314 <message> 7346 <message>
7315 <location filename="../../src/yuzu/applets/qt_controller.ui" line="418"/> 7347 <location filename="../../src/yuzu/applets/qt_controller.ui" line="418"/>
7316 <source>P4</source> 7348 <source>P4</source>
7317 <translation type="unfinished"/> 7349 <translation>P4</translation>
7318 </message> 7350 </message>
7319 <message> 7351 <message>
7320 <location filename="../../src/yuzu/applets/qt_controller.ui" line="514"/> 7352 <location filename="../../src/yuzu/applets/qt_controller.ui" line="514"/>
@@ -7378,59 +7410,59 @@ p, li { white-space: pre-wrap; }
7378 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1881"/> 7410 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1881"/>
7379 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2078"/> 7411 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2078"/>
7380 <source>Use Current Config</source> 7412 <source>Use Current Config</source>
7381 <translation type="unfinished"/> 7413 <translation>Gebruik Huidige Configuratie</translation>
7382 </message> 7414 </message>
7383 <message> 7415 <message>
7384 <location filename="../../src/yuzu/applets/qt_controller.ui" line="615"/> 7416 <location filename="../../src/yuzu/applets/qt_controller.ui" line="615"/>
7385 <source>P2</source> 7417 <source>P2</source>
7386 <translation type="unfinished"/> 7418 <translation>P2</translation>
7387 </message> 7419 </message>
7388 <message> 7420 <message>
7389 <location filename="../../src/yuzu/applets/qt_controller.ui" line="812"/> 7421 <location filename="../../src/yuzu/applets/qt_controller.ui" line="812"/>
7390 <source>P1</source> 7422 <source>P1</source>
7391 <translation type="unfinished"/> 7423 <translation>P1</translation>
7392 </message> 7424 </message>
7393 <message> 7425 <message>
7394 <location filename="../../src/yuzu/applets/qt_controller.ui" line="932"/> 7426 <location filename="../../src/yuzu/applets/qt_controller.ui" line="932"/>
7395 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2303"/> 7427 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2303"/>
7396 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="430"/> 7428 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="430"/>
7397 <source>Handheld</source> 7429 <source>Handheld</source>
7398 <translation>Mobiel</translation> 7430 <translation>Handheld</translation>
7399 </message> 7431 </message>
7400 <message> 7432 <message>
7401 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1126"/> 7433 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1126"/>
7402 <source>P3</source> 7434 <source>P3</source>
7403 <translation type="unfinished"/> 7435 <translation>P3</translation>
7404 </message> 7436 </message>
7405 <message> 7437 <message>
7406 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1363"/> 7438 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1363"/>
7407 <source>P7</source> 7439 <source>P7</source>
7408 <translation type="unfinished"/> 7440 <translation>P7</translation>
7409 </message> 7441 </message>
7410 <message> 7442 <message>
7411 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1560"/> 7443 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1560"/>
7412 <source>P8</source> 7444 <source>P8</source>
7413 <translation type="unfinished"/> 7445 <translation>P8</translation>
7414 </message> 7446 </message>
7415 <message> 7447 <message>
7416 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1757"/> 7448 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1757"/>
7417 <source>P5</source> 7449 <source>P5</source>
7418 <translation type="unfinished"/> 7450 <translation>P5</translation>
7419 </message> 7451 </message>
7420 <message> 7452 <message>
7421 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1958"/> 7453 <location filename="../../src/yuzu/applets/qt_controller.ui" line="1958"/>
7422 <source>P6</source> 7454 <source>P6</source>
7423 <translation type="unfinished"/> 7455 <translation>P6</translation>
7424 </message> 7456 </message>
7425 <message> 7457 <message>
7426 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2272"/> 7458 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2272"/>
7427 <source>Console Mode</source> 7459 <source>Console Mode</source>
7428 <translation>Console ID:</translation> 7460 <translation>Console-ID:</translation>
7429 </message> 7461 </message>
7430 <message> 7462 <message>
7431 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2293"/> 7463 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2293"/>
7432 <source>Docked</source> 7464 <source>Docked</source>
7433 <translation>GeDocked</translation> 7465 <translation>Docked</translation>
7434 </message> 7466 </message>
7435 <message> 7467 <message>
7436 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2313"/> 7468 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2313"/>
@@ -7456,7 +7488,7 @@ p, li { white-space: pre-wrap; }
7456 <message> 7488 <message>
7457 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2432"/> 7489 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2432"/>
7458 <source>Create</source> 7490 <source>Create</source>
7459 <translation type="unfinished"/> 7491 <translation>Maak</translation>
7460 </message> 7492 </message>
7461 <message> 7493 <message>
7462 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2467"/> 7494 <location filename="../../src/yuzu/applets/qt_controller.ui" line="2467"/>
@@ -7511,32 +7543,32 @@ p, li { white-space: pre-wrap; }
7511 <message> 7543 <message>
7512 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="434"/> 7544 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="434"/>
7513 <source>GameCube Controller</source> 7545 <source>GameCube Controller</source>
7514 <translation>GameCube Controller</translation> 7546 <translation>GameCube-controller</translation>
7515 </message> 7547 </message>
7516 <message> 7548 <message>
7517 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="443"/> 7549 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="443"/>
7518 <source>Poke Ball Plus</source> 7550 <source>Poke Ball Plus</source>
7519 <translation type="unfinished"/> 7551 <translation>Poke Ball Plus</translation>
7520 </message> 7552 </message>
7521 <message> 7553 <message>
7522 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="447"/> 7554 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="447"/>
7523 <source>NES Controller</source> 7555 <source>NES Controller</source>
7524 <translation type="unfinished"/> 7556 <translation>NES-controller</translation>
7525 </message> 7557 </message>
7526 <message> 7558 <message>
7527 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="451"/> 7559 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="451"/>
7528 <source>SNES Controller</source> 7560 <source>SNES Controller</source>
7529 <translation type="unfinished"/> 7561 <translation>SNES-controller</translation>
7530 </message> 7562 </message>
7531 <message> 7563 <message>
7532 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="455"/> 7564 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="455"/>
7533 <source>N64 Controller</source> 7565 <source>N64 Controller</source>
7534 <translation type="unfinished"/> 7566 <translation>N64-controller</translation>
7535 </message> 7567 </message>
7536 <message> 7568 <message>
7537 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="459"/> 7569 <location filename="../../src/yuzu/applets/qt_controller.cpp" line="459"/>
7538 <source>Sega Genesis</source> 7570 <source>Sega Genesis</source>
7539 <translation type="unfinished"/> 7571 <translation>Sega Genesis</translation>
7540 </message> 7572 </message>
7541</context> 7573</context>
7542<context> 7574<context>
@@ -7546,19 +7578,21 @@ p, li { white-space: pre-wrap; }
7546 <location filename="../../src/yuzu/applets/qt_error.cpp" line="40"/> 7578 <location filename="../../src/yuzu/applets/qt_error.cpp" line="40"/>
7547 <location filename="../../src/yuzu/applets/qt_error.cpp" line="55"/> 7579 <location filename="../../src/yuzu/applets/qt_error.cpp" line="55"/>
7548 <source>Error Code: %1-%2 (0x%3)</source> 7580 <source>Error Code: %1-%2 (0x%3)</source>
7549 <translation type="unfinished"/> 7581 <translation>Foutcode: %1-%2 (0x%3)</translation>
7550 </message> 7582 </message>
7551 <message> 7583 <message>
7552 <location filename="../../src/yuzu/applets/qt_error.cpp" line="31"/> 7584 <location filename="../../src/yuzu/applets/qt_error.cpp" line="31"/>
7553 <source>An error has occurred. 7585 <source>An error has occurred.
7554Please try again or contact the developer of the software.</source> 7586Please try again or contact the developer of the software.</source>
7555 <translation type="unfinished"/> 7587 <translation>Er is een fout opgetreden.
7588Probeer het opnieuw of neem contact op met de software-ontwikkelaar.</translation>
7556 </message> 7589 </message>
7557 <message> 7590 <message>
7558 <location filename="../../src/yuzu/applets/qt_error.cpp" line="44"/> 7591 <location filename="../../src/yuzu/applets/qt_error.cpp" line="44"/>
7559 <source>An error occurred on %1 at %2. 7592 <source>An error occurred on %1 at %2.
7560Please try again or contact the developer of the software.</source> 7593Please try again or contact the developer of the software.</source>
7561 <translation type="unfinished"/> 7594 <translation>Er is een fout opgetreden op %1 bij %2.
7595Probeer het opnieuw of neem contact op met de software-ontwikkelaar.</translation>
7562 </message> 7596 </message>
7563 <message> 7597 <message>
7564 <location filename="../../src/yuzu/applets/qt_error.cpp" line="59"/> 7598 <location filename="../../src/yuzu/applets/qt_error.cpp" line="59"/>
@@ -7567,7 +7601,11 @@ Please try again or contact the developer of the software.</source>
7567%1 7601%1
7568 7602
7569%2</source> 7603%2</source>
7570 <translation type="unfinished"/> 7604 <translation>Er is een fout opgetreden.
7605
7606%1
7607
7608%2</translation>
7571 </message> 7609 </message>
7572</context> 7610</context>
7573<context> 7611<context>
@@ -7588,68 +7626,68 @@ Please try again or contact the developer of the software.</source>
7588 <message> 7626 <message>
7589 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/> 7627 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/>
7590 <source>Profile Creator</source> 7628 <source>Profile Creator</source>
7591 <translation type="unfinished"/> 7629 <translation>Profielmaker</translation>
7592 </message> 7630 </message>
7593 <message> 7631 <message>
7594 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/> 7632 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/>
7595 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="187"/> 7633 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="187"/>
7596 <source>Profile Selector</source> 7634 <source>Profile Selector</source>
7597 <translation>Profiel keuzeschakelaar</translation> 7635 <translation>Profielkiezer</translation>
7598 </message> 7636 </message>
7599 <message> 7637 <message>
7600 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/> 7638 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/>
7601 <source>Profile Icon Editor</source> 7639 <source>Profile Icon Editor</source>
7602 <translation type="unfinished"/> 7640 <translation>Profielicoon-editor</translation>
7603 </message> 7641 </message>
7604 <message> 7642 <message>
7605 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/> 7643 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/>
7606 <source>Profile Nickname Editor</source> 7644 <source>Profile Nickname Editor</source>
7607 <translation type="unfinished"/> 7645 <translation>Profielnaam-editor</translation>
7608 </message> 7646 </message>
7609 <message> 7647 <message>
7610 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/> 7648 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/>
7611 <source>Who will receive the points?</source> 7649 <source>Who will receive the points?</source>
7612 <translation type="unfinished"/> 7650 <translation>Wie krijgt de punten?</translation>
7613 </message> 7651 </message>
7614 <message> 7652 <message>
7615 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/> 7653 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/>
7616 <source>Who is using Nintendo eShop?</source> 7654 <source>Who is using Nintendo eShop?</source>
7617 <translation type="unfinished"/> 7655 <translation>Wie gebruikt de Nintendo eShop?</translation>
7618 </message> 7656 </message>
7619 <message> 7657 <message>
7620 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/> 7658 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/>
7621 <source>Who is making this purchase?</source> 7659 <source>Who is making this purchase?</source>
7622 <translation type="unfinished"/> 7660 <translation>Wie doet deze aankoop?</translation>
7623 </message> 7661 </message>
7624 <message> 7662 <message>
7625 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/> 7663 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/>
7626 <source>Who is posting?</source> 7664 <source>Who is posting?</source>
7627 <translation type="unfinished"/> 7665 <translation>Wie post er?</translation>
7628 </message> 7666 </message>
7629 <message> 7667 <message>
7630 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/> 7668 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/>
7631 <source>Select a user to link to a Nintendo Account.</source> 7669 <source>Select a user to link to a Nintendo Account.</source>
7632 <translation type="unfinished"/> 7670 <translation>Selecteer een gebruiker om te koppelen aan een Nintendo-account.</translation>
7633 </message> 7671 </message>
7634 <message> 7672 <message>
7635 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/> 7673 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/>
7636 <source>Change settings for which user?</source> 7674 <source>Change settings for which user?</source>
7637 <translation type="unfinished"/> 7675 <translation>Instellingen wijzigen voor welke gebruiker?</translation>
7638 </message> 7676 </message>
7639 <message> 7677 <message>
7640 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/> 7678 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/>
7641 <source>Format data for which user?</source> 7679 <source>Format data for which user?</source>
7642 <translation type="unfinished"/> 7680 <translation>Formatteer gegevens voor welke gebruiker?</translation>
7643 </message> 7681 </message>
7644 <message> 7682 <message>
7645 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/> 7683 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/>
7646 <source>Which user will be transferred to another console?</source> 7684 <source>Which user will be transferred to another console?</source>
7647 <translation type="unfinished"/> 7685 <translation>Welke gebruiker wordt overgezet naar een andere console?</translation>
7648 </message> 7686 </message>
7649 <message> 7687 <message>
7650 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/> 7688 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/>
7651 <source>Send save data for which user?</source> 7689 <source>Send save data for which user?</source>
7652 <translation type="unfinished"/> 7690 <translation>Gegevens verzenden voor welke gebruiker?</translation>
7653 </message> 7691 </message>
7654 <message> 7692 <message>
7655 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/> 7693 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/>
@@ -7662,12 +7700,12 @@ Please try again or contact the developer of the software.</source>
7662 <message> 7700 <message>
7663 <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="14"/> 7701 <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="14"/>
7664 <source>Software Keyboard</source> 7702 <source>Software Keyboard</source>
7665 <translation>Software Toetsenbord</translation> 7703 <translation>Softwaretoetsenbord</translation>
7666 </message> 7704 </message>
7667 <message> 7705 <message>
7668 <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="199"/> 7706 <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="199"/>
7669 <source>Enter Text</source> 7707 <source>Enter Text</source>
7670 <translation type="unfinished"/> 7708 <translation>Voer Tekst In</translation>
7671 </message> 7709 </message>
7672 <message> 7710 <message>
7673 <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="479"/> 7711 <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="479"/>
@@ -7676,7 +7714,11 @@ Please try again or contact the developer of the software.</source>
7676p, li { white-space: pre-wrap; } 7714p, li { white-space: pre-wrap; }
7677&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;&quot;&gt; 7715&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;&quot;&gt;
7678&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 7716&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
7679 <translation type="unfinished"/> 7717 <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
7718&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
7719p, li { white-space: pre-wrap; }
7720&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:26pt; font-weight:400; font-style:normal;&quot;&gt;
7721&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
7680 </message> 7722 </message>
7681 <message> 7723 <message>
7682 <location filename="../../src/yuzu/applets/qt_software_keyboard.cpp" line="403"/> 7724 <location filename="../../src/yuzu/applets/qt_software_keyboard.cpp" line="403"/>
@@ -7695,7 +7737,7 @@ p, li { white-space: pre-wrap; }
7695 <message> 7737 <message>
7696 <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="10"/> 7738 <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="10"/>
7697 <source>Enter a hotkey</source> 7739 <source>Enter a hotkey</source>
7698 <translation>Voer een hotkey in</translation> 7740 <translation>Voer een sneltoets in</translation>
7699 </message> 7741 </message>
7700</context> 7742</context>
7701<context> 7743<context>
@@ -7711,12 +7753,12 @@ p, li { white-space: pre-wrap; }
7711 <message> 7753 <message>
7712 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/> 7754 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/>
7713 <source>[%1] %2</source> 7755 <source>[%1] %2</source>
7714 <translation type="unfinished"/> 7756 <translation>[%1] %2</translation>
7715 </message> 7757 </message>
7716 <message> 7758 <message>
7717 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/> 7759 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/>
7718 <source>waited by no thread</source> 7760 <source>waited by no thread</source>
7719 <translation>wachtend door geen draad</translation> 7761 <translation>wachtend door geen thread</translation>
7720 </message> 7762 </message>
7721</context> 7763</context>
7722<context> 7764<context>
@@ -7729,7 +7771,7 @@ p, li { white-space: pre-wrap; }
7729 <message> 7771 <message>
7730 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="204"/> 7772 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="204"/>
7731 <source>paused</source> 7773 <source>paused</source>
7732 <translation>gepauzeerd</translation> 7774 <translation>onderbroken</translation>
7733 </message> 7775 </message>
7734 <message> 7776 <message>
7735 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="210"/> 7777 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="210"/>
@@ -7739,7 +7781,7 @@ p, li { white-space: pre-wrap; }
7739 <message> 7781 <message>
7740 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="213"/> 7782 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="213"/>
7741 <source>waiting for IPC reply</source> 7783 <source>waiting for IPC reply</source>
7742 <translation>wachten op IPC antwoord</translation> 7784 <translation>wachten op IPC-antwoord</translation>
7743 </message> 7785 </message>
7744 <message> 7786 <message>
7745 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="216"/> 7787 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="216"/>
@@ -7759,7 +7801,7 @@ p, li { white-space: pre-wrap; }
7759 <message> 7801 <message>
7760 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="225"/> 7802 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="225"/>
7761 <source>waiting for suspend resume</source> 7803 <source>waiting for suspend resume</source>
7762 <translation type="unfinished"/> 7804 <translation>wachtend op hervatten onderbreking</translation>
7763 </message> 7805 </message>
7764 <message> 7806 <message>
7765 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="228"/> 7807 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="228"/>
@@ -7769,7 +7811,7 @@ p, li { white-space: pre-wrap; }
7769 <message> 7811 <message>
7770 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="233"/> 7812 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="233"/>
7771 <source>initialized</source> 7813 <source>initialized</source>
7772 <translation>geinitialiseerd</translation> 7814 <translation>geïnitialiseerd</translation>
7773 </message> 7815 </message>
7774 <message> 7816 <message>
7775 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="236"/> 7817 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="236"/>
@@ -7809,7 +7851,7 @@ p, li { white-space: pre-wrap; }
7809 <message> 7851 <message>
7810 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="304"/> 7852 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="304"/>
7811 <source>thread id = %1</source> 7853 <source>thread id = %1</source>
7812 <translation>draad id = %1</translation> 7854 <translation>thread-id = %1</translation>
7813 </message> 7855 </message>
7814 <message> 7856 <message>
7815 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="305"/> 7857 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="305"/>
@@ -7827,7 +7869,7 @@ p, li { white-space: pre-wrap; }
7827 <message> 7869 <message>
7828 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="325"/> 7870 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="325"/>
7829 <source>waited by thread</source> 7871 <source>waited by thread</source>
7830 <translation>Wachtend door draad</translation> 7872 <translation>wachtend door thread</translation>
7831 </message> 7873 </message>
7832</context> 7874</context>
7833<context> 7875<context>
@@ -7835,7 +7877,7 @@ p, li { white-space: pre-wrap; }
7835 <message> 7877 <message>
7836 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="399"/> 7878 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="399"/>
7837 <source>&amp;Wait Tree</source> 7879 <source>&amp;Wait Tree</source>
7838 <translation type="unfinished"/> 7880 <translation>&amp;Wait Tree</translation>
7839 </message> 7881 </message>
7840</context> 7882</context>
7841</TS> \ No newline at end of file 7883</TS> \ No newline at end of file
diff --git a/dist/languages/pl.ts b/dist/languages/pl.ts
index 36daf71d2..e822fcac8 100644
--- a/dist/languages/pl.ts
+++ b/dist/languages/pl.ts
@@ -1377,8 +1377,8 @@ Gdy ta opcja jest włączona, niedopasowanie jest uruchamiane tylko wtedy, gdy d
1377 </message> 1377 </message>
1378 <message> 1378 <message>
1379 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1379 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1380 <source>Extended memory layout (6GB DRAM)</source> 1380 <source>Extended memory layout (8GB DRAM)</source>
1381 <translation>Rozszerzony układ pamięci (6GB DRAM)</translation> 1381 <translation type="unfinished"/>
1382 </message> 1382 </message>
1383 <message> 1383 <message>
1384 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1384 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/pt_BR.ts b/dist/languages/pt_BR.ts
index 98f1345a2..50213db36 100644
--- a/dist/languages/pt_BR.ts
+++ b/dist/languages/pt_BR.ts
@@ -1383,8 +1383,8 @@ Isto banirá tanto o nome de usuário do fórum como o endereço IP.</translatio
1383 </message> 1383 </message>
1384 <message> 1384 <message>
1385 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1385 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1386 <source>Extended memory layout (6GB DRAM)</source> 1386 <source>Extended memory layout (8GB DRAM)</source>
1387 <translation>Layout de memória extendida (6GB DRAM)</translation> 1387 <translation type="unfinished"/>
1388 </message> 1388 </message>
1389 <message> 1389 <message>
1390 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1390 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/pt_PT.ts b/dist/languages/pt_PT.ts
index 293283ac9..da8aa6d13 100644
--- a/dist/languages/pt_PT.ts
+++ b/dist/languages/pt_PT.ts
@@ -1373,8 +1373,8 @@ Isto banirá tanto o nome de usuário do fórum como o endereço IP.</translatio
1373 </message> 1373 </message>
1374 <message> 1374 <message>
1375 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1375 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1376 <source>Extended memory layout (6GB DRAM)</source> 1376 <source>Extended memory layout (8GB DRAM)</source>
1377 <translation>Layout de memória extendida (6GB DRAM)</translation> 1377 <translation type="unfinished"/>
1378 </message> 1378 </message>
1379 <message> 1379 <message>
1380 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1380 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/ru_RU.ts b/dist/languages/ru_RU.ts
index eee646732..898c1800c 100644
--- a/dist/languages/ru_RU.ts
+++ b/dist/languages/ru_RU.ts
@@ -381,17 +381,17 @@ This would ban both their forum username and their IP address.</source>
381 <message> 381 <message>
382 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/> 382 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/>
383 <source>Output Device:</source> 383 <source>Output Device:</source>
384 <translation type="unfinished"/> 384 <translation>УÑтройÑтво вывода:</translation>
385 </message> 385 </message>
386 <message> 386 <message>
387 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/> 387 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/>
388 <source>Input Device:</source> 388 <source>Input Device:</source>
389 <translation type="unfinished"/> 389 <translation>УÑтройÑтво ввода:</translation>
390 </message> 390 </message>
391 <message> 391 <message>
392 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/> 392 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="70"/>
393 <source>Sound Output Mode:</source> 393 <source>Sound Output Mode:</source>
394 <translation type="unfinished"/> 394 <translation>Режим вывода звука:</translation>
395 </message> 395 </message>
396 <message> 396 <message>
397 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/> 397 <location filename="../../src/yuzu/configuration/configure_audio.ui" line="78"/>
@@ -551,13 +551,13 @@ This would ban both their forum username and their IP address.</source>
551 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt; 551 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
552 </source> 552 </source>
553 <translation> 553 <translation>
554 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, ÑƒÐ¼ÐµÐ½ÑŒÑˆÐ°Ñ Ñ‚Ð¾Ñ‡Ð½Ð¾Ñть Ñложенных умноженных инÑтрукций на ЦП без поддержки FMA.&lt;/div&gt; 554 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть за Ñчет ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ñ‚Ð¾Ñ‡Ð½Ð¾Ñти инÑтрукций fused-multiply-add на ЦП без вÑтроенной поддержки FMA.&lt;/div&gt;
555 </translation> 555 </translation>
556 </message> 556 </message>
557 <message> 557 <message>
558 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/> 558 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/>
559 <source>Unfuse FMA (improve performance on CPUs without FMA)</source> 559 <source>Unfuse FMA (improve performance on CPUs without FMA)</source>
560 <translation>Ðе иÑпользовать FMA (улучшает производительноÑть на ЦП без FMA)</translation> 560 <translation>Отключить FMA (улучшает производительноÑть на ЦП без FMA)</translation>
561 </message> 561 </message>
562 <message> 562 <message>
563 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="113"/> 563 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="113"/>
@@ -565,7 +565,7 @@ This would ban both their forum username and their IP address.</source>
565 &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt; 565 &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
566 </source> 566 </source>
567 <translation> 567 <translation>
568 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть некоторых аппрокÑимирующих функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой за Ñчет иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼ÐµÐ½ÐµÐµ точных нативных приближений.&lt;/div&gt; 568 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть некоторых приближенных функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой за Ñчет иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼ÐµÐ½ÐµÐµ точных нативных приближений&lt;/div&gt;
569 </translation> 569 </translation>
570 </message> 570 </message>
571 <message> 571 <message>
@@ -579,13 +579,13 @@ This would ban both their forum username and their IP address.</source>
579 &lt;div&gt;This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.&lt;/div&gt; 579 &lt;div&gt;This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.&lt;/div&gt;
580 </source> 580 </source>
581 <translation> 581 <translation>
582 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐ°ÐµÑ‚ ÑкороÑть 32-битных ASIMD-функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ запÑтой путём работы Ñ Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ñ‹Ð¼Ð¸ режимами округлениÑ.&lt;/div&gt; 582 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть работы 32-битных ASIMD-функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ запÑтой, Ñ€Ð°Ð±Ð¾Ñ‚Ð°Ñ Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ режимами округлениÑ.&lt;/div&gt;
583 </translation> 583 </translation>
584 </message> 584 </message>
585 <message> 585 <message>
586 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="130"/> 586 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="130"/>
587 <source>Faster ASIMD instructions (32 bits only)</source> 587 <source>Faster ASIMD instructions (32 bits only)</source>
588 <translation>Ðолее быÑтрые инÑтрукции ASIMD (только 32 бит)</translation> 588 <translation>УÑкоренные инÑтрукции ASIMD (только 32 бит)</translation>
589 </message> 589 </message>
590 <message> 590 <message>
591 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="137"/> 591 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="137"/>
@@ -593,20 +593,22 @@ This would ban both their forum username and their IP address.</source>
593 &lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt; 593 &lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt;
594 </source> 594 </source>
595 <translation> 595 <translation>
596 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, ÑƒÐ±Ð¸Ñ€Ð°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÑƒ на NaN. Обратите внимание, что Ñто также Ñнижает точноÑть некоторых инÑтрукций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой.&lt;/div&gt; 596 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, удалÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÑƒ NaN. Обратите внимание, что Ñто также Ñнижает точноÑть некоторых инÑтрукций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой.&lt;/div&gt;
597 </translation> 597 </translation>
598 </message> 598 </message>
599 <message> 599 <message>
600 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="142"/> 600 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="142"/>
601 <source>Inaccurate NaN handling</source> 601 <source>Inaccurate NaN handling</source>
602 <translation>ÐепÑÐ°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ° NaN</translation> 602 <translation>ÐеÑоÑÐ½Ð°Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ° NaN</translation>
603 </message> 603 </message>
604 <message> 604 <message>
605 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="149"/> 605 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="149"/>
606 <source> 606 <source>
607 &lt;div&gt;This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.&lt;/div&gt; 607 &lt;div&gt;This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.&lt;/div&gt;
608 </source> 608 </source>
609 <translation type="unfinished"/> 609 <translation>
610 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть за Ñчет иÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ безопаÑноÑти перед каждым чтением/запиÑью памÑти в гоÑтевом режиме. Отключение Ñтой опции может позволить игре читать/запиÑывать памÑть ÑмулÑтора.
611 </translation>
610 </message> 612 </message>
611 <message> 613 <message>
612 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="154"/> 614 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="154"/>
@@ -618,12 +620,14 @@ This would ban both their forum username and their IP address.</source>
618 <source> 620 <source>
619 &lt;div&gt;This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.&lt;/div&gt; 621 &lt;div&gt;This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.&lt;/div&gt;
620 </source> 622 </source>
621 <translation type="unfinished"/> 623 <translation>
624 &lt;div&gt;Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, полагаÑÑÑŒ только на Ñемантику cmpxchg Ð´Ð»Ñ Ð¾Ð±ÐµÑÐ¿ÐµÑ‡ÐµÐ½Ð¸Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑти инÑтрукций иÑключительного доÑтупа. Обратите внимание, что Ñто может привеÑти к полным завиÑаниÑм и другим уÑловиÑм гонки.&lt;/div&gt;
625 </translation>
622 </message> 626 </message>
623 <message> 627 <message>
624 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="166"/> 628 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="166"/>
625 <source>Ignore global monitor</source> 629 <source>Ignore global monitor</source>
626 <translation type="unfinished"/> 630 <translation>Игнорировать глобальный мониторинг</translation>
627 </message> 631 </message>
628 <message> 632 <message>
629 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="191"/> 633 <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="191"/>
@@ -660,7 +664,11 @@ This would ban both their forum username and their IP address.</source>
660 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt; 664 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it inlines accesses to PageTable::pointers into emitted code.&lt;/div&gt;
661 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt; 665 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.&lt;/div&gt;
662 </source> 666 </source>
663 <translation type="unfinished"/> 667 <translation>
668 &lt;div style=&quot;white-space: nowrap&quot;&gt;Эта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет доÑтуп гоÑтевой программы к памÑти.&lt;/div&gt;
669 &lt;div style=&quot;white-space: nowrap&quot;&gt; Включение Ñтой оптимизации вÑтраивает доÑтуп к указателÑм PageTable::pointers в Ñмулируемый код.&lt;/div&gt;
670 &lt;div style=&quot;white-space: nowrap&quot;&gt;Отключение Ñтой функции заÑтавлÑет вÑе Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº памÑти проходить через функции Memory::Read/Memory::Write.&lt;/div&gt;
671 </translation>
664 </message> 672 </message>
665 <message> 673 <message>
666 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="48"/> 674 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="48"/>
@@ -672,7 +680,9 @@ This would ban both their forum username and their IP address.</source>
672 <source> 680 <source>
673 &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt; 681 &lt;div&gt;This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.&lt;/div&gt;
674 </source> 682 </source>
675 <translation type="unfinished"/> 683 <translation>
684 &lt;div&gt;Эта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет избежать поиÑка диÑпетчера, позволÑÑ Ñмитированным базовым блокам переходить непоÑредÑтвенно к другим базовым блокам, еÑли конечный ПК Ñтатичен.&lt;/div&gt;
685 </translation>
676 </message> 686 </message>
677 <message> 687 <message>
678 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/> 688 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/>
@@ -684,7 +694,9 @@ This would ban both their forum username and their IP address.</source>
684 <source> 694 <source>
685 &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt; 695 &lt;div&gt;This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.&lt;/div&gt;
686 </source> 696 </source>
687 <translation type="unfinished"/> 697 <translation>
698 &lt;div&gt;Эта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет избежать поиÑка диÑпетчера, отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ñ Ð¿Ð¾Ñ‚ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ñ‹Ðµ адреÑа возврата инÑтрукций BL. Это приближено к тому, что проиÑходит Ñ Ð±ÑƒÑ„ÐµÑ€Ð¾Ð¼ Ñтека возврата на реальном ЦП.&lt;/div&gt;
699 </translation>
688 </message> 700 </message>
689 <message> 701 <message>
690 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/> 702 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/>
@@ -696,7 +708,9 @@ This would ban both their forum username and their IP address.</source>
696 <source> 708 <source>
697 &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt; 709 &lt;div&gt;Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.&lt;/div&gt;
698 </source> 710 </source>
699 <translation type="unfinished"/> 711 <translation>
712 &lt;div&gt;Включите двухуровневую ÑиÑтему диÑпетчеризации. Сначала иÑпользуетÑÑ Ð±Ð¾Ð»ÐµÐµ быÑтрый диÑпетчер, напиÑанный на аÑÑемблере и имеющий небольшой кÑш MRU Ð´Ð»Ñ Ð¼ÐµÑÑ‚ Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð¾Ð². ЕÑли он не ÑправлÑетÑÑ, диÑÐ¿ÐµÑ‚Ñ‡ÐµÑ€Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ÑÑ Ðº более медленному диÑпетчеру на C++.&lt;/div&gt;
713 </translation>
700 </message> 714 </message>
701 <message> 715 <message>
702 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/> 716 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/>
@@ -708,7 +722,9 @@ This would ban both their forum username and their IP address.</source>
708 <source> 722 <source>
709 &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt; 723 &lt;div&gt;Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.&lt;/div&gt;
710 </source> 724 </source>
711 <translation type="unfinished"/> 725 <translation>
726 &lt;div&gt;Включает IR-оптимизацию, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑƒÐ¼ÐµÐ½ÑŒÑˆÐ°ÐµÑ‚ ненужные Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº Ñтруктуре контекÑта ЦП.&lt;/div&gt;
727 </translation>
712 </message> 728 </message>
713 <message> 729 <message>
714 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/> 730 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/>
@@ -720,19 +736,23 @@ This would ban both their forum username and their IP address.</source>
720 <source> 736 <source>
721 &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt; 737 &lt;div&gt;Enables IR optimizations that involve constant propagation.&lt;/div&gt;
722 </source> 738 </source>
723 <translation type="unfinished"/> 739 <translation>
740 &lt;div&gt;Включает IR-оптимизацию, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²ÐºÐ»ÑŽÑ‡Ð°ÐµÑ‚ раÑпроÑтранение конÑтант.&lt;/div&gt;
741 </translation>
724 </message> 742 </message>
725 <message> 743 <message>
726 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/> 744 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/>
727 <source>Enable constant propagation</source> 745 <source>Enable constant propagation</source>
728 <translation>Включить поÑтоÑнное раÑпроÑтранение</translation> 746 <translation>Включить раÑпроÑтранение конÑтант</translation>
729 </message> 747 </message>
730 <message> 748 <message>
731 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="115"/> 749 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="115"/>
732 <source> 750 <source>
733 &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt; 751 &lt;div&gt;Enables miscellaneous IR optimizations.&lt;/div&gt;
734 </source> 752 </source>
735 <translation type="unfinished"/> 753 <translation>
754 &lt;div&gt;Включает различные IR-оптимизации.&lt;/div&gt;
755 </translation>
736 </message> 756 </message>
737 <message> 757 <message>
738 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/> 758 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/>
@@ -745,12 +765,15 @@ This would ban both their forum username and their IP address.</source>
745 &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt; 765 &lt;div style=&quot;white-space: nowrap&quot;&gt;When enabled, a misalignment is only triggered when an access crosses a page boundary.&lt;/div&gt;
746 &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt; 766 &lt;div style=&quot;white-space: nowrap&quot;&gt;When disabled, a misalignment is triggered on all misaligned accesses.&lt;/div&gt;
747 </source> 767 </source>
748 <translation type="unfinished"/> 768 <translation>
769 &lt;div style=&quot;white-space: nowrap&quot;&gt;ЕÑли Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, Ñмещение Ñрабатывает только тогда, когда доÑтуп переÑекает границу Ñтраницы.&lt;/div&gt;
770 &lt;div style=&quot;white-space: nowrap&quot;&gt;ЕÑли отключено, Ñмещение Ñрабатывает при вÑех Ñмещенных доÑтупах.&lt;/div&gt;
771 </translation>
749 </message> 772 </message>
750 <message> 773 <message>
751 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="133"/> 774 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="133"/>
752 <source>Enable misalignment check reduction</source> 775 <source>Enable misalignment check reduction</source>
753 <translation type="unfinished"/> 776 <translation>Включить уменьшение проверки неÑооÑноÑти</translation>
754 </message> 777 </message>
755 <message> 778 <message>
756 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="140"/> 779 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="140"/>
@@ -759,12 +782,16 @@ This would ban both their forum username and their IP address.</source>
759 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt; 782 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt;
760 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt; 783 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt;
761 </source> 784 </source>
762 <translation type="unfinished"/> 785 <translation>
786 &lt;div style=&quot;white-space: nowrap&quot;&gt;Эта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет доÑтуп гоÑтевой программы к памÑти.&lt;/div&gt;
787 &lt;div style=&quot;white-space: nowrap&quot;&gt; Включение Ñтой оптимизации приводит к тому, что чтение/запиÑÑŒ гоÑтевой памÑти производитÑÑ Ð½ÐµÐ¿Ð¾ÑредÑтвенно в памÑть и иÑпользует MMU хоÑта.&lt;/div&gt;
788 &lt;div style=&quot;white-space: nowrap&quot;&gt;Отключение Ñтой функции заÑтавлÑет вÑе Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº памÑти иÑпользовать программную ÑмулÑцию MMU.&lt;/div&gt;
789 </translation>
763 </message> 790 </message>
764 <message> 791 <message>
765 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="147"/> 792 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="147"/>
766 <source>Enable Host MMU Emulation (general memory instructions)</source> 793 <source>Enable Host MMU Emulation (general memory instructions)</source>
767 <translation type="unfinished"/> 794 <translation>Включить ÑмулÑцию MMU хоÑта (инÑтрукции общей памÑти)</translation>
768 </message> 795 </message>
769 <message> 796 <message>
770 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="154"/> 797 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="154"/>
@@ -773,12 +800,16 @@ This would ban both their forum username and their IP address.</source>
773 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt; 800 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt;
774 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all exclusive memory accesses to use Software MMU Emulation.&lt;/div&gt; 801 &lt;div style=&quot;white-space: nowrap&quot;&gt;Disabling this forces all exclusive memory accesses to use Software MMU Emulation.&lt;/div&gt;
775 </source> 802 </source>
776 <translation type="unfinished"/> 803 <translation>
804 &lt;div style=&quot;white-space: nowrap&quot;&gt;Эта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет доÑтуп гоÑтевой программы к ÑкÑклюзивной памÑти.&lt;/div&gt;
805 &lt;div style=&quot;white-space: nowrap&quot;&gt;Включение Ñтой оптимизации приводит к тому, что чтение/запиÑÑŒ в ÑкÑклюзивную памÑть гоÑÑ‚Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð½ÐµÐ¿Ð¾ÑредÑтвенно в памÑть и иÑпользует MMU хоÑта.&lt;/div&gt;
806 &lt;div style=&quot;white-space: nowrap&quot;&gt; Отключение Ñтой функции заÑтавлÑет вÑе ÑкÑклюзивные доÑтупы к памÑти иÑпользовать ÑмулÑцию программного MMU.&lt;/div&gt;
807 </translation>
777 </message> 808 </message>
778 <message> 809 <message>
779 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="161"/> 810 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="161"/>
780 <source>Enable Host MMU Emulation (exclusive memory instructions)</source> 811 <source>Enable Host MMU Emulation (exclusive memory instructions)</source>
781 <translation type="unfinished"/> 812 <translation>Включить ÑмулÑцию MMU хоÑта (инÑтрукции иÑключительной памÑти)</translation>
782 </message> 813 </message>
783 <message> 814 <message>
784 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="168"/> 815 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="168"/>
@@ -786,12 +817,15 @@ This would ban both their forum username and their IP address.</source>
786 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up exclusive memory accesses by the guest program.&lt;/div&gt; 817 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up exclusive memory accesses by the guest program.&lt;/div&gt;
787 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.&lt;/div&gt; 818 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.&lt;/div&gt;
788 </source> 819 </source>
789 <translation type="unfinished"/> 820 <translation>
821 &lt;div style=&quot;white-space: nowrap&quot;&gt;Эта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет обращение гоÑтевой программы к иÑключительной памÑти.&lt;/div&gt;
822 &lt;div style=&quot;white-space: nowrap&quot;&gt;Ее включение Ñнижает накладные раÑходы, ÑвÑзанные Ñ Ð¾Ñ‚ÐºÐ°Ð·Ð¾Ð¼ fastmem при доÑтупе к иÑключительной памÑти.&lt;/div&gt;
823 </translation>
790 </message> 824 </message>
791 <message> 825 <message>
792 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="174"/> 826 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="174"/>
793 <source>Enable recompilation of exclusive memory instructions</source> 827 <source>Enable recompilation of exclusive memory instructions</source>
794 <translation type="unfinished"/> 828 <translation>Разрешить перекомпилÑцию инÑтрукций иÑключительной памÑти</translation>
795 </message> 829 </message>
796 <message> 830 <message>
797 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="181"/> 831 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="181"/>
@@ -799,7 +833,10 @@ This would ban both their forum username and their IP address.</source>
799 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.&lt;/div&gt; 833 &lt;div style=&quot;white-space: nowrap&quot;&gt;This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.&lt;/div&gt;
800 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.&lt;/div&gt; 834 &lt;div style=&quot;white-space: nowrap&quot;&gt;Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.&lt;/div&gt;
801 </source> 835 </source>
802 <translation type="unfinished"/> 836 <translation>
837 &lt;div style=&quot;white-space: nowrap&quot;&gt;Эта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет обращение к памÑти, позволÑÑ ÑƒÑпешное обращение к недопуÑтимой памÑти.&lt;/div&gt;
838 &lt;div style=&quot;white-space: nowrap&quot;&gt;Включение Ñтой оптимизации Ñнижает накладные раÑходы на вÑе Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº памÑти и не влиÑет на программы, которые не обращаютÑÑ Ðº недопуÑтимой памÑти.&lt;/div&gt;
839 </translation>
803 </message> 840 </message>
804 <message> 841 <message>
805 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="187"/> 842 <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="187"/>
@@ -917,17 +954,17 @@ This would ban both their forum username and their IP address.</source>
917 <message> 954 <message>
918 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="198"/> 955 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="198"/>
919 <source>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</source> 956 <source>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</source>
920 <translation>ЕÑли включено, отключает компилÑтор макроÑа Just In Time. Включение опции делает игры медленнее</translation> 957 <translation>ЕÑли включено, отключает компилÑтор макроÑа Just In Time. Включение Ñтого параметра замедлÑет работу игр</translation>
921 </message> 958 </message>
922 <message> 959 <message>
923 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/> 960 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/>
924 <source>Disable Macro JIT</source> 961 <source>Disable Macro JIT</source>
925 <translation>Отключить Macro JIT</translation> 962 <translation>Отключить Ð¼Ð°ÐºÑ€Ð¾Ñ JIT</translation>
926 </message> 963 </message>
927 <message> 964 <message>
928 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="211"/> 965 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="211"/>
929 <source>When checked, it disables the macro HLE functions. Enabling this makes games run slower</source> 966 <source>When checked, it disables the macro HLE functions. Enabling this makes games run slower</source>
930 <translation type="unfinished"/> 967 <translation>ЕÑли флажок уÑтановлен, он отключает функции макроÑа HLE. Включение Ñтого параметра замедлÑет работу игр</translation>
931 </message> 968 </message>
932 <message> 969 <message>
933 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="214"/> 970 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="214"/>
@@ -947,12 +984,12 @@ This would ban both their forum username and their IP address.</source>
947 <message> 984 <message>
948 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="231"/> 985 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="231"/>
949 <source>When checked, it executes shaders without loop logic changes</source> 986 <source>When checked, it executes shaders without loop logic changes</source>
950 <translation type="unfinished"/> 987 <translation>ЕÑли включено, шейдеры выполнÑÑŽÑ‚ÑÑ Ð±ÐµÐ· Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð»Ð¾Ð³Ð¸ÐºÐ¸ цикла</translation>
951 </message> 988 </message>
952 <message> 989 <message>
953 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="234"/> 990 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="234"/>
954 <source>Disable Loop safety checks</source> 991 <source>Disable Loop safety checks</source>
955 <translation type="unfinished"/> 992 <translation>Отключить проверку безопаÑноÑти цикла</translation>
956 </message> 993 </message>
957 <message> 994 <message>
958 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="244"/> 995 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="244"/>
@@ -967,12 +1004,12 @@ This would ban both their forum username and their IP address.</source>
967 <message> 1004 <message>
968 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="257"/> 1005 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="257"/>
969 <source>Enable FS Access Log</source> 1006 <source>Enable FS Access Log</source>
970 <translation type="unfinished"/> 1007 <translation>Включить журнал доÑтупа к ФС</translation>
971 </message> 1008 </message>
972 <message> 1009 <message>
973 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="264"/> 1010 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="264"/>
974 <source>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</source> 1011 <source>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</source>
975 <translation type="unfinished"/> 1012 <translation>Включите Ñту опцию, чтобы вывеÑти на конÑоль поÑледний Ñгенерированный ÑпиÑок аудиокоманд. ВлиÑет только на игры, иÑпользующие аудио рендерер.</translation>
976 </message> 1013 </message>
977 <message> 1014 <message>
978 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="267"/> 1015 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="267"/>
@@ -1007,7 +1044,7 @@ This would ban both their forum username and their IP address.</source>
1007 <message> 1044 <message>
1008 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="311"/> 1045 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="311"/>
1009 <source>Enable Auto-Stub**</source> 1046 <source>Enable Auto-Stub**</source>
1010 <translation type="unfinished"/> 1047 <translation>Включить автоподÑтавку**</translation>
1011 </message> 1048 </message>
1012 <message> 1049 <message>
1013 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="318"/> 1050 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="318"/>
@@ -1346,8 +1383,8 @@ This would ban both their forum username and their IP address.</source>
1346 </message> 1383 </message>
1347 <message> 1384 <message>
1348 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1385 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1349 <source>Extended memory layout (6GB DRAM)</source> 1386 <source>Extended memory layout (8GB DRAM)</source>
1350 <translation>РаÑÑˆÐ¸Ñ€ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ° памÑти (6 ГБ DRAM)</translation> 1387 <translation>РаÑÑˆÐ¸Ñ€ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ° памÑти (8 ГБ DRAM)</translation>
1351 </message> 1388 </message>
1352 <message> 1389 <message>
1353 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1390 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
@@ -1716,12 +1753,12 @@ This would ban both their forum username and their IP address.</source>
1716 <message> 1753 <message>
1717 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/> 1754 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/>
1718 <source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source> 1755 <source>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</source>
1719 <translation type="unfinished"/> 1756 <translation>Включает аÑинхронное декодирование текÑтур ASTC, что может уменьшить фризы при загрузке. Эта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ ÑвлÑетÑÑ ÑкÑпериментальной.</translation>
1720 </message> 1757 </message>
1721 <message> 1758 <message>
1722 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/> 1759 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/>
1723 <source>Decode ASTC textures asynchronously (Hack)</source> 1760 <source>Decode ASTC textures asynchronously (Hack)</source>
1724 <translation type="unfinished"/> 1761 <translation>ÐÑинхронное декодирование текÑтур ASTC (Хак)</translation>
1725 </message> 1762 </message>
1726 <message> 1763 <message>
1727 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/> 1764 <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/>
@@ -2236,7 +2273,7 @@ This would ban both their forum username and their IP address.</source>
2236 <message> 2273 <message>
2237 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/> 2274 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2726"/>
2238 <source>Enable direct Pro Controller driver [EXPERIMENTAL]</source> 2275 <source>Enable direct Pro Controller driver [EXPERIMENTAL]</source>
2239 <translation type="unfinished"/> 2276 <translation>Включить прÑмой драйвер Pro Controller [ЭКСПЕРИМЕÐТÐЛЬÐО]</translation>
2240 </message> 2277 </message>
2241 <message> 2278 <message>
2242 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/> 2279 <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2739"/>
@@ -4580,12 +4617,12 @@ Drag points to change position, or double-click table cells to edit values.</sou
4580 <message> 4617 <message>
4581 <location filename="../../src/yuzu/main.cpp" line="1230"/> 4618 <location filename="../../src/yuzu/main.cpp" line="1230"/>
4582 <source>Emulated mouse is enabled</source> 4619 <source>Emulated mouse is enabled</source>
4583 <translation type="unfinished"/> 4620 <translation>Ð­Ð¼ÑƒÐ»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð¼Ñ‹ÑˆÑŒ включена</translation>
4584 </message> 4621 </message>
4585 <message> 4622 <message>
4586 <location filename="../../src/yuzu/main.cpp" line="1231"/> 4623 <location filename="../../src/yuzu/main.cpp" line="1231"/>
4587 <source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source> 4624 <source>Real mouse input and mouse panning are incompatible. Please disable the emulated mouse in input advanced settings to allow mouse panning.</source>
4588 <translation type="unfinished"/> 4625 <translation>Ввод реальной мыши и панорамирование мышью неÑовмеÑтимы. ПожалуйÑта, отключите Ñмулированную мышь в раÑширенных наÑтройках ввода, чтобы разрешить панорамирование мышью.</translation>
4589 </message> 4626 </message>
4590 <message> 4627 <message>
4591 <location filename="../../src/yuzu/main.cpp" line="1453"/> 4628 <location filename="../../src/yuzu/main.cpp" line="1453"/>
@@ -7613,7 +7650,7 @@ Please try again or contact the developer of the software.</source>
7613 <message> 7650 <message>
7614 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/> 7651 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="166"/>
7615 <source>Profile Creator</source> 7652 <source>Profile Creator</source>
7616 <translation type="unfinished"/> 7653 <translation>Создатель профилÑ</translation>
7617 </message> 7654 </message>
7618 <message> 7655 <message>
7619 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/> 7656 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="169"/>
@@ -7624,57 +7661,57 @@ Please try again or contact the developer of the software.</source>
7624 <message> 7661 <message>
7625 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/> 7662 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="172"/>
7626 <source>Profile Icon Editor</source> 7663 <source>Profile Icon Editor</source>
7627 <translation type="unfinished"/> 7664 <translation>Редактор иконки профилÑ</translation>
7628 </message> 7665 </message>
7629 <message> 7666 <message>
7630 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/> 7667 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="175"/>
7631 <source>Profile Nickname Editor</source> 7668 <source>Profile Nickname Editor</source>
7632 <translation type="unfinished"/> 7669 <translation>Редактор никнейма профилÑ</translation>
7633 </message> 7670 </message>
7634 <message> 7671 <message>
7635 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/> 7672 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="197"/>
7636 <source>Who will receive the points?</source> 7673 <source>Who will receive the points?</source>
7637 <translation type="unfinished"/> 7674 <translation>Кто будет получать очки?</translation>
7638 </message> 7675 </message>
7639 <message> 7676 <message>
7640 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/> 7677 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="200"/>
7641 <source>Who is using Nintendo eShop?</source> 7678 <source>Who is using Nintendo eShop?</source>
7642 <translation type="unfinished"/> 7679 <translation>Кто иÑпользует Nintendo eShop?</translation>
7643 </message> 7680 </message>
7644 <message> 7681 <message>
7645 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/> 7682 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="203"/>
7646 <source>Who is making this purchase?</source> 7683 <source>Who is making this purchase?</source>
7647 <translation type="unfinished"/> 7684 <translation>Кто Ñовершает Ñту покупку?</translation>
7648 </message> 7685 </message>
7649 <message> 7686 <message>
7650 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/> 7687 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="206"/>
7651 <source>Who is posting?</source> 7688 <source>Who is posting?</source>
7652 <translation type="unfinished"/> 7689 <translation>Кто публикует?</translation>
7653 </message> 7690 </message>
7654 <message> 7691 <message>
7655 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/> 7692 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="209"/>
7656 <source>Select a user to link to a Nintendo Account.</source> 7693 <source>Select a user to link to a Nintendo Account.</source>
7657 <translation type="unfinished"/> 7694 <translation>Выберите Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²Ñзки к учетной запиÑи Nintendo.</translation>
7658 </message> 7695 </message>
7659 <message> 7696 <message>
7660 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/> 7697 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="212"/>
7661 <source>Change settings for which user?</source> 7698 <source>Change settings for which user?</source>
7662 <translation type="unfinished"/> 7699 <translation>Изменить наÑтройки Ð´Ð»Ñ ÐºÐ°ÐºÐ¾Ð³Ð¾ пользователÑ?</translation>
7663 </message> 7700 </message>
7664 <message> 7701 <message>
7665 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/> 7702 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="215"/>
7666 <source>Format data for which user?</source> 7703 <source>Format data for which user?</source>
7667 <translation type="unfinished"/> 7704 <translation>Форматировать данные Ð´Ð»Ñ ÐºÐ°ÐºÐ¾Ð³Ð¾ пользователÑ?</translation>
7668 </message> 7705 </message>
7669 <message> 7706 <message>
7670 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/> 7707 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="218"/>
7671 <source>Which user will be transferred to another console?</source> 7708 <source>Which user will be transferred to another console?</source>
7672 <translation type="unfinished"/> 7709 <translation>Какой пользователь будет переходить на другую конÑоль?</translation>
7673 </message> 7710 </message>
7674 <message> 7711 <message>
7675 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/> 7712 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="221"/>
7676 <source>Send save data for which user?</source> 7713 <source>Send save data for which user?</source>
7677 <translation type="unfinished"/> 7714 <translation>Отправить Ñохранение какому пользователю?</translation>
7678 </message> 7715 </message>
7679 <message> 7716 <message>
7680 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/> 7717 <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="225"/>
@@ -7740,7 +7777,7 @@ p, li { white-space: pre-wrap; }
7740 <message> 7777 <message>
7741 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/> 7778 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="158"/>
7742 <source>[%1] %2</source> 7779 <source>[%1] %2</source>
7743 <translation type="unfinished"/> 7780 <translation>[%1] %2</translation>
7744 </message> 7781 </message>
7745 <message> 7782 <message>
7746 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/> 7783 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="184"/>
@@ -7753,17 +7790,17 @@ p, li { white-space: pre-wrap; }
7753 <message> 7790 <message>
7754 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="202"/> 7791 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="202"/>
7755 <source>runnable</source> 7792 <source>runnable</source>
7756 <translation type="unfinished"/> 7793 <translation>runnable</translation>
7757 </message> 7794 </message>
7758 <message> 7795 <message>
7759 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="204"/> 7796 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="204"/>
7760 <source>paused</source> 7797 <source>paused</source>
7761 <translation type="unfinished"/> 7798 <translation>paused</translation>
7762 </message> 7799 </message>
7763 <message> 7800 <message>
7764 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="210"/> 7801 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="210"/>
7765 <source>sleeping</source> 7802 <source>sleeping</source>
7766 <translation type="unfinished"/> 7803 <translation>sleeping</translation>
7767 </message> 7804 </message>
7768 <message> 7805 <message>
7769 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="213"/> 7806 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="213"/>
@@ -7778,32 +7815,32 @@ p, li { white-space: pre-wrap; }
7778 <message> 7815 <message>
7779 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="219"/> 7816 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="219"/>
7780 <source>waiting for condition variable</source> 7817 <source>waiting for condition variable</source>
7781 <translation type="unfinished"/> 7818 <translation>waiting for condition variable</translation>
7782 </message> 7819 </message>
7783 <message> 7820 <message>
7784 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="222"/> 7821 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="222"/>
7785 <source>waiting for address arbiter</source> 7822 <source>waiting for address arbiter</source>
7786 <translation type="unfinished"/> 7823 <translation>waiting for address arbiter</translation>
7787 </message> 7824 </message>
7788 <message> 7825 <message>
7789 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="225"/> 7826 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="225"/>
7790 <source>waiting for suspend resume</source> 7827 <source>waiting for suspend resume</source>
7791 <translation type="unfinished"/> 7828 <translation>waiting for suspend resume</translation>
7792 </message> 7829 </message>
7793 <message> 7830 <message>
7794 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="228"/> 7831 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="228"/>
7795 <source>waiting</source> 7832 <source>waiting</source>
7796 <translation type="unfinished"/> 7833 <translation>waiting</translation>
7797 </message> 7834 </message>
7798 <message> 7835 <message>
7799 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="233"/> 7836 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="233"/>
7800 <source>initialized</source> 7837 <source>initialized</source>
7801 <translation type="unfinished"/> 7838 <translation>initialized</translation>
7802 </message> 7839 </message>
7803 <message> 7840 <message>
7804 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="236"/> 7841 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="236"/>
7805 <source>terminated</source> 7842 <source>terminated</source>
7806 <translation type="unfinished"/> 7843 <translation>terminated</translation>
7807 </message> 7844 </message>
7808 <message> 7845 <message>
7809 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="239"/> 7846 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="239"/>
@@ -7818,7 +7855,7 @@ p, li { white-space: pre-wrap; }
7818 <message> 7855 <message>
7819 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="294"/> 7856 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="294"/>
7820 <source>ideal</source> 7857 <source>ideal</source>
7821 <translation type="unfinished"/> 7858 <translation>ideal</translation>
7822 </message> 7859 </message>
7823 <message> 7860 <message>
7824 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="297"/> 7861 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="297"/>
@@ -7848,7 +7885,7 @@ p, li { white-space: pre-wrap; }
7848 <message> 7885 <message>
7849 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="309"/> 7886 <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="309"/>
7850 <source>last running ticks = %1</source> 7887 <source>last running ticks = %1</source>
7851 <translation type="unfinished"/> 7888 <translation>last running ticks = %1</translation>
7852 </message> 7889 </message>
7853</context> 7890</context>
7854<context> 7891<context>
diff --git a/dist/languages/sv.ts b/dist/languages/sv.ts
index b81ed7fd6..8c60a4942 100644
--- a/dist/languages/sv.ts
+++ b/dist/languages/sv.ts
@@ -122,7 +122,7 @@ p, li { white-space: pre-wrap; }
122 <message> 122 <message>
123 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="330"/> 123 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="330"/>
124 <source>%1 has been unbanned</source> 124 <source>%1 has been unbanned</source>
125 <translation type="unfinished"/> 125 <translation>%1 har haft dess bannlysning upphävd.</translation>
126 </message> 126 </message>
127 <message> 127 <message>
128 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="446"/> 128 <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="446"/>
@@ -242,22 +242,22 @@ Detta kommer bannlysa både dennes användarnamn på forum samt IP-adress.</tran
242 <message> 242 <message>
243 <location filename="../../src/yuzu/compatdb.ui" line="77"/> 243 <location filename="../../src/yuzu/compatdb.ui" line="77"/>
244 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game boot?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> 244 <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Does the game boot?&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
245 <translation type="unfinished"/> 245 <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Startar Spelet? &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
246 </message> 246 </message>
247 <message> 247 <message>
248 <location filename="../../src/yuzu/compatdb.ui" line="100"/> 248 <location filename="../../src/yuzu/compatdb.ui" line="100"/>
249 <source>Yes The game starts to output video or audio</source> 249 <source>Yes The game starts to output video or audio</source>
250 <translation type="unfinished"/> 250 <translation>Ja Spelet öppnar till utmatning av video eller audio</translation>
251 </message> 251 </message>
252 <message> 252 <message>
253 <location filename="../../src/yuzu/compatdb.ui" line="107"/> 253 <location filename="../../src/yuzu/compatdb.ui" line="107"/>
254 <source>No The game doesn&apos;t get past the &quot;Launching...&quot; screen</source> 254 <source>No The game doesn&apos;t get past the &quot;Launching...&quot; screen</source>
255 <translation type="unfinished"/> 255 <translation>Nej Spelet öppnar ej förbi &quot;Startar...&quot; skärmen</translation>
256 </message> 256 </message>
257 <message> 257 <message>
258 <location filename="../../src/yuzu/compatdb.ui" line="124"/> 258 <location filename="../../src/yuzu/compatdb.ui" line="124"/>
259 <source>Yes The game gets past the intro/menu and into gameplay</source> 259 <source>Yes The game gets past the intro/menu and into gameplay</source>
260 <translation type="unfinished"/> 260 <translation>Ja Spelet öppnar förbi introt/menyn och in i själva spelandet</translation>
261 </message> 261 </message>
262 <message> 262 <message>
263 <location filename="../../src/yuzu/compatdb.ui" line="131"/> 263 <location filename="../../src/yuzu/compatdb.ui" line="131"/>
@@ -1031,7 +1031,7 @@ avgjord kod.&lt;/div&gt;
1031 <message> 1031 <message>
1032 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="325"/> 1032 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="325"/>
1033 <source>Disable Web Applet</source> 1033 <source>Disable Web Applet</source>
1034 <translation type="unfinished"/> 1034 <translation>Avaktivera Webbappletten</translation>
1035 </message> 1035 </message>
1036 <message> 1036 <message>
1037 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="332"/> 1037 <location filename="../../src/yuzu/configuration/configure_debug.ui" line="332"/>
@@ -1360,8 +1360,8 @@ avgjord kod.&lt;/div&gt;
1360 </message> 1360 </message>
1361 <message> 1361 <message>
1362 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1362 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1363 <source>Extended memory layout (6GB DRAM)</source> 1363 <source>Extended memory layout (8GB DRAM)</source>
1364 <translation>Utökad minnesöversikt (6GB DRAM)</translation> 1364 <translation type="unfinished"/>
1365 </message> 1365 </message>
1366 <message> 1366 <message>
1367 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1367 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
@@ -3320,13 +3320,13 @@ UUID: %2</source>
3320 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/> 3320 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/>
3321 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="123"/> 3321 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="123"/>
3322 <source>Pull</source> 3322 <source>Pull</source>
3323 <translation type="unfinished"/> 3323 <translation>Dra</translation>
3324 </message> 3324 </message>
3325 <message> 3325 <message>
3326 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="133"/> 3326 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="133"/>
3327 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="172"/> 3327 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="172"/>
3328 <source>Push</source> 3328 <source>Push</source>
3329 <translation type="unfinished"/> 3329 <translation>Knuff</translation>
3330 </message> 3330 </message>
3331 <message> 3331 <message>
3332 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="206"/> 3332 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="206"/>
@@ -3347,7 +3347,7 @@ UUID: %2</source>
3347 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/> 3347 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="300"/>
3348 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/> 3348 <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="314"/>
3349 <source>Enable</source> 3349 <source>Enable</source>
3350 <translation type="unfinished"/> 3350 <translation>Aktivera</translation>
3351 </message> 3351 </message>
3352 <message> 3352 <message>
3353 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/> 3353 <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="307"/>
@@ -4493,17 +4493,17 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
4493 <message> 4493 <message>
4494 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="97"/> 4494 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="97"/>
4495 <source>Nickname</source> 4495 <source>Nickname</source>
4496 <translation type="unfinished"/> 4496 <translation>Smeknamn</translation>
4497 </message> 4497 </message>
4498 <message> 4498 <message>
4499 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="111"/> 4499 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="111"/>
4500 <source>Password</source> 4500 <source>Password</source>
4501 <translation type="unfinished"/> 4501 <translation>Lösenord</translation>
4502 </message> 4502 </message>
4503 <message> 4503 <message>
4504 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="153"/> 4504 <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="153"/>
4505 <source>Connect</source> 4505 <source>Connect</source>
4506 <translation type="unfinished"/> 4506 <translation>Anslut</translation>
4507 </message> 4507 </message>
4508</context> 4508</context>
4509<context> 4509<context>
@@ -4511,12 +4511,12 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
4511 <message> 4511 <message>
4512 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="120"/> 4512 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="120"/>
4513 <source>Connecting</source> 4513 <source>Connecting</source>
4514 <translation type="unfinished"/> 4514 <translation>Ansluter</translation>
4515 </message> 4515 </message>
4516 <message> 4516 <message>
4517 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="125"/> 4517 <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="125"/>
4518 <source>Connect</source> 4518 <source>Connect</source>
4519 <translation type="unfinished"/> 4519 <translation>Anslut</translation>
4520 </message> 4520 </message>
4521</context> 4521</context>
4522<context> 4522<context>
@@ -4534,7 +4534,7 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
4534 <message> 4534 <message>
4535 <location filename="../../src/yuzu/main.cpp" line="432"/> 4535 <location filename="../../src/yuzu/main.cpp" line="432"/>
4536 <source>Broken Vulkan Installation Detected</source> 4536 <source>Broken Vulkan Installation Detected</source>
4537 <translation type="unfinished"/> 4537 <translation>Felaktig Vulkaninstallation Upptäckt</translation>
4538 </message> 4538 </message>
4539 <message> 4539 <message>
4540 <location filename="../../src/yuzu/main.cpp" line="433"/> 4540 <location filename="../../src/yuzu/main.cpp" line="433"/>
@@ -4550,7 +4550,7 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
4550 <location filename="../../src/yuzu/main.cpp" line="874"/> 4550 <location filename="../../src/yuzu/main.cpp" line="874"/>
4551 <location filename="../../src/yuzu/main.cpp" line="877"/> 4551 <location filename="../../src/yuzu/main.cpp" line="877"/>
4552 <source>Disable Web Applet</source> 4552 <source>Disable Web Applet</source>
4553 <translation type="unfinished"/> 4553 <translation>Avaktivera Webbappletten</translation>
4554 </message> 4554 </message>
4555 <message> 4555 <message>
4556 <location filename="../../src/yuzu/main.cpp" line="878"/> 4556 <location filename="../../src/yuzu/main.cpp" line="878"/>
@@ -4591,7 +4591,7 @@ Dra punkter för att ändra position, eller dubbelklicka tabellceller för att r
4591 <message> 4591 <message>
4592 <location filename="../../src/yuzu/main.cpp" line="1230"/> 4592 <location filename="../../src/yuzu/main.cpp" line="1230"/>
4593 <source>Emulated mouse is enabled</source> 4593 <source>Emulated mouse is enabled</source>
4594 <translation type="unfinished"/> 4594 <translation>Emulerad datormus är aktiverad</translation>
4595 </message> 4595 </message>
4596 <message> 4596 <message>
4597 <location filename="../../src/yuzu/main.cpp" line="1231"/> 4597 <location filename="../../src/yuzu/main.cpp" line="1231"/>
@@ -5171,7 +5171,7 @@ Please, only use this feature to install updates and DLC.</source>
5171 <location filename="../../src/yuzu/main.cpp" line="3182"/> 5171 <location filename="../../src/yuzu/main.cpp" line="3182"/>
5172 <location filename="../../src/yuzu/main.cpp" line="3201"/> 5172 <location filename="../../src/yuzu/main.cpp" line="3201"/>
5173 <source>Hardware requirements not met</source> 5173 <source>Hardware requirements not met</source>
5174 <translation type="unfinished"/> 5174 <translation> HÃ¥rdvarukraven uppfylls ej</translation>
5175 </message> 5175 </message>
5176 <message> 5176 <message>
5177 <location filename="../../src/yuzu/main.cpp" line="3183"/> 5177 <location filename="../../src/yuzu/main.cpp" line="3183"/>
@@ -5202,17 +5202,17 @@ Please, only use this feature to install updates and DLC.</source>
5202 <message> 5202 <message>
5203 <location filename="../../src/yuzu/main.cpp" line="3514"/> 5203 <location filename="../../src/yuzu/main.cpp" line="3514"/>
5204 <source>TAS Recording</source> 5204 <source>TAS Recording</source>
5205 <translation type="unfinished"/> 5205 <translation>TAS Inspelning</translation>
5206 </message> 5206 </message>
5207 <message> 5207 <message>
5208 <location filename="../../src/yuzu/main.cpp" line="3515"/> 5208 <location filename="../../src/yuzu/main.cpp" line="3515"/>
5209 <source>Overwrite file of player 1?</source> 5209 <source>Overwrite file of player 1?</source>
5210 <translation type="unfinished"/> 5210 <translation>Överskriv spelare 1:s fil?</translation>
5211 </message> 5211 </message>
5212 <message> 5212 <message>
5213 <location filename="../../src/yuzu/main.cpp" line="3541"/> 5213 <location filename="../../src/yuzu/main.cpp" line="3541"/>
5214 <source>Invalid config detected</source> 5214 <source>Invalid config detected</source>
5215 <translation type="unfinished"/> 5215 <translation>Ogiltig konfiguration upptäckt</translation>
5216 </message> 5216 </message>
5217 <message> 5217 <message>
5218 <location filename="../../src/yuzu/main.cpp" line="3542"/> 5218 <location filename="../../src/yuzu/main.cpp" line="3542"/>
@@ -5223,13 +5223,13 @@ Please, only use this feature to install updates and DLC.</source>
5223 <location filename="../../src/yuzu/main.cpp" line="3712"/> 5223 <location filename="../../src/yuzu/main.cpp" line="3712"/>
5224 <location filename="../../src/yuzu/main.cpp" line="3740"/> 5224 <location filename="../../src/yuzu/main.cpp" line="3740"/>
5225 <source>Amiibo</source> 5225 <source>Amiibo</source>
5226 <translation type="unfinished"/> 5226 <translation>Amiibo</translation>
5227 </message> 5227 </message>
5228 <message> 5228 <message>
5229 <location filename="../../src/yuzu/main.cpp" line="3712"/> 5229 <location filename="../../src/yuzu/main.cpp" line="3712"/>
5230 <location filename="../../src/yuzu/main.cpp" line="3740"/> 5230 <location filename="../../src/yuzu/main.cpp" line="3740"/>
5231 <source>The current amiibo has been removed</source> 5231 <source>The current amiibo has been removed</source>
5232 <translation type="unfinished"/> 5232 <translation>Den aktuella amiibon har avlägsnats</translation>
5233 </message> 5233 </message>
5234 <message> 5234 <message>
5235 <location filename="../../src/yuzu/main.cpp" line="3717"/> 5235 <location filename="../../src/yuzu/main.cpp" line="3717"/>
@@ -5240,7 +5240,7 @@ Please, only use this feature to install updates and DLC.</source>
5240 <location filename="../../src/yuzu/main.cpp" line="3717"/> 5240 <location filename="../../src/yuzu/main.cpp" line="3717"/>
5241 <location filename="../../src/yuzu/main.cpp" line="3752"/> 5241 <location filename="../../src/yuzu/main.cpp" line="3752"/>
5242 <source>The current game is not looking for amiibos</source> 5242 <source>The current game is not looking for amiibos</source>
5243 <translation type="unfinished"/> 5243 <translation>Det aktuella spelet letar ej efter amiibos</translation>
5244 </message> 5244 </message>
5245 <message> 5245 <message>
5246 <location filename="../../src/yuzu/main.cpp" line="3723"/> 5246 <location filename="../../src/yuzu/main.cpp" line="3723"/>
@@ -5260,17 +5260,17 @@ Please, only use this feature to install updates and DLC.</source>
5260 <message> 5260 <message>
5261 <location filename="../../src/yuzu/main.cpp" line="3746"/> 5261 <location filename="../../src/yuzu/main.cpp" line="3746"/>
5262 <source>The selected file is not a valid amiibo</source> 5262 <source>The selected file is not a valid amiibo</source>
5263 <translation type="unfinished"/> 5263 <translation>Den valda filen är inte en giltig amiibo</translation>
5264 </message> 5264 </message>
5265 <message> 5265 <message>
5266 <location filename="../../src/yuzu/main.cpp" line="3749"/> 5266 <location filename="../../src/yuzu/main.cpp" line="3749"/>
5267 <source>The selected file is already on use</source> 5267 <source>The selected file is already on use</source>
5268 <translation type="unfinished"/> 5268 <translation>Den valda filen är redan använd</translation>
5269 </message> 5269 </message>
5270 <message> 5270 <message>
5271 <location filename="../../src/yuzu/main.cpp" line="3755"/> 5271 <location filename="../../src/yuzu/main.cpp" line="3755"/>
5272 <source>An unknown error occurred</source> 5272 <source>An unknown error occurred</source>
5273 <translation type="unfinished"/> 5273 <translation>Ett okänt fel har inträffat</translation>
5274 </message> 5274 </message>
5275 <message> 5275 <message>
5276 <location filename="../../src/yuzu/main.cpp" line="3807"/> 5276 <location filename="../../src/yuzu/main.cpp" line="3807"/>
@@ -5285,22 +5285,22 @@ Please, only use this feature to install updates and DLC.</source>
5285 <message> 5285 <message>
5286 <location filename="../../src/yuzu/main.cpp" line="3891"/> 5286 <location filename="../../src/yuzu/main.cpp" line="3891"/>
5287 <source>TAS state: Running %1/%2</source> 5287 <source>TAS state: Running %1/%2</source>
5288 <translation type="unfinished"/> 5288 <translation>TAStillstånd: pågående %1/%2</translation>
5289 </message> 5289 </message>
5290 <message> 5290 <message>
5291 <location filename="../../src/yuzu/main.cpp" line="3895"/> 5291 <location filename="../../src/yuzu/main.cpp" line="3895"/>
5292 <source>TAS state: Recording %1</source> 5292 <source>TAS state: Recording %1</source>
5293 <translation type="unfinished"/> 5293 <translation>TAStillstånd: spelar in %1</translation>
5294 </message> 5294 </message>
5295 <message> 5295 <message>
5296 <location filename="../../src/yuzu/main.cpp" line="3897"/> 5296 <location filename="../../src/yuzu/main.cpp" line="3897"/>
5297 <source>TAS state: Idle %1/%2</source> 5297 <source>TAS state: Idle %1/%2</source>
5298 <translation type="unfinished"/> 5298 <translation>TAStillstånd: inaktiv %1/%2</translation>
5299 </message> 5299 </message>
5300 <message> 5300 <message>
5301 <location filename="../../src/yuzu/main.cpp" line="3901"/> 5301 <location filename="../../src/yuzu/main.cpp" line="3901"/>
5302 <source>TAS State: Invalid</source> 5302 <source>TAS State: Invalid</source>
5303 <translation type="unfinished"/> 5303 <translation>TAStillstånd: ogiltigt</translation>
5304 </message> 5304 </message>
5305 <message> 5305 <message>
5306 <location filename="../../src/yuzu/main.cpp" line="3915"/> 5306 <location filename="../../src/yuzu/main.cpp" line="3915"/>
@@ -5902,7 +5902,7 @@ Vill du strunta i detta och avsluta ändå?</translation>
5902 <message> 5902 <message>
5903 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="118"/> 5903 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="118"/>
5904 <source>Password</source> 5904 <source>Password</source>
5905 <translation type="unfinished"/> 5905 <translation>Lösenord</translation>
5906 </message> 5906 </message>
5907 <message> 5907 <message>
5908 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="125"/> 5908 <location filename="../../src/yuzu/multiplayer/host_room.ui" line="125"/>
@@ -6169,7 +6169,7 @@ Debug Message: </source>
6169 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="32"/> 6169 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="32"/>
6170 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="39"/> 6170 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="39"/>
6171 <source>Nickname</source> 6171 <source>Nickname</source>
6172 <translation type="unfinished"/> 6172 <translation>Smeknamn</translation>
6173 </message> 6173 </message>
6174 <message> 6174 <message>
6175 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="59"/> 6175 <location filename="../../src/yuzu/multiplayer/lobby.ui" line="59"/>
diff --git a/dist/languages/tr_TR.ts b/dist/languages/tr_TR.ts
index 98a7f479f..47a0ca9c8 100644
--- a/dist/languages/tr_TR.ts
+++ b/dist/languages/tr_TR.ts
@@ -1368,8 +1368,8 @@ Bu seçenek belleğe yazma/okuma işlemlerindeki güvenlik kontrolünü kaldıra
1368 </message> 1368 </message>
1369 <message> 1369 <message>
1370 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1370 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1371 <source>Extended memory layout (6GB DRAM)</source> 1371 <source>Extended memory layout (8GB DRAM)</source>
1372 <translation>Artırılmış hafıza düzeni (6GB DRAM)</translation> 1372 <translation type="unfinished"/>
1373 </message> 1373 </message>
1374 <message> 1374 <message>
1375 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1375 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/uk.ts b/dist/languages/uk.ts
index 02bdf2233..3c4e788f6 100644
--- a/dist/languages/uk.ts
+++ b/dist/languages/uk.ts
@@ -1346,8 +1346,8 @@ This would ban both their forum username and their IP address.</source>
1346 </message> 1346 </message>
1347 <message> 1347 <message>
1348 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1348 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1349 <source>Extended memory layout (6GB DRAM)</source> 1349 <source>Extended memory layout (8GB DRAM)</source>
1350 <translation>Розширене ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ð¼&apos;Ñті (6 ГБ DRAM)</translation> 1350 <translation type="unfinished"/>
1351 </message> 1351 </message>
1352 <message> 1352 <message>
1353 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1353 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/zh_CN.ts b/dist/languages/zh_CN.ts
index 9da8b0b32..2de1e921e 100644
--- a/dist/languages/zh_CN.ts
+++ b/dist/languages/zh_CN.ts
@@ -1380,8 +1380,8 @@ This would ban both their forum username and their IP address.</source>
1380 </message> 1380 </message>
1381 <message> 1381 <message>
1382 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1382 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1383 <source>Extended memory layout (6GB DRAM)</source> 1383 <source>Extended memory layout (8GB DRAM)</source>
1384 <translation>扩展的内存布局 (6GB DRAM)</translation> 1384 <translation>扩展的内存布局 (8GB DRAM)</translation>
1385 </message> 1385 </message>
1386 <message> 1386 <message>
1387 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1387 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/dist/languages/zh_TW.ts b/dist/languages/zh_TW.ts
index 472b00114..f6cd1934d 100644
--- a/dist/languages/zh_TW.ts
+++ b/dist/languages/zh_TW.ts
@@ -1382,8 +1382,8 @@ This would ban both their forum username and their IP address.</source>
1382 </message> 1382 </message>
1383 <message> 1383 <message>
1384 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> 1384 <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/>
1385 <source>Extended memory layout (6GB DRAM)</source> 1385 <source>Extended memory layout (8GB DRAM)</source>
1386 <translation>扩展的内存布局 (6GB DRAM)</translation> 1386 <translation>扩展的内存布局 (8GB DRAM)</translation>
1387 </message> 1387 </message>
1388 <message> 1388 <message>
1389 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> 1389 <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/>
diff --git a/externals/dynarmic b/externals/dynarmic
Subproject c08c5a9362bb224dc343c2f616c24df027dfdf1 Subproject 7da378033a7764f955516f75194856d87bbcd7a
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 312a49f42..5e3a74c0f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -113,6 +113,9 @@ else()
113 113
114 $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init> 114 $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
115 $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field> 115 $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
116 $<$<CXX_COMPILER_ID:Clang>:-Werror=shadow-uncaptured-local>
117 $<$<CXX_COMPILER_ID:Clang>:-Werror=implicit-fallthrough>
118 $<$<CXX_COMPILER_ID:Clang>:-Werror=type-limits>
116 $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init> 119 $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
117 $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field> 120 $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
118 ) 121 )
diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp
index ad869facb..53b258c4f 100644
--- a/src/audio_core/renderer/system.cpp
+++ b/src/audio_core/renderer/system.cpp
@@ -436,10 +436,7 @@ void System::Stop() {
436 } 436 }
437 437
438 if (execution_mode == ExecutionMode::Auto) { 438 if (execution_mode == ExecutionMode::Auto) {
439 // Should wait for the system to terminate here, but core timing (should have) already 439 terminate_event.Wait();
440 // stopped, so this isn't needed. Find a way to make this definite.
441
442 // terminate_event.Wait();
443 } 440 }
444} 441}
445 442
diff --git a/src/audio_core/sink/sdl2_sink.cpp b/src/audio_core/sink/sdl2_sink.cpp
index ee1a0652f..c1529d1f9 100644
--- a/src/audio_core/sink/sdl2_sink.cpp
+++ b/src/audio_core/sink/sdl2_sink.cpp
@@ -3,6 +3,7 @@
3 3
4#include <span> 4#include <span>
5#include <vector> 5#include <vector>
6#include <SDL.h>
6 7
7#include "audio_core/common/common.h" 8#include "audio_core/common/common.h"
8#include "audio_core/sink/sdl2_sink.h" 9#include "audio_core/sink/sdl2_sink.h"
@@ -10,16 +11,6 @@
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "core/core.h" 12#include "core/core.h"
12 13
13// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
14#ifdef __clang__
15#pragma clang diagnostic push
16#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
17#endif
18#include <SDL.h>
19#ifdef __clang__
20#pragma clang diagnostic pop
21#endif
22
23namespace AudioCore::Sink { 14namespace AudioCore::Sink {
24/** 15/**
25 * SDL sink stream, responsible for sinking samples to hardware. 16 * SDL sink stream, responsible for sinking samples to hardware.
diff --git a/src/common/address_space.inc b/src/common/address_space.inc
index 2195dabd5..1ee82df53 100644
--- a/src/common/address_space.inc
+++ b/src/common/address_space.inc
@@ -72,7 +72,7 @@ MAP_MEMBER(void)::MapLocked(VaType virt, PaType phys, VaType size, ExtraBlockInf
72 } 72 }
73 }()}; 73 }()};
74 74
75 if (block_end_predecessor->virt >= virt) { 75 if (block_end_predecessor != blocks.begin() && block_end_predecessor->virt >= virt) {
76 // If this block's start would be overlapped by the map then reuse it as a tail 76 // If this block's start would be overlapped by the map then reuse it as a tail
77 // block 77 // block
78 block_end_predecessor->virt = virt_end; 78 block_end_predecessor->virt = virt_end;
@@ -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/input.h b/src/common/input.h
index 51b277c1f..66fb15f0a 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -111,6 +111,8 @@ struct AnalogProperties {
111 float offset{}; 111 float offset{};
112 // Invert direction of the sensor data 112 // Invert direction of the sensor data
113 bool inverted{}; 113 bool inverted{};
114 // Invert the state if it's converted to a button
115 bool inverted_button{};
114 // Press once to activate, press again to release 116 // Press once to activate, press again to release
115 bool toggle{}; 117 bool toggle{};
116}; 118};
diff --git a/src/common/intrusive_list.h b/src/common/intrusive_list.h
new file mode 100644
index 000000000..d330dc1c2
--- /dev/null
+++ b/src/common/intrusive_list.h
@@ -0,0 +1,631 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/parent_of_member.h"
8
9namespace Common {
10
11// Forward declare implementation class for Node.
12namespace impl {
13
14class IntrusiveListImpl;
15
16}
17
18class IntrusiveListNode {
19 YUZU_NON_COPYABLE(IntrusiveListNode);
20
21private:
22 friend class impl::IntrusiveListImpl;
23
24 IntrusiveListNode* m_prev;
25 IntrusiveListNode* m_next;
26
27public:
28 constexpr IntrusiveListNode() : m_prev(this), m_next(this) {}
29
30 constexpr bool IsLinked() const {
31 return m_next != this;
32 }
33
34private:
35 constexpr void LinkPrev(IntrusiveListNode* node) {
36 // We can't link an already linked node.
37 ASSERT(!node->IsLinked());
38 this->SplicePrev(node, node);
39 }
40
41 constexpr void SplicePrev(IntrusiveListNode* first, IntrusiveListNode* last) {
42 // Splice a range into the list.
43 auto last_prev = last->m_prev;
44 first->m_prev = m_prev;
45 last_prev->m_next = this;
46 m_prev->m_next = first;
47 m_prev = last_prev;
48 }
49
50 constexpr void LinkNext(IntrusiveListNode* node) {
51 // We can't link an already linked node.
52 ASSERT(!node->IsLinked());
53 return this->SpliceNext(node, node);
54 }
55
56 constexpr void SpliceNext(IntrusiveListNode* first, IntrusiveListNode* last) {
57 // Splice a range into the list.
58 auto last_prev = last->m_prev;
59 first->m_prev = this;
60 last_prev->m_next = m_next;
61 m_next->m_prev = last_prev;
62 m_next = first;
63 }
64
65 constexpr void Unlink() {
66 this->Unlink(m_next);
67 }
68
69 constexpr void Unlink(IntrusiveListNode* last) {
70 // Unlink a node from a next node.
71 auto last_prev = last->m_prev;
72 m_prev->m_next = last;
73 last->m_prev = m_prev;
74 last_prev->m_next = this;
75 m_prev = last_prev;
76 }
77
78 constexpr IntrusiveListNode* GetPrev() {
79 return m_prev;
80 }
81
82 constexpr const IntrusiveListNode* GetPrev() const {
83 return m_prev;
84 }
85
86 constexpr IntrusiveListNode* GetNext() {
87 return m_next;
88 }
89
90 constexpr const IntrusiveListNode* GetNext() const {
91 return m_next;
92 }
93};
94// DEPRECATED: static_assert(std::is_literal_type<IntrusiveListNode>::value);
95
96namespace impl {
97
98class IntrusiveListImpl {
99 YUZU_NON_COPYABLE(IntrusiveListImpl);
100
101private:
102 IntrusiveListNode m_root_node;
103
104public:
105 template <bool Const>
106 class Iterator;
107
108 using value_type = IntrusiveListNode;
109 using size_type = size_t;
110 using difference_type = ptrdiff_t;
111 using pointer = value_type*;
112 using const_pointer = const value_type*;
113 using reference = value_type&;
114 using const_reference = const value_type&;
115 using iterator = Iterator<false>;
116 using const_iterator = Iterator<true>;
117 using reverse_iterator = std::reverse_iterator<iterator>;
118 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
119
120 template <bool Const>
121 class Iterator {
122 public:
123 using iterator_category = std::bidirectional_iterator_tag;
124 using value_type = typename IntrusiveListImpl::value_type;
125 using difference_type = typename IntrusiveListImpl::difference_type;
126 using pointer =
127 std::conditional_t<Const, IntrusiveListImpl::const_pointer, IntrusiveListImpl::pointer>;
128 using reference = std::conditional_t<Const, IntrusiveListImpl::const_reference,
129 IntrusiveListImpl::reference>;
130
131 private:
132 pointer m_node;
133
134 public:
135 constexpr explicit Iterator(pointer n) : m_node(n) {}
136
137 constexpr bool operator==(const Iterator& rhs) const {
138 return m_node == rhs.m_node;
139 }
140
141 constexpr pointer operator->() const {
142 return m_node;
143 }
144
145 constexpr reference operator*() const {
146 return *m_node;
147 }
148
149 constexpr Iterator& operator++() {
150 m_node = m_node->m_next;
151 return *this;
152 }
153
154 constexpr Iterator& operator--() {
155 m_node = m_node->m_prev;
156 return *this;
157 }
158
159 constexpr Iterator operator++(int) {
160 const Iterator it{*this};
161 ++(*this);
162 return it;
163 }
164
165 constexpr Iterator operator--(int) {
166 const Iterator it{*this};
167 --(*this);
168 return it;
169 }
170
171 constexpr operator Iterator<true>() const {
172 return Iterator<true>(m_node);
173 }
174
175 constexpr Iterator<false> GetNonConstIterator() const {
176 return Iterator<false>(const_cast<IntrusiveListImpl::pointer>(m_node));
177 }
178 };
179
180public:
181 constexpr IntrusiveListImpl() : m_root_node() {}
182
183 // Iterator accessors.
184 constexpr iterator begin() {
185 return iterator(m_root_node.GetNext());
186 }
187
188 constexpr const_iterator begin() const {
189 return const_iterator(m_root_node.GetNext());
190 }
191
192 constexpr iterator end() {
193 return iterator(std::addressof(m_root_node));
194 }
195
196 constexpr const_iterator end() const {
197 return const_iterator(std::addressof(m_root_node));
198 }
199
200 constexpr iterator iterator_to(reference v) {
201 // Only allow iterator_to for values in lists.
202 ASSERT(v.IsLinked());
203 return iterator(std::addressof(v));
204 }
205
206 constexpr const_iterator iterator_to(const_reference v) const {
207 // Only allow iterator_to for values in lists.
208 ASSERT(v.IsLinked());
209 return const_iterator(std::addressof(v));
210 }
211
212 // Content management.
213 constexpr bool empty() const {
214 return !m_root_node.IsLinked();
215 }
216
217 constexpr size_type size() const {
218 return static_cast<size_type>(std::distance(this->begin(), this->end()));
219 }
220
221 constexpr reference back() {
222 return *m_root_node.GetPrev();
223 }
224
225 constexpr const_reference back() const {
226 return *m_root_node.GetPrev();
227 }
228
229 constexpr reference front() {
230 return *m_root_node.GetNext();
231 }
232
233 constexpr const_reference front() const {
234 return *m_root_node.GetNext();
235 }
236
237 constexpr void push_back(reference node) {
238 m_root_node.LinkPrev(std::addressof(node));
239 }
240
241 constexpr void push_front(reference node) {
242 m_root_node.LinkNext(std::addressof(node));
243 }
244
245 constexpr void pop_back() {
246 m_root_node.GetPrev()->Unlink();
247 }
248
249 constexpr void pop_front() {
250 m_root_node.GetNext()->Unlink();
251 }
252
253 constexpr iterator insert(const_iterator pos, reference node) {
254 pos.GetNonConstIterator()->LinkPrev(std::addressof(node));
255 return iterator(std::addressof(node));
256 }
257
258 constexpr void splice(const_iterator pos, IntrusiveListImpl& o) {
259 splice_impl(pos, o.begin(), o.end());
260 }
261
262 constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first) {
263 const_iterator last(first);
264 std::advance(last, 1);
265 splice_impl(pos, first, last);
266 }
267
268 constexpr void splice(const_iterator pos, IntrusiveListImpl& o, const_iterator first,
269 const_iterator last) {
270 splice_impl(pos, first, last);
271 }
272
273 constexpr iterator erase(const_iterator pos) {
274 if (pos == this->end()) {
275 return this->end();
276 }
277 iterator it(pos.GetNonConstIterator());
278 (it++)->Unlink();
279 return it;
280 }
281
282 constexpr void clear() {
283 while (!this->empty()) {
284 this->pop_front();
285 }
286 }
287
288private:
289 constexpr void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) {
290 if (_first == _last) {
291 return;
292 }
293 iterator pos(_pos.GetNonConstIterator());
294 iterator first(_first.GetNonConstIterator());
295 iterator last(_last.GetNonConstIterator());
296 first->Unlink(std::addressof(*last));
297 pos->SplicePrev(std::addressof(*first), std::addressof(*first));
298 }
299};
300
301} // namespace impl
302
303template <class T, class Traits>
304class IntrusiveList {
305 YUZU_NON_COPYABLE(IntrusiveList);
306
307private:
308 impl::IntrusiveListImpl m_impl;
309
310public:
311 template <bool Const>
312 class Iterator;
313
314 using value_type = T;
315 using size_type = size_t;
316 using difference_type = ptrdiff_t;
317 using pointer = value_type*;
318 using const_pointer = const value_type*;
319 using reference = value_type&;
320 using const_reference = const value_type&;
321 using iterator = Iterator<false>;
322 using const_iterator = Iterator<true>;
323 using reverse_iterator = std::reverse_iterator<iterator>;
324 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
325
326 template <bool Const>
327 class Iterator {
328 public:
329 friend class Common::IntrusiveList<T, Traits>;
330
331 using ImplIterator =
332 std::conditional_t<Const, Common::impl::IntrusiveListImpl::const_iterator,
333 Common::impl::IntrusiveListImpl::iterator>;
334
335 using iterator_category = std::bidirectional_iterator_tag;
336 using value_type = typename IntrusiveList::value_type;
337 using difference_type = typename IntrusiveList::difference_type;
338 using pointer =
339 std::conditional_t<Const, IntrusiveList::const_pointer, IntrusiveList::pointer>;
340 using reference =
341 std::conditional_t<Const, IntrusiveList::const_reference, IntrusiveList::reference>;
342
343 private:
344 ImplIterator m_iterator;
345
346 private:
347 constexpr explicit Iterator(ImplIterator it) : m_iterator(it) {}
348
349 constexpr ImplIterator GetImplIterator() const {
350 return m_iterator;
351 }
352
353 public:
354 constexpr bool operator==(const Iterator& rhs) const {
355 return m_iterator == rhs.m_iterator;
356 }
357
358 constexpr pointer operator->() const {
359 return std::addressof(Traits::GetParent(*m_iterator));
360 }
361
362 constexpr reference operator*() const {
363 return Traits::GetParent(*m_iterator);
364 }
365
366 constexpr Iterator& operator++() {
367 ++m_iterator;
368 return *this;
369 }
370
371 constexpr Iterator& operator--() {
372 --m_iterator;
373 return *this;
374 }
375
376 constexpr Iterator operator++(int) {
377 const Iterator it{*this};
378 ++m_iterator;
379 return it;
380 }
381
382 constexpr Iterator operator--(int) {
383 const Iterator it{*this};
384 --m_iterator;
385 return it;
386 }
387
388 constexpr operator Iterator<true>() const {
389 return Iterator<true>(m_iterator);
390 }
391 };
392
393private:
394 static constexpr IntrusiveListNode& GetNode(reference ref) {
395 return Traits::GetNode(ref);
396 }
397
398 static constexpr IntrusiveListNode const& GetNode(const_reference ref) {
399 return Traits::GetNode(ref);
400 }
401
402 static constexpr reference GetParent(IntrusiveListNode& node) {
403 return Traits::GetParent(node);
404 }
405
406 static constexpr const_reference GetParent(IntrusiveListNode const& node) {
407 return Traits::GetParent(node);
408 }
409
410public:
411 constexpr IntrusiveList() : m_impl() {}
412
413 // Iterator accessors.
414 constexpr iterator begin() {
415 return iterator(m_impl.begin());
416 }
417
418 constexpr const_iterator begin() const {
419 return const_iterator(m_impl.begin());
420 }
421
422 constexpr iterator end() {
423 return iterator(m_impl.end());
424 }
425
426 constexpr const_iterator end() const {
427 return const_iterator(m_impl.end());
428 }
429
430 constexpr const_iterator cbegin() const {
431 return this->begin();
432 }
433
434 constexpr const_iterator cend() const {
435 return this->end();
436 }
437
438 constexpr reverse_iterator rbegin() {
439 return reverse_iterator(this->end());
440 }
441
442 constexpr const_reverse_iterator rbegin() const {
443 return const_reverse_iterator(this->end());
444 }
445
446 constexpr reverse_iterator rend() {
447 return reverse_iterator(this->begin());
448 }
449
450 constexpr const_reverse_iterator rend() const {
451 return const_reverse_iterator(this->begin());
452 }
453
454 constexpr const_reverse_iterator crbegin() const {
455 return this->rbegin();
456 }
457
458 constexpr const_reverse_iterator crend() const {
459 return this->rend();
460 }
461
462 constexpr iterator iterator_to(reference v) {
463 return iterator(m_impl.iterator_to(GetNode(v)));
464 }
465
466 constexpr const_iterator iterator_to(const_reference v) const {
467 return const_iterator(m_impl.iterator_to(GetNode(v)));
468 }
469
470 // Content management.
471 constexpr bool empty() const {
472 return m_impl.empty();
473 }
474
475 constexpr size_type size() const {
476 return m_impl.size();
477 }
478
479 constexpr reference back() {
480 return GetParent(m_impl.back());
481 }
482
483 constexpr const_reference back() const {
484 return GetParent(m_impl.back());
485 }
486
487 constexpr reference front() {
488 return GetParent(m_impl.front());
489 }
490
491 constexpr const_reference front() const {
492 return GetParent(m_impl.front());
493 }
494
495 constexpr void push_back(reference ref) {
496 m_impl.push_back(GetNode(ref));
497 }
498
499 constexpr void push_front(reference ref) {
500 m_impl.push_front(GetNode(ref));
501 }
502
503 constexpr void pop_back() {
504 m_impl.pop_back();
505 }
506
507 constexpr void pop_front() {
508 m_impl.pop_front();
509 }
510
511 constexpr iterator insert(const_iterator pos, reference ref) {
512 return iterator(m_impl.insert(pos.GetImplIterator(), GetNode(ref)));
513 }
514
515 constexpr void splice(const_iterator pos, IntrusiveList& o) {
516 m_impl.splice(pos.GetImplIterator(), o.m_impl);
517 }
518
519 constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first) {
520 m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator());
521 }
522
523 constexpr void splice(const_iterator pos, IntrusiveList& o, const_iterator first,
524 const_iterator last) {
525 m_impl.splice(pos.GetImplIterator(), o.m_impl, first.GetImplIterator(),
526 last.GetImplIterator());
527 }
528
529 constexpr iterator erase(const_iterator pos) {
530 return iterator(m_impl.erase(pos.GetImplIterator()));
531 }
532
533 constexpr void clear() {
534 m_impl.clear();
535 }
536};
537
538template <auto T, class Derived = Common::impl::GetParentType<T>>
539class IntrusiveListMemberTraits;
540
541template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
542class IntrusiveListMemberTraits<Member, Derived> {
543public:
544 using ListType = IntrusiveList<Derived, IntrusiveListMemberTraits>;
545
546private:
547 friend class IntrusiveList<Derived, IntrusiveListMemberTraits>;
548
549 static constexpr IntrusiveListNode& GetNode(Derived& parent) {
550 return parent.*Member;
551 }
552
553 static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
554 return parent.*Member;
555 }
556
557 static Derived& GetParent(IntrusiveListNode& node) {
558 return Common::GetParentReference<Member, Derived>(std::addressof(node));
559 }
560
561 static Derived const& GetParent(IntrusiveListNode const& node) {
562 return Common::GetParentReference<Member, Derived>(std::addressof(node));
563 }
564};
565
566template <auto T, class Derived = Common::impl::GetParentType<T>>
567class IntrusiveListMemberTraitsByNonConstexprOffsetOf;
568
569template <class Parent, IntrusiveListNode Parent::*Member, class Derived>
570class IntrusiveListMemberTraitsByNonConstexprOffsetOf<Member, Derived> {
571public:
572 using ListType = IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
573
574private:
575 friend class IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>;
576
577 static constexpr IntrusiveListNode& GetNode(Derived& parent) {
578 return parent.*Member;
579 }
580
581 static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
582 return parent.*Member;
583 }
584
585 static Derived& GetParent(IntrusiveListNode& node) {
586 return *reinterpret_cast<Derived*>(reinterpret_cast<char*>(std::addressof(node)) -
587 GetOffset());
588 }
589
590 static Derived const& GetParent(IntrusiveListNode const& node) {
591 return *reinterpret_cast<const Derived*>(
592 reinterpret_cast<const char*>(std::addressof(node)) - GetOffset());
593 }
594
595 static uintptr_t GetOffset() {
596 return reinterpret_cast<uintptr_t>(std::addressof(reinterpret_cast<Derived*>(0)->*Member));
597 }
598};
599
600template <class Derived>
601class IntrusiveListBaseNode : public IntrusiveListNode {};
602
603template <class Derived>
604class IntrusiveListBaseTraits {
605public:
606 using ListType = IntrusiveList<Derived, IntrusiveListBaseTraits>;
607
608private:
609 friend class IntrusiveList<Derived, IntrusiveListBaseTraits>;
610
611 static constexpr IntrusiveListNode& GetNode(Derived& parent) {
612 return static_cast<IntrusiveListNode&>(
613 static_cast<IntrusiveListBaseNode<Derived>&>(parent));
614 }
615
616 static constexpr IntrusiveListNode const& GetNode(Derived const& parent) {
617 return static_cast<const IntrusiveListNode&>(
618 static_cast<const IntrusiveListBaseNode<Derived>&>(parent));
619 }
620
621 static constexpr Derived& GetParent(IntrusiveListNode& node) {
622 return static_cast<Derived&>(static_cast<IntrusiveListBaseNode<Derived>&>(node));
623 }
624
625 static constexpr Derived const& GetParent(IntrusiveListNode const& node) {
626 return static_cast<const Derived&>(
627 static_cast<const IntrusiveListBaseNode<Derived>&>(node));
628 }
629};
630
631} // namespace Common
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 84955030b..db1774c71 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -45,6 +45,7 @@ void LogSettings() {
45 log_setting("System_LanguageIndex", values.language_index.GetValue()); 45 log_setting("System_LanguageIndex", values.language_index.GetValue());
46 log_setting("System_RegionIndex", values.region_index.GetValue()); 46 log_setting("System_RegionIndex", values.region_index.GetValue());
47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 47 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
48 log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue());
48 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 49 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
49 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue()); 50 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
50 log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue()); 51 log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
@@ -60,7 +61,8 @@ void LogSettings() {
60 log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue()); 61 log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
61 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); 62 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
62 log_setting("Renderer_AsyncASTC", values.async_astc.GetValue()); 63 log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
63 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 64 log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
65 log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue());
64 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue()); 66 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
65 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 67 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
66 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); 68 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
@@ -191,7 +193,7 @@ void RestoreGlobalState(bool is_powered_on) {
191 193
192 // Core 194 // Core
193 values.use_multi_core.SetGlobal(true); 195 values.use_multi_core.SetGlobal(true);
194 values.use_extended_memory_layout.SetGlobal(true); 196 values.use_unsafe_extended_memory_layout.SetGlobal(true);
195 197
196 // CPU 198 // CPU
197 values.cpu_accuracy.SetGlobal(true); 199 values.cpu_accuracy.SetGlobal(true);
@@ -205,6 +207,7 @@ void RestoreGlobalState(bool is_powered_on) {
205 // Renderer 207 // Renderer
206 values.fsr_sharpening_slider.SetGlobal(true); 208 values.fsr_sharpening_slider.SetGlobal(true);
207 values.renderer_backend.SetGlobal(true); 209 values.renderer_backend.SetGlobal(true);
210 values.async_presentation.SetGlobal(true);
208 values.renderer_force_max_clock.SetGlobal(true); 211 values.renderer_force_max_clock.SetGlobal(true);
209 values.vulkan_device.SetGlobal(true); 212 values.vulkan_device.SetGlobal(true);
210 values.fullscreen_mode.SetGlobal(true); 213 values.fullscreen_mode.SetGlobal(true);
@@ -221,11 +224,10 @@ void RestoreGlobalState(bool is_powered_on) {
221 values.nvdec_emulation.SetGlobal(true); 224 values.nvdec_emulation.SetGlobal(true);
222 values.accelerate_astc.SetGlobal(true); 225 values.accelerate_astc.SetGlobal(true);
223 values.async_astc.SetGlobal(true); 226 values.async_astc.SetGlobal(true);
224 values.use_vsync.SetGlobal(true); 227 values.use_reactive_flushing.SetGlobal(true);
225 values.shader_backend.SetGlobal(true); 228 values.shader_backend.SetGlobal(true);
226 values.use_asynchronous_shaders.SetGlobal(true); 229 values.use_asynchronous_shaders.SetGlobal(true);
227 values.use_fast_gpu_time.SetGlobal(true); 230 values.use_fast_gpu_time.SetGlobal(true);
228 values.use_pessimistic_flushes.SetGlobal(true);
229 values.use_vulkan_driver_pipeline_cache.SetGlobal(true); 231 values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
230 values.bg_red.SetGlobal(true); 232 values.bg_red.SetGlobal(true);
231 values.bg_green.SetGlobal(true); 233 values.bg_green.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index b77a1580a..f4eb4e3cd 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -16,6 +16,13 @@
16 16
17namespace Settings { 17namespace Settings {
18 18
19enum class VSyncMode : u32 {
20 Immediate = 0,
21 Mailbox = 1,
22 FIFO = 2,
23 FIFORelaxed = 3,
24};
25
19enum class RendererBackend : u32 { 26enum class RendererBackend : u32 {
20 OpenGL = 0, 27 OpenGL = 0,
21 Vulkan = 1, 28 Vulkan = 1,
@@ -388,7 +395,8 @@ struct Values {
388 395
389 // Core 396 // Core
390 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"}; 397 SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
391 SwitchableSetting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"}; 398 SwitchableSetting<bool> use_unsafe_extended_memory_layout{false,
399 "use_unsafe_extended_memory_layout"};
392 400
393 // Cpu 401 // Cpu
394 SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, 402 SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
@@ -422,6 +430,7 @@ struct Values {
422 // Renderer 430 // Renderer
423 SwitchableSetting<RendererBackend, true> renderer_backend{ 431 SwitchableSetting<RendererBackend, true> renderer_backend{
424 RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"}; 432 RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
433 SwitchableSetting<bool> async_presentation{false, "async_presentation"};
425 SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"}; 434 SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
426 Setting<bool> renderer_debug{false, "debug"}; 435 Setting<bool> renderer_debug{false, "debug"};
427 Setting<bool> renderer_shader_feedback{false, "shader_feedback"}; 436 Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
@@ -454,12 +463,13 @@ struct Values {
454 SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; 463 SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
455 SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"}; 464 SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
456 SwitchableSetting<bool> async_astc{false, "async_astc"}; 465 SwitchableSetting<bool> async_astc{false, "async_astc"};
457 SwitchableSetting<bool> use_vsync{true, "use_vsync"}; 466 Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate,
467 VSyncMode::FIFORelaxed, "use_vsync"};
468 SwitchableSetting<bool> use_reactive_flushing{true, "use_reactive_flushing"};
458 SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL, 469 SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL,
459 ShaderBackend::SPIRV, "shader_backend"}; 470 ShaderBackend::SPIRV, "shader_backend"};
460 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 471 SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
461 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 472 SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
462 SwitchableSetting<bool> use_pessimistic_flushes{false, "use_pessimistic_flushes"};
463 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true, 473 SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
464 "use_vulkan_driver_pipeline_cache"}; 474 "use_vulkan_driver_pipeline_cache"};
465 475
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 0e2095c45..b4885835d 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -259,6 +259,20 @@ public:
259 return *this; 259 return *this;
260 } 260 }
261 261
262 void RotateFromOrigin(float roll, float pitch, float yaw) {
263 float temp = y;
264 y = std::cos(roll) * y - std::sin(roll) * z;
265 z = std::sin(roll) * temp + std::cos(roll) * z;
266
267 temp = x;
268 x = std::cos(pitch) * x + std::sin(pitch) * z;
269 z = -std::sin(pitch) * temp + std::cos(pitch) * z;
270
271 temp = x;
272 x = std::cos(yaw) * x - std::sin(yaw) * y;
273 y = std::sin(yaw) * temp + std::cos(yaw) * y;
274 }
275
262 [[nodiscard]] constexpr T Length2() const { 276 [[nodiscard]] constexpr T Length2() const {
263 return x * x + y * y + z * z; 277 return x * x + y * y + z * z;
264 } 278 }
diff --git a/src/core/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 caa6a77be..b5f62690e 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -137,7 +137,7 @@ struct System::Impl {
137 device_memory = std::make_unique<Core::DeviceMemory>(); 137 device_memory = std::make_unique<Core::DeviceMemory>();
138 138
139 is_multicore = Settings::values.use_multi_core.GetValue(); 139 is_multicore = Settings::values.use_multi_core.GetValue();
140 extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); 140 extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
141 141
142 core_timing.SetMulticore(is_multicore); 142 core_timing.SetMulticore(is_multicore);
143 core_timing.Initialize([&system]() { system.RegisterHostThread(); }); 143 core_timing.Initialize([&system]() { system.RegisterHostThread(); });
@@ -169,7 +169,7 @@ struct System::Impl {
169 void ReinitializeIfNecessary(System& system) { 169 void ReinitializeIfNecessary(System& system) {
170 const bool must_reinitialize = 170 const bool must_reinitialize =
171 is_multicore != Settings::values.use_multi_core.GetValue() || 171 is_multicore != Settings::values.use_multi_core.GetValue() ||
172 extended_memory_layout != Settings::values.use_extended_memory_layout.GetValue(); 172 extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
173 173
174 if (!must_reinitialize) { 174 if (!must_reinitialize) {
175 return; 175 return;
@@ -178,7 +178,7 @@ struct System::Impl {
178 LOG_DEBUG(Kernel, "Re-initializing"); 178 LOG_DEBUG(Kernel, "Re-initializing");
179 179
180 is_multicore = Settings::values.use_multi_core.GetValue(); 180 is_multicore = Settings::values.use_multi_core.GetValue();
181 extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); 181 extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
182 182
183 Initialize(system); 183 Initialize(system);
184 } 184 }
@@ -293,6 +293,7 @@ struct System::Impl {
293 ASSERT(Kernel::KProcess::Initialize(main_process, system, "main", 293 ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
294 Kernel::KProcess::ProcessType::Userland, resource_limit) 294 Kernel::KProcess::ProcessType::Userland, resource_limit)
295 .IsSuccess()); 295 .IsSuccess());
296 Kernel::KProcess::Register(system.Kernel(), main_process);
296 kernel.MakeApplicationProcess(main_process); 297 kernel.MakeApplicationProcess(main_process);
297 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); 298 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
298 if (load_result != Loader::ResultStatus::Success) { 299 if (load_result != Loader::ResultStatus::Success) {
@@ -611,6 +612,10 @@ void System::PrepareReschedule(const u32 core_index) {
611 impl->kernel.PrepareReschedule(core_index); 612 impl->kernel.PrepareReschedule(core_index);
612} 613}
613 614
615size_t System::GetCurrentHostThreadID() const {
616 return impl->kernel.GetCurrentHostThreadID();
617}
618
614PerfStatsResults System::GetAndResetPerfStats() { 619PerfStatsResults System::GetAndResetPerfStats() {
615 return impl->GetAndResetPerfStats(); 620 return impl->GetAndResetPerfStats();
616} 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/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 a70f8807c..366880711 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -376,6 +376,7 @@ void EmulatedController::ReloadInput() {
376 motion.accel = emulated_motion.GetAcceleration(); 376 motion.accel = emulated_motion.GetAcceleration();
377 motion.gyro = emulated_motion.GetGyroscope(); 377 motion.gyro = emulated_motion.GetGyroscope();
378 motion.rotation = emulated_motion.GetRotations(); 378 motion.rotation = emulated_motion.GetRotations();
379 motion.euler = emulated_motion.GetEulerAngles();
379 motion.orientation = emulated_motion.GetOrientation(); 380 motion.orientation = emulated_motion.GetOrientation();
380 motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity); 381 motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
381 } 382 }
@@ -551,6 +552,8 @@ void EmulatedController::EnableSystemButtons() {
551void EmulatedController::DisableSystemButtons() { 552void EmulatedController::DisableSystemButtons() {
552 std::scoped_lock lock{mutex}; 553 std::scoped_lock lock{mutex};
553 system_buttons_enabled = false; 554 system_buttons_enabled = false;
555 controller.home_button_state.raw = 0;
556 controller.capture_button_state.raw = 0;
554} 557}
555 558
556void EmulatedController::ResetSystemButtons() { 559void EmulatedController::ResetSystemButtons() {
@@ -685,6 +688,12 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage
685 ReloadInput(); 688 ReloadInput();
686} 689}
687 690
691void EmulatedController::StartMotionCalibration() {
692 for (ControllerMotionInfo& motion : controller.motion_values) {
693 motion.emulated.Calibrate();
694 }
695}
696
688void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, 697void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
689 Common::UUID uuid) { 698 Common::UUID uuid) {
690 if (index >= controller.button_values.size()) { 699 if (index >= controller.button_values.size()) {
@@ -734,6 +743,8 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
734 if (is_configuring) { 743 if (is_configuring) {
735 controller.npad_button_state.raw = NpadButton::None; 744 controller.npad_button_state.raw = NpadButton::None;
736 controller.debug_pad_button_state.raw = 0; 745 controller.debug_pad_button_state.raw = 0;
746 controller.home_button_state.raw = 0;
747 controller.capture_button_state.raw = 0;
737 lock.unlock(); 748 lock.unlock();
738 TriggerOnChange(ControllerTriggerType::Button, false); 749 TriggerOnChange(ControllerTriggerType::Button, false);
739 return; 750 return;
@@ -974,16 +985,12 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
974 emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold); 985 emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold);
975 emulated.UpdateRotation(raw_status.delta_timestamp); 986 emulated.UpdateRotation(raw_status.delta_timestamp);
976 emulated.UpdateOrientation(raw_status.delta_timestamp); 987 emulated.UpdateOrientation(raw_status.delta_timestamp);
977 force_update_motion = raw_status.force_update;
978
979 if (is_configuring) {
980 return;
981 }
982 988
983 auto& motion = controller.motion_state[index]; 989 auto& motion = controller.motion_state[index];
984 motion.accel = emulated.GetAcceleration(); 990 motion.accel = emulated.GetAcceleration();
985 motion.gyro = emulated.GetGyroscope(); 991 motion.gyro = emulated.GetGyroscope();
986 motion.rotation = emulated.GetRotations(); 992 motion.rotation = emulated.GetRotations();
993 motion.euler = emulated.GetEulerAngles();
987 motion.orientation = emulated.GetOrientation(); 994 motion.orientation = emulated.GetOrientation();
988 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); 995 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
989} 996}
@@ -1616,19 +1623,6 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
1616 1623
1617MotionState EmulatedController::GetMotions() const { 1624MotionState EmulatedController::GetMotions() const {
1618 std::unique_lock lock{mutex}; 1625 std::unique_lock lock{mutex};
1619
1620 // Some drivers like mouse motion need constant refreshing
1621 if (force_update_motion) {
1622 for (auto& device : motion_devices) {
1623 if (!device) {
1624 continue;
1625 }
1626 lock.unlock();
1627 device->ForceUpdate();
1628 lock.lock();
1629 }
1630 }
1631
1632 return controller.motion_state; 1626 return controller.motion_state;
1633} 1627}
1634 1628
@@ -1694,8 +1688,21 @@ void EmulatedController::DeleteCallback(int key) {
1694 callback_list.erase(iterator); 1688 callback_list.erase(iterator);
1695} 1689}
1696 1690
1697void EmulatedController::TurboButtonUpdate() { 1691void EmulatedController::StatusUpdate() {
1698 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 }
1699} 1706}
1700 1707
1701NpadButton EmulatedController::GetTurboButtonMask() const { 1708NpadButton EmulatedController::GetTurboButtonMask() const {
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 429655355..88fad2f56 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -106,6 +106,7 @@ struct ControllerMotion {
106 Common::Vec3f accel{}; 106 Common::Vec3f accel{};
107 Common::Vec3f gyro{}; 107 Common::Vec3f gyro{};
108 Common::Vec3f rotation{}; 108 Common::Vec3f rotation{};
109 Common::Vec3f euler{};
109 std::array<Common::Vec3f, 3> orientation{}; 110 std::array<Common::Vec3f, 3> orientation{};
110 bool is_at_rest{}; 111 bool is_at_rest{};
111}; 112};
@@ -289,6 +290,9 @@ public:
289 */ 290 */
290 void SetMotionParam(std::size_t index, Common::ParamPackage param); 291 void SetMotionParam(std::size_t index, Common::ParamPackage param);
291 292
293 /// Auto calibrates the current motion devices
294 void StartMotionCalibration();
295
292 /// Returns the latest button status from the controller with parameters 296 /// Returns the latest button status from the controller with parameters
293 ButtonValues GetButtonsValues() const; 297 ButtonValues GetButtonsValues() const;
294 298
@@ -414,8 +418,8 @@ public:
414 */ 418 */
415 void DeleteCallback(int key); 419 void DeleteCallback(int key);
416 420
417 /// Swaps the state of the turbo buttons 421 /// Swaps the state of the turbo buttons and updates motion input
418 void TurboButtonUpdate(); 422 void StatusUpdate();
419 423
420private: 424private:
421 /// creates input devices from params 425 /// creates input devices from params
@@ -527,7 +531,6 @@ private:
527 bool is_configuring{false}; 531 bool is_configuring{false};
528 bool system_buttons_enabled{true}; 532 bool system_buttons_enabled{true};
529 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; 533 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
530 bool force_update_motion{false};
531 u32 turbo_button_state{0}; 534 u32 turbo_button_state{0};
532 535
533 // 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 7cee39a53..4ccb1c596 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -54,6 +54,7 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
54 case Common::Input::InputType::Analog: 54 case Common::Input::InputType::Analog:
55 status.value = TransformToTrigger(callback).pressed.value; 55 status.value = TransformToTrigger(callback).pressed.value;
56 status.toggle = callback.analog_status.properties.toggle; 56 status.toggle = callback.analog_status.properties.toggle;
57 status.inverted = callback.analog_status.properties.inverted_button;
57 break; 58 break;
58 case Common::Input::InputType::Trigger: 59 case Common::Input::InputType::Trigger:
59 status.value = TransformToTrigger(callback).pressed.value; 60 status.value = TransformToTrigger(callback).pressed.value;
@@ -61,6 +62,9 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
61 case Common::Input::InputType::Button: 62 case Common::Input::InputType::Button:
62 status = callback.button_status; 63 status = callback.button_status;
63 break; 64 break;
65 case Common::Input::InputType::Motion:
66 status.value = std::abs(callback.motion_status.gyro.x.raw_value) > 1.0f;
67 break;
64 default: 68 default:
65 LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type); 69 LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
66 break; 70 break;
@@ -82,7 +86,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
82 .range = 1.0f, 86 .range = 1.0f,
83 .offset = 0.0f, 87 .offset = 0.0f,
84 }; 88 };
85 status.delta_timestamp = 5000; 89 status.delta_timestamp = 1000;
86 status.force_update = true; 90 status.force_update = true;
87 status.accel.x = { 91 status.accel.x = {
88 .value = 0.0f, 92 .value = 0.0f,
@@ -226,6 +230,10 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta
226 status = callback.trigger_status; 230 status = callback.trigger_status;
227 calculate_button_value = false; 231 calculate_button_value = false;
228 break; 232 break;
233 case Common::Input::InputType::Motion:
234 status.analog.properties.range = 1.0f;
235 raw_value = callback.motion_status.accel.x.raw_value;
236 break;
229 default: 237 default:
230 LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type); 238 LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
231 break; 239 break;
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp
index 0dd66c1cc..f56f2ae1d 100644
--- a/src/core/hid/motion_input.cpp
+++ b/src/core/hid/motion_input.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <cmath>
5
4#include "common/math_util.h" 6#include "common/math_util.h"
5#include "core/hid/motion_input.h" 7#include "core/hid/motion_input.h"
6 8
@@ -35,11 +37,17 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
35 gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue); 37 gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue);
36 gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue); 38 gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue);
37 39
38 // Auto adjust drift to minimize drift 40 // Auto adjust gyro_bias to minimize drift
39 if (!IsMoving(IsAtRestRelaxed)) { 41 if (!IsMoving(IsAtRestRelaxed)) {
40 gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); 42 gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
41 } 43 }
42 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
43 if (gyro.Length() < gyro_threshold * user_gyro_threshold) { 51 if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
44 gyro = {}; 52 gyro = {};
45 } else { 53 } else {
@@ -51,6 +59,20 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
51 quat = quaternion; 59 quat = quaternion;
52} 60}
53 61
62void MotionInput::SetEulerAngles(const Common::Vec3f& euler_angles) {
63 const float cr = std::cos(euler_angles.x * 0.5f);
64 const float sr = std::sin(euler_angles.x * 0.5f);
65 const float cp = std::cos(euler_angles.y * 0.5f);
66 const float sp = std::sin(euler_angles.y * 0.5f);
67 const float cy = std::cos(euler_angles.z * 0.5f);
68 const float sy = std::sin(euler_angles.z * 0.5f);
69
70 quat.w = cr * cp * cy + sr * sp * sy;
71 quat.xyz.x = sr * cp * cy - cr * sp * sy;
72 quat.xyz.y = cr * sp * cy + sr * cp * sy;
73 quat.xyz.z = cr * cp * sy - sr * sp * cy;
74}
75
54void MotionInput::SetGyroBias(const Common::Vec3f& bias) { 76void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
55 gyro_bias = bias; 77 gyro_bias = bias;
56} 78}
@@ -91,6 +113,19 @@ void MotionInput::UpdateRotation(u64 elapsed_time) {
91 rotations += gyro * sample_period; 113 rotations += gyro * sample_period;
92} 114}
93 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
94// Based on Madgwick's implementation of Mayhony's AHRS algorithm. 129// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
95// 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
96void MotionInput::UpdateOrientation(u64 elapsed_time) { 131void MotionInput::UpdateOrientation(u64 elapsed_time) {
@@ -222,6 +257,26 @@ Common::Vec3f MotionInput::GetRotations() const {
222 return rotations; 257 return rotations;
223} 258}
224 259
260Common::Vec3f MotionInput::GetEulerAngles() const {
261 // roll (x-axis rotation)
262 const float sinr_cosp = 2 * (quat.w * quat.xyz.x + quat.xyz.y * quat.xyz.z);
263 const float cosr_cosp = 1 - 2 * (quat.xyz.x * quat.xyz.x + quat.xyz.y * quat.xyz.y);
264
265 // pitch (y-axis rotation)
266 const float sinp = std::sqrt(1 + 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
267 const float cosp = std::sqrt(1 - 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
268
269 // yaw (z-axis rotation)
270 const float siny_cosp = 2 * (quat.w * quat.xyz.z + quat.xyz.x * quat.xyz.y);
271 const float cosy_cosp = 1 - 2 * (quat.xyz.y * quat.xyz.y + quat.xyz.z * quat.xyz.z);
272
273 return {
274 std::atan2(sinr_cosp, cosr_cosp),
275 2 * std::atan2(sinp, cosp) - Common::PI / 2,
276 std::atan2(siny_cosp, cosy_cosp),
277 };
278}
279
225void MotionInput::ResetOrientation() { 280void MotionInput::ResetOrientation() {
226 if (!reset_enabled || only_accelerometer) { 281 if (!reset_enabled || only_accelerometer) {
227 return; 282 return;
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h
index 9f3fc1cf7..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;
@@ -35,6 +37,7 @@ public:
35 void SetAcceleration(const Common::Vec3f& acceleration); 37 void SetAcceleration(const Common::Vec3f& acceleration);
36 void SetGyroscope(const Common::Vec3f& gyroscope); 38 void SetGyroscope(const Common::Vec3f& gyroscope);
37 void SetQuaternion(const Common::Quaternion<f32>& quaternion); 39 void SetQuaternion(const Common::Quaternion<f32>& quaternion);
40 void SetEulerAngles(const Common::Vec3f& euler_angles);
38 void SetGyroBias(const Common::Vec3f& bias); 41 void SetGyroBias(const Common::Vec3f& bias);
39 void SetGyroThreshold(f32 threshold); 42 void SetGyroThreshold(f32 threshold);
40 43
@@ -48,17 +51,21 @@ public:
48 void UpdateRotation(u64 elapsed_time); 51 void UpdateRotation(u64 elapsed_time);
49 void UpdateOrientation(u64 elapsed_time); 52 void UpdateOrientation(u64 elapsed_time);
50 53
54 void Calibrate();
55
51 [[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const; 56 [[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
52 [[nodiscard]] Common::Vec3f GetAcceleration() const; 57 [[nodiscard]] Common::Vec3f GetAcceleration() const;
53 [[nodiscard]] Common::Vec3f GetGyroscope() const; 58 [[nodiscard]] Common::Vec3f GetGyroscope() const;
54 [[nodiscard]] Common::Vec3f GetGyroBias() const; 59 [[nodiscard]] Common::Vec3f GetGyroBias() const;
55 [[nodiscard]] Common::Vec3f GetRotations() const; 60 [[nodiscard]] Common::Vec3f GetRotations() const;
56 [[nodiscard]] Common::Quaternion<f32> GetQuaternion() const; 61 [[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
62 [[nodiscard]] Common::Vec3f GetEulerAngles() const;
57 63
58 [[nodiscard]] bool IsMoving(f32 sensitivity) const; 64 [[nodiscard]] bool IsMoving(f32 sensitivity) const;
59 [[nodiscard]] bool IsCalibrated(f32 sensitivity) const; 65 [[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
60 66
61private: 67private:
68 void StopCalibration();
62 void ResetOrientation(); 69 void ResetOrientation();
63 void SetOrientationFromAccelerometer(); 70 void SetOrientationFromAccelerometer();
64 71
@@ -101,6 +108,12 @@ private:
101 108
102 // Use accelerometer values to calculate position 109 // Use accelerometer values to calculate position
103 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;
104}; 117};
105 118
106} // namespace Core::HID 119} // namespace Core::HID
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
index 36d0d20d2..49bdc671e 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -35,12 +35,13 @@ namespace {
35using namespace Common::Literals; 35using namespace Common::Literals;
36 36
37u32 GetMemorySizeForInit() { 37u32 GetMemorySizeForInit() {
38 return Settings::values.use_extended_memory_layout ? Smc::MemorySize_8GB : Smc::MemorySize_4GB; 38 return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemorySize_8GB
39 : Smc::MemorySize_4GB;
39} 40}
40 41
41Smc::MemoryArrangement GetMemoryArrangeForInit() { 42Smc::MemoryArrangement GetMemoryArrangeForInit() {
42 return Settings::values.use_extended_memory_layout ? Smc::MemoryArrangement_8GB 43 return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemoryArrangement_8GB
43 : Smc::MemoryArrangement_4GB; 44 : Smc::MemoryArrangement_4GB;
44} 45}
45} // namespace 46} // namespace
46 47
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 9b71fe371..f384b1568 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -182,8 +182,8 @@ public:
182 explicit KAutoObjectWithList(KernelCore& kernel) : KAutoObject(kernel) {} 182 explicit KAutoObjectWithList(KernelCore& kernel) : KAutoObject(kernel) {}
183 183
184 static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) { 184 static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) {
185 const u64 lid = lhs.GetId(); 185 const uintptr_t lid = reinterpret_cast<uintptr_t>(std::addressof(lhs));
186 const u64 rid = rhs.GetId(); 186 const uintptr_t rid = reinterpret_cast<uintptr_t>(std::addressof(rhs));
187 187
188 if (lid < rid) { 188 if (lid < rid) {
189 return -1; 189 return -1;
diff --git a/src/core/hle/kernel/k_event_info.h b/src/core/hle/kernel/k_event_info.h
index 25b3ff594..eacfa5dc6 100644
--- a/src/core/hle/kernel/k_event_info.h
+++ b/src/core/hle/kernel/k_event_info.h
@@ -5,14 +5,15 @@
5 5
6#include <array> 6#include <array>
7 7
8#include <boost/intrusive/list.hpp> 8#include "common/intrusive_list.h"
9 9
10#include "core/hle/kernel/slab_helpers.h" 10#include "core/hle/kernel/slab_helpers.h"
11#include "core/hle/kernel/svc_types.h" 11#include "core/hle/kernel/svc_types.h"
12 12
13namespace Kernel { 13namespace Kernel {
14 14
15class KEventInfo : public KSlabAllocated<KEventInfo>, public boost::intrusive::list_base_hook<> { 15class KEventInfo : public KSlabAllocated<KEventInfo>,
16 public Common::IntrusiveListBaseNode<KEventInfo> {
16public: 17public:
17 struct InfoCreateThread { 18 struct InfoCreateThread {
18 u32 thread_id{}; 19 u32 thread_id{};
diff --git a/src/core/hle/kernel/k_object_name.h b/src/core/hle/kernel/k_object_name.h
index 2d97fc777..a8876fe37 100644
--- a/src/core/hle/kernel/k_object_name.h
+++ b/src/core/hle/kernel/k_object_name.h
@@ -5,7 +5,8 @@
5 5
6#include <array> 6#include <array>
7#include <memory> 7#include <memory>
8#include <boost/intrusive/list.hpp> 8
9#include "common/intrusive_list.h"
9 10
10#include "core/hle/kernel/k_light_lock.h" 11#include "core/hle/kernel/k_light_lock.h"
11#include "core/hle/kernel/slab_helpers.h" 12#include "core/hle/kernel/slab_helpers.h"
@@ -15,13 +16,14 @@ namespace Kernel {
15 16
16class KObjectNameGlobalData; 17class KObjectNameGlobalData;
17 18
18class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> { 19class KObjectName : public KSlabAllocated<KObjectName>,
20 public Common::IntrusiveListBaseNode<KObjectName> {
19public: 21public:
20 explicit KObjectName(KernelCore&) {} 22 explicit KObjectName(KernelCore&) {}
21 virtual ~KObjectName() = default; 23 virtual ~KObjectName() = default;
22 24
23 static constexpr size_t NameLengthMax = 12; 25 static constexpr size_t NameLengthMax = 12;
24 using List = boost::intrusive::list<KObjectName>; 26 using List = Common::IntrusiveListBaseTraits<KObjectName>::ListType;
25 27
26 static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name); 28 static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name);
27 static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name); 29 static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name);
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index 21c040e62..625280290 100644
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -7,7 +7,7 @@
7#include <string> 7#include <string>
8#include <utility> 8#include <utility>
9 9
10#include <boost/intrusive/list.hpp> 10#include "common/intrusive_list.h"
11 11
12#include "core/hle/kernel/k_server_session.h" 12#include "core/hle/kernel/k_server_session.h"
13#include "core/hle/kernel/k_synchronization_object.h" 13#include "core/hle/kernel/k_synchronization_object.h"
@@ -42,7 +42,7 @@ public:
42 bool IsSignaled() const override; 42 bool IsSignaled() const override;
43 43
44private: 44private:
45 using SessionList = boost::intrusive::list<KServerSession>; 45 using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType;
46 46
47 void CleanupSessions(); 47 void CleanupSessions();
48 48
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 5ee02f556..403891919 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -8,7 +8,7 @@
8#include <string> 8#include <string>
9#include <utility> 9#include <utility>
10 10
11#include <boost/intrusive/list.hpp> 11#include "common/intrusive_list.h"
12 12
13#include "core/hle/kernel/k_light_lock.h" 13#include "core/hle/kernel/k_light_lock.h"
14#include "core/hle/kernel/k_session_request.h" 14#include "core/hle/kernel/k_session_request.h"
@@ -27,7 +27,7 @@ class KSession;
27class KThread; 27class KThread;
28 28
29class KServerSession final : public KSynchronizationObject, 29class KServerSession final : public KSynchronizationObject,
30 public boost::intrusive::list_base_hook<> { 30 public Common::IntrusiveListBaseNode<KServerSession> {
31 KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); 31 KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
32 32
33 friend class ServiceThread; 33 friend class ServiceThread;
@@ -67,7 +67,8 @@ private:
67 KSession* m_parent{}; 67 KSession* m_parent{};
68 68
69 /// List of threads which are pending a reply. 69 /// List of threads which are pending a reply.
70 boost::intrusive::list<KSessionRequest> m_request_list{}; 70 using RequestList = Common::IntrusiveListBaseTraits<KSessionRequest>::ListType;
71 RequestList m_request_list{};
71 KSessionRequest* m_current_request{}; 72 KSessionRequest* m_current_request{};
72 73
73 KLightLock m_lock; 74 KLightLock m_lock;
diff --git a/src/core/hle/kernel/k_session_request.h b/src/core/hle/kernel/k_session_request.h
index b5f04907b..283669e0a 100644
--- a/src/core/hle/kernel/k_session_request.h
+++ b/src/core/hle/kernel/k_session_request.h
@@ -5,6 +5,8 @@
5 5
6#include <array> 6#include <array>
7 7
8#include "common/intrusive_list.h"
9
8#include "core/hle/kernel/k_auto_object.h" 10#include "core/hle/kernel/k_auto_object.h"
9#include "core/hle/kernel/k_event.h" 11#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_memory_block.h" 12#include "core/hle/kernel/k_memory_block.h"
@@ -16,7 +18,7 @@ namespace Kernel {
16 18
17class KSessionRequest final : public KSlabAllocated<KSessionRequest>, 19class KSessionRequest final : public KSlabAllocated<KSessionRequest>,
18 public KAutoObject, 20 public KAutoObject,
19 public boost::intrusive::list_base_hook<> { 21 public Common::IntrusiveListBaseNode<KSessionRequest> {
20 KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject); 22 KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject);
21 23
22public: 24public:
diff --git a/src/core/hle/kernel/k_shared_memory_info.h b/src/core/hle/kernel/k_shared_memory_info.h
index 75b73ba39..2d8ff20d6 100644
--- a/src/core/hle/kernel/k_shared_memory_info.h
+++ b/src/core/hle/kernel/k_shared_memory_info.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <boost/intrusive/list.hpp> 6#include "common/intrusive_list.h"
7 7
8#include "core/hle/kernel/slab_helpers.h" 8#include "core/hle/kernel/slab_helpers.h"
9 9
@@ -12,7 +12,7 @@ namespace Kernel {
12class KSharedMemory; 12class KSharedMemory;
13 13
14class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>, 14class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>,
15 public boost::intrusive::list_base_hook<> { 15 public Common::IntrusiveListBaseNode<KSharedMemoryInfo> {
16 16
17public: 17public:
18 explicit KSharedMemoryInfo(KernelCore&) {} 18 explicit KSharedMemoryInfo(KernelCore&) {}
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 9c1a41128..f9814ac8f 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -12,7 +12,7 @@
12#include <utility> 12#include <utility>
13#include <vector> 13#include <vector>
14 14
15#include <boost/intrusive/list.hpp> 15#include "common/intrusive_list.h"
16 16
17#include "common/intrusive_red_black_tree.h" 17#include "common/intrusive_red_black_tree.h"
18#include "common/spin_lock.h" 18#include "common/spin_lock.h"
@@ -119,7 +119,7 @@ s32 GetCurrentCoreId(KernelCore& kernel);
119Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel); 119Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel);
120 120
121class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, 121class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
122 public boost::intrusive::list_base_hook<>, 122 public Common::IntrusiveListBaseNode<KThread>,
123 public KTimerTask { 123 public KTimerTask {
124 KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); 124 KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
125 125
@@ -138,7 +138,7 @@ public:
138public: 138public:
139 using ThreadContext32 = Core::ARM_Interface::ThreadContext32; 139 using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
140 using ThreadContext64 = Core::ARM_Interface::ThreadContext64; 140 using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
141 using WaiterList = boost::intrusive::list<KThread>; 141 using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType;
142 142
143 /** 143 /**
144 * Gets the thread's current priority 144 * Gets the thread's current priority
@@ -750,8 +750,9 @@ private:
750 ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>; 750 ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
751 751
752public: 752public:
753 class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>, 753 class LockWithPriorityInheritanceInfo
754 public boost::intrusive::list_base_hook<> { 754 : public KSlabAllocated<LockWithPriorityInheritanceInfo>,
755 public Common::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> {
755 public: 756 public:
756 explicit LockWithPriorityInheritanceInfo(KernelCore&) {} 757 explicit LockWithPriorityInheritanceInfo(KernelCore&) {}
757 758
@@ -839,7 +840,7 @@ public:
839 840
840private: 841private:
841 using LockWithPriorityInheritanceInfoList = 842 using LockWithPriorityInheritanceInfoList =
842 boost::intrusive::list<LockWithPriorityInheritanceInfo>; 843 Common::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType;
843 844
844 ConditionVariableThreadTree* m_condvar_tree{}; 845 ConditionVariableThreadTree* m_condvar_tree{};
845 u64 m_condvar_key{}; 846 u64 m_condvar_key{};
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4f3366c9d..f33600ca5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -95,7 +95,7 @@ struct KernelCore::Impl {
95 pt_heap_region.GetSize()); 95 pt_heap_region.GetSize());
96 } 96 }
97 97
98 InitializeHackSharedMemory(); 98 InitializeHackSharedMemory(kernel);
99 RegisterHostThread(nullptr); 99 RegisterHostThread(nullptr);
100 } 100 }
101 101
@@ -216,10 +216,12 @@ struct KernelCore::Impl {
216 auto* main_thread{Kernel::KThread::Create(system.Kernel())}; 216 auto* main_thread{Kernel::KThread::Create(system.Kernel())};
217 main_thread->SetCurrentCore(core); 217 main_thread->SetCurrentCore(core);
218 ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, core).IsSuccess()); 218 ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, core).IsSuccess());
219 KThread::Register(system.Kernel(), main_thread);
219 220
220 auto* idle_thread{Kernel::KThread::Create(system.Kernel())}; 221 auto* idle_thread{Kernel::KThread::Create(system.Kernel())};
221 idle_thread->SetCurrentCore(core); 222 idle_thread->SetCurrentCore(core);
222 ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, core).IsSuccess()); 223 ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, core).IsSuccess());
224 KThread::Register(system.Kernel(), idle_thread);
223 225
224 schedulers[i]->Initialize(main_thread, idle_thread, core); 226 schedulers[i]->Initialize(main_thread, idle_thread, core);
225 } 227 }
@@ -230,6 +232,7 @@ struct KernelCore::Impl {
230 const Core::Timing::CoreTiming& core_timing) { 232 const Core::Timing::CoreTiming& core_timing) {
231 system_resource_limit = KResourceLimit::Create(system.Kernel()); 233 system_resource_limit = KResourceLimit::Create(system.Kernel());
232 system_resource_limit->Initialize(&core_timing); 234 system_resource_limit->Initialize(&core_timing);
235 KResourceLimit::Register(kernel, system_resource_limit);
233 236
234 const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()}; 237 const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()};
235 const auto total_size{sizes.first}; 238 const auto total_size{sizes.first};
@@ -355,6 +358,7 @@ struct KernelCore::Impl {
355 ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {}, 358 ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {},
356 core_id) 359 core_id)
357 .IsSuccess()); 360 .IsSuccess());
361 KThread::Register(system.Kernel(), shutdown_threads[core_id]);
358 } 362 }
359 } 363 }
360 364
@@ -729,7 +733,7 @@ struct KernelCore::Impl {
729 memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize()); 733 memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize());
730 } 734 }
731 735
732 void InitializeHackSharedMemory() { 736 void InitializeHackSharedMemory(KernelCore& kernel) {
733 // Setup memory regions for emulated processes 737 // Setup memory regions for emulated processes
734 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel 738 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel
735 constexpr std::size_t hid_size{0x40000}; 739 constexpr std::size_t hid_size{0x40000};
@@ -746,14 +750,23 @@ struct KernelCore::Impl {
746 750
747 hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 751 hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
748 Svc::MemoryPermission::Read, hid_size); 752 Svc::MemoryPermission::Read, hid_size);
753 KSharedMemory::Register(kernel, hid_shared_mem);
754
749 font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 755 font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
750 Svc::MemoryPermission::Read, font_size); 756 Svc::MemoryPermission::Read, font_size);
757 KSharedMemory::Register(kernel, font_shared_mem);
758
751 irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 759 irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
752 Svc::MemoryPermission::Read, irs_size); 760 Svc::MemoryPermission::Read, irs_size);
761 KSharedMemory::Register(kernel, irs_shared_mem);
762
753 time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 763 time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
754 Svc::MemoryPermission::Read, time_size); 764 Svc::MemoryPermission::Read, time_size);
765 KSharedMemory::Register(kernel, time_shared_mem);
766
755 hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 767 hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
756 Svc::MemoryPermission::Read, hidbus_size); 768 Svc::MemoryPermission::Read, hidbus_size);
769 KSharedMemory::Register(kernel, hidbus_shared_mem);
757 } 770 }
758 771
759 std::mutex registered_objects_lock; 772 std::mutex registered_objects_lock;
@@ -1072,12 +1085,15 @@ static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process,
1072 // Commit the thread reservation. 1085 // Commit the thread reservation.
1073 thread_reservation.Commit(); 1086 thread_reservation.Commit();
1074 1087
1088 // Register the thread.
1089 KThread::Register(kernel, thread);
1090
1075 return std::jthread( 1091 return std::jthread(
1076 [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] { 1092 [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] {
1077 // Set the thread name. 1093 // Set the thread name.
1078 Common::SetCurrentThreadName(thread_name.c_str()); 1094 Common::SetCurrentThreadName(thread_name.c_str());
1079 1095
1080 // Register the thread. 1096 // Set the thread as current.
1081 kernel.RegisterHostThread(thread); 1097 kernel.RegisterHostThread(thread);
1082 1098
1083 // Run the callback. 1099 // Run the callback.
@@ -1099,6 +1115,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
1099 // Ensure that we don't hold onto any extra references. 1115 // Ensure that we don't hold onto any extra references.
1100 SCOPE_EXIT({ process->Close(); }); 1116 SCOPE_EXIT({ process->Close(); });
1101 1117
1118 // Register the new process.
1119 KProcess::Register(*this, process);
1120
1102 // Run the host thread. 1121 // Run the host thread.
1103 return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func)); 1122 return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func));
1104} 1123}
@@ -1124,6 +1143,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
1124 // Ensure that we don't hold onto any extra references. 1143 // Ensure that we don't hold onto any extra references.
1125 SCOPE_EXIT({ process->Close(); }); 1144 SCOPE_EXIT({ process->Close(); });
1126 1145
1146 // Register the new process.
1147 KProcess::Register(*this, process);
1148
1127 // Reserve a new thread from the process resource limit. 1149 // Reserve a new thread from the process resource limit.
1128 KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax); 1150 KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax);
1129 ASSERT(thread_reservation.Succeeded()); 1151 ASSERT(thread_reservation.Succeeded());
@@ -1136,6 +1158,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
1136 // Commit the thread reservation. 1158 // Commit the thread reservation.
1137 thread_reservation.Commit(); 1159 thread_reservation.Commit();
1138 1160
1161 // Register the new thread.
1162 KThread::Register(*this, thread);
1163
1139 // Begin running the thread. 1164 // Begin running the thread.
1140 ASSERT(R_SUCCEEDED(thread->Run())); 1165 ASSERT(R_SUCCEEDED(thread->Run()));
1141} 1166}
diff --git a/src/core/hle/service/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/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 8abf71608..ef4aec4ea 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;
diff --git a/src/core/hle/service/ipc_helpers.h b/src/core/hle/service/ipc_helpers.h
index e4cb4e1f2..0e222362e 100644
--- a/src/core/hle/service/ipc_helpers.h
+++ b/src/core/hle/service/ipc_helpers.h
@@ -156,6 +156,7 @@ public:
156 156
157 auto* session = Kernel::KSession::Create(kernel); 157 auto* session = Kernel::KSession::Create(kernel);
158 session->Initialize(nullptr, 0); 158 session->Initialize(nullptr, 0);
159 Kernel::KSession::Register(kernel, session);
159 160
160 auto next_manager = std::make_shared<Service::SessionRequestManager>( 161 auto next_manager = std::make_shared<Service::SessionRequestManager>(
161 kernel, manager->GetServerManager()); 162 kernel, manager->GetServerManager());
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
index a39ce5212..6a313a03b 100644
--- a/src/core/hle/service/kernel_helpers.cpp
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -25,6 +25,9 @@ ServiceContext::ServiceContext(Core::System& system_, std::string name_)
25 Kernel::KProcess::ProcessType::KernelInternal, 25 Kernel::KProcess::ProcessType::KernelInternal,
26 kernel.GetSystemResourceLimit()) 26 kernel.GetSystemResourceLimit())
27 .IsSuccess()); 27 .IsSuccess());
28
29 // Register the process.
30 Kernel::KProcess::Register(kernel, process);
28 process_created = true; 31 process_created = true;
29} 32}
30 33
diff --git a/src/core/hle/service/mutex.cpp b/src/core/hle/service/mutex.cpp
index 07589a0f0..b0ff71d1b 100644
--- a/src/core/hle/service/mutex.cpp
+++ b/src/core/hle/service/mutex.cpp
@@ -12,6 +12,9 @@ Mutex::Mutex(Core::System& system) : m_system(system) {
12 m_event = Kernel::KEvent::Create(system.Kernel()); 12 m_event = Kernel::KEvent::Create(system.Kernel());
13 m_event->Initialize(nullptr); 13 m_event->Initialize(nullptr);
14 14
15 // Register the event.
16 Kernel::KEvent::Register(system.Kernel(), m_event);
17
15 ASSERT(R_SUCCEEDED(m_event->Signal())); 18 ASSERT(R_SUCCEEDED(m_event->Signal()));
16} 19}
17 20
diff --git a/src/core/hle/service/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..e5de65ce0 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{
@@ -54,9 +53,9 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
54 current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point; 53 current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point;
55} 54}
56 55
57NfpDevice::~NfpDevice() { 56NfcDevice::~NfcDevice() {
58 activate_event->Close(); 57 service_context.CloseEvent(activate_event);
59 deactivate_event->Close(); 58 service_context.CloseEvent(deactivate_event);
60 if (!is_controller_set) { 59 if (!is_controller_set) {
61 return; 60 return;
62 } 61 }
@@ -64,7 +63,7 @@ NfpDevice::~NfpDevice() {
64 is_controller_set = false; 63 is_controller_set = false;
65}; 64};
66 65
67void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { 66void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
68 if (!is_initalized) { 67 if (!is_initalized) {
69 return; 68 return;
70 } 69 }
@@ -92,14 +91,14 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
92 const auto nfc_status = npad_device->GetNfc(); 91 const auto nfc_status = npad_device->GetNfc();
93 switch (nfc_status.state) { 92 switch (nfc_status.state) {
94 case Common::Input::NfcState::NewAmiibo: 93 case Common::Input::NfcState::NewAmiibo:
95 LoadAmiibo(nfc_status.data); 94 LoadNfcTag(nfc_status.data);
96 break; 95 break;
97 case Common::Input::NfcState::AmiiboRemoved: 96 case Common::Input::NfcState::AmiiboRemoved:
98 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { 97 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
99 break; 98 break;
100 } 99 }
101 if (device_state != DeviceState::SearchingForTag) { 100 if (device_state != DeviceState::SearchingForTag) {
102 CloseAmiibo(); 101 CloseNfcTag();
103 } 102 }
104 break; 103 break;
105 default: 104 default:
@@ -107,28 +106,29 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
107 } 106 }
108} 107}
109 108
110bool NfpDevice::LoadAmiibo(std::span<const u8> data) { 109bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
111 if (device_state != DeviceState::SearchingForTag) { 110 if (device_state != DeviceState::SearchingForTag) {
112 LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state); 111 LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
113 return false; 112 return false;
114 } 113 }
115 114
116 if (data.size() != sizeof(EncryptedNTAG215File)) { 115 if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
117 LOG_ERROR(Service_NFP, "Not an amiibo, size={}", data.size()); 116 LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
118 return false; 117 return false;
119 } 118 }
120 119
121 // TODO: Filter by allowed_protocols here 120 mifare_data.resize(data.size());
121 memcpy(mifare_data.data(), data.data(), data.size());
122 122
123 memcpy(&tag_data, data.data(), sizeof(EncryptedNTAG215File)); 123 memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
124 is_plain_amiibo = AmiiboCrypto::IsAmiiboValid(tag_data); 124 is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
125 125
126 if (is_plain_amiibo) { 126 if (is_plain_amiibo) {
127 encrypted_tag_data = AmiiboCrypto::EncodedDataToNfcData(tag_data); 127 encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(tag_data);
128 LOG_INFO(Service_NFP, "Using plain amiibo"); 128 LOG_INFO(Service_NFP, "Using plain amiibo");
129 } else { 129 } else {
130 tag_data = {}; 130 tag_data = {};
131 memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); 131 memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
132 } 132 }
133 133
134 device_state = DeviceState::TagFound; 134 device_state = DeviceState::TagFound;
@@ -137,8 +137,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
137 return true; 137 return true;
138} 138}
139 139
140void NfpDevice::CloseAmiibo() { 140void NfcDevice::CloseNfcTag() {
141 LOG_INFO(Service_NFP, "Remove amiibo"); 141 LOG_INFO(Service_NFC, "Remove nfc tag");
142 142
143 if (device_state == DeviceState::TagMounted) { 143 if (device_state == DeviceState::TagMounted) {
144 Unmount(); 144 Unmount();
@@ -147,26 +147,28 @@ void NfpDevice::CloseAmiibo() {
147 device_state = DeviceState::TagRemoved; 147 device_state = DeviceState::TagRemoved;
148 encrypted_tag_data = {}; 148 encrypted_tag_data = {};
149 tag_data = {}; 149 tag_data = {};
150 mifare_data = {};
150 activate_event->GetReadableEvent().Clear(); 151 activate_event->GetReadableEvent().Clear();
151 deactivate_event->Signal(); 152 deactivate_event->Signal();
152} 153}
153 154
154Kernel::KReadableEvent& NfpDevice::GetActivateEvent() const { 155Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
155 return activate_event->GetReadableEvent(); 156 return activate_event->GetReadableEvent();
156} 157}
157 158
158Kernel::KReadableEvent& NfpDevice::GetDeactivateEvent() const { 159Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
159 return deactivate_event->GetReadableEvent(); 160 return deactivate_event->GetReadableEvent();
160} 161}
161 162
162void NfpDevice::Initialize() { 163void NfcDevice::Initialize() {
163 device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; 164 device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
164 encrypted_tag_data = {}; 165 encrypted_tag_data = {};
165 tag_data = {}; 166 tag_data = {};
167 mifare_data = {};
166 is_initalized = true; 168 is_initalized = true;
167} 169}
168 170
169void NfpDevice::Finalize() { 171void NfcDevice::Finalize() {
170 if (device_state == DeviceState::TagMounted) { 172 if (device_state == DeviceState::TagMounted) {
171 Unmount(); 173 Unmount();
172 } 174 }
@@ -177,17 +179,17 @@ void NfpDevice::Finalize() {
177 is_initalized = false; 179 is_initalized = false;
178} 180}
179 181
180Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { 182Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
181 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { 183 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
182 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 184 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
183 return WrongDeviceState; 185 return ResultWrongDeviceState;
184 } 186 }
185 187
186 if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, 188 if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
187 Common::Input::PollingMode::NFC) != 189 Common::Input::PollingMode::NFC) !=
188 Common::Input::DriverResult::Success) { 190 Common::Input::DriverResult::Success) {
189 LOG_ERROR(Service_NFP, "Nfc not supported"); 191 LOG_ERROR(Service_NFC, "Nfc not supported");
190 return NfcDisabled; 192 return ResultNfcDisabled;
191 } 193 }
192 194
193 device_state = DeviceState::SearchingForTag; 195 device_state = DeviceState::SearchingForTag;
@@ -195,7 +197,7 @@ Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
195 return ResultSuccess; 197 return ResultSuccess;
196} 198}
197 199
198Result NfpDevice::StopDetection() { 200Result NfcDevice::StopDetection() {
199 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, 201 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
200 Common::Input::PollingMode::Active); 202 Common::Input::PollingMode::Active);
201 203
@@ -204,7 +206,7 @@ Result NfpDevice::StopDetection() {
204 } 206 }
205 207
206 if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { 208 if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
207 CloseAmiibo(); 209 CloseNfcTag();
208 } 210 }
209 211
210 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { 212 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
@@ -212,94 +214,129 @@ Result NfpDevice::StopDetection() {
212 return ResultSuccess; 214 return ResultSuccess;
213 } 215 }
214 216
215 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 217 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
216 return WrongDeviceState; 218 return ResultWrongDeviceState;
217} 219}
218 220
219Result NfpDevice::Flush() { 221Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
220 if (device_state != DeviceState::TagMounted) { 222 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
221 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 223 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
222 if (device_state == DeviceState::TagRemoved) { 224 if (device_state == DeviceState::TagRemoved) {
223 return TagRemoved; 225 return ResultTagRemoved;
224 } 226 }
225 return WrongDeviceState; 227 return ResultWrongDeviceState;
226 } 228 }
227 229
228 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 230 if (is_mifare) {
229 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 231 tag_info = {
230 return WrongDeviceState; 232 .uuid = encrypted_tag_data.uuid.uid,
233 .uuid_extension = {},
234 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
235 .protocol = NfcProtocol::TypeA,
236 .tag_type = TagType::Type4,
237 };
238 return ResultSuccess;
231 } 239 }
232 240
233 auto& settings = tag_data.settings; 241 // Protocol and tag type may change here
234 242 tag_info = {
235 const auto& current_date = GetAmiiboDate(current_posix_time); 243 .uuid = encrypted_tag_data.uuid.uid,
236 if (settings.write_date.raw_date != current_date.raw_date) { 244 .uuid_extension = {},
237 settings.write_date = current_date; 245 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
238 UpdateSettingsCrc(); 246 .protocol = NfcProtocol::TypeA,
239 } 247 .tag_type = TagType::Type2,
248 };
240 249
241 tag_data.write_counter++; 250 return ResultSuccess;
251}
242 252
243 FlushWithBreak(BreakType::Normal); 253Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
254 std::span<MifareReadBlockData> read_block_data) const {
255 Result result = ResultSuccess;
244 256
245 is_data_moddified = false; 257 for (std::size_t i = 0; i < parameters.size(); i++) {
258 result = ReadMifare(parameters[i], read_block_data[i]);
259 if (result.IsError()) {
260 break;
261 }
262 }
246 263
247 return ResultSuccess; 264 return result;
248} 265}
249 266
250Result NfpDevice::FlushDebug() { 267Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
251 if (device_state != DeviceState::TagMounted) { 268 MifareReadBlockData& read_block_data) const {
269 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
270 read_block_data.sector_number = parameter.sector_number;
271
272 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
252 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 273 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
253 if (device_state == DeviceState::TagRemoved) { 274 if (device_state == DeviceState::TagRemoved) {
254 return TagRemoved; 275 return ResultTagRemoved;
255 } 276 }
256 return WrongDeviceState; 277 return ResultWrongDeviceState;
257 } 278 }
258 279
259 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 280 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
260 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 281 return Mifare::ResultReadError;
261 return WrongDeviceState;
262 } 282 }
263 283
264 tag_data.write_counter++; 284 // TODO: Use parameter.sector_key to read encrypted data
265 285 memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock));
266 FlushWithBreak(BreakType::Normal);
267
268 is_data_moddified = false;
269 286
270 return ResultSuccess; 287 return ResultSuccess;
271} 288}
272 289
273Result NfpDevice::FlushWithBreak(BreakType break_type) { 290Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
274 if (break_type != BreakType::Normal) { 291 Result result = ResultSuccess;
275 LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
276 return WrongDeviceState;
277 }
278 292
279 std::vector<u8> data(sizeof(EncryptedNTAG215File)); 293 for (std::size_t i = 0; i < parameters.size(); i++) {
280 if (is_plain_amiibo) { 294 result = WriteMifare(parameters[i]);
281 memcpy(data.data(), &tag_data, sizeof(tag_data)); 295 if (result.IsError()) {
282 } else { 296 break;
283 if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
284 LOG_ERROR(Service_NFP, "Failed to encode data");
285 return WriteAmiiboFailed;
286 } 297 }
287
288 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
289 } 298 }
290 299
291 if (!npad_device->WriteNfc(data)) { 300 if (!npad_device->WriteNfc(mifare_data)) {
292 LOG_ERROR(Service_NFP, "Error writing to file"); 301 LOG_ERROR(Service_NFP, "Error writing to file");
293 return WriteAmiiboFailed; 302 return Mifare::ResultReadError;
303 }
304
305 return result;
306}
307
308Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
309 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
310
311 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
312 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
313 if (device_state == DeviceState::TagRemoved) {
314 return ResultTagRemoved;
315 }
316 return ResultWrongDeviceState;
317 }
318
319 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
320 return Mifare::ResultReadError;
294 } 321 }
295 322
323 // TODO: Use parameter.sector_key to encrypt the data
324 memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock));
325
296 return ResultSuccess; 326 return ResultSuccess;
297} 327}
298 328
299Result NfpDevice::Mount(MountTarget mount_target_) { 329Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
330 std::span<const u8> command_data,
331 std::span<u8> out_data) {
332 // Not implemented
333 return ResultSuccess;
334}
335
336Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) {
300 if (device_state != DeviceState::TagFound) { 337 if (device_state != DeviceState::TagFound) {
301 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 338 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
302 return WrongDeviceState; 339 return ResultWrongDeviceState;
303 } 340 }
304 341
305 // The loaded amiibo is not encrypted 342 // The loaded amiibo is not encrypted
@@ -309,22 +346,22 @@ Result NfpDevice::Mount(MountTarget mount_target_) {
309 return ResultSuccess; 346 return ResultSuccess;
310 } 347 }
311 348
312 if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { 349 if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
313 LOG_ERROR(Service_NFP, "Not an amiibo"); 350 LOG_ERROR(Service_NFP, "Not an amiibo");
314 return NotAnAmiibo; 351 return ResultNotAnAmiibo;
315 } 352 }
316 353
317 // Mark amiibos as read only when keys are missing 354 // Mark amiibos as read only when keys are missing
318 if (!AmiiboCrypto::IsKeyAvailable()) { 355 if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
319 LOG_ERROR(Service_NFP, "No keys detected"); 356 LOG_ERROR(Service_NFP, "No keys detected");
320 device_state = DeviceState::TagMounted; 357 device_state = DeviceState::TagMounted;
321 mount_target = MountTarget::Rom; 358 mount_target = NFP::MountTarget::Rom;
322 return ResultSuccess; 359 return ResultSuccess;
323 } 360 }
324 361
325 if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { 362 if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
326 LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state); 363 LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
327 return CorruptedData; 364 return ResultCorruptedData;
328 } 365 }
329 366
330 device_state = DeviceState::TagMounted; 367 device_state = DeviceState::TagMounted;
@@ -332,13 +369,13 @@ Result NfpDevice::Mount(MountTarget mount_target_) {
332 return ResultSuccess; 369 return ResultSuccess;
333} 370}
334 371
335Result NfpDevice::Unmount() { 372Result NfcDevice::Unmount() {
336 if (device_state != DeviceState::TagMounted) { 373 if (device_state != DeviceState::TagMounted) {
337 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 374 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
338 if (device_state == DeviceState::TagRemoved) { 375 if (device_state == DeviceState::TagRemoved) {
339 return TagRemoved; 376 return ResultTagRemoved;
340 } 377 }
341 return WrongDeviceState; 378 return ResultWrongDeviceState;
342 } 379 }
343 380
344 // Save data before unloading the amiibo 381 // Save data before unloading the amiibo
@@ -347,43 +384,123 @@ Result NfpDevice::Unmount() {
347 } 384 }
348 385
349 device_state = DeviceState::TagFound; 386 device_state = DeviceState::TagFound;
350 mount_target = MountTarget::None; 387 mount_target = NFP::MountTarget::None;
351 is_app_area_open = false; 388 is_app_area_open = false;
352 389
353 return ResultSuccess; 390 return ResultSuccess;
354} 391}
355 392
356Result NfpDevice::GetTagInfo(TagInfo& tag_info) const { 393Result NfcDevice::Flush() {
357 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { 394 if (device_state != DeviceState::TagMounted) {
358 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 395 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
359 if (device_state == DeviceState::TagRemoved) { 396 if (device_state == DeviceState::TagRemoved) {
360 return TagRemoved; 397 return ResultTagRemoved;
361 } 398 }
362 return WrongDeviceState; 399 return ResultWrongDeviceState;
363 } 400 }
364 401
365 tag_info = { 402 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
366 .uuid = encrypted_tag_data.uuid.uid, 403 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
367 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), 404 return ResultWrongDeviceState;
368 .protocol = TagProtocol::TypeA, 405 }
369 .tag_type = TagType::Type2, 406
370 }; 407 auto& settings = tag_data.settings;
408
409 const auto& current_date = GetAmiiboDate(current_posix_time);
410 if (settings.write_date.raw_date != current_date.raw_date) {
411 settings.write_date = current_date;
412 UpdateSettingsCrc();
413 }
414
415 tag_data.write_counter++;
416
417 FlushWithBreak(NFP::BreakType::Normal);
418
419 is_data_moddified = false;
371 420
372 return ResultSuccess; 421 return ResultSuccess;
373} 422}
374 423
375Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { 424Result NfcDevice::FlushDebug() {
425 if (device_state != DeviceState::TagMounted) {
426 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
427 if (device_state == DeviceState::TagRemoved) {
428 return ResultTagRemoved;
429 }
430 return ResultWrongDeviceState;
431 }
432
433 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
434 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
435 return ResultWrongDeviceState;
436 }
437
438 tag_data.write_counter++;
439
440 FlushWithBreak(NFP::BreakType::Normal);
441
442 is_data_moddified = false;
443
444 return ResultSuccess;
445}
446
447Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
448 if (break_type != NFP::BreakType::Normal) {
449 LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
450 return ResultWrongDeviceState;
451 }
452
453 std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
454 if (is_plain_amiibo) {
455 memcpy(data.data(), &tag_data, sizeof(tag_data));
456 } else {
457 if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
458 LOG_ERROR(Service_NFP, "Failed to encode data");
459 return ResultWriteAmiiboFailed;
460 }
461
462 memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
463 }
464
465 if (!npad_device->WriteNfc(data)) {
466 LOG_ERROR(Service_NFP, "Error writing to file");
467 return ResultWriteAmiiboFailed;
468 }
469
470 return ResultSuccess;
471}
472
473Result NfcDevice::Restore() {
474 if (device_state != DeviceState::TagMounted) {
475 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
476 if (device_state == DeviceState::TagRemoved) {
477 return ResultTagRemoved;
478 }
479 return ResultWrongDeviceState;
480 }
481
482 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
483 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
484 return ResultWrongDeviceState;
485 }
486
487 // TODO: Load amiibo from backup on system
488 LOG_ERROR(Service_NFP, "Not Implemented");
489 return ResultSuccess;
490}
491
492Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
376 if (device_state != DeviceState::TagMounted) { 493 if (device_state != DeviceState::TagMounted) {
377 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 494 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
378 if (device_state == DeviceState::TagRemoved) { 495 if (device_state == DeviceState::TagRemoved) {
379 return TagRemoved; 496 return ResultTagRemoved;
380 } 497 }
381 return WrongDeviceState; 498 return ResultWrongDeviceState;
382 } 499 }
383 500
384 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 501 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
385 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 502 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
386 return WrongDeviceState; 503 return ResultWrongDeviceState;
387 } 504 }
388 505
389 const auto& settings = tag_data.settings; 506 const auto& settings = tag_data.settings;
@@ -393,18 +510,18 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const {
393 .last_write_date = settings.write_date.GetWriteDate(), 510 .last_write_date = settings.write_date.GetWriteDate(),
394 .write_counter = tag_data.write_counter, 511 .write_counter = tag_data.write_counter,
395 .version = tag_data.amiibo_version, 512 .version = tag_data.amiibo_version,
396 .application_area_size = sizeof(ApplicationArea), 513 .application_area_size = sizeof(NFP::ApplicationArea),
397 }; 514 };
398 return ResultSuccess; 515 return ResultSuccess;
399} 516}
400 517
401Result NfpDevice::GetModelInfo(ModelInfo& model_info) const { 518Result NfcDevice::GetModelInfo(NFP::ModelInfo& model_info) const {
402 if (device_state != DeviceState::TagMounted) { 519 if (device_state != DeviceState::TagMounted) {
403 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 520 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
404 if (device_state == DeviceState::TagRemoved) { 521 if (device_state == DeviceState::TagRemoved) {
405 return TagRemoved; 522 return ResultTagRemoved;
406 } 523 }
407 return WrongDeviceState; 524 return ResultWrongDeviceState;
408 } 525 }
409 526
410 const auto& model_info_data = encrypted_tag_data.user_memory.model_info; 527 const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
@@ -418,22 +535,22 @@ Result NfpDevice::GetModelInfo(ModelInfo& model_info) const {
418 return ResultSuccess; 535 return ResultSuccess;
419} 536}
420 537
421Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { 538Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const {
422 if (device_state != DeviceState::TagMounted) { 539 if (device_state != DeviceState::TagMounted) {
423 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 540 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
424 if (device_state == DeviceState::TagRemoved) { 541 if (device_state == DeviceState::TagRemoved) {
425 return TagRemoved; 542 return ResultTagRemoved;
426 } 543 }
427 return WrongDeviceState; 544 return ResultWrongDeviceState;
428 } 545 }
429 546
430 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 547 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
431 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 548 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
432 return WrongDeviceState; 549 return ResultWrongDeviceState;
433 } 550 }
434 551
435 if (tag_data.settings.settings.amiibo_initialized == 0) { 552 if (tag_data.settings.settings.amiibo_initialized == 0) {
436 return RegistrationIsNotInitialized; 553 return ResultRegistrationIsNotInitialized;
437 } 554 }
438 555
439 Service::Mii::MiiManager manager; 556 Service::Mii::MiiManager manager;
@@ -450,22 +567,22 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const {
450 return ResultSuccess; 567 return ResultSuccess;
451} 568}
452 569
453Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const { 570Result NfcDevice::GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const {
454 if (device_state != DeviceState::TagMounted) { 571 if (device_state != DeviceState::TagMounted) {
455 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 572 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
456 if (device_state == DeviceState::TagRemoved) { 573 if (device_state == DeviceState::TagRemoved) {
457 return TagRemoved; 574 return ResultTagRemoved;
458 } 575 }
459 return WrongDeviceState; 576 return ResultWrongDeviceState;
460 } 577 }
461 578
462 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 579 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
463 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 580 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
464 return WrongDeviceState; 581 return ResultWrongDeviceState;
465 } 582 }
466 583
467 if (tag_data.settings.settings.amiibo_initialized == 0) { 584 if (tag_data.settings.settings.amiibo_initialized == 0) {
468 return RegistrationIsNotInitialized; 585 return ResultRegistrationIsNotInitialized;
469 } 586 }
470 587
471 Service::Mii::MiiManager manager; 588 Service::Mii::MiiManager manager;
@@ -482,18 +599,18 @@ Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) con
482 return ResultSuccess; 599 return ResultSuccess;
483} 600}
484 601
485Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { 602Result NfcDevice::GetAdminInfo(NFP::AdminInfo& admin_info) const {
486 if (device_state != DeviceState::TagMounted) { 603 if (device_state != DeviceState::TagMounted) {
487 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 604 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
488 if (device_state == DeviceState::TagRemoved) { 605 if (device_state == DeviceState::TagRemoved) {
489 return TagRemoved; 606 return ResultTagRemoved;
490 } 607 }
491 return WrongDeviceState; 608 return ResultWrongDeviceState;
492 } 609 }
493 610
494 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 611 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
495 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 612 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
496 return WrongDeviceState; 613 return ResultWrongDeviceState;
497 } 614 }
498 615
499 u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4); 616 u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4);
@@ -503,17 +620,18 @@ Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
503 620
504 u64 application_id = 0; 621 u64 application_id = 0;
505 u32 application_area_id = 0; 622 u32 application_area_id = 0;
506 AppAreaVersion app_area_version = AppAreaVersion::NotSet; 623 NFP::AppAreaVersion app_area_version = NFP::AppAreaVersion::NotSet;
507 if (tag_data.settings.settings.appdata_initialized != 0) { 624 if (tag_data.settings.settings.appdata_initialized != 0) {
508 application_id = tag_data.application_id; 625 application_id = tag_data.application_id;
509 app_area_version = 626 app_area_version = static_cast<NFP::AppAreaVersion>(
510 static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf); 627 application_id >> NFP::application_id_version_offset & 0xf);
511 628
512 // Restore application id to original value 629 // Restore application id to original value
513 if (application_id >> 0x38 != 0) { 630 if (application_id >> 0x38 != 0) {
514 const u8 application_byte = tag_data.application_id_byte & 0xf; 631 const u8 application_byte = tag_data.application_id_byte & 0xf;
515 application_id = RemoveVersionByte(application_id) | 632 application_id =
516 (static_cast<u64>(application_byte) << application_id_version_offset); 633 RemoveVersionByte(application_id) |
634 (static_cast<u64>(application_byte) << NFP::application_id_version_offset);
517 } 635 }
518 636
519 application_area_id = tag_data.application_area_id; 637 application_area_id = tag_data.application_area_id;
@@ -532,22 +650,22 @@ Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
532 return ResultSuccess; 650 return ResultSuccess;
533} 651}
534 652
535Result NfpDevice::DeleteRegisterInfo() { 653Result NfcDevice::DeleteRegisterInfo() {
536 if (device_state != DeviceState::TagMounted) { 654 if (device_state != DeviceState::TagMounted) {
537 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 655 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
538 if (device_state == DeviceState::TagRemoved) { 656 if (device_state == DeviceState::TagRemoved) {
539 return TagRemoved; 657 return ResultTagRemoved;
540 } 658 }
541 return WrongDeviceState; 659 return ResultWrongDeviceState;
542 } 660 }
543 661
544 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 662 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
545 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 663 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
546 return WrongDeviceState; 664 return ResultWrongDeviceState;
547 } 665 }
548 666
549 if (tag_data.settings.settings.amiibo_initialized == 0) { 667 if (tag_data.settings.settings.amiibo_initialized == 0) {
550 return RegistrationIsNotInitialized; 668 return ResultRegistrationIsNotInitialized;
551 } 669 }
552 670
553 Common::TinyMT rng{}; 671 Common::TinyMT rng{};
@@ -564,18 +682,18 @@ Result NfpDevice::DeleteRegisterInfo() {
564 return Flush(); 682 return Flush();
565} 683}
566 684
567Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) { 685Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info) {
568 if (device_state != DeviceState::TagMounted) { 686 if (device_state != DeviceState::TagMounted) {
569 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 687 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
570 if (device_state == DeviceState::TagRemoved) { 688 if (device_state == DeviceState::TagRemoved) {
571 return TagRemoved; 689 return ResultTagRemoved;
572 } 690 }
573 return WrongDeviceState; 691 return ResultWrongDeviceState;
574 } 692 }
575 693
576 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 694 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
577 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 695 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
578 return WrongDeviceState; 696 return ResultWrongDeviceState;
579 } 697 }
580 698
581 Service::Mii::MiiManager manager; 699 Service::Mii::MiiManager manager;
@@ -587,7 +705,7 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
587 settings.write_date.raw_date = 0; 705 settings.write_date.raw_date = 0;
588 } 706 }
589 707
590 SetAmiiboName(settings, amiibo_name); 708 SetAmiiboName(settings, register_info.amiibo_name);
591 tag_data.owner_mii = manager.BuildFromStoreData(mii); 709 tag_data.owner_mii = manager.BuildFromStoreData(mii);
592 tag_data.mii_extension = manager.SetFromStoreData(mii); 710 tag_data.mii_extension = manager.SetFromStoreData(mii);
593 tag_data.unknown = 0; 711 tag_data.unknown = 0;
@@ -601,18 +719,18 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
601 return Flush(); 719 return Flush();
602} 720}
603 721
604Result NfpDevice::RestoreAmiibo() { 722Result NfcDevice::RestoreAmiibo() {
605 if (device_state != DeviceState::TagMounted) { 723 if (device_state != DeviceState::TagMounted) {
606 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 724 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
607 if (device_state == DeviceState::TagRemoved) { 725 if (device_state == DeviceState::TagRemoved) {
608 return TagRemoved; 726 return ResultTagRemoved;
609 } 727 }
610 return WrongDeviceState; 728 return ResultWrongDeviceState;
611 } 729 }
612 730
613 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 731 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
614 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 732 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
615 return WrongDeviceState; 733 return ResultWrongDeviceState;
616 } 734 }
617 735
618 // TODO: Load amiibo from backup on system 736 // TODO: Load amiibo from backup on system
@@ -620,7 +738,7 @@ Result NfpDevice::RestoreAmiibo() {
620 return ResultSuccess; 738 return ResultSuccess;
621} 739}
622 740
623Result NfpDevice::Format() { 741Result NfcDevice::Format() {
624 auto result1 = DeleteApplicationArea(); 742 auto result1 = DeleteApplicationArea();
625 auto result2 = DeleteRegisterInfo(); 743 auto result2 = DeleteRegisterInfo();
626 744
@@ -635,28 +753,28 @@ Result NfpDevice::Format() {
635 return Flush(); 753 return Flush();
636} 754}
637 755
638Result NfpDevice::OpenApplicationArea(u32 access_id) { 756Result NfcDevice::OpenApplicationArea(u32 access_id) {
639 if (device_state != DeviceState::TagMounted) { 757 if (device_state != DeviceState::TagMounted) {
640 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 758 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
641 if (device_state == DeviceState::TagRemoved) { 759 if (device_state == DeviceState::TagRemoved) {
642 return TagRemoved; 760 return ResultTagRemoved;
643 } 761 }
644 return WrongDeviceState; 762 return ResultWrongDeviceState;
645 } 763 }
646 764
647 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 765 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
648 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 766 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
649 return WrongDeviceState; 767 return ResultWrongDeviceState;
650 } 768 }
651 769
652 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 770 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
653 LOG_WARNING(Service_NFP, "Application area is not initialized"); 771 LOG_WARNING(Service_NFP, "Application area is not initialized");
654 return ApplicationAreaIsNotInitialized; 772 return ResultApplicationAreaIsNotInitialized;
655 } 773 }
656 774
657 if (tag_data.application_area_id != access_id) { 775 if (tag_data.application_area_id != access_id) {
658 LOG_WARNING(Service_NFP, "Wrong application area id"); 776 LOG_WARNING(Service_NFP, "Wrong application area id");
659 return WrongApplicationAreaId; 777 return ResultWrongApplicationAreaId;
660 } 778 }
661 779
662 is_app_area_open = true; 780 is_app_area_open = true;
@@ -664,25 +782,25 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) {
664 return ResultSuccess; 782 return ResultSuccess;
665} 783}
666 784
667Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { 785Result NfcDevice::GetApplicationAreaId(u32& application_area_id) const {
668 application_area_id = {}; 786 application_area_id = {};
669 787
670 if (device_state != DeviceState::TagMounted) { 788 if (device_state != DeviceState::TagMounted) {
671 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 789 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
672 if (device_state == DeviceState::TagRemoved) { 790 if (device_state == DeviceState::TagRemoved) {
673 return TagRemoved; 791 return ResultTagRemoved;
674 } 792 }
675 return WrongDeviceState; 793 return ResultWrongDeviceState;
676 } 794 }
677 795
678 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 796 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
679 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 797 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
680 return WrongDeviceState; 798 return ResultWrongDeviceState;
681 } 799 }
682 800
683 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 801 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
684 LOG_WARNING(Service_NFP, "Application area is not initialized"); 802 LOG_WARNING(Service_NFP, "Application area is not initialized");
685 return ApplicationAreaIsNotInitialized; 803 return ResultApplicationAreaIsNotInitialized;
686 } 804 }
687 805
688 application_area_id = tag_data.application_area_id; 806 application_area_id = tag_data.application_area_id;
@@ -690,64 +808,61 @@ Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
690 return ResultSuccess; 808 return ResultSuccess;
691} 809}
692 810
693Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { 811Result NfcDevice::GetApplicationArea(std::span<u8> data) const {
694 if (device_state != DeviceState::TagMounted) { 812 if (device_state != DeviceState::TagMounted) {
695 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 813 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
696 if (device_state == DeviceState::TagRemoved) { 814 if (device_state == DeviceState::TagRemoved) {
697 return TagRemoved; 815 return ResultTagRemoved;
698 } 816 }
699 return WrongDeviceState; 817 return ResultWrongDeviceState;
700 } 818 }
701 819
702 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 820 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
703 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 821 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
704 return WrongDeviceState; 822 return ResultWrongDeviceState;
705 } 823 }
706 824
707 if (!is_app_area_open) { 825 if (!is_app_area_open) {
708 LOG_ERROR(Service_NFP, "Application area is not open"); 826 LOG_ERROR(Service_NFP, "Application area is not open");
709 return WrongDeviceState; 827 return ResultWrongDeviceState;
710 } 828 }
711 829
712 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 830 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
713 LOG_ERROR(Service_NFP, "Application area is not initialized"); 831 LOG_ERROR(Service_NFP, "Application area is not initialized");
714 return ApplicationAreaIsNotInitialized; 832 return ResultApplicationAreaIsNotInitialized;
715 }
716
717 if (data.size() > sizeof(ApplicationArea)) {
718 data.resize(sizeof(ApplicationArea));
719 } 833 }
720 834
721 memcpy(data.data(), tag_data.application_area.data(), data.size()); 835 memcpy(data.data(), tag_data.application_area.data(),
836 std::min(data.size(), sizeof(NFP::ApplicationArea)));
722 837
723 return ResultSuccess; 838 return ResultSuccess;
724} 839}
725 840
726Result NfpDevice::SetApplicationArea(std::span<const u8> data) { 841Result NfcDevice::SetApplicationArea(std::span<const u8> data) {
727 if (device_state != DeviceState::TagMounted) { 842 if (device_state != DeviceState::TagMounted) {
728 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 843 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
729 if (device_state == DeviceState::TagRemoved) { 844 if (device_state == DeviceState::TagRemoved) {
730 return TagRemoved; 845 return ResultTagRemoved;
731 } 846 }
732 return WrongDeviceState; 847 return ResultWrongDeviceState;
733 } 848 }
734 849
735 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 850 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
736 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 851 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
737 return WrongDeviceState; 852 return ResultWrongDeviceState;
738 } 853 }
739 854
740 if (!is_app_area_open) { 855 if (!is_app_area_open) {
741 LOG_ERROR(Service_NFP, "Application area is not open"); 856 LOG_ERROR(Service_NFP, "Application area is not open");
742 return WrongDeviceState; 857 return ResultWrongDeviceState;
743 } 858 }
744 859
745 if (tag_data.settings.settings.appdata_initialized.Value() == 0) { 860 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
746 LOG_ERROR(Service_NFP, "Application area is not initialized"); 861 LOG_ERROR(Service_NFP, "Application area is not initialized");
747 return ApplicationAreaIsNotInitialized; 862 return ResultApplicationAreaIsNotInitialized;
748 } 863 }
749 864
750 if (data.size() > sizeof(ApplicationArea)) { 865 if (data.size() > sizeof(NFP::ApplicationArea)) {
751 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size()); 866 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
752 return ResultUnknown; 867 return ResultUnknown;
753 } 868 }
@@ -756,9 +871,9 @@ Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
756 std::memcpy(tag_data.application_area.data(), data.data(), data.size()); 871 std::memcpy(tag_data.application_area.data(), data.data(), data.size());
757 // Fill remaining data with random numbers 872 // Fill remaining data with random numbers
758 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), 873 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
759 sizeof(ApplicationArea) - data.size()); 874 sizeof(NFP::ApplicationArea) - data.size());
760 875
761 if (tag_data.application_write_counter != counter_limit) { 876 if (tag_data.application_write_counter != NFP::counter_limit) {
762 tag_data.application_write_counter++; 877 tag_data.application_write_counter++;
763 } 878 }
764 879
@@ -767,64 +882,64 @@ Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
767 return ResultSuccess; 882 return ResultSuccess;
768} 883}
769 884
770Result NfpDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) { 885Result NfcDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
771 if (device_state != DeviceState::TagMounted) { 886 if (device_state != DeviceState::TagMounted) {
772 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 887 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
773 if (device_state == DeviceState::TagRemoved) { 888 if (device_state == DeviceState::TagRemoved) {
774 return TagRemoved; 889 return ResultTagRemoved;
775 } 890 }
776 return WrongDeviceState; 891 return ResultWrongDeviceState;
777 } 892 }
778 893
779 if (tag_data.settings.settings.appdata_initialized.Value() != 0) { 894 if (tag_data.settings.settings.appdata_initialized.Value() != 0) {
780 LOG_ERROR(Service_NFP, "Application area already exist"); 895 LOG_ERROR(Service_NFP, "Application area already exist");
781 return ApplicationAreaExist; 896 return ResultApplicationAreaExist;
782 } 897 }
783 898
784 return RecreateApplicationArea(access_id, data); 899 return RecreateApplicationArea(access_id, data);
785} 900}
786 901
787Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) { 902Result NfcDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
788 if (device_state != DeviceState::TagMounted) { 903 if (device_state != DeviceState::TagMounted) {
789 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 904 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
790 if (device_state == DeviceState::TagRemoved) { 905 if (device_state == DeviceState::TagRemoved) {
791 return TagRemoved; 906 return ResultTagRemoved;
792 } 907 }
793 return WrongDeviceState; 908 return ResultWrongDeviceState;
794 } 909 }
795 910
796 if (is_app_area_open) { 911 if (is_app_area_open) {
797 LOG_ERROR(Service_NFP, "Application area is open"); 912 LOG_ERROR(Service_NFP, "Application area is open");
798 return WrongDeviceState; 913 return ResultWrongDeviceState;
799 } 914 }
800 915
801 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 916 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
802 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 917 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
803 return WrongDeviceState; 918 return ResultWrongDeviceState;
804 } 919 }
805 920
806 if (data.size() > sizeof(ApplicationArea)) { 921 if (data.size() > sizeof(NFP::ApplicationArea)) {
807 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size()); 922 LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
808 return WrongApplicationAreaSize; 923 return ResultWrongApplicationAreaSize;
809 } 924 }
810 925
811 Common::TinyMT rng{}; 926 Common::TinyMT rng{};
812 std::memcpy(tag_data.application_area.data(), data.data(), data.size()); 927 std::memcpy(tag_data.application_area.data(), data.data(), data.size());
813 // Fill remaining data with random numbers 928 // Fill remaining data with random numbers
814 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(), 929 rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
815 sizeof(ApplicationArea) - data.size()); 930 sizeof(NFP::ApplicationArea) - data.size());
816 931
817 if (tag_data.application_write_counter != counter_limit) { 932 if (tag_data.application_write_counter != NFP::counter_limit) {
818 tag_data.application_write_counter++; 933 tag_data.application_write_counter++;
819 } 934 }
820 935
821 const u64 application_id = system.GetApplicationProcessProgramID(); 936 const u64 application_id = system.GetApplicationProcessProgramID();
822 937
823 tag_data.application_id_byte = 938 tag_data.application_id_byte =
824 static_cast<u8>(application_id >> application_id_version_offset & 0xf); 939 static_cast<u8>(application_id >> NFP::application_id_version_offset & 0xf);
825 tag_data.application_id = 940 tag_data.application_id =
826 RemoveVersionByte(application_id) | 941 RemoveVersionByte(application_id) | (static_cast<u64>(NFP::AppAreaVersion::NintendoSwitch)
827 (static_cast<u64>(AppAreaVersion::NintendoSwitch) << application_id_version_offset); 942 << NFP::application_id_version_offset);
828 tag_data.settings.settings.appdata_initialized.Assign(1); 943 tag_data.settings.settings.appdata_initialized.Assign(1);
829 tag_data.application_area_id = access_id; 944 tag_data.application_area_id = access_id;
830 tag_data.unknown = {}; 945 tag_data.unknown = {};
@@ -835,30 +950,30 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat
835 return Flush(); 950 return Flush();
836} 951}
837 952
838Result NfpDevice::DeleteApplicationArea() { 953Result NfcDevice::DeleteApplicationArea() {
839 if (device_state != DeviceState::TagMounted) { 954 if (device_state != DeviceState::TagMounted) {
840 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 955 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
841 if (device_state == DeviceState::TagRemoved) { 956 if (device_state == DeviceState::TagRemoved) {
842 return TagRemoved; 957 return ResultTagRemoved;
843 } 958 }
844 return WrongDeviceState; 959 return ResultWrongDeviceState;
845 } 960 }
846 961
847 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 962 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
848 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); 963 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
849 return WrongDeviceState; 964 return ResultWrongDeviceState;
850 } 965 }
851 966
852 if (tag_data.settings.settings.appdata_initialized == 0) { 967 if (tag_data.settings.settings.appdata_initialized == 0) {
853 return ApplicationAreaIsNotInitialized; 968 return ResultApplicationAreaIsNotInitialized;
854 } 969 }
855 970
856 if (tag_data.application_write_counter != counter_limit) { 971 if (tag_data.application_write_counter != NFP::counter_limit) {
857 tag_data.application_write_counter++; 972 tag_data.application_write_counter++;
858 } 973 }
859 974
860 Common::TinyMT rng{}; 975 Common::TinyMT rng{};
861 rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea)); 976 rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(NFP::ApplicationArea));
862 rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64)); 977 rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64));
863 rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32)); 978 rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
864 rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8)); 979 rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));
@@ -872,18 +987,18 @@ Result NfpDevice::DeleteApplicationArea() {
872 return Flush(); 987 return Flush();
873} 988}
874 989
875Result NfpDevice::ExistApplicationArea(bool& has_application_area) { 990Result NfcDevice::ExistsApplicationArea(bool& has_application_area) const {
876 if (device_state != DeviceState::TagMounted) { 991 if (device_state != DeviceState::TagMounted) {
877 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 992 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
878 if (device_state == DeviceState::TagRemoved) { 993 if (device_state == DeviceState::TagRemoved) {
879 return TagRemoved; 994 return ResultTagRemoved;
880 } 995 }
881 return WrongDeviceState; 996 return ResultWrongDeviceState;
882 } 997 }
883 998
884 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 999 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
885 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1000 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
886 return WrongDeviceState; 1001 return ResultWrongDeviceState;
887 } 1002 }
888 1003
889 has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0; 1004 has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0;
@@ -891,21 +1006,21 @@ Result NfpDevice::ExistApplicationArea(bool& has_application_area) {
891 return ResultSuccess; 1006 return ResultSuccess;
892} 1007}
893 1008
894Result NfpDevice::GetAll(NfpData& data) const { 1009Result NfcDevice::GetAll(NFP::NfpData& data) const {
895 if (device_state != DeviceState::TagMounted) { 1010 if (device_state != DeviceState::TagMounted) {
896 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1011 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
897 if (device_state == DeviceState::TagRemoved) { 1012 if (device_state == DeviceState::TagRemoved) {
898 return TagRemoved; 1013 return ResultTagRemoved;
899 } 1014 }
900 return WrongDeviceState; 1015 return ResultWrongDeviceState;
901 } 1016 }
902 1017
903 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1018 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
904 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1019 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
905 return WrongDeviceState; 1020 return ResultWrongDeviceState;
906 } 1021 }
907 1022
908 CommonInfo common_info{}; 1023 NFP::CommonInfo common_info{};
909 Service::Mii::MiiManager manager; 1024 Service::Mii::MiiManager manager;
910 const u64 application_id = tag_data.application_id; 1025 const u64 application_id = tag_data.application_id;
911 1026
@@ -930,8 +1045,8 @@ Result NfpDevice::GetAll(NfpData& data) const {
930 .settings_crc_counter = tag_data.settings.crc_counter, 1045 .settings_crc_counter = tag_data.settings.crc_counter,
931 .font_region = tag_data.settings.settings.font_region, 1046 .font_region = tag_data.settings.settings.font_region,
932 .tag_type = PackedTagType::Type2, 1047 .tag_type = PackedTagType::Type2,
933 .console_type = 1048 .console_type = static_cast<NFP::AppAreaVersion>(
934 static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf), 1049 application_id >> NFP::application_id_version_offset & 0xf),
935 .application_id_byte = tag_data.application_id_byte, 1050 .application_id_byte = tag_data.application_id_byte,
936 .application_area = tag_data.application_area, 1051 .application_area = tag_data.application_area,
937 }; 1052 };
@@ -939,18 +1054,18 @@ Result NfpDevice::GetAll(NfpData& data) const {
939 return ResultSuccess; 1054 return ResultSuccess;
940} 1055}
941 1056
942Result NfpDevice::SetAll(const NfpData& data) { 1057Result NfcDevice::SetAll(const NFP::NfpData& data) {
943 if (device_state != DeviceState::TagMounted) { 1058 if (device_state != DeviceState::TagMounted) {
944 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1059 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
945 if (device_state == DeviceState::TagRemoved) { 1060 if (device_state == DeviceState::TagRemoved) {
946 return TagRemoved; 1061 return ResultTagRemoved;
947 } 1062 }
948 return WrongDeviceState; 1063 return ResultWrongDeviceState;
949 } 1064 }
950 1065
951 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1066 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
952 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1067 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
953 return WrongDeviceState; 1068 return ResultWrongDeviceState;
954 } 1069 }
955 1070
956 tag_data.constant_value = data.magic; 1071 tag_data.constant_value = data.magic;
@@ -977,18 +1092,18 @@ Result NfpDevice::SetAll(const NfpData& data) {
977 return ResultSuccess; 1092 return ResultSuccess;
978} 1093}
979 1094
980Result NfpDevice::BreakTag(BreakType break_type) { 1095Result NfcDevice::BreakTag(NFP::BreakType break_type) {
981 if (device_state != DeviceState::TagMounted) { 1096 if (device_state != DeviceState::TagMounted) {
982 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1097 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
983 if (device_state == DeviceState::TagRemoved) { 1098 if (device_state == DeviceState::TagRemoved) {
984 return TagRemoved; 1099 return ResultTagRemoved;
985 } 1100 }
986 return WrongDeviceState; 1101 return ResultWrongDeviceState;
987 } 1102 }
988 1103
989 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1104 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
990 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1105 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
991 return WrongDeviceState; 1106 return ResultWrongDeviceState;
992 } 1107 }
993 1108
994 // TODO: Complete this implementation 1109 // TODO: Complete this implementation
@@ -996,28 +1111,28 @@ Result NfpDevice::BreakTag(BreakType break_type) {
996 return FlushWithBreak(break_type); 1111 return FlushWithBreak(break_type);
997} 1112}
998 1113
999Result NfpDevice::ReadBackupData() { 1114Result NfcDevice::ReadBackupData(std::span<u8> data) const {
1000 // Not implemented 1115 // Not implemented
1001 return ResultSuccess; 1116 return ResultSuccess;
1002} 1117}
1003 1118
1004Result NfpDevice::WriteBackupData() { 1119Result NfcDevice::WriteBackupData(std::span<const u8> data) {
1005 // Not implemented 1120 // Not implemented
1006 return ResultSuccess; 1121 return ResultSuccess;
1007} 1122}
1008 1123
1009Result NfpDevice::WriteNtf() { 1124Result NfcDevice::WriteNtf(std::span<const u8> data) {
1010 if (device_state != DeviceState::TagMounted) { 1125 if (device_state != DeviceState::TagMounted) {
1011 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 1126 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
1012 if (device_state == DeviceState::TagRemoved) { 1127 if (device_state == DeviceState::TagRemoved) {
1013 return TagRemoved; 1128 return ResultTagRemoved;
1014 } 1129 }
1015 return WrongDeviceState; 1130 return ResultWrongDeviceState;
1016 } 1131 }
1017 1132
1018 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { 1133 if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
1019 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); 1134 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
1020 return WrongDeviceState; 1135 return ResultWrongDeviceState;
1021 } 1136 }
1022 1137
1023 // Not implemented 1138 // Not implemented
@@ -1025,29 +1140,12 @@ Result NfpDevice::WriteNtf() {
1025 return ResultSuccess; 1140 return ResultSuccess;
1026} 1141}
1027 1142
1028u64 NfpDevice::GetHandle() const { 1143NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) const {
1029 // Generate a handle based of the npad id 1144 std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
1030 return static_cast<u64>(npad_id); 1145 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 1146
1049 // Convert from big endian to little endian 1147 // Convert from big endian to little endian
1050 for (std::size_t i = 0; i < amiibo_name_length; i++) { 1148 for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
1051 settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]); 1149 settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
1052 } 1150 }
1053 1151
@@ -1058,8 +1156,8 @@ AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const {
1058 return amiibo_name; 1156 return amiibo_name;
1059} 1157}
1060 1158
1061void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name) { 1159void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) {
1062 std::array<char16_t, amiibo_name_length> settings_amiibo_name{}; 1160 std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
1063 1161
1064 // Convert from utf8 to utf16 1162 // Convert from utf8 to utf16
1065 const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data()); 1163 const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data());
@@ -1067,16 +1165,16 @@ void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo
1067 amiibo_name_utf16.size() * sizeof(char16_t)); 1165 amiibo_name_utf16.size() * sizeof(char16_t));
1068 1166
1069 // Convert from little endian to big endian 1167 // Convert from little endian to big endian
1070 for (std::size_t i = 0; i < amiibo_name_length; i++) { 1168 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]); 1169 settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]);
1072 } 1170 }
1073} 1171}
1074 1172
1075AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const { 1173NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
1076 const auto& time_zone_manager = 1174 const auto& time_zone_manager =
1077 system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); 1175 system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
1078 Time::TimeZone::CalendarInfo calendar_info{}; 1176 Time::TimeZone::CalendarInfo calendar_info{};
1079 AmiiboDate amiibo_date{}; 1177 NFP::AmiiboDate amiibo_date{};
1080 1178
1081 amiibo_date.SetYear(2000); 1179 amiibo_date.SetYear(2000);
1082 amiibo_date.SetMonth(1); 1180 amiibo_date.SetMonth(1);
@@ -1091,14 +1189,14 @@ AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const {
1091 return amiibo_date; 1189 return amiibo_date;
1092} 1190}
1093 1191
1094u64 NfpDevice::RemoveVersionByte(u64 application_id) const { 1192u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
1095 return application_id & ~(0xfULL << application_id_version_offset); 1193 return application_id & ~(0xfULL << NFP::application_id_version_offset);
1096} 1194}
1097 1195
1098void NfpDevice::UpdateSettingsCrc() { 1196void NfcDevice::UpdateSettingsCrc() {
1099 auto& settings = tag_data.settings; 1197 auto& settings = tag_data.settings;
1100 1198
1101 if (settings.crc_counter != counter_limit) { 1199 if (settings.crc_counter != NFP::counter_limit) {
1102 settings.crc_counter++; 1200 settings.crc_counter++;
1103 } 1201 }
1104 1202
@@ -1109,7 +1207,7 @@ void NfpDevice::UpdateSettingsCrc() {
1109 settings.crc = crc.checksum(); 1207 settings.crc = crc.checksum();
1110} 1208}
1111 1209
1112void NfpDevice::UpdateRegisterInfoCrc() { 1210void NfcDevice::UpdateRegisterInfoCrc() {
1113#pragma pack(push, 1) 1211#pragma pack(push, 1)
1114 struct CrcData { 1212 struct CrcData {
1115 Mii::Ver3StoreData mii; 1213 Mii::Ver3StoreData mii;
@@ -1134,4 +1232,18 @@ void NfpDevice::UpdateRegisterInfoCrc() {
1134 tag_data.register_info_crc = crc.checksum(); 1232 tag_data.register_info_crc = crc.checksum();
1135} 1233}
1136 1234
1137} // namespace Service::NFP 1235u64 NfcDevice::GetHandle() const {
1236 // Generate a handle based of the npad id
1237 return static_cast<u64>(npad_id);
1238}
1239
1240DeviceState NfcDevice::GetCurrentState() const {
1241 return device_state;
1242}
1243
1244Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const {
1245 out_npad_id = npad_id;
1246 return ResultSuccess;
1247}
1248
1249} // 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..654eda98e
--- /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 RemoveVersionByte(u64 application_id) const;
109 void UpdateSettingsCrc();
110 void UpdateRegisterInfoCrc();
111
112 bool is_controller_set{};
113 int callback_key;
114 const Core::HID::NpadIdType npad_id;
115 Core::System& system;
116 Core::HID::EmulatedController* npad_device = nullptr;
117 KernelHelpers::ServiceContext& service_context;
118 Kernel::KEvent* activate_event = nullptr;
119 Kernel::KEvent* deactivate_event = nullptr;
120 Kernel::KEvent* availability_change_event = nullptr;
121
122 bool is_initalized{};
123 NfcProtocol allowed_protocols{};
124 DeviceState device_state{DeviceState::Unavailable};
125
126 // NFP data
127 bool is_data_moddified{};
128 bool is_app_area_open{};
129 bool is_plain_amiibo{};
130 s64 current_posix_time{};
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/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index 6b4a1291e..156bc27d8 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -33,6 +33,9 @@ ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_m
33 // Initialize event. 33 // Initialize event.
34 m_event = Kernel::KEvent::Create(system.Kernel()); 34 m_event = Kernel::KEvent::Create(system.Kernel());
35 m_event->Initialize(nullptr); 35 m_event->Initialize(nullptr);
36
37 // Register event.
38 Kernel::KEvent::Register(system.Kernel(), m_event);
36} 39}
37 40
38ServerManager::~ServerManager() { 41ServerManager::~ServerManager() {
@@ -160,6 +163,9 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
160 // Initialize the event. 163 // Initialize the event.
161 m_deferral_event->Initialize(nullptr); 164 m_deferral_event->Initialize(nullptr);
162 165
166 // Register the event.
167 Kernel::KEvent::Register(m_system.Kernel(), m_deferral_event);
168
163 // Set the output. 169 // Set the output.
164 *out_event = m_deferral_event; 170 *out_event = m_deferral_event;
165 171
diff --git a/src/core/hle/service/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/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index c45be5726..1608fa24c 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -64,6 +64,9 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
64 auto* port = Kernel::KPort::Create(kernel); 64 auto* port = Kernel::KPort::Create(kernel);
65 port->Initialize(ServerSessionCountMax, false, 0); 65 port->Initialize(ServerSessionCountMax, false, 0);
66 66
67 // Register the port.
68 Kernel::KPort::Register(kernel, port);
69
67 service_ports.emplace(name, port); 70 service_ports.emplace(name, port);
68 registered_services.emplace(name, handler); 71 registered_services.emplace(name, handler);
69 if (deferral_event) { 72 if (deferral_event) {
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp
index 419c1df2b..7dce28fe0 100644
--- a/src/core/hle/service/sm/sm_controller.cpp
+++ b/src/core/hle/service/sm/sm_controller.cpp
@@ -49,6 +49,9 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
49 // Commit the session reservation. 49 // Commit the session reservation.
50 session_reservation.Commit(); 50 session_reservation.Commit();
51 51
52 // Register the session.
53 Kernel::KSession::Register(system.Kernel(), session);
54
52 // Register with server manager. 55 // Register with server manager.
53 session_manager->GetServerManager().RegisterSession(&session->GetServerSession(), 56 session_manager->GetServerManager().RegisterSession(&session->GetServerSession(),
54 session_manager); 57 session_manager);
diff --git a/src/core/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 432310632..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::IsGPULevelHigh() || !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/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 9178b00ca..7a2f3c90a 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -85,6 +85,20 @@ static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) {
85 return "Unknown"; 85 return "Unknown";
86} 86}
87 87
88static constexpr const char* TranslateVSyncMode(Settings::VSyncMode mode) {
89 switch (mode) {
90 case Settings::VSyncMode::Immediate:
91 return "Immediate";
92 case Settings::VSyncMode::Mailbox:
93 return "Mailbox";
94 case Settings::VSyncMode::FIFO:
95 return "FIFO";
96 case Settings::VSyncMode::FIFORelaxed:
97 return "FIFO Relaxed";
98 }
99 return "Unknown";
100}
101
88u64 GetTelemetryId() { 102u64 GetTelemetryId() {
89 u64 telemetry_id{}; 103 u64 telemetry_id{};
90 const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id"; 104 const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id";
@@ -241,7 +255,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
241 AddField(field_type, "Renderer_NvdecEmulation", 255 AddField(field_type, "Renderer_NvdecEmulation",
242 TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue())); 256 TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue()));
243 AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue()); 257 AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue());
244 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); 258 AddField(field_type, "Renderer_UseVsync",
259 TranslateVSyncMode(Settings::values.vsync_mode.GetValue()));
245 AddField(field_type, "Renderer_ShaderBackend", 260 AddField(field_type, "Renderer_ShaderBackend",
246 static_cast<u32>(Settings::values.shader_backend.GetValue())); 261 static_cast<u32>(Settings::values.shader_backend.GetValue()));
247 AddField(field_type, "Renderer_UseAsynchronousShaders", 262 AddField(field_type, "Renderer_UseAsynchronousShaders",
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..b03143e04 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -575,7 +575,6 @@ struct NFCPollingCommandData {
575static_assert(sizeof(NFCPollingCommandData) == 0x05, "NFCPollingCommandData is an invalid size"); 575static_assert(sizeof(NFCPollingCommandData) == 0x05, "NFCPollingCommandData is an invalid size");
576 576
577struct NFCRequestState { 577struct NFCRequestState {
578 MCUSubCommand sub_command;
579 NFCReadCommand command_argument; 578 NFCReadCommand command_argument;
580 u8 packet_id; 579 u8 packet_id;
581 INSERT_PADDING_BYTES(0x1); 580 INSERT_PADDING_BYTES(0x1);
@@ -587,6 +586,7 @@ struct NFCRequestState {
587 NFCPollingCommandData nfc_polling; 586 NFCPollingCommandData nfc_polling;
588 }; 587 };
589 u8 crc; 588 u8 crc;
589 INSERT_PADDING_BYTES(0x1);
590}; 590};
591static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size"); 591static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size");
592 592
@@ -659,7 +659,10 @@ struct SubCommandPacket {
659 OutputReport output_report; 659 OutputReport output_report;
660 u8 packet_counter; 660 u8 packet_counter;
661 INSERT_PADDING_BYTES(0x8); // This contains vibration data 661 INSERT_PADDING_BYTES(0x8); // This contains vibration data
662 SubCommand sub_command; 662 union {
663 SubCommand sub_command;
664 MCUSubCommand mcu_sub_command;
665 };
663 std::array<u8, 0x26> command_data; 666 std::array<u8, 0x26> command_data;
664}; 667};
665static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size"); 668static_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..77ea6d5cf 100644
--- a/src/input_common/helpers/joycon_protocol/nfc.cpp
+++ b/src/input_common/helpers/joycon_protocol/nfc.cpp
@@ -278,7 +278,6 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
278 278
279DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) { 279DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) {
280 NFCRequestState request{ 280 NFCRequestState request{
281 .sub_command = MCUSubCommand::ReadDeviceMode,
282 .command_argument = NFCReadCommand::StartPolling, 281 .command_argument = NFCReadCommand::StartPolling,
283 .packet_id = 0x0, 282 .packet_id = 0x0,
284 .packet_flag = MCUPacketFlag::LastCommandPacket, 283 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -296,13 +295,13 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) {
296 295
297 std::array<u8, sizeof(NFCRequestState)> request_data{}; 296 std::array<u8, sizeof(NFCRequestState)> request_data{};
298 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 297 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
299 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 298 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
300 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 299 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
300 output);
301} 301}
302 302
303DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { 303DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
304 NFCRequestState request{ 304 NFCRequestState request{
305 .sub_command = MCUSubCommand::ReadDeviceMode,
306 .command_argument = NFCReadCommand::StopPolling, 305 .command_argument = NFCReadCommand::StopPolling,
307 .packet_id = 0x0, 306 .packet_id = 0x0,
308 .packet_flag = MCUPacketFlag::LastCommandPacket, 307 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -313,13 +312,13 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
313 312
314 std::array<u8, sizeof(NFCRequestState)> request_data{}; 313 std::array<u8, sizeof(NFCRequestState)> request_data{};
315 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 314 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
316 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 315 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
317 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 316 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
317 output);
318} 318}
319 319
320DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) { 320DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) {
321 NFCRequestState request{ 321 NFCRequestState request{
322 .sub_command = MCUSubCommand::ReadDeviceMode,
323 .command_argument = NFCReadCommand::StartWaitingRecieve, 322 .command_argument = NFCReadCommand::StartWaitingRecieve,
324 .packet_id = 0x0, 323 .packet_id = 0x0,
325 .packet_flag = MCUPacketFlag::LastCommandPacket, 324 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -330,13 +329,13 @@ DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& out
330 329
331 std::vector<u8> request_data(sizeof(NFCRequestState)); 330 std::vector<u8> request_data(sizeof(NFCRequestState));
332 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 331 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
333 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 332 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
334 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 333 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
334 output);
335} 335}
336 336
337DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { 337DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {
338 NFCRequestState request{ 338 NFCRequestState request{
339 .sub_command = MCUSubCommand::ReadDeviceMode,
340 .command_argument = NFCReadCommand::Ntag, 339 .command_argument = NFCReadCommand::Ntag,
341 .packet_id = 0x0, 340 .packet_id = 0x0,
342 .packet_flag = MCUPacketFlag::LastCommandPacket, 341 .packet_flag = MCUPacketFlag::LastCommandPacket,
@@ -355,8 +354,9 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
355 354
356 std::array<u8, sizeof(NFCRequestState)> request_data{}; 355 std::array<u8, sizeof(NFCRequestState)> request_data{};
357 memcpy(request_data.data(), &request, sizeof(NFCRequestState)); 356 memcpy(request_data.data(), &request, sizeof(NFCRequestState));
358 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); 357 request_data[36] = CalculateMCU_CRC8(request_data.data(), 36);
359 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); 358 return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data,
359 output);
360} 360}
361 361
362NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(NFCPages pages) const { 362NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(NFCPages pages) const {
diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp
index 9361b00c5..8c2ee4eb3 100644
--- a/src/input_common/input_mapping.cpp
+++ b/src/input_common/input_mapping.cpp
@@ -82,6 +82,9 @@ void MappingFactory::RegisterButton(const MappingData& data) {
82 new_input.Set("axis", data.index); 82 new_input.Set("axis", data.index);
83 new_input.Set("threshold", 0.5f); 83 new_input.Set("threshold", 0.5f);
84 break; 84 break;
85 case EngineInputType::Motion:
86 new_input.Set("motion", data.index);
87 break;
85 default: 88 default:
86 return; 89 return;
87 } 90 }
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp
index 8c6a6521a..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 }
@@ -939,6 +939,7 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateAnalogDevice(
939 .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), 939 .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f),
940 .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), 940 .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f),
941 .inverted = params.Get("invert", "+") == "-", 941 .inverted = params.Get("invert", "+") == "-",
942 .inverted_button = params.Get("inverted", false) != 0,
942 .toggle = params.Get("toggle", false) != 0, 943 .toggle = params.Get("toggle", false) != 0,
943 }; 944 };
944 input_engine->PreSetController(identifier); 945 input_engine->PreSetController(identifier);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 0cd87a48f..fee510f7b 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
@@ -473,7 +473,8 @@ void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) {
473} 473}
474 474
475void EmitSetSampleMask(EmitContext& ctx, Id value) { 475void EmitSetSampleMask(EmitContext& ctx, Id value) {
476 ctx.OpStore(ctx.sample_mask, value); 476 const Id pointer{ctx.OpAccessChain(ctx.output_u32, ctx.sample_mask, ctx.u32_zero_value)};
477 ctx.OpStore(pointer, value);
477} 478}
478 479
479void EmitSetFragDepth(EmitContext& ctx, Id value) { 480void EmitSetFragDepth(EmitContext& ctx, Id value) {
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index d48d4860e..47739794f 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -1572,7 +1572,8 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
1572 Decorate(frag_depth, spv::Decoration::BuiltIn, spv::BuiltIn::FragDepth); 1572 Decorate(frag_depth, spv::Decoration::BuiltIn, spv::BuiltIn::FragDepth);
1573 } 1573 }
1574 if (info.stores_sample_mask) { 1574 if (info.stores_sample_mask) {
1575 sample_mask = DefineOutput(*this, U32[1], std::nullopt); 1575 const Id array_type{TypeArray(U32[1], Const(1U))};
1576 sample_mask = DefineOutput(*this, array_type, std::nullopt);
1576 Decorate(sample_mask, spv::Decoration::BuiltIn, spv::BuiltIn::SampleMask); 1577 Decorate(sample_mask, spv::Decoration::BuiltIn, spv::BuiltIn::SampleMask);
1577 } 1578 }
1578 break; 1579 break;
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 39b774c98..1e158f375 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -15,7 +15,7 @@ add_executable(tests
15 core/core_timing.cpp 15 core/core_timing.cpp
16 core/internal_network/network.cpp 16 core/internal_network/network.cpp
17 precompiled_headers.h 17 precompiled_headers.h
18 video_core/buffer_base.cpp 18 video_core/memory_tracker.cpp
19 input_common/calibration_configuration_job.cpp 19 input_common/calibration_configuration_job.cpp
20) 20)
21 21
diff --git a/src/tests/video_core/buffer_base.cpp b/src/tests/video_core/buffer_base.cpp
deleted file mode 100644
index 734dbf4b6..000000000
--- a/src/tests/video_core/buffer_base.cpp
+++ /dev/null
@@ -1,549 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <stdexcept>
5#include <unordered_map>
6
7#include <catch2/catch_test_macros.hpp>
8
9#include "common/alignment.h"
10#include "common/common_types.h"
11#include "video_core/buffer_cache/buffer_base.h"
12
13namespace {
14using VideoCommon::BufferBase;
15using Range = std::pair<u64, u64>;
16
17constexpr u64 PAGE = 4096;
18constexpr u64 WORD = 4096 * 64;
19
20constexpr VAddr c = 0x1328914000;
21
22class RasterizerInterface {
23public:
24 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
25 const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS};
26 const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >>
27 Core::Memory::YUZU_PAGEBITS};
28 for (u64 page = page_start; page < page_end; ++page) {
29 int& value = page_table[page];
30 value += delta;
31 if (value < 0) {
32 throw std::logic_error{"negative page"};
33 }
34 if (value == 0) {
35 page_table.erase(page);
36 }
37 }
38 }
39
40 [[nodiscard]] int Count(VAddr addr) const noexcept {
41 const auto it = page_table.find(addr >> Core::Memory::YUZU_PAGEBITS);
42 return it == page_table.end() ? 0 : it->second;
43 }
44
45 [[nodiscard]] unsigned Count() const noexcept {
46 unsigned count = 0;
47 for (const auto& [index, value] : page_table) {
48 count += value;
49 }
50 return count;
51 }
52
53private:
54 std::unordered_map<u64, int> page_table;
55};
56} // Anonymous namespace
57
58TEST_CASE("BufferBase: Small buffer", "[video_core]") {
59 RasterizerInterface rasterizer;
60 BufferBase buffer(rasterizer, c, WORD);
61 REQUIRE(rasterizer.Count() == 0);
62 buffer.UnmarkRegionAsCpuModified(c, WORD);
63 REQUIRE(rasterizer.Count() == WORD / PAGE);
64 REQUIRE(buffer.ModifiedCpuRegion(c, WORD) == Range{0, 0});
65
66 buffer.MarkRegionAsCpuModified(c + PAGE, 1);
67 REQUIRE(buffer.ModifiedCpuRegion(c, WORD) == Range{PAGE * 1, PAGE * 2});
68}
69
70TEST_CASE("BufferBase: Large buffer", "[video_core]") {
71 RasterizerInterface rasterizer;
72 BufferBase buffer(rasterizer, c, WORD * 32);
73 buffer.UnmarkRegionAsCpuModified(c, WORD * 32);
74 buffer.MarkRegionAsCpuModified(c + 4096, WORD * 4);
75 REQUIRE(buffer.ModifiedCpuRegion(c, WORD + PAGE * 2) == Range{PAGE, WORD + PAGE * 2});
76 REQUIRE(buffer.ModifiedCpuRegion(c + PAGE * 2, PAGE * 6) == Range{PAGE * 2, PAGE * 8});
77 REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{PAGE, WORD * 4 + PAGE});
78 REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 4, PAGE) == Range{WORD * 4, WORD * 4 + PAGE});
79 REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 3 + PAGE * 63, PAGE) ==
80 Range{WORD * 3 + PAGE * 63, WORD * 4});
81
82 buffer.MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 6, PAGE);
83 buffer.MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE);
84 REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 5, WORD) ==
85 Range{WORD * 5 + PAGE * 6, WORD * 5 + PAGE * 9});
86
87 buffer.UnmarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE);
88 REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 5, WORD) ==
89 Range{WORD * 5 + PAGE * 6, WORD * 5 + PAGE * 7});
90
91 buffer.MarkRegionAsCpuModified(c + PAGE, WORD * 31 + PAGE * 63);
92 REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{PAGE, WORD * 32});
93
94 buffer.UnmarkRegionAsCpuModified(c + PAGE * 4, PAGE);
95 buffer.UnmarkRegionAsCpuModified(c + PAGE * 6, PAGE);
96
97 buffer.UnmarkRegionAsCpuModified(c, WORD * 32);
98 REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{0, 0});
99}
100
101TEST_CASE("BufferBase: Rasterizer counting", "[video_core]") {
102 RasterizerInterface rasterizer;
103 BufferBase buffer(rasterizer, c, PAGE * 2);
104 REQUIRE(rasterizer.Count() == 0);
105 buffer.UnmarkRegionAsCpuModified(c, PAGE);
106 REQUIRE(rasterizer.Count() == 1);
107 buffer.MarkRegionAsCpuModified(c, PAGE * 2);
108 REQUIRE(rasterizer.Count() == 0);
109 buffer.UnmarkRegionAsCpuModified(c, PAGE);
110 buffer.UnmarkRegionAsCpuModified(c + PAGE, PAGE);
111 REQUIRE(rasterizer.Count() == 2);
112 buffer.MarkRegionAsCpuModified(c, PAGE * 2);
113 REQUIRE(rasterizer.Count() == 0);
114}
115
116TEST_CASE("BufferBase: Basic range", "[video_core]") {
117 RasterizerInterface rasterizer;
118 BufferBase buffer(rasterizer, c, WORD);
119 buffer.UnmarkRegionAsCpuModified(c, WORD);
120 buffer.MarkRegionAsCpuModified(c, PAGE);
121 int num = 0;
122 buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
123 REQUIRE(offset == 0U);
124 REQUIRE(size == PAGE);
125 ++num;
126 });
127 REQUIRE(num == 1U);
128}
129
130TEST_CASE("BufferBase: Border upload", "[video_core]") {
131 RasterizerInterface rasterizer;
132 BufferBase buffer(rasterizer, c, WORD * 2);
133 buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
134 buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
135 buffer.ForEachUploadRange(c, WORD * 2, [](u64 offset, u64 size) {
136 REQUIRE(offset == WORD - PAGE);
137 REQUIRE(size == PAGE * 2);
138 });
139}
140
141TEST_CASE("BufferBase: Border upload range", "[video_core]") {
142 RasterizerInterface rasterizer;
143 BufferBase buffer(rasterizer, c, WORD * 2);
144 buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
145 buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
146 buffer.ForEachUploadRange(c + WORD - PAGE, PAGE * 2, [](u64 offset, u64 size) {
147 REQUIRE(offset == WORD - PAGE);
148 REQUIRE(size == PAGE * 2);
149 });
150 buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
151 buffer.ForEachUploadRange(c + WORD - PAGE, PAGE, [](u64 offset, u64 size) {
152 REQUIRE(offset == WORD - PAGE);
153 REQUIRE(size == PAGE);
154 });
155 buffer.ForEachUploadRange(c + WORD, PAGE, [](u64 offset, u64 size) {
156 REQUIRE(offset == WORD);
157 REQUIRE(size == PAGE);
158 });
159}
160
161TEST_CASE("BufferBase: Border upload partial range", "[video_core]") {
162 RasterizerInterface rasterizer;
163 BufferBase buffer(rasterizer, c, WORD * 2);
164 buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
165 buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
166 buffer.ForEachUploadRange(c + WORD - 1, 2, [](u64 offset, u64 size) {
167 REQUIRE(offset == WORD - PAGE);
168 REQUIRE(size == PAGE * 2);
169 });
170 buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
171 buffer.ForEachUploadRange(c + WORD - 1, 1, [](u64 offset, u64 size) {
172 REQUIRE(offset == WORD - PAGE);
173 REQUIRE(size == PAGE);
174 });
175 buffer.ForEachUploadRange(c + WORD + 50, 1, [](u64 offset, u64 size) {
176 REQUIRE(offset == WORD);
177 REQUIRE(size == PAGE);
178 });
179}
180
181TEST_CASE("BufferBase: Partial word uploads", "[video_core]") {
182 RasterizerInterface rasterizer;
183 BufferBase buffer(rasterizer, c, 0x9d000);
184 int num = 0;
185 buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
186 REQUIRE(offset == 0U);
187 REQUIRE(size == WORD);
188 ++num;
189 });
190 REQUIRE(num == 1);
191 buffer.ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) {
192 REQUIRE(offset == WORD);
193 REQUIRE(size == WORD);
194 ++num;
195 });
196 REQUIRE(num == 2);
197 buffer.ForEachUploadRange(c + 0x79000, 0x24000, [&](u64 offset, u64 size) {
198 REQUIRE(offset == WORD * 2);
199 REQUIRE(size == PAGE * 0x1d);
200 ++num;
201 });
202 REQUIRE(num == 3);
203}
204
205TEST_CASE("BufferBase: Partial page upload", "[video_core]") {
206 RasterizerInterface rasterizer;
207 BufferBase buffer(rasterizer, c, WORD);
208 buffer.UnmarkRegionAsCpuModified(c, WORD);
209 int num = 0;
210 buffer.MarkRegionAsCpuModified(c + PAGE * 2, PAGE);
211 buffer.MarkRegionAsCpuModified(c + PAGE * 9, PAGE);
212 buffer.ForEachUploadRange(c, PAGE * 3, [&](u64 offset, u64 size) {
213 REQUIRE(offset == PAGE * 2);
214 REQUIRE(size == PAGE);
215 ++num;
216 });
217 REQUIRE(num == 1);
218 buffer.ForEachUploadRange(c + PAGE * 7, PAGE * 3, [&](u64 offset, u64 size) {
219 REQUIRE(offset == PAGE * 9);
220 REQUIRE(size == PAGE);
221 ++num;
222 });
223 REQUIRE(num == 2);
224}
225
226TEST_CASE("BufferBase: Partial page upload with multiple words on the right") {
227 RasterizerInterface rasterizer;
228 BufferBase buffer(rasterizer, c, WORD * 8);
229 buffer.UnmarkRegionAsCpuModified(c, WORD * 8);
230 buffer.MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7);
231 int num = 0;
232 buffer.ForEachUploadRange(c + PAGE * 10, WORD * 7, [&](u64 offset, u64 size) {
233 REQUIRE(offset == PAGE * 13);
234 REQUIRE(size == WORD * 7 - PAGE * 3);
235 ++num;
236 });
237 REQUIRE(num == 1);
238 buffer.ForEachUploadRange(c + PAGE, WORD * 8, [&](u64 offset, u64 size) {
239 REQUIRE(offset == WORD * 7 + PAGE * 10);
240 REQUIRE(size == PAGE * 3);
241 ++num;
242 });
243 REQUIRE(num == 2);
244}
245
246TEST_CASE("BufferBase: Partial page upload with multiple words on the left", "[video_core]") {
247 RasterizerInterface rasterizer;
248 BufferBase buffer(rasterizer, c, WORD * 8);
249 buffer.UnmarkRegionAsCpuModified(c, WORD * 8);
250 buffer.MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7);
251 int num = 0;
252 buffer.ForEachUploadRange(c + PAGE * 16, WORD * 7, [&](u64 offset, u64 size) {
253 REQUIRE(offset == PAGE * 16);
254 REQUIRE(size == WORD * 7 - PAGE * 3);
255 ++num;
256 });
257 REQUIRE(num == 1);
258 buffer.ForEachUploadRange(c + PAGE, WORD, [&](u64 offset, u64 size) {
259 REQUIRE(offset == PAGE * 13);
260 REQUIRE(size == PAGE * 3);
261 ++num;
262 });
263 REQUIRE(num == 2);
264}
265
266TEST_CASE("BufferBase: Partial page upload with multiple words in the middle", "[video_core]") {
267 RasterizerInterface rasterizer;
268 BufferBase buffer(rasterizer, c, WORD * 8);
269 buffer.UnmarkRegionAsCpuModified(c, WORD * 8);
270 buffer.MarkRegionAsCpuModified(c + PAGE * 13, PAGE * 140);
271 int num = 0;
272 buffer.ForEachUploadRange(c + PAGE * 16, WORD, [&](u64 offset, u64 size) {
273 REQUIRE(offset == PAGE * 16);
274 REQUIRE(size == WORD);
275 ++num;
276 });
277 REQUIRE(num == 1);
278 buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
279 REQUIRE(offset == PAGE * 13);
280 REQUIRE(size == PAGE * 3);
281 ++num;
282 });
283 REQUIRE(num == 2);
284 buffer.ForEachUploadRange(c, WORD * 8, [&](u64 offset, u64 size) {
285 REQUIRE(offset == WORD + PAGE * 16);
286 REQUIRE(size == PAGE * 73);
287 ++num;
288 });
289 REQUIRE(num == 3);
290}
291
292TEST_CASE("BufferBase: Empty right bits", "[video_core]") {
293 RasterizerInterface rasterizer;
294 BufferBase buffer(rasterizer, c, WORD * 2048);
295 buffer.UnmarkRegionAsCpuModified(c, WORD * 2048);
296 buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
297 buffer.ForEachUploadRange(c, WORD * 2048, [](u64 offset, u64 size) {
298 REQUIRE(offset == WORD - PAGE);
299 REQUIRE(size == PAGE * 2);
300 });
301}
302
303TEST_CASE("BufferBase: Out of bound ranges 1", "[video_core]") {
304 RasterizerInterface rasterizer;
305 BufferBase buffer(rasterizer, c, WORD);
306 buffer.UnmarkRegionAsCpuModified(c, WORD);
307 buffer.MarkRegionAsCpuModified(c, PAGE);
308 int num = 0;
309 buffer.ForEachUploadRange(c - WORD, WORD, [&](u64 offset, u64 size) { ++num; });
310 buffer.ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) { ++num; });
311 buffer.ForEachUploadRange(c - PAGE, PAGE, [&](u64 offset, u64 size) { ++num; });
312 REQUIRE(num == 0);
313 buffer.ForEachUploadRange(c - PAGE, PAGE * 2, [&](u64 offset, u64 size) { ++num; });
314 REQUIRE(num == 1);
315 buffer.MarkRegionAsCpuModified(c, WORD);
316 REQUIRE(rasterizer.Count() == 0);
317}
318
319TEST_CASE("BufferBase: Out of bound ranges 2", "[video_core]") {
320 RasterizerInterface rasterizer;
321 BufferBase buffer(rasterizer, c, 0x22000);
322 REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x22000, PAGE));
323 REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x28000, PAGE));
324 REQUIRE(rasterizer.Count() == 0);
325 REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x21100, PAGE - 0x100));
326 REQUIRE(rasterizer.Count() == 1);
327 REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c - 0x1000, PAGE * 2));
328 buffer.UnmarkRegionAsCpuModified(c - 0x3000, PAGE * 2);
329 buffer.UnmarkRegionAsCpuModified(c - 0x2000, PAGE * 2);
330 REQUIRE(rasterizer.Count() == 2);
331}
332
333TEST_CASE("BufferBase: Out of bound ranges 3", "[video_core]") {
334 RasterizerInterface rasterizer;
335 BufferBase buffer(rasterizer, c, 0x310720);
336 buffer.UnmarkRegionAsCpuModified(c, 0x310720);
337 REQUIRE(rasterizer.Count(c) == 1);
338 REQUIRE(rasterizer.Count(c + PAGE) == 1);
339 REQUIRE(rasterizer.Count(c + WORD) == 1);
340 REQUIRE(rasterizer.Count(c + WORD + PAGE) == 1);
341}
342
343TEST_CASE("BufferBase: Sparse regions 1", "[video_core]") {
344 RasterizerInterface rasterizer;
345 BufferBase buffer(rasterizer, c, WORD);
346 buffer.UnmarkRegionAsCpuModified(c, WORD);
347 buffer.MarkRegionAsCpuModified(c + PAGE * 1, PAGE);
348 buffer.MarkRegionAsCpuModified(c + PAGE * 3, PAGE * 4);
349 buffer.ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable {
350 static constexpr std::array<u64, 2> offsets{PAGE, PAGE * 3};
351 static constexpr std::array<u64, 2> sizes{PAGE, PAGE * 4};
352 REQUIRE(offset == offsets.at(i));
353 REQUIRE(size == sizes.at(i));
354 ++i;
355 });
356}
357
358TEST_CASE("BufferBase: Sparse regions 2", "[video_core]") {
359 RasterizerInterface rasterizer;
360 BufferBase buffer(rasterizer, c, 0x22000);
361 buffer.UnmarkRegionAsCpuModified(c, 0x22000);
362 REQUIRE(rasterizer.Count() == 0x22);
363 buffer.MarkRegionAsCpuModified(c + PAGE * 0x1B, PAGE);
364 buffer.MarkRegionAsCpuModified(c + PAGE * 0x21, PAGE);
365 buffer.ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable {
366 static constexpr std::array<u64, 2> offsets{PAGE * 0x1B, PAGE * 0x21};
367 static constexpr std::array<u64, 2> sizes{PAGE, PAGE};
368 REQUIRE(offset == offsets.at(i));
369 REQUIRE(size == sizes.at(i));
370 ++i;
371 });
372}
373
374TEST_CASE("BufferBase: Single page modified range", "[video_core]") {
375 RasterizerInterface rasterizer;
376 BufferBase buffer(rasterizer, c, PAGE);
377 REQUIRE(buffer.IsRegionCpuModified(c, PAGE));
378 buffer.UnmarkRegionAsCpuModified(c, PAGE);
379 REQUIRE(!buffer.IsRegionCpuModified(c, PAGE));
380}
381
382TEST_CASE("BufferBase: Two page modified range", "[video_core]") {
383 RasterizerInterface rasterizer;
384 BufferBase buffer(rasterizer, c, PAGE * 2);
385 REQUIRE(buffer.IsRegionCpuModified(c, PAGE));
386 REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
387 REQUIRE(buffer.IsRegionCpuModified(c, PAGE * 2));
388 buffer.UnmarkRegionAsCpuModified(c, PAGE);
389 REQUIRE(!buffer.IsRegionCpuModified(c, PAGE));
390}
391
392TEST_CASE("BufferBase: Multi word modified ranges", "[video_core]") {
393 for (int offset = 0; offset < 4; ++offset) {
394 const VAddr address = c + WORD * offset;
395 RasterizerInterface rasterizer;
396 BufferBase buffer(rasterizer, address, WORD * 4);
397 REQUIRE(buffer.IsRegionCpuModified(address, PAGE));
398 REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 48, PAGE));
399 REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 56, PAGE));
400
401 buffer.UnmarkRegionAsCpuModified(address + PAGE * 32, PAGE);
402 REQUIRE(buffer.IsRegionCpuModified(address + PAGE, WORD));
403 REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 31, PAGE));
404 REQUIRE(!buffer.IsRegionCpuModified(address + PAGE * 32, PAGE));
405 REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 33, PAGE));
406 REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 31, PAGE * 2));
407 REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 32, PAGE * 2));
408
409 buffer.UnmarkRegionAsCpuModified(address + PAGE * 33, PAGE);
410 REQUIRE(!buffer.IsRegionCpuModified(address + PAGE * 32, PAGE * 2));
411 }
412}
413
414TEST_CASE("BufferBase: Single page in large buffer", "[video_core]") {
415 RasterizerInterface rasterizer;
416 BufferBase buffer(rasterizer, c, WORD * 16);
417 buffer.UnmarkRegionAsCpuModified(c, WORD * 16);
418 REQUIRE(!buffer.IsRegionCpuModified(c, WORD * 16));
419
420 buffer.MarkRegionAsCpuModified(c + WORD * 12 + PAGE * 8, PAGE);
421 REQUIRE(buffer.IsRegionCpuModified(c, WORD * 16));
422 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 10, WORD * 2));
423 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 11, WORD * 2));
424 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12, WORD * 2));
425 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 4, PAGE * 8));
426 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE * 8));
427 REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE));
428 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 7, PAGE * 2));
429 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 8, PAGE * 2));
430}
431
432TEST_CASE("BufferBase: Out of bounds region query") {
433 RasterizerInterface rasterizer;
434 BufferBase buffer(rasterizer, c, WORD * 16);
435 REQUIRE(!buffer.IsRegionCpuModified(c - PAGE, PAGE));
436 REQUIRE(!buffer.IsRegionCpuModified(c - PAGE * 2, PAGE));
437 REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 16, PAGE));
438 REQUIRE(buffer.IsRegionCpuModified(c + WORD * 16 - PAGE, WORD * 64));
439 REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 16, WORD * 64));
440}
441
442TEST_CASE("BufferBase: Wrap word regions") {
443 RasterizerInterface rasterizer;
444 BufferBase buffer(rasterizer, c, WORD * 2);
445 buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
446 buffer.MarkRegionAsCpuModified(c + PAGE * 63, PAGE * 2);
447 REQUIRE(buffer.IsRegionCpuModified(c, WORD * 2));
448 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 62, PAGE));
449 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE));
450 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 64, PAGE));
451 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE * 2));
452 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE * 8));
453 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 60, PAGE * 8));
454
455 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 127, WORD * 16));
456 buffer.MarkRegionAsCpuModified(c + PAGE * 127, PAGE);
457 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 127, WORD * 16));
458 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 127, PAGE));
459 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 126, PAGE));
460 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 126, PAGE * 2));
461 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 128, WORD * 16));
462}
463
464TEST_CASE("BufferBase: Unaligned page region query") {
465 RasterizerInterface rasterizer;
466 BufferBase buffer(rasterizer, c, WORD);
467 buffer.UnmarkRegionAsCpuModified(c, WORD);
468 buffer.MarkRegionAsCpuModified(c + 4000, 1000);
469 REQUIRE(buffer.IsRegionCpuModified(c, PAGE));
470 REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
471 REQUIRE(buffer.IsRegionCpuModified(c + 4000, 1000));
472 REQUIRE(buffer.IsRegionCpuModified(c + 4000, 1));
473}
474
475TEST_CASE("BufferBase: Cached write") {
476 RasterizerInterface rasterizer;
477 BufferBase buffer(rasterizer, c, WORD);
478 buffer.UnmarkRegionAsCpuModified(c, WORD);
479 buffer.CachedCpuWrite(c + PAGE, PAGE);
480 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE));
481 buffer.FlushCachedWrites();
482 REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
483 buffer.MarkRegionAsCpuModified(c, WORD);
484 REQUIRE(rasterizer.Count() == 0);
485}
486
487TEST_CASE("BufferBase: Multiple cached write") {
488 RasterizerInterface rasterizer;
489 BufferBase buffer(rasterizer, c, WORD);
490 buffer.UnmarkRegionAsCpuModified(c, WORD);
491 buffer.CachedCpuWrite(c + PAGE, PAGE);
492 buffer.CachedCpuWrite(c + PAGE * 3, PAGE);
493 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE));
494 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 3, PAGE));
495 buffer.FlushCachedWrites();
496 REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
497 REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 3, PAGE));
498 buffer.MarkRegionAsCpuModified(c, WORD);
499 REQUIRE(rasterizer.Count() == 0);
500}
501
502TEST_CASE("BufferBase: Cached write unmarked") {
503 RasterizerInterface rasterizer;
504 BufferBase buffer(rasterizer, c, WORD);
505 buffer.UnmarkRegionAsCpuModified(c, WORD);
506 buffer.CachedCpuWrite(c + PAGE, PAGE);
507 buffer.UnmarkRegionAsCpuModified(c + PAGE, PAGE);
508 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE));
509 buffer.FlushCachedWrites();
510 REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
511 buffer.MarkRegionAsCpuModified(c, WORD);
512 REQUIRE(rasterizer.Count() == 0);
513}
514
515TEST_CASE("BufferBase: Cached write iterated") {
516 RasterizerInterface rasterizer;
517 BufferBase buffer(rasterizer, c, WORD);
518 buffer.UnmarkRegionAsCpuModified(c, WORD);
519 buffer.CachedCpuWrite(c + PAGE, PAGE);
520 int num = 0;
521 buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
522 REQUIRE(num == 0);
523 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE));
524 buffer.FlushCachedWrites();
525 REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
526 buffer.MarkRegionAsCpuModified(c, WORD);
527 REQUIRE(rasterizer.Count() == 0);
528}
529
530TEST_CASE("BufferBase: Cached write downloads") {
531 RasterizerInterface rasterizer;
532 BufferBase buffer(rasterizer, c, WORD);
533 buffer.UnmarkRegionAsCpuModified(c, WORD);
534 REQUIRE(rasterizer.Count() == 64);
535 buffer.CachedCpuWrite(c + PAGE, PAGE);
536 REQUIRE(rasterizer.Count() == 63);
537 buffer.MarkRegionAsGpuModified(c + PAGE, PAGE);
538 int num = 0;
539 buffer.ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; });
540 buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
541 REQUIRE(num == 0);
542 REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE));
543 REQUIRE(!buffer.IsRegionGpuModified(c + PAGE, PAGE));
544 buffer.FlushCachedWrites();
545 REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
546 REQUIRE(!buffer.IsRegionGpuModified(c + PAGE, PAGE));
547 buffer.MarkRegionAsCpuModified(c, WORD);
548 REQUIRE(rasterizer.Count() == 0);
549}
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp
new file mode 100644
index 000000000..618793668
--- /dev/null
+++ b/src/tests/video_core/memory_tracker.cpp
@@ -0,0 +1,549 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5#include <stdexcept>
6#include <unordered_map>
7
8#include <catch2/catch_test_macros.hpp>
9
10#include "common/alignment.h"
11#include "common/common_types.h"
12#include "video_core/buffer_cache/memory_tracker_base.h"
13
14namespace {
15using Range = std::pair<u64, u64>;
16
17constexpr u64 PAGE = 4096;
18constexpr u64 WORD = 4096 * 64;
19constexpr u64 HIGH_PAGE_BITS = 22;
20constexpr u64 HIGH_PAGE_SIZE = 1ULL << HIGH_PAGE_BITS;
21
22constexpr VAddr c = 16 * HIGH_PAGE_SIZE;
23
24class RasterizerInterface {
25public:
26 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
27 const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS};
28 const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >>
29 Core::Memory::YUZU_PAGEBITS};
30 for (u64 page = page_start; page < page_end; ++page) {
31 int& value = page_table[page];
32 value += delta;
33 if (value < 0) {
34 throw std::logic_error{"negative page"};
35 }
36 if (value == 0) {
37 page_table.erase(page);
38 }
39 }
40 }
41
42 [[nodiscard]] int Count(VAddr addr) const noexcept {
43 const auto it = page_table.find(addr >> Core::Memory::YUZU_PAGEBITS);
44 return it == page_table.end() ? 0 : it->second;
45 }
46
47 [[nodiscard]] unsigned Count() const noexcept {
48 unsigned count = 0;
49 for (const auto& [index, value] : page_table) {
50 count += value;
51 }
52 return count;
53 }
54
55private:
56 std::unordered_map<u64, int> page_table;
57};
58} // Anonymous namespace
59
60using MemoryTracker = VideoCommon::MemoryTrackerBase<RasterizerInterface>;
61
62TEST_CASE("MemoryTracker: Small region", "[video_core]") {
63 RasterizerInterface rasterizer;
64 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
65 REQUIRE(rasterizer.Count() == 0);
66 memory_track->UnmarkRegionAsCpuModified(c, WORD);
67 REQUIRE(rasterizer.Count() == WORD / PAGE);
68 REQUIRE(memory_track->ModifiedCpuRegion(c, WORD) == Range{0, 0});
69
70 memory_track->MarkRegionAsCpuModified(c + PAGE, 1);
71 REQUIRE(memory_track->ModifiedCpuRegion(c, WORD) == Range{c + PAGE * 1, c + PAGE * 2});
72}
73
74TEST_CASE("MemoryTracker: Large region", "[video_core]") {
75 RasterizerInterface rasterizer;
76 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
77 memory_track->UnmarkRegionAsCpuModified(c, WORD * 32);
78 memory_track->MarkRegionAsCpuModified(c + 4096, WORD * 4);
79 REQUIRE(memory_track->ModifiedCpuRegion(c, WORD + PAGE * 2) ==
80 Range{c + PAGE, c + WORD + PAGE * 2});
81 REQUIRE(memory_track->ModifiedCpuRegion(c + PAGE * 2, PAGE * 6) ==
82 Range{c + PAGE * 2, c + PAGE * 8});
83 REQUIRE(memory_track->ModifiedCpuRegion(c, WORD * 32) == Range{c + PAGE, c + WORD * 4 + PAGE});
84 REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 4, PAGE) ==
85 Range{c + WORD * 4, c + WORD * 4 + PAGE});
86 REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 3 + PAGE * 63, PAGE) ==
87 Range{c + WORD * 3 + PAGE * 63, c + WORD * 4});
88
89 memory_track->MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 6, PAGE);
90 memory_track->MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE);
91 REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 5, WORD) ==
92 Range{c + WORD * 5 + PAGE * 6, c + WORD * 5 + PAGE * 9});
93
94 memory_track->UnmarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE);
95 REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 5, WORD) ==
96 Range{c + WORD * 5 + PAGE * 6, c + WORD * 5 + PAGE * 7});
97
98 memory_track->MarkRegionAsCpuModified(c + PAGE, WORD * 31 + PAGE * 63);
99 REQUIRE(memory_track->ModifiedCpuRegion(c, WORD * 32) == Range{c + PAGE, c + WORD * 32});
100
101 memory_track->UnmarkRegionAsCpuModified(c + PAGE * 4, PAGE);
102 memory_track->UnmarkRegionAsCpuModified(c + PAGE * 6, PAGE);
103
104 memory_track->UnmarkRegionAsCpuModified(c, WORD * 32);
105 REQUIRE(memory_track->ModifiedCpuRegion(c, WORD * 32) == Range{0, 0});
106}
107
108TEST_CASE("MemoryTracker: Rasterizer counting", "[video_core]") {
109 RasterizerInterface rasterizer;
110 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
111 REQUIRE(rasterizer.Count() == 0);
112 memory_track->UnmarkRegionAsCpuModified(c, PAGE);
113 REQUIRE(rasterizer.Count() == 1);
114 memory_track->MarkRegionAsCpuModified(c, PAGE * 2);
115 REQUIRE(rasterizer.Count() == 0);
116 memory_track->UnmarkRegionAsCpuModified(c, PAGE);
117 memory_track->UnmarkRegionAsCpuModified(c + PAGE, PAGE);
118 REQUIRE(rasterizer.Count() == 2);
119 memory_track->MarkRegionAsCpuModified(c, PAGE * 2);
120 REQUIRE(rasterizer.Count() == 0);
121}
122
123TEST_CASE("MemoryTracker: Basic range", "[video_core]") {
124 RasterizerInterface rasterizer;
125 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
126 memory_track->UnmarkRegionAsCpuModified(c, WORD);
127 memory_track->MarkRegionAsCpuModified(c, PAGE);
128 int num = 0;
129 memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
130 REQUIRE(offset == c);
131 REQUIRE(size == PAGE);
132 ++num;
133 });
134 REQUIRE(num == 1U);
135}
136
137TEST_CASE("MemoryTracker: Border upload", "[video_core]") {
138 RasterizerInterface rasterizer;
139 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
140 memory_track->UnmarkRegionAsCpuModified(c, WORD * 2);
141 memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
142 memory_track->ForEachUploadRange(c, WORD * 2, [](u64 offset, u64 size) {
143 REQUIRE(offset == c + WORD - PAGE);
144 REQUIRE(size == PAGE * 2);
145 });
146}
147
148TEST_CASE("MemoryTracker: Border upload range", "[video_core]") {
149 RasterizerInterface rasterizer;
150 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
151 memory_track->UnmarkRegionAsCpuModified(c, WORD * 2);
152 memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
153 memory_track->ForEachUploadRange(c + WORD - PAGE, PAGE * 2, [](u64 offset, u64 size) {
154 REQUIRE(offset == c + WORD - PAGE);
155 REQUIRE(size == PAGE * 2);
156 });
157 memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
158 memory_track->ForEachUploadRange(c + WORD - PAGE, PAGE, [](u64 offset, u64 size) {
159 REQUIRE(offset == c + WORD - PAGE);
160 REQUIRE(size == PAGE);
161 });
162 memory_track->ForEachUploadRange(c + WORD, PAGE, [](u64 offset, u64 size) {
163 REQUIRE(offset == c + WORD);
164 REQUIRE(size == PAGE);
165 });
166}
167
168TEST_CASE("MemoryTracker: Border upload partial range", "[video_core]") {
169 RasterizerInterface rasterizer;
170 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
171 memory_track->UnmarkRegionAsCpuModified(c, WORD * 2);
172 memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
173 memory_track->ForEachUploadRange(c + WORD - 1, 2, [](u64 offset, u64 size) {
174 REQUIRE(offset == c + WORD - PAGE);
175 REQUIRE(size == PAGE * 2);
176 });
177 memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
178 memory_track->ForEachUploadRange(c + WORD - 1, 1, [](u64 offset, u64 size) {
179 REQUIRE(offset == c + WORD - PAGE);
180 REQUIRE(size == PAGE);
181 });
182 memory_track->ForEachUploadRange(c + WORD + 50, 1, [](u64 offset, u64 size) {
183 REQUIRE(offset == c + WORD);
184 REQUIRE(size == PAGE);
185 });
186}
187
188TEST_CASE("MemoryTracker: Partial word uploads", "[video_core]") {
189 RasterizerInterface rasterizer;
190 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
191 int num = 0;
192 memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
193 REQUIRE(offset == c);
194 REQUIRE(size == WORD);
195 ++num;
196 });
197 REQUIRE(num == 1);
198 memory_track->ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) {
199 REQUIRE(offset == c + WORD);
200 REQUIRE(size == WORD);
201 ++num;
202 });
203 REQUIRE(num == 2);
204 memory_track->ForEachUploadRange(c + 0x79000, 0x24000, [&](u64 offset, u64 size) {
205 REQUIRE(offset == c + WORD * 2);
206 REQUIRE(size == PAGE * 0x1d);
207 ++num;
208 });
209 REQUIRE(num == 3);
210}
211
212TEST_CASE("MemoryTracker: Partial page upload", "[video_core]") {
213 RasterizerInterface rasterizer;
214 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
215 memory_track->UnmarkRegionAsCpuModified(c, WORD);
216 int num = 0;
217 memory_track->MarkRegionAsCpuModified(c + PAGE * 2, PAGE);
218 memory_track->MarkRegionAsCpuModified(c + PAGE * 9, PAGE);
219 memory_track->ForEachUploadRange(c, PAGE * 3, [&](u64 offset, u64 size) {
220 REQUIRE(offset == c + PAGE * 2);
221 REQUIRE(size == PAGE);
222 ++num;
223 });
224 REQUIRE(num == 1);
225 memory_track->ForEachUploadRange(c + PAGE * 7, PAGE * 3, [&](u64 offset, u64 size) {
226 REQUIRE(offset == c + PAGE * 9);
227 REQUIRE(size == PAGE);
228 ++num;
229 });
230 REQUIRE(num == 2);
231}
232
233TEST_CASE("MemoryTracker: Partial page upload with multiple words on the right") {
234 RasterizerInterface rasterizer;
235 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
236 memory_track->UnmarkRegionAsCpuModified(c, WORD * 9);
237 memory_track->MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7);
238 int num = 0;
239 memory_track->ForEachUploadRange(c + PAGE * 10, WORD * 7, [&](u64 offset, u64 size) {
240 REQUIRE(offset == c + PAGE * 13);
241 REQUIRE(size == WORD * 7 - PAGE * 3);
242 ++num;
243 });
244 REQUIRE(num == 1);
245 memory_track->ForEachUploadRange(c + PAGE, WORD * 8, [&](u64 offset, u64 size) {
246 REQUIRE(offset == c + WORD * 7 + PAGE * 10);
247 REQUIRE(size == PAGE * 3);
248 ++num;
249 });
250 REQUIRE(num == 2);
251}
252
253TEST_CASE("MemoryTracker: Partial page upload with multiple words on the left", "[video_core]") {
254 RasterizerInterface rasterizer;
255 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
256 memory_track->UnmarkRegionAsCpuModified(c, WORD * 8);
257 memory_track->MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7);
258 int num = 0;
259 memory_track->ForEachUploadRange(c + PAGE * 16, WORD * 7, [&](u64 offset, u64 size) {
260 REQUIRE(offset == c + PAGE * 16);
261 REQUIRE(size == WORD * 7 - PAGE * 3);
262 ++num;
263 });
264 REQUIRE(num == 1);
265 memory_track->ForEachUploadRange(c + PAGE, WORD, [&](u64 offset, u64 size) {
266 REQUIRE(offset == c + PAGE * 13);
267 REQUIRE(size == PAGE * 3);
268 ++num;
269 });
270 REQUIRE(num == 2);
271}
272
273TEST_CASE("MemoryTracker: Partial page upload with multiple words in the middle", "[video_core]") {
274 RasterizerInterface rasterizer;
275 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
276 memory_track->UnmarkRegionAsCpuModified(c, WORD * 8);
277 memory_track->MarkRegionAsCpuModified(c + PAGE * 13, PAGE * 140);
278 int num = 0;
279 memory_track->ForEachUploadRange(c + PAGE * 16, WORD, [&](u64 offset, u64 size) {
280 REQUIRE(offset == c + PAGE * 16);
281 REQUIRE(size == WORD);
282 ++num;
283 });
284 REQUIRE(num == 1);
285 memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
286 REQUIRE(offset == c + PAGE * 13);
287 REQUIRE(size == PAGE * 3);
288 ++num;
289 });
290 REQUIRE(num == 2);
291 memory_track->ForEachUploadRange(c, WORD * 8, [&](u64 offset, u64 size) {
292 REQUIRE(offset == c + WORD + PAGE * 16);
293 REQUIRE(size == PAGE * 73);
294 ++num;
295 });
296 REQUIRE(num == 3);
297}
298
299TEST_CASE("MemoryTracker: Empty right bits", "[video_core]") {
300 RasterizerInterface rasterizer;
301 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
302 memory_track->UnmarkRegionAsCpuModified(c, WORD * 2048);
303 memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
304 memory_track->ForEachUploadRange(c, WORD * 2048, [](u64 offset, u64 size) {
305 REQUIRE(offset == c + WORD - PAGE);
306 REQUIRE(size == PAGE * 2);
307 });
308}
309
310TEST_CASE("MemoryTracker: Out of bound ranges 1", "[video_core]") {
311 RasterizerInterface rasterizer;
312 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
313 memory_track->UnmarkRegionAsCpuModified(c - WORD, 3 * WORD);
314 memory_track->MarkRegionAsCpuModified(c, PAGE);
315 REQUIRE(rasterizer.Count() == (3 * WORD - PAGE) / PAGE);
316 int num = 0;
317 memory_track->ForEachUploadRange(c - WORD, WORD, [&](u64 offset, u64 size) { ++num; });
318 memory_track->ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) { ++num; });
319 memory_track->ForEachUploadRange(c - PAGE, PAGE, [&](u64 offset, u64 size) { ++num; });
320 REQUIRE(num == 0);
321 memory_track->ForEachUploadRange(c - PAGE, PAGE * 2, [&](u64 offset, u64 size) { ++num; });
322 REQUIRE(num == 1);
323 memory_track->MarkRegionAsCpuModified(c, WORD);
324 REQUIRE(rasterizer.Count() == 2 * WORD / PAGE);
325}
326
327TEST_CASE("MemoryTracker: Out of bound ranges 2", "[video_core]") {
328 RasterizerInterface rasterizer;
329 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
330 REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c + 0x22000, PAGE));
331 REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c + 0x28000, PAGE));
332 REQUIRE(rasterizer.Count() == 2);
333 REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c + 0x21100, PAGE - 0x100));
334 REQUIRE(rasterizer.Count() == 3);
335 REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c - PAGE, PAGE * 2));
336 memory_track->UnmarkRegionAsCpuModified(c - PAGE * 3, PAGE * 2);
337 memory_track->UnmarkRegionAsCpuModified(c - PAGE * 2, PAGE * 2);
338 REQUIRE(rasterizer.Count() == 7);
339}
340
341TEST_CASE("MemoryTracker: Out of bound ranges 3", "[video_core]") {
342 RasterizerInterface rasterizer;
343 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
344 memory_track->UnmarkRegionAsCpuModified(c, 0x310720);
345 REQUIRE(rasterizer.Count(c) == 1);
346 REQUIRE(rasterizer.Count(c + PAGE) == 1);
347 REQUIRE(rasterizer.Count(c + WORD) == 1);
348 REQUIRE(rasterizer.Count(c + WORD + PAGE) == 1);
349}
350
351TEST_CASE("MemoryTracker: Sparse regions 1", "[video_core]") {
352 RasterizerInterface rasterizer;
353 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
354 memory_track->UnmarkRegionAsCpuModified(c, WORD);
355 memory_track->MarkRegionAsCpuModified(c + PAGE * 1, PAGE);
356 memory_track->MarkRegionAsCpuModified(c + PAGE * 3, PAGE * 4);
357 memory_track->ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable {
358 static constexpr std::array<u64, 2> offsets{c + PAGE, c + PAGE * 3};
359 static constexpr std::array<u64, 2> sizes{PAGE, PAGE * 4};
360 REQUIRE(offset == offsets.at(i));
361 REQUIRE(size == sizes.at(i));
362 ++i;
363 });
364}
365
366TEST_CASE("MemoryTracker: Sparse regions 2", "[video_core]") {
367 RasterizerInterface rasterizer;
368 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
369 memory_track->UnmarkRegionAsCpuModified(c, PAGE * 0x23);
370 REQUIRE(rasterizer.Count() == 0x23);
371 memory_track->MarkRegionAsCpuModified(c + PAGE * 0x1B, PAGE);
372 memory_track->MarkRegionAsCpuModified(c + PAGE * 0x21, PAGE);
373 memory_track->ForEachUploadRange(c, PAGE * 0x23, [i = 0](u64 offset, u64 size) mutable {
374 static constexpr std::array<u64, 3> offsets{c + PAGE * 0x1B, c + PAGE * 0x21};
375 static constexpr std::array<u64, 3> sizes{PAGE, PAGE};
376 REQUIRE(offset == offsets.at(i));
377 REQUIRE(size == sizes.at(i));
378 ++i;
379 });
380}
381
382TEST_CASE("MemoryTracker: Single page modified range", "[video_core]") {
383 RasterizerInterface rasterizer;
384 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
385 REQUIRE(memory_track->IsRegionCpuModified(c, PAGE));
386 memory_track->UnmarkRegionAsCpuModified(c, PAGE);
387 REQUIRE(!memory_track->IsRegionCpuModified(c, PAGE));
388}
389
390TEST_CASE("MemoryTracker: Two page modified range", "[video_core]") {
391 RasterizerInterface rasterizer;
392 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
393 REQUIRE(memory_track->IsRegionCpuModified(c, PAGE));
394 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
395 REQUIRE(memory_track->IsRegionCpuModified(c, PAGE * 2));
396 memory_track->UnmarkRegionAsCpuModified(c, PAGE);
397 REQUIRE(!memory_track->IsRegionCpuModified(c, PAGE));
398}
399
400TEST_CASE("MemoryTracker: Multi word modified ranges", "[video_core]") {
401 for (int offset = 0; offset < 4; ++offset) {
402 const VAddr address = c + WORD * offset;
403 RasterizerInterface rasterizer;
404 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
405 REQUIRE(memory_track->IsRegionCpuModified(address, PAGE));
406 REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 48, PAGE));
407 REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 56, PAGE));
408
409 memory_track->UnmarkRegionAsCpuModified(address + PAGE * 32, PAGE);
410 REQUIRE(memory_track->IsRegionCpuModified(address + PAGE, WORD));
411 REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 31, PAGE));
412 REQUIRE(!memory_track->IsRegionCpuModified(address + PAGE * 32, PAGE));
413 REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 33, PAGE));
414 REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 31, PAGE * 2));
415 REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 32, PAGE * 2));
416
417 memory_track->UnmarkRegionAsCpuModified(address + PAGE * 33, PAGE);
418 REQUIRE(!memory_track->IsRegionCpuModified(address + PAGE * 32, PAGE * 2));
419 }
420}
421
422TEST_CASE("MemoryTracker: Single page in large region", "[video_core]") {
423 RasterizerInterface rasterizer;
424 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
425 memory_track->UnmarkRegionAsCpuModified(c, WORD * 16);
426 REQUIRE(!memory_track->IsRegionCpuModified(c, WORD * 16));
427
428 memory_track->MarkRegionAsCpuModified(c + WORD * 12 + PAGE * 8, PAGE);
429 REQUIRE(memory_track->IsRegionCpuModified(c, WORD * 16));
430 REQUIRE(!memory_track->IsRegionCpuModified(c + WORD * 10, WORD * 2));
431 REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 11, WORD * 2));
432 REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12, WORD * 2));
433 REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 4, PAGE * 8));
434 REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE * 8));
435 REQUIRE(!memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE));
436 REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 7, PAGE * 2));
437 REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 8, PAGE * 2));
438}
439
440TEST_CASE("MemoryTracker: Wrap word regions") {
441 RasterizerInterface rasterizer;
442 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
443 memory_track->UnmarkRegionAsCpuModified(c, WORD * 32);
444 memory_track->MarkRegionAsCpuModified(c + PAGE * 63, PAGE * 2);
445 REQUIRE(memory_track->IsRegionCpuModified(c, WORD * 2));
446 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 62, PAGE));
447 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 63, PAGE));
448 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 64, PAGE));
449 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 63, PAGE * 2));
450 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 63, PAGE * 8));
451 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 60, PAGE * 8));
452
453 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 127, WORD * 16));
454 memory_track->MarkRegionAsCpuModified(c + PAGE * 127, PAGE);
455 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 127, WORD * 16));
456 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 127, PAGE));
457 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 126, PAGE));
458 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 126, PAGE * 2));
459 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 128, WORD * 16));
460}
461
462TEST_CASE("MemoryTracker: Unaligned page region query") {
463 RasterizerInterface rasterizer;
464 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
465 memory_track->UnmarkRegionAsCpuModified(c, WORD);
466 memory_track->MarkRegionAsCpuModified(c + 4000, 1000);
467 REQUIRE(memory_track->IsRegionCpuModified(c, PAGE));
468 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
469 REQUIRE(memory_track->IsRegionCpuModified(c + 4000, 1000));
470 REQUIRE(memory_track->IsRegionCpuModified(c + 4000, 1));
471}
472
473TEST_CASE("MemoryTracker: Cached write") {
474 RasterizerInterface rasterizer;
475 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
476 memory_track->UnmarkRegionAsCpuModified(c, WORD);
477 memory_track->CachedCpuWrite(c + PAGE, c + PAGE);
478 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE));
479 memory_track->FlushCachedWrites();
480 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
481 memory_track->MarkRegionAsCpuModified(c, WORD);
482 REQUIRE(rasterizer.Count() == 0);
483}
484
485TEST_CASE("MemoryTracker: Multiple cached write") {
486 RasterizerInterface rasterizer;
487 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
488 memory_track->UnmarkRegionAsCpuModified(c, WORD);
489 memory_track->CachedCpuWrite(c + PAGE, PAGE);
490 memory_track->CachedCpuWrite(c + PAGE * 3, PAGE);
491 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE));
492 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 3, PAGE));
493 memory_track->FlushCachedWrites();
494 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
495 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 3, PAGE));
496 memory_track->MarkRegionAsCpuModified(c, WORD);
497 REQUIRE(rasterizer.Count() == 0);
498}
499
500TEST_CASE("MemoryTracker: Cached write unmarked") {
501 RasterizerInterface rasterizer;
502 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
503 memory_track->UnmarkRegionAsCpuModified(c, WORD);
504 memory_track->CachedCpuWrite(c + PAGE, PAGE);
505 memory_track->UnmarkRegionAsCpuModified(c + PAGE, PAGE);
506 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE));
507 memory_track->FlushCachedWrites();
508 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
509 memory_track->MarkRegionAsCpuModified(c, WORD);
510 REQUIRE(rasterizer.Count() == 0);
511}
512
513TEST_CASE("MemoryTracker: Cached write iterated") {
514 RasterizerInterface rasterizer;
515 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
516 memory_track->UnmarkRegionAsCpuModified(c, WORD);
517 memory_track->CachedCpuWrite(c + PAGE, PAGE);
518 int num = 0;
519 memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
520 REQUIRE(num == 0);
521 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE));
522 memory_track->FlushCachedWrites();
523 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
524 memory_track->MarkRegionAsCpuModified(c, WORD);
525 REQUIRE(rasterizer.Count() == 0);
526}
527
528TEST_CASE("MemoryTracker: Cached write downloads") {
529 RasterizerInterface rasterizer;
530 std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer));
531 memory_track->UnmarkRegionAsCpuModified(c, WORD);
532 REQUIRE(rasterizer.Count() == 64);
533 memory_track->CachedCpuWrite(c + PAGE, PAGE);
534 REQUIRE(rasterizer.Count() == 63);
535 memory_track->MarkRegionAsGpuModified(c + PAGE, PAGE);
536 int num = 0;
537 memory_track->ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; });
538 REQUIRE(num == 0);
539 num = 0;
540 memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; });
541 REQUIRE(num == 0);
542 REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE));
543 REQUIRE(memory_track->IsRegionGpuModified(c + PAGE, PAGE));
544 memory_track->FlushCachedWrites();
545 REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE));
546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE));
547 memory_track->MarkRegionAsCpuModified(c, WORD);
548 REQUIRE(rasterizer.Count() == 0);
549} \ No newline at end of file
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index e904573d7..a0009a36f 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -11,8 +11,11 @@ endif()
11 11
12add_library(video_core STATIC 12add_library(video_core STATIC
13 buffer_cache/buffer_base.h 13 buffer_cache/buffer_base.h
14 buffer_cache/buffer_cache_base.h
14 buffer_cache/buffer_cache.cpp 15 buffer_cache/buffer_cache.cpp
15 buffer_cache/buffer_cache.h 16 buffer_cache/buffer_cache.h
17 buffer_cache/memory_tracker_base.h
18 buffer_cache/word_manager.h
16 cache_types.h 19 cache_types.h
17 cdma_pusher.cpp 20 cdma_pusher.cpp
18 cdma_pusher.h 21 cdma_pusher.h
@@ -104,6 +107,7 @@ add_library(video_core STATIC
104 renderer_null/renderer_null.h 107 renderer_null/renderer_null.h
105 renderer_opengl/blit_image.cpp 108 renderer_opengl/blit_image.cpp
106 renderer_opengl/blit_image.h 109 renderer_opengl/blit_image.h
110 renderer_opengl/gl_buffer_cache_base.cpp
107 renderer_opengl/gl_buffer_cache.cpp 111 renderer_opengl/gl_buffer_cache.cpp
108 renderer_opengl/gl_buffer_cache.h 112 renderer_opengl/gl_buffer_cache.h
109 renderer_opengl/gl_compute_pipeline.cpp 113 renderer_opengl/gl_compute_pipeline.cpp
@@ -154,6 +158,7 @@ add_library(video_core STATIC
154 renderer_vulkan/renderer_vulkan.cpp 158 renderer_vulkan/renderer_vulkan.cpp
155 renderer_vulkan/vk_blit_screen.cpp 159 renderer_vulkan/vk_blit_screen.cpp
156 renderer_vulkan/vk_blit_screen.h 160 renderer_vulkan/vk_blit_screen.h
161 renderer_vulkan/vk_buffer_cache_base.cpp
157 renderer_vulkan/vk_buffer_cache.cpp 162 renderer_vulkan/vk_buffer_cache.cpp
158 renderer_vulkan/vk_buffer_cache.h 163 renderer_vulkan/vk_buffer_cache.h
159 renderer_vulkan/vk_command_pool.cpp 164 renderer_vulkan/vk_command_pool.cpp
@@ -174,6 +179,8 @@ add_library(video_core STATIC
174 renderer_vulkan/vk_master_semaphore.h 179 renderer_vulkan/vk_master_semaphore.h
175 renderer_vulkan/vk_pipeline_cache.cpp 180 renderer_vulkan/vk_pipeline_cache.cpp
176 renderer_vulkan/vk_pipeline_cache.h 181 renderer_vulkan/vk_pipeline_cache.h
182 renderer_vulkan/vk_present_manager.cpp
183 renderer_vulkan/vk_present_manager.h
177 renderer_vulkan/vk_query_cache.cpp 184 renderer_vulkan/vk_query_cache.cpp
178 renderer_vulkan/vk_query_cache.h 185 renderer_vulkan/vk_query_cache.h
179 renderer_vulkan/vk_rasterizer.cpp 186 renderer_vulkan/vk_rasterizer.cpp
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h
index 1b4d63616..0bb3bf8ae 100644
--- a/src/video_core/buffer_cache/buffer_base.h
+++ b/src/video_core/buffer_cache/buffer_base.h
@@ -1,5 +1,5 @@
1// SPDX-FileCopyrightText: Copyright 2020 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-3.0-or-later
3 3
4#pragma once 4#pragma once
5 5
@@ -11,15 +11,14 @@
11#include "common/alignment.h" 11#include "common/alignment.h"
12#include "common/common_funcs.h" 12#include "common/common_funcs.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/div_ceil.h" 14#include "video_core/buffer_cache/word_manager.h"
15#include "common/settings.h"
16#include "core/memory.h"
17 15
18namespace VideoCommon { 16namespace VideoCommon {
19 17
20enum class BufferFlagBits { 18enum class BufferFlagBits {
21 Picked = 1 << 0, 19 Picked = 1 << 0,
22 CachedWrites = 1 << 1, 20 CachedWrites = 1 << 1,
21 PreemtiveDownload = 1 << 2,
23}; 22};
24DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits) 23DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
25 24
@@ -36,116 +35,12 @@ struct NullBufferParams {};
36 */ 35 */
37template <class RasterizerInterface> 36template <class RasterizerInterface>
38class BufferBase { 37class BufferBase {
39 static constexpr u64 PAGES_PER_WORD = 64;
40 static constexpr u64 BYTES_PER_PAGE = Core::Memory::YUZU_PAGESIZE;
41 static constexpr u64 BYTES_PER_WORD = PAGES_PER_WORD * BYTES_PER_PAGE;
42
43 /// Vector tracking modified pages tightly packed with small vector optimization
44 union WordsArray {
45 /// Returns the pointer to the words state
46 [[nodiscard]] const u64* Pointer(bool is_short) const noexcept {
47 return is_short ? &stack : heap;
48 }
49
50 /// Returns the pointer to the words state
51 [[nodiscard]] u64* Pointer(bool is_short) noexcept {
52 return is_short ? &stack : heap;
53 }
54
55 u64 stack = 0; ///< Small buffers storage
56 u64* heap; ///< Not-small buffers pointer to the storage
57 };
58
59 struct Words {
60 explicit Words() = default;
61 explicit Words(u64 size_bytes_) : size_bytes{size_bytes_} {
62 if (IsShort()) {
63 cpu.stack = ~u64{0};
64 gpu.stack = 0;
65 cached_cpu.stack = 0;
66 untracked.stack = ~u64{0};
67 } else {
68 // Share allocation between CPU and GPU pages and set their default values
69 const size_t num_words = NumWords();
70 u64* const alloc = new u64[num_words * 4];
71 cpu.heap = alloc;
72 gpu.heap = alloc + num_words;
73 cached_cpu.heap = alloc + num_words * 2;
74 untracked.heap = alloc + num_words * 3;
75 std::fill_n(cpu.heap, num_words, ~u64{0});
76 std::fill_n(gpu.heap, num_words, 0);
77 std::fill_n(cached_cpu.heap, num_words, 0);
78 std::fill_n(untracked.heap, num_words, ~u64{0});
79 }
80 // Clean up tailing bits
81 const u64 last_word_size = size_bytes % BYTES_PER_WORD;
82 const u64 last_local_page = Common::DivCeil(last_word_size, BYTES_PER_PAGE);
83 const u64 shift = (PAGES_PER_WORD - last_local_page) % PAGES_PER_WORD;
84 const u64 last_word = (~u64{0} << shift) >> shift;
85 cpu.Pointer(IsShort())[NumWords() - 1] = last_word;
86 untracked.Pointer(IsShort())[NumWords() - 1] = last_word;
87 }
88
89 ~Words() {
90 Release();
91 }
92
93 Words& operator=(Words&& rhs) noexcept {
94 Release();
95 size_bytes = rhs.size_bytes;
96 cpu = rhs.cpu;
97 gpu = rhs.gpu;
98 cached_cpu = rhs.cached_cpu;
99 untracked = rhs.untracked;
100 rhs.cpu.heap = nullptr;
101 return *this;
102 }
103
104 Words(Words&& rhs) noexcept
105 : size_bytes{rhs.size_bytes}, cpu{rhs.cpu}, gpu{rhs.gpu},
106 cached_cpu{rhs.cached_cpu}, untracked{rhs.untracked} {
107 rhs.cpu.heap = nullptr;
108 }
109
110 Words& operator=(const Words&) = delete;
111 Words(const Words&) = delete;
112
113 /// Returns true when the buffer fits in the small vector optimization
114 [[nodiscard]] bool IsShort() const noexcept {
115 return size_bytes <= BYTES_PER_WORD;
116 }
117
118 /// Returns the number of words of the buffer
119 [[nodiscard]] size_t NumWords() const noexcept {
120 return Common::DivCeil(size_bytes, BYTES_PER_WORD);
121 }
122
123 /// Release buffer resources
124 void Release() {
125 if (!IsShort()) {
126 // CPU written words is the base for the heap allocation
127 delete[] cpu.heap;
128 }
129 }
130
131 u64 size_bytes = 0;
132 WordsArray cpu;
133 WordsArray gpu;
134 WordsArray cached_cpu;
135 WordsArray untracked;
136 };
137
138 enum class Type {
139 CPU,
140 GPU,
141 CachedCPU,
142 Untracked,
143 };
144
145public: 38public:
146 explicit BufferBase(RasterizerInterface& rasterizer_, VAddr cpu_addr_, u64 size_bytes) 39 static constexpr u64 BASE_PAGE_BITS = 16;
147 : rasterizer{&rasterizer_}, cpu_addr{Common::AlignDown(cpu_addr_, BYTES_PER_PAGE)}, 40 static constexpr u64 BASE_PAGE_SIZE = 1ULL << BASE_PAGE_BITS;
148 words(Common::AlignUp(size_bytes + (cpu_addr_ - cpu_addr), BYTES_PER_PAGE)) {} 41
42 explicit BufferBase(RasterizerInterface& rasterizer_, VAddr cpu_addr_, u64 size_bytes_)
43 : cpu_addr{cpu_addr_}, size_bytes{size_bytes_} {}
149 44
150 explicit BufferBase(NullBufferParams) {} 45 explicit BufferBase(NullBufferParams) {}
151 46
@@ -155,105 +50,15 @@ public:
155 BufferBase& operator=(BufferBase&&) = default; 50 BufferBase& operator=(BufferBase&&) = default;
156 BufferBase(BufferBase&&) = default; 51 BufferBase(BufferBase&&) = default;
157 52
158 /// Returns the inclusive CPU modified range in a begin end pair
159 [[nodiscard]] std::pair<u64, u64> ModifiedCpuRegion(VAddr query_cpu_addr,
160 u64 query_size) const noexcept {
161 const u64 offset = query_cpu_addr - cpu_addr;
162 return ModifiedRegion<Type::CPU>(offset, query_size);
163 }
164
165 /// Returns the inclusive GPU modified range in a begin end pair
166 [[nodiscard]] std::pair<u64, u64> ModifiedGpuRegion(VAddr query_cpu_addr,
167 u64 query_size) const noexcept {
168 const u64 offset = query_cpu_addr - cpu_addr;
169 return ModifiedRegion<Type::GPU>(offset, query_size);
170 }
171
172 /// Returns true if a region has been modified from the CPU
173 [[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) const noexcept {
174 const u64 offset = query_cpu_addr - cpu_addr;
175 return IsRegionModified<Type::CPU>(offset, query_size);
176 }
177
178 /// Returns true if a region has been modified from the GPU
179 [[nodiscard]] bool IsRegionGpuModified(VAddr query_cpu_addr, u64 query_size) const noexcept {
180 const u64 offset = query_cpu_addr - cpu_addr;
181 return IsRegionModified<Type::GPU>(offset, query_size);
182 }
183
184 /// Mark region as CPU modified, notifying the rasterizer about this change
185 void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 size) {
186 ChangeRegionState<Type::CPU, true>(dirty_cpu_addr, size);
187 }
188
189 /// Unmark region as CPU modified, notifying the rasterizer about this change
190 void UnmarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 size) {
191 ChangeRegionState<Type::CPU, false>(dirty_cpu_addr, size);
192 }
193
194 /// Mark region as modified from the host GPU
195 void MarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 size) noexcept {
196 ChangeRegionState<Type::GPU, true>(dirty_cpu_addr, size);
197 }
198
199 /// Unmark region as modified from the host GPU
200 void UnmarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 size) noexcept {
201 ChangeRegionState<Type::GPU, false>(dirty_cpu_addr, size);
202 }
203
204 /// Mark region as modified from the CPU
205 /// but don't mark it as modified until FlusHCachedWrites is called.
206 void CachedCpuWrite(VAddr dirty_cpu_addr, u64 size) {
207 flags |= BufferFlagBits::CachedWrites;
208 ChangeRegionState<Type::CachedCPU, true>(dirty_cpu_addr, size);
209 }
210
211 /// Flushes cached CPU writes, and notify the rasterizer about the deltas
212 void FlushCachedWrites() noexcept {
213 flags &= ~BufferFlagBits::CachedWrites;
214 const u64 num_words = NumWords();
215 u64* const cached_words = Array<Type::CachedCPU>();
216 u64* const untracked_words = Array<Type::Untracked>();
217 u64* const cpu_words = Array<Type::CPU>();
218 for (u64 word_index = 0; word_index < num_words; ++word_index) {
219 const u64 cached_bits = cached_words[word_index];
220 NotifyRasterizer<false>(word_index, untracked_words[word_index], cached_bits);
221 untracked_words[word_index] |= cached_bits;
222 cpu_words[word_index] |= cached_bits;
223 if (!Settings::values.use_pessimistic_flushes) {
224 cached_words[word_index] = 0;
225 }
226 }
227 }
228
229 /// Call 'func' for each CPU modified range and unmark those pages as CPU modified
230 template <typename Func>
231 void ForEachUploadRange(VAddr query_cpu_range, u64 size, Func&& func) {
232 ForEachModifiedRange<Type::CPU>(query_cpu_range, size, true, func);
233 }
234
235 /// Call 'func' for each GPU modified range and unmark those pages as GPU modified
236 template <typename Func>
237 void ForEachDownloadRange(VAddr query_cpu_range, u64 size, bool clear, Func&& func) {
238 ForEachModifiedRange<Type::GPU>(query_cpu_range, size, clear, func);
239 }
240
241 template <typename Func>
242 void ForEachDownloadRangeAndClear(VAddr query_cpu_range, u64 size, Func&& func) {
243 ForEachModifiedRange<Type::GPU>(query_cpu_range, size, true, func);
244 }
245
246 /// Call 'func' for each GPU modified range and unmark those pages as GPU modified
247 template <typename Func>
248 void ForEachDownloadRange(Func&& func) {
249 ForEachModifiedRange<Type::GPU>(cpu_addr, SizeBytes(), true, func);
250 }
251
252 /// Mark buffer as picked 53 /// Mark buffer as picked
253 void Pick() noexcept { 54 void Pick() noexcept {
254 flags |= BufferFlagBits::Picked; 55 flags |= BufferFlagBits::Picked;
255 } 56 }
256 57
58 void MarkPreemtiveDownload() noexcept {
59 flags |= BufferFlagBits::PreemtiveDownload;
60 }
61
257 /// Unmark buffer as picked 62 /// Unmark buffer as picked
258 void Unpick() noexcept { 63 void Unpick() noexcept {
259 flags &= ~BufferFlagBits::Picked; 64 flags &= ~BufferFlagBits::Picked;
@@ -284,6 +89,10 @@ public:
284 return True(flags & BufferFlagBits::CachedWrites); 89 return True(flags & BufferFlagBits::CachedWrites);
285 } 90 }
286 91
92 bool IsPreemtiveDownload() const noexcept {
93 return True(flags & BufferFlagBits::PreemtiveDownload);
94 }
95
287 /// Returns the base CPU address of the buffer 96 /// Returns the base CPU address of the buffer
288 [[nodiscard]] VAddr CpuAddr() const noexcept { 97 [[nodiscard]] VAddr CpuAddr() const noexcept {
289 return cpu_addr; 98 return cpu_addr;
@@ -295,11 +104,6 @@ public:
295 return static_cast<u32>(other_cpu_addr - cpu_addr); 104 return static_cast<u32>(other_cpu_addr - cpu_addr);
296 } 105 }
297 106
298 /// Returns the size in bytes of the buffer
299 [[nodiscard]] u64 SizeBytes() const noexcept {
300 return words.size_bytes;
301 }
302
303 size_t getLRUID() const noexcept { 107 size_t getLRUID() const noexcept {
304 return lru_id; 108 return lru_id;
305 } 109 }
@@ -308,305 +112,16 @@ public:
308 lru_id = lru_id_; 112 lru_id = lru_id_;
309 } 113 }
310 114
311private: 115 size_t SizeBytes() const {
312 template <Type type> 116 return size_bytes;
313 u64* Array() noexcept {
314 if constexpr (type == Type::CPU) {
315 return words.cpu.Pointer(IsShort());
316 } else if constexpr (type == Type::GPU) {
317 return words.gpu.Pointer(IsShort());
318 } else if constexpr (type == Type::CachedCPU) {
319 return words.cached_cpu.Pointer(IsShort());
320 } else if constexpr (type == Type::Untracked) {
321 return words.untracked.Pointer(IsShort());
322 }
323 }
324
325 template <Type type>
326 const u64* Array() const noexcept {
327 if constexpr (type == Type::CPU) {
328 return words.cpu.Pointer(IsShort());
329 } else if constexpr (type == Type::GPU) {
330 return words.gpu.Pointer(IsShort());
331 } else if constexpr (type == Type::CachedCPU) {
332 return words.cached_cpu.Pointer(IsShort());
333 } else if constexpr (type == Type::Untracked) {
334 return words.untracked.Pointer(IsShort());
335 }
336 }
337
338 /**
339 * Change the state of a range of pages
340 *
341 * @param dirty_addr Base address to mark or unmark as modified
342 * @param size Size in bytes to mark or unmark as modified
343 */
344 template <Type type, bool enable>
345 void ChangeRegionState(u64 dirty_addr, s64 size) noexcept(type == Type::GPU) {
346 const s64 difference = dirty_addr - cpu_addr;
347 const u64 offset = std::max<s64>(difference, 0);
348 size += std::min<s64>(difference, 0);
349 if (offset >= SizeBytes() || size < 0) {
350 return;
351 }
352 u64* const untracked_words = Array<Type::Untracked>();
353 u64* const state_words = Array<type>();
354 const u64 offset_end = std::min(offset + size, SizeBytes());
355 const u64 begin_page_index = offset / BYTES_PER_PAGE;
356 const u64 begin_word_index = begin_page_index / PAGES_PER_WORD;
357 const u64 end_page_index = Common::DivCeil(offset_end, BYTES_PER_PAGE);
358 const u64 end_word_index = Common::DivCeil(end_page_index, PAGES_PER_WORD);
359 u64 page_index = begin_page_index % PAGES_PER_WORD;
360 u64 word_index = begin_word_index;
361 while (word_index < end_word_index) {
362 const u64 next_word_first_page = (word_index + 1) * PAGES_PER_WORD;
363 const u64 left_offset =
364 std::min(next_word_first_page - end_page_index, PAGES_PER_WORD) % PAGES_PER_WORD;
365 const u64 right_offset = page_index;
366 u64 bits = ~u64{0};
367 bits = (bits >> right_offset) << right_offset;
368 bits = (bits << left_offset) >> left_offset;
369 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
370 NotifyRasterizer<!enable>(word_index, untracked_words[word_index], bits);
371 }
372 if constexpr (enable) {
373 state_words[word_index] |= bits;
374 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
375 untracked_words[word_index] |= bits;
376 }
377 } else {
378 state_words[word_index] &= ~bits;
379 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
380 untracked_words[word_index] &= ~bits;
381 }
382 }
383 page_index = 0;
384 ++word_index;
385 }
386 }
387
388 /**
389 * Notify rasterizer about changes in the CPU tracking state of a word in the buffer
390 *
391 * @param word_index Index to the word to notify to the rasterizer
392 * @param current_bits Current state of the word
393 * @param new_bits New state of the word
394 *
395 * @tparam add_to_rasterizer True when the rasterizer should start tracking the new pages
396 */
397 template <bool add_to_rasterizer>
398 void NotifyRasterizer(u64 word_index, u64 current_bits, u64 new_bits) const {
399 u64 changed_bits = (add_to_rasterizer ? current_bits : ~current_bits) & new_bits;
400 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
401 while (changed_bits != 0) {
402 const int empty_bits = std::countr_zero(changed_bits);
403 addr += empty_bits * BYTES_PER_PAGE;
404 changed_bits >>= empty_bits;
405
406 const u32 continuous_bits = std::countr_one(changed_bits);
407 const u64 size = continuous_bits * BYTES_PER_PAGE;
408 const VAddr begin_addr = addr;
409 addr += size;
410 changed_bits = continuous_bits < PAGES_PER_WORD ? (changed_bits >> continuous_bits) : 0;
411 rasterizer->UpdatePagesCachedCount(begin_addr, size, add_to_rasterizer ? 1 : -1);
412 }
413 }
414
415 /**
416 * Loop over each page in the given range, turn off those bits and notify the rasterizer if
417 * needed. Call the given function on each turned off range.
418 *
419 * @param query_cpu_range Base CPU address to loop over
420 * @param size Size in bytes of the CPU range to loop over
421 * @param func Function to call for each turned off region
422 */
423 template <Type type, typename Func>
424 void ForEachModifiedRange(VAddr query_cpu_range, s64 size, bool clear, Func&& func) {
425 static_assert(type != Type::Untracked);
426
427 const s64 difference = query_cpu_range - cpu_addr;
428 const u64 query_begin = std::max<s64>(difference, 0);
429 size += std::min<s64>(difference, 0);
430 if (query_begin >= SizeBytes() || size < 0) {
431 return;
432 }
433 u64* const untracked_words = Array<Type::Untracked>();
434 u64* const state_words = Array<type>();
435 const u64 query_end = query_begin + std::min(static_cast<u64>(size), SizeBytes());
436 u64* const words_begin = state_words + query_begin / BYTES_PER_WORD;
437 u64* const words_end = state_words + Common::DivCeil(query_end, BYTES_PER_WORD);
438
439 const auto modified = [](u64 word) { return word != 0; };
440 const auto first_modified_word = std::find_if(words_begin, words_end, modified);
441 if (first_modified_word == words_end) {
442 // Exit early when the buffer is not modified
443 return;
444 }
445 const auto last_modified_word = std::find_if_not(first_modified_word, words_end, modified);
446
447 const u64 word_index_begin = std::distance(state_words, first_modified_word);
448 const u64 word_index_end = std::distance(state_words, last_modified_word);
449
450 const unsigned local_page_begin = std::countr_zero(*first_modified_word);
451 const unsigned local_page_end =
452 static_cast<unsigned>(PAGES_PER_WORD) - std::countl_zero(last_modified_word[-1]);
453 const u64 word_page_begin = word_index_begin * PAGES_PER_WORD;
454 const u64 word_page_end = (word_index_end - 1) * PAGES_PER_WORD;
455 const u64 query_page_begin = query_begin / BYTES_PER_PAGE;
456 const u64 query_page_end = Common::DivCeil(query_end, BYTES_PER_PAGE);
457 const u64 page_index_begin = std::max(word_page_begin + local_page_begin, query_page_begin);
458 const u64 page_index_end = std::min(word_page_end + local_page_end, query_page_end);
459 const u64 first_word_page_begin = page_index_begin % PAGES_PER_WORD;
460 const u64 last_word_page_end = (page_index_end - 1) % PAGES_PER_WORD + 1;
461
462 u64 page_begin = first_word_page_begin;
463 u64 current_base = 0;
464 u64 current_size = 0;
465 bool on_going = false;
466 for (u64 word_index = word_index_begin; word_index < word_index_end; ++word_index) {
467 const bool is_last_word = word_index + 1 == word_index_end;
468 const u64 page_end = is_last_word ? last_word_page_end : PAGES_PER_WORD;
469 const u64 right_offset = page_begin;
470 const u64 left_offset = PAGES_PER_WORD - page_end;
471 u64 bits = ~u64{0};
472 bits = (bits >> right_offset) << right_offset;
473 bits = (bits << left_offset) >> left_offset;
474
475 const u64 current_word = state_words[word_index] & bits;
476 if (clear) {
477 state_words[word_index] &= ~bits;
478 }
479
480 if constexpr (type == Type::CPU) {
481 const u64 current_bits = untracked_words[word_index] & bits;
482 untracked_words[word_index] &= ~bits;
483 NotifyRasterizer<true>(word_index, current_bits, ~u64{0});
484 }
485 // Exclude CPU modified pages when visiting GPU pages
486 const u64 word = current_word & ~(type == Type::GPU ? untracked_words[word_index] : 0);
487 u64 page = page_begin;
488 page_begin = 0;
489
490 while (page < page_end) {
491 const int empty_bits = std::countr_zero(word >> page);
492 if (on_going && empty_bits != 0) {
493 InvokeModifiedRange(func, current_size, current_base);
494 current_size = 0;
495 on_going = false;
496 }
497 if (empty_bits == PAGES_PER_WORD) {
498 break;
499 }
500 page += empty_bits;
501
502 const int continuous_bits = std::countr_one(word >> page);
503 if (!on_going && continuous_bits != 0) {
504 current_base = word_index * PAGES_PER_WORD + page;
505 on_going = true;
506 }
507 current_size += continuous_bits;
508 page += continuous_bits;
509 }
510 }
511 if (on_going && current_size > 0) {
512 InvokeModifiedRange(func, current_size, current_base);
513 }
514 }
515
516 template <typename Func>
517 void InvokeModifiedRange(Func&& func, u64 current_size, u64 current_base) {
518 const u64 current_size_bytes = current_size * BYTES_PER_PAGE;
519 const u64 offset_begin = current_base * BYTES_PER_PAGE;
520 const u64 offset_end = std::min(offset_begin + current_size_bytes, SizeBytes());
521 func(offset_begin, offset_end - offset_begin);
522 }
523
524 /**
525 * Returns true when a region has been modified
526 *
527 * @param offset Offset in bytes from the start of the buffer
528 * @param size Size in bytes of the region to query for modifications
529 */
530 template <Type type>
531 [[nodiscard]] bool IsRegionModified(u64 offset, u64 size) const noexcept {
532 static_assert(type != Type::Untracked);
533
534 const u64* const untracked_words = Array<Type::Untracked>();
535 const u64* const state_words = Array<type>();
536 const u64 num_query_words = size / BYTES_PER_WORD + 1;
537 const u64 word_begin = offset / BYTES_PER_WORD;
538 const u64 word_end = std::min<u64>(word_begin + num_query_words, NumWords());
539 const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
540 u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD;
541 for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) {
542 const u64 off_word = type == Type::GPU ? untracked_words[word_index] : 0;
543 const u64 word = state_words[word_index] & ~off_word;
544 if (word == 0) {
545 continue;
546 }
547 const u64 page_end = std::min((word_index + 1) * PAGES_PER_WORD, page_limit);
548 const u64 local_page_end = page_end % PAGES_PER_WORD;
549 const u64 page_end_shift = (PAGES_PER_WORD - local_page_end) % PAGES_PER_WORD;
550 if (((word >> page_index) << page_index) << page_end_shift != 0) {
551 return true;
552 }
553 }
554 return false;
555 }
556
557 /**
558 * Returns a begin end pair with the inclusive modified region
559 *
560 * @param offset Offset in bytes from the start of the buffer
561 * @param size Size in bytes of the region to query for modifications
562 */
563 template <Type type>
564 [[nodiscard]] std::pair<u64, u64> ModifiedRegion(u64 offset, u64 size) const noexcept {
565 static_assert(type != Type::Untracked);
566
567 const u64* const untracked_words = Array<Type::Untracked>();
568 const u64* const state_words = Array<type>();
569 const u64 num_query_words = size / BYTES_PER_WORD + 1;
570 const u64 word_begin = offset / BYTES_PER_WORD;
571 const u64 word_end = std::min<u64>(word_begin + num_query_words, NumWords());
572 const u64 page_base = offset / BYTES_PER_PAGE;
573 const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
574 u64 begin = std::numeric_limits<u64>::max();
575 u64 end = 0;
576 for (u64 word_index = word_begin; word_index < word_end; ++word_index) {
577 const u64 off_word = type == Type::GPU ? untracked_words[word_index] : 0;
578 const u64 word = state_words[word_index] & ~off_word;
579 if (word == 0) {
580 continue;
581 }
582 const u64 local_page_begin = std::countr_zero(word);
583 const u64 local_page_end = PAGES_PER_WORD - std::countl_zero(word);
584 const u64 page_index = word_index * PAGES_PER_WORD;
585 const u64 page_begin = std::max(page_index + local_page_begin, page_base);
586 const u64 page_end = std::min(page_index + local_page_end, page_limit);
587 begin = std::min(begin, page_begin);
588 end = std::max(end, page_end);
589 }
590 static constexpr std::pair<u64, u64> EMPTY{0, 0};
591 return begin < end ? std::make_pair(begin * BYTES_PER_PAGE, end * BYTES_PER_PAGE) : EMPTY;
592 }
593
594 /// Returns the number of words of the buffer
595 [[nodiscard]] size_t NumWords() const noexcept {
596 return words.NumWords();
597 } 117 }
598 118
599 /// Returns true when the buffer fits in the small vector optimization 119private:
600 [[nodiscard]] bool IsShort() const noexcept {
601 return words.IsShort();
602 }
603
604 RasterizerInterface* rasterizer = nullptr;
605 VAddr cpu_addr = 0; 120 VAddr cpu_addr = 0;
606 Words words;
607 BufferFlagBits flags{}; 121 BufferFlagBits flags{};
608 int stream_score = 0; 122 int stream_score = 0;
609 size_t lru_id = SIZE_MAX; 123 size_t lru_id = SIZE_MAX;
124 size_t size_bytes = 0;
610}; 125};
611 126
612} // namespace VideoCommon 127} // namespace VideoCommon
diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp
index a16308b60..40db243d2 100644
--- a/src/video_core/buffer_cache/buffer_cache.cpp
+++ b/src/video_core/buffer_cache/buffer_cache.cpp
@@ -1,5 +1,5 @@
1// SPDX-FileCopyrightText: Copyright 2021 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-3.0-or-later
3 3
4#include "common/microprofile.h" 4#include "common/microprofile.h"
5 5
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index abdc593df..6624919a4 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1,485 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2019 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-3.0-or-later
3 3
4#pragma once 4#pragma once
5 5
6#include <algorithm> 6#include <algorithm>
7#include <array>
8#include <memory> 7#include <memory>
9#include <mutex>
10#include <numeric> 8#include <numeric>
11#include <span>
12#include <vector>
13
14#include <boost/container/small_vector.hpp>
15#include <boost/icl/interval_set.hpp>
16
17#include "common/common_types.h"
18#include "common/div_ceil.h"
19#include "common/literals.h"
20#include "common/lru_cache.h"
21#include "common/microprofile.h"
22#include "common/polyfill_ranges.h"
23#include "common/scratch_buffer.h"
24#include "common/settings.h"
25#include "core/memory.h"
26#include "video_core/buffer_cache/buffer_base.h"
27#include "video_core/control/channel_state_cache.h"
28#include "video_core/delayed_destruction_ring.h"
29#include "video_core/dirty_flags.h"
30#include "video_core/engines/draw_manager.h"
31#include "video_core/engines/kepler_compute.h"
32#include "video_core/engines/maxwell_3d.h"
33#include "video_core/memory_manager.h"
34#include "video_core/rasterizer_interface.h"
35#include "video_core/surface.h"
36#include "video_core/texture_cache/slot_vector.h"
37#include "video_core/texture_cache/types.h"
38 9
39namespace VideoCommon { 10#include "video_core/buffer_cache/buffer_cache_base.h"
40
41MICROPROFILE_DECLARE(GPU_PrepareBuffers);
42MICROPROFILE_DECLARE(GPU_BindUploadBuffers);
43MICROPROFILE_DECLARE(GPU_DownloadMemory);
44
45using BufferId = SlotId;
46
47using VideoCore::Surface::PixelFormat;
48using namespace Common::Literals;
49
50constexpr u32 NUM_VERTEX_BUFFERS = 32;
51constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
52constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
53constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
54constexpr u32 NUM_STORAGE_BUFFERS = 16;
55constexpr u32 NUM_TEXTURE_BUFFERS = 16;
56constexpr u32 NUM_STAGES = 5;
57
58enum class ObtainBufferSynchronize : u32 {
59 NoSynchronize = 0,
60 FullSynchronize = 1,
61 SynchronizeNoDirty = 2,
62};
63
64enum class ObtainBufferOperation : u32 {
65 DoNothing = 0,
66 MarkAsWritten = 1,
67 DiscardWrite = 2,
68 MarkQuery = 3,
69};
70
71using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>;
72using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>;
73
74template <typename P>
75class BufferCache : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
76
77 // Page size for caching purposes.
78 // This is unrelated to the CPU page size and it can be changed as it seems optimal.
79 static constexpr u32 YUZU_PAGEBITS = 16;
80 static constexpr u64 YUZU_PAGESIZE = u64{1} << YUZU_PAGEBITS;
81
82 static constexpr bool IS_OPENGL = P::IS_OPENGL;
83 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS =
84 P::HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS;
85 static constexpr bool HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT =
86 P::HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT;
87 static constexpr bool NEEDS_BIND_UNIFORM_INDEX = P::NEEDS_BIND_UNIFORM_INDEX;
88 static constexpr bool NEEDS_BIND_STORAGE_INDEX = P::NEEDS_BIND_STORAGE_INDEX;
89 static constexpr bool USE_MEMORY_MAPS = P::USE_MEMORY_MAPS;
90 static constexpr bool SEPARATE_IMAGE_BUFFERS_BINDINGS = P::SEPARATE_IMAGE_BUFFER_BINDINGS;
91
92 static constexpr BufferId NULL_BUFFER_ID{0};
93
94 static constexpr s64 DEFAULT_EXPECTED_MEMORY = 512_MiB;
95 static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB;
96 static constexpr s64 TARGET_THRESHOLD = 4_GiB;
97
98 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
99
100 using Runtime = typename P::Runtime;
101 using Buffer = typename P::Buffer;
102
103 using IntervalSet = boost::icl::interval_set<VAddr>;
104 using IntervalType = typename IntervalSet::interval_type;
105
106 struct Empty {};
107
108 struct OverlapResult {
109 std::vector<BufferId> ids;
110 VAddr begin;
111 VAddr end;
112 bool has_stream_leap = false;
113 };
114
115 struct Binding {
116 VAddr cpu_addr{};
117 u32 size{};
118 BufferId buffer_id;
119 };
120
121 struct TextureBufferBinding : Binding {
122 PixelFormat format;
123 };
124
125 static constexpr Binding NULL_BINDING{
126 .cpu_addr = 0,
127 .size = 0,
128 .buffer_id = NULL_BUFFER_ID,
129 };
130
131public:
132 static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = static_cast<u32>(4_KiB);
133
134 explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_,
135 Core::Memory::Memory& cpu_memory_, Runtime& runtime_);
136
137 void TickFrame();
138
139 void WriteMemory(VAddr cpu_addr, u64 size);
140
141 void CachedWriteMemory(VAddr cpu_addr, u64 size);
142
143 void DownloadMemory(VAddr cpu_addr, u64 size);
144
145 bool InlineMemory(VAddr dest_address, size_t copy_size, std::span<const u8> inlined_buffer);
146
147 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size);
148
149 void DisableGraphicsUniformBuffer(size_t stage, u32 index);
150
151 void UpdateGraphicsBuffers(bool is_indexed);
152
153 void UpdateComputeBuffers();
154
155 void BindHostGeometryBuffers(bool is_indexed);
156
157 void BindHostStageBuffers(size_t stage);
158
159 void BindHostComputeBuffers();
160
161 void SetUniformBuffersState(const std::array<u32, NUM_STAGES>& mask,
162 const UniformBufferSizes* sizes);
163
164 void SetComputeUniformBufferState(u32 mask, const ComputeUniformBufferSizes* sizes);
165
166 void UnbindGraphicsStorageBuffers(size_t stage);
167
168 void BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
169 bool is_written);
170
171 void UnbindGraphicsTextureBuffers(size_t stage);
172
173 void BindGraphicsTextureBuffer(size_t stage, size_t tbo_index, GPUVAddr gpu_addr, u32 size,
174 PixelFormat format, bool is_written, bool is_image);
175
176 void UnbindComputeStorageBuffers();
177
178 void BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
179 bool is_written);
180
181 void UnbindComputeTextureBuffers();
182
183 void BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, PixelFormat format,
184 bool is_written, bool is_image);
185
186 void FlushCachedWrites();
187
188 /// Return true when there are uncommitted buffers to be downloaded
189 [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
190
191 void AccumulateFlushes();
192
193 /// Return true when the caller should wait for async downloads
194 [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
195
196 /// Commit asynchronous downloads
197 void CommitAsyncFlushes();
198 void CommitAsyncFlushesHigh();
199
200 /// Pop asynchronous downloads
201 void PopAsyncFlushes();
202
203 bool DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount);
204
205 bool DMAClear(GPUVAddr src_address, u64 amount, u32 value);
206
207 [[nodiscard]] std::pair<Buffer*, u32> ObtainBuffer(GPUVAddr gpu_addr, u32 size,
208 ObtainBufferSynchronize sync_info,
209 ObtainBufferOperation post_op);
210
211 /// Return true when a CPU region is modified from the GPU
212 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
213
214 /// Return true when a region is registered on the cache
215 [[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size);
216
217 /// Return true when a CPU region is modified from the CPU
218 [[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size);
219
220 void SetDrawIndirect(
221 const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect_) {
222 current_draw_indirect = current_draw_indirect_;
223 }
224
225 [[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
226
227 [[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
228
229 std::recursive_mutex mutex;
230 Runtime& runtime;
231
232private:
233 template <typename Func>
234 static void ForEachEnabledBit(u32 enabled_mask, Func&& func) {
235 for (u32 index = 0; enabled_mask != 0; ++index, enabled_mask >>= 1) {
236 const int disabled_bits = std::countr_zero(enabled_mask);
237 index += disabled_bits;
238 enabled_mask >>= disabled_bits;
239 func(index);
240 }
241 }
242
243 template <typename Func>
244 void ForEachBufferInRange(VAddr cpu_addr, u64 size, Func&& func) {
245 const u64 page_end = Common::DivCeil(cpu_addr + size, YUZU_PAGESIZE);
246 for (u64 page = cpu_addr >> YUZU_PAGEBITS; page < page_end;) {
247 const BufferId buffer_id = page_table[page];
248 if (!buffer_id) {
249 ++page;
250 continue;
251 }
252 Buffer& buffer = slot_buffers[buffer_id];
253 func(buffer_id, buffer);
254
255 const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes();
256 page = Common::DivCeil(end_addr, YUZU_PAGESIZE);
257 }
258 }
259
260 template <typename Func>
261 void ForEachWrittenRange(VAddr cpu_addr, u64 size, Func&& func) {
262 const VAddr start_address = cpu_addr;
263 const VAddr end_address = start_address + size;
264 const VAddr search_base =
265 static_cast<VAddr>(std::min<s64>(0LL, static_cast<s64>(start_address - size)));
266 const IntervalType search_interval{search_base, search_base + 1};
267 auto it = common_ranges.lower_bound(search_interval);
268 if (it == common_ranges.end()) {
269 it = common_ranges.begin();
270 }
271 for (; it != common_ranges.end(); it++) {
272 VAddr inter_addr_end = it->upper();
273 VAddr inter_addr = it->lower();
274 if (inter_addr >= end_address) {
275 break;
276 }
277 if (inter_addr_end <= start_address) {
278 continue;
279 }
280 if (inter_addr_end > end_address) {
281 inter_addr_end = end_address;
282 }
283 if (inter_addr < start_address) {
284 inter_addr = start_address;
285 }
286 func(inter_addr, inter_addr_end);
287 }
288 }
289
290 static bool IsRangeGranular(VAddr cpu_addr, size_t size) {
291 return (cpu_addr & ~Core::Memory::YUZU_PAGEMASK) ==
292 ((cpu_addr + size) & ~Core::Memory::YUZU_PAGEMASK);
293 }
294
295 void RunGarbageCollector();
296
297 void BindHostIndexBuffer();
298
299 void BindHostVertexBuffers();
300
301 void BindHostDrawIndirectBuffers();
302
303 void BindHostGraphicsUniformBuffers(size_t stage);
304
305 void BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 binding_index, bool needs_bind);
306
307 void BindHostGraphicsStorageBuffers(size_t stage);
308
309 void BindHostGraphicsTextureBuffers(size_t stage);
310
311 void BindHostTransformFeedbackBuffers();
312
313 void BindHostComputeUniformBuffers();
314
315 void BindHostComputeStorageBuffers();
316
317 void BindHostComputeTextureBuffers();
318
319 void DoUpdateGraphicsBuffers(bool is_indexed);
320
321 void DoUpdateComputeBuffers();
322
323 void UpdateIndexBuffer();
324
325 void UpdateVertexBuffers();
326
327 void UpdateVertexBuffer(u32 index);
328
329 void UpdateDrawIndirect();
330
331 void UpdateUniformBuffers(size_t stage);
332
333 void UpdateStorageBuffers(size_t stage);
334
335 void UpdateTextureBuffers(size_t stage);
336
337 void UpdateTransformFeedbackBuffers();
338
339 void UpdateTransformFeedbackBuffer(u32 index);
340
341 void UpdateComputeUniformBuffers();
342
343 void UpdateComputeStorageBuffers();
344
345 void UpdateComputeTextureBuffers();
346
347 void MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size);
348
349 [[nodiscard]] BufferId FindBuffer(VAddr cpu_addr, u32 size);
350
351 [[nodiscard]] OverlapResult ResolveOverlaps(VAddr cpu_addr, u32 wanted_size);
352
353 void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
354
355 [[nodiscard]] BufferId CreateBuffer(VAddr cpu_addr, u32 wanted_size);
356
357 void Register(BufferId buffer_id);
358
359 void Unregister(BufferId buffer_id);
360
361 template <bool insert>
362 void ChangeRegister(BufferId buffer_id);
363
364 void TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept;
365
366 bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size);
367
368 bool SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size);
369
370 void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
371 std::span<BufferCopy> copies);
372
373 void ImmediateUploadMemory(Buffer& buffer, u64 largest_copy,
374 std::span<const BufferCopy> copies);
375
376 void MappedUploadMemory(Buffer& buffer, u64 total_size_bytes, std::span<BufferCopy> copies);
377
378 void DownloadBufferMemory(Buffer& buffer_id);
379
380 void DownloadBufferMemory(Buffer& buffer_id, VAddr cpu_addr, u64 size);
381
382 void DeleteBuffer(BufferId buffer_id);
383
384 void NotifyBufferDeletion();
385
386 [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index,
387 bool is_written = false) const;
388
389 [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size,
390 PixelFormat format);
391
392 [[nodiscard]] std::span<const u8> ImmediateBufferWithData(VAddr cpu_addr, size_t size);
393
394 [[nodiscard]] std::span<u8> ImmediateBuffer(size_t wanted_capacity);
395
396 [[nodiscard]] bool HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept;
397
398 void ClearDownload(IntervalType subtract_interval);
399
400 VideoCore::RasterizerInterface& rasterizer;
401 Core::Memory::Memory& cpu_memory;
402
403 SlotVector<Buffer> slot_buffers;
404 DelayedDestructionRing<Buffer, 8> delayed_destruction_ring;
405
406 const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{};
407
408 u32 last_index_count = 0;
409
410 Binding index_buffer;
411 std::array<Binding, NUM_VERTEX_BUFFERS> vertex_buffers;
412 std::array<std::array<Binding, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES> uniform_buffers;
413 std::array<std::array<Binding, NUM_STORAGE_BUFFERS>, NUM_STAGES> storage_buffers;
414 std::array<std::array<TextureBufferBinding, NUM_TEXTURE_BUFFERS>, NUM_STAGES> texture_buffers;
415 std::array<Binding, NUM_TRANSFORM_FEEDBACK_BUFFERS> transform_feedback_buffers;
416 Binding count_buffer_binding;
417 Binding indirect_buffer_binding;
418
419 std::array<Binding, NUM_COMPUTE_UNIFORM_BUFFERS> compute_uniform_buffers;
420 std::array<Binding, NUM_STORAGE_BUFFERS> compute_storage_buffers;
421 std::array<TextureBufferBinding, NUM_TEXTURE_BUFFERS> compute_texture_buffers;
422
423 std::array<u32, NUM_STAGES> enabled_uniform_buffer_masks{};
424 u32 enabled_compute_uniform_buffer_mask = 0;
425
426 const UniformBufferSizes* uniform_buffer_sizes{};
427 const ComputeUniformBufferSizes* compute_uniform_buffer_sizes{};
428
429 std::array<u32, NUM_STAGES> enabled_storage_buffers{};
430 std::array<u32, NUM_STAGES> written_storage_buffers{};
431 u32 enabled_compute_storage_buffers = 0;
432 u32 written_compute_storage_buffers = 0;
433
434 std::array<u32, NUM_STAGES> enabled_texture_buffers{};
435 std::array<u32, NUM_STAGES> written_texture_buffers{};
436 std::array<u32, NUM_STAGES> image_texture_buffers{};
437 u32 enabled_compute_texture_buffers = 0;
438 u32 written_compute_texture_buffers = 0;
439 u32 image_compute_texture_buffers = 0;
440
441 std::array<u32, 16> uniform_cache_hits{};
442 std::array<u32, 16> uniform_cache_shots{};
443
444 u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE;
445
446 bool has_deleted_buffers = false;
447
448 std::conditional_t<HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS, std::array<u32, NUM_STAGES>, Empty>
449 dirty_uniform_buffers{};
450 std::conditional_t<IS_OPENGL, std::array<u32, NUM_STAGES>, Empty> fast_bound_uniform_buffers{};
451 std::conditional_t<HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS,
452 std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>, Empty>
453 uniform_buffer_binding_sizes{};
454 11
455 std::vector<BufferId> cached_write_buffer_ids; 12namespace VideoCommon {
456
457 IntervalSet uncommitted_ranges;
458 IntervalSet common_ranges;
459 std::deque<IntervalSet> committed_ranges;
460
461 Common::ScratchBuffer<u8> immediate_buffer_alloc;
462
463 struct LRUItemParams {
464 using ObjectType = BufferId;
465 using TickType = u64;
466 };
467 Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
468 u64 frame_tick = 0;
469 u64 total_used_memory = 0;
470 u64 minimum_memory = 0;
471 u64 critical_memory = 0;
472 13
473 std::array<BufferId, ((1ULL << 39) >> YUZU_PAGEBITS)> page_table; 14using Core::Memory::YUZU_PAGESIZE;
474};
475 15
476template <class P> 16template <class P>
477BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_, 17BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
478 Core::Memory::Memory& cpu_memory_, Runtime& runtime_) 18 Core::Memory::Memory& cpu_memory_, Runtime& runtime_)
479 : runtime{runtime_}, rasterizer{rasterizer_}, cpu_memory{cpu_memory_} { 19 : runtime{runtime_}, rasterizer{rasterizer_}, cpu_memory{cpu_memory_}, memory_tracker{
20 rasterizer} {
480 // Ensure the first slot is used for the null buffer 21 // Ensure the first slot is used for the null buffer
481 void(slot_buffers.insert(runtime, NullBufferParams{})); 22 void(slot_buffers.insert(runtime, NullBufferParams{}));
482 common_ranges.clear(); 23 common_ranges.clear();
24 inline_buffer_id = NULL_BUFFER_ID;
483 25
484 if (!runtime.CanReportMemoryUsage()) { 26 if (!runtime.CanReportMemoryUsage()) {
485 minimum_memory = DEFAULT_EXPECTED_MEMORY; 27 minimum_memory = DEFAULT_EXPECTED_MEMORY;
@@ -543,35 +85,78 @@ void BufferCache<P>::TickFrame() {
543 } 85 }
544 ++frame_tick; 86 ++frame_tick;
545 delayed_destruction_ring.Tick(); 87 delayed_destruction_ring.Tick();
88
89 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
90 for (auto& buffer : async_buffers_death_ring) {
91 runtime.FreeDeferredStagingBuffer(buffer);
92 }
93 async_buffers_death_ring.clear();
94 }
546} 95}
547 96
548template <class P> 97template <class P>
549void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) { 98void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) {
550 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) { 99 memory_tracker.MarkRegionAsCpuModified(cpu_addr, size);
551 buffer.MarkRegionAsCpuModified(cpu_addr, size); 100 if (memory_tracker.IsRegionGpuModified(cpu_addr, size)) {
552 }); 101 const IntervalType subtract_interval{cpu_addr, cpu_addr + size};
102 ClearDownload(subtract_interval);
103 common_ranges.subtract(subtract_interval);
104 }
553} 105}
554 106
555template <class P> 107template <class P>
556void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) { 108void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) {
557 ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) { 109 memory_tracker.CachedCpuWrite(cpu_addr, size);
558 if (!buffer.HasCachedWrites()) { 110}
559 cached_write_buffer_ids.push_back(buffer_id); 111
560 } 112template <class P>
561 buffer.CachedCpuWrite(cpu_addr, size); 113std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(VAddr cpu_addr,
562 }); 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 memory_tracker.MarkRegionAsPreflushable(cpu_addr_start_aligned,
126 cpu_addr_end_aligned - cpu_addr_start_aligned);
127 area->preemtive = !IsRegionGpuModified(cpu_addr, size);
128 return area;
563} 129}
564 130
565template <class P> 131template <class P>
566void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) { 132void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) {
133 WaitOnAsyncFlushes(cpu_addr, size);
567 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) { 134 ForEachBufferInRange(cpu_addr, size, [&](BufferId, Buffer& buffer) {
568 DownloadBufferMemory(buffer, cpu_addr, size); 135 DownloadBufferMemory(buffer, cpu_addr, size);
569 }); 136 });
570} 137}
571 138
572template <class P> 139template <class P>
140void BufferCache<P>::WaitOnAsyncFlushes(VAddr cpu_addr, u64 size) {
141 bool must_wait = false;
142 ForEachInOverlapCounter(async_downloads, cpu_addr, size,
143 [&](VAddr, VAddr, int) { must_wait = true; });
144 bool must_release = false;
145 ForEachInRangeSet(pending_ranges, cpu_addr, size, [&](VAddr, VAddr) { must_release = true; });
146 if (must_release) {
147 std::function<void()> tmp([]() {});
148 rasterizer.SignalFence(std::move(tmp));
149 }
150 if (must_wait || must_release) {
151 rasterizer.ReleaseFences();
152 }
153}
154
155template <class P>
573void BufferCache<P>::ClearDownload(IntervalType subtract_interval) { 156void BufferCache<P>::ClearDownload(IntervalType subtract_interval) {
157 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1024);
574 uncommitted_ranges.subtract(subtract_interval); 158 uncommitted_ranges.subtract(subtract_interval);
159 pending_ranges.subtract(subtract_interval);
575 for (auto& interval_set : committed_ranges) { 160 for (auto& interval_set : committed_ranges) {
576 interval_set.subtract(subtract_interval); 161 interval_set.subtract(subtract_interval);
577 } 162 }
@@ -591,6 +176,7 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
591 } 176 }
592 177
593 const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount}; 178 const IntervalType subtract_interval{*cpu_dest_address, *cpu_dest_address + amount};
179 WaitOnAsyncFlushes(*cpu_src_address, static_cast<u32>(amount));
594 ClearDownload(subtract_interval); 180 ClearDownload(subtract_interval);
595 181
596 BufferId buffer_a; 182 BufferId buffer_a;
@@ -616,10 +202,11 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
616 const VAddr diff = base_address - *cpu_src_address; 202 const VAddr diff = base_address - *cpu_src_address;
617 const VAddr new_base_address = *cpu_dest_address + diff; 203 const VAddr new_base_address = *cpu_dest_address + diff;
618 const IntervalType add_interval{new_base_address, new_base_address + size}; 204 const IntervalType add_interval{new_base_address, new_base_address + size};
619 uncommitted_ranges.add(add_interval);
620 tmp_intervals.push_back(add_interval); 205 tmp_intervals.push_back(add_interval);
206 uncommitted_ranges.add(add_interval);
207 pending_ranges.add(add_interval);
621 }; 208 };
622 ForEachWrittenRange(*cpu_src_address, amount, mirror); 209 ForEachInRangeSet(common_ranges, *cpu_src_address, amount, mirror);
623 // This subtraction in this order is important for overlapping copies. 210 // This subtraction in this order is important for overlapping copies.
624 common_ranges.subtract(subtract_interval); 211 common_ranges.subtract(subtract_interval);
625 const bool has_new_downloads = tmp_intervals.size() != 0; 212 const bool has_new_downloads = tmp_intervals.size() != 0;
@@ -628,9 +215,9 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
628 } 215 }
629 runtime.CopyBuffer(dest_buffer, src_buffer, copies); 216 runtime.CopyBuffer(dest_buffer, src_buffer, copies);
630 if (has_new_downloads) { 217 if (has_new_downloads) {
631 dest_buffer.MarkRegionAsGpuModified(*cpu_dest_address, amount); 218 memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount);
632 } 219 }
633 std::vector<u8> tmp_buffer(amount); 220 tmp_buffer.resize(amount);
634 cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount); 221 cpu_memory.ReadBlockUnsafe(*cpu_src_address, tmp_buffer.data(), amount);
635 cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount); 222 cpu_memory.WriteBlockUnsafe(*cpu_dest_address, tmp_buffer.data(), amount);
636 return true; 223 return true;
@@ -866,10 +453,7 @@ void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_add
866 453
867template <class P> 454template <class P>
868void BufferCache<P>::FlushCachedWrites() { 455void BufferCache<P>::FlushCachedWrites() {
869 for (const BufferId buffer_id : cached_write_buffer_ids) { 456 memory_tracker.FlushCachedWrites();
870 slot_buffers[buffer_id].FlushCachedWrites();
871 }
872 cached_write_buffer_ids.clear();
873} 457}
874 458
875template <class P> 459template <class P>
@@ -879,10 +463,6 @@ bool BufferCache<P>::HasUncommittedFlushes() const noexcept {
879 463
880template <class P> 464template <class P>
881void BufferCache<P>::AccumulateFlushes() { 465void BufferCache<P>::AccumulateFlushes() {
882 if (Settings::values.gpu_accuracy.GetValue() != Settings::GPUAccuracy::High) {
883 uncommitted_ranges.clear();
884 return;
885 }
886 if (uncommitted_ranges.empty()) { 466 if (uncommitted_ranges.empty()) {
887 return; 467 return;
888 } 468 }
@@ -891,7 +471,11 @@ void BufferCache<P>::AccumulateFlushes() {
891 471
892template <class P> 472template <class P>
893bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept { 473bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
894 return false; 474 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
475 return (!async_buffers.empty() && async_buffers.front().has_value());
476 } else {
477 return false;
478 }
895} 479}
896 480
897template <class P> 481template <class P>
@@ -899,12 +483,15 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
899 AccumulateFlushes(); 483 AccumulateFlushes();
900 484
901 if (committed_ranges.empty()) { 485 if (committed_ranges.empty()) {
486 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
487
488 async_buffers.emplace_back(std::optional<Async_Buffer>{});
489 }
902 return; 490 return;
903 } 491 }
904 MICROPROFILE_SCOPE(GPU_DownloadMemory); 492 MICROPROFILE_SCOPE(GPU_DownloadMemory);
905 const bool is_accuracy_normal =
906 Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::Normal;
907 493
494 pending_ranges.clear();
908 auto it = committed_ranges.begin(); 495 auto it = committed_ranges.begin();
909 while (it != committed_ranges.end()) { 496 while (it != committed_ranges.end()) {
910 auto& current_intervals = *it; 497 auto& current_intervals = *it;
@@ -926,11 +513,12 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
926 const std::size_t size = interval.upper() - interval.lower(); 513 const std::size_t size = interval.upper() - interval.lower();
927 const VAddr cpu_addr = interval.lower(); 514 const VAddr cpu_addr = interval.lower();
928 ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) { 515 ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
929 buffer.ForEachDownloadRangeAndClear( 516 const VAddr buffer_start = buffer.CpuAddr();
930 cpu_addr, size, [&](u64 range_offset, u64 range_size) { 517 const VAddr buffer_end = buffer_start + buffer.SizeBytes();
931 if (is_accuracy_normal) { 518 const VAddr new_start = std::max(buffer_start, cpu_addr);
932 return; 519 const VAddr new_end = std::min(buffer_end, cpu_addr + size);
933 } 520 memory_tracker.ForEachDownloadRange(
521 new_start, new_end - new_start, false, [&](u64 cpu_addr_out, u64 range_size) {
934 const VAddr buffer_addr = buffer.CpuAddr(); 522 const VAddr buffer_addr = buffer.CpuAddr();
935 const auto add_download = [&](VAddr start, VAddr end) { 523 const auto add_download = [&](VAddr start, VAddr end) {
936 const u64 new_offset = start - buffer_addr; 524 const u64 new_offset = start - buffer_addr;
@@ -944,92 +532,143 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
944 buffer_id, 532 buffer_id,
945 }); 533 });
946 // Align up to avoid cache conflicts 534 // Align up to avoid cache conflicts
947 constexpr u64 align = 8ULL; 535 constexpr u64 align = 64ULL;
948 constexpr u64 mask = ~(align - 1ULL); 536 constexpr u64 mask = ~(align - 1ULL);
949 total_size_bytes += (new_size + align - 1) & mask; 537 total_size_bytes += (new_size + align - 1) & mask;
950 largest_copy = std::max(largest_copy, new_size); 538 largest_copy = std::max(largest_copy, new_size);
951 }; 539 };
952 540
953 const VAddr start_address = buffer_addr + range_offset; 541 ForEachInRangeSet(common_ranges, cpu_addr_out, range_size, add_download);
954 const VAddr end_address = start_address + range_size;
955 ForEachWrittenRange(start_address, range_size, add_download);
956 const IntervalType subtract_interval{start_address, end_address};
957 common_ranges.subtract(subtract_interval);
958 }); 542 });
959 }); 543 });
960 } 544 }
961 } 545 }
962 committed_ranges.clear(); 546 committed_ranges.clear();
963 if (downloads.empty()) { 547 if (downloads.empty()) {
548 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
549
550 async_buffers.emplace_back(std::optional<Async_Buffer>{});
551 }
964 return; 552 return;
965 } 553 }
966 if constexpr (USE_MEMORY_MAPS) { 554 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
967 auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes); 555 auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes, true);
556 boost::container::small_vector<BufferCopy, 4> normalized_copies;
557 IntervalSet new_async_range{};
968 runtime.PreCopyBarrier(); 558 runtime.PreCopyBarrier();
969 for (auto& [copy, buffer_id] : downloads) { 559 for (auto& [copy, buffer_id] : downloads) {
970 // Have in mind the staging buffer offset for the copy
971 copy.dst_offset += download_staging.offset; 560 copy.dst_offset += download_staging.offset;
972 const std::array copies{copy}; 561 const std::array copies{copy};
973 runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies, false); 562 BufferCopy second_copy{copy};
563 Buffer& buffer = slot_buffers[buffer_id];
564 second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
565 VAddr orig_cpu_addr = static_cast<VAddr>(second_copy.src_offset);
566 const IntervalType base_interval{orig_cpu_addr, orig_cpu_addr + copy.size};
567 async_downloads += std::make_pair(base_interval, 1);
568 runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
569 normalized_copies.push_back(second_copy);
974 } 570 }
975 runtime.PostCopyBarrier(); 571 runtime.PostCopyBarrier();
976 runtime.Finish(); 572 pending_downloads.emplace_back(std::move(normalized_copies));
977 for (const auto& [copy, buffer_id] : downloads) { 573 async_buffers.emplace_back(download_staging);
978 const Buffer& buffer = slot_buffers[buffer_id];
979 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
980 // Undo the modified offset
981 const u64 dst_offset = copy.dst_offset - download_staging.offset;
982 const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset;
983 cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size);
984 }
985 } else { 574 } else {
986 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy); 575 if (!Settings::IsGPULevelHigh()) {
987 for (const auto& [copy, buffer_id] : downloads) { 576 committed_ranges.clear();
988 Buffer& buffer = slot_buffers[buffer_id]; 577 uncommitted_ranges.clear();
989 buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size)); 578 } else {
990 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; 579 if constexpr (USE_MEMORY_MAPS) {
991 cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size); 580 auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
581 runtime.PreCopyBarrier();
582 for (auto& [copy, buffer_id] : downloads) {
583 // Have in mind the staging buffer offset for the copy
584 copy.dst_offset += download_staging.offset;
585 const std::array copies{copy};
586 runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies,
587 false);
588 }
589 runtime.PostCopyBarrier();
590 runtime.Finish();
591 for (const auto& [copy, buffer_id] : downloads) {
592 const Buffer& buffer = slot_buffers[buffer_id];
593 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
594 // Undo the modified offset
595 const u64 dst_offset = copy.dst_offset - download_staging.offset;
596 const u8* read_mapped_memory = download_staging.mapped_span.data() + dst_offset;
597 cpu_memory.WriteBlockUnsafe(cpu_addr, read_mapped_memory, copy.size);
598 }
599 } else {
600 const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
601 for (const auto& [copy, buffer_id] : downloads) {
602 Buffer& buffer = slot_buffers[buffer_id];
603 buffer.ImmediateDownload(copy.src_offset,
604 immediate_buffer.subspan(0, copy.size));
605 const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset;
606 cpu_memory.WriteBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size);
607 }
608 }
992 } 609 }
993 } 610 }
994} 611}
995 612
996template <class P> 613template <class P>
997void BufferCache<P>::CommitAsyncFlushes() { 614void BufferCache<P>::CommitAsyncFlushes() {
998 if (Settings::values.gpu_accuracy.GetValue() == Settings::GPUAccuracy::High) { 615 CommitAsyncFlushesHigh();
999 CommitAsyncFlushesHigh();
1000 } else {
1001 uncommitted_ranges.clear();
1002 committed_ranges.clear();
1003 }
1004} 616}
1005 617
1006template <class P> 618template <class P>
1007void BufferCache<P>::PopAsyncFlushes() {} 619void BufferCache<P>::PopAsyncFlushes() {
620 MICROPROFILE_SCOPE(GPU_DownloadMemory);
621 PopAsyncBuffers();
622}
1008 623
1009template <class P> 624template <class P>
1010bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { 625void BufferCache<P>::PopAsyncBuffers() {
1011 const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE); 626 if (async_buffers.empty()) {
1012 for (u64 page = addr >> YUZU_PAGEBITS; page < page_end;) { 627 return;
1013 const BufferId image_id = page_table[page]; 628 }
1014 if (!image_id) { 629 if (!async_buffers.front().has_value()) {
1015 ++page; 630 async_buffers.pop_front();
1016 continue; 631 return;
1017 } 632 }
1018 Buffer& buffer = slot_buffers[image_id]; 633 if constexpr (IMPLEMENTS_ASYNC_DOWNLOADS) {
1019 if (buffer.IsRegionGpuModified(addr, size)) { 634 auto& downloads = pending_downloads.front();
1020 return true; 635 auto& async_buffer = async_buffers.front();
636 u8* base = async_buffer->mapped_span.data();
637 const size_t base_offset = async_buffer->offset;
638 for (const auto& copy : downloads) {
639 const VAddr cpu_addr = static_cast<VAddr>(copy.src_offset);
640 const u64 dst_offset = copy.dst_offset - base_offset;
641 const u8* read_mapped_memory = base + dst_offset;
642 ForEachInOverlapCounter(
643 async_downloads, cpu_addr, copy.size, [&](VAddr start, VAddr end, int count) {
644 cpu_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - cpu_addr],
645 end - start);
646 if (count == 1) {
647 const IntervalType base_interval{start, end};
648 common_ranges.subtract(base_interval);
649 }
650 });
651 const IntervalType subtract_interval{cpu_addr, cpu_addr + copy.size};
652 RemoveEachInOverlapCounter(async_downloads, subtract_interval, -1);
1021 } 653 }
1022 const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes(); 654 async_buffers_death_ring.emplace_back(*async_buffer);
1023 page = Common::DivCeil(end_addr, YUZU_PAGESIZE); 655 async_buffers.pop_front();
656 pending_downloads.pop_front();
1024 } 657 }
1025 return false; 658}
659
660template <class P>
661bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) {
662 bool is_dirty = false;
663 ForEachInRangeSet(common_ranges, addr, size, [&](VAddr, VAddr) { is_dirty = true; });
664 return is_dirty;
1026} 665}
1027 666
1028template <class P> 667template <class P>
1029bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) { 668bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) {
1030 const VAddr end_addr = addr + size; 669 const VAddr end_addr = addr + size;
1031 const u64 page_end = Common::DivCeil(end_addr, YUZU_PAGESIZE); 670 const u64 page_end = Common::DivCeil(end_addr, CACHING_PAGESIZE);
1032 for (u64 page = addr >> YUZU_PAGEBITS; page < page_end;) { 671 for (u64 page = addr >> CACHING_PAGEBITS; page < page_end;) {
1033 const BufferId buffer_id = page_table[page]; 672 const BufferId buffer_id = page_table[page];
1034 if (!buffer_id) { 673 if (!buffer_id) {
1035 ++page; 674 ++page;
@@ -1041,28 +680,14 @@ bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) {
1041 if (buf_start_addr < end_addr && addr < buf_end_addr) { 680 if (buf_start_addr < end_addr && addr < buf_end_addr) {
1042 return true; 681 return true;
1043 } 682 }
1044 page = Common::DivCeil(end_addr, YUZU_PAGESIZE); 683 page = Common::DivCeil(end_addr, CACHING_PAGESIZE);
1045 } 684 }
1046 return false; 685 return false;
1047} 686}
1048 687
1049template <class P> 688template <class P>
1050bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) { 689bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) {
1051 const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE); 690 return memory_tracker.IsRegionCpuModified(addr, size);
1052 for (u64 page = addr >> YUZU_PAGEBITS; page < page_end;) {
1053 const BufferId image_id = page_table[page];
1054 if (!image_id) {
1055 ++page;
1056 continue;
1057 }
1058 Buffer& buffer = slot_buffers[image_id];
1059 if (buffer.IsRegionCpuModified(addr, size)) {
1060 return true;
1061 }
1062 const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes();
1063 page = Common::DivCeil(end_addr, YUZU_PAGESIZE);
1064 }
1065 return false;
1066} 691}
1067 692
1068template <class P> 693template <class P>
@@ -1072,7 +697,7 @@ void BufferCache<P>::BindHostIndexBuffer() {
1072 const u32 offset = buffer.Offset(index_buffer.cpu_addr); 697 const u32 offset = buffer.Offset(index_buffer.cpu_addr);
1073 const u32 size = index_buffer.size; 698 const u32 size = index_buffer.size;
1074 const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); 699 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
1075 if (!draw_state.inline_index_draw_indexes.empty()) { 700 if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
1076 if constexpr (USE_MEMORY_MAPS) { 701 if constexpr (USE_MEMORY_MAPS) {
1077 auto upload_staging = runtime.UploadStagingBuffer(size); 702 auto upload_staging = runtime.UploadStagingBuffer(size);
1078 std::array<BufferCopy, 1> copies{ 703 std::array<BufferCopy, 1> copies{
@@ -1155,7 +780,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
1155 TouchBuffer(buffer, binding.buffer_id); 780 TouchBuffer(buffer, binding.buffer_id);
1156 const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID && 781 const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
1157 size <= uniform_buffer_skip_cache_size && 782 size <= uniform_buffer_skip_cache_size &&
1158 !buffer.IsRegionGpuModified(cpu_addr, size); 783 !memory_tracker.IsRegionGpuModified(cpu_addr, size);
1159 if (use_fast_buffer) { 784 if (use_fast_buffer) {
1160 if constexpr (IS_OPENGL) { 785 if constexpr (IS_OPENGL) {
1161 if (runtime.HasFastBufferSubData()) { 786 if (runtime.HasFastBufferSubData()) {
@@ -1378,27 +1003,36 @@ void BufferCache<P>::UpdateIndexBuffer() {
1378 // We have to check for the dirty flags and index count 1003 // We have to check for the dirty flags and index count
1379 // The index count is currently changed without updating the dirty flags 1004 // The index count is currently changed without updating the dirty flags
1380 const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); 1005 const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
1381 const auto& index_array = draw_state.index_buffer; 1006 const auto& index_buffer_ref = draw_state.index_buffer;
1382 auto& flags = maxwell3d->dirty.flags; 1007 auto& flags = maxwell3d->dirty.flags;
1383 if (!flags[Dirty::IndexBuffer]) { 1008 if (!flags[Dirty::IndexBuffer]) {
1384 return; 1009 return;
1385 } 1010 }
1386 flags[Dirty::IndexBuffer] = false; 1011 flags[Dirty::IndexBuffer] = false;
1387 last_index_count = index_array.count; 1012 if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
1388 if (!draw_state.inline_index_draw_indexes.empty()) {
1389 auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size()); 1013 auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size());
1014 u32 buffer_size = Common::AlignUp(inline_index_size, CACHING_PAGESIZE);
1015 if (inline_buffer_id == NULL_BUFFER_ID) [[unlikely]] {
1016 inline_buffer_id = CreateBuffer(0, buffer_size);
1017 }
1018 if (slot_buffers[inline_buffer_id].SizeBytes() < buffer_size) [[unlikely]] {
1019 slot_buffers.erase(inline_buffer_id);
1020 inline_buffer_id = CreateBuffer(0, buffer_size);
1021 }
1390 index_buffer = Binding{ 1022 index_buffer = Binding{
1391 .cpu_addr = 0, 1023 .cpu_addr = 0,
1392 .size = inline_index_size, 1024 .size = inline_index_size,
1393 .buffer_id = CreateBuffer(0, inline_index_size), 1025 .buffer_id = inline_buffer_id,
1394 }; 1026 };
1395 return; 1027 return;
1396 } 1028 }
1397 const GPUVAddr gpu_addr_begin = index_array.StartAddress(); 1029
1398 const GPUVAddr gpu_addr_end = index_array.EndAddress(); 1030 const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress();
1031 const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
1399 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin); 1032 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
1400 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin); 1033 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
1401 const u32 draw_size = (index_array.count + index_array.first) * index_array.FormatSizeInBytes(); 1034 const u32 draw_size =
1035 (index_buffer_ref.count + index_buffer_ref.first) * index_buffer_ref.FormatSizeInBytes();
1402 const u32 size = std::min(address_size, draw_size); 1036 const u32 size = std::min(address_size, draw_size);
1403 if (size == 0 || !cpu_addr) { 1037 if (size == 0 || !cpu_addr) {
1404 index_buffer = NULL_BINDING; 1038 index_buffer = NULL_BINDING;
@@ -1434,17 +1068,15 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
1434 const GPUVAddr gpu_addr_begin = array.Address(); 1068 const GPUVAddr gpu_addr_begin = array.Address();
1435 const GPUVAddr gpu_addr_end = limit.Address() + 1; 1069 const GPUVAddr gpu_addr_end = limit.Address() + 1;
1436 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin); 1070 const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
1437 u32 address_size = static_cast<u32>( 1071 const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
1438 std::min(gpu_addr_end - gpu_addr_begin, static_cast<u64>(std::numeric_limits<u32>::max()))); 1072 u32 size = address_size; // TODO: Analyze stride and number of vertices
1439 if (array.enable == 0 || address_size == 0 || !cpu_addr) { 1073 if (array.enable == 0 || size == 0 || !cpu_addr) {
1440 vertex_buffers[index] = NULL_BINDING; 1074 vertex_buffers[index] = NULL_BINDING;
1441 return; 1075 return;
1442 } 1076 }
1443 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) { 1077 if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end)) {
1444 address_size = 1078 size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
1445 static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, address_size));
1446 } 1079 }
1447 const u32 size = address_size; // TODO: Analyze stride and number of vertices
1448 vertex_buffers[index] = Binding{ 1080 vertex_buffers[index] = Binding{
1449 .cpu_addr = *cpu_addr, 1081 .cpu_addr = *cpu_addr,
1450 .size = size, 1082 .size = size,
@@ -1591,17 +1223,16 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
1591 1223
1592template <class P> 1224template <class P>
1593void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) { 1225void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) {
1594 Buffer& buffer = slot_buffers[buffer_id]; 1226 memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
1595 buffer.MarkRegionAsGpuModified(cpu_addr, size); 1227
1228 if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) {
1229 SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size);
1230 }
1596 1231
1597 const IntervalType base_interval{cpu_addr, cpu_addr + size}; 1232 const IntervalType base_interval{cpu_addr, cpu_addr + size};
1598 common_ranges.add(base_interval); 1233 common_ranges.add(base_interval);
1599
1600 const bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
1601 if (!is_async) {
1602 return;
1603 }
1604 uncommitted_ranges.add(base_interval); 1234 uncommitted_ranges.add(base_interval);
1235 pending_ranges.add(base_interval);
1605} 1236}
1606 1237
1607template <class P> 1238template <class P>
@@ -1609,7 +1240,7 @@ BufferId BufferCache<P>::FindBuffer(VAddr cpu_addr, u32 size) {
1609 if (cpu_addr == 0) { 1240 if (cpu_addr == 0) {
1610 return NULL_BUFFER_ID; 1241 return NULL_BUFFER_ID;
1611 } 1242 }
1612 const u64 page = cpu_addr >> YUZU_PAGEBITS; 1243 const u64 page = cpu_addr >> CACHING_PAGEBITS;
1613 const BufferId buffer_id = page_table[page]; 1244 const BufferId buffer_id = page_table[page];
1614 if (!buffer_id) { 1245 if (!buffer_id) {
1615 return CreateBuffer(cpu_addr, size); 1246 return CreateBuffer(cpu_addr, size);
@@ -1638,9 +1269,9 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
1638 .has_stream_leap = has_stream_leap, 1269 .has_stream_leap = has_stream_leap,
1639 }; 1270 };
1640 } 1271 }
1641 for (; cpu_addr >> YUZU_PAGEBITS < Common::DivCeil(end, YUZU_PAGESIZE); 1272 for (; cpu_addr >> CACHING_PAGEBITS < Common::DivCeil(end, CACHING_PAGESIZE);
1642 cpu_addr += YUZU_PAGESIZE) { 1273 cpu_addr += CACHING_PAGESIZE) {
1643 const BufferId overlap_id = page_table[cpu_addr >> YUZU_PAGEBITS]; 1274 const BufferId overlap_id = page_table[cpu_addr >> CACHING_PAGEBITS];
1644 if (!overlap_id) { 1275 if (!overlap_id) {
1645 continue; 1276 continue;
1646 } 1277 }
@@ -1666,11 +1297,11 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
1666 // as a stream buffer. Increase the size to skip constantly recreating buffers. 1297 // as a stream buffer. Increase the size to skip constantly recreating buffers.
1667 has_stream_leap = true; 1298 has_stream_leap = true;
1668 if (expands_right) { 1299 if (expands_right) {
1669 begin -= YUZU_PAGESIZE * 256; 1300 begin -= CACHING_PAGESIZE * 256;
1670 cpu_addr = begin; 1301 cpu_addr = begin;
1671 } 1302 }
1672 if (expands_left) { 1303 if (expands_left) {
1673 end += YUZU_PAGESIZE * 256; 1304 end += CACHING_PAGESIZE * 256;
1674 } 1305 }
1675 } 1306 }
1676 } 1307 }
@@ -1690,25 +1321,22 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
1690 if (accumulate_stream_score) { 1321 if (accumulate_stream_score) {
1691 new_buffer.IncreaseStreamScore(overlap.StreamScore() + 1); 1322 new_buffer.IncreaseStreamScore(overlap.StreamScore() + 1);
1692 } 1323 }
1693 std::vector<BufferCopy> copies; 1324 boost::container::small_vector<BufferCopy, 1> copies;
1694 const size_t dst_base_offset = overlap.CpuAddr() - new_buffer.CpuAddr(); 1325 const size_t dst_base_offset = overlap.CpuAddr() - new_buffer.CpuAddr();
1695 overlap.ForEachDownloadRange([&](u64 begin, u64 range_size) { 1326 copies.push_back(BufferCopy{
1696 copies.push_back(BufferCopy{ 1327 .src_offset = 0,
1697 .src_offset = begin, 1328 .dst_offset = dst_base_offset,
1698 .dst_offset = dst_base_offset + begin, 1329 .size = overlap.SizeBytes(),
1699 .size = range_size,
1700 });
1701 new_buffer.UnmarkRegionAsCpuModified(begin, range_size);
1702 new_buffer.MarkRegionAsGpuModified(begin, range_size);
1703 }); 1330 });
1704 if (!copies.empty()) { 1331 runtime.CopyBuffer(new_buffer, overlap, copies);
1705 runtime.CopyBuffer(slot_buffers[new_buffer_id], overlap, copies); 1332 DeleteBuffer(overlap_id, true);
1706 }
1707 DeleteBuffer(overlap_id);
1708} 1333}
1709 1334
1710template <class P> 1335template <class P>
1711BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) { 1336BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) {
1337 VAddr cpu_addr_end = Common::AlignUp(cpu_addr + wanted_size, CACHING_PAGESIZE);
1338 cpu_addr = Common::AlignDown(cpu_addr, CACHING_PAGESIZE);
1339 wanted_size = static_cast<u32>(cpu_addr_end - cpu_addr);
1712 const OverlapResult overlap = ResolveOverlaps(cpu_addr, wanted_size); 1340 const OverlapResult overlap = ResolveOverlaps(cpu_addr, wanted_size);
1713 const u32 size = static_cast<u32>(overlap.end - overlap.begin); 1341 const u32 size = static_cast<u32>(overlap.end - overlap.begin);
1714 const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size); 1342 const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size);
@@ -1718,7 +1346,7 @@ BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) {
1718 JoinOverlap(new_buffer_id, overlap_id, !overlap.has_stream_leap); 1346 JoinOverlap(new_buffer_id, overlap_id, !overlap.has_stream_leap);
1719 } 1347 }
1720 Register(new_buffer_id); 1348 Register(new_buffer_id);
1721 TouchBuffer(slot_buffers[new_buffer_id], new_buffer_id); 1349 TouchBuffer(new_buffer, new_buffer_id);
1722 return new_buffer_id; 1350 return new_buffer_id;
1723} 1351}
1724 1352
@@ -1746,8 +1374,8 @@ void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
1746 } 1374 }
1747 const VAddr cpu_addr_begin = buffer.CpuAddr(); 1375 const VAddr cpu_addr_begin = buffer.CpuAddr();
1748 const VAddr cpu_addr_end = cpu_addr_begin + size; 1376 const VAddr cpu_addr_end = cpu_addr_begin + size;
1749 const u64 page_begin = cpu_addr_begin / YUZU_PAGESIZE; 1377 const u64 page_begin = cpu_addr_begin / CACHING_PAGESIZE;
1750 const u64 page_end = Common::DivCeil(cpu_addr_end, YUZU_PAGESIZE); 1378 const u64 page_end = Common::DivCeil(cpu_addr_end, CACHING_PAGESIZE);
1751 for (u64 page = page_begin; page != page_end; ++page) { 1379 for (u64 page = page_begin; page != page_end; ++page) {
1752 if constexpr (insert) { 1380 if constexpr (insert) {
1753 page_table[page] = buffer_id; 1381 page_table[page] = buffer_id;
@@ -1766,9 +1394,6 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
1766 1394
1767template <class P> 1395template <class P>
1768bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { 1396bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) {
1769 if (buffer.CpuAddr() == 0) {
1770 return true;
1771 }
1772 return SynchronizeBufferImpl(buffer, cpu_addr, size); 1397 return SynchronizeBufferImpl(buffer, cpu_addr, size);
1773} 1398}
1774 1399
@@ -1777,10 +1402,11 @@ bool BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 s
1777 boost::container::small_vector<BufferCopy, 4> copies; 1402 boost::container::small_vector<BufferCopy, 4> copies;
1778 u64 total_size_bytes = 0; 1403 u64 total_size_bytes = 0;
1779 u64 largest_copy = 0; 1404 u64 largest_copy = 0;
1780 buffer.ForEachUploadRange(cpu_addr, size, [&](u64 range_offset, u64 range_size) { 1405 VAddr buffer_start = buffer.CpuAddr();
1406 memory_tracker.ForEachUploadRange(cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) {
1781 copies.push_back(BufferCopy{ 1407 copies.push_back(BufferCopy{
1782 .src_offset = total_size_bytes, 1408 .src_offset = total_size_bytes,
1783 .dst_offset = range_offset, 1409 .dst_offset = cpu_addr_out - buffer_start,
1784 .size = range_size, 1410 .size = range_size,
1785 }); 1411 });
1786 total_size_bytes += range_size; 1412 total_size_bytes += range_size;
@@ -1795,6 +1421,51 @@ bool BufferCache<P>::SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 s
1795} 1421}
1796 1422
1797template <class P> 1423template <class P>
1424bool BufferCache<P>::SynchronizeBufferNoModified(Buffer& buffer, VAddr cpu_addr, u32 size) {
1425 boost::container::small_vector<BufferCopy, 4> copies;
1426 u64 total_size_bytes = 0;
1427 u64 largest_copy = 0;
1428 IntervalSet found_sets{};
1429 auto make_copies = [&] {
1430 for (auto& interval : found_sets) {
1431 const std::size_t sub_size = interval.upper() - interval.lower();
1432 const VAddr cpu_addr_ = interval.lower();
1433 copies.push_back(BufferCopy{
1434 .src_offset = total_size_bytes,
1435 .dst_offset = cpu_addr_ - buffer.CpuAddr(),
1436 .size = sub_size,
1437 });
1438 total_size_bytes += sub_size;
1439 largest_copy = std::max<u64>(largest_copy, sub_size);
1440 }
1441 const std::span<BufferCopy> copies_span(copies.data(), copies.size());
1442 UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
1443 };
1444 memory_tracker.ForEachUploadRange(cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) {
1445 const VAddr base_adr = cpu_addr_out;
1446 const VAddr end_adr = base_adr + range_size;
1447 const IntervalType add_interval{base_adr, end_adr};
1448 found_sets.add(add_interval);
1449 });
1450 if (found_sets.empty()) {
1451 return true;
1452 }
1453 const IntervalType search_interval{cpu_addr, cpu_addr + size};
1454 auto it = common_ranges.lower_bound(search_interval);
1455 auto it_end = common_ranges.upper_bound(search_interval);
1456 if (it == common_ranges.end()) {
1457 make_copies();
1458 return false;
1459 }
1460 while (it != it_end) {
1461 found_sets.subtract(*it);
1462 it++;
1463 }
1464 make_copies();
1465 return false;
1466}
1467
1468template <class P>
1798void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, 1469void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
1799 std::span<BufferCopy> copies) { 1470 std::span<BufferCopy> copies) {
1800 if constexpr (USE_MEMORY_MAPS) { 1471 if constexpr (USE_MEMORY_MAPS) {
@@ -1805,39 +1476,45 @@ void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 larg
1805} 1476}
1806 1477
1807template <class P> 1478template <class P>
1808void BufferCache<P>::ImmediateUploadMemory(Buffer& buffer, u64 largest_copy, 1479void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
1809 std::span<const BufferCopy> copies) { 1480 [[maybe_unused]] u64 largest_copy,
1810 std::span<u8> immediate_buffer; 1481 [[maybe_unused]] std::span<const BufferCopy> copies) {
1811 for (const BufferCopy& copy : copies) { 1482 if constexpr (!USE_MEMORY_MAPS) {
1812 std::span<const u8> upload_span; 1483 std::span<u8> immediate_buffer;
1813 const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset; 1484 for (const BufferCopy& copy : copies) {
1814 if (IsRangeGranular(cpu_addr, copy.size)) { 1485 std::span<const u8> upload_span;
1815 upload_span = std::span(cpu_memory.GetPointer(cpu_addr), copy.size); 1486 const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset;
1816 } else { 1487 if (IsRangeGranular(cpu_addr, copy.size)) {
1817 if (immediate_buffer.empty()) { 1488 upload_span = std::span(cpu_memory.GetPointer(cpu_addr), copy.size);
1818 immediate_buffer = ImmediateBuffer(largest_copy); 1489 } else {
1490 if (immediate_buffer.empty()) {
1491 immediate_buffer = ImmediateBuffer(largest_copy);
1492 }
1493 cpu_memory.ReadBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size);
1494 upload_span = immediate_buffer.subspan(0, copy.size);
1819 } 1495 }
1820 cpu_memory.ReadBlockUnsafe(cpu_addr, immediate_buffer.data(), copy.size); 1496 buffer.ImmediateUpload(copy.dst_offset, upload_span);
1821 upload_span = immediate_buffer.subspan(0, copy.size);
1822 } 1497 }
1823 buffer.ImmediateUpload(copy.dst_offset, upload_span);
1824 } 1498 }
1825} 1499}
1826 1500
1827template <class P> 1501template <class P>
1828void BufferCache<P>::MappedUploadMemory(Buffer& buffer, u64 total_size_bytes, 1502void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
1829 std::span<BufferCopy> copies) { 1503 [[maybe_unused]] u64 total_size_bytes,
1830 auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes); 1504 [[maybe_unused]] std::span<BufferCopy> copies) {
1831 const std::span<u8> staging_pointer = upload_staging.mapped_span; 1505 if constexpr (USE_MEMORY_MAPS) {
1832 for (BufferCopy& copy : copies) { 1506 auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes);
1833 u8* const src_pointer = staging_pointer.data() + copy.src_offset; 1507 const std::span<u8> staging_pointer = upload_staging.mapped_span;
1834 const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset; 1508 for (BufferCopy& copy : copies) {
1835 cpu_memory.ReadBlockUnsafe(cpu_addr, src_pointer, copy.size); 1509 u8* const src_pointer = staging_pointer.data() + copy.src_offset;
1510 const VAddr cpu_addr = buffer.CpuAddr() + copy.dst_offset;
1511 cpu_memory.ReadBlockUnsafe(cpu_addr, src_pointer, copy.size);
1836 1512
1837 // Apply the staging offset 1513 // Apply the staging offset
1838 copy.src_offset += upload_staging.offset; 1514 copy.src_offset += upload_staging.offset;
1515 }
1516 runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
1839 } 1517 }
1840 runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
1841} 1518}
1842 1519
1843template <class P> 1520template <class P>
@@ -1847,7 +1524,9 @@ bool BufferCache<P>::InlineMemory(VAddr dest_address, size_t copy_size,
1847 if (!is_dirty) { 1524 if (!is_dirty) {
1848 return false; 1525 return false;
1849 } 1526 }
1850 if (!IsRegionGpuModified(dest_address, copy_size)) { 1527 VAddr aligned_start = Common::AlignDown(dest_address, YUZU_PAGESIZE);
1528 VAddr aligned_end = Common::AlignUp(dest_address + copy_size, YUZU_PAGESIZE);
1529 if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
1851 return false; 1530 return false;
1852 } 1531 }
1853 1532
@@ -1886,30 +1565,31 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
1886 boost::container::small_vector<BufferCopy, 1> copies; 1565 boost::container::small_vector<BufferCopy, 1> copies;
1887 u64 total_size_bytes = 0; 1566 u64 total_size_bytes = 0;
1888 u64 largest_copy = 0; 1567 u64 largest_copy = 0;
1889 buffer.ForEachDownloadRangeAndClear(cpu_addr, size, [&](u64 range_offset, u64 range_size) { 1568 memory_tracker.ForEachDownloadRangeAndClear(
1890 const VAddr buffer_addr = buffer.CpuAddr(); 1569 cpu_addr, size, [&](u64 cpu_addr_out, u64 range_size) {
1891 const auto add_download = [&](VAddr start, VAddr end) { 1570 const VAddr buffer_addr = buffer.CpuAddr();
1892 const u64 new_offset = start - buffer_addr; 1571 const auto add_download = [&](VAddr start, VAddr end) {
1893 const u64 new_size = end - start; 1572 const u64 new_offset = start - buffer_addr;
1894 copies.push_back(BufferCopy{ 1573 const u64 new_size = end - start;
1895 .src_offset = new_offset, 1574 copies.push_back(BufferCopy{
1896 .dst_offset = total_size_bytes, 1575 .src_offset = new_offset,
1897 .size = new_size, 1576 .dst_offset = total_size_bytes,
1898 }); 1577 .size = new_size,
1899 // Align up to avoid cache conflicts 1578 });
1900 constexpr u64 align = 256ULL; 1579 // Align up to avoid cache conflicts
1901 constexpr u64 mask = ~(align - 1ULL); 1580 constexpr u64 align = 64ULL;
1902 total_size_bytes += (new_size + align - 1) & mask; 1581 constexpr u64 mask = ~(align - 1ULL);
1903 largest_copy = std::max(largest_copy, new_size); 1582 total_size_bytes += (new_size + align - 1) & mask;
1904 }; 1583 largest_copy = std::max(largest_copy, new_size);
1905 1584 };
1906 const VAddr start_address = buffer_addr + range_offset; 1585
1907 const VAddr end_address = start_address + range_size; 1586 const VAddr start_address = cpu_addr_out;
1908 ForEachWrittenRange(start_address, range_size, add_download); 1587 const VAddr end_address = start_address + range_size;
1909 const IntervalType subtract_interval{start_address, end_address}; 1588 ForEachInRangeSet(common_ranges, start_address, range_size, add_download);
1910 ClearDownload(subtract_interval); 1589 const IntervalType subtract_interval{start_address, end_address};
1911 common_ranges.subtract(subtract_interval); 1590 ClearDownload(subtract_interval);
1912 }); 1591 common_ranges.subtract(subtract_interval);
1592 });
1913 if (total_size_bytes == 0) { 1593 if (total_size_bytes == 0) {
1914 return; 1594 return;
1915 } 1595 }
@@ -1943,7 +1623,7 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
1943} 1623}
1944 1624
1945template <class P> 1625template <class P>
1946void BufferCache<P>::DeleteBuffer(BufferId buffer_id) { 1626void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
1947 const auto scalar_replace = [buffer_id](Binding& binding) { 1627 const auto scalar_replace = [buffer_id](Binding& binding) {
1948 if (binding.buffer_id == buffer_id) { 1628 if (binding.buffer_id == buffer_id) {
1949 binding.buffer_id = BufferId{}; 1629 binding.buffer_id = BufferId{};
@@ -1959,11 +1639,12 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id) {
1959 replace(transform_feedback_buffers); 1639 replace(transform_feedback_buffers);
1960 replace(compute_uniform_buffers); 1640 replace(compute_uniform_buffers);
1961 replace(compute_storage_buffers); 1641 replace(compute_storage_buffers);
1962 std::erase(cached_write_buffer_ids, buffer_id);
1963 1642
1964 // Mark the whole buffer as CPU written to stop tracking CPU writes 1643 // Mark the whole buffer as CPU written to stop tracking CPU writes
1965 Buffer& buffer = slot_buffers[buffer_id]; 1644 if (!do_not_mark) {
1966 buffer.MarkRegionAsCpuModified(buffer.CpuAddr(), buffer.SizeBytes()); 1645 Buffer& buffer = slot_buffers[buffer_id];
1646 memory_tracker.MarkRegionAsCpuModified(buffer.CpuAddr(), buffer.SizeBytes());
1647 }
1967 1648
1968 Unregister(buffer_id); 1649 Unregister(buffer_id);
1969 delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); 1650 delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id]));
@@ -2011,7 +1692,7 @@ typename BufferCache<P>::Binding BufferCache<P>::StorageBufferBinding(GPUVAddr s
2011 LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index); 1692 LOG_WARNING(HW_GPU, "Failed to find storage buffer for cbuf index {}", cbuf_index);
2012 return NULL_BINDING; 1693 return NULL_BINDING;
2013 } 1694 }
2014 const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, Core::Memory::YUZU_PAGESIZE); 1695 const VAddr cpu_end = Common::AlignUp(*cpu_addr + size, YUZU_PAGESIZE);
2015 const Binding binding{ 1696 const Binding binding{
2016 .cpu_addr = *cpu_addr, 1697 .cpu_addr = *cpu_addr,
2017 .size = is_written ? size : static_cast<u32>(cpu_end - *cpu_addr), 1698 .size = is_written ? size : static_cast<u32>(cpu_end - *cpu_addr),
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
new file mode 100644
index 000000000..0445ec47f
--- /dev/null
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -0,0 +1,579 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <algorithm>
7#include <array>
8#include <functional>
9#include <memory>
10#include <mutex>
11#include <numeric>
12#include <span>
13#include <unordered_map>
14#include <vector>
15
16#include <boost/container/small_vector.hpp>
17#define BOOST_NO_MT
18#include <boost/pool/detail/mutex.hpp>
19#undef BOOST_NO_MT
20#include <boost/icl/interval.hpp>
21#include <boost/icl/interval_base_set.hpp>
22#include <boost/icl/interval_set.hpp>
23#include <boost/icl/split_interval_map.hpp>
24#include <boost/pool/pool.hpp>
25#include <boost/pool/pool_alloc.hpp>
26#include <boost/pool/poolfwd.hpp>
27
28#include "common/common_types.h"
29#include "common/div_ceil.h"
30#include "common/literals.h"
31#include "common/lru_cache.h"
32#include "common/microprofile.h"
33#include "common/scope_exit.h"
34#include "common/settings.h"
35#include "core/memory.h"
36#include "video_core/buffer_cache/buffer_base.h"
37#include "video_core/control/channel_state_cache.h"
38#include "video_core/delayed_destruction_ring.h"
39#include "video_core/dirty_flags.h"
40#include "video_core/engines/draw_manager.h"
41#include "video_core/engines/kepler_compute.h"
42#include "video_core/engines/maxwell_3d.h"
43#include "video_core/memory_manager.h"
44#include "video_core/rasterizer_interface.h"
45#include "video_core/surface.h"
46#include "video_core/texture_cache/slot_vector.h"
47#include "video_core/texture_cache/types.h"
48
49namespace boost {
50template <typename T>
51class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>;
52}
53
54namespace VideoCommon {
55
56MICROPROFILE_DECLARE(GPU_PrepareBuffers);
57MICROPROFILE_DECLARE(GPU_BindUploadBuffers);
58MICROPROFILE_DECLARE(GPU_DownloadMemory);
59
60using BufferId = SlotId;
61
62using VideoCore::Surface::PixelFormat;
63using namespace Common::Literals;
64
65constexpr u32 NUM_VERTEX_BUFFERS = 32;
66constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
67constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
68constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
69constexpr u32 NUM_STORAGE_BUFFERS = 16;
70constexpr u32 NUM_TEXTURE_BUFFERS = 16;
71constexpr u32 NUM_STAGES = 5;
72
73using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>;
74using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>;
75
76enum class ObtainBufferSynchronize : u32 {
77 NoSynchronize = 0,
78 FullSynchronize = 1,
79 SynchronizeNoDirty = 2,
80};
81
82enum class ObtainBufferOperation : u32 {
83 DoNothing = 0,
84 MarkAsWritten = 1,
85 DiscardWrite = 2,
86 MarkQuery = 3,
87};
88
89template <typename P>
90class BufferCache : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
91 // Page size for caching purposes.
92 // This is unrelated to the CPU page size and it can be changed as it seems optimal.
93 static constexpr u32 CACHING_PAGEBITS = 16;
94 static constexpr u64 CACHING_PAGESIZE = u64{1} << CACHING_PAGEBITS;
95
96 static constexpr bool IS_OPENGL = P::IS_OPENGL;
97 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS =
98 P::HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS;
99 static constexpr bool HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT =
100 P::HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT;
101 static constexpr bool NEEDS_BIND_UNIFORM_INDEX = P::NEEDS_BIND_UNIFORM_INDEX;
102 static constexpr bool NEEDS_BIND_STORAGE_INDEX = P::NEEDS_BIND_STORAGE_INDEX;
103 static constexpr bool USE_MEMORY_MAPS = P::USE_MEMORY_MAPS;
104 static constexpr bool SEPARATE_IMAGE_BUFFERS_BINDINGS = P::SEPARATE_IMAGE_BUFFER_BINDINGS;
105 static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = P::IMPLEMENTS_ASYNC_DOWNLOADS;
106
107 static constexpr BufferId NULL_BUFFER_ID{0};
108
109 static constexpr s64 DEFAULT_EXPECTED_MEMORY = 512_MiB;
110 static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB;
111 static constexpr s64 TARGET_THRESHOLD = 4_GiB;
112
113 // Debug Flags.
114
115 static constexpr bool DISABLE_DOWNLOADS = true;
116
117 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
118
119 using Runtime = typename P::Runtime;
120 using Buffer = typename P::Buffer;
121 using Async_Buffer = typename P::Async_Buffer;
122 using MemoryTracker = typename P::MemoryTracker;
123
124 using IntervalCompare = std::less<VAddr>;
125 using IntervalInstance = boost::icl::interval_type_default<VAddr, std::less>;
126 using IntervalAllocator = boost::fast_pool_allocator<VAddr>;
127 using IntervalSet = boost::icl::interval_set<VAddr>;
128 using IntervalType = typename IntervalSet::interval_type;
129
130 template <typename Type>
131 struct counter_add_functor : public boost::icl::identity_based_inplace_combine<Type> {
132 // types
133 typedef counter_add_functor<Type> type;
134 typedef boost::icl::identity_based_inplace_combine<Type> base_type;
135
136 // public member functions
137 void operator()(Type& current, const Type& added) const {
138 current += added;
139 if (current < base_type::identity_element()) {
140 current = base_type::identity_element();
141 }
142 }
143
144 // public static functions
145 static void version(Type&){};
146 };
147
148 using OverlapCombine = counter_add_functor<int>;
149 using OverlapSection = boost::icl::inter_section<int>;
150 using OverlapCounter = boost::icl::split_interval_map<VAddr, int>;
151
152 struct Empty {};
153
154 struct OverlapResult {
155 std::vector<BufferId> ids;
156 VAddr begin;
157 VAddr end;
158 bool has_stream_leap = false;
159 };
160
161 struct Binding {
162 VAddr cpu_addr{};
163 u32 size{};
164 BufferId buffer_id;
165 };
166
167 struct TextureBufferBinding : Binding {
168 PixelFormat format;
169 };
170
171 static constexpr Binding NULL_BINDING{
172 .cpu_addr = 0,
173 .size = 0,
174 .buffer_id = NULL_BUFFER_ID,
175 };
176
177public:
178 static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = static_cast<u32>(4_KiB);
179
180 explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_,
181 Core::Memory::Memory& cpu_memory_, Runtime& runtime_);
182
183 void TickFrame();
184
185 void WriteMemory(VAddr cpu_addr, u64 size);
186
187 void CachedWriteMemory(VAddr cpu_addr, u64 size);
188
189 void DownloadMemory(VAddr cpu_addr, u64 size);
190
191 std::optional<VideoCore::RasterizerDownloadArea> GetFlushArea(VAddr cpu_addr, u64 size);
192
193 bool InlineMemory(VAddr dest_address, size_t copy_size, std::span<const u8> inlined_buffer);
194
195 void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size);
196
197 void DisableGraphicsUniformBuffer(size_t stage, u32 index);
198
199 void UpdateGraphicsBuffers(bool is_indexed);
200
201 void UpdateComputeBuffers();
202
203 void BindHostGeometryBuffers(bool is_indexed);
204
205 void BindHostStageBuffers(size_t stage);
206
207 void BindHostComputeBuffers();
208
209 void SetUniformBuffersState(const std::array<u32, NUM_STAGES>& mask,
210 const UniformBufferSizes* sizes);
211
212 void SetComputeUniformBufferState(u32 mask, const ComputeUniformBufferSizes* sizes);
213
214 void UnbindGraphicsStorageBuffers(size_t stage);
215
216 void BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
217 bool is_written);
218
219 void UnbindGraphicsTextureBuffers(size_t stage);
220
221 void BindGraphicsTextureBuffer(size_t stage, size_t tbo_index, GPUVAddr gpu_addr, u32 size,
222 PixelFormat format, bool is_written, bool is_image);
223
224 void UnbindComputeStorageBuffers();
225
226 void BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
227 bool is_written);
228
229 void UnbindComputeTextureBuffers();
230
231 void BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, PixelFormat format,
232 bool is_written, bool is_image);
233
234 [[nodiscard]] std::pair<Buffer*, u32> ObtainBuffer(GPUVAddr gpu_addr, u32 size,
235 ObtainBufferSynchronize sync_info,
236 ObtainBufferOperation post_op);
237 void FlushCachedWrites();
238
239 /// Return true when there are uncommitted buffers to be downloaded
240 [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
241
242 void AccumulateFlushes();
243
244 /// Return true when the caller should wait for async downloads
245 [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
246
247 /// Commit asynchronous downloads
248 void CommitAsyncFlushes();
249 void CommitAsyncFlushesHigh();
250
251 /// Pop asynchronous downloads
252 void PopAsyncFlushes();
253 void PopAsyncBuffers();
254
255 bool DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount);
256
257 bool DMAClear(GPUVAddr src_address, u64 amount, u32 value);
258
259 /// Return true when a CPU region is modified from the GPU
260 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
261
262 /// Return true when a region is registered on the cache
263 [[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size);
264
265 /// Return true when a CPU region is modified from the CPU
266 [[nodiscard]] bool IsRegionCpuModified(VAddr addr, size_t size);
267
268 void SetDrawIndirect(
269 const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect_) {
270 current_draw_indirect = current_draw_indirect_;
271 }
272
273 [[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
274
275 [[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
276
277 std::recursive_mutex mutex;
278 Runtime& runtime;
279
280private:
281 template <typename Func>
282 static void ForEachEnabledBit(u32 enabled_mask, Func&& func) {
283 for (u32 index = 0; enabled_mask != 0; ++index, enabled_mask >>= 1) {
284 const int disabled_bits = std::countr_zero(enabled_mask);
285 index += disabled_bits;
286 enabled_mask >>= disabled_bits;
287 func(index);
288 }
289 }
290
291 template <typename Func>
292 void ForEachBufferInRange(VAddr cpu_addr, u64 size, Func&& func) {
293 const u64 page_end = Common::DivCeil(cpu_addr + size, CACHING_PAGESIZE);
294 for (u64 page = cpu_addr >> CACHING_PAGEBITS; page < page_end;) {
295 const BufferId buffer_id = page_table[page];
296 if (!buffer_id) {
297 ++page;
298 continue;
299 }
300 Buffer& buffer = slot_buffers[buffer_id];
301 func(buffer_id, buffer);
302
303 const VAddr end_addr = buffer.CpuAddr() + buffer.SizeBytes();
304 page = Common::DivCeil(end_addr, CACHING_PAGESIZE);
305 }
306 }
307
308 template <typename Func>
309 void ForEachInRangeSet(IntervalSet& current_range, VAddr cpu_addr, u64 size, Func&& func) {
310 const VAddr start_address = cpu_addr;
311 const VAddr end_address = start_address + size;
312 const IntervalType search_interval{start_address, end_address};
313 auto it = current_range.lower_bound(search_interval);
314 if (it == current_range.end()) {
315 return;
316 }
317 auto end_it = current_range.upper_bound(search_interval);
318 for (; it != end_it; it++) {
319 VAddr inter_addr_end = it->upper();
320 VAddr inter_addr = it->lower();
321 if (inter_addr_end > end_address) {
322 inter_addr_end = end_address;
323 }
324 if (inter_addr < start_address) {
325 inter_addr = start_address;
326 }
327 func(inter_addr, inter_addr_end);
328 }
329 }
330
331 template <typename Func>
332 void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size,
333 Func&& func) {
334 const VAddr start_address = cpu_addr;
335 const VAddr end_address = start_address + size;
336 const IntervalType search_interval{start_address, end_address};
337 auto it = current_range.lower_bound(search_interval);
338 if (it == current_range.end()) {
339 return;
340 }
341 auto end_it = current_range.upper_bound(search_interval);
342 for (; it != end_it; it++) {
343 auto& inter = it->first;
344 VAddr inter_addr_end = inter.upper();
345 VAddr inter_addr = inter.lower();
346 if (inter_addr_end > end_address) {
347 inter_addr_end = end_address;
348 }
349 if (inter_addr < start_address) {
350 inter_addr = start_address;
351 }
352 func(inter_addr, inter_addr_end, it->second);
353 }
354 }
355
356 void RemoveEachInOverlapCounter(OverlapCounter& current_range,
357 const IntervalType search_interval, int subtract_value) {
358 bool any_removals = false;
359 current_range.add(std::make_pair(search_interval, subtract_value));
360 do {
361 any_removals = false;
362 auto it = current_range.lower_bound(search_interval);
363 if (it == current_range.end()) {
364 return;
365 }
366 auto end_it = current_range.upper_bound(search_interval);
367 for (; it != end_it; it++) {
368 if (it->second <= 0) {
369 any_removals = true;
370 current_range.erase(it);
371 break;
372 }
373 }
374 } while (any_removals);
375 }
376
377 static bool IsRangeGranular(VAddr cpu_addr, size_t size) {
378 return (cpu_addr & ~Core::Memory::YUZU_PAGEMASK) ==
379 ((cpu_addr + size) & ~Core::Memory::YUZU_PAGEMASK);
380 }
381
382 void RunGarbageCollector();
383
384 void WaitOnAsyncFlushes(VAddr cpu_addr, u64 size);
385
386 void BindHostIndexBuffer();
387
388 void BindHostVertexBuffers();
389
390 void BindHostDrawIndirectBuffers();
391
392 void BindHostGraphicsUniformBuffers(size_t stage);
393
394 void BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 binding_index, bool needs_bind);
395
396 void BindHostGraphicsStorageBuffers(size_t stage);
397
398 void BindHostGraphicsTextureBuffers(size_t stage);
399
400 void BindHostTransformFeedbackBuffers();
401
402 void BindHostComputeUniformBuffers();
403
404 void BindHostComputeStorageBuffers();
405
406 void BindHostComputeTextureBuffers();
407
408 void DoUpdateGraphicsBuffers(bool is_indexed);
409
410 void DoUpdateComputeBuffers();
411
412 void UpdateIndexBuffer();
413
414 void UpdateVertexBuffers();
415
416 void UpdateVertexBuffer(u32 index);
417
418 void UpdateDrawIndirect();
419
420 void UpdateUniformBuffers(size_t stage);
421
422 void UpdateStorageBuffers(size_t stage);
423
424 void UpdateTextureBuffers(size_t stage);
425
426 void UpdateTransformFeedbackBuffers();
427
428 void UpdateTransformFeedbackBuffer(u32 index);
429
430 void UpdateComputeUniformBuffers();
431
432 void UpdateComputeStorageBuffers();
433
434 void UpdateComputeTextureBuffers();
435
436 void MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size);
437
438 [[nodiscard]] BufferId FindBuffer(VAddr cpu_addr, u32 size);
439
440 [[nodiscard]] OverlapResult ResolveOverlaps(VAddr cpu_addr, u32 wanted_size);
441
442 void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
443
444 [[nodiscard]] BufferId CreateBuffer(VAddr cpu_addr, u32 wanted_size);
445
446 void Register(BufferId buffer_id);
447
448 void Unregister(BufferId buffer_id);
449
450 template <bool insert>
451 void ChangeRegister(BufferId buffer_id);
452
453 void TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept;
454
455 bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size);
456
457 bool SynchronizeBufferImpl(Buffer& buffer, VAddr cpu_addr, u32 size);
458
459 bool SynchronizeBufferNoModified(Buffer& buffer, VAddr cpu_addr, u32 size);
460
461 void UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
462 std::span<BufferCopy> copies);
463
464 void ImmediateUploadMemory(Buffer& buffer, u64 largest_copy,
465 std::span<const BufferCopy> copies);
466
467 void MappedUploadMemory(Buffer& buffer, u64 total_size_bytes, std::span<BufferCopy> copies);
468
469 void DownloadBufferMemory(Buffer& buffer_id);
470
471 void DownloadBufferMemory(Buffer& buffer_id, VAddr cpu_addr, u64 size);
472
473 void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false);
474
475 void NotifyBufferDeletion();
476
477 [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index,
478 bool is_written) const;
479
480 [[nodiscard]] TextureBufferBinding GetTextureBufferBinding(GPUVAddr gpu_addr, u32 size,
481 PixelFormat format);
482
483 [[nodiscard]] std::span<const u8> ImmediateBufferWithData(VAddr cpu_addr, size_t size);
484
485 [[nodiscard]] std::span<u8> ImmediateBuffer(size_t wanted_capacity);
486
487 [[nodiscard]] bool HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept;
488
489 void ClearDownload(IntervalType subtract_interval);
490
491 VideoCore::RasterizerInterface& rasterizer;
492 Core::Memory::Memory& cpu_memory;
493
494 SlotVector<Buffer> slot_buffers;
495 DelayedDestructionRing<Buffer, 8> delayed_destruction_ring;
496
497 const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{};
498
499 u32 last_index_count = 0;
500
501 Binding index_buffer;
502 std::array<Binding, NUM_VERTEX_BUFFERS> vertex_buffers;
503 std::array<std::array<Binding, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES> uniform_buffers;
504 std::array<std::array<Binding, NUM_STORAGE_BUFFERS>, NUM_STAGES> storage_buffers;
505 std::array<std::array<TextureBufferBinding, NUM_TEXTURE_BUFFERS>, NUM_STAGES> texture_buffers;
506 std::array<Binding, NUM_TRANSFORM_FEEDBACK_BUFFERS> transform_feedback_buffers;
507 Binding count_buffer_binding;
508 Binding indirect_buffer_binding;
509
510 std::array<Binding, NUM_COMPUTE_UNIFORM_BUFFERS> compute_uniform_buffers;
511 std::array<Binding, NUM_STORAGE_BUFFERS> compute_storage_buffers;
512 std::array<TextureBufferBinding, NUM_TEXTURE_BUFFERS> compute_texture_buffers;
513
514 std::array<u32, NUM_STAGES> enabled_uniform_buffer_masks{};
515 u32 enabled_compute_uniform_buffer_mask = 0;
516
517 const UniformBufferSizes* uniform_buffer_sizes{};
518 const ComputeUniformBufferSizes* compute_uniform_buffer_sizes{};
519
520 std::array<u32, NUM_STAGES> enabled_storage_buffers{};
521 std::array<u32, NUM_STAGES> written_storage_buffers{};
522 u32 enabled_compute_storage_buffers = 0;
523 u32 written_compute_storage_buffers = 0;
524
525 std::array<u32, NUM_STAGES> enabled_texture_buffers{};
526 std::array<u32, NUM_STAGES> written_texture_buffers{};
527 std::array<u32, NUM_STAGES> image_texture_buffers{};
528 u32 enabled_compute_texture_buffers = 0;
529 u32 written_compute_texture_buffers = 0;
530 u32 image_compute_texture_buffers = 0;
531
532 std::array<u32, 16> uniform_cache_hits{};
533 std::array<u32, 16> uniform_cache_shots{};
534
535 u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE;
536
537 bool has_deleted_buffers = false;
538
539 std::conditional_t<HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS, std::array<u32, NUM_STAGES>, Empty>
540 dirty_uniform_buffers{};
541 std::conditional_t<IS_OPENGL, std::array<u32, NUM_STAGES>, Empty> fast_bound_uniform_buffers{};
542 std::conditional_t<HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS,
543 std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>, Empty>
544 uniform_buffer_binding_sizes{};
545
546 MemoryTracker memory_tracker;
547 IntervalSet uncommitted_ranges;
548 IntervalSet common_ranges;
549 IntervalSet cached_ranges;
550 IntervalSet pending_ranges;
551 std::deque<IntervalSet> committed_ranges;
552
553 // Async Buffers
554 OverlapCounter async_downloads;
555 std::deque<std::optional<Async_Buffer>> async_buffers;
556 std::deque<boost::container::small_vector<BufferCopy, 4>> pending_downloads;
557 std::optional<Async_Buffer> current_buffer;
558
559 std::deque<Async_Buffer> async_buffers_death_ring;
560
561 size_t immediate_buffer_capacity = 0;
562 Common::ScratchBuffer<u8> immediate_buffer_alloc;
563
564 struct LRUItemParams {
565 using ObjectType = BufferId;
566 using TickType = u64;
567 };
568 Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
569 u64 frame_tick = 0;
570 u64 total_used_memory = 0;
571 u64 minimum_memory = 0;
572 u64 critical_memory = 0;
573 BufferId inline_buffer_id;
574
575 std::array<BufferId, ((1ULL << 39) >> CACHING_PAGEBITS)> page_table;
576 std::vector<u8> tmp_buffer;
577};
578
579} // namespace VideoCommon
diff --git a/src/video_core/buffer_cache/memory_tracker_base.h b/src/video_core/buffer_cache/memory_tracker_base.h
new file mode 100644
index 000000000..6036b21c9
--- /dev/null
+++ b/src/video_core/buffer_cache/memory_tracker_base.h
@@ -0,0 +1,299 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <algorithm>
7#include <bit>
8#include <deque>
9#include <limits>
10#include <type_traits>
11#include <unordered_set>
12#include <utility>
13
14#include "common/alignment.h"
15#include "common/common_types.h"
16#include "video_core/buffer_cache/word_manager.h"
17
18namespace VideoCommon {
19
20template <class RasterizerInterface>
21class MemoryTrackerBase {
22 static constexpr size_t MAX_CPU_PAGE_BITS = 39;
23 static constexpr size_t HIGHER_PAGE_BITS = 22;
24 static constexpr size_t HIGHER_PAGE_SIZE = 1ULL << HIGHER_PAGE_BITS;
25 static constexpr size_t HIGHER_PAGE_MASK = HIGHER_PAGE_SIZE - 1ULL;
26 static constexpr size_t NUM_HIGH_PAGES = 1ULL << (MAX_CPU_PAGE_BITS - HIGHER_PAGE_BITS);
27 static constexpr size_t MANAGER_POOL_SIZE = 32;
28 static constexpr size_t WORDS_STACK_NEEDED = HIGHER_PAGE_SIZE / BYTES_PER_WORD;
29 using Manager = WordManager<RasterizerInterface, WORDS_STACK_NEEDED>;
30
31public:
32 MemoryTrackerBase(RasterizerInterface& rasterizer_) : rasterizer{&rasterizer_} {}
33 ~MemoryTrackerBase() = default;
34
35 /// Returns the inclusive CPU modified range in a begin end pair
36 [[nodiscard]] std::pair<u64, u64> ModifiedCpuRegion(VAddr query_cpu_addr,
37 u64 query_size) noexcept {
38 return IteratePairs<true>(
39 query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
40 return manager->template ModifiedRegion<Type::CPU>(offset, size);
41 });
42 }
43
44 /// Returns the inclusive GPU modified range in a begin end pair
45 [[nodiscard]] std::pair<u64, u64> ModifiedGpuRegion(VAddr query_cpu_addr,
46 u64 query_size) noexcept {
47 return IteratePairs<false>(
48 query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
49 return manager->template ModifiedRegion<Type::GPU>(offset, size);
50 });
51 }
52
53 /// Returns true if a region has been modified from the CPU
54 [[nodiscard]] bool IsRegionCpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
55 return IteratePages<true>(
56 query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
57 return manager->template IsRegionModified<Type::CPU>(offset, size);
58 });
59 }
60
61 /// Returns true if a region has been modified from the GPU
62 [[nodiscard]] bool IsRegionGpuModified(VAddr query_cpu_addr, u64 query_size) noexcept {
63 return IteratePages<false>(
64 query_cpu_addr, query_size, [](Manager* manager, u64 offset, size_t size) {
65 return manager->template IsRegionModified<Type::GPU>(offset, size);
66 });
67 }
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
77 /// Mark region as CPU modified, notifying the rasterizer about this change
78 void MarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
79 IteratePages<true>(dirty_cpu_addr, query_size,
80 [](Manager* manager, u64 offset, size_t size) {
81 manager->template ChangeRegionState<Type::CPU, true>(
82 manager->GetCpuAddr() + offset, size);
83 });
84 }
85
86 /// Unmark region as CPU modified, notifying the rasterizer about this change
87 void UnmarkRegionAsCpuModified(VAddr dirty_cpu_addr, u64 query_size) {
88 IteratePages<true>(dirty_cpu_addr, query_size,
89 [](Manager* manager, u64 offset, size_t size) {
90 manager->template ChangeRegionState<Type::CPU, false>(
91 manager->GetCpuAddr() + offset, size);
92 });
93 }
94
95 /// Mark region as modified from the host GPU
96 void MarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept {
97 IteratePages<true>(dirty_cpu_addr, query_size,
98 [](Manager* manager, u64 offset, size_t size) {
99 manager->template ChangeRegionState<Type::GPU, true>(
100 manager->GetCpuAddr() + offset, size);
101 });
102 }
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
113 /// Unmark region as modified from the host GPU
114 void UnmarkRegionAsGpuModified(VAddr dirty_cpu_addr, u64 query_size) noexcept {
115 IteratePages<true>(dirty_cpu_addr, query_size,
116 [](Manager* manager, u64 offset, size_t size) {
117 manager->template ChangeRegionState<Type::GPU, false>(
118 manager->GetCpuAddr() + offset, size);
119 });
120 }
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
131 /// Mark region as modified from the CPU
132 /// but don't mark it as modified until FlusHCachedWrites is called.
133 void CachedCpuWrite(VAddr dirty_cpu_addr, u64 query_size) {
134 IteratePages<true>(
135 dirty_cpu_addr, query_size, [this](Manager* manager, u64 offset, size_t size) {
136 const VAddr cpu_address = manager->GetCpuAddr() + offset;
137 manager->template ChangeRegionState<Type::CachedCPU, true>(cpu_address, size);
138 cached_pages.insert(static_cast<u32>(cpu_address >> HIGHER_PAGE_BITS));
139 });
140 }
141
142 /// Flushes cached CPU writes, and notify the rasterizer about the deltas
143 void FlushCachedWrites(VAddr query_cpu_addr, u64 query_size) noexcept {
144 IteratePages<false>(query_cpu_addr, query_size,
145 [](Manager* manager, [[maybe_unused]] u64 offset,
146 [[maybe_unused]] size_t size) { manager->FlushCachedWrites(); });
147 }
148
149 void FlushCachedWrites() noexcept {
150 for (auto id : cached_pages) {
151 top_tier[id]->FlushCachedWrites();
152 }
153 cached_pages.clear();
154 }
155
156 /// Call 'func' for each CPU modified range and unmark those pages as CPU modified
157 template <typename Func>
158 void ForEachUploadRange(VAddr query_cpu_range, u64 query_size, Func&& func) {
159 IteratePages<true>(query_cpu_range, query_size,
160 [&func](Manager* manager, u64 offset, size_t size) {
161 manager->template ForEachModifiedRange<Type::CPU, true>(
162 manager->GetCpuAddr() + offset, size, func);
163 });
164 }
165
166 /// Call 'func' for each GPU modified range and unmark those pages as GPU modified
167 template <typename Func>
168 void ForEachDownloadRange(VAddr query_cpu_range, u64 query_size, bool clear, Func&& func) {
169 IteratePages<false>(query_cpu_range, query_size,
170 [&func, clear](Manager* manager, u64 offset, size_t size) {
171 if (clear) {
172 manager->template ForEachModifiedRange<Type::GPU, true>(
173 manager->GetCpuAddr() + offset, size, func);
174 } else {
175 manager->template ForEachModifiedRange<Type::GPU, false>(
176 manager->GetCpuAddr() + offset, size, func);
177 }
178 });
179 }
180
181 template <typename Func>
182 void ForEachDownloadRangeAndClear(VAddr query_cpu_range, u64 query_size, Func&& func) {
183 IteratePages<false>(query_cpu_range, query_size,
184 [&func](Manager* manager, u64 offset, size_t size) {
185 manager->template ForEachModifiedRange<Type::GPU, true>(
186 manager->GetCpuAddr() + offset, size, func);
187 });
188 }
189
190private:
191 template <bool create_region_on_fail, typename Func>
192 bool IteratePages(VAddr cpu_address, size_t size, Func&& func) {
193 using FuncReturn = typename std::invoke_result<Func, Manager*, u64, size_t>::type;
194 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
195 std::size_t remaining_size{size};
196 std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS};
197 u64 page_offset{cpu_address & HIGHER_PAGE_MASK};
198 while (remaining_size > 0) {
199 const std::size_t copy_amount{
200 std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
201 auto* manager{top_tier[page_index]};
202 if (manager) {
203 if constexpr (BOOL_BREAK) {
204 if (func(manager, page_offset, copy_amount)) {
205 return true;
206 }
207 } else {
208 func(manager, page_offset, copy_amount);
209 }
210 } else if constexpr (create_region_on_fail) {
211 CreateRegion(page_index);
212 manager = top_tier[page_index];
213 if constexpr (BOOL_BREAK) {
214 if (func(manager, page_offset, copy_amount)) {
215 return true;
216 }
217 } else {
218 func(manager, page_offset, copy_amount);
219 }
220 }
221 page_index++;
222 page_offset = 0;
223 remaining_size -= copy_amount;
224 }
225 return false;
226 }
227
228 template <bool create_region_on_fail, typename Func>
229 std::pair<u64, u64> IteratePairs(VAddr cpu_address, size_t size, Func&& func) {
230 std::size_t remaining_size{size};
231 std::size_t page_index{cpu_address >> HIGHER_PAGE_BITS};
232 u64 page_offset{cpu_address & HIGHER_PAGE_MASK};
233 u64 begin = std::numeric_limits<u64>::max();
234 u64 end = 0;
235 while (remaining_size > 0) {
236 const std::size_t copy_amount{
237 std::min<std::size_t>(HIGHER_PAGE_SIZE - page_offset, remaining_size)};
238 auto* manager{top_tier[page_index]};
239 const auto execute = [&] {
240 auto [new_begin, new_end] = func(manager, page_offset, copy_amount);
241 if (new_begin != 0 || new_end != 0) {
242 const u64 base_address = page_index << HIGHER_PAGE_BITS;
243 begin = std::min(new_begin + base_address, begin);
244 end = std::max(new_end + base_address, end);
245 }
246 };
247 if (manager) {
248 execute();
249 } else if constexpr (create_region_on_fail) {
250 CreateRegion(page_index);
251 manager = top_tier[page_index];
252 execute();
253 }
254 page_index++;
255 page_offset = 0;
256 remaining_size -= copy_amount;
257 }
258 if (begin < end) {
259 return std::make_pair(begin, end);
260 } else {
261 return std::make_pair(0ULL, 0ULL);
262 }
263 }
264
265 void CreateRegion(std::size_t page_index) {
266 const VAddr base_cpu_addr = page_index << HIGHER_PAGE_BITS;
267 top_tier[page_index] = GetNewManager(base_cpu_addr);
268 }
269
270 Manager* GetNewManager(VAddr base_cpu_addess) {
271 const auto on_return = [&] {
272 auto* new_manager = free_managers.front();
273 new_manager->SetCpuAddress(base_cpu_addess);
274 free_managers.pop_front();
275 return new_manager;
276 };
277 if (!free_managers.empty()) {
278 return on_return();
279 }
280 manager_pool.emplace_back();
281 auto& last_pool = manager_pool.back();
282 for (size_t i = 0; i < MANAGER_POOL_SIZE; i++) {
283 new (&last_pool[i]) Manager(0, *rasterizer, HIGHER_PAGE_SIZE);
284 free_managers.push_back(&last_pool[i]);
285 }
286 return on_return();
287 }
288
289 std::deque<std::array<Manager, MANAGER_POOL_SIZE>> manager_pool;
290 std::deque<Manager*> free_managers;
291
292 std::array<Manager*, NUM_HIGH_PAGES> top_tier{};
293
294 std::unordered_set<u32> cached_pages;
295
296 RasterizerInterface* rasterizer = nullptr;
297};
298
299} // namespace VideoCommon
diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h
new file mode 100644
index 000000000..a336bde41
--- /dev/null
+++ b/src/video_core/buffer_cache/word_manager.h
@@ -0,0 +1,485 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <algorithm>
7#include <bit>
8#include <limits>
9#include <span>
10#include <utility>
11
12#include "common/alignment.h"
13#include "common/common_funcs.h"
14#include "common/common_types.h"
15#include "common/div_ceil.h"
16#include "core/memory.h"
17
18namespace VideoCommon {
19
20constexpr u64 PAGES_PER_WORD = 64;
21constexpr u64 BYTES_PER_PAGE = Core::Memory::YUZU_PAGESIZE;
22constexpr u64 BYTES_PER_WORD = PAGES_PER_WORD * BYTES_PER_PAGE;
23
24enum class Type {
25 CPU,
26 GPU,
27 CachedCPU,
28 Untracked,
29 Preflushable,
30};
31
32/// Vector tracking modified pages tightly packed with small vector optimization
33template <size_t stack_words = 1>
34struct WordsArray {
35 /// Returns the pointer to the words state
36 [[nodiscard]] const u64* Pointer(bool is_short) const noexcept {
37 return is_short ? stack.data() : heap;
38 }
39
40 /// Returns the pointer to the words state
41 [[nodiscard]] u64* Pointer(bool is_short) noexcept {
42 return is_short ? stack.data() : heap;
43 }
44
45 std::array<u64, stack_words> stack{}; ///< Small buffers storage
46 u64* heap; ///< Not-small buffers pointer to the storage
47};
48
49template <size_t stack_words = 1>
50struct Words {
51 explicit Words() = default;
52 explicit Words(u64 size_bytes_) : size_bytes{size_bytes_} {
53 num_words = Common::DivCeil(size_bytes, BYTES_PER_WORD);
54 if (IsShort()) {
55 cpu.stack.fill(~u64{0});
56 gpu.stack.fill(0);
57 cached_cpu.stack.fill(0);
58 untracked.stack.fill(~u64{0});
59 preflushable.stack.fill(0);
60 } else {
61 // Share allocation between CPU and GPU pages and set their default values
62 u64* const alloc = new u64[num_words * 5];
63 cpu.heap = alloc;
64 gpu.heap = alloc + num_words;
65 cached_cpu.heap = alloc + num_words * 2;
66 untracked.heap = alloc + num_words * 3;
67 preflushable.heap = alloc + num_words * 4;
68 std::fill_n(cpu.heap, num_words, ~u64{0});
69 std::fill_n(gpu.heap, num_words, 0);
70 std::fill_n(cached_cpu.heap, num_words, 0);
71 std::fill_n(untracked.heap, num_words, ~u64{0});
72 std::fill_n(preflushable.heap, num_words, 0);
73 }
74 // Clean up tailing bits
75 const u64 last_word_size = size_bytes % BYTES_PER_WORD;
76 const u64 last_local_page = Common::DivCeil(last_word_size, BYTES_PER_PAGE);
77 const u64 shift = (PAGES_PER_WORD - last_local_page) % PAGES_PER_WORD;
78 const u64 last_word = (~u64{0} << shift) >> shift;
79 cpu.Pointer(IsShort())[NumWords() - 1] = last_word;
80 untracked.Pointer(IsShort())[NumWords() - 1] = last_word;
81 }
82
83 ~Words() {
84 Release();
85 }
86
87 Words& operator=(Words&& rhs) noexcept {
88 Release();
89 size_bytes = rhs.size_bytes;
90 num_words = rhs.num_words;
91 cpu = rhs.cpu;
92 gpu = rhs.gpu;
93 cached_cpu = rhs.cached_cpu;
94 untracked = rhs.untracked;
95 preflushable = rhs.preflushable;
96 rhs.cpu.heap = nullptr;
97 return *this;
98 }
99
100 Words(Words&& rhs) noexcept
101 : size_bytes{rhs.size_bytes}, num_words{rhs.num_words}, cpu{rhs.cpu}, gpu{rhs.gpu},
102 cached_cpu{rhs.cached_cpu}, untracked{rhs.untracked}, preflushable{rhs.preflushable} {
103 rhs.cpu.heap = nullptr;
104 }
105
106 Words& operator=(const Words&) = delete;
107 Words(const Words&) = delete;
108
109 /// Returns true when the buffer fits in the small vector optimization
110 [[nodiscard]] bool IsShort() const noexcept {
111 return num_words <= stack_words;
112 }
113
114 /// Returns the number of words of the buffer
115 [[nodiscard]] size_t NumWords() const noexcept {
116 return num_words;
117 }
118
119 /// Release buffer resources
120 void Release() {
121 if (!IsShort()) {
122 // CPU written words is the base for the heap allocation
123 delete[] cpu.heap;
124 }
125 }
126
127 template <Type type>
128 std::span<u64> Span() noexcept {
129 if constexpr (type == Type::CPU) {
130 return std::span<u64>(cpu.Pointer(IsShort()), num_words);
131 } else if constexpr (type == Type::GPU) {
132 return std::span<u64>(gpu.Pointer(IsShort()), num_words);
133 } else if constexpr (type == Type::CachedCPU) {
134 return std::span<u64>(cached_cpu.Pointer(IsShort()), num_words);
135 } else if constexpr (type == Type::Untracked) {
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);
139 }
140 }
141
142 template <Type type>
143 std::span<const u64> Span() const noexcept {
144 if constexpr (type == Type::CPU) {
145 return std::span<const u64>(cpu.Pointer(IsShort()), num_words);
146 } else if constexpr (type == Type::GPU) {
147 return std::span<const u64>(gpu.Pointer(IsShort()), num_words);
148 } else if constexpr (type == Type::CachedCPU) {
149 return std::span<const u64>(cached_cpu.Pointer(IsShort()), num_words);
150 } else if constexpr (type == Type::Untracked) {
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);
154 }
155 }
156
157 u64 size_bytes = 0;
158 size_t num_words = 0;
159 WordsArray<stack_words> cpu;
160 WordsArray<stack_words> gpu;
161 WordsArray<stack_words> cached_cpu;
162 WordsArray<stack_words> untracked;
163 WordsArray<stack_words> preflushable;
164};
165
166template <class RasterizerInterface, size_t stack_words = 1>
167class WordManager {
168public:
169 explicit WordManager(VAddr cpu_addr_, RasterizerInterface& rasterizer_, u64 size_bytes)
170 : cpu_addr{cpu_addr_}, rasterizer{&rasterizer_}, words{size_bytes} {}
171
172 explicit WordManager() = default;
173
174 void SetCpuAddress(VAddr new_cpu_addr) {
175 cpu_addr = new_cpu_addr;
176 }
177
178 VAddr GetCpuAddr() const {
179 return cpu_addr;
180 }
181
182 static u64 ExtractBits(u64 word, size_t page_start, size_t page_end) {
183 constexpr size_t number_bits = sizeof(u64) * 8;
184 const size_t limit_page_end = number_bits - std::min(page_end, number_bits);
185 u64 bits = (word >> page_start) << page_start;
186 bits = (bits << limit_page_end) >> limit_page_end;
187 return bits;
188 }
189
190 static std::pair<size_t, size_t> GetWordPage(VAddr address) {
191 const size_t converted_address = static_cast<size_t>(address);
192 const size_t word_number = converted_address / BYTES_PER_WORD;
193 const size_t amount_pages = converted_address % BYTES_PER_WORD;
194 return std::make_pair(word_number, amount_pages / BYTES_PER_PAGE);
195 }
196
197 template <typename Func>
198 void IterateWords(size_t offset, size_t size, Func&& func) const {
199 using FuncReturn = std::invoke_result_t<Func, std::size_t, u64>;
200 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
201 const size_t start = static_cast<size_t>(std::max<s64>(static_cast<s64>(offset), 0LL));
202 const size_t end = static_cast<size_t>(std::max<s64>(static_cast<s64>(offset + size), 0LL));
203 if (start >= SizeBytes() || end <= start) {
204 return;
205 }
206 auto [start_word, start_page] = GetWordPage(start);
207 auto [end_word, end_page] = GetWordPage(end + BYTES_PER_PAGE - 1ULL);
208 const size_t num_words = NumWords();
209 start_word = std::min(start_word, num_words);
210 end_word = std::min(end_word, num_words);
211 const size_t diff = end_word - start_word;
212 end_word += (end_page + PAGES_PER_WORD - 1ULL) / PAGES_PER_WORD;
213 end_word = std::min(end_word, num_words);
214 end_page += diff * PAGES_PER_WORD;
215 constexpr u64 base_mask{~0ULL};
216 for (size_t word_index = start_word; word_index < end_word; word_index++) {
217 const u64 mask = ExtractBits(base_mask, start_page, end_page);
218 start_page = 0;
219 end_page -= PAGES_PER_WORD;
220 if constexpr (BOOL_BREAK) {
221 if (func(word_index, mask)) {
222 return;
223 }
224 } else {
225 func(word_index, mask);
226 }
227 }
228 }
229
230 template <typename Func>
231 void IteratePages(u64 mask, Func&& func) const {
232 size_t offset = 0;
233 while (mask != 0) {
234 const size_t empty_bits = std::countr_zero(mask);
235 offset += empty_bits;
236 mask = mask >> empty_bits;
237
238 const size_t continuous_bits = std::countr_one(mask);
239 func(offset, continuous_bits);
240 mask = continuous_bits < PAGES_PER_WORD ? (mask >> continuous_bits) : 0;
241 offset += continuous_bits;
242 }
243 }
244
245 /**
246 * Change the state of a range of pages
247 *
248 * @param dirty_addr Base address to mark or unmark as modified
249 * @param size Size in bytes to mark or unmark as modified
250 */
251 template <Type type, bool enable>
252 void ChangeRegionState(u64 dirty_addr, u64 size) noexcept(type == Type::GPU) {
253 std::span<u64> state_words = words.template Span<type>();
254 [[maybe_unused]] std::span<u64> untracked_words = words.template Span<Type::Untracked>();
255 [[maybe_unused]] std::span<u64> cached_words = words.template Span<Type::CachedCPU>();
256 IterateWords(dirty_addr - cpu_addr, size, [&](size_t index, u64 mask) {
257 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
258 NotifyRasterizer<!enable>(index, untracked_words[index], mask);
259 }
260 if constexpr (enable) {
261 state_words[index] |= mask;
262 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
263 untracked_words[index] |= mask;
264 }
265 if constexpr (type == Type::CPU) {
266 cached_words[index] &= ~mask;
267 }
268 } else {
269 if constexpr (type == Type::CPU) {
270 const u64 word = state_words[index] & mask;
271 cached_words[index] &= ~word;
272 }
273 state_words[index] &= ~mask;
274 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
275 untracked_words[index] &= ~mask;
276 }
277 }
278 });
279 }
280
281 /**
282 * Loop over each page in the given range, turn off those bits and notify the rasterizer if
283 * needed. Call the given function on each turned off range.
284 *
285 * @param query_cpu_range Base CPU address to loop over
286 * @param size Size in bytes of the CPU range to loop over
287 * @param func Function to call for each turned off region
288 */
289 template <Type type, bool clear, typename Func>
290 void ForEachModifiedRange(VAddr query_cpu_range, s64 size, Func&& func) {
291 static_assert(type != Type::Untracked);
292
293 std::span<u64> state_words = words.template Span<type>();
294 [[maybe_unused]] std::span<u64> untracked_words = words.template Span<Type::Untracked>();
295 [[maybe_unused]] std::span<u64> cached_words = words.template Span<Type::CachedCPU>();
296 const size_t offset = query_cpu_range - cpu_addr;
297 bool pending = false;
298 size_t pending_offset{};
299 size_t pending_pointer{};
300 const auto release = [&]() {
301 func(cpu_addr + pending_offset * BYTES_PER_PAGE,
302 (pending_pointer - pending_offset) * BYTES_PER_PAGE);
303 };
304 IterateWords(offset, size, [&](size_t index, u64 mask) {
305 if constexpr (type == Type::GPU) {
306 mask &= ~untracked_words[index];
307 }
308 const u64 word = state_words[index] & mask;
309 if constexpr (clear) {
310 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
311 NotifyRasterizer<true>(index, untracked_words[index], mask);
312 }
313 state_words[index] &= ~mask;
314 if constexpr (type == Type::CPU || type == Type::CachedCPU) {
315 untracked_words[index] &= ~mask;
316 }
317 if constexpr (type == Type::CPU) {
318 cached_words[index] &= ~word;
319 }
320 }
321 const size_t base_offset = index * PAGES_PER_WORD;
322 IteratePages(word, [&](size_t pages_offset, size_t pages_size) {
323 const auto reset = [&]() {
324 pending_offset = base_offset + pages_offset;
325 pending_pointer = base_offset + pages_offset + pages_size;
326 };
327 if (!pending) {
328 reset();
329 pending = true;
330 return;
331 }
332 if (pending_pointer == base_offset + pages_offset) {
333 pending_pointer += pages_size;
334 return;
335 }
336 release();
337 reset();
338 });
339 });
340 if (pending) {
341 release();
342 }
343 }
344
345 /**
346 * Returns true when a region has been modified
347 *
348 * @param offset Offset in bytes from the start of the buffer
349 * @param size Size in bytes of the region to query for modifications
350 */
351 template <Type type>
352 [[nodiscard]] bool IsRegionModified(u64 offset, u64 size) const noexcept {
353 static_assert(type != Type::Untracked);
354
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>();
358 bool result = false;
359 IterateWords(offset, size, [&](size_t index, u64 mask) {
360 if constexpr (type == Type::GPU) {
361 mask &= ~untracked_words[index];
362 }
363 const u64 word = state_words[index] & mask;
364 if (word != 0) {
365 result = true;
366 return true;
367 }
368 return false;
369 });
370 return result;
371 }
372
373 /**
374 * Returns a begin end pair with the inclusive modified region
375 *
376 * @param offset Offset in bytes from the start of the buffer
377 * @param size Size in bytes of the region to query for modifications
378 */
379 template <Type type>
380 [[nodiscard]] std::pair<u64, u64> ModifiedRegion(u64 offset, u64 size) const noexcept {
381 static_assert(type != Type::Untracked);
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>();
385 u64 begin = std::numeric_limits<u64>::max();
386 u64 end = 0;
387 IterateWords(offset, size, [&](size_t index, u64 mask) {
388 if constexpr (type == Type::GPU) {
389 mask &= ~untracked_words[index];
390 }
391 const u64 word = state_words[index] & mask;
392 if (word == 0) {
393 return;
394 }
395 const u64 local_page_begin = std::countr_zero(word);
396 const u64 local_page_end = PAGES_PER_WORD - std::countl_zero(word);
397 const u64 page_index = index * PAGES_PER_WORD;
398 begin = std::min(begin, page_index + local_page_begin);
399 end = page_index + local_page_end;
400 });
401 static constexpr std::pair<u64, u64> EMPTY{0, 0};
402 return begin < end ? std::make_pair(begin * BYTES_PER_PAGE, end * BYTES_PER_PAGE) : EMPTY;
403 }
404
405 /// Returns the number of words of the manager
406 [[nodiscard]] size_t NumWords() const noexcept {
407 return words.NumWords();
408 }
409
410 /// Returns the size in bytes of the manager
411 [[nodiscard]] u64 SizeBytes() const noexcept {
412 return words.size_bytes;
413 }
414
415 /// Returns true when the buffer fits in the small vector optimization
416 [[nodiscard]] bool IsShort() const noexcept {
417 return words.IsShort();
418 }
419
420 void FlushCachedWrites() noexcept {
421 const u64 num_words = NumWords();
422 u64* const cached_words = Array<Type::CachedCPU>();
423 u64* const untracked_words = Array<Type::Untracked>();
424 u64* const cpu_words = Array<Type::CPU>();
425 for (u64 word_index = 0; word_index < num_words; ++word_index) {
426 const u64 cached_bits = cached_words[word_index];
427 NotifyRasterizer<false>(word_index, untracked_words[word_index], cached_bits);
428 untracked_words[word_index] |= cached_bits;
429 cpu_words[word_index] |= cached_bits;
430 cached_words[word_index] = 0;
431 }
432 }
433
434private:
435 template <Type type>
436 u64* Array() noexcept {
437 if constexpr (type == Type::CPU) {
438 return words.cpu.Pointer(IsShort());
439 } else if constexpr (type == Type::GPU) {
440 return words.gpu.Pointer(IsShort());
441 } else if constexpr (type == Type::CachedCPU) {
442 return words.cached_cpu.Pointer(IsShort());
443 } else if constexpr (type == Type::Untracked) {
444 return words.untracked.Pointer(IsShort());
445 }
446 }
447
448 template <Type type>
449 const u64* Array() const noexcept {
450 if constexpr (type == Type::CPU) {
451 return words.cpu.Pointer(IsShort());
452 } else if constexpr (type == Type::GPU) {
453 return words.gpu.Pointer(IsShort());
454 } else if constexpr (type == Type::CachedCPU) {
455 return words.cached_cpu.Pointer(IsShort());
456 } else if constexpr (type == Type::Untracked) {
457 return words.untracked.Pointer(IsShort());
458 }
459 }
460
461 /**
462 * Notify rasterizer about changes in the CPU tracking state of a word in the buffer
463 *
464 * @param word_index Index to the word to notify to the rasterizer
465 * @param current_bits Current state of the word
466 * @param new_bits New state of the word
467 *
468 * @tparam add_to_rasterizer True when the rasterizer should start tracking the new pages
469 */
470 template <bool add_to_rasterizer>
471 void NotifyRasterizer(u64 word_index, u64 current_bits, u64 new_bits) const {
472 u64 changed_bits = (add_to_rasterizer ? current_bits : ~current_bits) & new_bits;
473 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
474 IteratePages(changed_bits, [&](size_t offset, size_t size) {
475 rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE,
476 size * BYTES_PER_PAGE, add_to_rasterizer ? 1 : -1);
477 });
478 }
479
480 VAddr cpu_addr = 0;
481 RasterizerInterface* rasterizer = nullptr;
482 Words<stack_words> words;
483};
484
485} // namespace VideoCommon
diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp
index 4e75f33ca..ab4f4d407 100644
--- a/src/video_core/compatible_formats.cpp
+++ b/src/video_core/compatible_formats.cpp
@@ -126,15 +126,14 @@ constexpr std::array VIEW_CLASS_ASTC_8x8_RGBA{
126 PixelFormat::ASTC_2D_8X8_SRGB, 126 PixelFormat::ASTC_2D_8X8_SRGB,
127}; 127};
128 128
129// Missing formats: 129constexpr std::array VIEW_CLASS_ASTC_10x5_RGBA{
130// PixelFormat::ASTC_2D_10X5_UNORM 130 PixelFormat::ASTC_2D_10X5_UNORM,
131// PixelFormat::ASTC_2D_10X5_SRGB 131 PixelFormat::ASTC_2D_10X5_SRGB,
132 132};
133// Missing formats:
134// PixelFormat::ASTC_2D_10X6_SRGB
135 133
136constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{ 134constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{
137 PixelFormat::ASTC_2D_10X6_UNORM, 135 PixelFormat::ASTC_2D_10X6_UNORM,
136 PixelFormat::ASTC_2D_10X6_SRGB,
138}; 137};
139 138
140constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{ 139constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{
@@ -147,9 +146,10 @@ constexpr std::array VIEW_CLASS_ASTC_10x10_RGBA{
147 PixelFormat::ASTC_2D_10X10_SRGB, 146 PixelFormat::ASTC_2D_10X10_SRGB,
148}; 147};
149 148
150// Missing formats 149constexpr std::array VIEW_CLASS_ASTC_12x10_RGBA{
151// ASTC_2D_12X10_UNORM, 150 PixelFormat::ASTC_2D_12X10_UNORM,
152// ASTC_2D_12X10_SRGB, 151 PixelFormat::ASTC_2D_12X10_SRGB,
152};
153 153
154constexpr std::array VIEW_CLASS_ASTC_12x12_RGBA{ 154constexpr std::array VIEW_CLASS_ASTC_12x12_RGBA{
155 PixelFormat::ASTC_2D_12X12_UNORM, 155 PixelFormat::ASTC_2D_12X12_UNORM,
@@ -229,9 +229,11 @@ constexpr Table MakeViewTable() {
229 EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA); 229 EnableRange(view, VIEW_CLASS_ASTC_6x6_RGBA);
230 EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA); 230 EnableRange(view, VIEW_CLASS_ASTC_8x5_RGBA);
231 EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA); 231 EnableRange(view, VIEW_CLASS_ASTC_8x8_RGBA);
232 EnableRange(view, VIEW_CLASS_ASTC_10x5_RGBA);
232 EnableRange(view, VIEW_CLASS_ASTC_10x6_RGBA); 233 EnableRange(view, VIEW_CLASS_ASTC_10x6_RGBA);
233 EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA); 234 EnableRange(view, VIEW_CLASS_ASTC_10x8_RGBA);
234 EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA); 235 EnableRange(view, VIEW_CLASS_ASTC_10x10_RGBA);
236 EnableRange(view, VIEW_CLASS_ASTC_12x10_RGBA);
235 EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA); 237 EnableRange(view, VIEW_CLASS_ASTC_12x12_RGBA);
236 return view; 238 return view;
237} 239}
diff --git a/src/video_core/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/fence_manager.h b/src/video_core/fence_manager.h
index c390ac91b..35d699bbf 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -4,13 +4,20 @@
4#pragma once 4#pragma once
5 5
6#include <algorithm> 6#include <algorithm>
7#include <condition_variable>
7#include <cstring> 8#include <cstring>
8#include <deque> 9#include <deque>
9#include <functional> 10#include <functional>
10#include <memory> 11#include <memory>
12#include <mutex>
13#include <thread>
11#include <queue> 14#include <queue>
12 15
13#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/microprofile.h"
18#include "common/scope_exit.h"
19#include "common/settings.h"
20#include "common/thread.h"
14#include "video_core/delayed_destruction_ring.h" 21#include "video_core/delayed_destruction_ring.h"
15#include "video_core/gpu.h" 22#include "video_core/gpu.h"
16#include "video_core/host1x/host1x.h" 23#include "video_core/host1x/host1x.h"
@@ -23,15 +30,26 @@ class FenceBase {
23public: 30public:
24 explicit FenceBase(bool is_stubbed_) : is_stubbed{is_stubbed_} {} 31 explicit FenceBase(bool is_stubbed_) : is_stubbed{is_stubbed_} {}
25 32
33 bool IsStubbed() const {
34 return is_stubbed;
35 }
36
26protected: 37protected:
27 bool is_stubbed; 38 bool is_stubbed;
28}; 39};
29 40
30template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache> 41template <typename Traits>
31class FenceManager { 42class FenceManager {
43 using TFence = typename Traits::FenceType;
44 using TTextureCache = typename Traits::TextureCacheType;
45 using TBufferCache = typename Traits::BufferCacheType;
46 using TQueryCache = typename Traits::QueryCacheType;
47 static constexpr bool can_async_check = Traits::HAS_ASYNC_CHECK;
48
32public: 49public:
33 /// Notify the fence manager about a new frame 50 /// Notify the fence manager about a new frame
34 void TickFrame() { 51 void TickFrame() {
52 std::unique_lock lock(ring_guard);
35 delayed_destruction_ring.Tick(); 53 delayed_destruction_ring.Tick();
36 } 54 }
37 55
@@ -41,22 +59,43 @@ public:
41 buffer_cache.AccumulateFlushes(); 59 buffer_cache.AccumulateFlushes();
42 } 60 }
43 61
62 void SignalReference() {
63 std::function<void()> do_nothing([] {});
64 SignalFence(std::move(do_nothing));
65 }
66
44 void SyncOperation(std::function<void()>&& func) { 67 void SyncOperation(std::function<void()>&& func) {
45 uncommitted_operations.emplace_back(std::move(func)); 68 uncommitted_operations.emplace_back(std::move(func));
46 } 69 }
47 70
48 void SignalFence(std::function<void()>&& func) { 71 void SignalFence(std::function<void()>&& func) {
49 TryReleasePendingFences(); 72 rasterizer.InvalidateGPUCache();
73 bool delay_fence = Settings::IsGPULevelHigh();
74 if constexpr (!can_async_check) {
75 TryReleasePendingFences<false>();
76 }
50 const bool should_flush = ShouldFlush(); 77 const bool should_flush = ShouldFlush();
51 CommitAsyncFlushes(); 78 CommitAsyncFlushes();
52 uncommitted_operations.emplace_back(std::move(func));
53 CommitOperations();
54 TFence new_fence = CreateFence(!should_flush); 79 TFence new_fence = CreateFence(!should_flush);
55 fences.push(new_fence); 80 if constexpr (can_async_check) {
81 guard.lock();
82 }
83 if (delay_fence) {
84 uncommitted_operations.emplace_back(std::move(func));
85 }
86 pending_operations.emplace_back(std::move(uncommitted_operations));
56 QueueFence(new_fence); 87 QueueFence(new_fence);
88 if (!delay_fence) {
89 func();
90 }
91 fences.push(std::move(new_fence));
57 if (should_flush) { 92 if (should_flush) {
58 rasterizer.FlushCommands(); 93 rasterizer.FlushCommands();
59 } 94 }
95 if constexpr (can_async_check) {
96 guard.unlock();
97 cv.notify_all();
98 }
60 } 99 }
61 100
62 void SignalSyncPoint(u32 value) { 101 void SignalSyncPoint(u32 value) {
@@ -66,29 +105,30 @@ public:
66 } 105 }
67 106
68 void WaitPendingFences() { 107 void WaitPendingFences() {
69 while (!fences.empty()) { 108 if constexpr (!can_async_check) {
70 TFence& current_fence = fences.front(); 109 TryReleasePendingFences<true>();
71 if (ShouldWait()) {
72 WaitFence(current_fence);
73 }
74 PopAsyncFlushes();
75 auto operations = std::move(pending_operations.front());
76 pending_operations.pop_front();
77 for (auto& operation : operations) {
78 operation();
79 }
80 PopFence();
81 } 110 }
82 } 111 }
83 112
84protected: 113protected:
85 explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, 114 explicit FenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_,
86 TTextureCache& texture_cache_, TTBufferCache& buffer_cache_, 115 TTextureCache& texture_cache_, TBufferCache& buffer_cache_,
87 TQueryCache& query_cache_) 116 TQueryCache& query_cache_)
88 : rasterizer{rasterizer_}, gpu{gpu_}, syncpoint_manager{gpu.Host1x().GetSyncpointManager()}, 117 : rasterizer{rasterizer_}, gpu{gpu_}, syncpoint_manager{gpu.Host1x().GetSyncpointManager()},
89 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {} 118 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, query_cache{query_cache_} {
119 if constexpr (can_async_check) {
120 fence_thread =
121 std::jthread([this](std::stop_token token) { ReleaseThreadFunc(token); });
122 }
123 }
90 124
91 virtual ~FenceManager() = default; 125 virtual ~FenceManager() {
126 if constexpr (can_async_check) {
127 fence_thread.request_stop();
128 cv.notify_all();
129 fence_thread.join();
130 }
131 }
92 132
93 /// Creates a Fence Interface, does not create a backend fence if 'is_stubbed' is 133 /// Creates a Fence Interface, does not create a backend fence if 'is_stubbed' is
94 /// true 134 /// true
@@ -104,15 +144,20 @@ protected:
104 Tegra::GPU& gpu; 144 Tegra::GPU& gpu;
105 Tegra::Host1x::SyncpointManager& syncpoint_manager; 145 Tegra::Host1x::SyncpointManager& syncpoint_manager;
106 TTextureCache& texture_cache; 146 TTextureCache& texture_cache;
107 TTBufferCache& buffer_cache; 147 TBufferCache& buffer_cache;
108 TQueryCache& query_cache; 148 TQueryCache& query_cache;
109 149
110private: 150private:
151 template <bool force_wait>
111 void TryReleasePendingFences() { 152 void TryReleasePendingFences() {
112 while (!fences.empty()) { 153 while (!fences.empty()) {
113 TFence& current_fence = fences.front(); 154 TFence& current_fence = fences.front();
114 if (ShouldWait() && !IsFenceSignaled(current_fence)) { 155 if (ShouldWait() && !IsFenceSignaled(current_fence)) {
115 return; 156 if constexpr (force_wait) {
157 WaitFence(current_fence);
158 } else {
159 return;
160 }
116 } 161 }
117 PopAsyncFlushes(); 162 PopAsyncFlushes();
118 auto operations = std::move(pending_operations.front()); 163 auto operations = std::move(pending_operations.front());
@@ -120,7 +165,49 @@ private:
120 for (auto& operation : operations) { 165 for (auto& operation : operations) {
121 operation(); 166 operation();
122 } 167 }
123 PopFence(); 168 {
169 std::unique_lock lock(ring_guard);
170 delayed_destruction_ring.Push(std::move(current_fence));
171 }
172 fences.pop();
173 }
174 }
175
176 void ReleaseThreadFunc(std::stop_token stop_token) {
177 std::string name = "GPUFencingThread";
178 MicroProfileOnThreadCreate(name.c_str());
179
180 // Cleanup
181 SCOPE_EXIT({ MicroProfileOnThreadExit(); });
182
183 Common::SetCurrentThreadName(name.c_str());
184 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
185
186 TFence current_fence;
187 std::deque<std::function<void()>> current_operations;
188 while (!stop_token.stop_requested()) {
189 {
190 std::unique_lock lock(guard);
191 cv.wait(lock, [&] { return stop_token.stop_requested() || !fences.empty(); });
192 if (stop_token.stop_requested()) [[unlikely]] {
193 return;
194 }
195 current_fence = std::move(fences.front());
196 current_operations = std::move(pending_operations.front());
197 fences.pop();
198 pending_operations.pop_front();
199 }
200 if (!current_fence->IsStubbed()) {
201 WaitFence(current_fence);
202 }
203 PopAsyncFlushes();
204 for (auto& operation : current_operations) {
205 operation();
206 }
207 {
208 std::unique_lock lock(ring_guard);
209 delayed_destruction_ring.Push(std::move(current_fence));
210 }
124 } 211 }
125 } 212 }
126 213
@@ -154,19 +241,16 @@ private:
154 query_cache.CommitAsyncFlushes(); 241 query_cache.CommitAsyncFlushes();
155 } 242 }
156 243
157 void PopFence() {
158 delayed_destruction_ring.Push(std::move(fences.front()));
159 fences.pop();
160 }
161
162 void CommitOperations() {
163 pending_operations.emplace_back(std::move(uncommitted_operations));
164 }
165
166 std::queue<TFence> fences; 244 std::queue<TFence> fences;
167 std::deque<std::function<void()>> uncommitted_operations; 245 std::deque<std::function<void()>> uncommitted_operations;
168 std::deque<std::deque<std::function<void()>>> pending_operations; 246 std::deque<std::deque<std::function<void()>>> pending_operations;
169 247
248 std::mutex guard;
249 std::mutex ring_guard;
250 std::condition_variable cv;
251
252 std::jthread fence_thread;
253
170 DelayedDestructionRing<TFence, 6> delayed_destruction_ring; 254 DelayedDestructionRing<TFence, 6> delayed_destruction_ring;
171}; 255};
172 256
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/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 01fb5b546..7b2cde7a7 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -82,6 +82,7 @@ void MemoryManager::SetEntry(size_t position, MemoryManager::EntryType entry) {
82} 82}
83 83
84PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const { 84PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const {
85 std::unique_lock<std::mutex> lock(guard);
85 return kind_map.GetValueAt(gpu_addr); 86 return kind_map.GetValueAt(gpu_addr);
86} 87}
87 88
@@ -160,7 +161,10 @@ GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr
160 } 161 }
161 remaining_size -= big_page_size; 162 remaining_size -= big_page_size;
162 } 163 }
163 kind_map.Map(gpu_addr, gpu_addr + size, kind); 164 {
165 std::unique_lock<std::mutex> lock(guard);
166 kind_map.Map(gpu_addr, gpu_addr + size, kind);
167 }
164 return gpu_addr; 168 return gpu_addr;
165} 169}
166 170
@@ -553,6 +557,7 @@ size_t MemoryManager::MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const {
553} 557}
554 558
555size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const { 559size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const {
560 std::unique_lock<std::mutex> lock(guard);
556 return kind_map.GetContinuousSizeFrom(gpu_addr); 561 return kind_map.GetContinuousSizeFrom(gpu_addr);
557} 562}
558 563
@@ -745,10 +750,10 @@ void MemoryManager::FlushCaching() {
745 return; 750 return;
746 } 751 }
747 accumulator->Callback([this](GPUVAddr addr, size_t size) { 752 accumulator->Callback([this](GPUVAddr addr, size_t size) {
748 GetSubmappedRangeImpl<false>(addr, size, page_stash); 753 GetSubmappedRangeImpl<false>(addr, size, page_stash2);
749 }); 754 });
750 rasterizer->InnerInvalidation(page_stash); 755 rasterizer->InnerInvalidation(page_stash2);
751 page_stash.clear(); 756 page_stash2.clear();
752 accumulator->Clear(); 757 accumulator->Clear();
753} 758}
754 759
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index fbbe856c4..794535122 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -5,6 +5,7 @@
5 5
6#include <atomic> 6#include <atomic>
7#include <map> 7#include <map>
8#include <mutex>
8#include <optional> 9#include <optional>
9#include <vector> 10#include <vector>
10 11
@@ -215,6 +216,9 @@ private:
215 216
216 std::vector<u64> big_page_continuous; 217 std::vector<u64> big_page_continuous;
217 std::vector<std::pair<VAddr, std::size_t>> page_stash{}; 218 std::vector<std::pair<VAddr, std::size_t>> page_stash{};
219 std::vector<std::pair<VAddr, std::size_t>> page_stash2{};
220
221 mutable std::mutex guard;
218 222
219 static constexpr size_t continuous_bits = 64; 223 static constexpr size_t continuous_bits = 64;
220 224
diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h
index 8906ba6d8..1528cc1dd 100644
--- a/src/video_core/query_cache.h
+++ b/src/video_core/query_cache.h
@@ -6,6 +6,7 @@
6#include <algorithm> 6#include <algorithm>
7#include <array> 7#include <array>
8#include <cstring> 8#include <cstring>
9#include <functional>
9#include <iterator> 10#include <iterator>
10#include <list> 11#include <list>
11#include <memory> 12#include <memory>
@@ -17,13 +18,19 @@
17 18
18#include "common/assert.h" 19#include "common/assert.h"
19#include "common/settings.h" 20#include "common/settings.h"
21#include "core/memory.h"
20#include "video_core/control/channel_state_cache.h" 22#include "video_core/control/channel_state_cache.h"
21#include "video_core/engines/maxwell_3d.h" 23#include "video_core/engines/maxwell_3d.h"
22#include "video_core/memory_manager.h" 24#include "video_core/memory_manager.h"
23#include "video_core/rasterizer_interface.h" 25#include "video_core/rasterizer_interface.h"
26#include "video_core/texture_cache/slot_vector.h"
24 27
25namespace VideoCommon { 28namespace VideoCommon {
26 29
30using AsyncJobId = SlotId;
31
32static constexpr AsyncJobId NULL_ASYNC_JOB_ID{0};
33
27template <class QueryCache, class HostCounter> 34template <class QueryCache, class HostCounter>
28class CounterStreamBase { 35class CounterStreamBase {
29public: 36public:
@@ -93,9 +100,13 @@ private:
93template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter> 100template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter>
94class QueryCacheBase : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { 101class QueryCacheBase : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
95public: 102public:
96 explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_) 103 explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_,
97 : rasterizer{rasterizer_}, streams{{CounterStream{static_cast<QueryCache&>(*this), 104 Core::Memory::Memory& cpu_memory_)
98 VideoCore::QueryType::SamplesPassed}}} {} 105 : rasterizer{rasterizer_},
106 cpu_memory{cpu_memory_}, streams{{CounterStream{static_cast<QueryCache&>(*this),
107 VideoCore::QueryType::SamplesPassed}}} {
108 (void)slot_async_jobs.insert(); // Null value
109 }
99 110
100 void InvalidateRegion(VAddr addr, std::size_t size) { 111 void InvalidateRegion(VAddr addr, std::size_t size) {
101 std::unique_lock lock{mutex}; 112 std::unique_lock lock{mutex};
@@ -126,10 +137,15 @@ public:
126 query = Register(type, *cpu_addr, host_ptr, timestamp.has_value()); 137 query = Register(type, *cpu_addr, host_ptr, timestamp.has_value());
127 } 138 }
128 139
129 query->BindCounter(Stream(type).Current(), timestamp); 140 auto result = query->BindCounter(Stream(type).Current(), timestamp);
130 if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) { 141 if (result) {
131 AsyncFlushQuery(*cpu_addr); 142 auto async_job_id = query->GetAsyncJob();
143 auto& async_job = slot_async_jobs[async_job_id];
144 async_job.collected = true;
145 async_job.value = *result;
146 query->SetAsyncJob(NULL_ASYNC_JOB_ID);
132 } 147 }
148 AsyncFlushQuery(query, timestamp, lock);
133 } 149 }
134 150
135 /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch. 151 /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch.
@@ -173,15 +189,18 @@ public:
173 } 189 }
174 190
175 void CommitAsyncFlushes() { 191 void CommitAsyncFlushes() {
192 std::unique_lock lock{mutex};
176 committed_flushes.push_back(uncommitted_flushes); 193 committed_flushes.push_back(uncommitted_flushes);
177 uncommitted_flushes.reset(); 194 uncommitted_flushes.reset();
178 } 195 }
179 196
180 bool HasUncommittedFlushes() const { 197 bool HasUncommittedFlushes() const {
198 std::unique_lock lock{mutex};
181 return uncommitted_flushes != nullptr; 199 return uncommitted_flushes != nullptr;
182 } 200 }
183 201
184 bool ShouldWaitAsyncFlushes() const { 202 bool ShouldWaitAsyncFlushes() const {
203 std::unique_lock lock{mutex};
185 if (committed_flushes.empty()) { 204 if (committed_flushes.empty()) {
186 return false; 205 return false;
187 } 206 }
@@ -189,6 +208,7 @@ public:
189 } 208 }
190 209
191 void PopAsyncFlushes() { 210 void PopAsyncFlushes() {
211 std::unique_lock lock{mutex};
192 if (committed_flushes.empty()) { 212 if (committed_flushes.empty()) {
193 return; 213 return;
194 } 214 }
@@ -197,15 +217,25 @@ public:
197 committed_flushes.pop_front(); 217 committed_flushes.pop_front();
198 return; 218 return;
199 } 219 }
200 for (VAddr query_address : *flush_list) { 220 for (AsyncJobId async_job_id : *flush_list) {
201 FlushAndRemoveRegion(query_address, 4); 221 AsyncJob& async_job = slot_async_jobs[async_job_id];
222 if (!async_job.collected) {
223 FlushAndRemoveRegion(async_job.query_location, 2, true);
224 }
202 } 225 }
203 committed_flushes.pop_front(); 226 committed_flushes.pop_front();
204 } 227 }
205 228
206private: 229private:
230 struct AsyncJob {
231 bool collected = false;
232 u64 value = 0;
233 VAddr query_location = 0;
234 std::optional<u64> timestamp{};
235 };
236
207 /// Flushes a memory range to guest memory and removes it from the cache. 237 /// Flushes a memory range to guest memory and removes it from the cache.
208 void FlushAndRemoveRegion(VAddr addr, std::size_t size) { 238 void FlushAndRemoveRegion(VAddr addr, std::size_t size, bool async = false) {
209 const u64 addr_begin = addr; 239 const u64 addr_begin = addr;
210 const u64 addr_end = addr_begin + size; 240 const u64 addr_end = addr_begin + size;
211 const auto in_range = [addr_begin, addr_end](const CachedQuery& query) { 241 const auto in_range = [addr_begin, addr_end](const CachedQuery& query) {
@@ -225,8 +255,16 @@ private:
225 if (!in_range(query)) { 255 if (!in_range(query)) {
226 continue; 256 continue;
227 } 257 }
228 rasterizer.UpdatePagesCachedCount(query.GetCpuAddr(), query.SizeInBytes(), -1); 258 AsyncJobId async_job_id = query.GetAsyncJob();
229 query.Flush(); 259 auto flush_result = query.Flush(async);
260 if (async_job_id == NULL_ASYNC_JOB_ID) {
261 ASSERT_MSG(false, "This should not be reachable at all");
262 continue;
263 }
264 AsyncJob& async_job = slot_async_jobs[async_job_id];
265 async_job.collected = true;
266 async_job.value = flush_result;
267 query.SetAsyncJob(NULL_ASYNC_JOB_ID);
230 } 268 }
231 std::erase_if(contents, in_range); 269 std::erase_if(contents, in_range);
232 } 270 }
@@ -234,7 +272,6 @@ private:
234 272
235 /// 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.
236 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) {
237 rasterizer.UpdatePagesCachedCount(cpu_addr, CachedQuery::SizeInBytes(timestamp), 1);
238 const u64 page = static_cast<u64>(cpu_addr) >> YUZU_PAGEBITS; 275 const u64 page = static_cast<u64>(cpu_addr) >> YUZU_PAGEBITS;
239 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,
240 host_ptr); 277 host_ptr);
@@ -253,26 +290,60 @@ private:
253 return found != std::end(contents) ? &*found : nullptr; 290 return found != std::end(contents) ? &*found : nullptr;
254 } 291 }
255 292
256 void AsyncFlushQuery(VAddr addr) { 293 void AsyncFlushQuery(CachedQuery* query, std::optional<u64> timestamp,
257 if (!uncommitted_flushes) { 294 std::unique_lock<std::recursive_mutex>& lock) {
258 uncommitted_flushes = std::make_shared<std::vector<VAddr>>(); 295 const AsyncJobId new_async_job_id = slot_async_jobs.insert();
296 {
297 AsyncJob& async_job = slot_async_jobs[new_async_job_id];
298 query->SetAsyncJob(new_async_job_id);
299 async_job.query_location = query->GetCpuAddr();
300 async_job.collected = false;
301
302 if (!uncommitted_flushes) {
303 uncommitted_flushes = std::make_shared<std::vector<AsyncJobId>>();
304 }
305 uncommitted_flushes->push_back(new_async_job_id);
259 } 306 }
260 uncommitted_flushes->push_back(addr); 307 lock.unlock();
308 std::function<void()> operation([this, new_async_job_id, timestamp] {
309 std::unique_lock local_lock{mutex};
310 AsyncJob& async_job = slot_async_jobs[new_async_job_id];
311 u64 value = async_job.value;
312 VAddr address = async_job.query_location;
313 slot_async_jobs.erase(new_async_job_id);
314 local_lock.unlock();
315 if (timestamp) {
316 u64 timestamp_value = *timestamp;
317 cpu_memory.WriteBlockUnsafe(address + sizeof(u64), &timestamp_value, sizeof(u64));
318 cpu_memory.WriteBlockUnsafe(address, &value, sizeof(u64));
319 rasterizer.InvalidateRegion(address, sizeof(u64) * 2,
320 VideoCommon::CacheType::NoQueryCache);
321 } else {
322 u32 small_value = static_cast<u32>(value);
323 cpu_memory.WriteBlockUnsafe(address, &small_value, sizeof(u32));
324 rasterizer.InvalidateRegion(address, sizeof(u32),
325 VideoCommon::CacheType::NoQueryCache);
326 }
327 });
328 rasterizer.SyncOperation(std::move(operation));
261 } 329 }
262 330
263 static constexpr std::uintptr_t YUZU_PAGESIZE = 4096; 331 static constexpr std::uintptr_t YUZU_PAGESIZE = 4096;
264 static constexpr unsigned YUZU_PAGEBITS = 12; 332 static constexpr unsigned YUZU_PAGEBITS = 12;
265 333
334 SlotVector<AsyncJob> slot_async_jobs;
335
266 VideoCore::RasterizerInterface& rasterizer; 336 VideoCore::RasterizerInterface& rasterizer;
337 Core::Memory::Memory& cpu_memory;
267 338
268 std::recursive_mutex mutex; 339 mutable std::recursive_mutex mutex;
269 340
270 std::unordered_map<u64, std::vector<CachedQuery>> cached_queries; 341 std::unordered_map<u64, std::vector<CachedQuery>> cached_queries;
271 342
272 std::array<CounterStream, VideoCore::NumQueryTypes> streams; 343 std::array<CounterStream, VideoCore::NumQueryTypes> streams;
273 344
274 std::shared_ptr<std::vector<VAddr>> uncommitted_flushes{}; 345 std::shared_ptr<std::vector<AsyncJobId>> uncommitted_flushes{};
275 std::list<std::shared_ptr<std::vector<VAddr>>> committed_flushes; 346 std::list<std::shared_ptr<std::vector<AsyncJobId>>> committed_flushes;
276}; 347};
277 348
278template <class QueryCache, class HostCounter> 349template <class QueryCache, class HostCounter>
@@ -291,12 +362,12 @@ public:
291 virtual ~HostCounterBase() = default; 362 virtual ~HostCounterBase() = default;
292 363
293 /// Returns the current value of the query. 364 /// Returns the current value of the query.
294 u64 Query() { 365 u64 Query(bool async = false) {
295 if (result) { 366 if (result) {
296 return *result; 367 return *result;
297 } 368 }
298 369
299 u64 value = BlockingQuery() + base_result; 370 u64 value = BlockingQuery(async) + base_result;
300 if (dependency) { 371 if (dependency) {
301 value += dependency->Query(); 372 value += dependency->Query();
302 dependency = nullptr; 373 dependency = nullptr;
@@ -317,7 +388,7 @@ public:
317 388
318protected: 389protected:
319 /// Returns the value of query from the backend API blocking as needed. 390 /// Returns the value of query from the backend API blocking as needed.
320 virtual u64 BlockingQuery() const = 0; 391 virtual u64 BlockingQuery(bool async = false) const = 0;
321 392
322private: 393private:
323 std::shared_ptr<HostCounter> dependency; ///< Counter to add to this value. 394 std::shared_ptr<HostCounter> dependency; ///< Counter to add to this value.
@@ -340,26 +411,33 @@ public:
340 CachedQueryBase& operator=(const CachedQueryBase&) = delete; 411 CachedQueryBase& operator=(const CachedQueryBase&) = delete;
341 412
342 /// Flushes the query to guest memory. 413 /// Flushes the query to guest memory.
343 virtual void Flush() { 414 virtual u64 Flush(bool async = false) {
344 // When counter is nullptr it means that it's just been reset. We are supposed to write a 415 // When counter is nullptr it means that it's just been reset. We are supposed to write a
345 // zero in these cases. 416 // zero in these cases.
346 const u64 value = counter ? counter->Query() : 0; 417 const u64 value = counter ? counter->Query(async) : 0;
418 if (async) {
419 return value;
420 }
347 std::memcpy(host_ptr, &value, sizeof(u64)); 421 std::memcpy(host_ptr, &value, sizeof(u64));
348 422
349 if (timestamp) { 423 if (timestamp) {
350 std::memcpy(host_ptr + TIMESTAMP_OFFSET, &*timestamp, sizeof(u64)); 424 std::memcpy(host_ptr + TIMESTAMP_OFFSET, &*timestamp, sizeof(u64));
351 } 425 }
426 return value;
352 } 427 }
353 428
354 /// Binds a counter to this query. 429 /// Binds a counter to this query.
355 void BindCounter(std::shared_ptr<HostCounter> counter_, std::optional<u64> timestamp_) { 430 std::optional<u64> BindCounter(std::shared_ptr<HostCounter> counter_,
431 std::optional<u64> timestamp_) {
432 std::optional<u64> result{};
356 if (counter) { 433 if (counter) {
357 // If there's an old counter set it means the query is being rewritten by the game. 434 // If there's an old counter set it means the query is being rewritten by the game.
358 // To avoid losing the data forever, flush here. 435 // To avoid losing the data forever, flush here.
359 Flush(); 436 result = std::make_optional(Flush());
360 } 437 }
361 counter = std::move(counter_); 438 counter = std::move(counter_);
362 timestamp = timestamp_; 439 timestamp = timestamp_;
440 return result;
363 } 441 }
364 442
365 VAddr GetCpuAddr() const noexcept { 443 VAddr GetCpuAddr() const noexcept {
@@ -374,6 +452,14 @@ public:
374 return with_timestamp ? LARGE_QUERY_SIZE : SMALL_QUERY_SIZE; 452 return with_timestamp ? LARGE_QUERY_SIZE : SMALL_QUERY_SIZE;
375 } 453 }
376 454
455 void SetAsyncJob(AsyncJobId assigned_async_job_) {
456 assigned_async_job = assigned_async_job_;
457 }
458
459 AsyncJobId GetAsyncJob() const {
460 return assigned_async_job;
461 }
462
377protected: 463protected:
378 /// Returns true when querying the counter may potentially block. 464 /// Returns true when querying the counter may potentially block.
379 bool WaitPending() const noexcept { 465 bool WaitPending() const noexcept {
@@ -389,6 +475,7 @@ private:
389 u8* host_ptr; ///< Writable host pointer. 475 u8* host_ptr; ///< Writable host pointer.
390 std::shared_ptr<HostCounter> counter; ///< Host counter to query, owns the dependency tree. 476 std::shared_ptr<HostCounter> counter; ///< Host counter to query, owns the dependency tree.
391 std::optional<u64> timestamp; ///< Timestamp to flush to guest memory. 477 std::optional<u64> timestamp; ///< Timestamp to flush to guest memory.
478 AsyncJobId assigned_async_job;
392}; 479};
393 480
394} // namespace VideoCommon 481} // namespace VideoCommon
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_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index a8c3f8b67..18d3c3ac0 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -8,6 +8,7 @@
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/buffer_cache/buffer_cache.h" 10#include "video_core/buffer_cache/buffer_cache.h"
11#include "video_core/buffer_cache/memory_tracker_base.h"
11#include "video_core/rasterizer_interface.h" 12#include "video_core/rasterizer_interface.h"
12#include "video_core/renderer_opengl/gl_device.h" 13#include "video_core/renderer_opengl/gl_device.h"
13#include "video_core/renderer_opengl/gl_resource_manager.h" 14#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -200,6 +201,8 @@ private:
200struct BufferCacheParams { 201struct BufferCacheParams {
201 using Runtime = OpenGL::BufferCacheRuntime; 202 using Runtime = OpenGL::BufferCacheRuntime;
202 using Buffer = OpenGL::Buffer; 203 using Buffer = OpenGL::Buffer;
204 using Async_Buffer = u32;
205 using MemoryTracker = VideoCommon::MemoryTrackerBase<VideoCore::RasterizerInterface>;
203 206
204 static constexpr bool IS_OPENGL = true; 207 static constexpr bool IS_OPENGL = true;
205 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = true; 208 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = true;
@@ -208,6 +211,7 @@ struct BufferCacheParams {
208 static constexpr bool NEEDS_BIND_STORAGE_INDEX = true; 211 static constexpr bool NEEDS_BIND_STORAGE_INDEX = true;
209 static constexpr bool USE_MEMORY_MAPS = false; 212 static constexpr bool USE_MEMORY_MAPS = false;
210 static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = true; 213 static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = true;
214 static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = false;
211}; 215};
212 216
213using BufferCache = VideoCommon::BufferCache<BufferCacheParams>; 217using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache_base.cpp b/src/video_core/renderer_opengl/gl_buffer_cache_base.cpp
new file mode 100644
index 000000000..f15ae8e25
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_buffer_cache_base.cpp
@@ -0,0 +1,9 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "video_core/buffer_cache/buffer_cache.h"
5#include "video_core/renderer_opengl/gl_buffer_cache.h"
6
7namespace VideoCommon {
8template class VideoCommon::BufferCache<OpenGL::BufferCacheParams>;
9}
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_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h
index f1446e732..e21b19dcc 100644
--- a/src/video_core/renderer_opengl/gl_fence_manager.h
+++ b/src/video_core/renderer_opengl/gl_fence_manager.h
@@ -30,7 +30,17 @@ private:
30}; 30};
31 31
32using Fence = std::shared_ptr<GLInnerFence>; 32using Fence = std::shared_ptr<GLInnerFence>;
33using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCache, BufferCache, QueryCache>; 33
34struct FenceManagerParams {
35 using FenceType = Fence;
36 using BufferCacheType = BufferCache;
37 using TextureCacheType = TextureCache;
38 using QueryCacheType = QueryCache;
39
40 static constexpr bool HAS_ASYNC_CHECK = false;
41};
42
43using GenericFenceManager = VideoCommon::FenceManager<FenceManagerParams>;
34 44
35class FenceManagerOpenGL final : public GenericFenceManager { 45class FenceManagerOpenGL final : public GenericFenceManager {
36public: 46public:
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp
index 5070db441..99d7347f5 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_query_cache.cpp
@@ -26,8 +26,8 @@ constexpr GLenum GetTarget(VideoCore::QueryType type) {
26 26
27} // Anonymous namespace 27} // Anonymous namespace
28 28
29QueryCache::QueryCache(RasterizerOpenGL& rasterizer_) 29QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_)
30 : QueryCacheBase(rasterizer_), gl_rasterizer{rasterizer_} {} 30 : QueryCacheBase(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {}
31 31
32QueryCache::~QueryCache() = default; 32QueryCache::~QueryCache() = default;
33 33
@@ -74,7 +74,7 @@ void HostCounter::EndQuery() {
74 glEndQuery(GetTarget(type)); 74 glEndQuery(GetTarget(type));
75} 75}
76 76
77u64 HostCounter::BlockingQuery() const { 77u64 HostCounter::BlockingQuery([[maybe_unused]] bool async) const {
78 GLint64 value; 78 GLint64 value;
79 glGetQueryObjecti64v(query.handle, GL_QUERY_RESULT, &value); 79 glGetQueryObjecti64v(query.handle, GL_QUERY_RESULT, &value);
80 return static_cast<u64>(value); 80 return static_cast<u64>(value);
@@ -96,7 +96,7 @@ CachedQuery& CachedQuery::operator=(CachedQuery&& rhs) noexcept {
96 return *this; 96 return *this;
97} 97}
98 98
99void CachedQuery::Flush() { 99u64 CachedQuery::Flush([[maybe_unused]] bool async) {
100 // Waiting for a query while another query of the same target is enabled locks Nvidia's driver. 100 // Waiting for a query while another query of the same target is enabled locks Nvidia's driver.
101 // To avoid this disable and re-enable keeping the dependency stream. 101 // To avoid this disable and re-enable keeping the dependency stream.
102 // But we only have to do this if we have pending waits to be done. 102 // But we only have to do this if we have pending waits to be done.
@@ -106,11 +106,13 @@ void CachedQuery::Flush() {
106 stream.Update(false); 106 stream.Update(false);
107 } 107 }
108 108
109 VideoCommon::CachedQueryBase<HostCounter>::Flush(); 109 auto result = VideoCommon::CachedQueryBase<HostCounter>::Flush();
110 110
111 if (slice_counter) { 111 if (slice_counter) {
112 stream.Update(true); 112 stream.Update(true);
113 } 113 }
114
115 return result;
114} 116}
115 117
116} // namespace OpenGL 118} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h
index 14ce59990..872513f22 100644
--- a/src/video_core/renderer_opengl/gl_query_cache.h
+++ b/src/video_core/renderer_opengl/gl_query_cache.h
@@ -28,7 +28,7 @@ using CounterStream = VideoCommon::CounterStreamBase<QueryCache, HostCounter>;
28class QueryCache final 28class QueryCache final
29 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { 29 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> {
30public: 30public:
31 explicit QueryCache(RasterizerOpenGL& rasterizer_); 31 explicit QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_);
32 ~QueryCache(); 32 ~QueryCache();
33 33
34 OGLQuery AllocateQuery(VideoCore::QueryType type); 34 OGLQuery AllocateQuery(VideoCore::QueryType type);
@@ -51,7 +51,7 @@ public:
51 void EndQuery(); 51 void EndQuery();
52 52
53private: 53private:
54 u64 BlockingQuery() const override; 54 u64 BlockingQuery(bool async = false) const override;
55 55
56 QueryCache& cache; 56 QueryCache& cache;
57 const VideoCore::QueryType type; 57 const VideoCore::QueryType type;
@@ -70,7 +70,7 @@ public:
70 CachedQuery(const CachedQuery&) = delete; 70 CachedQuery(const CachedQuery&) = delete;
71 CachedQuery& operator=(const CachedQuery&) = delete; 71 CachedQuery& operator=(const CachedQuery&) = delete;
72 72
73 void Flush() override; 73 u64 Flush(bool async = false) override;
74 74
75private: 75private:
76 QueryCache* cache; 76 QueryCache* cache;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4993d4709..f5baa0f3c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -63,7 +63,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra
63 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 63 buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
64 shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager, 64 shader_cache(*this, emu_window_, device, texture_cache, buffer_cache, program_manager,
65 state_tracker, gpu.ShaderNotify()), 65 state_tracker, gpu.ShaderNotify()),
66 query_cache(*this), accelerate_dma(buffer_cache, texture_cache), 66 query_cache(*this, cpu_memory_), accelerate_dma(buffer_cache, texture_cache),
67 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache), 67 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache),
68 blit_image(program_manager_) {} 68 blit_image(program_manager_) {}
69 69
@@ -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 032a8ebc5..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 }
@@ -861,9 +861,12 @@ GLuint Image::StorageHandle() noexcept {
861 case PixelFormat::ASTC_2D_8X5_SRGB: 861 case PixelFormat::ASTC_2D_8X5_SRGB:
862 case PixelFormat::ASTC_2D_5X4_SRGB: 862 case PixelFormat::ASTC_2D_5X4_SRGB:
863 case PixelFormat::ASTC_2D_5X5_SRGB: 863 case PixelFormat::ASTC_2D_5X5_SRGB:
864 case PixelFormat::ASTC_2D_10X5_SRGB:
865 case PixelFormat::ASTC_2D_10X6_SRGB:
864 case PixelFormat::ASTC_2D_10X8_SRGB: 866 case PixelFormat::ASTC_2D_10X8_SRGB:
865 case PixelFormat::ASTC_2D_6X6_SRGB: 867 case PixelFormat::ASTC_2D_6X6_SRGB:
866 case PixelFormat::ASTC_2D_10X10_SRGB: 868 case PixelFormat::ASTC_2D_10X10_SRGB:
869 case PixelFormat::ASTC_2D_12X10_SRGB:
867 case PixelFormat::ASTC_2D_12X12_SRGB: 870 case PixelFormat::ASTC_2D_12X12_SRGB:
868 case PixelFormat::ASTC_2D_8X6_SRGB: 871 case PixelFormat::ASTC_2D_8X6_SRGB:
869 case PixelFormat::ASTC_2D_6X5_SRGB: 872 case PixelFormat::ASTC_2D_6X5_SRGB:
@@ -1123,7 +1126,8 @@ bool Image::ScaleDown(bool ignore) {
1123 1126
1124ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, 1127ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
1125 ImageId image_id_, Image& image, const SlotVector<Image>&) 1128 ImageId image_id_, Image& image, const SlotVector<Image>&)
1126 : 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} {
1127 const Device& device = runtime.device; 1131 const Device& device = runtime.device;
1128 if (True(image.flags & ImageFlagBits::Converted)) { 1132 if (True(image.flags & ImageFlagBits::Converted)) {
1129 internal_format = IsPixelFormatSRGB(info.format) ? GL_SRGB8_ALPHA8 : GL_RGBA8; 1133 internal_format = IsPixelFormatSRGB(info.format) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
@@ -1214,12 +1218,12 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
1214 1218
1215ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, 1219ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
1216 const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) 1220 const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_)
1217 : VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_}, 1221 : VideoCommon::ImageViewBase{info, view_info, gpu_addr_},
1218 buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {} 1222 buffer_size{VideoCommon::CalculateGuestSizeInBytes(info)} {}
1219 1223
1220ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, 1224ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
1221 const VideoCommon::ImageViewInfo& view_info) 1225 const VideoCommon::ImageViewInfo& view_info)
1222 : VideoCommon::ImageViewBase{info, view_info} {} 1226 : VideoCommon::ImageViewBase{info, view_info, 0} {}
1223 1227
1224ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params) 1228ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params)
1225 : VideoCommon::ImageViewBase{params}, views{runtime.null_image_views} {} 1229 : VideoCommon::ImageViewBase{params}, views{runtime.null_image_views} {}
@@ -1279,7 +1283,7 @@ GLuint ImageView::MakeView(Shader::TextureType view_type, GLenum view_format) {
1279 ApplySwizzle(view.handle, format, casted_swizzle); 1283 ApplySwizzle(view.handle, format, casted_swizzle);
1280 } 1284 }
1281 if (set_object_label) { 1285 if (set_object_label) {
1282 const std::string name = VideoCommon::Name(*this); 1286 const std::string name = VideoCommon::Name(*this, gpu_addr);
1283 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());
1284 } 1288 }
1285 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_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index ef1190e1f..c7dc7e0a1 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -100,10 +100,13 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
100 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM 100 {GL_COMPRESSED_RGBA_ASTC_6x6_KHR}, // ASTC_2D_6X6_UNORM
101 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB 101 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR}, // ASTC_2D_6X6_SRGB
102 {GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM 102 {GL_COMPRESSED_RGBA_ASTC_10x6_KHR}, // ASTC_2D_10X6_UNORM
103 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR}, // ASTC_2D_10X6_SRGB
103 {GL_COMPRESSED_RGBA_ASTC_10x5_KHR}, // ASTC_2D_10X5_UNORM 104 {GL_COMPRESSED_RGBA_ASTC_10x5_KHR}, // ASTC_2D_10X5_UNORM
104 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR}, // ASTC_2D_10X5_SRGB 105 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR}, // ASTC_2D_10X5_SRGB
105 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM 106 {GL_COMPRESSED_RGBA_ASTC_10x10_KHR}, // ASTC_2D_10X10_UNORM
106 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB 107 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR}, // ASTC_2D_10X10_SRGB
108 {GL_COMPRESSED_RGBA_ASTC_12x10_KHR}, // ASTC_2D_12X10_UNORM
109 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR}, // ASTC_2D_12X10_SRGB
107 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM 110 {GL_COMPRESSED_RGBA_ASTC_12x12_KHR}, // ASTC_2D_12X12_UNORM
108 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB 111 {GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR}, // ASTC_2D_12X12_SRGB
109 {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6_UNORM 112 {GL_COMPRESSED_RGBA_ASTC_8x6_KHR}, // ASTC_2D_8X6_UNORM
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 5dce51be8..8853cf0f7 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -197,10 +197,13 @@ struct FormatTuple {
197 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM 197 {VK_FORMAT_ASTC_6x6_UNORM_BLOCK}, // ASTC_2D_6X6_UNORM
198 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB 198 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK}, // ASTC_2D_6X6_SRGB
199 {VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM 199 {VK_FORMAT_ASTC_10x6_UNORM_BLOCK}, // ASTC_2D_10X6_UNORM
200 {VK_FORMAT_ASTC_10x6_SRGB_BLOCK}, // ASTC_2D_10X6_SRGB
200 {VK_FORMAT_ASTC_10x5_UNORM_BLOCK}, // ASTC_2D_10X5_UNORM 201 {VK_FORMAT_ASTC_10x5_UNORM_BLOCK}, // ASTC_2D_10X5_UNORM
201 {VK_FORMAT_ASTC_10x5_SRGB_BLOCK}, // ASTC_2D_10X5_SRGB 202 {VK_FORMAT_ASTC_10x5_SRGB_BLOCK}, // ASTC_2D_10X5_SRGB
202 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM 203 {VK_FORMAT_ASTC_10x10_UNORM_BLOCK}, // ASTC_2D_10X10_UNORM
203 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB 204 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK}, // ASTC_2D_10X10_SRGB
205 {VK_FORMAT_ASTC_12x10_UNORM_BLOCK}, // ASTC_2D_12X10_UNORM
206 {VK_FORMAT_ASTC_12x10_SRGB_BLOCK}, // ASTC_2D_12X10_SRGB
204 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM 207 {VK_FORMAT_ASTC_12x12_UNORM_BLOCK}, // ASTC_2D_12X12_UNORM
205 {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB 208 {VK_FORMAT_ASTC_12x12_SRGB_BLOCK}, // ASTC_2D_12X12_SRGB
206 {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6_UNORM 209 {VK_FORMAT_ASTC_8x6_UNORM_BLOCK}, // ASTC_2D_8X6_UNORM
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 2a8d9e377..8e31eba34 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -88,13 +88,14 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
88 instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, 88 instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
89 Settings::values.renderer_debug.GetValue())), 89 Settings::values.renderer_debug.GetValue())),
90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), 90 debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
91 surface(CreateSurface(instance, render_window)), 91 surface(CreateSurface(instance, render_window.GetWindowInfo())),
92 device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), 92 device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false),
93 state_tracker(), scheduler(device, state_tracker), 93 state_tracker(), scheduler(device, state_tracker),
94 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, 94 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
95 render_window.GetFramebufferLayout().height, false), 95 render_window.GetFramebufferLayout().height, false),
96 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler, 96 present_manager(render_window, device, memory_allocator, scheduler, swapchain),
97 screen_info), 97 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager,
98 scheduler, screen_info),
98 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator, 99 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator,
99 state_tracker, scheduler) { 100 state_tracker, scheduler) {
100 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { 101 if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
@@ -121,46 +122,19 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
121 return; 122 return;
122 } 123 }
123 // Update screen info if the framebuffer size has changed. 124 // Update screen info if the framebuffer size has changed.
124 if (screen_info.width != framebuffer->width || screen_info.height != framebuffer->height) { 125 screen_info.width = framebuffer->width;
125 screen_info.width = framebuffer->width; 126 screen_info.height = framebuffer->height;
126 screen_info.height = framebuffer->height; 127
127 }
128 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; 128 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
129 const bool use_accelerated = 129 const bool use_accelerated =
130 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); 130 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
131 const bool is_srgb = use_accelerated && screen_info.is_srgb; 131 const bool is_srgb = use_accelerated && screen_info.is_srgb;
132 RenderScreenshot(*framebuffer, use_accelerated); 132 RenderScreenshot(*framebuffer, use_accelerated);
133 133
134 bool has_been_recreated = false; 134 Frame* frame = present_manager.GetRenderFrame();
135 const auto recreate_swapchain = [&](u32 width, u32 height) { 135 blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
136 if (!has_been_recreated) { 136 scheduler.Flush(*frame->render_ready);
137 has_been_recreated = true; 137 present_manager.Present(frame);
138 scheduler.Finish();
139 }
140 swapchain.Create(width, height, is_srgb);
141 };
142
143 const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
144 if (swapchain.NeedsRecreation(is_srgb) || swapchain.GetWidth() != layout.width ||
145 swapchain.GetHeight() != layout.height) {
146 recreate_swapchain(layout.width, layout.height);
147 }
148 bool is_outdated;
149 do {
150 swapchain.AcquireNextImage();
151 is_outdated = swapchain.IsOutDated();
152 if (is_outdated) {
153 recreate_swapchain(layout.width, layout.height);
154 }
155 } while (is_outdated);
156 if (has_been_recreated) {
157 blit_screen.Recreate();
158 }
159 const VkSemaphore render_semaphore = blit_screen.DrawToSwapchain(*framebuffer, use_accelerated);
160 const VkSemaphore present_semaphore = swapchain.CurrentPresentSemaphore();
161 scheduler.Flush(render_semaphore, present_semaphore);
162 scheduler.WaitWorker();
163 swapchain.Present(render_semaphore);
164 138
165 gpu.RendererFrameEndNotify(); 139 gpu.RendererFrameEndNotify();
166 rasterizer.TickFrame(); 140 rasterizer.TickFrame();
@@ -246,8 +220,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
246 }); 220 });
247 const VkExtent2D render_area{.width = layout.width, .height = layout.height}; 221 const VkExtent2D render_area{.width = layout.width, .height = layout.height};
248 const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); 222 const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area);
249 // Since we're not rendering to the screen, ignore the render semaphore. 223 blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated);
250 void(blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated));
251 224
252 const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); 225 const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4);
253 const VkBufferCreateInfo dst_buffer_info{ 226 const VkBufferCreateInfo dst_buffer_info{
@@ -270,7 +243,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
270 .pNext = nullptr, 243 .pNext = nullptr,
271 .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, 244 .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
272 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, 245 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
273 .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 246 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
274 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 247 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
275 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 248 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
276 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 249 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 009e75e0d..f44367cb2 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -9,6 +9,7 @@
9#include "common/dynamic_library.h" 9#include "common/dynamic_library.h"
10#include "video_core/renderer_base.h" 10#include "video_core/renderer_base.h"
11#include "video_core/renderer_vulkan/vk_blit_screen.h" 11#include "video_core/renderer_vulkan/vk_blit_screen.h"
12#include "video_core/renderer_vulkan/vk_present_manager.h"
12#include "video_core/renderer_vulkan/vk_rasterizer.h" 13#include "video_core/renderer_vulkan/vk_rasterizer.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 14#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/vk_state_tracker.h" 15#include "video_core/renderer_vulkan/vk_state_tracker.h"
@@ -76,6 +77,7 @@ private:
76 StateTracker state_tracker; 77 StateTracker state_tracker;
77 Scheduler scheduler; 78 Scheduler scheduler;
78 Swapchain swapchain; 79 Swapchain swapchain;
80 PresentManager present_manager;
79 BlitScreen blit_screen; 81 BlitScreen blit_screen;
80 RasterizerVulkan rasterizer; 82 RasterizerVulkan rasterizer;
81 std::optional<TurboMode> turbo_mode; 83 std::optional<TurboMode> turbo_mode;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 2f0cc27e8..1e0fdd3d9 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -122,10 +122,12 @@ struct BlitScreen::BufferData {
122 122
123BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_, 123BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_,
124 const Device& device_, MemoryAllocator& memory_allocator_, 124 const Device& device_, MemoryAllocator& memory_allocator_,
125 Swapchain& swapchain_, Scheduler& scheduler_, const ScreenInfo& screen_info_) 125 Swapchain& swapchain_, PresentManager& present_manager_,
126 Scheduler& scheduler_, const ScreenInfo& screen_info_)
126 : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, 127 : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_},
127 memory_allocator{memory_allocator_}, swapchain{swapchain_}, scheduler{scheduler_}, 128 memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_},
128 image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { 129 scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_},
130 current_srgb{swapchain.IsSrgb()}, image_view_format{swapchain.GetImageViewFormat()} {
129 resource_ticks.resize(image_count); 131 resource_ticks.resize(image_count);
130 132
131 CreateStaticResources(); 133 CreateStaticResources();
@@ -135,25 +137,20 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin
135BlitScreen::~BlitScreen() = default; 137BlitScreen::~BlitScreen() = default;
136 138
137void BlitScreen::Recreate() { 139void BlitScreen::Recreate() {
140 present_manager.WaitPresent();
141 scheduler.Finish();
142 device.GetLogical().WaitIdle();
138 CreateDynamicResources(); 143 CreateDynamicResources();
139} 144}
140 145
141VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, 146void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
142 const VkFramebuffer& host_framebuffer, 147 const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout,
143 const Layout::FramebufferLayout layout, VkExtent2D render_area, 148 VkExtent2D render_area, bool use_accelerated) {
144 bool use_accelerated) {
145 RefreshResources(framebuffer); 149 RefreshResources(framebuffer);
146 150
147 // Finish any pending renderpass 151 // Finish any pending renderpass
148 scheduler.RequestOutsideRenderPassOperationContext(); 152 scheduler.RequestOutsideRenderPassOperationContext();
149 153
150 if (const auto swapchain_images = swapchain.GetImageCount(); swapchain_images != image_count) {
151 image_count = swapchain_images;
152 Recreate();
153 }
154
155 const std::size_t image_index = swapchain.GetImageIndex();
156
157 scheduler.Wait(resource_ticks[image_index]); 154 scheduler.Wait(resource_ticks[image_index]);
158 resource_ticks[image_index] = scheduler.CurrentTick(); 155 resource_ticks[image_index] = scheduler.CurrentTick();
159 156
@@ -169,7 +166,7 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
169 std::memcpy(mapped_span.data(), &data, sizeof(data)); 166 std::memcpy(mapped_span.data(), &data, sizeof(data));
170 167
171 if (!use_accelerated) { 168 if (!use_accelerated) {
172 const u64 image_offset = GetRawImageOffset(framebuffer, image_index); 169 const u64 image_offset = GetRawImageOffset(framebuffer);
173 170
174 const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset; 171 const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
175 const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr); 172 const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr);
@@ -204,8 +201,8 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
204 .depth = 1, 201 .depth = 1,
205 }, 202 },
206 }; 203 };
207 scheduler.Record([this, copy, image_index](vk::CommandBuffer cmdbuf) { 204 scheduler.Record([this, copy, index = image_index](vk::CommandBuffer cmdbuf) {
208 const VkImage image = *raw_images[image_index]; 205 const VkImage image = *raw_images[index];
209 const VkImageMemoryBarrier base_barrier{ 206 const VkImageMemoryBarrier base_barrier{
210 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 207 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
211 .pNext = nullptr, 208 .pNext = nullptr,
@@ -245,14 +242,15 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
245 242
246 const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue(); 243 const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue();
247 if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) { 244 if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) {
248 UpdateAADescriptorSet(image_index, source_image_view, false); 245 UpdateAADescriptorSet(source_image_view, false);
249 const u32 up_scale = Settings::values.resolution_info.up_scale; 246 const u32 up_scale = Settings::values.resolution_info.up_scale;
250 const u32 down_shift = Settings::values.resolution_info.down_shift; 247 const u32 down_shift = Settings::values.resolution_info.down_shift;
251 VkExtent2D size{ 248 VkExtent2D size{
252 .width = (up_scale * framebuffer.width) >> down_shift, 249 .width = (up_scale * framebuffer.width) >> down_shift,
253 .height = (up_scale * framebuffer.height) >> down_shift, 250 .height = (up_scale * framebuffer.height) >> down_shift,
254 }; 251 };
255 scheduler.Record([this, image_index, size, anti_alias_pass](vk::CommandBuffer cmdbuf) { 252 scheduler.Record([this, index = image_index, size,
253 anti_alias_pass](vk::CommandBuffer cmdbuf) {
256 const VkImageMemoryBarrier base_barrier{ 254 const VkImageMemoryBarrier base_barrier{
257 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 255 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
258 .pNext = nullptr, 256 .pNext = nullptr,
@@ -326,7 +324,7 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
326 324
327 cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); 325 cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices));
328 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline_layout, 0, 326 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline_layout, 0,
329 aa_descriptor_sets[image_index], {}); 327 aa_descriptor_sets[index], {});
330 cmdbuf.Draw(4, 1, 0, 0); 328 cmdbuf.Draw(4, 1, 0, 0);
331 cmdbuf.EndRenderPass(); 329 cmdbuf.EndRenderPass();
332 330
@@ -369,81 +367,99 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
369 }; 367 };
370 VkImageView fsr_image_view = 368 VkImageView fsr_image_view =
371 fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); 369 fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect);
372 UpdateDescriptorSet(image_index, fsr_image_view, true); 370 UpdateDescriptorSet(fsr_image_view, true);
373 } else { 371 } else {
374 const bool is_nn = 372 const bool is_nn =
375 Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::NearestNeighbor; 373 Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::NearestNeighbor;
376 UpdateDescriptorSet(image_index, source_image_view, is_nn); 374 UpdateDescriptorSet(source_image_view, is_nn);
377 } 375 }
378 376
379 scheduler.Record( 377 scheduler.Record([this, host_framebuffer, index = image_index,
380 [this, host_framebuffer, image_index, size = render_area](vk::CommandBuffer cmdbuf) { 378 size = render_area](vk::CommandBuffer cmdbuf) {
381 const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; 379 const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f;
382 const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; 380 const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f;
383 const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; 381 const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f;
384 const VkClearValue clear_color{ 382 const VkClearValue clear_color{
385 .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, 383 .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}},
386 }; 384 };
387 const VkRenderPassBeginInfo renderpass_bi{ 385 const VkRenderPassBeginInfo renderpass_bi{
388 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 386 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
389 .pNext = nullptr, 387 .pNext = nullptr,
390 .renderPass = *renderpass, 388 .renderPass = *renderpass,
391 .framebuffer = host_framebuffer, 389 .framebuffer = host_framebuffer,
392 .renderArea = 390 .renderArea =
393 { 391 {
394 .offset = {0, 0}, 392 .offset = {0, 0},
395 .extent = size, 393 .extent = size,
396 }, 394 },
397 .clearValueCount = 1, 395 .clearValueCount = 1,
398 .pClearValues = &clear_color, 396 .pClearValues = &clear_color,
399 }; 397 };
400 const VkViewport viewport{ 398 const VkViewport viewport{
401 .x = 0.0f, 399 .x = 0.0f,
402 .y = 0.0f, 400 .y = 0.0f,
403 .width = static_cast<float>(size.width), 401 .width = static_cast<float>(size.width),
404 .height = static_cast<float>(size.height), 402 .height = static_cast<float>(size.height),
405 .minDepth = 0.0f, 403 .minDepth = 0.0f,
406 .maxDepth = 1.0f, 404 .maxDepth = 1.0f,
407 }; 405 };
408 const VkRect2D scissor{ 406 const VkRect2D scissor{
409 .offset = {0, 0}, 407 .offset = {0, 0},
410 .extent = size, 408 .extent = size,
411 }; 409 };
412 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); 410 cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
413 auto graphics_pipeline = [this]() { 411 auto graphics_pipeline = [this]() {
414 switch (Settings::values.scaling_filter.GetValue()) { 412 switch (Settings::values.scaling_filter.GetValue()) {
415 case Settings::ScalingFilter::NearestNeighbor: 413 case Settings::ScalingFilter::NearestNeighbor:
416 case Settings::ScalingFilter::Bilinear: 414 case Settings::ScalingFilter::Bilinear:
417 return *bilinear_pipeline; 415 return *bilinear_pipeline;
418 case Settings::ScalingFilter::Bicubic: 416 case Settings::ScalingFilter::Bicubic:
419 return *bicubic_pipeline; 417 return *bicubic_pipeline;
420 case Settings::ScalingFilter::Gaussian: 418 case Settings::ScalingFilter::Gaussian:
421 return *gaussian_pipeline; 419 return *gaussian_pipeline;
422 case Settings::ScalingFilter::ScaleForce: 420 case Settings::ScalingFilter::ScaleForce:
423 return *scaleforce_pipeline; 421 return *scaleforce_pipeline;
424 default: 422 default:
425 return *bilinear_pipeline; 423 return *bilinear_pipeline;
426 } 424 }
427 }(); 425 }();
428 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); 426 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
429 cmdbuf.SetViewport(0, viewport); 427 cmdbuf.SetViewport(0, viewport);
430 cmdbuf.SetScissor(0, scissor); 428 cmdbuf.SetScissor(0, scissor);
431 429
432 cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); 430 cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices));
433 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, 431 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0,
434 descriptor_sets[image_index], {}); 432 descriptor_sets[index], {});
435 cmdbuf.Draw(4, 1, 0, 0); 433 cmdbuf.Draw(4, 1, 0, 0);
436 cmdbuf.EndRenderPass(); 434 cmdbuf.EndRenderPass();
437 }); 435 });
438 return *semaphores[image_index];
439} 436}
440 437
441VkSemaphore BlitScreen::DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, 438void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer,
442 bool use_accelerated) { 439 bool use_accelerated, bool is_srgb) {
443 const std::size_t image_index = swapchain.GetImageIndex(); 440 // Recreate dynamic resources if the the image count or colorspace changed
444 const VkExtent2D render_area = swapchain.GetSize(); 441 if (const std::size_t swapchain_images = swapchain.GetImageCount();
442 swapchain_images != image_count || current_srgb != is_srgb) {
443 current_srgb = is_srgb;
444 image_view_format = current_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
445 image_count = swapchain_images;
446 Recreate();
447 }
448
449 // Recreate the presentation frame if the dimensions of the window changed
445 const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); 450 const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
446 return Draw(framebuffer, *framebuffers[image_index], layout, render_area, use_accelerated); 451 if (layout.width != frame->width || layout.height != frame->height ||
452 is_srgb != frame->is_srgb) {
453 Recreate();
454 present_manager.RecreateFrame(frame, layout.width, layout.height, is_srgb,
455 image_view_format, *renderpass);
456 }
457
458 const VkExtent2D render_area{frame->width, frame->height};
459 Draw(framebuffer, *frame->framebuffer, layout, render_area, use_accelerated);
460 if (++image_index >= image_count) {
461 image_index = 0;
462 }
447} 463}
448 464
449vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { 465vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) {
@@ -471,13 +487,11 @@ void BlitScreen::CreateStaticResources() {
471} 487}
472 488
473void BlitScreen::CreateDynamicResources() { 489void BlitScreen::CreateDynamicResources() {
474 CreateSemaphores();
475 CreateDescriptorPool(); 490 CreateDescriptorPool();
476 CreateDescriptorSetLayout(); 491 CreateDescriptorSetLayout();
477 CreateDescriptorSets(); 492 CreateDescriptorSets();
478 CreatePipelineLayout(); 493 CreatePipelineLayout();
479 CreateRenderPass(); 494 CreateRenderPass();
480 CreateFramebuffers();
481 CreateGraphicsPipeline(); 495 CreateGraphicsPipeline();
482 fsr.reset(); 496 fsr.reset();
483 smaa.reset(); 497 smaa.reset();
@@ -525,11 +539,6 @@ void BlitScreen::CreateShaders() {
525 } 539 }
526} 540}
527 541
528void BlitScreen::CreateSemaphores() {
529 semaphores.resize(image_count);
530 std::ranges::generate(semaphores, [this] { return device.GetLogical().CreateSemaphore(); });
531}
532
533void BlitScreen::CreateDescriptorPool() { 542void BlitScreen::CreateDescriptorPool() {
534 const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ 543 const std::array<VkDescriptorPoolSize, 2> pool_sizes{{
535 { 544 {
@@ -571,10 +580,10 @@ void BlitScreen::CreateDescriptorPool() {
571} 580}
572 581
573void BlitScreen::CreateRenderPass() { 582void BlitScreen::CreateRenderPass() {
574 renderpass = CreateRenderPassImpl(swapchain.GetImageViewFormat()); 583 renderpass = CreateRenderPassImpl(image_view_format);
575} 584}
576 585
577vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format, bool is_present) { 586vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) {
578 const VkAttachmentDescription color_attachment{ 587 const VkAttachmentDescription color_attachment{
579 .flags = 0, 588 .flags = 0,
580 .format = format, 589 .format = format,
@@ -584,7 +593,7 @@ vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format, bool is_present
584 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 593 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
585 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 594 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
586 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 595 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
587 .finalLayout = is_present ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_GENERAL, 596 .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
588 }; 597 };
589 598
590 const VkAttachmentReference color_attachment_ref{ 599 const VkAttachmentReference color_attachment_ref{
@@ -1052,16 +1061,6 @@ void BlitScreen::CreateSampler() {
1052 nn_sampler = device.GetLogical().CreateSampler(ci_nn); 1061 nn_sampler = device.GetLogical().CreateSampler(ci_nn);
1053} 1062}
1054 1063
1055void BlitScreen::CreateFramebuffers() {
1056 const VkExtent2D size{swapchain.GetSize()};
1057 framebuffers.resize(image_count);
1058
1059 for (std::size_t i = 0; i < image_count; ++i) {
1060 const VkImageView image_view{swapchain.GetImageViewIndex(i)};
1061 framebuffers[i] = CreateFramebuffer(image_view, size, renderpass);
1062 }
1063}
1064
1065void BlitScreen::ReleaseRawImages() { 1064void BlitScreen::ReleaseRawImages() {
1066 for (const u64 tick : resource_ticks) { 1065 for (const u64 tick : resource_ticks) {
1067 scheduler.Wait(tick); 1066 scheduler.Wait(tick);
@@ -1175,7 +1174,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1175 aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass); 1174 aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass);
1176 return; 1175 return;
1177 } 1176 }
1178 aa_renderpass = CreateRenderPassImpl(GetFormat(framebuffer), false); 1177 aa_renderpass = CreateRenderPassImpl(GetFormat(framebuffer));
1179 aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass); 1178 aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass);
1180 1179
1181 const std::array<VkPipelineShaderStageCreateInfo, 2> fxaa_shader_stages{{ 1180 const std::array<VkPipelineShaderStageCreateInfo, 2> fxaa_shader_stages{{
@@ -1319,8 +1318,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1319 aa_pipeline = device.GetLogical().CreateGraphicsPipeline(fxaa_pipeline_ci); 1318 aa_pipeline = device.GetLogical().CreateGraphicsPipeline(fxaa_pipeline_ci);
1320} 1319}
1321 1320
1322void BlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView image_view, 1321void BlitScreen::UpdateAADescriptorSet(VkImageView image_view, bool nn) const {
1323 bool nn) const {
1324 const VkDescriptorImageInfo image_info{ 1322 const VkDescriptorImageInfo image_info{
1325 .sampler = nn ? *nn_sampler : *sampler, 1323 .sampler = nn ? *nn_sampler : *sampler,
1326 .imageView = image_view, 1324 .imageView = image_view,
@@ -1356,8 +1354,7 @@ void BlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView imag
1356 device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, sampler_write_2}, {}); 1354 device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, sampler_write_2}, {});
1357} 1355}
1358 1356
1359void BlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view, 1357void BlitScreen::UpdateDescriptorSet(VkImageView image_view, bool nn) const {
1360 bool nn) const {
1361 const VkDescriptorBufferInfo buffer_info{ 1358 const VkDescriptorBufferInfo buffer_info{
1362 .buffer = *buffer, 1359 .buffer = *buffer,
1363 .offset = offsetof(BufferData, uniform), 1360 .offset = offsetof(BufferData, uniform),
@@ -1480,8 +1477,7 @@ u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer)
1480 return sizeof(BufferData) + GetSizeInBytes(framebuffer) * image_count; 1477 return sizeof(BufferData) + GetSizeInBytes(framebuffer) * image_count;
1481} 1478}
1482 1479
1483u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, 1480u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const {
1484 std::size_t image_index) const {
1485 constexpr auto first_image_offset = static_cast<u64>(sizeof(BufferData)); 1481 constexpr auto first_image_offset = static_cast<u64>(sizeof(BufferData));
1486 return first_image_offset + GetSizeInBytes(framebuffer) * image_index; 1482 return first_image_offset + GetSizeInBytes(framebuffer) * image_index;
1487} 1483}
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index ebe10b08b..68ec20253 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -5,6 +5,7 @@
5 5
6#include <memory> 6#include <memory>
7 7
8#include "core/frontend/framebuffer_layout.h"
8#include "video_core/vulkan_common/vulkan_memory_allocator.h" 9#include "video_core/vulkan_common/vulkan_memory_allocator.h"
9#include "video_core/vulkan_common/vulkan_wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
10 11
@@ -42,6 +43,9 @@ class RasterizerVulkan;
42class Scheduler; 43class Scheduler;
43class SMAA; 44class SMAA;
44class Swapchain; 45class Swapchain;
46class PresentManager;
47
48struct Frame;
45 49
46struct ScreenInfo { 50struct ScreenInfo {
47 VkImage image{}; 51 VkImage image{};
@@ -55,18 +59,17 @@ class BlitScreen {
55public: 59public:
56 explicit BlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window, 60 explicit BlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window,
57 const Device& device, MemoryAllocator& memory_manager, Swapchain& swapchain, 61 const Device& device, MemoryAllocator& memory_manager, Swapchain& swapchain,
58 Scheduler& scheduler, const ScreenInfo& screen_info); 62 PresentManager& present_manager, Scheduler& scheduler,
63 const ScreenInfo& screen_info);
59 ~BlitScreen(); 64 ~BlitScreen();
60 65
61 void Recreate(); 66 void Recreate();
62 67
63 [[nodiscard]] VkSemaphore Draw(const Tegra::FramebufferConfig& framebuffer, 68 void Draw(const Tegra::FramebufferConfig& framebuffer, const VkFramebuffer& host_framebuffer,
64 const VkFramebuffer& host_framebuffer, 69 const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated);
65 const Layout::FramebufferLayout layout, VkExtent2D render_area,
66 bool use_accelerated);
67 70
68 [[nodiscard]] VkSemaphore DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, 71 void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer,
69 bool use_accelerated); 72 bool use_accelerated, bool is_srgb);
70 73
71 [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, 74 [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view,
72 VkExtent2D extent); 75 VkExtent2D extent);
@@ -79,10 +82,9 @@ private:
79 82
80 void CreateStaticResources(); 83 void CreateStaticResources();
81 void CreateShaders(); 84 void CreateShaders();
82 void CreateSemaphores();
83 void CreateDescriptorPool(); 85 void CreateDescriptorPool();
84 void CreateRenderPass(); 86 void CreateRenderPass();
85 vk::RenderPass CreateRenderPassImpl(VkFormat, bool is_present = true); 87 vk::RenderPass CreateRenderPassImpl(VkFormat format);
86 void CreateDescriptorSetLayout(); 88 void CreateDescriptorSetLayout();
87 void CreateDescriptorSets(); 89 void CreateDescriptorSets();
88 void CreatePipelineLayout(); 90 void CreatePipelineLayout();
@@ -90,15 +92,14 @@ private:
90 void CreateSampler(); 92 void CreateSampler();
91 93
92 void CreateDynamicResources(); 94 void CreateDynamicResources();
93 void CreateFramebuffers();
94 95
95 void RefreshResources(const Tegra::FramebufferConfig& framebuffer); 96 void RefreshResources(const Tegra::FramebufferConfig& framebuffer);
96 void ReleaseRawImages(); 97 void ReleaseRawImages();
97 void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); 98 void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer);
98 void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); 99 void CreateRawImages(const Tegra::FramebufferConfig& framebuffer);
99 100
100 void UpdateDescriptorSet(std::size_t image_index, VkImageView image_view, bool nn) const; 101 void UpdateDescriptorSet(VkImageView image_view, bool nn) const;
101 void UpdateAADescriptorSet(std::size_t image_index, VkImageView image_view, bool nn) const; 102 void UpdateAADescriptorSet(VkImageView image_view, bool nn) const;
102 void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const; 103 void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const;
103 void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, 104 void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer,
104 const Layout::FramebufferLayout layout) const; 105 const Layout::FramebufferLayout layout) const;
@@ -107,16 +108,17 @@ private:
107 void CreateFSR(); 108 void CreateFSR();
108 109
109 u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; 110 u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const;
110 u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, 111 u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const;
111 std::size_t image_index) const;
112 112
113 Core::Memory::Memory& cpu_memory; 113 Core::Memory::Memory& cpu_memory;
114 Core::Frontend::EmuWindow& render_window; 114 Core::Frontend::EmuWindow& render_window;
115 const Device& device; 115 const Device& device;
116 MemoryAllocator& memory_allocator; 116 MemoryAllocator& memory_allocator;
117 Swapchain& swapchain; 117 Swapchain& swapchain;
118 PresentManager& present_manager;
118 Scheduler& scheduler; 119 Scheduler& scheduler;
119 std::size_t image_count; 120 std::size_t image_count;
121 std::size_t image_index{};
120 const ScreenInfo& screen_info; 122 const ScreenInfo& screen_info;
121 123
122 vk::ShaderModule vertex_shader; 124 vk::ShaderModule vertex_shader;
@@ -135,7 +137,6 @@ private:
135 vk::Pipeline gaussian_pipeline; 137 vk::Pipeline gaussian_pipeline;
136 vk::Pipeline scaleforce_pipeline; 138 vk::Pipeline scaleforce_pipeline;
137 vk::RenderPass renderpass; 139 vk::RenderPass renderpass;
138 std::vector<vk::Framebuffer> framebuffers;
139 vk::DescriptorSets descriptor_sets; 140 vk::DescriptorSets descriptor_sets;
140 vk::Sampler nn_sampler; 141 vk::Sampler nn_sampler;
141 vk::Sampler sampler; 142 vk::Sampler sampler;
@@ -145,7 +146,6 @@ private:
145 146
146 std::vector<u64> resource_ticks; 147 std::vector<u64> resource_ticks;
147 148
148 std::vector<vk::Semaphore> semaphores;
149 std::vector<vk::Image> raw_images; 149 std::vector<vk::Image> raw_images;
150 std::vector<vk::ImageView> raw_image_views; 150 std::vector<vk::ImageView> raw_image_views;
151 std::vector<MemoryCommit> raw_buffer_commits; 151 std::vector<MemoryCommit> raw_buffer_commits;
@@ -164,6 +164,8 @@ private:
164 u32 raw_width = 0; 164 u32 raw_width = 0;
165 u32 raw_height = 0; 165 u32 raw_height = 0;
166 Service::android::PixelFormat pixel_format{}; 166 Service::android::PixelFormat pixel_format{};
167 bool current_srgb;
168 VkFormat image_view_format;
167 169
168 std::unique_ptr<FSR> fsr; 170 std::unique_ptr<FSR> fsr;
169 std::unique_ptr<SMAA> smaa; 171 std::unique_ptr<SMAA> smaa;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 9cbcb3c8f..510602e8e 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -314,8 +314,12 @@ StagingBufferRef BufferCacheRuntime::UploadStagingBuffer(size_t size) {
314 return staging_pool.Request(size, MemoryUsage::Upload); 314 return staging_pool.Request(size, MemoryUsage::Upload);
315} 315}
316 316
317StagingBufferRef BufferCacheRuntime::DownloadStagingBuffer(size_t size) { 317StagingBufferRef BufferCacheRuntime::DownloadStagingBuffer(size_t size, bool deferred) {
318 return staging_pool.Request(size, MemoryUsage::Download); 318 return staging_pool.Request(size, MemoryUsage::Download, deferred);
319}
320
321void BufferCacheRuntime::FreeDeferredStagingBuffer(StagingBufferRef& ref) {
322 staging_pool.FreeDeferred(ref);
319} 323}
320 324
321u64 BufferCacheRuntime::GetDeviceLocalMemory() const { 325u64 BufferCacheRuntime::GetDeviceLocalMemory() const {
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index 183b33632..879f1ed94 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -3,7 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "video_core/buffer_cache/buffer_cache.h" 6#include "video_core/buffer_cache/buffer_cache_base.h"
7#include "video_core/buffer_cache/memory_tracker_base.h"
7#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
8#include "video_core/renderer_vulkan/vk_compute_pass.h" 9#include "video_core/renderer_vulkan/vk_compute_pass.h"
9#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 10#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -75,7 +76,9 @@ public:
75 76
76 [[nodiscard]] StagingBufferRef UploadStagingBuffer(size_t size); 77 [[nodiscard]] StagingBufferRef UploadStagingBuffer(size_t size);
77 78
78 [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size); 79 [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size, bool deferred = false);
80
81 void FreeDeferredStagingBuffer(StagingBufferRef& ref);
79 82
80 void PreCopyBarrier(); 83 void PreCopyBarrier();
81 84
@@ -142,6 +145,8 @@ private:
142struct BufferCacheParams { 145struct BufferCacheParams {
143 using Runtime = Vulkan::BufferCacheRuntime; 146 using Runtime = Vulkan::BufferCacheRuntime;
144 using Buffer = Vulkan::Buffer; 147 using Buffer = Vulkan::Buffer;
148 using Async_Buffer = Vulkan::StagingBufferRef;
149 using MemoryTracker = VideoCommon::MemoryTrackerBase<VideoCore::RasterizerInterface>;
145 150
146 static constexpr bool IS_OPENGL = false; 151 static constexpr bool IS_OPENGL = false;
147 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = false; 152 static constexpr bool HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS = false;
@@ -150,6 +155,7 @@ struct BufferCacheParams {
150 static constexpr bool NEEDS_BIND_STORAGE_INDEX = false; 155 static constexpr bool NEEDS_BIND_STORAGE_INDEX = false;
151 static constexpr bool USE_MEMORY_MAPS = true; 156 static constexpr bool USE_MEMORY_MAPS = true;
152 static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = false; 157 static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = false;
158 static constexpr bool IMPLEMENTS_ASYNC_DOWNLOADS = true;
153}; 159};
154 160
155using BufferCache = VideoCommon::BufferCache<BufferCacheParams>; 161using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache_base.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache_base.cpp
new file mode 100644
index 000000000..f9e271507
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache_base.cpp
@@ -0,0 +1,9 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "video_core/buffer_cache/buffer_cache.h"
5#include "video_core/renderer_vulkan/vk_buffer_cache.h"
6
7namespace VideoCommon {
8template class VideoCommon::BufferCache<Vulkan::BufferCacheParams>;
9}
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index 0214b103a..fad9e3832 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -5,6 +5,7 @@
5 5
6#include "video_core/renderer_vulkan/vk_buffer_cache.h" 6#include "video_core/renderer_vulkan/vk_buffer_cache.h"
7#include "video_core/renderer_vulkan/vk_fence_manager.h" 7#include "video_core/renderer_vulkan/vk_fence_manager.h"
8#include "video_core/renderer_vulkan/vk_query_cache.h"
8#include "video_core/renderer_vulkan/vk_scheduler.h" 9#include "video_core/renderer_vulkan/vk_scheduler.h"
9#include "video_core/renderer_vulkan/vk_texture_cache.h" 10#include "video_core/renderer_vulkan/vk_texture_cache.h"
10#include "video_core/vulkan_common/vulkan_device.h" 11#include "video_core/vulkan_common/vulkan_device.h"
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index 7fe2afcd9..145359d4e 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -40,7 +40,16 @@ private:
40}; 40};
41using Fence = std::shared_ptr<InnerFence>; 41using Fence = std::shared_ptr<InnerFence>;
42 42
43using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCache, BufferCache, QueryCache>; 43struct FenceManagerParams {
44 using FenceType = Fence;
45 using BufferCacheType = BufferCache;
46 using TextureCacheType = TextureCache;
47 using QueryCacheType = QueryCache;
48
49 static constexpr bool HAS_ASYNC_CHECK = true;
50};
51
52using GenericFenceManager = VideoCommon::FenceManager<FenceManagerParams>;
44 53
45class FenceManager final : public GenericFenceManager { 54class FenceManager final : public GenericFenceManager {
46public: 55public:
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
new file mode 100644
index 000000000..c49583013
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -0,0 +1,457 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/microprofile.h"
5#include "common/settings.h"
6#include "common/thread.h"
7#include "video_core/renderer_vulkan/vk_present_manager.h"
8#include "video_core/renderer_vulkan/vk_scheduler.h"
9#include "video_core/renderer_vulkan/vk_swapchain.h"
10#include "video_core/vulkan_common/vulkan_device.h"
11
12namespace Vulkan {
13
14MICROPROFILE_DEFINE(Vulkan_WaitPresent, "Vulkan", "Wait For Present", MP_RGB(128, 128, 128));
15MICROPROFILE_DEFINE(Vulkan_CopyToSwapchain, "Vulkan", "Copy to swapchain", MP_RGB(192, 255, 192));
16
17namespace {
18
19bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat format) {
20 const VkFormatProperties props{physical_device.GetFormatProperties(format)};
21 return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT);
22}
23
24[[nodiscard]] VkImageSubresourceLayers MakeImageSubresourceLayers() {
25 return VkImageSubresourceLayers{
26 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
27 .mipLevel = 0,
28 .baseArrayLayer = 0,
29 .layerCount = 1,
30 };
31}
32
33[[nodiscard]] VkImageBlit MakeImageBlit(s32 frame_width, s32 frame_height, s32 swapchain_width,
34 s32 swapchain_height) {
35 return VkImageBlit{
36 .srcSubresource = MakeImageSubresourceLayers(),
37 .srcOffsets =
38 {
39 {
40 .x = 0,
41 .y = 0,
42 .z = 0,
43 },
44 {
45 .x = frame_width,
46 .y = frame_height,
47 .z = 1,
48 },
49 },
50 .dstSubresource = MakeImageSubresourceLayers(),
51 .dstOffsets =
52 {
53 {
54 .x = 0,
55 .y = 0,
56 .z = 0,
57 },
58 {
59 .x = swapchain_width,
60 .y = swapchain_height,
61 .z = 1,
62 },
63 },
64 };
65}
66
67[[nodiscard]] VkImageCopy MakeImageCopy(u32 frame_width, u32 frame_height, u32 swapchain_width,
68 u32 swapchain_height) {
69 return VkImageCopy{
70 .srcSubresource = MakeImageSubresourceLayers(),
71 .srcOffset =
72 {
73 .x = 0,
74 .y = 0,
75 .z = 0,
76 },
77 .dstSubresource = MakeImageSubresourceLayers(),
78 .dstOffset =
79 {
80 .x = 0,
81 .y = 0,
82 .z = 0,
83 },
84 .extent =
85 {
86 .width = std::min(frame_width, swapchain_width),
87 .height = std::min(frame_height, swapchain_height),
88 .depth = 1,
89 },
90 };
91}
92
93} // Anonymous namespace
94
95PresentManager::PresentManager(Core::Frontend::EmuWindow& render_window_, const Device& device_,
96 MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
97 Swapchain& swapchain_)
98 : render_window{render_window_}, device{device_},
99 memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_},
100 blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())},
101 use_present_thread{Settings::values.async_presentation.GetValue()},
102 image_count{swapchain.GetImageCount()} {
103
104 auto& dld = device.GetLogical();
105 cmdpool = dld.CreateCommandPool({
106 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
107 .pNext = nullptr,
108 .flags =
109 VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
110 .queueFamilyIndex = device.GetGraphicsFamily(),
111 });
112 auto cmdbuffers = cmdpool.Allocate(image_count);
113
114 frames.resize(image_count);
115 for (u32 i = 0; i < frames.size(); i++) {
116 Frame& frame = frames[i];
117 frame.cmdbuf = vk::CommandBuffer{cmdbuffers[i], device.GetDispatchLoader()};
118 frame.render_ready = dld.CreateSemaphore({
119 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
120 .pNext = nullptr,
121 .flags = 0,
122 });
123 frame.present_done = dld.CreateFence({
124 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
125 .pNext = nullptr,
126 .flags = VK_FENCE_CREATE_SIGNALED_BIT,
127 });
128 free_queue.push(&frame);
129 }
130
131 if (use_present_thread) {
132 present_thread = std::jthread([this](std::stop_token token) { PresentThread(token); });
133 }
134}
135
136PresentManager::~PresentManager() = default;
137
138Frame* PresentManager::GetRenderFrame() {
139 MICROPROFILE_SCOPE(Vulkan_WaitPresent);
140
141 // Wait for free presentation frames
142 std::unique_lock lock{free_mutex};
143 free_cv.wait(lock, [this] { return !free_queue.empty(); });
144
145 // Take the frame from the queue
146 Frame* frame = free_queue.front();
147 free_queue.pop();
148
149 // Wait for the presentation to be finished so all frame resources are free
150 frame->present_done.Wait();
151 frame->present_done.Reset();
152
153 return frame;
154}
155
156void PresentManager::Present(Frame* frame) {
157 if (!use_present_thread) {
158 scheduler.WaitWorker();
159 CopyToSwapchain(frame);
160 free_queue.push(frame);
161 return;
162 }
163
164 scheduler.Record([this, frame](vk::CommandBuffer) {
165 std::unique_lock lock{queue_mutex};
166 present_queue.push(frame);
167 frame_cv.notify_one();
168 });
169}
170
171void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb,
172 VkFormat image_view_format, VkRenderPass rd) {
173 auto& dld = device.GetLogical();
174
175 frame->width = width;
176 frame->height = height;
177 frame->is_srgb = is_srgb;
178
179 frame->image = dld.CreateImage({
180 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
181 .pNext = nullptr,
182 .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
183 .imageType = VK_IMAGE_TYPE_2D,
184 .format = swapchain.GetImageFormat(),
185 .extent =
186 {
187 .width = width,
188 .height = height,
189 .depth = 1,
190 },
191 .mipLevels = 1,
192 .arrayLayers = 1,
193 .samples = VK_SAMPLE_COUNT_1_BIT,
194 .tiling = VK_IMAGE_TILING_OPTIMAL,
195 .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
196 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
197 .queueFamilyIndexCount = 0,
198 .pQueueFamilyIndices = nullptr,
199 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
200 });
201
202 frame->image_commit = memory_allocator.Commit(frame->image, MemoryUsage::DeviceLocal);
203
204 frame->image_view = dld.CreateImageView({
205 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
206 .pNext = nullptr,
207 .flags = 0,
208 .image = *frame->image,
209 .viewType = VK_IMAGE_VIEW_TYPE_2D,
210 .format = image_view_format,
211 .components =
212 {
213 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
214 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
215 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
216 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
217 },
218 .subresourceRange =
219 {
220 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
221 .baseMipLevel = 0,
222 .levelCount = 1,
223 .baseArrayLayer = 0,
224 .layerCount = 1,
225 },
226 });
227
228 const VkImageView image_view{*frame->image_view};
229 frame->framebuffer = dld.CreateFramebuffer({
230 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
231 .pNext = nullptr,
232 .flags = 0,
233 .renderPass = rd,
234 .attachmentCount = 1,
235 .pAttachments = &image_view,
236 .width = width,
237 .height = height,
238 .layers = 1,
239 });
240}
241
242void PresentManager::WaitPresent() {
243 if (!use_present_thread) {
244 return;
245 }
246
247 // Wait for the present queue to be empty
248 {
249 std::unique_lock queue_lock{queue_mutex};
250 frame_cv.wait(queue_lock, [this] { return present_queue.empty(); });
251 }
252
253 // The above condition will be satisfied when the last frame is taken from the queue.
254 // To ensure that frame has been presented as well take hold of the swapchain
255 // mutex.
256 std::scoped_lock swapchain_lock{swapchain_mutex};
257}
258
259void PresentManager::PresentThread(std::stop_token token) {
260 Common::SetCurrentThreadName("VulkanPresent");
261 while (!token.stop_requested()) {
262 std::unique_lock lock{queue_mutex};
263
264 // Wait for presentation frames
265 Common::CondvarWait(frame_cv, lock, token, [this] { return !present_queue.empty(); });
266 if (token.stop_requested()) {
267 return;
268 }
269
270 // Take the frame and notify anyone waiting
271 Frame* frame = present_queue.front();
272 present_queue.pop();
273 frame_cv.notify_one();
274
275 // By exchanging the lock ownership we take the swapchain lock
276 // before the queue lock goes out of scope. This way the swapchain
277 // lock in WaitPresent is guaranteed to occur after here.
278 std::exchange(lock, std::unique_lock{swapchain_mutex});
279
280 CopyToSwapchain(frame);
281
282 // Free the frame for reuse
283 std::scoped_lock fl{free_mutex};
284 free_queue.push(frame);
285 free_cv.notify_one();
286 }
287}
288
289void PresentManager::CopyToSwapchain(Frame* frame) {
290 MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain);
291
292 const auto recreate_swapchain = [&] {
293 swapchain.Create(frame->width, frame->height, frame->is_srgb);
294 image_count = swapchain.GetImageCount();
295 };
296
297 // If the size or colorspace of the incoming frames has changed, recreate the swapchain
298 // to account for that.
299 const bool srgb_changed = swapchain.NeedsRecreation(frame->is_srgb);
300 const bool size_changed =
301 swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;
302 if (srgb_changed || size_changed) {
303 recreate_swapchain();
304 }
305
306 while (swapchain.AcquireNextImage()) {
307 recreate_swapchain();
308 }
309
310 const vk::CommandBuffer cmdbuf{frame->cmdbuf};
311 cmdbuf.Begin({
312 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
313 .pNext = nullptr,
314 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
315 .pInheritanceInfo = nullptr,
316 });
317
318 const VkImage image{swapchain.CurrentImage()};
319 const VkExtent2D extent = swapchain.GetExtent();
320 const std::array pre_barriers{
321 VkImageMemoryBarrier{
322 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
323 .pNext = nullptr,
324 .srcAccessMask = 0,
325 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
326 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
327 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
328 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
329 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
330 .image = image,
331 .subresourceRange{
332 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
333 .baseMipLevel = 0,
334 .levelCount = 1,
335 .baseArrayLayer = 0,
336 .layerCount = VK_REMAINING_ARRAY_LAYERS,
337 },
338 },
339 VkImageMemoryBarrier{
340 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
341 .pNext = nullptr,
342 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
343 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
344 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
345 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
346 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
347 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
348 .image = *frame->image,
349 .subresourceRange{
350 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
351 .baseMipLevel = 0,
352 .levelCount = 1,
353 .baseArrayLayer = 0,
354 .layerCount = VK_REMAINING_ARRAY_LAYERS,
355 },
356 },
357 };
358 const std::array post_barriers{
359 VkImageMemoryBarrier{
360 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
361 .pNext = nullptr,
362 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
363 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
364 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
365 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
366 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
367 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
368 .image = image,
369 .subresourceRange{
370 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
371 .baseMipLevel = 0,
372 .levelCount = 1,
373 .baseArrayLayer = 0,
374 .layerCount = VK_REMAINING_ARRAY_LAYERS,
375 },
376 },
377 VkImageMemoryBarrier{
378 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
379 .pNext = nullptr,
380 .srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
381 .dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
382 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
383 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
384 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
385 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
386 .image = *frame->image,
387 .subresourceRange{
388 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
389 .baseMipLevel = 0,
390 .levelCount = 1,
391 .baseArrayLayer = 0,
392 .layerCount = VK_REMAINING_ARRAY_LAYERS,
393 },
394 },
395 };
396
397 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, {},
398 {}, {}, pre_barriers);
399
400 if (blit_supported) {
401 cmdbuf.BlitImage(*frame->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image,
402 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
403 MakeImageBlit(frame->width, frame->height, extent.width, extent.height),
404 VK_FILTER_LINEAR);
405 } else {
406 cmdbuf.CopyImage(*frame->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image,
407 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
408 MakeImageCopy(frame->width, frame->height, extent.width, extent.height));
409 }
410
411 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, {},
412 {}, {}, post_barriers);
413
414 cmdbuf.End();
415
416 const VkSemaphore present_semaphore = swapchain.CurrentPresentSemaphore();
417 const VkSemaphore render_semaphore = swapchain.CurrentRenderSemaphore();
418 const std::array wait_semaphores = {present_semaphore, *frame->render_ready};
419
420 static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{
421 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
422 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
423 };
424
425 const VkSubmitInfo submit_info{
426 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
427 .pNext = nullptr,
428 .waitSemaphoreCount = 2U,
429 .pWaitSemaphores = wait_semaphores.data(),
430 .pWaitDstStageMask = wait_stage_masks.data(),
431 .commandBufferCount = 1,
432 .pCommandBuffers = cmdbuf.address(),
433 .signalSemaphoreCount = 1U,
434 .pSignalSemaphores = &render_semaphore,
435 };
436
437 // Submit the image copy/blit to the swapchain
438 {
439 std::scoped_lock lock{scheduler.submit_mutex};
440 switch (const VkResult result =
441 device.GetGraphicsQueue().Submit(submit_info, *frame->present_done)) {
442 case VK_SUCCESS:
443 break;
444 case VK_ERROR_DEVICE_LOST:
445 device.ReportLoss();
446 [[fallthrough]];
447 default:
448 vk::Check(result);
449 break;
450 }
451 }
452
453 // Present
454 swapchain.Present(render_semaphore);
455}
456
457} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
new file mode 100644
index 000000000..420a775e2
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -0,0 +1,83 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <condition_variable>
7#include <mutex>
8#include <queue>
9
10#include "common/common_types.h"
11#include "common/polyfill_thread.h"
12#include "video_core/vulkan_common/vulkan_memory_allocator.h"
13#include "video_core/vulkan_common/vulkan_wrapper.h"
14
15namespace Core::Frontend {
16class EmuWindow;
17} // namespace Core::Frontend
18
19namespace Vulkan {
20
21class Device;
22class Scheduler;
23class Swapchain;
24
25struct Frame {
26 u32 width;
27 u32 height;
28 bool is_srgb;
29 vk::Image image;
30 vk::ImageView image_view;
31 vk::Framebuffer framebuffer;
32 MemoryCommit image_commit;
33 vk::CommandBuffer cmdbuf;
34 vk::Semaphore render_ready;
35 vk::Fence present_done;
36};
37
38class PresentManager {
39public:
40 PresentManager(Core::Frontend::EmuWindow& render_window, const Device& device,
41 MemoryAllocator& memory_allocator, Scheduler& scheduler, Swapchain& swapchain);
42 ~PresentManager();
43
44 /// Returns the last used presentation frame
45 Frame* GetRenderFrame();
46
47 /// Pushes a frame for presentation
48 void Present(Frame* frame);
49
50 /// Recreates the present frame to match the provided parameters
51 void RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb,
52 VkFormat image_view_format, VkRenderPass rd);
53
54 /// Waits for the present thread to finish presenting all queued frames.
55 void WaitPresent();
56
57private:
58 void PresentThread(std::stop_token token);
59
60 void CopyToSwapchain(Frame* frame);
61
62private:
63 Core::Frontend::EmuWindow& render_window;
64 const Device& device;
65 MemoryAllocator& memory_allocator;
66 Scheduler& scheduler;
67 Swapchain& swapchain;
68 vk::CommandPool cmdpool;
69 std::vector<Frame> frames;
70 std::queue<Frame*> present_queue;
71 std::queue<Frame*> free_queue;
72 std::condition_variable_any frame_cv;
73 std::condition_variable free_cv;
74 std::mutex swapchain_mutex;
75 std::mutex queue_mutex;
76 std::mutex free_mutex;
77 std::jthread present_thread;
78 bool blit_supported;
79 bool use_present_thread;
80 std::size_t image_count;
81};
82
83} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 929c8ece6..d67490449 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -66,9 +66,10 @@ void QueryPool::Reserve(std::pair<VkQueryPool, u32> query) {
66 } 66 }
67} 67}
68 68
69QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_, 69QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_,
70 Core::Memory::Memory& cpu_memory_, const Device& device_,
70 Scheduler& scheduler_) 71 Scheduler& scheduler_)
71 : QueryCacheBase{rasterizer_}, device{device_}, scheduler{scheduler_}, 72 : QueryCacheBase{rasterizer_, cpu_memory_}, device{device_}, scheduler{scheduler_},
72 query_pools{ 73 query_pools{
73 QueryPool{device_, scheduler_, QueryType::SamplesPassed}, 74 QueryPool{device_, scheduler_, QueryType::SamplesPassed},
74 } {} 75 } {}
@@ -98,8 +99,10 @@ HostCounter::HostCounter(QueryCache& cache_, std::shared_ptr<HostCounter> depend
98 query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} { 99 query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} {
99 const vk::Device* logical = &cache.GetDevice().GetLogical(); 100 const vk::Device* logical = &cache.GetDevice().GetLogical();
100 cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { 101 cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) {
102 const bool use_precise = Settings::IsGPULevelHigh();
101 logical->ResetQueryPool(query.first, query.second, 1); 103 logical->ResetQueryPool(query.first, query.second, 1);
102 cmdbuf.BeginQuery(query.first, query.second, VK_QUERY_CONTROL_PRECISE_BIT); 104 cmdbuf.BeginQuery(query.first, query.second,
105 use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0);
103 }); 106 });
104} 107}
105 108
@@ -112,8 +115,10 @@ void HostCounter::EndQuery() {
112 [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); }); 115 [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); });
113} 116}
114 117
115u64 HostCounter::BlockingQuery() const { 118u64 HostCounter::BlockingQuery(bool async) const {
116 cache.GetScheduler().Wait(tick); 119 if (!async) {
120 cache.GetScheduler().Wait(tick);
121 }
117 u64 data; 122 u64 data;
118 const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults( 123 const VkResult query_result = cache.GetDevice().GetLogical().GetQueryResults(
119 query.first, query.second, 1, sizeof(data), &data, sizeof(data), 124 query.first, query.second, 1, sizeof(data), &data, sizeof(data),
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index 26762ee09..c1b9552eb 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -52,7 +52,8 @@ private:
52class QueryCache final 52class QueryCache final
53 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { 53 : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> {
54public: 54public:
55 explicit QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_, 55 explicit QueryCache(VideoCore::RasterizerInterface& rasterizer_,
56 Core::Memory::Memory& cpu_memory_, const Device& device_,
56 Scheduler& scheduler_); 57 Scheduler& scheduler_);
57 ~QueryCache(); 58 ~QueryCache();
58 59
@@ -83,7 +84,7 @@ public:
83 void EndQuery(); 84 void EndQuery();
84 85
85private: 86private:
86 u64 BlockingQuery() const override; 87 u64 BlockingQuery(bool async = false) const override;
87 88
88 QueryCache& cache; 89 QueryCache& cache;
89 const VideoCore::QueryType type; 90 const VideoCore::QueryType type;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 2559a3aa7..628e1376f 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -172,7 +172,8 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
172 buffer_cache(*this, cpu_memory_, buffer_cache_runtime), 172 buffer_cache(*this, cpu_memory_, buffer_cache_runtime),
173 pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue, 173 pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue,
174 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), 174 render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()),
175 query_cache{*this, device, scheduler}, accelerate_dma(buffer_cache, texture_cache, scheduler), 175 query_cache{*this, cpu_memory_, device, scheduler},
176 accelerate_dma(buffer_cache, texture_cache, scheduler),
176 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), 177 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
177 wfi_event(device.GetLogical().CreateEvent()) { 178 wfi_event(device.GetLogical().CreateEvent()) {
178 scheduler.SetQueryCache(query_cache); 179 scheduler.SetQueryCache(query_cache);
@@ -501,6 +502,22 @@ bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size, VideoCommon::CacheT
501 return false; 502 return false;
502} 503}
503 504
505VideoCore::RasterizerDownloadArea RasterizerVulkan::GetFlushArea(VAddr addr, u64 size) {
506 {
507 std::scoped_lock lock{texture_cache.mutex};
508 auto area = texture_cache.GetFlushArea(addr, size);
509 if (area) {
510 return *area;
511 }
512 }
513 VideoCore::RasterizerDownloadArea new_area{
514 .start_address = Common::AlignDown(addr, Core::Memory::YUZU_PAGESIZE),
515 .end_address = Common::AlignUp(addr + size, Core::Memory::YUZU_PAGESIZE),
516 .preemtive = true,
517 };
518 return new_area;
519}
520
504void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { 521void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) {
505 if (addr == 0 || size == 0) { 522 if (addr == 0 || size == 0) {
506 return; 523 return;
@@ -597,7 +614,7 @@ void RasterizerVulkan::SignalSyncPoint(u32 value) {
597} 614}
598 615
599void RasterizerVulkan::SignalReference() { 616void RasterizerVulkan::SignalReference() {
600 fence_manager.SignalOrdering(); 617 fence_manager.SignalReference();
601} 618}
602 619
603void RasterizerVulkan::ReleaseFences() { 620void RasterizerVulkan::ReleaseFences() {
@@ -630,7 +647,7 @@ void RasterizerVulkan::WaitForIdle() {
630 cmdbuf.SetEvent(event, flags); 647 cmdbuf.SetEvent(event, flags);
631 cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {}); 648 cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {});
632 }); 649 });
633 SignalReference(); 650 fence_manager.SignalOrdering();
634} 651}
635 652
636void RasterizerVulkan::FragmentBarrier() { 653void RasterizerVulkan::FragmentBarrier() {
@@ -675,7 +692,8 @@ bool RasterizerVulkan::AccelerateConditionalRendering() {
675 const GPUVAddr condition_address{maxwell3d->regs.render_enable.Address()}; 692 const GPUVAddr condition_address{maxwell3d->regs.render_enable.Address()};
676 Maxwell::ReportSemaphore::Compare cmp; 693 Maxwell::ReportSemaphore::Compare cmp;
677 if (gpu_memory->IsMemoryDirty(condition_address, sizeof(cmp), 694 if (gpu_memory->IsMemoryDirty(condition_address, sizeof(cmp),
678 VideoCommon::CacheType::BufferCache)) { 695 VideoCommon::CacheType::BufferCache |
696 VideoCommon::CacheType::QueryCache)) {
679 return true; 697 return true;
680 } 698 }
681 return false; 699 return false;
@@ -775,7 +793,7 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
775 const Tegra::DMA::BufferOperand& buffer_operand, 793 const Tegra::DMA::BufferOperand& buffer_operand,
776 const Tegra::DMA::ImageOperand& image_operand) { 794 const Tegra::DMA::ImageOperand& image_operand) {
777 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; 795 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
778 const auto image_id = texture_cache.DmaImageId(image_operand); 796 const auto image_id = texture_cache.DmaImageId(image_operand, IS_IMAGE_UPLOAD);
779 if (image_id == VideoCommon::NULL_IMAGE_ID) { 797 if (image_id == VideoCommon::NULL_IMAGE_ID) {
780 return false; 798 return false;
781 } 799 }
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 1659fbc13..9bd422850 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;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index 057e16967..80455ec08 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -46,10 +46,11 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
46 46
47Scheduler::~Scheduler() = default; 47Scheduler::~Scheduler() = default;
48 48
49void Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { 49u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
50 // When flushing, we only send data to the worker thread; no waiting is necessary. 50 // When flushing, we only send data to the worker thread; no waiting is necessary.
51 SubmitExecution(signal_semaphore, wait_semaphore); 51 const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
52 AllocateNewContext(); 52 AllocateNewContext();
53 return signal_value;
53} 54}
54 55
55void Scheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { 56void Scheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
@@ -205,7 +206,7 @@ void Scheduler::AllocateWorkerCommandBuffer() {
205 }); 206 });
206} 207}
207 208
208void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { 209u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
209 EndPendingOperations(); 210 EndPendingOperations();
210 InvalidateState(); 211 InvalidateState();
211 212
@@ -217,6 +218,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s
217 on_submit(); 218 on_submit();
218 } 219 }
219 220
221 std::scoped_lock lock{submit_mutex};
220 switch (const VkResult result = master_semaphore->SubmitQueue( 222 switch (const VkResult result = master_semaphore->SubmitQueue(
221 cmdbuf, signal_semaphore, wait_semaphore, signal_value)) { 223 cmdbuf, signal_semaphore, wait_semaphore, signal_value)) {
222 case VK_SUCCESS: 224 case VK_SUCCESS:
@@ -231,6 +233,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s
231 }); 233 });
232 chunk->MarkSubmit(); 234 chunk->MarkSubmit();
233 DispatchWork(); 235 DispatchWork();
236 return signal_value;
234} 237}
235 238
236void Scheduler::AllocateNewContext() { 239void Scheduler::AllocateNewContext() {
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 8d75ce987..475c682eb 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -34,7 +34,7 @@ public:
34 ~Scheduler(); 34 ~Scheduler();
35 35
36 /// Sends the current execution context to the GPU. 36 /// Sends the current execution context to the GPU.
37 void Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr); 37 u64 Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
38 38
39 /// Sends the current execution context to the GPU and waits for it to complete. 39 /// Sends the current execution context to the GPU and waits for it to complete.
40 void Finish(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr); 40 void Finish(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
@@ -106,6 +106,8 @@ public:
106 return *master_semaphore; 106 return *master_semaphore;
107 } 107 }
108 108
109 std::mutex submit_mutex;
110
109private: 111private:
110 class Command { 112 class Command {
111 public: 113 public:
@@ -201,7 +203,7 @@ private:
201 203
202 void AllocateWorkerCommandBuffer(); 204 void AllocateWorkerCommandBuffer();
203 205
204 void SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore); 206 u64 SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore);
205 207
206 void AllocateNewContext(); 208 void AllocateNewContext();
207 209
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index b1465e35c..1e80ce463 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -14,6 +14,7 @@
14#include "video_core/renderer_vulkan/vk_swapchain.h" 14#include "video_core/renderer_vulkan/vk_swapchain.h"
15#include "video_core/vulkan_common/vulkan_device.h" 15#include "video_core/vulkan_common/vulkan_device.h"
16#include "video_core/vulkan_common/vulkan_wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
17#include "vulkan/vulkan_core.h"
17 18
18namespace Vulkan { 19namespace Vulkan {
19 20
@@ -33,23 +34,47 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats)
33 return found != formats.end() ? *found : formats[0]; 34 return found != formats.end() ? *found : formats[0];
34} 35}
35 36
36VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { 37static constexpr VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
37 // Mailbox (triple buffering) doesn't lock the application like fifo (vsync), 38 bool has_fifo_relaxed) {
38 // prefer it if vsync option is not selected 39 // Mailbox doesn't lock the application like FIFO (vsync)
39 const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); 40 // FIFO present mode locks the framerate to the monitor's refresh rate
40 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless && 41 Settings::VSyncMode setting = [has_imm, has_mailbox]() {
41 found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) { 42 // Choose Mailbox or Immediate if unlocked and those modes are supported
42 return VK_PRESENT_MODE_MAILBOX_KHR; 43 const auto mode = Settings::values.vsync_mode.GetValue();
43 } 44 if (Settings::values.use_speed_limit.GetValue()) {
44 if (!Settings::values.use_speed_limit.GetValue()) { 45 return mode;
45 // FIFO present mode locks the framerate to the monitor's refresh rate, 46 }
46 // Find an alternative to surpass this limitation if FPS is unlocked. 47 switch (mode) {
47 const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR); 48 case Settings::VSyncMode::FIFO:
48 if (found_imm != modes.end()) { 49 case Settings::VSyncMode::FIFORelaxed:
49 return VK_PRESENT_MODE_IMMEDIATE_KHR; 50 if (has_mailbox) {
51 return Settings::VSyncMode::Mailbox;
52 } else if (has_imm) {
53 return Settings::VSyncMode::Immediate;
54 }
55 [[fallthrough]];
56 default:
57 return mode;
50 } 58 }
59 }();
60 if ((setting == Settings::VSyncMode::Mailbox && !has_mailbox) ||
61 (setting == Settings::VSyncMode::Immediate && !has_imm) ||
62 (setting == Settings::VSyncMode::FIFORelaxed && !has_fifo_relaxed)) {
63 setting = Settings::VSyncMode::FIFO;
64 }
65
66 switch (setting) {
67 case Settings::VSyncMode::Immediate:
68 return VK_PRESENT_MODE_IMMEDIATE_KHR;
69 case Settings::VSyncMode::Mailbox:
70 return VK_PRESENT_MODE_MAILBOX_KHR;
71 case Settings::VSyncMode::FIFO:
72 return VK_PRESENT_MODE_FIFO_KHR;
73 case Settings::VSyncMode::FIFORelaxed:
74 return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
75 default:
76 return VK_PRESENT_MODE_FIFO_KHR;
51 } 77 }
52 return VK_PRESENT_MODE_FIFO_KHR;
53} 78}
54 79
55VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) { 80VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) {
@@ -99,18 +124,16 @@ void Swapchain::Create(u32 width_, u32 height_, bool srgb) {
99 return; 124 return;
100 } 125 }
101 126
102 device.GetLogical().WaitIdle();
103 Destroy(); 127 Destroy();
104 128
105 CreateSwapchain(capabilities, srgb); 129 CreateSwapchain(capabilities, srgb);
106 CreateSemaphores(); 130 CreateSemaphores();
107 CreateImageViews();
108 131
109 resource_ticks.clear(); 132 resource_ticks.clear();
110 resource_ticks.resize(image_count); 133 resource_ticks.resize(image_count);
111} 134}
112 135
113void Swapchain::AcquireNextImage() { 136bool Swapchain::AcquireNextImage() {
114 const VkResult result = device.GetLogical().AcquireNextImageKHR( 137 const VkResult result = device.GetLogical().AcquireNextImageKHR(
115 *swapchain, std::numeric_limits<u64>::max(), *present_semaphores[frame_index], 138 *swapchain, std::numeric_limits<u64>::max(), *present_semaphores[frame_index],
116 VK_NULL_HANDLE, &image_index); 139 VK_NULL_HANDLE, &image_index);
@@ -127,8 +150,11 @@ void Swapchain::AcquireNextImage() {
127 LOG_ERROR(Render_Vulkan, "vkAcquireNextImageKHR returned {}", vk::ToString(result)); 150 LOG_ERROR(Render_Vulkan, "vkAcquireNextImageKHR returned {}", vk::ToString(result));
128 break; 151 break;
129 } 152 }
153
130 scheduler.Wait(resource_ticks[image_index]); 154 scheduler.Wait(resource_ticks[image_index]);
131 resource_ticks[image_index] = scheduler.CurrentTick(); 155 resource_ticks[image_index] = scheduler.CurrentTick();
156
157 return is_suboptimal || is_outdated;
132} 158}
133 159
134void Swapchain::Present(VkSemaphore render_semaphore) { 160void Swapchain::Present(VkSemaphore render_semaphore) {
@@ -143,6 +169,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
143 .pImageIndices = &image_index, 169 .pImageIndices = &image_index,
144 .pResults = nullptr, 170 .pResults = nullptr,
145 }; 171 };
172 std::scoped_lock lock{scheduler.submit_mutex};
146 switch (const VkResult result = present_queue.Present(present_info)) { 173 switch (const VkResult result = present_queue.Present(present_info)) {
147 case VK_SUCCESS: 174 case VK_SUCCESS:
148 break; 175 break;
@@ -165,11 +192,17 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
165void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { 192void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) {
166 const auto physical_device{device.GetPhysical()}; 193 const auto physical_device{device.GetPhysical()};
167 const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; 194 const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
168 const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; 195 const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface);
196 has_mailbox = std::find(present_modes.begin(), present_modes.end(),
197 VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end();
198 has_imm = std::find(present_modes.begin(), present_modes.end(),
199 VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end();
200 has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(),
201 VK_PRESENT_MODE_FIFO_RELAXED_KHR) != present_modes.end();
169 202
170 const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)}; 203 const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)};
171 const VkSurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)}; 204 surface_format = ChooseSwapSurfaceFormat(formats);
172 present_mode = ChooseSwapPresentMode(present_modes); 205 present_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed);
173 206
174 u32 requested_image_count{capabilities.minImageCount + 1}; 207 u32 requested_image_count{capabilities.minImageCount + 1};
175 // Ensure Triple buffering if possible. 208 // Ensure Triple buffering if possible.
@@ -193,7 +226,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
193 .imageColorSpace = surface_format.colorSpace, 226 .imageColorSpace = surface_format.colorSpace,
194 .imageExtent = {}, 227 .imageExtent = {},
195 .imageArrayLayers = 1, 228 .imageArrayLayers = 1,
196 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 229 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
197 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, 230 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
198 .queueFamilyIndexCount = 0, 231 .queueFamilyIndexCount = 0,
199 .pQueueFamilyIndices = nullptr, 232 .pQueueFamilyIndices = nullptr,
@@ -230,7 +263,6 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
230 263
231 extent = swapchain_ci.imageExtent; 264 extent = swapchain_ci.imageExtent;
232 current_srgb = srgb; 265 current_srgb = srgb;
233 current_fps_unlocked = !Settings::values.use_speed_limit.GetValue();
234 266
235 images = swapchain.GetImages(); 267 images = swapchain.GetImages();
236 image_count = static_cast<u32>(images.size()); 268 image_count = static_cast<u32>(images.size());
@@ -241,56 +273,20 @@ void Swapchain::CreateSemaphores() {
241 present_semaphores.resize(image_count); 273 present_semaphores.resize(image_count);
242 std::ranges::generate(present_semaphores, 274 std::ranges::generate(present_semaphores,
243 [this] { return device.GetLogical().CreateSemaphore(); }); 275 [this] { return device.GetLogical().CreateSemaphore(); });
244} 276 render_semaphores.resize(image_count);
245 277 std::ranges::generate(render_semaphores,
246void Swapchain::CreateImageViews() { 278 [this] { return device.GetLogical().CreateSemaphore(); });
247 VkImageViewCreateInfo ci{
248 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
249 .pNext = nullptr,
250 .flags = 0,
251 .image = {},
252 .viewType = VK_IMAGE_VIEW_TYPE_2D,
253 .format = image_view_format,
254 .components =
255 {
256 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
257 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
258 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
259 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
260 },
261 .subresourceRange =
262 {
263 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
264 .baseMipLevel = 0,
265 .levelCount = 1,
266 .baseArrayLayer = 0,
267 .layerCount = 1,
268 },
269 };
270
271 image_views.resize(image_count);
272 for (std::size_t i = 0; i < image_count; i++) {
273 ci.image = images[i];
274 image_views[i] = device.GetLogical().CreateImageView(ci);
275 }
276} 279}
277 280
278void Swapchain::Destroy() { 281void Swapchain::Destroy() {
279 frame_index = 0; 282 frame_index = 0;
280 present_semaphores.clear(); 283 present_semaphores.clear();
281 framebuffers.clear();
282 image_views.clear();
283 swapchain.reset(); 284 swapchain.reset();
284} 285}
285 286
286bool Swapchain::HasFpsUnlockChanged() const {
287 return current_fps_unlocked != !Settings::values.use_speed_limit.GetValue();
288}
289
290bool Swapchain::NeedsPresentModeUpdate() const { 287bool Swapchain::NeedsPresentModeUpdate() const {
291 // Mailbox present mode is the ideal for all scenarios. If it is not available, 288 const auto requested_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed);
292 // A different present mode is needed to support unlocked FPS above the monitor's refresh rate. 289 return present_mode != requested_mode;
293 return present_mode != VK_PRESENT_MODE_MAILBOX_KHR && HasFpsUnlockChanged();
294} 290}
295 291
296} // namespace Vulkan 292} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index caf1ff32b..bf1ea7254 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -27,7 +27,7 @@ public:
27 void Create(u32 width, u32 height, bool srgb); 27 void Create(u32 width, u32 height, bool srgb);
28 28
29 /// Acquires the next image in the swapchain, waits as needed. 29 /// Acquires the next image in the swapchain, waits as needed.
30 void AcquireNextImage(); 30 bool AcquireNextImage();
31 31
32 /// Presents the rendered image to the swapchain. 32 /// Presents the rendered image to the swapchain.
33 void Present(VkSemaphore render_semaphore); 33 void Present(VkSemaphore render_semaphore);
@@ -52,6 +52,11 @@ public:
52 return is_suboptimal; 52 return is_suboptimal;
53 } 53 }
54 54
55 /// Returns true when the swapchain format is in the srgb color space
56 bool IsSrgb() const {
57 return current_srgb;
58 }
59
55 VkExtent2D GetSize() const { 60 VkExtent2D GetSize() const {
56 return extent; 61 return extent;
57 } 62 }
@@ -64,22 +69,34 @@ public:
64 return image_index; 69 return image_index;
65 } 70 }
66 71
72 std::size_t GetFrameIndex() const {
73 return frame_index;
74 }
75
67 VkImage GetImageIndex(std::size_t index) const { 76 VkImage GetImageIndex(std::size_t index) const {
68 return images[index]; 77 return images[index];
69 } 78 }
70 79
71 VkImageView GetImageViewIndex(std::size_t index) const { 80 VkImage CurrentImage() const {
72 return *image_views[index]; 81 return images[image_index];
73 } 82 }
74 83
75 VkFormat GetImageViewFormat() const { 84 VkFormat GetImageViewFormat() const {
76 return image_view_format; 85 return image_view_format;
77 } 86 }
78 87
88 VkFormat GetImageFormat() const {
89 return surface_format.format;
90 }
91
79 VkSemaphore CurrentPresentSemaphore() const { 92 VkSemaphore CurrentPresentSemaphore() const {
80 return *present_semaphores[frame_index]; 93 return *present_semaphores[frame_index];
81 } 94 }
82 95
96 VkSemaphore CurrentRenderSemaphore() const {
97 return *render_semaphores[frame_index];
98 }
99
83 u32 GetWidth() const { 100 u32 GetWidth() const {
84 return width; 101 return width;
85 } 102 }
@@ -88,6 +105,10 @@ public:
88 return height; 105 return height;
89 } 106 }
90 107
108 VkExtent2D GetExtent() const {
109 return extent;
110 }
111
91private: 112private:
92 void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb); 113 void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb);
93 void CreateSemaphores(); 114 void CreateSemaphores();
@@ -95,8 +116,6 @@ private:
95 116
96 void Destroy(); 117 void Destroy();
97 118
98 bool HasFpsUnlockChanged() const;
99
100 bool NeedsPresentModeUpdate() const; 119 bool NeedsPresentModeUpdate() const;
101 120
102 const VkSurfaceKHR surface; 121 const VkSurfaceKHR surface;
@@ -107,10 +126,9 @@ private:
107 126
108 std::size_t image_count{}; 127 std::size_t image_count{};
109 std::vector<VkImage> images; 128 std::vector<VkImage> images;
110 std::vector<vk::ImageView> image_views;
111 std::vector<vk::Framebuffer> framebuffers;
112 std::vector<u64> resource_ticks; 129 std::vector<u64> resource_ticks;
113 std::vector<vk::Semaphore> present_semaphores; 130 std::vector<vk::Semaphore> present_semaphores;
131 std::vector<vk::Semaphore> render_semaphores;
114 132
115 u32 width; 133 u32 width;
116 u32 height; 134 u32 height;
@@ -121,9 +139,12 @@ private:
121 VkFormat image_view_format{}; 139 VkFormat image_view_format{};
122 VkExtent2D extent{}; 140 VkExtent2D extent{};
123 VkPresentModeKHR present_mode{}; 141 VkPresentModeKHR present_mode{};
142 VkSurfaceFormatKHR surface_format{};
143 bool has_imm{false};
144 bool has_mailbox{false};
145 bool has_fifo_relaxed{false};
124 146
125 bool current_srgb{}; 147 bool current_srgb{};
126 bool current_fps_unlocked{};
127 bool is_outdated{}; 148 bool is_outdated{};
128 bool is_suboptimal{}; 149 bool is_suboptimal{};
129}; 150};
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index d0a7d8f35..9ca7751c5 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -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)
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index c656c5386..6f360177a 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -265,7 +265,6 @@ private:
265 VkImage image_handle = VK_NULL_HANDLE; 265 VkImage image_handle = VK_NULL_HANDLE;
266 VkImageView render_target = VK_NULL_HANDLE; 266 VkImageView render_target = VK_NULL_HANDLE;
267 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; 267 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
268 GPUVAddr gpu_addr = 0;
269 u32 buffer_size = 0; 268 u32 buffer_size = 0;
270}; 269};
271 270
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
index 009dab0b6..0630ebda5 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
@@ -14,13 +14,18 @@ namespace Vulkan {
14 14
15UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_) 15UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_)
16 : device{device_}, scheduler{scheduler_} { 16 : device{device_}, scheduler{scheduler_} {
17 payload_start = payload.data();
17 payload_cursor = payload.data(); 18 payload_cursor = payload.data();
18} 19}
19 20
20UpdateDescriptorQueue::~UpdateDescriptorQueue() = default; 21UpdateDescriptorQueue::~UpdateDescriptorQueue() = default;
21 22
22void UpdateDescriptorQueue::TickFrame() { 23void UpdateDescriptorQueue::TickFrame() {
23 payload_cursor = payload.data(); 24 if (++frame_index >= FRAMES_IN_FLIGHT) {
25 frame_index = 0;
26 }
27 payload_start = payload.data() + frame_index * FRAME_PAYLOAD_SIZE;
28 payload_cursor = payload_start;
24} 29}
25 30
26void UpdateDescriptorQueue::Acquire() { 31void UpdateDescriptorQueue::Acquire() {
@@ -28,10 +33,10 @@ void UpdateDescriptorQueue::Acquire() {
28 // This is the maximum number of entries a single draw call might use. 33 // This is the maximum number of entries a single draw call might use.
29 static constexpr size_t MIN_ENTRIES = 0x400; 34 static constexpr size_t MIN_ENTRIES = 0x400;
30 35
31 if (std::distance(payload.data(), payload_cursor) + MIN_ENTRIES >= payload.max_size()) { 36 if (std::distance(payload_start, payload_cursor) + MIN_ENTRIES >= FRAME_PAYLOAD_SIZE) {
32 LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread"); 37 LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread");
33 scheduler.WaitWorker(); 38 scheduler.WaitWorker();
34 payload_cursor = payload.data(); 39 payload_cursor = payload_start;
35 } 40 }
36 upload_start = payload_cursor; 41 upload_start = payload_cursor;
37} 42}
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 625bcc809..1c1a7020b 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -29,6 +29,12 @@ struct DescriptorUpdateEntry {
29}; 29};
30 30
31class UpdateDescriptorQueue final { 31class UpdateDescriptorQueue final {
32 // This should be plenty for the vast majority of cases. Most desktop platforms only
33 // provide up to 3 swapchain images.
34 static constexpr size_t FRAMES_IN_FLIGHT = 5;
35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x10000;
36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;
37
32public: 38public:
33 explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_); 39 explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_);
34 ~UpdateDescriptorQueue(); 40 ~UpdateDescriptorQueue();
@@ -73,9 +79,11 @@ private:
73 const Device& device; 79 const Device& device;
74 Scheduler& scheduler; 80 Scheduler& scheduler;
75 81
82 size_t frame_index{0};
76 DescriptorUpdateEntry* payload_cursor = nullptr; 83 DescriptorUpdateEntry* payload_cursor = nullptr;
84 DescriptorUpdateEntry* payload_start = nullptr;
77 const DescriptorUpdateEntry* upload_start = nullptr; 85 const DescriptorUpdateEntry* upload_start = nullptr;
78 std::array<DescriptorUpdateEntry, 0x10000> payload; 86 std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload;
79}; 87};
80 88
81} // namespace Vulkan 89} // namespace Vulkan
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index d9482371b..c5213875b 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -228,14 +228,14 @@ const ShaderInfo* ShaderCache::MakeShaderInfo(GenericEnvironment& env, VAddr cpu
228 auto info = std::make_unique<ShaderInfo>(); 228 auto info = std::make_unique<ShaderInfo>();
229 if (const std::optional<u64> cached_hash{env.Analyze()}) { 229 if (const std::optional<u64> cached_hash{env.Analyze()}) {
230 info->unique_hash = *cached_hash; 230 info->unique_hash = *cached_hash;
231 info->size_bytes = env.CachedSize(); 231 info->size_bytes = env.CachedSizeBytes();
232 } else { 232 } else {
233 // Slow path, not really hit on commercial games 233 // Slow path, not really hit on commercial games
234 // Build a control flow graph to get the real shader size 234 // Build a control flow graph to get the real shader size
235 Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block; 235 Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block;
236 Shader::Maxwell::Flow::CFG cfg{env, flow_block, env.StartAddress()}; 236 Shader::Maxwell::Flow::CFG cfg{env, flow_block, env.StartAddress()};
237 info->unique_hash = env.CalculateHash(); 237 info->unique_hash = env.CalculateHash();
238 info->size_bytes = env.ReadSize(); 238 info->size_bytes = env.ReadSizeBytes();
239 } 239 }
240 const size_t size_bytes{info->size_bytes}; 240 const size_t size_bytes{info->size_bytes};
241 const ShaderInfo* const result{info.get()}; 241 const ShaderInfo* const result{info.get()};
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp
index 574760f80..c7cb56243 100644
--- a/src/video_core/shader_environment.cpp
+++ b/src/video_core/shader_environment.cpp
@@ -170,15 +170,19 @@ std::optional<u64> GenericEnvironment::Analyze() {
170void GenericEnvironment::SetCachedSize(size_t size_bytes) { 170void GenericEnvironment::SetCachedSize(size_t size_bytes) {
171 cached_lowest = start_address; 171 cached_lowest = start_address;
172 cached_highest = start_address + static_cast<u32>(size_bytes); 172 cached_highest = start_address + static_cast<u32>(size_bytes);
173 code.resize(CachedSize()); 173 code.resize(CachedSizeWords());
174 gpu_memory->ReadBlock(program_base + cached_lowest, code.data(), code.size() * sizeof(u64)); 174 gpu_memory->ReadBlock(program_base + cached_lowest, code.data(), code.size() * sizeof(u64));
175} 175}
176 176
177size_t GenericEnvironment::CachedSize() const noexcept { 177size_t GenericEnvironment::CachedSizeWords() const noexcept {
178 return cached_highest - cached_lowest + INST_SIZE; 178 return CachedSizeBytes() / INST_SIZE;
179} 179}
180 180
181size_t GenericEnvironment::ReadSize() const noexcept { 181size_t GenericEnvironment::CachedSizeBytes() const noexcept {
182 return static_cast<size_t>(cached_highest) - cached_lowest + INST_SIZE;
183}
184
185size_t GenericEnvironment::ReadSizeBytes() const noexcept {
182 return read_highest - read_lowest + INST_SIZE; 186 return read_highest - read_lowest + INST_SIZE;
183} 187}
184 188
@@ -187,7 +191,7 @@ bool GenericEnvironment::CanBeSerialized() const noexcept {
187} 191}
188 192
189u64 GenericEnvironment::CalculateHash() const { 193u64 GenericEnvironment::CalculateHash() const {
190 const size_t size{ReadSize()}; 194 const size_t size{ReadSizeBytes()};
191 const auto data{std::make_unique<char[]>(size)}; 195 const auto data{std::make_unique<char[]>(size)};
192 gpu_memory->ReadBlock(program_base + read_lowest, data.get(), size); 196 gpu_memory->ReadBlock(program_base + read_lowest, data.get(), size);
193 return Common::CityHash64(data.get(), size); 197 return Common::CityHash64(data.get(), size);
@@ -198,7 +202,7 @@ void GenericEnvironment::Dump(u64 hash) {
198} 202}
199 203
200void GenericEnvironment::Serialize(std::ofstream& file) const { 204void GenericEnvironment::Serialize(std::ofstream& file) const {
201 const u64 code_size{static_cast<u64>(CachedSize())}; 205 const u64 code_size{static_cast<u64>(CachedSizeBytes())};
202 const u64 num_texture_types{static_cast<u64>(texture_types.size())}; 206 const u64 num_texture_types{static_cast<u64>(texture_types.size())};
203 const u64 num_texture_pixel_formats{static_cast<u64>(texture_pixel_formats.size())}; 207 const u64 num_texture_pixel_formats{static_cast<u64>(texture_pixel_formats.size())};
204 const u64 num_cbuf_values{static_cast<u64>(cbuf_values.size())}; 208 const u64 num_cbuf_values{static_cast<u64>(cbuf_values.size())};
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h
index d75987a52..a0f61cbda 100644
--- a/src/video_core/shader_environment.h
+++ b/src/video_core/shader_environment.h
@@ -48,9 +48,11 @@ public:
48 48
49 void SetCachedSize(size_t size_bytes); 49 void SetCachedSize(size_t size_bytes);
50 50
51 [[nodiscard]] size_t CachedSize() const noexcept; 51 [[nodiscard]] size_t CachedSizeWords() const noexcept;
52 52
53 [[nodiscard]] size_t ReadSize() const noexcept; 53 [[nodiscard]] size_t CachedSizeBytes() const noexcept;
54
55 [[nodiscard]] size_t ReadSizeBytes() const noexcept;
54 56
55 [[nodiscard]] bool CanBeSerialized() const noexcept; 57 [[nodiscard]] bool CanBeSerialized() const noexcept;
56 58
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 1a76d4178..cb51529e4 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -250,10 +250,13 @@ bool IsPixelFormatASTC(PixelFormat format) {
250 case PixelFormat::ASTC_2D_6X6_UNORM: 250 case PixelFormat::ASTC_2D_6X6_UNORM:
251 case PixelFormat::ASTC_2D_6X6_SRGB: 251 case PixelFormat::ASTC_2D_6X6_SRGB:
252 case PixelFormat::ASTC_2D_10X6_UNORM: 252 case PixelFormat::ASTC_2D_10X6_UNORM:
253 case PixelFormat::ASTC_2D_10X6_SRGB:
253 case PixelFormat::ASTC_2D_10X5_UNORM: 254 case PixelFormat::ASTC_2D_10X5_UNORM:
254 case PixelFormat::ASTC_2D_10X5_SRGB: 255 case PixelFormat::ASTC_2D_10X5_SRGB:
255 case PixelFormat::ASTC_2D_10X10_UNORM: 256 case PixelFormat::ASTC_2D_10X10_UNORM:
256 case PixelFormat::ASTC_2D_10X10_SRGB: 257 case PixelFormat::ASTC_2D_10X10_SRGB:
258 case PixelFormat::ASTC_2D_12X10_UNORM:
259 case PixelFormat::ASTC_2D_12X10_SRGB:
257 case PixelFormat::ASTC_2D_12X12_UNORM: 260 case PixelFormat::ASTC_2D_12X12_UNORM:
258 case PixelFormat::ASTC_2D_12X12_SRGB: 261 case PixelFormat::ASTC_2D_12X12_SRGB:
259 case PixelFormat::ASTC_2D_8X6_UNORM: 262 case PixelFormat::ASTC_2D_8X6_UNORM:
@@ -279,11 +282,13 @@ bool IsPixelFormatSRGB(PixelFormat format) {
279 case PixelFormat::ASTC_2D_8X5_SRGB: 282 case PixelFormat::ASTC_2D_8X5_SRGB:
280 case PixelFormat::ASTC_2D_5X4_SRGB: 283 case PixelFormat::ASTC_2D_5X4_SRGB:
281 case PixelFormat::ASTC_2D_5X5_SRGB: 284 case PixelFormat::ASTC_2D_5X5_SRGB:
285 case PixelFormat::ASTC_2D_10X6_SRGB:
282 case PixelFormat::ASTC_2D_10X8_SRGB: 286 case PixelFormat::ASTC_2D_10X8_SRGB:
283 case PixelFormat::ASTC_2D_6X6_SRGB: 287 case PixelFormat::ASTC_2D_6X6_SRGB:
284 case PixelFormat::ASTC_2D_10X5_SRGB: 288 case PixelFormat::ASTC_2D_10X5_SRGB:
285 case PixelFormat::ASTC_2D_10X10_SRGB: 289 case PixelFormat::ASTC_2D_10X10_SRGB:
286 case PixelFormat::ASTC_2D_12X12_SRGB: 290 case PixelFormat::ASTC_2D_12X12_SRGB:
291 case PixelFormat::ASTC_2D_12X10_SRGB:
287 case PixelFormat::ASTC_2D_8X6_SRGB: 292 case PixelFormat::ASTC_2D_8X6_SRGB:
288 case PixelFormat::ASTC_2D_6X5_SRGB: 293 case PixelFormat::ASTC_2D_6X5_SRGB:
289 return true; 294 return true;
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 44b79af20..0225d3287 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -95,10 +95,13 @@ enum class PixelFormat {
95 ASTC_2D_6X6_UNORM, 95 ASTC_2D_6X6_UNORM,
96 ASTC_2D_6X6_SRGB, 96 ASTC_2D_6X6_SRGB,
97 ASTC_2D_10X6_UNORM, 97 ASTC_2D_10X6_UNORM,
98 ASTC_2D_10X6_SRGB,
98 ASTC_2D_10X5_UNORM, 99 ASTC_2D_10X5_UNORM,
99 ASTC_2D_10X5_SRGB, 100 ASTC_2D_10X5_SRGB,
100 ASTC_2D_10X10_UNORM, 101 ASTC_2D_10X10_UNORM,
101 ASTC_2D_10X10_SRGB, 102 ASTC_2D_10X10_SRGB,
103 ASTC_2D_12X10_UNORM,
104 ASTC_2D_12X10_SRGB,
102 ASTC_2D_12X12_UNORM, 105 ASTC_2D_12X12_UNORM,
103 ASTC_2D_12X12_SRGB, 106 ASTC_2D_12X12_SRGB,
104 ASTC_2D_8X6_UNORM, 107 ASTC_2D_8X6_UNORM,
@@ -232,10 +235,13 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
232 6, // ASTC_2D_6X6_UNORM 235 6, // ASTC_2D_6X6_UNORM
233 6, // ASTC_2D_6X6_SRGB 236 6, // ASTC_2D_6X6_SRGB
234 10, // ASTC_2D_10X6_UNORM 237 10, // ASTC_2D_10X6_UNORM
238 10, // ASTC_2D_10X6_SRGB
235 10, // ASTC_2D_10X5_UNORM 239 10, // ASTC_2D_10X5_UNORM
236 10, // ASTC_2D_10X5_SRGB 240 10, // ASTC_2D_10X5_SRGB
237 10, // ASTC_2D_10X10_UNORM 241 10, // ASTC_2D_10X10_UNORM
238 10, // ASTC_2D_10X10_SRGB 242 10, // ASTC_2D_10X10_SRGB
243 12, // ASTC_2D_12X10_UNORM
244 12, // ASTC_2D_12X10_SRGB
239 12, // ASTC_2D_12X12_UNORM 245 12, // ASTC_2D_12X12_UNORM
240 12, // ASTC_2D_12X12_SRGB 246 12, // ASTC_2D_12X12_SRGB
241 8, // ASTC_2D_8X6_UNORM 247 8, // ASTC_2D_8X6_UNORM
@@ -338,10 +344,13 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
338 6, // ASTC_2D_6X6_UNORM 344 6, // ASTC_2D_6X6_UNORM
339 6, // ASTC_2D_6X6_SRGB 345 6, // ASTC_2D_6X6_SRGB
340 6, // ASTC_2D_10X6_UNORM 346 6, // ASTC_2D_10X6_UNORM
347 6, // ASTC_2D_10X6_SRGB
341 5, // ASTC_2D_10X5_UNORM 348 5, // ASTC_2D_10X5_UNORM
342 5, // ASTC_2D_10X5_SRGB 349 5, // ASTC_2D_10X5_SRGB
343 10, // ASTC_2D_10X10_UNORM 350 10, // ASTC_2D_10X10_UNORM
344 10, // ASTC_2D_10X10_SRGB 351 10, // ASTC_2D_10X10_SRGB
352 10, // ASTC_2D_12X10_UNORM
353 10, // ASTC_2D_12X10_SRGB
345 12, // ASTC_2D_12X12_UNORM 354 12, // ASTC_2D_12X12_UNORM
346 12, // ASTC_2D_12X12_SRGB 355 12, // ASTC_2D_12X12_SRGB
347 6, // ASTC_2D_8X6_UNORM 356 6, // ASTC_2D_8X6_UNORM
@@ -444,10 +453,13 @@ constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
444 128, // ASTC_2D_6X6_UNORM 453 128, // ASTC_2D_6X6_UNORM
445 128, // ASTC_2D_6X6_SRGB 454 128, // ASTC_2D_6X6_SRGB
446 128, // ASTC_2D_10X6_UNORM 455 128, // ASTC_2D_10X6_UNORM
456 128, // ASTC_2D_10X6_SRGB
447 128, // ASTC_2D_10X5_UNORM 457 128, // ASTC_2D_10X5_UNORM
448 128, // ASTC_2D_10X5_SRGB 458 128, // ASTC_2D_10X5_SRGB
449 128, // ASTC_2D_10X10_UNORM 459 128, // ASTC_2D_10X10_UNORM
450 128, // ASTC_2D_10X10_SRGB 460 128, // ASTC_2D_10X10_SRGB
461 128, // ASTC_2D_12X10_UNORM
462 128, // ASTC_2D_12X10_SRGB
451 128, // ASTC_2D_12X12_UNORM 463 128, // ASTC_2D_12X12_UNORM
452 128, // ASTC_2D_12X12_SRGB 464 128, // ASTC_2D_12X12_SRGB
453 128, // ASTC_2D_8X6_UNORM 465 128, // ASTC_2D_8X6_UNORM
diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp
index 5fc2b2fec..11ced6c38 100644
--- a/src/video_core/texture_cache/format_lookup_table.cpp
+++ b/src/video_core/texture_cache/format_lookup_table.cpp
@@ -210,6 +210,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
210 return PixelFormat::ASTC_2D_6X6_SRGB; 210 return PixelFormat::ASTC_2D_6X6_SRGB;
211 case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR): 211 case Hash(TextureFormat::ASTC_2D_10X6, UNORM, LINEAR):
212 return PixelFormat::ASTC_2D_10X6_UNORM; 212 return PixelFormat::ASTC_2D_10X6_UNORM;
213 case Hash(TextureFormat::ASTC_2D_10X6, UNORM, SRGB):
214 return PixelFormat::ASTC_2D_10X6_SRGB;
213 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, LINEAR): 215 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, LINEAR):
214 return PixelFormat::ASTC_2D_10X5_UNORM; 216 return PixelFormat::ASTC_2D_10X5_UNORM;
215 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, SRGB): 217 case Hash(TextureFormat::ASTC_2D_10X5, UNORM, SRGB):
@@ -218,6 +220,10 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
218 return PixelFormat::ASTC_2D_10X10_UNORM; 220 return PixelFormat::ASTC_2D_10X10_UNORM;
219 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB): 221 case Hash(TextureFormat::ASTC_2D_10X10, UNORM, SRGB):
220 return PixelFormat::ASTC_2D_10X10_SRGB; 222 return PixelFormat::ASTC_2D_10X10_SRGB;
223 case Hash(TextureFormat::ASTC_2D_12X10, UNORM, LINEAR):
224 return PixelFormat::ASTC_2D_12X10_UNORM;
225 case Hash(TextureFormat::ASTC_2D_12X10, UNORM, SRGB):
226 return PixelFormat::ASTC_2D_12X10_SRGB;
221 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, LINEAR): 227 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, LINEAR):
222 return PixelFormat::ASTC_2D_12X12_UNORM; 228 return PixelFormat::ASTC_2D_12X12_UNORM;
223 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, SRGB): 229 case Hash(TextureFormat::ASTC_2D_12X12, UNORM, SRGB):
diff --git a/src/video_core/texture_cache/formatter.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 f1f0a057b..9ee57a076 100644
--- a/src/video_core/texture_cache/formatter.h
+++ b/src/video_core/texture_cache/formatter.h
@@ -179,6 +179,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
179 return "ASTC_2D_6X6_SRGB"; 179 return "ASTC_2D_6X6_SRGB";
180 case PixelFormat::ASTC_2D_10X6_UNORM: 180 case PixelFormat::ASTC_2D_10X6_UNORM:
181 return "ASTC_2D_10X6_UNORM"; 181 return "ASTC_2D_10X6_UNORM";
182 case PixelFormat::ASTC_2D_10X6_SRGB:
183 return "ASTC_2D_10X6_SRGB";
182 case PixelFormat::ASTC_2D_10X5_UNORM: 184 case PixelFormat::ASTC_2D_10X5_UNORM:
183 return "ASTC_2D_10X5_UNORM"; 185 return "ASTC_2D_10X5_UNORM";
184 case PixelFormat::ASTC_2D_10X5_SRGB: 186 case PixelFormat::ASTC_2D_10X5_SRGB:
@@ -187,6 +189,10 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
187 return "ASTC_2D_10X10_UNORM"; 189 return "ASTC_2D_10X10_UNORM";
188 case PixelFormat::ASTC_2D_10X10_SRGB: 190 case PixelFormat::ASTC_2D_10X10_SRGB:
189 return "ASTC_2D_10X10_SRGB"; 191 return "ASTC_2D_10X10_SRGB";
192 case PixelFormat::ASTC_2D_12X10_UNORM:
193 return "ASTC_2D_12X10_UNORM";
194 case PixelFormat::ASTC_2D_12X10_SRGB:
195 return "ASTC_2D_12X10_SRGB";
190 case PixelFormat::ASTC_2D_12X12_UNORM: 196 case PixelFormat::ASTC_2D_12X12_UNORM:
191 return "ASTC_2D_12X12_UNORM"; 197 return "ASTC_2D_12X12_UNORM";
192 case PixelFormat::ASTC_2D_12X12_SRGB: 198 case PixelFormat::ASTC_2D_12X12_SRGB:
@@ -268,7 +274,7 @@ struct RenderTargets;
268 274
269[[nodiscard]] std::string Name(const ImageBase& image); 275[[nodiscard]] std::string Name(const ImageBase& image);
270 276
271[[nodiscard]] std::string Name(const ImageViewBase& image_view); 277[[nodiscard]] std::string Name(const ImageViewBase& image_view, GPUVAddr addr);
272 278
273[[nodiscard]] std::string Name(const RenderTargets& render_targets); 279[[nodiscard]] std::string Name(const RenderTargets& render_targets);
274 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 e601f8446..e1198dcf8 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;
@@ -888,7 +921,7 @@ void TextureCache<P>::DownloadImageIntoBuffer(typename TextureCache<P>::Image* i
888 buffer, 921 buffer,
889 download_map.buffer, 922 download_map.buffer,
890 }; 923 };
891 std::array buffer_offsets{ 924 std::array<u64, 2> buffer_offsets{
892 buffer_offset, 925 buffer_offset,
893 download_map.offset, 926 download_map.offset,
894 }; 927 };
@@ -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;
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 6f288b3f8..6ffca2af2 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -617,7 +617,9 @@ bool Device::ShouldBoostClocks() const {
617 617
618 const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F; 618 const bool is_steam_deck = vendor_id == 0x1002 && device_id == 0x163F;
619 619
620 return validated_driver && !is_steam_deck; 620 const bool is_debugging = this->HasDebuggingToolAttached();
621
622 return validated_driver && !is_steam_deck && !is_debugging;
621} 623}
622 624
623bool Device::GetSuitability(bool requires_swapchain) { 625bool Device::GetSuitability(bool requires_swapchain) {
diff --git a/src/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_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp
index fa9bafa20..c34599365 100644
--- a/src/video_core/vulkan_common/vulkan_surface.cpp
+++ b/src/video_core/vulkan_common/vulkan_surface.cpp
@@ -23,10 +23,10 @@
23 23
24namespace Vulkan { 24namespace Vulkan {
25 25
26vk::SurfaceKHR CreateSurface(const vk::Instance& instance, 26vk::SurfaceKHR CreateSurface(
27 const Core::Frontend::EmuWindow& emu_window) { 27 const vk::Instance& instance,
28 [[maybe_unused]] const Core::Frontend::EmuWindow::WindowSystemInfo& window_info) {
28 [[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch(); 29 [[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
29 [[maybe_unused]] const auto& window_info = emu_window.GetWindowInfo();
30 VkSurfaceKHR unsafe_surface = nullptr; 30 VkSurfaceKHR unsafe_surface = nullptr;
31 31
32#ifdef _WIN32 32#ifdef _WIN32
diff --git a/src/video_core/vulkan_common/vulkan_surface.h b/src/video_core/vulkan_common/vulkan_surface.h
index 5725143e6..5e18c06c4 100644
--- a/src/video_core/vulkan_common/vulkan_surface.h
+++ b/src/video_core/vulkan_common/vulkan_surface.h
@@ -3,15 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/frontend/emu_window.h"
6#include "video_core/vulkan_common/vulkan_wrapper.h" 7#include "video_core/vulkan_common/vulkan_wrapper.h"
7 8
8namespace Core::Frontend {
9class EmuWindow;
10}
11
12namespace Vulkan { 9namespace Vulkan {
13 10
14[[nodiscard]] vk::SurfaceKHR CreateSurface(const vk::Instance& instance, 11[[nodiscard]] vk::SurfaceKHR CreateSurface(
15 const Core::Frontend::EmuWindow& emu_window); 12 const vk::Instance& instance, const Core::Frontend::EmuWindow::WindowSystemInfo& window_info);
16 13
17} // namespace Vulkan 14} // namespace Vulkan
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 0f8c1e6a6..2d7b9ab65 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -189,6 +189,8 @@ add_executable(yuzu
189 multiplayer/state.h 189 multiplayer/state.h
190 multiplayer/validation.h 190 multiplayer/validation.h
191 precompiled_headers.h 191 precompiled_headers.h
192 qt_common.cpp
193 qt_common.h
192 startup_checks.cpp 194 startup_checks.cpp
193 startup_checks.h 195 startup_checks.h
194 uisettings.cpp 196 uisettings.cpp
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.cpp b/src/yuzu/bootmanager.cpp
index 4c7bf28d8..59d226113 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -1,36 +1,48 @@
1// SPDX-FileCopyrightText: 2014 Citra Emulator Project 1// SPDX-FileCopyrightText: 2014 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <algorithm>
5#include <array>
6#include <cmath>
7#include <cstring>
8#include <string>
9#include <tuple>
10#include <type_traits>
4#include <glad/glad.h> 11#include <glad/glad.h>
5 12
6#include <QApplication> 13#include <QtCore/qglobal.h>
7#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA 14#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
15#include <QCamera>
8#include <QCameraImageCapture> 16#include <QCameraImageCapture>
9#include <QCameraInfo> 17#include <QCameraInfo>
10#endif 18#endif
19#include <QCursor>
20#include <QEvent>
21#include <QGuiApplication>
11#include <QHBoxLayout> 22#include <QHBoxLayout>
23#include <QKeyEvent>
24#include <QLayout>
25#include <QList>
12#include <QMessageBox> 26#include <QMessageBox>
13#include <QPainter>
14#include <QScreen> 27#include <QScreen>
15#include <QString> 28#include <QSize>
16#include <QStringList> 29#include <QStringLiteral>
30#include <QSurfaceFormat>
31#include <QTimer>
17#include <QWindow> 32#include <QWindow>
33#include <QtCore/qobjectdefs.h>
18 34
19#ifdef HAS_OPENGL 35#ifdef HAS_OPENGL
20#include <QOffscreenSurface> 36#include <QOffscreenSurface>
21#include <QOpenGLContext> 37#include <QOpenGLContext>
22#endif 38#endif
23 39
24#if !defined(WIN32)
25#include <qpa/qplatformnativeinterface.h>
26#endif
27
28#include <fmt/format.h>
29
30#include "common/assert.h"
31#include "common/microprofile.h" 40#include "common/microprofile.h"
41#include "common/polyfill_thread.h"
32#include "common/scm_rev.h" 42#include "common/scm_rev.h"
33#include "common/settings.h" 43#include "common/settings.h"
44#include "common/settings_input.h"
45#include "common/thread.h"
34#include "core/core.h" 46#include "core/core.h"
35#include "core/cpu_manager.h" 47#include "core/cpu_manager.h"
36#include "core/frontend/framebuffer_layout.h" 48#include "core/frontend/framebuffer_layout.h"
@@ -40,11 +52,16 @@
40#include "input_common/drivers/tas_input.h" 52#include "input_common/drivers/tas_input.h"
41#include "input_common/drivers/touch_screen.h" 53#include "input_common/drivers/touch_screen.h"
42#include "input_common/main.h" 54#include "input_common/main.h"
55#include "video_core/gpu.h"
56#include "video_core/rasterizer_interface.h"
43#include "video_core/renderer_base.h" 57#include "video_core/renderer_base.h"
44#include "yuzu/bootmanager.h" 58#include "yuzu/bootmanager.h"
45#include "yuzu/main.h" 59#include "yuzu/main.h"
60#include "yuzu/qt_common.h"
46 61
47static Core::Frontend::WindowSystemType GetWindowSystemType(); 62class QObject;
63class QPaintEngine;
64class QSurface;
48 65
49EmuThread::EmuThread(Core::System& system) : m_system{system} {} 66EmuThread::EmuThread(Core::System& system) : m_system{system} {}
50 67
@@ -154,7 +171,10 @@ public:
154 171
155 // disable vsync for any shared contexts 172 // disable vsync for any shared contexts
156 auto format = share_context->format(); 173 auto format = share_context->format();
157 format.setSwapInterval(main_surface ? Settings::values.use_vsync.GetValue() : 0); 174 const int swap_interval =
175 Settings::values.vsync_mode.GetValue() == Settings::VSyncMode::Immediate ? 0 : 1;
176
177 format.setSwapInterval(main_surface ? swap_interval : 0);
158 178
159 context = std::make_unique<QOpenGLContext>(); 179 context = std::make_unique<QOpenGLContext>();
160 context->setShareContext(share_context); 180 context->setShareContext(share_context);
@@ -221,7 +241,7 @@ public:
221 explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { 241 explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
222 setAttribute(Qt::WA_NativeWindow); 242 setAttribute(Qt::WA_NativeWindow);
223 setAttribute(Qt::WA_PaintOnScreen); 243 setAttribute(Qt::WA_PaintOnScreen);
224 if (GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { 244 if (QtCommon::GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) {
225 setAttribute(Qt::WA_DontCreateNativeAncestors); 245 setAttribute(Qt::WA_DontCreateNativeAncestors);
226 } 246 }
227 } 247 }
@@ -259,46 +279,6 @@ struct NullRenderWidget : public RenderWidget {
259 explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {} 279 explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {}
260}; 280};
261 281
262static Core::Frontend::WindowSystemType GetWindowSystemType() {
263 // Determine WSI type based on Qt platform.
264 QString platform_name = QGuiApplication::platformName();
265 if (platform_name == QStringLiteral("windows"))
266 return Core::Frontend::WindowSystemType::Windows;
267 else if (platform_name == QStringLiteral("xcb"))
268 return Core::Frontend::WindowSystemType::X11;
269 else if (platform_name == QStringLiteral("wayland"))
270 return Core::Frontend::WindowSystemType::Wayland;
271 else if (platform_name == QStringLiteral("wayland-egl"))
272 return Core::Frontend::WindowSystemType::Wayland;
273 else if (platform_name == QStringLiteral("cocoa"))
274 return Core::Frontend::WindowSystemType::Cocoa;
275 else if (platform_name == QStringLiteral("android"))
276 return Core::Frontend::WindowSystemType::Android;
277
278 LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString());
279 return Core::Frontend::WindowSystemType::Windows;
280}
281
282static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
283 Core::Frontend::EmuWindow::WindowSystemInfo wsi;
284 wsi.type = GetWindowSystemType();
285
286 // Our Win32 Qt external doesn't have the private API.
287#if defined(WIN32) || defined(__APPLE__)
288 wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
289#else
290 QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
291 wsi.display_connection = pni->nativeResourceForWindow("display", window);
292 if (wsi.type == Core::Frontend::WindowSystemType::Wayland)
293 wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
294 else
295 wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
296#endif
297 wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f;
298
299 return wsi;
300}
301
302GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, 282GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
303 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_, 283 std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
304 Core::System& system_) 284 Core::System& system_)
@@ -904,7 +884,7 @@ bool GRenderWindow::InitRenderTarget() {
904 } 884 }
905 885
906 // Update the Window System information with the new render target 886 // Update the Window System information with the new render target
907 window_info = GetWindowSystemInfo(child_widget->windowHandle()); 887 window_info = QtCommon::GetWindowSystemInfo(child_widget->windowHandle());
908 888
909 child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); 889 child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height);
910 layout()->addWidget(child_widget); 890 layout()->addWidget(child_widget);
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index bb4eca07f..b7b9d4141 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -5,27 +5,45 @@
5 5
6#include <atomic> 6#include <atomic>
7#include <condition_variable> 7#include <condition_variable>
8#include <cstddef>
8#include <memory> 9#include <memory>
9#include <mutex> 10#include <mutex>
11#include <utility>
12#include <vector>
10 13
14#include <QByteArray>
11#include <QImage> 15#include <QImage>
16#include <QObject>
17#include <QPoint>
18#include <QString>
12#include <QStringList> 19#include <QStringList>
13#include <QThread> 20#include <QThread>
14#include <QTouchEvent>
15#include <QWidget> 21#include <QWidget>
22#include <qglobal.h>
23#include <qnamespace.h>
24#include <qobjectdefs.h>
16 25
26#include "common/common_types.h"
27#include "common/logging/log.h"
17#include "common/polyfill_thread.h" 28#include "common/polyfill_thread.h"
18#include "common/thread.h" 29#include "common/thread.h"
19#include "core/frontend/emu_window.h" 30#include "core/frontend/emu_window.h"
20 31
21class GRenderWindow;
22class GMainWindow; 32class GMainWindow;
23class QCamera; 33class QCamera;
24class QCameraImageCapture; 34class QCameraImageCapture;
35class QCloseEvent;
36class QFocusEvent;
25class QKeyEvent; 37class QKeyEvent;
38class QMouseEvent;
39class QObject;
40class QResizeEvent;
41class QShowEvent;
42class QTimer;
43class QTouchEvent;
44class QWheelEvent;
26 45
27namespace Core { 46namespace Core {
28enum class SystemResultStatus : u32;
29class System; 47class System;
30} // namespace Core 48} // namespace Core
31 49
@@ -40,7 +58,6 @@ enum class TasState;
40 58
41namespace VideoCore { 59namespace VideoCore {
42enum class LoadCallbackStage; 60enum class LoadCallbackStage;
43class RendererBase;
44} // namespace VideoCore 61} // namespace VideoCore
45 62
46class EmuThread final : public QThread { 63class EmuThread final : public QThread {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index bb731276e..a49d12266 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -6,6 +6,7 @@
6#include <QSettings> 6#include <QSettings>
7#include "common/fs/fs.h" 7#include "common/fs/fs.h"
8#include "common/fs/path_util.h" 8#include "common/fs/path_util.h"
9#include "common/settings.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/hle/service/acc/profile_manager.h" 11#include "core/hle/service/acc/profile_manager.h"
11#include "core/hle/service/hid/controllers/npad.h" 12#include "core/hle/service/hid/controllers/npad.h"
@@ -497,7 +498,7 @@ void Config::ReadCoreValues() {
497 qt_config->beginGroup(QStringLiteral("Core")); 498 qt_config->beginGroup(QStringLiteral("Core"));
498 499
499 ReadGlobalSetting(Settings::values.use_multi_core); 500 ReadGlobalSetting(Settings::values.use_multi_core);
500 ReadGlobalSetting(Settings::values.use_extended_memory_layout); 501 ReadGlobalSetting(Settings::values.use_unsafe_extended_memory_layout);
501 502
502 qt_config->endGroup(); 503 qt_config->endGroup();
503} 504}
@@ -692,6 +693,7 @@ void Config::ReadRendererValues() {
692 qt_config->beginGroup(QStringLiteral("Renderer")); 693 qt_config->beginGroup(QStringLiteral("Renderer"));
693 694
694 ReadGlobalSetting(Settings::values.renderer_backend); 695 ReadGlobalSetting(Settings::values.renderer_backend);
696 ReadGlobalSetting(Settings::values.async_presentation);
695 ReadGlobalSetting(Settings::values.renderer_force_max_clock); 697 ReadGlobalSetting(Settings::values.renderer_force_max_clock);
696 ReadGlobalSetting(Settings::values.vulkan_device); 698 ReadGlobalSetting(Settings::values.vulkan_device);
697 ReadGlobalSetting(Settings::values.fullscreen_mode); 699 ReadGlobalSetting(Settings::values.fullscreen_mode);
@@ -708,17 +710,20 @@ void Config::ReadRendererValues() {
708 ReadGlobalSetting(Settings::values.nvdec_emulation); 710 ReadGlobalSetting(Settings::values.nvdec_emulation);
709 ReadGlobalSetting(Settings::values.accelerate_astc); 711 ReadGlobalSetting(Settings::values.accelerate_astc);
710 ReadGlobalSetting(Settings::values.async_astc); 712 ReadGlobalSetting(Settings::values.async_astc);
711 ReadGlobalSetting(Settings::values.use_vsync); 713 ReadGlobalSetting(Settings::values.use_reactive_flushing);
712 ReadGlobalSetting(Settings::values.shader_backend); 714 ReadGlobalSetting(Settings::values.shader_backend);
713 ReadGlobalSetting(Settings::values.use_asynchronous_shaders); 715 ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
714 ReadGlobalSetting(Settings::values.use_fast_gpu_time); 716 ReadGlobalSetting(Settings::values.use_fast_gpu_time);
715 ReadGlobalSetting(Settings::values.use_pessimistic_flushes);
716 ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); 717 ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
717 ReadGlobalSetting(Settings::values.bg_red); 718 ReadGlobalSetting(Settings::values.bg_red);
718 ReadGlobalSetting(Settings::values.bg_green); 719 ReadGlobalSetting(Settings::values.bg_green);
719 ReadGlobalSetting(Settings::values.bg_blue); 720 ReadGlobalSetting(Settings::values.bg_blue);
720 721
721 if (global) { 722 if (global) {
723 Settings::values.vsync_mode.SetValue(static_cast<Settings::VSyncMode>(
724 ReadSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()),
725 static_cast<u32>(Settings::values.vsync_mode.GetDefault()))
726 .value<u32>()));
722 ReadBasicSetting(Settings::values.renderer_debug); 727 ReadBasicSetting(Settings::values.renderer_debug);
723 ReadBasicSetting(Settings::values.renderer_shader_feedback); 728 ReadBasicSetting(Settings::values.renderer_shader_feedback);
724 ReadBasicSetting(Settings::values.enable_nsight_aftermath); 729 ReadBasicSetting(Settings::values.enable_nsight_aftermath);
@@ -1161,7 +1166,7 @@ void Config::SaveCoreValues() {
1161 qt_config->beginGroup(QStringLiteral("Core")); 1166 qt_config->beginGroup(QStringLiteral("Core"));
1162 1167
1163 WriteGlobalSetting(Settings::values.use_multi_core); 1168 WriteGlobalSetting(Settings::values.use_multi_core);
1164 WriteGlobalSetting(Settings::values.use_extended_memory_layout); 1169 WriteGlobalSetting(Settings::values.use_unsafe_extended_memory_layout);
1165 1170
1166 qt_config->endGroup(); 1171 qt_config->endGroup();
1167} 1172}
@@ -1313,6 +1318,7 @@ void Config::SaveRendererValues() {
1313 static_cast<u32>(Settings::values.renderer_backend.GetValue(global)), 1318 static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
1314 static_cast<u32>(Settings::values.renderer_backend.GetDefault()), 1319 static_cast<u32>(Settings::values.renderer_backend.GetDefault()),
1315 Settings::values.renderer_backend.UsingGlobal()); 1320 Settings::values.renderer_backend.UsingGlobal());
1321 WriteGlobalSetting(Settings::values.async_presentation);
1316 WriteGlobalSetting(Settings::values.renderer_force_max_clock); 1322 WriteGlobalSetting(Settings::values.renderer_force_max_clock);
1317 WriteGlobalSetting(Settings::values.vulkan_device); 1323 WriteGlobalSetting(Settings::values.vulkan_device);
1318 WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()), 1324 WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()),
@@ -1350,20 +1356,22 @@ void Config::SaveRendererValues() {
1350 Settings::values.nvdec_emulation.UsingGlobal()); 1356 Settings::values.nvdec_emulation.UsingGlobal());
1351 WriteGlobalSetting(Settings::values.accelerate_astc); 1357 WriteGlobalSetting(Settings::values.accelerate_astc);
1352 WriteGlobalSetting(Settings::values.async_astc); 1358 WriteGlobalSetting(Settings::values.async_astc);
1353 WriteGlobalSetting(Settings::values.use_vsync); 1359 WriteGlobalSetting(Settings::values.use_reactive_flushing);
1354 WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), 1360 WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()),
1355 static_cast<u32>(Settings::values.shader_backend.GetValue(global)), 1361 static_cast<u32>(Settings::values.shader_backend.GetValue(global)),
1356 static_cast<u32>(Settings::values.shader_backend.GetDefault()), 1362 static_cast<u32>(Settings::values.shader_backend.GetDefault()),
1357 Settings::values.shader_backend.UsingGlobal()); 1363 Settings::values.shader_backend.UsingGlobal());
1358 WriteGlobalSetting(Settings::values.use_asynchronous_shaders); 1364 WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
1359 WriteGlobalSetting(Settings::values.use_fast_gpu_time); 1365 WriteGlobalSetting(Settings::values.use_fast_gpu_time);
1360 WriteGlobalSetting(Settings::values.use_pessimistic_flushes);
1361 WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); 1366 WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
1362 WriteGlobalSetting(Settings::values.bg_red); 1367 WriteGlobalSetting(Settings::values.bg_red);
1363 WriteGlobalSetting(Settings::values.bg_green); 1368 WriteGlobalSetting(Settings::values.bg_green);
1364 WriteGlobalSetting(Settings::values.bg_blue); 1369 WriteGlobalSetting(Settings::values.bg_blue);
1365 1370
1366 if (global) { 1371 if (global) {
1372 WriteSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()),
1373 static_cast<u32>(Settings::values.vsync_mode.GetValue()),
1374 static_cast<u32>(Settings::values.vsync_mode.GetDefault()));
1367 WriteBasicSetting(Settings::values.renderer_debug); 1375 WriteBasicSetting(Settings::values.renderer_debug);
1368 WriteBasicSetting(Settings::values.renderer_shader_feedback); 1376 WriteBasicSetting(Settings::values.renderer_shader_feedback);
1369 WriteBasicSetting(Settings::values.enable_nsight_aftermath); 1377 WriteBasicSetting(Settings::values.enable_nsight_aftermath);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 207bcdc4d..26258d744 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -35,9 +35,6 @@ void ConfigureGeneral::SetConfiguration() {
35 35
36 ui->use_multi_core->setEnabled(runtime_lock); 36 ui->use_multi_core->setEnabled(runtime_lock);
37 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue()); 37 ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
38 ui->use_extended_memory_layout->setEnabled(runtime_lock);
39 ui->use_extended_memory_layout->setChecked(
40 Settings::values.use_extended_memory_layout.GetValue());
41 38
42 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue()); 39 ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
43 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue()); 40 ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
@@ -79,9 +76,6 @@ void ConfigureGeneral::ResetDefaults() {
79void ConfigureGeneral::ApplyConfiguration() { 76void ConfigureGeneral::ApplyConfiguration() {
80 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core, 77 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
81 use_multi_core); 78 use_multi_core);
82 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_extended_memory_layout,
83 ui->use_extended_memory_layout,
84 use_extended_memory_layout);
85 79
86 if (Settings::IsConfiguringGlobal()) { 80 if (Settings::IsConfiguringGlobal()) {
87 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 81 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
@@ -141,9 +135,6 @@ void ConfigureGeneral::SetupPerGameUI() {
141 Settings::values.use_speed_limit, use_speed_limit); 135 Settings::values.use_speed_limit, use_speed_limit);
142 ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, 136 ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
143 use_multi_core); 137 use_multi_core);
144 ConfigurationShared::SetColoredTristate(ui->use_extended_memory_layout,
145 Settings::values.use_extended_memory_layout,
146 use_extended_memory_layout);
147 138
148 connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { 139 connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() {
149 ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && 140 ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index a090c1a3f..7ff63f425 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -47,7 +47,6 @@ private:
47 47
48 ConfigurationShared::CheckState use_speed_limit; 48 ConfigurationShared::CheckState use_speed_limit;
49 ConfigurationShared::CheckState use_multi_core; 49 ConfigurationShared::CheckState use_multi_core;
50 ConfigurationShared::CheckState use_extended_memory_layout;
51 50
52 const Core::System& system; 51 const Core::System& system;
53}; 52};
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index add110bb0..986a1625b 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -62,13 +62,6 @@
62 </widget> 62 </widget>
63 </item> 63 </item>
64 <item> 64 <item>
65 <widget class="QCheckBox" name="use_extended_memory_layout">
66 <property name="text">
67 <string>Extended memory layout (8GB DRAM)</string>
68 </property>
69 </widget>
70 </item>
71 <item>
72 <widget class="QCheckBox" name="toggle_check_exit"> 65 <widget class="QCheckBox" name="toggle_check_exit">
73 <property name="text"> 66 <property name="text">
74 <string>Confirm exit while emulation is running</string> 67 <string>Confirm exit while emulation is running</string>
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index e9388daad..76e5b7499 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -4,20 +4,76 @@
4// Include this early to include Vulkan headers how we want to 4// Include this early to include Vulkan headers how we want to
5#include "video_core/vulkan_common/vulkan_wrapper.h" 5#include "video_core/vulkan_common/vulkan_wrapper.h"
6 6
7#include <algorithm>
8#include <iosfwd>
9#include <iterator>
10#include <string>
11#include <tuple>
12#include <utility>
13#include <vector>
14#include <QBoxLayout>
15#include <QCheckBox>
7#include <QColorDialog> 16#include <QColorDialog>
8#include <QVulkanInstance> 17#include <QComboBox>
18#include <QIcon>
19#include <QLabel>
20#include <QPixmap>
21#include <QPushButton>
22#include <QSlider>
23#include <QStringLiteral>
24#include <QtCore/qobjectdefs.h>
25#include <qcoreevent.h>
26#include <qglobal.h>
27#include <vulkan/vulkan_core.h>
9 28
10#include "common/common_types.h" 29#include "common/common_types.h"
30#include "common/dynamic_library.h"
11#include "common/logging/log.h" 31#include "common/logging/log.h"
12#include "common/settings.h" 32#include "common/settings.h"
13#include "core/core.h" 33#include "core/core.h"
14#include "ui_configure_graphics.h" 34#include "ui_configure_graphics.h"
15#include "video_core/vulkan_common/vulkan_instance.h" 35#include "video_core/vulkan_common/vulkan_instance.h"
16#include "video_core/vulkan_common/vulkan_library.h" 36#include "video_core/vulkan_common/vulkan_library.h"
37#include "video_core/vulkan_common/vulkan_surface.h"
17#include "yuzu/configuration/configuration_shared.h" 38#include "yuzu/configuration/configuration_shared.h"
18#include "yuzu/configuration/configure_graphics.h" 39#include "yuzu/configuration/configure_graphics.h"
40#include "yuzu/qt_common.h"
19#include "yuzu/uisettings.h" 41#include "yuzu/uisettings.h"
20 42
43static const std::vector<VkPresentModeKHR> default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR,
44 VK_PRESENT_MODE_FIFO_KHR};
45
46// Converts a setting to a present mode (or vice versa)
47static constexpr VkPresentModeKHR VSyncSettingToMode(Settings::VSyncMode mode) {
48 switch (mode) {
49 case Settings::VSyncMode::Immediate:
50 return VK_PRESENT_MODE_IMMEDIATE_KHR;
51 case Settings::VSyncMode::Mailbox:
52 return VK_PRESENT_MODE_MAILBOX_KHR;
53 case Settings::VSyncMode::FIFO:
54 return VK_PRESENT_MODE_FIFO_KHR;
55 case Settings::VSyncMode::FIFORelaxed:
56 return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
57 default:
58 return VK_PRESENT_MODE_FIFO_KHR;
59 }
60}
61
62static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode) {
63 switch (mode) {
64 case VK_PRESENT_MODE_IMMEDIATE_KHR:
65 return Settings::VSyncMode::Immediate;
66 case VK_PRESENT_MODE_MAILBOX_KHR:
67 return Settings::VSyncMode::Mailbox;
68 case VK_PRESENT_MODE_FIFO_KHR:
69 return Settings::VSyncMode::FIFO;
70 case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
71 return Settings::VSyncMode::FIFORelaxed;
72 default:
73 return Settings::VSyncMode::FIFO;
74 }
75}
76
21ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) 77ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent)
22 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { 78 : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} {
23 vulkan_device = Settings::values.vulkan_device.GetValue(); 79 vulkan_device = Settings::values.vulkan_device.GetValue();
@@ -39,13 +95,16 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren
39 95
40 connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { 96 connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
41 UpdateAPILayout(); 97 UpdateAPILayout();
98 PopulateVSyncModeSelection();
42 if (!Settings::IsConfiguringGlobal()) { 99 if (!Settings::IsConfiguringGlobal()) {
43 ConfigurationShared::SetHighlight( 100 ConfigurationShared::SetHighlight(
44 ui->api_widget, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX); 101 ui->api_widget, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX);
45 } 102 }
46 }); 103 });
47 connect(ui->device, qOverload<int>(&QComboBox::activated), this, 104 connect(ui->device, qOverload<int>(&QComboBox::activated), this, [this](int device) {
48 [this](int device) { UpdateDeviceSelection(device); }); 105 UpdateDeviceSelection(device);
106 PopulateVSyncModeSelection();
107 });
49 connect(ui->backend, qOverload<int>(&QComboBox::activated), this, 108 connect(ui->backend, qOverload<int>(&QComboBox::activated), this,
50 [this](int backend) { UpdateShaderBackendSelection(backend); }); 109 [this](int backend) { UpdateShaderBackendSelection(backend); });
51 110
@@ -70,6 +129,43 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren
70 ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal()); 129 ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal());
71} 130}
72 131
132void ConfigureGraphics::PopulateVSyncModeSelection() {
133 const Settings::RendererBackend backend{GetCurrentGraphicsBackend()};
134 if (backend == Settings::RendererBackend::Null) {
135 ui->vsync_mode_combobox->setEnabled(false);
136 return;
137 }
138 ui->vsync_mode_combobox->setEnabled(true);
139
140 const int current_index = //< current selected vsync mode from combobox
141 ui->vsync_mode_combobox->currentIndex();
142 const auto current_mode = //< current selected vsync mode as a VkPresentModeKHR
143 current_index == -1 ? VSyncSettingToMode(Settings::values.vsync_mode.GetValue())
144 : vsync_mode_combobox_enum_map[current_index];
145 int index{};
146 const int device{ui->device->currentIndex()}; //< current selected Vulkan device
147 const auto& present_modes = //< relevant vector of present modes for the selected device or API
148 backend == Settings::RendererBackend::Vulkan ? device_present_modes[device]
149 : default_present_modes;
150
151 ui->vsync_mode_combobox->clear();
152 vsync_mode_combobox_enum_map.clear();
153 vsync_mode_combobox_enum_map.reserve(present_modes.size());
154 for (const auto present_mode : present_modes) {
155 const auto mode_name = TranslateVSyncMode(present_mode, backend);
156 if (mode_name.isEmpty()) {
157 continue;
158 }
159
160 ui->vsync_mode_combobox->insertItem(index, mode_name);
161 vsync_mode_combobox_enum_map.push_back(present_mode);
162 if (present_mode == current_mode) {
163 ui->vsync_mode_combobox->setCurrentIndex(index);
164 }
165 index++;
166 }
167}
168
73void ConfigureGraphics::UpdateDeviceSelection(int device) { 169void ConfigureGraphics::UpdateDeviceSelection(int device) {
74 if (device == -1) { 170 if (device == -1) {
75 return; 171 return;
@@ -99,6 +195,9 @@ void ConfigureGraphics::SetConfiguration() {
99 ui->nvdec_emulation_widget->setEnabled(runtime_lock); 195 ui->nvdec_emulation_widget->setEnabled(runtime_lock);
100 ui->resolution_combobox->setEnabled(runtime_lock); 196 ui->resolution_combobox->setEnabled(runtime_lock);
101 ui->accelerate_astc->setEnabled(runtime_lock); 197 ui->accelerate_astc->setEnabled(runtime_lock);
198 ui->vsync_mode_layout->setEnabled(runtime_lock ||
199 Settings::values.renderer_backend.GetValue() ==
200 Settings::RendererBackend::Vulkan);
102 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); 201 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
103 ui->use_asynchronous_gpu_emulation->setChecked( 202 ui->use_asynchronous_gpu_emulation->setChecked(
104 Settings::values.use_asynchronous_gpu_emulation.GetValue()); 203 Settings::values.use_asynchronous_gpu_emulation.GetValue());
@@ -170,7 +269,24 @@ void ConfigureGraphics::SetConfiguration() {
170 Settings::values.bg_green.GetValue(), 269 Settings::values.bg_green.GetValue(),
171 Settings::values.bg_blue.GetValue())); 270 Settings::values.bg_blue.GetValue()));
172 UpdateAPILayout(); 271 UpdateAPILayout();
272 PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout
173 SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition()); 273 SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition());
274
275 // VSync setting needs to be determined after populating the VSync combobox
276 if (Settings::IsConfiguringGlobal()) {
277 const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue();
278 const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting);
279 int index{};
280 for (const auto mode : vsync_mode_combobox_enum_map) {
281 if (mode == vsync_mode) {
282 break;
283 }
284 index++;
285 }
286 if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) {
287 ui->vsync_mode_combobox->setCurrentIndex(index);
288 }
289 }
174} 290}
175 291
176void ConfigureGraphics::SetFSRIndicatorText(int percentage) { 292void ConfigureGraphics::SetFSRIndicatorText(int percentage) {
@@ -178,6 +294,27 @@ void ConfigureGraphics::SetFSRIndicatorText(int percentage) {
178 tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2))); 294 tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2)));
179} 295}
180 296
297const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode,
298 Settings::RendererBackend backend) const {
299 switch (mode) {
300 case VK_PRESENT_MODE_IMMEDIATE_KHR:
301 return backend == Settings::RendererBackend::OpenGL
302 ? tr("Off")
303 : QStringLiteral("Immediate (%1)").arg(tr("VSync Off"));
304 case VK_PRESENT_MODE_MAILBOX_KHR:
305 return QStringLiteral("Mailbox (%1)").arg(tr("Recommended"));
306 case VK_PRESENT_MODE_FIFO_KHR:
307 return backend == Settings::RendererBackend::OpenGL
308 ? tr("On")
309 : QStringLiteral("FIFO (%1)").arg(tr("VSync On"));
310 case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
311 return QStringLiteral("FIFO Relaxed");
312 default:
313 return {};
314 break;
315 }
316}
317
181void ConfigureGraphics::ApplyConfiguration() { 318void ConfigureGraphics::ApplyConfiguration() {
182 const auto resolution_setup = static_cast<Settings::ResolutionSetup>( 319 const auto resolution_setup = static_cast<Settings::ResolutionSetup>(
183 ui->resolution_combobox->currentIndex() - 320 ui->resolution_combobox->currentIndex() -
@@ -232,6 +369,10 @@ void ConfigureGraphics::ApplyConfiguration() {
232 Settings::values.anti_aliasing.SetValue(anti_aliasing); 369 Settings::values.anti_aliasing.SetValue(anti_aliasing);
233 } 370 }
234 Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value()); 371 Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
372
373 const auto mode = vsync_mode_combobox_enum_map[ui->vsync_mode_combobox->currentIndex()];
374 const auto vsync_mode = PresentModeToSetting(mode);
375 Settings::values.vsync_mode.SetValue(vsync_mode);
235 } else { 376 } else {
236 if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 377 if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
237 Settings::values.resolution_setup.SetGlobal(true); 378 Settings::values.resolution_setup.SetGlobal(true);
@@ -345,7 +486,9 @@ void ConfigureGraphics::UpdateAPILayout() {
345 ui->backend_widget->setVisible(true); 486 ui->backend_widget->setVisible(true);
346 break; 487 break;
347 case Settings::RendererBackend::Vulkan: 488 case Settings::RendererBackend::Vulkan:
348 ui->device->setCurrentIndex(vulkan_device); 489 if (static_cast<int>(vulkan_device) < ui->device->count()) {
490 ui->device->setCurrentIndex(vulkan_device);
491 }
349 ui->device_widget->setVisible(true); 492 ui->device_widget->setVisible(true);
350 ui->backend_widget->setVisible(false); 493 ui->backend_widget->setVisible(false);
351 break; 494 break;
@@ -363,16 +506,27 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
363 506
364 using namespace Vulkan; 507 using namespace Vulkan;
365 508
509 auto* window = this->window()->windowHandle();
510 auto wsi = QtCommon::GetWindowSystemInfo(window);
511
366 vk::InstanceDispatch dld; 512 vk::InstanceDispatch dld;
367 const Common::DynamicLibrary library = OpenLibrary(); 513 const Common::DynamicLibrary library = OpenLibrary();
368 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1); 514 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1, wsi.type);
369 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); 515 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
516 vk::SurfaceKHR surface = //< needed to view present modes for a device
517 CreateSurface(instance, wsi);
370 518
371 vulkan_devices.clear(); 519 vulkan_devices.clear();
372 vulkan_devices.reserve(physical_devices.size()); 520 vulkan_devices.reserve(physical_devices.size());
521 device_present_modes.clear();
522 device_present_modes.reserve(physical_devices.size());
373 for (const VkPhysicalDevice device : physical_devices) { 523 for (const VkPhysicalDevice device : physical_devices) {
374 const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName; 524 const auto physical_device = vk::PhysicalDevice(device, dld);
525 const std::string name = physical_device.GetProperties().deviceName;
526 const std::vector<VkPresentModeKHR> present_modes =
527 physical_device.GetSurfacePresentModesKHR(*surface);
375 vulkan_devices.push_back(QString::fromStdString(name)); 528 vulkan_devices.push_back(QString::fromStdString(name));
529 device_present_modes.push_back(present_modes);
376 } 530 }
377} catch (const Vulkan::vk::Exception& exception) { 531} catch (const Vulkan::vk::Exception& exception) {
378 LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); 532 LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
@@ -465,4 +619,6 @@ void ConfigureGraphics::SetupPerGameUI() {
465 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); 619 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
466 ConfigurationShared::InsertGlobalItem( 620 ConfigurationShared::InsertGlobalItem(
467 ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true))); 621 ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true)));
622
623 ui->vsync_mode_layout->setVisible(false);
468} 624}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index d98d6624e..901f604a5 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -5,9 +5,21 @@
5 5
6#include <memory> 6#include <memory>
7#include <vector> 7#include <vector>
8#include <QColor>
8#include <QString> 9#include <QString>
9#include <QWidget> 10#include <QWidget>
10#include "common/settings.h" 11#include <qobjectdefs.h>
12#include <vulkan/vulkan_core.h>
13#include "common/common_types.h"
14
15class QEvent;
16class QObject;
17
18namespace Settings {
19enum class NvdecEmulation : u32;
20enum class RendererBackend : u32;
21enum class ShaderBackend : u32;
22} // namespace Settings
11 23
12namespace Core { 24namespace Core {
13class System; 25class System;
@@ -35,6 +47,7 @@ private:
35 void changeEvent(QEvent* event) override; 47 void changeEvent(QEvent* event) override;
36 void RetranslateUI(); 48 void RetranslateUI();
37 49
50 void PopulateVSyncModeSelection();
38 void UpdateBackgroundColorButton(QColor color); 51 void UpdateBackgroundColorButton(QColor color);
39 void UpdateAPILayout(); 52 void UpdateAPILayout();
40 void UpdateDeviceSelection(int device); 53 void UpdateDeviceSelection(int device);
@@ -43,6 +56,10 @@ private:
43 void RetrieveVulkanDevices(); 56 void RetrieveVulkanDevices();
44 57
45 void SetFSRIndicatorText(int percentage); 58 void SetFSRIndicatorText(int percentage);
59 /* Turns a Vulkan present mode into a textual string for a UI
60 * (and eventually for a human to read) */
61 const QString TranslateVSyncMode(VkPresentModeKHR mode,
62 Settings::RendererBackend backend) const;
46 63
47 void SetupPerGameUI(); 64 void SetupPerGameUI();
48 65
@@ -58,6 +75,10 @@ private:
58 ConfigurationShared::CheckState use_asynchronous_gpu_emulation; 75 ConfigurationShared::CheckState use_asynchronous_gpu_emulation;
59 76
60 std::vector<QString> vulkan_devices; 77 std::vector<QString> vulkan_devices;
78 std::vector<std::vector<VkPresentModeKHR>> device_present_modes;
79 std::vector<VkPresentModeKHR>
80 vsync_mode_combobox_enum_map; //< Keeps track of which present mode corresponds to which
81 // selection in the combobox
61 u32 vulkan_device{}; 82 u32 vulkan_device{};
62 Settings::ShaderBackend shader_backend{}; 83 Settings::ShaderBackend shader_backend{};
63 84
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index a45ec69ec..39f70e406 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -189,6 +189,44 @@
189 </widget> 189 </widget>
190 </item> 190 </item>
191 <item> 191 <item>
192 <widget class="QWidget" name="vsync_mode_layout" native="true">
193 <layout class="QHBoxLayout" name="horizontalLayout_4">
194 <property name="leftMargin">
195 <number>0</number>
196 </property>
197 <property name="topMargin">
198 <number>0</number>
199 </property>
200 <property name="rightMargin">
201 <number>0</number>
202 </property>
203 <property name="bottomMargin">
204 <number>0</number>
205 </property>
206 <item>
207 <widget class="QLabel" name="vsync_mode_label">
208 <property name="text">
209 <string>VSync Mode:</string>
210 </property>
211 </widget>
212 </item>
213 <item>
214 <widget class="QComboBox" name="vsync_mode_combobox">
215 <property name="toolTip">
216 <string>FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate.
217FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down.
218Mailbox can have lower latency than FIFO and does not tear but may drop frames.
219Immediate (no synchronization) just presents whatever is available and can exhibit tearing.</string>
220 </property>
221 <property name="currentText">
222 <string/>
223 </property>
224 </widget>
225 </item>
226 </layout>
227 </widget>
228 </item>
229 <item>
192 <widget class="QWidget" name="nvdec_emulation_widget" native="true"> 230 <widget class="QWidget" name="nvdec_emulation_widget" native="true">
193 <layout class="QHBoxLayout" name="nvdec_emulation_layout"> 231 <layout class="QHBoxLayout" name="nvdec_emulation_layout">
194 <property name="leftMargin"> 232 <property name="leftMargin">
@@ -366,7 +404,7 @@
366 </item> 404 </item>
367 <item> 405 <item>
368 <property name="text"> 406 <property name="text">
369 <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string> 407 <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
370 </property> 408 </property>
371 </item> 409 </item>
372 <item> 410 <item>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 59fb1b334..627ed8b17 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -21,18 +21,19 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
21 21
22void ConfigureGraphicsAdvanced::SetConfiguration() { 22void ConfigureGraphicsAdvanced::SetConfiguration() {
23 const bool runtime_lock = !system.IsPoweredOn(); 23 const bool runtime_lock = !system.IsPoweredOn();
24 ui->use_vsync->setEnabled(runtime_lock); 24 ui->use_reactive_flushing->setEnabled(runtime_lock);
25 ui->async_present->setEnabled(runtime_lock);
25 ui->renderer_force_max_clock->setEnabled(runtime_lock); 26 ui->renderer_force_max_clock->setEnabled(runtime_lock);
26 ui->async_astc->setEnabled(runtime_lock); 27 ui->async_astc->setEnabled(runtime_lock);
27 ui->use_asynchronous_shaders->setEnabled(runtime_lock); 28 ui->use_asynchronous_shaders->setEnabled(runtime_lock);
28 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); 29 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
29 30
31 ui->async_present->setChecked(Settings::values.async_presentation.GetValue());
30 ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); 32 ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue());
31 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); 33 ui->use_reactive_flushing->setChecked(Settings::values.use_reactive_flushing.GetValue());
32 ui->async_astc->setChecked(Settings::values.async_astc.GetValue()); 34 ui->async_astc->setChecked(Settings::values.async_astc.GetValue());
33 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); 35 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
34 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); 36 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
35 ui->use_pessimistic_flushes->setChecked(Settings::values.use_pessimistic_flushes.GetValue());
36 ui->use_vulkan_driver_pipeline_cache->setChecked( 37 ui->use_vulkan_driver_pipeline_cache->setChecked(
37 Settings::values.use_vulkan_driver_pipeline_cache.GetValue()); 38 Settings::values.use_vulkan_driver_pipeline_cache.GetValue());
38 39
@@ -54,12 +55,15 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
54 55
55void ConfigureGraphicsAdvanced::ApplyConfiguration() { 56void ConfigureGraphicsAdvanced::ApplyConfiguration() {
56 ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy); 57 ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy);
58 ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_presentation,
59 ui->async_present, async_present);
57 ConfigurationShared::ApplyPerGameSetting(&Settings::values.renderer_force_max_clock, 60 ConfigurationShared::ApplyPerGameSetting(&Settings::values.renderer_force_max_clock,
58 ui->renderer_force_max_clock, 61 ui->renderer_force_max_clock,
59 renderer_force_max_clock); 62 renderer_force_max_clock);
60 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, 63 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
61 ui->anisotropic_filtering_combobox); 64 ui->anisotropic_filtering_combobox);
62 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); 65 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_reactive_flushing,
66 ui->use_reactive_flushing, use_reactive_flushing);
63 ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc, 67 ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc,
64 async_astc); 68 async_astc);
65 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, 69 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
@@ -67,8 +71,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
67 use_asynchronous_shaders); 71 use_asynchronous_shaders);
68 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, 72 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
69 ui->use_fast_gpu_time, use_fast_gpu_time); 73 ui->use_fast_gpu_time, use_fast_gpu_time);
70 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_pessimistic_flushes,
71 ui->use_pessimistic_flushes, use_pessimistic_flushes);
72 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache, 74 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache,
73 ui->use_vulkan_driver_pipeline_cache, 75 ui->use_vulkan_driver_pipeline_cache,
74 use_vulkan_driver_pipeline_cache); 76 use_vulkan_driver_pipeline_cache);
@@ -90,15 +92,14 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
90 // Disable if not global (only happens during game) 92 // Disable if not global (only happens during game)
91 if (Settings::IsConfiguringGlobal()) { 93 if (Settings::IsConfiguringGlobal()) {
92 ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); 94 ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
95 ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal());
93 ui->renderer_force_max_clock->setEnabled( 96 ui->renderer_force_max_clock->setEnabled(
94 Settings::values.renderer_force_max_clock.UsingGlobal()); 97 Settings::values.renderer_force_max_clock.UsingGlobal());
95 ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); 98 ui->use_reactive_flushing->setEnabled(Settings::values.use_reactive_flushing.UsingGlobal());
96 ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal()); 99 ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal());
97 ui->use_asynchronous_shaders->setEnabled( 100 ui->use_asynchronous_shaders->setEnabled(
98 Settings::values.use_asynchronous_shaders.UsingGlobal()); 101 Settings::values.use_asynchronous_shaders.UsingGlobal());
99 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); 102 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
100 ui->use_pessimistic_flushes->setEnabled(
101 Settings::values.use_pessimistic_flushes.UsingGlobal());
102 ui->use_vulkan_driver_pipeline_cache->setEnabled( 103 ui->use_vulkan_driver_pipeline_cache->setEnabled(
103 Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal()); 104 Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal());
104 ui->anisotropic_filtering_combobox->setEnabled( 105 ui->anisotropic_filtering_combobox->setEnabled(
@@ -107,10 +108,13 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
107 return; 108 return;
108 } 109 }
109 110
111 ConfigurationShared::SetColoredTristate(ui->async_present, Settings::values.async_presentation,
112 async_present);
110 ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock, 113 ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock,
111 Settings::values.renderer_force_max_clock, 114 Settings::values.renderer_force_max_clock,
112 renderer_force_max_clock); 115 renderer_force_max_clock);
113 ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync); 116 ConfigurationShared::SetColoredTristate(
117 ui->use_reactive_flushing, Settings::values.use_reactive_flushing, use_reactive_flushing);
114 ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc, 118 ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc,
115 async_astc); 119 async_astc);
116 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, 120 ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders,
@@ -118,9 +122,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
118 use_asynchronous_shaders); 122 use_asynchronous_shaders);
119 ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time, 123 ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time,
120 Settings::values.use_fast_gpu_time, use_fast_gpu_time); 124 Settings::values.use_fast_gpu_time, use_fast_gpu_time);
121 ConfigurationShared::SetColoredTristate(ui->use_pessimistic_flushes,
122 Settings::values.use_pessimistic_flushes,
123 use_pessimistic_flushes);
124 ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache, 125 ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache,
125 Settings::values.use_vulkan_driver_pipeline_cache, 126 Settings::values.use_vulkan_driver_pipeline_cache,
126 use_vulkan_driver_pipeline_cache); 127 use_vulkan_driver_pipeline_cache);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index bf1b04749..ae3c10946 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -36,12 +36,13 @@ private:
36 36
37 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; 37 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
38 38
39 ConfigurationShared::CheckState async_present;
39 ConfigurationShared::CheckState renderer_force_max_clock; 40 ConfigurationShared::CheckState renderer_force_max_clock;
40 ConfigurationShared::CheckState use_vsync; 41 ConfigurationShared::CheckState use_vsync;
41 ConfigurationShared::CheckState async_astc; 42 ConfigurationShared::CheckState async_astc;
43 ConfigurationShared::CheckState use_reactive_flushing;
42 ConfigurationShared::CheckState use_asynchronous_shaders; 44 ConfigurationShared::CheckState use_asynchronous_shaders;
43 ConfigurationShared::CheckState use_fast_gpu_time; 45 ConfigurationShared::CheckState use_fast_gpu_time;
44 ConfigurationShared::CheckState use_pessimistic_flushes;
45 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; 46 ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache;
46 47
47 const Core::System& system; 48 const Core::System& system;
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index a7dbdc18c..9d8cbea09 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -7,7 +7,7 @@
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>404</width> 9 <width>404</width>
10 <height>321</height> 10 <height>376</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -70,22 +70,19 @@
70 </widget> 70 </widget>
71 </item> 71 </item>
72 <item> 72 <item>
73 <widget class="QCheckBox" name="renderer_force_max_clock"> 73 <widget class="QCheckBox" name="async_present">
74 <property name="toolTip">
75 <string>Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed.</string>
76 </property>
77 <property name="text"> 74 <property name="text">
78 <string>Force maximum clocks (Vulkan only)</string> 75 <string>Enable asynchronous presentation (Vulkan only)</string>
79 </property> 76 </property>
80 </widget> 77 </widget>
81 </item> 78 </item>
82 <item> 79 <item>
83 <widget class="QCheckBox" name="use_vsync"> 80 <widget class="QCheckBox" name="renderer_force_max_clock">
84 <property name="toolTip"> 81 <property name="toolTip">
85 <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> 82 <string>Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed.</string>
86 </property> 83 </property>
87 <property name="text"> 84 <property name="text">
88 <string>Use VSync</string> 85 <string>Force maximum clocks (Vulkan only)</string>
89 </property> 86 </property>
90 </widget> 87 </widget>
91 </item> 88 </item>
@@ -100,39 +97,39 @@
100 </widget> 97 </widget>
101 </item> 98 </item>
102 <item> 99 <item>
103 <widget class="QCheckBox" name="use_asynchronous_shaders"> 100 <widget class="QCheckBox" name="use_reactive_flushing">
104 <property name="toolTip"> 101 <property name="toolTip">
105 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string> 102 <string>Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.</string>
106 </property> 103 </property>
107 <property name="text"> 104 <property name="text">
108 <string>Use asynchronous shader building (Hack)</string> 105 <string>Enable Reactive Flushing</string>
109 </property> 106 </property>
110 </widget> 107 </widget>
111 </item> 108 </item>
112 <item> 109 <item>
113 <widget class="QCheckBox" name="use_fast_gpu_time"> 110 <widget class="QCheckBox" name="use_asynchronous_shaders">
114 <property name="toolTip"> 111 <property name="toolTip">
115 <string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string> 112 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
116 </property> 113 </property>
117 <property name="text"> 114 <property name="text">
118 <string>Use Fast GPU Time (Hack)</string> 115 <string>Use asynchronous shader building (Hack)</string>
119 </property> 116 </property>
120 </widget> 117 </widget>
121 </item> 118 </item>
122 <item> 119 <item>
123 <widget class="QCheckBox" name="use_pessimistic_flushes"> 120 <widget class="QCheckBox" name="use_fast_gpu_time">
124 <property name="toolTip"> 121 <property name="toolTip">
125 <string>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</string> 122 <string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string>
126 </property> 123 </property>
127 <property name="text"> 124 <property name="text">
128 <string>Use pessimistic buffer flushes (Hack)</string> 125 <string>Use Fast GPU Time (Hack)</string>
129 </property> 126 </property>
130 </widget> 127 </widget>
131 </item> 128 </item>
132 <item> 129 <item>
133 <widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache"> 130 <widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache">
134 <property name="toolTip"> 131 <property name="toolTip">
135 <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</string> 132 <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</string>
136 </property> 133 </property>
137 <property name="text"> 134 <property name="text">
138 <string>Use Vulkan pipeline cache</string> 135 <string>Use Vulkan pipeline cache</string>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 50b62293e..2c2e7e47b 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -8,6 +8,7 @@
8#include <QInputDialog> 8#include <QInputDialog>
9#include <QMenu> 9#include <QMenu>
10#include <QMessageBox> 10#include <QMessageBox>
11#include <QMouseEvent>
11#include <QTimer> 12#include <QTimer>
12#include "common/assert.h" 13#include "common/assert.h"
13#include "common/param_package.h" 14#include "common/param_package.h"
@@ -206,7 +207,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
206 } 207 }
207 if (param.Has("axis")) { 208 if (param.Has("axis")) {
208 const QString axis = QString::fromStdString(param.Get("axis", "")); 209 const QString axis = QString::fromStdString(param.Get("axis", ""));
209 return QObject::tr("%1%2Axis %3").arg(toggle, invert, axis); 210 return QObject::tr("%1%2%3Axis %4").arg(toggle, inverted, invert, axis);
210 } 211 }
211 if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) { 212 if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) {
212 const QString axis_x = QString::fromStdString(param.Get("axis_x", "")); 213 const QString axis_x = QString::fromStdString(param.Get("axis_x", ""));
@@ -229,7 +230,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) {
229 return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name); 230 return QObject::tr("%1%2%3Hat %4").arg(turbo, toggle, inverted, button_name);
230 } 231 }
231 if (param.Has("axis")) { 232 if (param.Has("axis")) {
232 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); 233 return QObject::tr("%1%2%3Axis %4").arg(toggle, inverted, invert, button_name);
233 } 234 }
234 if (param.Has("motion")) { 235 if (param.Has("motion")) {
235 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); 236 return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name);
@@ -410,6 +411,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
410 button_map[button_id]->setText(ButtonToText(param)); 411 button_map[button_id]->setText(ButtonToText(param));
411 emulated_controller->SetButtonParam(button_id, param); 412 emulated_controller->SetButtonParam(button_id, param);
412 }); 413 });
414 context_menu.addAction(tr("Invert button"), [&] {
415 const bool invert_value = !param.Get("inverted", false);
416 param.Set("inverted", invert_value);
417 button_map[button_id]->setText(ButtonToText(param));
418 emulated_controller->SetButtonParam(button_id, param);
419 });
413 context_menu.addAction(tr("Set threshold"), [&] { 420 context_menu.addAction(tr("Set threshold"), [&] {
414 const int button_threshold = 421 const int button_threshold =
415 static_cast<int>(param.Get("threshold", 0.5f) * 100.0f); 422 static_cast<int>(param.Get("threshold", 0.5f) * 100.0f);
@@ -472,6 +479,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
472 param.Set("threshold", new_threshold / 1000.0f); 479 param.Set("threshold", new_threshold / 1000.0f);
473 emulated_controller->SetMotionParam(motion_id, param); 480 emulated_controller->SetMotionParam(motion_id, param);
474 }); 481 });
482 context_menu.addAction(tr("Calibrate sensor"), [&] {
483 emulated_controller->StartMotionCalibration();
484 });
475 } 485 }
476 context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location)); 486 context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location));
477 }); 487 });
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index c287220fc..a188eef92 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -180,6 +180,10 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ
180 battery_values = controller->GetBatteryValues(); 180 battery_values = controller->GetBatteryValues();
181 needs_redraw = true; 181 needs_redraw = true;
182 break; 182 break;
183 case Core::HID::ControllerTriggerType::Motion:
184 motion_values = controller->GetMotions();
185 needs_redraw = true;
186 break;
183 default: 187 default:
184 break; 188 break;
185 } 189 }
@@ -313,6 +317,15 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
313 DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0)); 317 DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0));
314 } 318 }
315 319
320 {
321 // Draw motion cubes
322 using namespace Settings::NativeMotion;
323 p.setPen(colors.outline);
324 p.setBrush(colors.transparent);
325 Draw3dCube(p, center + QPointF(-140, 90),
326 motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
327 }
328
316 using namespace Settings::NativeButton; 329 using namespace Settings::NativeButton;
317 330
318 // D-pad constants 331 // D-pad constants
@@ -435,6 +448,15 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
435 DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90)); 448 DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90));
436 } 449 }
437 450
451 {
452 // Draw motion cubes
453 using namespace Settings::NativeMotion;
454 p.setPen(colors.outline);
455 p.setBrush(colors.transparent);
456 Draw3dCube(p, center + QPointF(140, 90),
457 motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
458 }
459
438 using namespace Settings::NativeButton; 460 using namespace Settings::NativeButton;
439 461
440 // Face buttons constants 462 // Face buttons constants
@@ -555,6 +577,17 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
555 DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90)); 577 DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90));
556 } 578 }
557 579
580 {
581 // Draw motion cubes
582 using namespace Settings::NativeMotion;
583 p.setPen(colors.outline);
584 p.setBrush(colors.transparent);
585 Draw3dCube(p, center + QPointF(-180, 90),
586 motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
587 Draw3dCube(p, center + QPointF(180, 90),
588 motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
589 }
590
558 using namespace Settings::NativeButton; 591 using namespace Settings::NativeButton;
559 592
560 // Face buttons constants 593 // Face buttons constants
@@ -647,6 +680,15 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
647 DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0)); 680 DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0));
648 } 681 }
649 682
683 {
684 // Draw motion cubes
685 using namespace Settings::NativeMotion;
686 p.setPen(colors.outline);
687 p.setBrush(colors.transparent);
688 Draw3dCube(p, center + QPointF(0, -115),
689 motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f);
690 }
691
650 using namespace Settings::NativeButton; 692 using namespace Settings::NativeButton;
651 693
652 // Face buttons constants 694 // Face buttons constants
@@ -750,6 +792,15 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
750 DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105)); 792 DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105));
751 } 793 }
752 794
795 {
796 // Draw motion cubes
797 using namespace Settings::NativeMotion;
798 p.setPen(colors.button);
799 p.setBrush(colors.transparent);
800 Draw3dCube(p, center + QPointF(0, -100),
801 motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f);
802 }
803
753 using namespace Settings::NativeButton; 804 using namespace Settings::NativeButton;
754 805
755 // Face buttons constants 806 // Face buttons constants
@@ -2871,6 +2922,46 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di
2871 DrawPolygon(p, arrow_symbol); 2922 DrawPolygon(p, arrow_symbol);
2872} 2923}
2873 2924
2925// Draw motion functions
2926void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler,
2927 float size) {
2928 std::array<Common::Vec3f, 8> cube{
2929 Common::Vec3f{-0.7f, -1, -0.5f},
2930 {-0.7f, 1, -0.5f},
2931 {0.7f, 1, -0.5f},
2932 {0.7f, -1, -0.5f},
2933 {-0.7f, -1, 0.5f},
2934 {-0.7f, 1, 0.5f},
2935 {0.7f, 1, 0.5f},
2936 {0.7f, -1, 0.5f},
2937 };
2938
2939 for (Common::Vec3f& point : cube) {
2940 point.RotateFromOrigin(euler.x, euler.y, euler.z);
2941 point *= size;
2942 }
2943
2944 const std::array<QPointF, 4> front_face{
2945 center + QPointF{cube[0].x, cube[0].y},
2946 center + QPointF{cube[1].x, cube[1].y},
2947 center + QPointF{cube[2].x, cube[2].y},
2948 center + QPointF{cube[3].x, cube[3].y},
2949 };
2950 const std::array<QPointF, 4> back_face{
2951 center + QPointF{cube[4].x, cube[4].y},
2952 center + QPointF{cube[5].x, cube[5].y},
2953 center + QPointF{cube[6].x, cube[6].y},
2954 center + QPointF{cube[7].x, cube[7].y},
2955 };
2956
2957 DrawPolygon(p, front_face);
2958 DrawPolygon(p, back_face);
2959 p.drawLine(center + QPointF{cube[0].x, cube[0].y}, center + QPointF{cube[4].x, cube[4].y});
2960 p.drawLine(center + QPointF{cube[1].x, cube[1].y}, center + QPointF{cube[5].x, cube[5].y});
2961 p.drawLine(center + QPointF{cube[2].x, cube[2].y}, center + QPointF{cube[6].x, cube[6].y});
2962 p.drawLine(center + QPointF{cube[3].x, cube[3].y}, center + QPointF{cube[7].x, cube[7].y});
2963}
2964
2874template <size_t N> 2965template <size_t N>
2875void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) { 2966void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) {
2876 p.drawPolygon(polygon.data(), static_cast<int>(polygon.size())); 2967 p.drawPolygon(polygon.data(), static_cast<int>(polygon.size()));
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 267d134de..a16943c3c 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -9,6 +9,7 @@
9 9
10#include "common/input.h" 10#include "common/input.h"
11#include "common/settings_input.h" 11#include "common/settings_input.h"
12#include "common/vector_math.h"
12#include "core/hid/emulated_controller.h" 13#include "core/hid/emulated_controller.h"
13#include "core/hid/hid_types.h" 14#include "core/hid/hid_types.h"
14 15
@@ -193,6 +194,9 @@ private:
193 void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); 194 void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
194 void DrawArrow(QPainter& p, QPointF center, Direction direction, float size); 195 void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
195 196
197 // Draw motion functions
198 void Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler, float size);
199
196 // Draw primitive types 200 // Draw primitive types
197 template <size_t N> 201 template <size_t N>
198 void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon); 202 void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon);
@@ -222,4 +226,5 @@ private:
222 Core::HID::SticksValues stick_values{}; 226 Core::HID::SticksValues stick_values{};
223 Core::HID::TriggerValues trigger_values{}; 227 Core::HID::TriggerValues trigger_values{};
224 Core::HID::BatteryValues battery_values{}; 228 Core::HID::BatteryValues battery_values{};
229 Core::HID::MotionState motion_values{};
225}; 230};
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 6af34f793..286ccc5cd 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -111,6 +111,9 @@ void ConfigureSystem::SetConfiguration() {
111 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time)); 111 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time));
112 ui->device_name_edit->setText( 112 ui->device_name_edit->setText(
113 QString::fromUtf8(Settings::values.device_name.GetValue().c_str())); 113 QString::fromUtf8(Settings::values.device_name.GetValue().c_str()));
114 ui->use_unsafe_extended_memory_layout->setEnabled(enabled);
115 ui->use_unsafe_extended_memory_layout->setChecked(
116 Settings::values.use_unsafe_extended_memory_layout.GetValue());
114 117
115 if (Settings::IsConfiguringGlobal()) { 118 if (Settings::IsConfiguringGlobal()) {
116 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); 119 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
@@ -160,6 +163,9 @@ void ConfigureSystem::ApplyConfiguration() {
160 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region); 163 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
161 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index, 164 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
162 ui->combo_time_zone); 165 ui->combo_time_zone);
166 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_unsafe_extended_memory_layout,
167 ui->use_unsafe_extended_memory_layout,
168 use_unsafe_extended_memory_layout);
163 169
164 if (Settings::IsConfiguringGlobal()) { 170 if (Settings::IsConfiguringGlobal()) {
165 // Guard if during game and set to game-specific value 171 // Guard if during game and set to game-specific value
@@ -215,6 +221,10 @@ void ConfigureSystem::SetupPerGameUI() {
215 Settings::values.rng_seed.GetValue().has_value(), 221 Settings::values.rng_seed.GetValue().has_value(),
216 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed); 222 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
217 223
224 ConfigurationShared::SetColoredTristate(ui->use_unsafe_extended_memory_layout,
225 Settings::values.use_unsafe_extended_memory_layout,
226 use_unsafe_extended_memory_layout);
227
218 ui->custom_rtc_checkbox->setVisible(false); 228 ui->custom_rtc_checkbox->setVisible(false);
219 ui->custom_rtc_edit->setVisible(false); 229 ui->custom_rtc_edit->setVisible(false);
220} 230}
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index ec28724a1..ce1a91601 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -41,6 +41,7 @@ private:
41 bool enabled = false; 41 bool enabled = false;
42 42
43 ConfigurationShared::CheckState use_rng_seed; 43 ConfigurationShared::CheckState use_rng_seed;
44 ConfigurationShared::CheckState use_unsafe_extended_memory_layout;
44 45
45 Core::System& system; 46 Core::System& system;
46}; 47};
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 9e7bc3b93..e0caecd5e 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -478,6 +478,13 @@
478 </property> 478 </property>
479 </widget> 479 </widget>
480 </item> 480 </item>
481 <item row="7" column="0">
482 <widget class="QCheckBox" name="use_unsafe_extended_memory_layout">
483 <property name="text">
484 <string>Unsafe extended memory layout (8GB DRAM)</string>
485 </property>
486 </widget>
487 </item>
481 </layout> 488 </layout>
482 </item> 489 </item>
483 </layout> 490 </layout>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b79409a68..d932e33a7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -27,6 +27,7 @@
27#include "configuration/configure_input.h" 27#include "configuration/configure_input.h"
28#include "configuration/configure_per_game.h" 28#include "configuration/configure_per_game.h"
29#include "configuration/configure_tas.h" 29#include "configuration/configure_tas.h"
30#include "core/file_sys/romfs_factory.h"
30#include "core/file_sys/vfs.h" 31#include "core/file_sys/vfs.h"
31#include "core/file_sys/vfs_real.h" 32#include "core/file_sys/vfs_real.h"
32#include "core/frontend/applets/cabinet.h" 33#include "core/frontend/applets/cabinet.h"
@@ -570,8 +571,8 @@ void GMainWindow::RegisterMetaTypes() {
570 571
571 // Cabinet Applet 572 // Cabinet Applet
572 qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters"); 573 qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
573 qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>( 574 qRegisterMetaType<std::shared_ptr<Service::NFC::NfcDevice>>(
574 "std::shared_ptr<Service::NFP::NfpDevice>"); 575 "std::shared_ptr<Service::NFC::NfcDevice>");
575 576
576 // Controller Applet 577 // Controller Applet
577 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); 578 qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
@@ -599,7 +600,7 @@ void GMainWindow::RegisterMetaTypes() {
599} 600}
600 601
601void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, 602void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
602 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) { 603 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) {
603 cabinet_applet = 604 cabinet_applet =
604 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); 605 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device);
605 SCOPE_EXIT({ 606 SCOPE_EXIT({
@@ -4171,6 +4172,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
4171 } 4172 }
4172 4173
4173 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 4174 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
4175 bool all_keys_present{true};
4176
4174 if (keys.BaseDeriveNecessary()) { 4177 if (keys.BaseDeriveNecessary()) {
4175 Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory("", FileSys::Mode::Read)}; 4178 Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory("", FileSys::Mode::Read)};
4176 4179
@@ -4195,6 +4198,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
4195 errors += tr(" - Missing PRODINFO"); 4198 errors += tr(" - Missing PRODINFO");
4196 } 4199 }
4197 if (!errors.isEmpty()) { 4200 if (!errors.isEmpty()) {
4201 all_keys_present = false;
4198 QMessageBox::warning( 4202 QMessageBox::warning(
4199 this, tr("Derivation Components Missing"), 4203 this, tr("Derivation Components Missing"),
4200 tr("Encryption keys are missing. " 4204 tr("Encryption keys are missing. "
@@ -4222,11 +4226,40 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
4222 4226
4223 system->GetFileSystemController().CreateFactories(*vfs); 4227 system->GetFileSystemController().CreateFactories(*vfs);
4224 4228
4229 if (all_keys_present && !this->CheckSystemArchiveDecryption()) {
4230 LOG_WARNING(Frontend, "Mii model decryption failed");
4231 QMessageBox::warning(
4232 this, tr("System Archive Decryption Failed"),
4233 tr("Encryption keys failed to decrypt firmware. "
4234 "<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
4235 "quickstart guide</a> to get all your keys, firmware and "
4236 "games."));
4237 }
4238
4225 if (behavior == ReinitializeKeyBehavior::Warning) { 4239 if (behavior == ReinitializeKeyBehavior::Warning) {
4226 game_list->PopulateAsync(UISettings::values.game_dirs); 4240 game_list->PopulateAsync(UISettings::values.game_dirs);
4227 } 4241 }
4228} 4242}
4229 4243
4244bool GMainWindow::CheckSystemArchiveDecryption() {
4245 constexpr u64 MiiModelId = 0x0100000000000802;
4246
4247 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4248 if (!bis_system) {
4249 // Not having system BIS files is not an error.
4250 return true;
4251 }
4252
4253 auto mii_nca = bis_system->GetEntry(MiiModelId, FileSys::ContentRecordType::Data);
4254 if (!mii_nca) {
4255 // Not having the Mii model is not an error.
4256 return true;
4257 }
4258
4259 // Return whether we are able to decrypt the RomFS of the Mii model.
4260 return mii_nca->GetRomFS().get() != nullptr;
4261}
4262
4230std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, 4263std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed,
4231 u64 program_id) { 4264 u64 program_id) {
4232 const auto dlc_entries = 4265 const auto dlc_entries =
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 8b5c1d747..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);
@@ -392,6 +392,7 @@ private:
392 void LoadTranslation(); 392 void LoadTranslation();
393 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); 393 void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
394 bool CheckDarkMode(); 394 bool CheckDarkMode();
395 bool CheckSystemArchiveDecryption();
395 396
396 QString GetTasStateDescription() const; 397 QString GetTasStateDescription() const;
397 bool CreateShortcut(const std::string& shortcut_path, const std::string& title, 398 bool CreateShortcut(const std::string& shortcut_path, const std::string& title,
diff --git a/src/yuzu/qt_common.cpp b/src/yuzu/qt_common.cpp
new file mode 100644
index 000000000..5d0fd7674
--- /dev/null
+++ b/src/yuzu/qt_common.cpp
@@ -0,0 +1,55 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <QGuiApplication>
5#include <QStringLiteral>
6#include <QWindow>
7#include "common/logging/log.h"
8#include "core/frontend/emu_window.h"
9#include "yuzu/qt_common.h"
10
11#if !defined(WIN32) && !defined(__APPLE__)
12#include <qpa/qplatformnativeinterface.h>
13#endif
14
15namespace QtCommon {
16Core::Frontend::WindowSystemType GetWindowSystemType() {
17 // Determine WSI type based on Qt platform.
18 QString platform_name = QGuiApplication::platformName();
19 if (platform_name == QStringLiteral("windows"))
20 return Core::Frontend::WindowSystemType::Windows;
21 else if (platform_name == QStringLiteral("xcb"))
22 return Core::Frontend::WindowSystemType::X11;
23 else if (platform_name == QStringLiteral("wayland"))
24 return Core::Frontend::WindowSystemType::Wayland;
25 else if (platform_name == QStringLiteral("wayland-egl"))
26 return Core::Frontend::WindowSystemType::Wayland;
27 else if (platform_name == QStringLiteral("cocoa"))
28 return Core::Frontend::WindowSystemType::Cocoa;
29 else if (platform_name == QStringLiteral("android"))
30 return Core::Frontend::WindowSystemType::Android;
31
32 LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString());
33 return Core::Frontend::WindowSystemType::Windows;
34} // namespace Core::Frontend::WindowSystemType
35
36Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
37 Core::Frontend::EmuWindow::WindowSystemInfo wsi;
38 wsi.type = GetWindowSystemType();
39
40 // Our Win32 Qt external doesn't have the private API.
41#if defined(WIN32) || defined(__APPLE__)
42 wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
43#else
44 QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
45 wsi.display_connection = pni->nativeResourceForWindow("display", window);
46 if (wsi.type == Core::Frontend::WindowSystemType::Wayland)
47 wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
48 else
49 wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
50#endif
51 wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f;
52
53 return wsi;
54}
55} // namespace QtCommon
diff --git a/src/yuzu/qt_common.h b/src/yuzu/qt_common.h
new file mode 100644
index 000000000..9c63f08f3
--- /dev/null
+++ b/src/yuzu/qt_common.h
@@ -0,0 +1,15 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <QWindow>
7#include "core/frontend/emu_window.h"
8
9namespace QtCommon {
10
11Core::Frontend::WindowSystemType GetWindowSystemType();
12
13Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window);
14
15} // namespace QtCommon
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 464da3231..abe7092fc 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -4,18 +4,8 @@
4#include <memory> 4#include <memory>
5#include <optional> 5#include <optional>
6#include <sstream> 6#include <sstream>
7
8// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
9#ifdef __clang__
10#pragma clang diagnostic push
11#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
12#endif
13#include <SDL.h>
14#ifdef __clang__
15#pragma clang diagnostic pop
16#endif
17
18#include <INIReader.h> 7#include <INIReader.h>
8#include <SDL.h>
19#include "common/fs/file.h" 9#include "common/fs/file.h"
20#include "common/fs/fs.h" 10#include "common/fs/fs.h"
21#include "common/fs/path_util.h" 11#include "common/fs/path_util.h"
@@ -274,7 +264,7 @@ void Config::ReadValues() {
274 264
275 // Core 265 // Core
276 ReadSetting("Core", Settings::values.use_multi_core); 266 ReadSetting("Core", Settings::values.use_multi_core);
277 ReadSetting("Core", Settings::values.use_extended_memory_layout); 267 ReadSetting("Core", Settings::values.use_unsafe_extended_memory_layout);
278 268
279 // Cpu 269 // Cpu
280 ReadSetting("Cpu", Settings::values.cpu_accuracy); 270 ReadSetting("Cpu", Settings::values.cpu_accuracy);
@@ -300,6 +290,7 @@ void Config::ReadValues() {
300 290
301 // Renderer 291 // Renderer
302 ReadSetting("Renderer", Settings::values.renderer_backend); 292 ReadSetting("Renderer", Settings::values.renderer_backend);
293 ReadSetting("Renderer", Settings::values.async_presentation);
303 ReadSetting("Renderer", Settings::values.renderer_force_max_clock); 294 ReadSetting("Renderer", Settings::values.renderer_force_max_clock);
304 ReadSetting("Renderer", Settings::values.renderer_debug); 295 ReadSetting("Renderer", Settings::values.renderer_debug);
305 ReadSetting("Renderer", Settings::values.renderer_shader_feedback); 296 ReadSetting("Renderer", Settings::values.renderer_shader_feedback);
@@ -319,14 +310,14 @@ void Config::ReadValues() {
319 ReadSetting("Renderer", Settings::values.use_disk_shader_cache); 310 ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
320 ReadSetting("Renderer", Settings::values.gpu_accuracy); 311 ReadSetting("Renderer", Settings::values.gpu_accuracy);
321 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); 312 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
322 ReadSetting("Renderer", Settings::values.use_vsync); 313 ReadSetting("Renderer", Settings::values.vsync_mode);
323 ReadSetting("Renderer", Settings::values.shader_backend); 314 ReadSetting("Renderer", Settings::values.shader_backend);
315 ReadSetting("Renderer", Settings::values.use_reactive_flushing);
324 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); 316 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
325 ReadSetting("Renderer", Settings::values.nvdec_emulation); 317 ReadSetting("Renderer", Settings::values.nvdec_emulation);
326 ReadSetting("Renderer", Settings::values.accelerate_astc); 318 ReadSetting("Renderer", Settings::values.accelerate_astc);
327 ReadSetting("Renderer", Settings::values.async_astc); 319 ReadSetting("Renderer", Settings::values.async_astc);
328 ReadSetting("Renderer", Settings::values.use_fast_gpu_time); 320 ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
329 ReadSetting("Renderer", Settings::values.use_pessimistic_flushes);
330 ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache); 321 ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache);
331 322
332 ReadSetting("Renderer", Settings::values.bg_red); 323 ReadSetting("Renderer", Settings::values.bg_red);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 209cfc28a..5e7c3ac04 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -163,9 +163,9 @@ keyboard_enabled =
163# 0: Disabled, 1 (default): Enabled 163# 0: Disabled, 1 (default): Enabled
164use_multi_core = 164use_multi_core =
165 165
166# Enable extended guest system memory layout (8GB DRAM) 166# Enable unsafe extended guest system memory layout (8GB DRAM)
167# 0 (default): Disabled, 1: Enabled 167# 0 (default): Disabled, 1: Enabled
168use_extended_memory_layout = 168use_unsafe_extended_memory_layout =
169 169
170[Cpu] 170[Cpu]
171# Adjusts various optimizations. 171# Adjusts various optimizations.
@@ -264,6 +264,10 @@ cpuopt_unsafe_ignore_global_monitor =
264# 0: OpenGL, 1 (default): Vulkan 264# 0: OpenGL, 1 (default): Vulkan
265backend = 265backend =
266 266
267# Whether to enable asynchronous presentation (Vulkan only)
268# 0 (default): Off, 1: On
269async_presentation =
270
267# Enable graphics API debugging mode. 271# Enable graphics API debugging mode.
268# 0 (default): Disabled, 1: Enabled 272# 0 (default): Disabled, 1: Enabled
269debug = 273debug =
@@ -321,8 +325,14 @@ aspect_ratio =
321# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x 325# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x
322max_anisotropy = 326max_anisotropy =
323 327
324# Whether to enable V-Sync (caps the framerate at 60FPS) or not. 328# Whether to enable VSync or not.
325# 0 (default): Off, 1: On 329# OpenGL: Values other than 0 enable VSync
330# Vulkan: FIFO is selected if the requested mode is not supported by the driver.
331# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate.
332# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down.
333# Mailbox can have lower latency than FIFO and does not tear but may drop frames.
334# Immediate (no synchronization) just presents whatever is available and can exhibit tearing.
335# 0: Immediate (Off), 1: Mailbox, 2 (Default): FIFO (On), 3: FIFO Relaxed
326use_vsync = 336use_vsync =
327 337
328# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is 338# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is
@@ -330,6 +340,10 @@ use_vsync =
330# 0: GLSL, 1 (default): GLASM, 2: SPIR-V 340# 0: GLSL, 1 (default): GLASM, 2: SPIR-V
331shader_backend = 341shader_backend =
332 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
333# Whether to allow asynchronous shader building. 347# Whether to allow asynchronous shader building.
334# 0 (default): Off, 1: On 348# 0 (default): Off, 1: On
335use_asynchronous_shaders = 349use_asynchronous_shaders =
@@ -370,10 +384,6 @@ use_asynchronous_gpu_emulation =
370# 0: Off, 1 (default): On 384# 0: Off, 1 (default): On
371use_fast_gpu_time = 385use_fast_gpu_time =
372 386
373# Force unmodified buffers to be flushed, which can cost performance.
374# 0: Off (default), 1: On
375use_pessimistic_flushes =
376
377# Whether to use garbage collection or not for GPU caches. 387# Whether to use garbage collection or not for GPU caches.
378# 0 (default): Off, 1: On 388# 0 (default): Off, 1: On
379use_caches_gc = 389use_caches_gc =
diff --git a/vcpkg.json b/vcpkg.json
index 0352dab77..19f99e89e 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -49,7 +49,7 @@
49 "overrides": [ 49 "overrides": [
50 { 50 {
51 "name": "catch2", 51 "name": "catch2",
52 "version": "3.0.1" 52 "version": "3.3.1"
53 }, 53 },
54 { 54 {
55 "name": "fmt", 55 "name": "fmt",