diff options
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 | |||
| 4 | path_classifiers: | ||
| 5 | library: "externals" | ||
| 6 | extraction: | ||
| 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't support the ring controller</source> | 3431 | <source>The current mapped device doesn'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't have a ring attached</source> | 3436 | <source>The current mapped device doesn'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><html><head/><body><p>Server address of the host</p></body></html></source> | 4505 | <source><html><head/><body><p>Server address of the host</p></body></html></source> |
| 4506 | <translation type="unfinished"/> | 4506 | <translation><html><head/><body><p>Dirección del servidor del anfitrión</p></body></html></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'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'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 &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 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv3.0+.</span></p> | 25 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu is an experimental open-source emulator for the Nintendo Switch licensed under GPLv3.0+.</span></p> |
| 26 | <p style="-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;"><br /></p> | 26 | <p style="-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;"><br /></p> |
| 27 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">This software should not be used to play games you have not legally obtained.</span></p></body></html></source> | 27 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">This software should not be used to play games you have not legally obtained.</span></p></body></html></source> |
| 28 | <translation type="unfinished"/> | 28 | <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> |
| 29 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> | ||
| 30 | p, li { white-space: pre-wrap; } | ||
| 31 | </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> | ||
| 32 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">yuzu is een experimentele open-source emulator voor de Nintendo Switch met een licentie onder GPLv3.0+.</span></p> | ||
| 33 | <p style="-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;"><br /></p> | ||
| 34 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt;">Deze software mag niet worden gebruikt om spellen te spelen die je niet legaal hebt verkregen.</span></p></body></html></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 <br>of your touchpad.</source> | 61 | <source>Touch the top left corner <br>of your touchpad.</source> |
| 56 | <translation>Raak de linkerbovenhoek <br> van uw touchpad aan.</translation> | 62 | <translation>Raak de linkerbovenhoek <br> 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 <br>of your touchpad.</source> | 66 | <source>Now touch the bottom right corner <br>of your touchpad.</source> |
| 61 | <translation>klik nu op toets <br> op je toetsenbord</translation> | 67 | <translation>Raak nu de rechterbenedenhoek <br>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'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.<br><br>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.<br><br>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.<br><br>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 <b>kick</b> %1?</source> | 160 | <source>Are you sure you would like to <b>kick</b> %1?</source> |
| 155 | <translation>Weet je zeker dat je %1 wil <b>verwijderen</b>?</translation> | 161 | <translation>Weet je zeker dat je %1 wil <b>kicken</b>?</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 <b>kick and ban</b> %1? | 170 | <source>Are you sure you would like to <b>kick and ban</b> %1? |
| 165 | 171 | ||
| 166 | This would ban both their forum username and their IP address.</source> | 172 | This would ban both their forum username and their IP address.</source> |
| 167 | <translation type="unfinished"/> | 173 | <translation>Weet je zeker dat je %1 wilt <b>kicken en bannen</b>? |
| 174 | |||
| 175 | Dit 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><html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of yuzu you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected yuzu account</li></ul></body></html></source> | 239 | <source><html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of yuzu you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected yuzu account</li></ul></body></html></source> |
| 232 | <translation><html><head/><body><p><span style=" font-size:10pt;">Als je kiest een test case op te sturen naar de </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu compatibiliteitslijst</span></a><span style=" font-size:10pt;">, zal de volgende informatie worden verzameld en getoond op de site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Informatie (CPU / GPU / Besturingssysteem)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Welke versie van yuzu je draait</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Het verbonden yuzu account</li></ul></body></html></translation> | 240 | <translation><html><head/><body><p><span style=" font-size:10pt;">Als je kiest een test case op te sturen naar de </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu-compatibiliteitslijst</span></a><span style=" font-size:10pt;">, zal de volgende informatie worden verzameld en getoond op de site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware-informatie (CPU / GPU / Besturingssysteem)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Welke versie van yuzu je draait</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Het verbonden yuzu-account</li></ul></body></html></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><html><head/><body><p>Does the game boot?</p></body></html></source> | 244 | <source><html><head/><body><p>Does the game boot?</p></body></html></source> |
| 237 | <translation type="unfinished"/> | 245 | <translation><html><head/><body><p>Start het spel op?</p></body></html></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't get past the "Launching..." screen</source> | 254 | <source>No The game doesn't get past the "Launching..." screen</source> |
| 247 | <translation type="unfinished"/> | 255 | <translation>Nee Het spel komt niet voorbij het "Starten..." 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><html><head/><body><p>Does the game reach gameplay?</p></body></html></source> | 269 | <source><html><head/><body><p>Does the game reach gameplay?</p></body></html></source> |
| 262 | <translation type="unfinished"/> | 270 | <translation><html><head/><body><p>Bereikt het spel de gameplay?</p></body></html></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><html><head/><body><p>Does the game work without crashing, freezing or locking up during gameplay?</p></body></html></source> | 284 | <source><html><head/><body><p>Does the game work without crashing, freezing or locking up during gameplay?</p></body></html></source> |
| 277 | <translation type="unfinished"/> | 285 | <translation><html><head/><body><p>Werkt het spel zonder te crashen, te bevriezen of vast te lopen tijdens het spelen?</p></body></html></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't progress past a certain area</source> | 294 | <source>No The game can'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><html><head/><body><p>Is the game completely playable from start to finish?</p></body></html></source> | 299 | <source><html><head/><body><p>Is the game completely playable from start to finish?</p></body></html></source> |
| 292 | <translation type="unfinished"/> | 300 | <translation><html><head/><body><p>Is het spel volledig speelbaar van begin tot eind?</p></body></html></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><html><head/><body><p>Does the game have any graphical glitches?</p></body></html></source> | 319 | <source><html><head/><body><p>Does the game have any graphical glitches?</p></body></html></source> |
| 312 | <translation type="unfinished"/> | 320 | <translation><html><head/><body><p>Heeft het spel grafische glitches?</p></body></html></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><html><head/><body><p>Does the game have any audio glitches / missing effects?</p></body></html></source> | 339 | <source><html><head/><body><p>Does the game have any audio glitches / missing effects?</p></body></html></source> |
| 332 | <translation type="unfinished"/> | 340 | <translation><html><head/><body><p>Heeft het spel audio-glitches / ontbrekende effecten?</p></body></html></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 | <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> | 551 | <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> |
| 544 | </source> | 552 | </source> |
| 545 | <translation> | 553 | <translation> |
| 546 | <div>Deze optie verbeterd de prestatie door de accuratie van fused-multiply-add instructies te verminderen op CPU's zonder native FMA support.</div> | 554 | <div>Deze optie verbeterd de prestatie door de accuratie van fused-multiply-add-instructies te verminderen op CPU's zonder native FMA support.</div></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 | <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> | 577 | <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> |
| 571 | </source> | 578 | </source> |
| 572 | <translation> | 579 | <translation> |
| 573 | <div>Deze optie verbetert de snelheid of 32-bit ASIMD floating-point functies door incorrecte afronding modellen te gebruiken.</div> | 580 | <div>Deze optie verbetert de snelheid of 32-bit ASIMD floating-point functies door incorrecte afronding modellen te gebruiken.</div></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 | <div>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.</div> | 603 | <div>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.</div> |
| 598 | </source> | 604 | </source> |
| 599 | <translation type="unfinished"/> | 605 | <translation> |
| 606 | <div>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.</div></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 | <div>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.</div> | 616 | <div>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.</div> |
| 610 | </source> | 617 | </source> |
| 611 | <translation type="unfinished"/> | 618 | <translation> |
| 619 | <div>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 "race conditions".</div></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><html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html></source> | 651 | <source><html><head/><body><p><span style=" font-weight:600;">For debugging only.</span><br/>If you're not sure what these do, keep all of these enabled. <br/>These settings, when disabled, only take effect when CPU Debugging is enabled. </p></body></html></source> |
| 645 | <translation type="unfinished"/> | 652 | <translation><html><head/><body><p><span style=" font-weight:600;">Alleen voor debugging.</span><br/> Als u niet zeker weet wat deze doen, laat ze dan allemaal ingeschakeld. <br/>Deze instellingen, indien uitgeschakeld, hebben alleen effect wanneer CPU Debugging is ingeschakeld.</p></body></html></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 | <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> | 659 | <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> |
| 653 | </source> | 660 | </source> |
| 654 | <translation> | 661 | <translation> |
| 655 | <div style="white-space: nowrap">Deze optimazie versneld geheugen toegang door het gastprogramma.</div> | 662 | <div style="white-space: nowrap">Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.</div> |
| 656 | <div style="white-space: nowrap">Door dit aan te leggen geeft toegang tot PageTable::pointers in uitgezonden code.</div> | 663 | <div style="white-space: nowrap">Inschakelen zorgt ervoor dat exclusieve geheugenlees/schrijfacties van de gast rechtstreeks in het geheugen plaatsvinden en gebruik maken van de MMU van de host.</div> |
| 657 | <div style="white-space: nowrap">Door dit uit te leggen forceerd u alle geheugen toegang door Memory::Read/Memory::Write functies te gaan.</div></translation> | 664 | <div style="white-space: nowrap">Uitschakelen forceert het gebruik van Software MMU-emulatie voor alle exclusieve geheugentoepassingen.</div></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 | <div>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.</div> | 687 | <div>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.</div> |
| 681 | </source> | 688 | </source> |
| 682 | <translation> | 689 | <translation> |
| 683 | <div>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.</div></translation> | 690 | <div>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.</div></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 | <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> | 769 | <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> |
| 764 | </source> | 770 | </source> |
| 765 | <translation> | 771 | <translation> |
| 766 | <div style="white-space: nowrap">Deze optimazie versneld geheugen toegang door het gastprogramma.</div> | 772 | <div style="white-space: nowrap">Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.</div> |
| 767 | <div style="white-space: nowrap">Door dit aan te leggen geeft toegang tot PageTable::pointers in uitgezonden code.</div> | 773 | <div style="white-space: nowrap">Inschakelen zorgt ervoor dat geheugenlees/schrijfacties rechtstreeks in het geheugen plaatsvinden en gebruik maken van de MMU van de host.</div> |
| 768 | <div style="white-space: nowrap">Door dit uit te leggen forceerd u alle geheugen toegang door Memory::Read/Memory::Write functies te gaan.</div></translation> | 774 | <div style="white-space: nowrap">Uitschakelen forceert het gebruik van Software MMU-emulatie voor alle exclusieve geheugentoepassingen.</div></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 | <div style="white-space: nowrap">Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.</div> | 785 | <div style="white-space: nowrap">Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.</div> |
| 780 | <div style="white-space: nowrap">Disabling this forces all exclusive memory accesses to use Software MMU Emulation.</div> | 786 | <div style="white-space: nowrap">Disabling this forces all exclusive memory accesses to use Software MMU Emulation.</div> |
| 781 | </source> | 787 | </source> |
| 782 | <translation type="unfinished"/> | 788 | <translation> |
| 789 | <div style="white-space: nowrap">Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.</div> | ||
| 790 | <div style="white-space: nowrap">Inschakelen zorgt ervoor dat exclusieve geheugenlees/schrijfacties van de gast rechtstreeks in het geheugen plaatsvinden en gebruik maken van de MMU van de host.</div> | ||
| 791 | <div style="white-space: nowrap">Uitschakelen forceert het gebruik van Software MMU-emulatie voor alle exclusieve geheugentoepassingen.</div></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 | <div style="white-space: nowrap">This optimization speeds up exclusive memory accesses by the guest program.</div> | 801 | <div style="white-space: nowrap">This optimization speeds up exclusive memory accesses by the guest program.</div> |
| 793 | <div style="white-space: nowrap">Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.</div> | 802 | <div style="white-space: nowrap">Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.</div> |
| 794 | </source> | 803 | </source> |
| 795 | <translation type="unfinished"/> | 804 | <translation> |
| 805 | <div style="white-space: nowrap">Deze optimalisatie versnelt exclusieve geheugentoegang door het gastprogramma.</div> | ||
| 806 | <div style="white-space: nowrap">Het inschakelen ervan vermindert de overhead van fastmem falen van exclusieve geheugentoegang.</div></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 | <div style="white-space: nowrap">This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.</div> | 816 | <div style="white-space: nowrap">This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.</div> |
| 806 | <div style="white-space: nowrap">Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.</div> | 817 | <div style="white-space: nowrap">Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.</div> |
| 807 | </source> | 818 | </source> |
| 808 | <translation type="unfinished"/> | 819 | <translation> |
| 820 | <div style="white-space: nowrap">Deze optimalisering versnelt geheugentoepassingen door ongeldige geheugentoepassingen te laten slagen.</div> | ||
| 821 | <div style="white-space: nowrap">Het inschakelen ervan vermindert de overhead van alle geheugentoepassingen en heeft geen invloed op programma's die geen ongeldig geheugen gebruiken.</div></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'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'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'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't be deleted. It might be in use or non-existent.</source> | 1334 | <source>The metadata cache couldn'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. |
| 2649 | To invert the axes, first move your joystick vertically, and then horizontally.</source> | 2661 | To 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. |
| 2651 | Om de assen te spiegelen, beweek je joystick eerst verticaal en dan horizontaal.</translation> | 2663 | Om 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 "%1"</source> | 2791 | <source>Failed to create the input profile "%1"</source> |
| 2780 | <translation>Het is mislukt om Invoer Profiel "%1 te Creëer</translation> | 2792 | <translation>Kon invoerprofiel "%1" 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 "%1"</source> | 2801 | <source>Failed to delete the input profile "%1"</source> |
| 2790 | <translation>Het is mislukt om Invoer Profiel "%1 te Verwijderen</translation> | 2802 | <translation>Kon invoerprofiel "%1" 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 "%1"</source> | 2811 | <source>Failed to load the input profile "%1"</source> |
| 2800 | <translation>Het is mislukt om Invoer Profiel "%1 te Laden</translation> | 2812 | <translation>Kon invoerprofiel "%1" 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 "%1"</source> | 2821 | <source>Failed to save the input profile "%1"</source> |
| 2810 | <translation>Het is mislukt om Invoer Profiel "%1 Op te slaan</translation> | 2822 | <translation>Kon invoerprofiel "%1" 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><a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a></source> | 2920 | <source><a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a></source> |
| 2909 | <translation><a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Leer Meer</span></a></translation> | 2921 | <translation><a href='https://yuzu-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Meer Info</span></a></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.<br>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.<br>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.<br>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.<br>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.<br>Please wait for them to finish.</source> | 2995 | <source>UDP Test or calibration configuration is in progress.<br>Please wait for them to finish.</source> |
| 2984 | <translation>UDP Test of calibratie configuratie is bezig.<br>Wacht alstublieft totdat het voltooid is.</translation> | 2996 | <translation>UDP-test of kalibratieconfiguratie is bezig.<br>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'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's (*.jpg *.jpeg)</translation> | 3236 | <translation>JPEG-foto'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's save data will be deleted.</source> | 3293 | <source>Delete this user? All of the user'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 |
| 3292 | UUID: %2</source> | 3304 | UUID: %2</source> |
| 3293 | <translation type="unfinished"/> | 3305 | <translation>Naam: %1 |
| 3306 | UUID: %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't support the ring controller</source> | 3413 | <source>The current mapped device doesn'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't have a ring attached</source> | 3418 | <source>The current mapped device doesn'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: "%1" is not a valid language for region "%2"</source> | 3842 | <source>Warning: "%1" is not a valid language for region "%2"</source> |
| 3830 | <translation type="unfinished"/> | 3843 | <translation>Waarschuwing: "%1" is geen geldige taal voor regio "%2"</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><html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html></source> | 3855 | <source><html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html></source> |
| 3843 | <translation type="unfinished"/> | 3856 | <translation><html><head/><body><p>Leest controller-invoer van scripts in hetzelfde formaat als TAS-nx-scripts.<br/>Voor een meer gedetailleerde uitleg kunt u de<a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help-pagina</span></a>op de yuzu-website raadplegen.</p></body></html></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 -> General -> Hotkeys).</source> | 3860 | <source>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys).</source> |
| 3848 | <translation type="unfinished"/> | 3861 | <translation>Om te controleren welke sneltoetsen het afspelen/opnemen regelen, raadpleeg de sneltoetsinstellingen (Configuratie -> Algemeen -> 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.<br/>It will not play back scripts frame perfectly with the current, imperfect syncing method.</source> | 3865 | <source>WARNING: This is an experimental feature.<br/>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.<br/>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. |
| 3934 | Drag points to change position, or double-click table cells to edit values.</source> | 3947 | Drag 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. |
| 3936 | Sleep punten om positie te veranderen, of dubbel klik één van de tabel cellen om de waardes te veranderen.</translation> | 3949 | Versleep 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'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'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'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'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't being hosted.</source> | 4350 | <source>Web Service configuration can only be changed when a public room isn'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><a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a></source> | 4390 | <source><a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a></source> |
| 4378 | <translation><a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Leer meer</span></a></translation> | 4391 | <translation><a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Meer info</span></a></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>&Controller P1</source> | 4469 | <source>&Controller P1</source> |
| 4457 | <translation type="unfinished"/> | 4470 | <translation>&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><html><head/><body><p>Server address of the host</p></body></html></source> | 4487 | <source><html><head/><body><p>Server address of the host</p></body></html></source> |
| 4475 | <translation type="unfinished"/> | 4488 | <translation><html><head/><body><p>Serveradres van de host</p></body></html></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><html><head/><body><p>Port number the host is listening on</p></body></html></source> | 4497 | <source><html><head/><body><p>Port number the host is listening on</p></body></html></source> |
| 4485 | <translation type="unfinished"/> | 4498 | <translation><html><head/><body><p>Poortnummer waarop de host luistert</p></body></html></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.<br><br>Click <a href='https://yuzu-emu.org/wiki/faq/#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>here for instructions to fix the issue</a>.</source> | 4548 | <source>Vulkan initialization failed during boot.<br><br>Click <a href='https://yuzu-emu.org/wiki/faq/#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>here for instructions to fix the issue</a>.</source> |
| 4536 | <translation type="unfinished"/> | 4549 | <translation>Vulkan-initialisatie mislukt tijdens het opstarten.<br><br>Klik <a href='https://yuzu-emu.org/wiki/faq/#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>hier voor instructies om het probleem op te lossen</a>.</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>&Clear Recent Files</source> | 4596 | <source>&Clear Recent Files</source> |
| 4583 | <translation type="unfinished"/> | 4597 | <translation>&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>&Continue</source> | 4611 | <source>&Continue</source> |
| 4598 | <translation type="unfinished"/> | 4612 | <translation>&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>&Pause</source> | 4616 | <source>&Pause</source> |
| 4603 | <translation>&Pauzeren</translation> | 4617 | <translation>&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.<br><br>For an explanation of the various Switch formats yuzu supports, <a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>check out our wiki</a>. 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.<br><br>For an explanation of the various Switch formats yuzu supports, <a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>check out our wiki</a>. 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.<br><br>Voor een uitleg over welke Switch formaten yuzu ondersteund, <a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>kijk op onze wiki</a>. 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.<br><br>Voor een uitleg van de verschillende Switch-formaten die yuzu ondersteunt,<a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'> bekijk onze wiki</a>. 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: <a href='https://yuzu-emu.org/help/reference/log-files/'>How to Upload the Log File</a>. </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: <a href='https://yuzu-emu.org/help/reference/log-files/'>How to Upload the Log File</a>. </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: <a href='https://yuzu-emu.org/help/reference/log-files/'>Hoe upload je het logbestand</a>. </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<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to redump your files.<br>You can refer to the yuzu wiki</a> or the yuzu Discord</a> for help.</source> | 4664 | <source>%1<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to redump your files.<br>You can refer to the yuzu wiki</a> or the yuzu Discord</a> 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<br>Volg de <a href='https://yuzu-emu.org/help/quickstart/'>yuzu snelstartgids</a> om je bestanden te redumpen.<br>Je kunt de yuzu-wiki</a>of de yuzu-Discord</a> 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.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure.</source> | 4922 | <source>Please select the how you would like the RomFS dumped.<br>Full will copy all of the files into the new directory while <br>skeleton will only create the directory structure.</source> |
| 4909 | <translation>Selecteer alstublieft hoe je de RomFS wilt dumpen.<br>Volledig kopieërd alle bestanden in een map terwijl <br> skelet maakt alleen het map structuur.</translation> | 4923 | <translation>Selecteer hoe je de RomFS gedumpt wilt hebben.<br>Volledig zal alle bestanden naar de nieuwe map kopiëren, terwijl <br>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 > Configure > System > Filesystem > 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 > Configure > System > Filesystem > 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 > Configuratie > Systeem > Bestandssysteem > 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 "%1" does not exist.</source> | 4967 | <source>Cannot create shortcut on desktop. Path "%1" does not exist.</source> |
| 4954 | <translation type="unfinished"/> | 4968 | <translation>Kan geen snelkoppeling op het bureaublad maken. Pad "%1" 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 "%1" does not exist and cannot be created.</source> | 4972 | <source>Cannot create shortcut in applications menu. Path "%1" does not exist and cannot be created.</source> |
| 4959 | <translation type="unfinished"/> | 4973 | <translation>Kan geen snelkoppeling maken in toepassingen menu. Pad "%1" 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 "%1" does not exist and cannot be created.</source> | 4982 | <source>Cannot create icon file. Path "%1" does not exist and cannot be created.</source> |
| 4969 | <translation type="unfinished"/> | 4983 | <translation>Kan geen icoonbestand maken. Pad "%1" 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 'main' file.</source> | 5043 | <source>The directory you have selected does not contain a 'main' file.</source> |
| 5030 | <translation>De map die je hebt geselecteerd bevat geen 'main' bestand.</translation> | 5044 | <translation>De map die je hebt geselecteerd bevat geen 'main'-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. |
| 5061 | Please, only use this feature to install updates and DLC.</source> | 5075 | Please, 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. |
| 5077 | Gebruik 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 'Game' is fine.)</source> | 5156 | (In most instances, the default 'Game' 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 'Game' juist.)</translation> | 5158 | (In de meeste gevallen is de standaard "Spel" 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.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web.</source> | 5204 | <source>In order to submit a game compatibility test case, you must link your yuzu account.<br><br/>To link your yuzu account, go to Emulation &gt; Configuration &gt; Web.</source> |
| 5184 | <translation>Om game campatibiliteit te raporteren, moet je je yuzu account koppelen.<br><br/> Om je yuzu account te koppelen, ga naar Emulatie &gt; Configuratie &gt; Web.</translation> | 5205 | <translation>Om een spelcompatibiliteitstest in te dienen, moet je je yuzu-account koppelen.<br><br/>Om je yuzu-account te koppelen, ga naar Emulatie &gt; Configuratie &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 "%1".</source> | 5214 | <source>Unable to open the URL "%1".</source> |
| 5194 | <translation type="unfinished"/> | 5215 | <translation>Kan de URL "%1" 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't be used on docked mode. Pro controller will be selected.</source> | 5234 | <source>Handheld controller can'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'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>&Stop Running</source> | 5322 | <source>&Stop Running</source> |
| 5302 | <translation type="unfinished"/> | 5323 | <translation>&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&ecording</source> | 5332 | <source>Stop R&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&ecord</source> | 5337 | <source>R&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 | |||
| 5469 | and optionally make backups. | 5490 | and optionally make backups. |
| 5470 | 5491 | ||
| 5471 | This will delete your autogenerated key files and re-run the key derivation module.</source> | 5492 | This 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. |
| 5473 | Als je niet weet wat dit doet of wat je aan het doen bent, | 5494 | Als je niet weet wat dit betekent of wat je doet, |
| 5474 | dit is potentieel een vernietigende actie. | 5495 | is dit een potentieel destructieve actie. |
| 5475 | Zorg ervoor dat je zeker weet dat dit is wat je wilt doen | 5496 | Zorg ervoor dat dit is wat je wilt |
| 5476 | en optioneel maak backups. | 5497 | en maak eventueel back-ups. |
| 5477 | 5498 | ||
| 5478 | Dit zal je automatisch gegenereerde sleutel bestanden verwijderen en de sleutel verkrijger module opnieuw starten</translation> | 5499 | Dit 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. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small></source> | 5528 | <source>Encryption keys are missing. <br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu quickstart guide</a> to get all your keys, firmware and games.<br><br><small>(%1)</small></source> |
| 5508 | <translation type="unfinished"/> | 5529 | <translation>Encryptiesleutels ontbreken. <br>Volg <a href='https://yuzu-emu.org/help/quickstart/'>de yuzu-snelstartgids</a> om al je sleutels, firmware en spellen te krijgen.<br><br><small>(%1)</small></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... |
| 5513 | This may take up to a minute depending | 5534 | This may take up to a minute depending |
| 5514 | on your system's performance.</source> | 5535 | on your system's performance.</source> |
| 5515 | <translation>Dit zal misschien een paar minuten duren gebaseerd | 5536 | <translation>Sleutels afleiden... |
| 5516 | op je systeem's performatie.</translation> | 5537 | Dit kan tot een minuut duren, |
| 5538 | afhankelijk 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'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's performatie.</translation> | |||
| 5554 | Would you like to bypass this and exit anyway?</source> | 5576 | Would 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 | ||
| 5557 | Wilt u dit omzeilen en toch afsluiten?</translation> | 5579 | Wil 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.<br><br>GL Renderer:<br>%1</source> | 5618 | <source>Your GPU may not support OpenGL 4.6, or you do not have the latest graphics driver.<br><br>GL Renderer:<br>%1</source> |
| 5597 | <translation type="unfinished"/> | 5619 | <translation>Je GPU ondersteunt mogelijk OpenGL 4.6 niet, of je hebt niet het laatste grafische stuurprogramma.<br><br>GL Renderer:<br>%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.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%2</source> | 5623 | <source>Your GPU may not support one or more required OpenGL extensions. Please ensure you have the latest graphics driver.<br><br>GL Renderer:<br>%1<br><br>Unsupported extensions:<br>%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.<br><br>GL Renderer:<br>%1<br><br>Ondersteunde extensies:<br>%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'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't Boot</source> | 5840 | <source>Won'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 -> Configure -> 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 -> Configure -> Web. If you do not want to publish a room in the public lobby, then select Unlisted instead. |
| 5941 | Debug Message: </source> | 5963 | Debug 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 -> Configuratie -> Web. Als je geen kamer wilt publiceren in de openbare lobby, selecteer dan in plaats daarvan Niet Vermeld. |
| 5965 | Debug-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>&Recent Files</source> | 6276 | <source>&Recent Files</source> |
| 6253 | <translation type="unfinished"/> | 6277 | <translation>&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>&Reset Window Size</source> | 6291 | <source>&Reset Window Size</source> |
| 6268 | <translation type="unfinished"/> | 6292 | <translation>&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>&Debugging</source> | 6296 | <source>&Debugging</source> |
| 6273 | <translation type="unfinished"/> | 6297 | <translation>&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 &720p</source> | 6301 | <source>Reset Window Size to &720p</source> |
| 6278 | <translation type="unfinished"/> | 6302 | <translation>Herstel Venstergrootte naar &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 &900p</source> | 6311 | <source>Reset Window Size to &900p</source> |
| 6288 | <translation type="unfinished"/> | 6312 | <translation>Herstel Venstergrootte naar &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 &1080p</source> | 6321 | <source>Reset Window Size to &1080p</source> |
| 6298 | <translation type="unfinished"/> | 6322 | <translation>Herstel Venstergrootte naar &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>&Multiplayer</source> | 6331 | <source>&Multiplayer</source> |
| 6308 | <translation type="unfinished"/> | 6332 | <translation>&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>&Tools</source> | 6336 | <source>&Tools</source> |
| 6313 | <translation type="unfinished"/> | 6337 | <translation>&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>&TAS</source> | 6341 | <source>&TAS</source> |
| 6318 | <translation type="unfinished"/> | 6342 | <translation>&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>&Install Files to NAND...</source> | 6351 | <source>&Install Files to NAND...</source> |
| 6328 | <translation type="unfinished"/> | 6352 | <translation>&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&oad File...</source> | 6356 | <source>L&oad File...</source> |
| 6333 | <translation type="unfinished"/> | 6357 | <translation>L&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 &Folder...</source> | 6361 | <source>Load &Folder...</source> |
| 6338 | <translation type="unfinished"/> | 6362 | <translation>Laad &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>&Pause</source> | 6371 | <source>&Pause</source> |
| 6348 | <translation>&Pauzeren</translation> | 6372 | <translation>&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>&Reinitialize keys...</source> | 6381 | <source>&Reinitialize keys...</source> |
| 6358 | <translation type="unfinished"/> | 6382 | <translation>&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>&About yuzu</source> | 6386 | <source>&About yuzu</source> |
| 6363 | <translation type="unfinished"/> | 6387 | <translation>&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 &Window Mode</source> | 6391 | <source>Single &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&figure...</source> | 6396 | <source>Con&figure...</source> |
| 6373 | <translation type="unfinished"/> | 6397 | <translation>Con&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&ock Widget Headers</source> | 6401 | <source>Display D&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 &Filter Bar</source> | 6406 | <source>Show &Filter Bar</source> |
| 6383 | <translation type="unfinished"/> | 6407 | <translation>Toon &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 &Status Bar</source> | 6411 | <source>Show &Status Bar</source> |
| 6388 | <translation type="unfinished"/> | 6412 | <translation>Toon &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>&Browse Public Game Lobby</source> | 6421 | <source>&Browse Public Game Lobby</source> |
| 6398 | <translation type="unfinished"/> | 6422 | <translation>&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>&Create Room</source> | 6426 | <source>&Create Room</source> |
| 6403 | <translation type="unfinished"/> | 6427 | <translation>&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>&Leave Room</source> | 6431 | <source>&Leave Room</source> |
| 6408 | <translation type="unfinished"/> | 6432 | <translation>&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>&Direct Connect to Room</source> | 6436 | <source>&Direct Connect to Room</source> |
| 6413 | <translation type="unfinished"/> | 6437 | <translation>&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>&Show Current Room</source> | 6441 | <source>&Show Current Room</source> |
| 6418 | <translation type="unfinished"/> | 6442 | <translation>&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&ullscreen</source> | 6446 | <source>F&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>&Restart</source> | 6451 | <source>&Restart</source> |
| 6428 | <translation type="unfinished"/> | 6452 | <translation>&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 &Amiibo...</source> | 6456 | <source>Load/Remove &Amiibo...</source> |
| 6433 | <translation type="unfinished"/> | 6457 | <translation>Laad/Verwijder &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>&Report Compatibility</source> | 6461 | <source>&Report Compatibility</source> |
| 6438 | <translation type="unfinished"/> | 6462 | <translation>&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 &Mods Page</source> | 6466 | <source>Open &Mods Page</source> |
| 6443 | <translation type="unfinished"/> | 6467 | <translation>Open &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 &Quickstart Guide</source> | 6471 | <source>Open &Quickstart Guide</source> |
| 6448 | <translation type="unfinished"/> | 6472 | <translation>Open &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>&FAQ</source> | 6476 | <source>&FAQ</source> |
| 6453 | <translation type="unfinished"/> | 6477 | <translation>&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 &yuzu Folder</source> | 6481 | <source>Open &yuzu Folder</source> |
| 6458 | <translation type="unfinished"/> | 6482 | <translation>Open &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>&Capture Screenshot</source> | 6486 | <source>&Capture Screenshot</source> |
| 6463 | <translation type="unfinished"/> | 6487 | <translation>&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>&Configure TAS...</source> | 6491 | <source>&Configure TAS...</source> |
| 6468 | <translation type="unfinished"/> | 6492 | <translation>&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&urrent Game...</source> | 6496 | <source>Configure C&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>&Reset</source> | 6506 | <source>&Reset</source> |
| 6483 | <translation type="unfinished"/> | 6507 | <translation>&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&ecord</source> | 6511 | <source>R&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>&MicroProfile</source> | 6519 | <source>&MicroProfile</source> |
| 6496 | <translation type="unfinished"/> | 6520 | <translation>&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. |
| 6583 | Debug Message: </source> | 6607 | Debug 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. |
| 6609 | Debug-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. |
| 6682 | They may have left the room.</source> | 6707 | They may have left the room.</source> |
| 6683 | <translation type="unfinished"/> | 6708 | <translation>De gebruiker die je probeert te kicken/bannen kon niet gevonden worden. |
| 6709 | Ze 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. |
| 6688 | Please go to Configure -> System -> Network and make a selection.</source> | 6714 | Please go to Configure -> System -> Network and make a selection.</source> |
| 6689 | <translation type="unfinished"/> | 6715 | <translation>Er is geen geldige netwerkinterface geselecteerd. |
| 6716 | Ga naar Configuratie -> Systeem -> 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. |
| 6699 | Proceed anyway?</source> | 6726 | Proceed 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. |
| 6728 | Toch 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> | |||
| 6754 | p, li { white-space: pre-wrap; } | 6782 | p, li { white-space: pre-wrap; } |
| 6755 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;"> | 6783 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;"> |
| 6756 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></source> | 6784 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></source> |
| 6757 | <translation type="unfinished"/> | 6785 | <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> |
| 6786 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> | ||
| 6787 | p, li { white-space: pre-wrap; } | ||
| 6788 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;"> | ||
| 6789 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></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. |
| 7554 | Please try again or contact the developer of the software.</source> | 7586 | Please try again or contact the developer of the software.</source> |
| 7555 | <translation type="unfinished"/> | 7587 | <translation>Er is een fout opgetreden. |
| 7588 | Probeer 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. |
| 7560 | Please try again or contact the developer of the software.</source> | 7593 | Please 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. |
| 7595 | Probeer 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> | |||
| 7676 | p, li { white-space: pre-wrap; } | 7714 | p, li { white-space: pre-wrap; } |
| 7677 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> | 7715 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> |
| 7678 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></source> | 7716 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></source> |
| 7679 | <translation type="unfinished"/> | 7717 | <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> |
| 7718 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> | ||
| 7719 | p, li { white-space: pre-wrap; } | ||
| 7720 | </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> | ||
| 7721 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></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>&Wait Tree</source> | 7879 | <source>&Wait Tree</source> |
| 7838 | <translation type="unfinished"/> | 7880 | <translation>&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 | <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> | 551 | <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> |
| 552 | </source> | 552 | </source> |
| 553 | <translation> | 553 | <translation> |
| 554 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, ÑƒÐ¼ÐµÐ½ÑŒÑˆÐ°Ñ Ñ‚Ð¾Ñ‡Ð½Ð¾Ñть Ñложенных умноженных инÑтрукций на ЦП без поддержки FMA.</div> | 554 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть за Ñчет ÑÐ½Ð¸Ð¶ÐµÐ½Ð¸Ñ Ñ‚Ð¾Ñ‡Ð½Ð¾Ñти инÑтрукций fused-multiply-add на ЦП без вÑтроенной поддержки FMA.</div> |
| 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 | <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> | 565 | <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> |
| 566 | </source> | 566 | </source> |
| 567 | <translation> | 567 | <translation> |
| 568 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть некоторых аппрокÑимирующих функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой за Ñчет иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼ÐµÐ½ÐµÐµ точных нативных приближений.</div> | 568 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть некоторых приближенных функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой за Ñчет иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼ÐµÐ½ÐµÐµ точных нативных приближений</div> |
| 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 | <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> | 579 | <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> |
| 580 | </source> | 580 | </source> |
| 581 | <translation> | 581 | <translation> |
| 582 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐ°ÐµÑ‚ ÑкороÑть 32-битных ASIMD-функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ запÑтой путём работы Ñ Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ñ‹Ð¼Ð¸ режимами округлениÑ.</div> | 582 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть работы 32-битных ASIMD-функций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ запÑтой, Ñ€Ð°Ð±Ð¾Ñ‚Ð°Ñ Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ режимами округлениÑ.</div> |
| 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 | <div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div> | 593 | <div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div> |
| 594 | </source> | 594 | </source> |
| 595 | <translation> | 595 | <translation> |
| 596 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, ÑƒÐ±Ð¸Ñ€Ð°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÑƒ на NaN. Обратите внимание, что Ñто также Ñнижает точноÑть некоторых инÑтрукций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой.</div> | 596 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, удалÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÑƒ NaN. Обратите внимание, что Ñто также Ñнижает точноÑть некоторых инÑтрукций Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой.</div> |
| 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 | <div>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.</div> | 607 | <div>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.</div> |
| 608 | </source> | 608 | </source> |
| 609 | <translation type="unfinished"/> | 609 | <translation> |
| 610 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть за Ñчет иÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ безопаÑноÑти перед каждым чтением/запиÑью памÑти в гоÑтевом режиме. Отключение Ñтой опции может позволить игре читать/запиÑывать памÑть ÑмулÑтора. | ||
| 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 | <div>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.</div> | 621 | <div>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.</div> |
| 620 | </source> | 622 | </source> |
| 621 | <translation type="unfinished"/> | 623 | <translation> |
| 624 | <div>Ðта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐ°ÐµÑ‚ ÑкороÑть, полагаÑÑÑŒ только на Ñемантику cmpxchg Ð´Ð»Ñ Ð¾Ð±ÐµÑÐ¿ÐµÑ‡ÐµÐ½Ð¸Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑти инÑтрукций иÑключительного доÑтупа. Обратите внимание, что Ñто может привеÑти к полным завиÑаниÑм и другим уÑловиÑм гонки.</div> | ||
| 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 | <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> | 664 | <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> |
| 661 | <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> | 665 | <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> |
| 662 | </source> | 666 | </source> |
| 663 | <translation type="unfinished"/> | 667 | <translation> |
| 668 | <div style="white-space: nowrap">Ðта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет доÑтуп гоÑтевой программы к памÑти.</div> | ||
| 669 | <div style="white-space: nowrap"> Включение Ñтой оптимизации вÑтраивает доÑтуп к указателÑм PageTable::pointers в Ñмулируемый код.</div> | ||
| 670 | <div style="white-space: nowrap">Отключение Ñтой функции заÑтавлÑет вÑе Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº памÑти проходить через функции Memory::Read/Memory::Write.</div> | ||
| 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 | <div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div> | 681 | <div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div> |
| 674 | </source> | 682 | </source> |
| 675 | <translation type="unfinished"/> | 683 | <translation> |
| 684 | <div>Ðта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет избежать поиÑка диÑпетчера, позволÑÑ Ñмитированным базовым блокам переходить непоÑредÑтвенно к другим базовым блокам, еÑли конечный ПК Ñтатичен.</div> | ||
| 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 | <div>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.</div> | 695 | <div>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.</div> |
| 686 | </source> | 696 | </source> |
| 687 | <translation type="unfinished"/> | 697 | <translation> |
| 698 | <div>Ðта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет избежать поиÑка диÑпетчера, отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ñ Ð¿Ð¾Ñ‚ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ñ‹Ðµ адреÑа возврата инÑтрукций BL. Ðто приближено к тому, что проиÑходит Ñ Ð±ÑƒÑ„ÐµÑ€Ð¾Ð¼ Ñтека возврата на реальном ЦП.</div> | ||
| 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 | <div>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.</div> | 709 | <div>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.</div> |
| 698 | </source> | 710 | </source> |
| 699 | <translation type="unfinished"/> | 711 | <translation> |
| 712 | <div>Включите двухуровневую ÑиÑтему диÑпетчеризации. Сначала иÑпользуетÑÑ Ð±Ð¾Ð»ÐµÐµ быÑтрый диÑпетчер, напиÑанный на аÑÑемблере и имеющий небольшой кÑш MRU Ð´Ð»Ñ Ð¼ÐµÑÑ‚ Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ð¾Ð². ЕÑли он не ÑправлÑетÑÑ, диÑÐ¿ÐµÑ‚Ñ‡ÐµÑ€Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ÑÑ Ðº более медленному диÑпетчеру на C++.</div> | ||
| 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 | <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> | 723 | <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> |
| 710 | </source> | 724 | </source> |
| 711 | <translation type="unfinished"/> | 725 | <translation> |
| 726 | <div>Включает IR-оптимизацию, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑƒÐ¼ÐµÐ½ÑŒÑˆÐ°ÐµÑ‚ ненужные Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº Ñтруктуре контекÑта ЦП.</div> | ||
| 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 | <div>Enables IR optimizations that involve constant propagation.</div> | 737 | <div>Enables IR optimizations that involve constant propagation.</div> |
| 722 | </source> | 738 | </source> |
| 723 | <translation type="unfinished"/> | 739 | <translation> |
| 740 | <div>Включает IR-оптимизацию, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²ÐºÐ»ÑŽÑ‡Ð°ÐµÑ‚ раÑпроÑтранение конÑтант.</div> | ||
| 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 | <div>Enables miscellaneous IR optimizations.</div> | 751 | <div>Enables miscellaneous IR optimizations.</div> |
| 734 | </source> | 752 | </source> |
| 735 | <translation type="unfinished"/> | 753 | <translation> |
| 754 | <div>Включает различные IR-оптимизации.</div> | ||
| 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 | <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> | 765 | <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> |
| 746 | <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> | 766 | <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> |
| 747 | </source> | 767 | </source> |
| 748 | <translation type="unfinished"/> | 768 | <translation> |
| 769 | <div style="white-space: nowrap">ЕÑли Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, Ñмещение Ñрабатывает только тогда, когда доÑтуп переÑекает границу Ñтраницы.</div> | ||
| 770 | <div style="white-space: nowrap">ЕÑли отключено, Ñмещение Ñрабатывает при вÑех Ñмещенных доÑтупах.</div> | ||
| 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 | <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> | 782 | <div style="white-space: nowrap">Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.</div> |
| 760 | <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> | 783 | <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> |
| 761 | </source> | 784 | </source> |
| 762 | <translation type="unfinished"/> | 785 | <translation> |
| 786 | <div style="white-space: nowrap">Ðта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет доÑтуп гоÑтевой программы к памÑти.</div> | ||
| 787 | <div style="white-space: nowrap"> Включение Ñтой оптимизации приводит к тому, что чтение/запиÑÑŒ гоÑтевой памÑти производитÑÑ Ð½ÐµÐ¿Ð¾ÑредÑтвенно в памÑть и иÑпользует MMU хоÑта.</div> | ||
| 788 | <div style="white-space: nowrap">Отключение Ñтой функции заÑтавлÑет вÑе Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº памÑти иÑпользовать программную ÑмулÑцию MMU.</div> | ||
| 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 | <div style="white-space: nowrap">Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.</div> | 800 | <div style="white-space: nowrap">Enabling it causes guest exclusive memory reads/writes to be done directly into memory and make use of Host's MMU.</div> |
| 774 | <div style="white-space: nowrap">Disabling this forces all exclusive memory accesses to use Software MMU Emulation.</div> | 801 | <div style="white-space: nowrap">Disabling this forces all exclusive memory accesses to use Software MMU Emulation.</div> |
| 775 | </source> | 802 | </source> |
| 776 | <translation type="unfinished"/> | 803 | <translation> |
| 804 | <div style="white-space: nowrap">Ðта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет доÑтуп гоÑтевой программы к ÑкÑклюзивной памÑти.</div> | ||
| 805 | <div style="white-space: nowrap">Включение Ñтой оптимизации приводит к тому, что чтение/запиÑÑŒ в ÑкÑклюзивную памÑть гоÑÑ‚Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð½ÐµÐ¿Ð¾ÑредÑтвенно в памÑть и иÑпользует MMU хоÑта.</div> | ||
| 806 | <div style="white-space: nowrap"> Отключение Ñтой функции заÑтавлÑет вÑе ÑкÑклюзивные доÑтупы к памÑти иÑпользовать ÑмулÑцию программного MMU.</div> | ||
| 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 | <div style="white-space: nowrap">This optimization speeds up exclusive memory accesses by the guest program.</div> | 817 | <div style="white-space: nowrap">This optimization speeds up exclusive memory accesses by the guest program.</div> |
| 787 | <div style="white-space: nowrap">Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.</div> | 818 | <div style="white-space: nowrap">Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.</div> |
| 788 | </source> | 819 | </source> |
| 789 | <translation type="unfinished"/> | 820 | <translation> |
| 821 | <div style="white-space: nowrap">Ðта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет обращение гоÑтевой программы к иÑключительной памÑти.</div> | ||
| 822 | <div style="white-space: nowrap">Ее включение Ñнижает накладные раÑходы, ÑвÑзанные Ñ Ð¾Ñ‚ÐºÐ°Ð·Ð¾Ð¼ fastmem при доÑтупе к иÑключительной памÑти.</div> | ||
| 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 | <div style="white-space: nowrap">This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.</div> | 833 | <div style="white-space: nowrap">This optimization speeds up memory accesses by allowing invalid memory accesses to succeed.</div> |
| 800 | <div style="white-space: nowrap">Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.</div> | 834 | <div style="white-space: nowrap">Enabling it reduces the overhead of all memory accesses and has no impact on programs that don't access invalid memory.</div> |
| 801 | </source> | 835 | </source> |
| 802 | <translation type="unfinished"/> | 836 | <translation> |
| 837 | <div style="white-space: nowrap">Ðта Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑƒÑкорÑет обращение к памÑти, позволÑÑ ÑƒÑпешное обращение к недопуÑтимой памÑти.</div> | ||
| 838 | <div style="white-space: nowrap">Включение Ñтой оптимизации Ñнижает накладные раÑходы на вÑе Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº памÑти и не влиÑет на программы, которые не обращаютÑÑ Ðº недопуÑтимой памÑти.</div> | ||
| 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><html><head/><body><p>Does the game boot?</p></body></html></source> | 244 | <source><html><head/><body><p>Does the game boot?</p></body></html></source> |
| 245 | <translation type="unfinished"/> | 245 | <translation><html><head/><body><p>Startar Spelet? </p></body></html></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't get past the "Launching..." screen</source> | 254 | <source>No The game doesn't get past the "Launching..." screen</source> |
| 255 | <translation type="unfinished"/> | 255 | <translation>Nej Spelet öppnar ej förbi "Startar..." 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.</div> | |||
| 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.</div> | |||
| 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>Розширене ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ð¼'Ñті (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 | |||
| 23 | namespace AudioCore::Sink { | 14 | namespace 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 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | // Forward declare implementation class for Node. | ||
| 12 | namespace impl { | ||
| 13 | |||
| 14 | class IntrusiveListImpl; | ||
| 15 | |||
| 16 | } | ||
| 17 | |||
| 18 | class IntrusiveListNode { | ||
| 19 | YUZU_NON_COPYABLE(IntrusiveListNode); | ||
| 20 | |||
| 21 | private: | ||
| 22 | friend class impl::IntrusiveListImpl; | ||
| 23 | |||
| 24 | IntrusiveListNode* m_prev; | ||
| 25 | IntrusiveListNode* m_next; | ||
| 26 | |||
| 27 | public: | ||
| 28 | constexpr IntrusiveListNode() : m_prev(this), m_next(this) {} | ||
| 29 | |||
| 30 | constexpr bool IsLinked() const { | ||
| 31 | return m_next != this; | ||
| 32 | } | ||
| 33 | |||
| 34 | private: | ||
| 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 | |||
| 96 | namespace impl { | ||
| 97 | |||
| 98 | class IntrusiveListImpl { | ||
| 99 | YUZU_NON_COPYABLE(IntrusiveListImpl); | ||
| 100 | |||
| 101 | private: | ||
| 102 | IntrusiveListNode m_root_node; | ||
| 103 | |||
| 104 | public: | ||
| 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 | |||
| 180 | public: | ||
| 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 | |||
| 288 | private: | ||
| 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 | |||
| 303 | template <class T, class Traits> | ||
| 304 | class IntrusiveList { | ||
| 305 | YUZU_NON_COPYABLE(IntrusiveList); | ||
| 306 | |||
| 307 | private: | ||
| 308 | impl::IntrusiveListImpl m_impl; | ||
| 309 | |||
| 310 | public: | ||
| 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 | |||
| 393 | private: | ||
| 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 | |||
| 410 | public: | ||
| 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 | |||
| 538 | template <auto T, class Derived = Common::impl::GetParentType<T>> | ||
| 539 | class IntrusiveListMemberTraits; | ||
| 540 | |||
| 541 | template <class Parent, IntrusiveListNode Parent::*Member, class Derived> | ||
| 542 | class IntrusiveListMemberTraits<Member, Derived> { | ||
| 543 | public: | ||
| 544 | using ListType = IntrusiveList<Derived, IntrusiveListMemberTraits>; | ||
| 545 | |||
| 546 | private: | ||
| 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 | |||
| 566 | template <auto T, class Derived = Common::impl::GetParentType<T>> | ||
| 567 | class IntrusiveListMemberTraitsByNonConstexprOffsetOf; | ||
| 568 | |||
| 569 | template <class Parent, IntrusiveListNode Parent::*Member, class Derived> | ||
| 570 | class IntrusiveListMemberTraitsByNonConstexprOffsetOf<Member, Derived> { | ||
| 571 | public: | ||
| 572 | using ListType = IntrusiveList<Derived, IntrusiveListMemberTraitsByNonConstexprOffsetOf>; | ||
| 573 | |||
| 574 | private: | ||
| 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 | |||
| 600 | template <class Derived> | ||
| 601 | class IntrusiveListBaseNode : public IntrusiveListNode {}; | ||
| 602 | |||
| 603 | template <class Derived> | ||
| 604 | class IntrusiveListBaseTraits { | ||
| 605 | public: | ||
| 606 | using ListType = IntrusiveList<Derived, IntrusiveListBaseTraits>; | ||
| 607 | |||
| 608 | private: | ||
| 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 | ||
| 17 | namespace Settings { | 17 | namespace Settings { |
| 18 | 18 | ||
| 19 | enum class VSyncMode : u32 { | ||
| 20 | Immediate = 0, | ||
| 21 | Mailbox = 1, | ||
| 22 | FIFO = 2, | ||
| 23 | FIFORelaxed = 3, | ||
| 24 | }; | ||
| 25 | |||
| 19 | enum class RendererBackend : u32 { | 26 | enum 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 | ||
| 615 | size_t System::GetCurrentHostThreadID() const { | ||
| 616 | return impl->kernel.GetCurrentHostThreadID(); | ||
| 617 | } | ||
| 618 | |||
| 614 | PerfStatsResults System::GetAndResetPerfStats() { | 619 | PerfStatsResults 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 | ||
| 59 | std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { | 60 | std::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 | ||
| 68 | VectorVfsDirectory::~VectorVfsDirectory() = default; | 68 | VectorVfsDirectory::~VectorVfsDirectory() = default; |
| 69 | 69 | ||
| 70 | VirtualFile 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 | |||
| 70 | std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const { | 87 | std::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 | ||
| 109 | bool VectorVfsDirectory::DeleteFile(std::string_view file_name) { | 126 | bool 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 | ||
| 126 | void VectorVfsDirectory::AddFile(VirtualFile file) { | 144 | void 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 | ||
| 15 | void DefaultCabinetApplet::ShowCabinetApplet( | 15 | void 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 | ||
| 10 | namespace Service::NFP { | 10 | namespace Service::NFC { |
| 11 | class NfpDevice; | 11 | class NfcDevice; |
| 12 | } // namespace Service::NFP | 12 | } // namespace Service::NFC |
| 13 | 13 | ||
| 14 | namespace Core::Frontend { | 14 | namespace 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 | ||
| 32 | class DefaultCabinetApplet final : public CabinetApplet { | 32 | class DefaultCabinetApplet final : public CabinetApplet { |
| 33 | public: | 33 | public: |
| 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() { | |||
| 551 | void EmulatedController::DisableSystemButtons() { | 552 | void 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 | ||
| 556 | void EmulatedController::ResetSystemButtons() { | 559 | void EmulatedController::ResetSystemButtons() { |
| @@ -685,6 +688,12 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage | |||
| 685 | ReloadInput(); | 688 | ReloadInput(); |
| 686 | } | 689 | } |
| 687 | 690 | ||
| 691 | void EmulatedController::StartMotionCalibration() { | ||
| 692 | for (ControllerMotionInfo& motion : controller.motion_values) { | ||
| 693 | motion.emulated.Calibrate(); | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 688 | void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, | 697 | void 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 | ||
| 1617 | MotionState EmulatedController::GetMotions() const { | 1624 | MotionState 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 | ||
| 1697 | void EmulatedController::TurboButtonUpdate() { | 1691 | void 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 | ||
| 1701 | NpadButton EmulatedController::GetTurboButtonMask() const { | 1708 | NpadButton 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 | ||
| 420 | private: | 424 | private: |
| 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 | ||
| 62 | void 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 | |||
| 54 | void MotionInput::SetGyroBias(const Common::Vec3f& bias) { | 76 | void 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 | ||
| 116 | void MotionInput::Calibrate() { | ||
| 117 | calibration_mode = true; | ||
| 118 | calibration_counter = 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | void 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 |
| 96 | void MotionInput::UpdateOrientation(u64 elapsed_time) { | 131 | void MotionInput::UpdateOrientation(u64 elapsed_time) { |
| @@ -222,6 +257,26 @@ Common::Vec3f MotionInput::GetRotations() const { | |||
| 222 | return rotations; | 257 | return rotations; |
| 223 | } | 258 | } |
| 224 | 259 | ||
| 260 | Common::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 | |||
| 225 | void MotionInput::ResetOrientation() { | 280 | void 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 | ||
| 61 | private: | 67 | private: |
| 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 { | |||
| 35 | using namespace Common::Literals; | 35 | using namespace Common::Literals; |
| 36 | 36 | ||
| 37 | u32 GetMemorySizeForInit() { | 37 | u32 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 | ||
| 41 | Smc::MemoryArrangement GetMemoryArrangeForInit() { | 42 | Smc::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 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | 14 | ||
| 15 | class KEventInfo : public KSlabAllocated<KEventInfo>, public boost::intrusive::list_base_hook<> { | 15 | class KEventInfo : public KSlabAllocated<KEventInfo>, |
| 16 | public Common::IntrusiveListBaseNode<KEventInfo> { | ||
| 16 | public: | 17 | public: |
| 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 | ||
| 16 | class KObjectNameGlobalData; | 17 | class KObjectNameGlobalData; |
| 17 | 18 | ||
| 18 | class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> { | 19 | class KObjectName : public KSlabAllocated<KObjectName>, |
| 20 | public Common::IntrusiveListBaseNode<KObjectName> { | ||
| 19 | public: | 21 | public: |
| 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 | ||
| 44 | private: | 44 | private: |
| 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; | |||
| 27 | class KThread; | 27 | class KThread; |
| 28 | 28 | ||
| 29 | class KServerSession final : public KSynchronizationObject, | 29 | class 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 | ||
| 17 | class KSessionRequest final : public KSlabAllocated<KSessionRequest>, | 19 | class 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 | ||
| 22 | public: | 24 | public: |
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 { | |||
| 12 | class KSharedMemory; | 12 | class KSharedMemory; |
| 13 | 13 | ||
| 14 | class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>, | 14 | class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>, |
| 15 | public boost::intrusive::list_base_hook<> { | 15 | public Common::IntrusiveListBaseNode<KSharedMemoryInfo> { |
| 16 | 16 | ||
| 17 | public: | 17 | public: |
| 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); | |||
| 119 | Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel); | 119 | Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel); |
| 120 | 120 | ||
| 121 | class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, | 121 | class 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: | |||
| 138 | public: | 138 | public: |
| 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 | ||
| 752 | public: | 752 | public: |
| 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 | ||
| 840 | private: | 841 | private: |
| 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 | ||
| 16 | namespace Service::AM::Applets { | 16 | namespace 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 { | |||
| 19 | class System; | 19 | class System; |
| 20 | } // namespace Core | 20 | } // namespace Core |
| 21 | 21 | ||
| 22 | namespace Service::NFP { | 22 | namespace Service::NFC { |
| 23 | class NfpDevice; | 23 | class NfcDevice; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | namespace Service::AM::Applets { | 26 | namespace 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 | ||
| 17 | namespace Service::NFP::AmiiboCrypto { | 17 | namespace 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>; | |||
| 24 | struct HashSeed { | 24 | struct 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 | ||
| 36 | namespace Service::NFP { | 35 | namespace Service::NFC { |
| 37 | NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, | 36 | NfcDevice::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 | ||
| 57 | NfpDevice::~NfpDevice() { | 56 | NfcDevice::~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 | ||
| 67 | void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | 66 | void 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 | ||
| 110 | bool NfpDevice::LoadAmiibo(std::span<const u8> data) { | 109 | bool 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 | ||
| 140 | void NfpDevice::CloseAmiibo() { | 140 | void 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 | ||
| 154 | Kernel::KReadableEvent& NfpDevice::GetActivateEvent() const { | 155 | Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const { |
| 155 | return activate_event->GetReadableEvent(); | 156 | return activate_event->GetReadableEvent(); |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 158 | Kernel::KReadableEvent& NfpDevice::GetDeactivateEvent() const { | 159 | Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const { |
| 159 | return deactivate_event->GetReadableEvent(); | 160 | return deactivate_event->GetReadableEvent(); |
| 160 | } | 161 | } |
| 161 | 162 | ||
| 162 | void NfpDevice::Initialize() { | 163 | void 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 | ||
| 169 | void NfpDevice::Finalize() { | 171 | void 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 | ||
| 180 | Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { | 182 | Result 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 | ||
| 198 | Result NfpDevice::StopDetection() { | 200 | Result 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 | ||
| 219 | Result NfpDevice::Flush() { | 221 | Result 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); | 253 | Result 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 | ||
| 250 | Result NfpDevice::FlushDebug() { | 267 | Result 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 | ||
| 273 | Result NfpDevice::FlushWithBreak(BreakType break_type) { | 290 | Result 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 | |||
| 308 | Result 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 | ||
| 299 | Result NfpDevice::Mount(MountTarget mount_target_) { | 329 | Result 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 | |||
| 336 | Result 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 | ||
| 335 | Result NfpDevice::Unmount() { | 372 | Result 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 | ||
| 356 | Result NfpDevice::GetTagInfo(TagInfo& tag_info) const { | 393 | Result 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 | ||
| 375 | Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const { | 424 | Result 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 | |||
| 447 | Result 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 | |||
| 473 | Result 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 | |||
| 492 | Result 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 | ||
| 401 | Result NfpDevice::GetModelInfo(ModelInfo& model_info) const { | 518 | Result 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 | ||
| 421 | Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { | 538 | Result 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 | ||
| 453 | Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const { | 570 | Result 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 | ||
| 485 | Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { | 602 | Result 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 | ||
| 535 | Result NfpDevice::DeleteRegisterInfo() { | 653 | Result 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 | ||
| 567 | Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) { | 685 | Result 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 | ||
| 604 | Result NfpDevice::RestoreAmiibo() { | 722 | Result 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 | ||
| 623 | Result NfpDevice::Format() { | 741 | Result 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 | ||
| 638 | Result NfpDevice::OpenApplicationArea(u32 access_id) { | 756 | Result 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 | ||
| 667 | Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { | 785 | Result 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 | ||
| 693 | Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { | 811 | Result 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 | ||
| 726 | Result NfpDevice::SetApplicationArea(std::span<const u8> data) { | 841 | Result 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 | ||
| 770 | Result NfpDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) { | 885 | Result 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 | ||
| 787 | Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) { | 902 | Result 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 | ||
| 838 | Result NfpDevice::DeleteApplicationArea() { | 953 | Result 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 | ||
| 875 | Result NfpDevice::ExistApplicationArea(bool& has_application_area) { | 990 | Result 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 | ||
| 894 | Result NfpDevice::GetAll(NfpData& data) const { | 1009 | Result 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 | ||
| 942 | Result NfpDevice::SetAll(const NfpData& data) { | 1057 | Result 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 | ||
| 980 | Result NfpDevice::BreakTag(BreakType break_type) { | 1095 | Result 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 | ||
| 999 | Result NfpDevice::ReadBackupData() { | 1114 | Result NfcDevice::ReadBackupData(std::span<u8> data) const { |
| 1000 | // Not implemented | 1115 | // Not implemented |
| 1001 | return ResultSuccess; | 1116 | return ResultSuccess; |
| 1002 | } | 1117 | } |
| 1003 | 1118 | ||
| 1004 | Result NfpDevice::WriteBackupData() { | 1119 | Result NfcDevice::WriteBackupData(std::span<const u8> data) { |
| 1005 | // Not implemented | 1120 | // Not implemented |
| 1006 | return ResultSuccess; | 1121 | return ResultSuccess; |
| 1007 | } | 1122 | } |
| 1008 | 1123 | ||
| 1009 | Result NfpDevice::WriteNtf() { | 1124 | Result 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 | ||
| 1028 | u64 NfpDevice::GetHandle() const { | 1143 | NFP::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 | |||
| 1033 | u32 NfpDevice::GetApplicationAreaSize() const { | ||
| 1034 | return sizeof(ApplicationArea); | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | DeviceState NfpDevice::GetCurrentState() const { | ||
| 1038 | return device_state; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | Core::HID::NpadIdType NfpDevice::GetNpadId() const { | ||
| 1042 | return npad_id; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | AmiiboName 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 | ||
| 1061 | void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name) { | 1159 | void 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 | ||
| 1075 | AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const { | 1173 | NFP::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 | ||
| 1094 | u64 NfpDevice::RemoveVersionByte(u64 application_id) const { | 1192 | u64 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 | ||
| 1098 | void NfpDevice::UpdateSettingsCrc() { | 1196 | void 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 | ||
| 1112 | void NfpDevice::UpdateRegisterInfoCrc() { | 1210 | void 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 | 1235 | u64 NfcDevice::GetHandle() const { |
| 1236 | // Generate a handle based of the npad id | ||
| 1237 | return static_cast<u64>(npad_id); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | DeviceState NfcDevice::GetCurrentState() const { | ||
| 1241 | return device_state; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | Result 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 | |||
| 16 | namespace Kernel { | ||
| 17 | class KEvent; | ||
| 18 | class KReadableEvent; | ||
| 19 | } // namespace Kernel | ||
| 20 | |||
| 21 | namespace Core { | ||
| 22 | class System; | ||
| 23 | } // namespace Core | ||
| 24 | |||
| 25 | namespace Core::HID { | ||
| 26 | class EmulatedController; | ||
| 27 | enum class ControllerTriggerType; | ||
| 28 | enum class NpadIdType : u32; | ||
| 29 | } // namespace Core::HID | ||
| 30 | |||
| 31 | namespace Service::NFC { | ||
| 32 | class NfcDevice { | ||
| 33 | public: | ||
| 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 | |||
| 100 | private: | ||
| 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 | |||
| 14 | namespace Service::NFC { | ||
| 15 | |||
| 16 | DeviceManager::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 | |||
| 31 | DeviceManager ::~DeviceManager() { | ||
| 32 | service_context.CloseEvent(availability_change_event); | ||
| 33 | } | ||
| 34 | |||
| 35 | Result DeviceManager::Initialize() { | ||
| 36 | for (auto& device : devices) { | ||
| 37 | device->Initialize(); | ||
| 38 | } | ||
| 39 | is_initialized = true; | ||
| 40 | return ResultSuccess; | ||
| 41 | } | ||
| 42 | |||
| 43 | Result DeviceManager::Finalize() { | ||
| 44 | for (auto& device : devices) { | ||
| 45 | device->Finalize(); | ||
| 46 | } | ||
| 47 | is_initialized = false; | ||
| 48 | return ResultSuccess; | ||
| 49 | } | ||
| 50 | |||
| 51 | Result 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 | |||
| 69 | DeviceState 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 | |||
| 82 | Result 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 | |||
| 96 | Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const { | ||
| 97 | return availability_change_event->GetReadableEvent(); | ||
| 98 | } | ||
| 99 | |||
| 100 | Result 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 | |||
| 114 | Result 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 | |||
| 128 | Result 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 | |||
| 142 | Kernel::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 | |||
| 152 | Kernel::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 | |||
| 162 | Result 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 | |||
| 178 | Result 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 | |||
| 193 | Result 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 | |||
| 210 | Result 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 | |||
| 225 | Result 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 | |||
| 239 | Result 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 | |||
| 253 | Result 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 | |||
| 267 | Result 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 | |||
| 281 | Result 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 | |||
| 295 | Result 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 | |||
| 309 | Result 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 | |||
| 324 | Result 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 | |||
| 338 | Result 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 | |||
| 352 | Result 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 | |||
| 366 | u32 DeviceManager::GetApplicationAreaSize() const { | ||
| 367 | return sizeof(NFP::ApplicationArea); | ||
| 368 | } | ||
| 369 | |||
| 370 | Result 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 | |||
| 385 | Result 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 | |||
| 399 | Result 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 | |||
| 413 | Result 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 | |||
| 428 | Result 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 | |||
| 443 | Result 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 | |||
| 457 | Result 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 | |||
| 471 | Result 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 | |||
| 485 | Result 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 | |||
| 499 | Result 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 | |||
| 513 | Result 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 | |||
| 527 | Result 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 | |||
| 541 | Result 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 | |||
| 555 | Result 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 | |||
| 569 | Result 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 | |||
| 583 | Result 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 | |||
| 610 | std::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 | |||
| 619 | const 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 | |||
| 628 | Result 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 | |||
| 636 | Result 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 | |||
| 662 | Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const { | ||
| 663 | if (device == nullptr) { | ||
| 664 | return ResultInvalidArgument; | ||
| 665 | } | ||
| 666 | |||
| 667 | return ResultSuccess; | ||
| 668 | } | ||
| 669 | |||
| 670 | Result 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 | |||
| 679 | Result 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 | |||
| 688 | Result 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 | |||
| 19 | namespace Service::NFC { | ||
| 20 | class NfcDevice; | ||
| 21 | |||
| 22 | class DeviceManager { | ||
| 23 | public: | ||
| 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 | |||
| 76 | private: | ||
| 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 | |||
| 8 | namespace Service::NFC::Mifare { | ||
| 9 | |||
| 10 | constexpr Result ResultDeviceNotFound(ErrorModule::NFCMifare, 64); | ||
| 11 | constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65); | ||
| 12 | constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73); | ||
| 13 | constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80); | ||
| 14 | constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97); | ||
| 15 | constexpr 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 | |||
| 11 | namespace Service::NFC { | ||
| 12 | |||
| 13 | enum 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 | |||
| 24 | using DataBlock = std::array<u8, 0x10>; | ||
| 25 | using KeyData = std::array<u8, 0x6>; | ||
| 26 | |||
| 27 | struct SectorKey { | ||
| 28 | MifareCmd command; | ||
| 29 | u8 unknown; // Usually 1 | ||
| 30 | INSERT_PADDING_BYTES(0x6); | ||
| 31 | KeyData sector_key; | ||
| 32 | INSERT_PADDING_BYTES(0x2); | ||
| 33 | }; | ||
| 34 | static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); | ||
| 35 | |||
| 36 | // This is nn::nfc::MifareReadBlockParameter | ||
| 37 | struct MifareReadBlockParameter { | ||
| 38 | u8 sector_number; | ||
| 39 | INSERT_PADDING_BYTES(0x7); | ||
| 40 | SectorKey sector_key; | ||
| 41 | }; | ||
| 42 | static_assert(sizeof(MifareReadBlockParameter) == 0x18, | ||
| 43 | "MifareReadBlockParameter is an invalid size"); | ||
| 44 | |||
| 45 | // This is nn::nfc::MifareReadBlockData | ||
| 46 | struct MifareReadBlockData { | ||
| 47 | DataBlock data; | ||
| 48 | u8 sector_number; | ||
| 49 | INSERT_PADDING_BYTES(0x7); | ||
| 50 | }; | ||
| 51 | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); | ||
| 52 | |||
| 53 | // This is nn::nfc::MifareWriteBlockParameter | ||
| 54 | struct MifareWriteBlockParameter { | ||
| 55 | DataBlock data; | ||
| 56 | u8 sector_number; | ||
| 57 | INSERT_PADDING_BYTES(0x7); | ||
| 58 | SectorKey sector_key; | ||
| 59 | }; | ||
| 60 | static_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 | |||
| 13 | namespace Service::NFC { | ||
| 14 | |||
| 15 | MFIUser::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 | |||
| 44 | MFIUser ::~MFIUser() { | ||
| 45 | availability_change_event->Close(); | ||
| 46 | } | ||
| 47 | |||
| 48 | void 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 | |||
| 61 | void 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 | |||
| 74 | void 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 | |||
| 120 | void 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 | |||
| 144 | void 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 | |||
| 168 | void 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 | |||
| 209 | void 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 | |||
| 253 | void 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 | |||
| 279 | void 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 | |||
| 303 | void 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 | |||
| 327 | void 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 | |||
| 335 | void 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 | |||
| 353 | void 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 | |||
| 377 | void 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 | |||
| 391 | std::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 | |||
| 13 | namespace Service::NFC { | ||
| 14 | class NfcDevice; | ||
| 15 | |||
| 16 | class MFIUser final : public ServiceFramework<MFIUser> { | ||
| 17 | public: | ||
| 18 | explicit MFIUser(Core::System& system_); | ||
| 19 | ~MFIUser(); | ||
| 20 | |||
| 21 | private: | ||
| 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 | ||
| 15 | namespace Service::NFC { | 14 | namespace Service::NFC { |
| 16 | 15 | ||
| 16 | class IUser final : public NfcInterface { | ||
| 17 | public: | ||
| 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 | |||
| 50 | class ISystem final : public NfcInterface { | ||
| 51 | public: | ||
| 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 | ||
| 90 | using MFInterface = NfcInterface; | ||
| 91 | class MFIUser final : public MFInterface { | ||
| 92 | public: | ||
| 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 | |||
| 17 | class IAm final : public ServiceFramework<IAm> { | 118 | class IAm final : public ServiceFramework<IAm> { |
| 18 | public: | 119 | public: |
| 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 | ||
| 44 | private: | 145 | private: |
| 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 | ||
| 66 | private: | 167 | private: |
| 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 | ||
| 88 | private: | 189 | private: |
| 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 | ||
| 98 | class ISystem final : public ServiceFramework<ISystem> { | ||
| 99 | public: | ||
| 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 | |||
| 135 | class NFC_SYS final : public ServiceFramework<NFC_SYS> { | 199 | class NFC_SYS final : public ServiceFramework<NFC_SYS> { |
| 136 | public: | 200 | public: |
| 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 | ||
| 147 | private: | 211 | private: |
| 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 | |||
| 16 | namespace Service::NFC { | ||
| 17 | NfcDevice::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 | |||
| 34 | NfcDevice::~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 | |||
| 44 | void 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 | |||
| 84 | bool 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 | |||
| 105 | void 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 | |||
| 114 | Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const { | ||
| 115 | return activate_event->GetReadableEvent(); | ||
| 116 | } | ||
| 117 | |||
| 118 | Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const { | ||
| 119 | return deactivate_event->GetReadableEvent(); | ||
| 120 | } | ||
| 121 | |||
| 122 | void 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 | |||
| 129 | void 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 | |||
| 138 | Result 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 | |||
| 157 | Result 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 | |||
| 180 | Result 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 | |||
| 198 | Result 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 | |||
| 229 | Result 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 | |||
| 253 | Result 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 | |||
| 275 | u64 NfcDevice::GetHandle() const { | ||
| 276 | // Generate a handle based of the npad id | ||
| 277 | return static_cast<u64>(npad_id); | ||
| 278 | } | ||
| 279 | |||
| 280 | NFP::DeviceState NfcDevice::GetCurrentState() const { | ||
| 281 | return device_state; | ||
| 282 | } | ||
| 283 | |||
| 284 | Core::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 | |||
| 11 | namespace Kernel { | ||
| 12 | class KEvent; | ||
| 13 | class KReadableEvent; | ||
| 14 | } // namespace Kernel | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | class System; | ||
| 18 | } // namespace Core | ||
| 19 | |||
| 20 | namespace Core::HID { | ||
| 21 | class EmulatedController; | ||
| 22 | enum class ControllerTriggerType; | ||
| 23 | enum class NpadIdType : u32; | ||
| 24 | } // namespace Core::HID | ||
| 25 | |||
| 26 | namespace Service::NFC { | ||
| 27 | class NfcDevice { | ||
| 28 | public: | ||
| 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 | |||
| 55 | private: | ||
| 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 | |||
| 19 | namespace Service::NFC { | ||
| 20 | |||
| 21 | NfcInterface::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 | |||
| 25 | NfcInterface ::~NfcInterface() = default; | ||
| 26 | |||
| 27 | void 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 | |||
| 43 | void 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 | |||
| 58 | void 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 | |||
| 66 | void 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 | |||
| 77 | void 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 | |||
| 98 | void 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 | |||
| 114 | void 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 | |||
| 134 | void 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 | |||
| 142 | void 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 | |||
| 155 | void 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 | |||
| 167 | void 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 | |||
| 185 | void 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 | |||
| 195 | void 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 | |||
| 205 | void 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 | |||
| 230 | void 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 | |||
| 250 | void 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 | |||
| 276 | std::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 | |||
| 283 | BackendType NfcInterface::GetBackendType() const { | ||
| 284 | return backend_type; | ||
| 285 | } | ||
| 286 | |||
| 287 | Result 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 | |||
| 312 | Result 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 | |||
| 362 | Result 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 | ||
| 13 | namespace Service::NFC { | 10 | namespace Service::NFC { |
| 14 | class NfcDevice; | 11 | class DeviceManager; |
| 15 | 12 | ||
| 16 | class IUser final : public ServiceFramework<IUser> { | 13 | class NfcInterface : public ServiceFramework<NfcInterface> { |
| 17 | public: | 14 | public: |
| 18 | explicit IUser(Core::System& system_); | 15 | explicit NfcInterface(Core::System& system_, const char* name, BackendType service_backend); |
| 19 | ~IUser(); | 16 | ~NfcInterface(); |
| 20 | |||
| 21 | private: | ||
| 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); | 35 | protected: |
| 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 | ||
| 8 | namespace Service::NFC { | 8 | namespace Service::NFC { |
| 9 | 9 | ||
| 10 | constexpr Result DeviceNotFound(ErrorModule::NFC, 64); | 10 | constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64); |
| 11 | constexpr Result InvalidArgument(ErrorModule::NFC, 65); | 11 | constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65); |
| 12 | constexpr Result WrongDeviceState(ErrorModule::NFC, 73); | 12 | constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68); |
| 13 | constexpr Result NfcDisabled(ErrorModule::NFC, 80); | 13 | constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73); |
| 14 | constexpr Result TagRemoved(ErrorModule::NFC, 97); | 14 | constexpr Result ResultUnknown74(ErrorModule::NFC, 74); |
| 15 | 15 | constexpr Result ResultUnknown76(ErrorModule::NFC, 76); | |
| 16 | constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64); | 16 | constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77); |
| 17 | constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65); | 17 | constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80); |
| 18 | constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73); | 18 | constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88); |
| 19 | constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80); | 19 | constexpr Result ResultTagRemoved(ErrorModule::NFC, 97); |
| 20 | constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97); | 20 | constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120); |
| 21 | constexpr Result MifareReadError(ErrorModule::NFCMifare, 288); | 21 | constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); |
| 22 | constexpr Result ResultCorruptedData(ErrorModule::NFP, 144); | ||
| 23 | constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152); | ||
| 24 | constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168); | ||
| 25 | constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178); | ||
| 26 | constexpr 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 | |||
| 11 | namespace Service::NFC { | ||
| 12 | enum class BackendType : u32 { | ||
| 13 | None, | ||
| 14 | Nfc, | ||
| 15 | Nfp, | ||
| 16 | Mifare, | ||
| 17 | }; | ||
| 18 | |||
| 19 | // This is nn::nfc::DeviceState | ||
| 20 | enum 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 | ||
| 31 | enum class State : u32 { | ||
| 32 | NonInitialized, | ||
| 33 | Initialized, | ||
| 34 | }; | ||
| 35 | |||
| 36 | // This is nn::nfc::TagType | ||
| 37 | enum 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 | |||
| 46 | enum 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 | ||
| 57 | enum 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 | ||
| 68 | enum class TestWaveType : u32 { | ||
| 69 | Unknown, | ||
| 70 | }; | ||
| 71 | |||
| 72 | using UniqueSerialNumber = std::array<u8, 7>; | ||
| 73 | using UniqueSerialNumberExtension = std::array<u8, 3>; | ||
| 74 | |||
| 75 | // This is nn::nfc::DeviceHandle | ||
| 76 | using DeviceHandle = u64; | ||
| 77 | |||
| 78 | // This is nn::nfc::TagInfo | ||
| 79 | struct 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 | }; | ||
| 88 | static_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 | |||
| 14 | namespace Service::NFC { | ||
| 15 | |||
| 16 | IUser::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 | |||
| 53 | IUser ::~IUser() { | ||
| 54 | availability_change_event->Close(); | ||
| 55 | } | ||
| 56 | |||
| 57 | void 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 | |||
| 70 | void 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 | |||
| 83 | void 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 | |||
| 91 | void 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 | |||
| 99 | void 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 | |||
| 145 | void 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 | |||
| 163 | void 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 | |||
| 187 | void 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 | |||
| 201 | void 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 | |||
| 226 | void 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 | |||
| 250 | void 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 | |||
| 276 | void 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 | |||
| 300 | void 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 | |||
| 324 | void 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 | |||
| 356 | std::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 { | |||
| 13 | public: | 13 | public: |
| 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 { | |||
| 50 | public: | 50 | public: |
| 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 { | |||
| 89 | public: | 89 | public: |
| 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 | ||
| 167 | class ISystemManager final : public ServiceFramework<ISystemManager> { | 161 | class 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 | ||
| 195 | class IDebugManager final : public ServiceFramework<IDebugManager> { | 183 | class 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 | ||
| 223 | void LoopProcess(Core::System& system) { | 205 | void 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 | |||
| 14 | namespace Kernel { | ||
| 15 | class KEvent; | ||
| 16 | class KReadableEvent; | ||
| 17 | } // namespace Kernel | ||
| 18 | |||
| 19 | namespace Core { | ||
| 20 | class System; | ||
| 21 | } // namespace Core | ||
| 22 | |||
| 23 | namespace Core::HID { | ||
| 24 | class EmulatedController; | ||
| 25 | enum class ControllerTriggerType; | ||
| 26 | enum class NpadIdType : u32; | ||
| 27 | } // namespace Core::HID | ||
| 28 | |||
| 29 | namespace Service::NFP { | ||
| 30 | class NfpDevice { | ||
| 31 | public: | ||
| 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 | |||
| 85 | private: | ||
| 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 | ||
| 13 | namespace Service::NFP { | 16 | namespace Service::NFP { |
| 14 | 17 | ||
| 15 | Interface::Interface(Core::System& system_, const char* name) | 18 | Interface::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++) { | 21 | Interface::~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 | |||
| 26 | Interface::~Interface() { | ||
| 27 | availability_change_event->Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | void 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 | ||
| 43 | void Interface::InitializeSystem(HLERequestContext& ctx) { | 23 | void 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 | ||
| 56 | void Interface::InitializeDebug(HLERequestContext& ctx) { | 27 | void 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 | |||
| 69 | void 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 | ||
| 82 | void Interface::FinalizeSystem(HLERequestContext& ctx) { | 31 | void 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 | ||
| 95 | void Interface::FinalizeDebug(HLERequestContext& ctx) { | 35 | void 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 | |||
| 108 | void 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 | |||
| 154 | void 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 | |||
| 179 | void 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 | ||
| 203 | void Interface::Mount(HLERequestContext& ctx) { | 39 | void 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 | |||
| 425 | void 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 | ||
| 529 | void 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 | |||
| 553 | void 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 | |||
| 577 | void 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 | |||
| 585 | void 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 | |||
| 603 | void 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 | |||
| 627 | void Interface::GetApplicationAreaSize(HLERequestContext& ctx) { | 204 | void 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 | |||
| 645 | void 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 | ||
| 659 | void Interface::RecreateApplicationArea(HLERequestContext& ctx) { | 214 | void 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) { | |||
| 686 | void Interface::Format(HLERequestContext& ctx) { | 229 | void 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) { | |||
| 762 | void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) { | 275 | void 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(®ister_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) { | |||
| 788 | void Interface::DeleteRegisterInfo(HLERequestContext& ctx) { | 291 | void 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) { | |||
| 812 | void Interface::DeleteApplicationArea(HLERequestContext& ctx) { | 303 | void 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) { | |||
| 836 | void Interface::ExistsApplicationArea(HLERequestContext& ctx) { | 315 | void 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) { | |||
| 862 | void Interface::GetAll(HLERequestContext& ctx) { | 335 | void 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) { | |||
| 890 | void Interface::SetAll(HLERequestContext& ctx) { | 352 | void 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) { | |||
| 919 | void Interface::FlushDebug(HLERequestContext& ctx) { | 368 | void 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) { | |||
| 968 | void Interface::ReadBackupData(HLERequestContext& ctx) { | 394 | void 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) { | |||
| 992 | void Interface::WriteBackupData(HLERequestContext& ctx) { | 411 | void 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) { | |||
| 1016 | void Interface::WriteNtf(HLERequestContext& ctx) { | 424 | void 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 | ||
| 1040 | std::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 | ||
| 13 | namespace Service::NFP { | 10 | namespace Service::NFP { |
| 14 | class NfpDevice; | ||
| 15 | 11 | ||
| 16 | class Interface : public ServiceFramework<Interface> { | 12 | class Interface : public NFC::NfcInterface { |
| 17 | public: | 13 | public: |
| 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 | |||
| 65 | private: | ||
| 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 | ||
| 8 | namespace Service::NFP { | 8 | namespace Service::NFP { |
| 9 | 9 | ||
| 10 | constexpr Result DeviceNotFound(ErrorModule::NFP, 64); | 10 | constexpr Result ResultDeviceNotFound(ErrorModule::NFP, 64); |
| 11 | constexpr Result InvalidArgument(ErrorModule::NFP, 65); | 11 | constexpr Result ResultInvalidArgument(ErrorModule::NFP, 65); |
| 12 | constexpr Result WrongApplicationAreaSize(ErrorModule::NFP, 68); | 12 | constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68); |
| 13 | constexpr Result WrongDeviceState(ErrorModule::NFP, 73); | 13 | constexpr Result ResultWrongDeviceState(ErrorModule::NFP, 73); |
| 14 | constexpr Result NfcDisabled(ErrorModule::NFP, 80); | 14 | constexpr Result ResultUnknown74(ErrorModule::NFC, 74); |
| 15 | constexpr Result WriteAmiiboFailed(ErrorModule::NFP, 88); | 15 | constexpr Result ResultNfcDisabled(ErrorModule::NFP, 80); |
| 16 | constexpr Result TagRemoved(ErrorModule::NFP, 97); | 16 | constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88); |
| 17 | constexpr Result RegistrationIsNotInitialized(ErrorModule::NFP, 120); | 17 | constexpr Result ResultTagRemoved(ErrorModule::NFP, 97); |
| 18 | constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); | 18 | constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120); |
| 19 | constexpr Result CorruptedData(ErrorModule::NFP, 144); | 19 | constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); |
| 20 | constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152); | 20 | constexpr Result ResultCorruptedData(ErrorModule::NFP, 144); |
| 21 | constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168); | 21 | constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152); |
| 22 | constexpr Result NotAnAmiibo(ErrorModule::NFP, 178); | 22 | constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168); |
| 23 | constexpr 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 | ||
| 11 | namespace Service::NFP { | 12 | namespace Service::NFP { |
| 12 | static constexpr std::size_t amiibo_name_length = 0xA; | 13 | static constexpr std::size_t amiibo_name_length = 0xA; |
| 13 | static constexpr std::size_t application_id_version_offset = 0x1c; | 14 | static constexpr std::size_t application_id_version_offset = 0x1c; |
| 14 | static constexpr std::size_t counter_limit = 0xffff; | 15 | static constexpr std::size_t counter_limit = 0xffff; |
| 15 | 16 | ||
| 16 | enum class ServiceType : u32 { | 17 | // This is nn::nfp::ModelType |
| 17 | User, | ||
| 18 | Debug, | ||
| 19 | System, | ||
| 20 | }; | ||
| 21 | |||
| 22 | enum class DeviceState : u32 { | ||
| 23 | Initialized, | ||
| 24 | SearchingForTag, | ||
| 25 | TagFound, | ||
| 26 | TagRemoved, | ||
| 27 | TagMounted, | ||
| 28 | Unavailable, | ||
| 29 | Finalized, | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum class ModelType : u32 { | 18 | enum class ModelType : u32 { |
| 33 | Amiibo, | 19 | Amiibo, |
| 34 | }; | 20 | }; |
| 35 | 21 | ||
| 22 | // This is nn::nfp::MountTarget | ||
| 36 | enum class MountTarget : u32 { | 23 | enum 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 | ||
| 75 | enum 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 | |||
| 84 | enum 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 | ||
| 94 | enum 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 | |||
| 104 | enum class AppAreaVersion : u8 { | 62 | enum 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 | ||
| 76 | enum class WriteType : u32 { | ||
| 77 | Unknown0, | ||
| 78 | Unknown1, | ||
| 79 | }; | ||
| 80 | |||
| 118 | enum class CabinetMode : u8 { | 81 | enum 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 | ||
| 125 | enum 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 | |||
| 136 | using UniqueSerialNumber = std::array<u8, 7>; | ||
| 137 | using LockBytes = std::array<u8, 2>; | 88 | using LockBytes = std::array<u8, 2>; |
| 138 | using HashData = std::array<u8, 0x20>; | 89 | using HashData = std::array<u8, 0x20>; |
| 139 | using ApplicationArea = std::array<u8, 0xD8>; | 90 | using ApplicationArea = std::array<u8, 0xD8>; |
| 140 | using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; | 91 | using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; |
| 141 | using DataBlock = std::array<u8, 0x10>; | 92 | |
| 142 | using KeyData = std::array<u8, 0x6>; | 93 | // This is nn::nfp::TagInfo |
| 94 | using TagInfo = NFC::TagInfo; | ||
| 143 | 95 | ||
| 144 | struct TagUuid { | 96 | struct 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 | }; |
| 249 | static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size"); | 201 | static_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), | |||
| 326 | static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>, | 278 | static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>, |
| 327 | "EncryptedNTAG215File must be trivially copyable."); | 279 | "EncryptedNTAG215File must be trivially copyable."); |
| 328 | 280 | ||
| 329 | struct 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 | }; | ||
| 338 | static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size"); | ||
| 339 | |||
| 340 | struct CommonInfo { | 282 | struct 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 | }; |
| 348 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); | 290 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); |
| 349 | 291 | ||
| 292 | // This is nn::nfp::ModelInfo | ||
| 350 | struct ModelInfo { | 293 | struct 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 | }; |
| 358 | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); | 301 | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); |
| 359 | 302 | ||
| 303 | // This is nn::nfp::RegisterInfo | ||
| 360 | struct RegisterInfo { | 304 | struct 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 | }; |
| 367 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | 311 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); |
| 368 | 312 | ||
| 313 | // This is nn::nfp::RegisterInfoPrivate | ||
| 369 | struct RegisterInfoPrivate { | 314 | struct 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 | }; |
| 376 | static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size"); | 321 | static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size"); |
| 377 | 322 | ||
| 323 | // This is nn::nfp::AdminInfo | ||
| 378 | struct AdminInfo { | 324 | struct 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 { | |||
| 420 | static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size"); | 366 | static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size"); |
| 421 | #pragma pack() | 367 | #pragma pack() |
| 422 | 368 | ||
| 423 | struct SectorKey { | ||
| 424 | MifareCmd command; | ||
| 425 | u8 unknown; // Usually 1 | ||
| 426 | INSERT_PADDING_BYTES(0x6); | ||
| 427 | KeyData sector_key; | ||
| 428 | INSERT_PADDING_BYTES(0x2); | ||
| 429 | }; | ||
| 430 | static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); | ||
| 431 | |||
| 432 | struct MifareReadBlockParameter { | ||
| 433 | u8 sector_number; | ||
| 434 | INSERT_PADDING_BYTES(0x7); | ||
| 435 | SectorKey sector_key; | ||
| 436 | }; | ||
| 437 | static_assert(sizeof(MifareReadBlockParameter) == 0x18, | ||
| 438 | "MifareReadBlockParameter is an invalid size"); | ||
| 439 | |||
| 440 | struct MifareReadBlockData { | ||
| 441 | DataBlock data; | ||
| 442 | u8 sector_number; | ||
| 443 | INSERT_PADDING_BYTES(0x7); | ||
| 444 | }; | ||
| 445 | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); | ||
| 446 | |||
| 447 | struct MifareWriteBlockParameter { | ||
| 448 | DataBlock data; | ||
| 449 | u8 sector_number; | ||
| 450 | INSERT_PADDING_BYTES(0x7); | ||
| 451 | SectorKey sector_key; | ||
| 452 | }; | ||
| 453 | static_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 | ||
| 219 | private: | 219 | private: |
| 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 | ||
| 38 | ServerManager::~ServerManager() { | 41 | ServerManager::~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> | |||
| 142 | class ServiceFramework : public ServiceFrameworkBase { | 142 | class ServiceFramework : public ServiceFrameworkBase { |
| 143 | protected: | 143 | protected: |
| 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() { | |||
| 356 | std::optional<IPv4Address> GetHostIPv4Address() { | 356 | std::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 | ||
| 21 | namespace Core::Memory { | 23 | namespace 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 | ||
| 88 | static 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 | |||
| 88 | u64 GetTelemetryId() { | 102 | u64 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 | ||
| 239 | DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, | 239 | DriverResult 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 { | |||
| 575 | static_assert(sizeof(NFCPollingCommandData) == 0x05, "NFCPollingCommandData is an invalid size"); | 575 | static_assert(sizeof(NFCPollingCommandData) == 0x05, "NFCPollingCommandData is an invalid size"); |
| 576 | 576 | ||
| 577 | struct NFCRequestState { | 577 | struct 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 | }; |
| 591 | static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size"); | 591 | static_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 | }; |
| 665 | static_assert(sizeof(SubCommandPacket) == 0x31, "SubCommandPacket is an invalid size"); | 668 | static_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 | ||
| 279 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output) { | 279 | DriverResult 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 | ||
| 303 | DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) { | 303 | DriverResult 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 | ||
| 320 | DriverResult NfcProtocol::SendStartWaitingRecieveRequest(MCUCommandResponse& output) { | 320 | DriverResult 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 | ||
| 337 | DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) { | 337 | DriverResult 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 | ||
| 362 | NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(NFCPages pages) const { | 362 | NFCReadBlockCommand 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 | ||
| 475 | void EmitSetSampleMask(EmitContext& ctx, Id value) { | 475 | void 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 | ||
| 479 | void EmitSetFragDepth(EmitContext& ctx, Id value) { | 480 | void 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 | |||
| 13 | namespace { | ||
| 14 | using VideoCommon::BufferBase; | ||
| 15 | using Range = std::pair<u64, u64>; | ||
| 16 | |||
| 17 | constexpr u64 PAGE = 4096; | ||
| 18 | constexpr u64 WORD = 4096 * 64; | ||
| 19 | |||
| 20 | constexpr VAddr c = 0x1328914000; | ||
| 21 | |||
| 22 | class RasterizerInterface { | ||
| 23 | public: | ||
| 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 | |||
| 53 | private: | ||
| 54 | std::unordered_map<u64, int> page_table; | ||
| 55 | }; | ||
| 56 | } // Anonymous namespace | ||
| 57 | |||
| 58 | TEST_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 | |||
| 70 | TEST_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 | |||
| 101 | TEST_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 | |||
| 116 | TEST_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 | |||
| 130 | TEST_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 | |||
| 141 | TEST_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 | |||
| 161 | TEST_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 | |||
| 181 | TEST_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 | |||
| 205 | TEST_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 | |||
| 226 | TEST_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 | |||
| 246 | TEST_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 | |||
| 266 | TEST_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 | |||
| 292 | TEST_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 | |||
| 303 | TEST_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 | |||
| 319 | TEST_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 | |||
| 333 | TEST_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 | |||
| 343 | TEST_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 | |||
| 358 | TEST_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 | |||
| 374 | TEST_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 | |||
| 382 | TEST_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 | |||
| 392 | TEST_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 | |||
| 414 | TEST_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 | |||
| 432 | TEST_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 | |||
| 442 | TEST_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 | |||
| 464 | TEST_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 | |||
| 475 | TEST_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 | |||
| 487 | TEST_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 | |||
| 502 | TEST_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 | |||
| 515 | TEST_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 | |||
| 530 | TEST_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 | |||
| 14 | namespace { | ||
| 15 | using Range = std::pair<u64, u64>; | ||
| 16 | |||
| 17 | constexpr u64 PAGE = 4096; | ||
| 18 | constexpr u64 WORD = 4096 * 64; | ||
| 19 | constexpr u64 HIGH_PAGE_BITS = 22; | ||
| 20 | constexpr u64 HIGH_PAGE_SIZE = 1ULL << HIGH_PAGE_BITS; | ||
| 21 | |||
| 22 | constexpr VAddr c = 16 * HIGH_PAGE_SIZE; | ||
| 23 | |||
| 24 | class RasterizerInterface { | ||
| 25 | public: | ||
| 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 | |||
| 55 | private: | ||
| 56 | std::unordered_map<u64, int> page_table; | ||
| 57 | }; | ||
| 58 | } // Anonymous namespace | ||
| 59 | |||
| 60 | using MemoryTracker = VideoCommon::MemoryTrackerBase<RasterizerInterface>; | ||
| 61 | |||
| 62 | TEST_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 | |||
| 74 | TEST_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 | |||
| 108 | TEST_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 | |||
| 123 | TEST_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 | |||
| 137 | TEST_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 | |||
| 148 | TEST_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 | |||
| 168 | TEST_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 | |||
| 188 | TEST_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 | |||
| 212 | TEST_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 | |||
| 233 | TEST_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 | |||
| 253 | TEST_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 | |||
| 273 | TEST_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 | |||
| 299 | TEST_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 | |||
| 310 | TEST_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 | |||
| 327 | TEST_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 | |||
| 341 | TEST_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 | |||
| 351 | TEST_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 | |||
| 366 | TEST_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 | |||
| 382 | TEST_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 | |||
| 390 | TEST_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 | |||
| 400 | TEST_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 | |||
| 422 | TEST_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 | |||
| 440 | TEST_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 | |||
| 462 | TEST_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 | |||
| 473 | TEST_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 | |||
| 485 | TEST_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 | |||
| 500 | TEST_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 | |||
| 513 | TEST_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 | |||
| 528 | TEST_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 | ||
| 12 | add_library(video_core STATIC | 12 | add_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 | ||
| 18 | namespace VideoCommon { | 16 | namespace VideoCommon { |
| 19 | 17 | ||
| 20 | enum class BufferFlagBits { | 18 | enum class BufferFlagBits { |
| 21 | Picked = 1 << 0, | 19 | Picked = 1 << 0, |
| 22 | CachedWrites = 1 << 1, | 20 | CachedWrites = 1 << 1, |
| 21 | PreemtiveDownload = 1 << 2, | ||
| 23 | }; | 22 | }; |
| 24 | DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits) | 23 | DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits) |
| 25 | 24 | ||
| @@ -36,116 +35,12 @@ struct NullBufferParams {}; | |||
| 36 | */ | 35 | */ |
| 37 | template <class RasterizerInterface> | 36 | template <class RasterizerInterface> |
| 38 | class BufferBase { | 37 | class 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 | |||
| 145 | public: | 38 | public: |
| 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 | ||
| 311 | private: | 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 | 119 | private: |
| 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 | ||
| 39 | namespace VideoCommon { | 10 | #include "video_core/buffer_cache/buffer_cache_base.h" |
| 40 | |||
| 41 | MICROPROFILE_DECLARE(GPU_PrepareBuffers); | ||
| 42 | MICROPROFILE_DECLARE(GPU_BindUploadBuffers); | ||
| 43 | MICROPROFILE_DECLARE(GPU_DownloadMemory); | ||
| 44 | |||
| 45 | using BufferId = SlotId; | ||
| 46 | |||
| 47 | using VideoCore::Surface::PixelFormat; | ||
| 48 | using namespace Common::Literals; | ||
| 49 | |||
| 50 | constexpr u32 NUM_VERTEX_BUFFERS = 32; | ||
| 51 | constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4; | ||
| 52 | constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18; | ||
| 53 | constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8; | ||
| 54 | constexpr u32 NUM_STORAGE_BUFFERS = 16; | ||
| 55 | constexpr u32 NUM_TEXTURE_BUFFERS = 16; | ||
| 56 | constexpr u32 NUM_STAGES = 5; | ||
| 57 | |||
| 58 | enum class ObtainBufferSynchronize : u32 { | ||
| 59 | NoSynchronize = 0, | ||
| 60 | FullSynchronize = 1, | ||
| 61 | SynchronizeNoDirty = 2, | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum class ObtainBufferOperation : u32 { | ||
| 65 | DoNothing = 0, | ||
| 66 | MarkAsWritten = 1, | ||
| 67 | DiscardWrite = 2, | ||
| 68 | MarkQuery = 3, | ||
| 69 | }; | ||
| 70 | |||
| 71 | using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; | ||
| 72 | using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>; | ||
| 73 | |||
| 74 | template <typename P> | ||
| 75 | class 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 | |||
| 131 | public: | ||
| 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 | |||
| 232 | private: | ||
| 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; | 12 | namespace 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; | 14 | using Core::Memory::YUZU_PAGESIZE; |
| 474 | }; | ||
| 475 | 15 | ||
| 476 | template <class P> | 16 | template <class P> |
| 477 | BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_, | 17 | BufferCache<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 | ||
| 548 | template <class P> | 97 | template <class P> |
| 549 | void BufferCache<P>::WriteMemory(VAddr cpu_addr, u64 size) { | 98 | void 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 | ||
| 555 | template <class P> | 107 | template <class P> |
| 556 | void BufferCache<P>::CachedWriteMemory(VAddr cpu_addr, u64 size) { | 108 | void 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 | } | 112 | template <class P> |
| 561 | buffer.CachedCpuWrite(cpu_addr, size); | 113 | std::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 | ||
| 565 | template <class P> | 131 | template <class P> |
| 566 | void BufferCache<P>::DownloadMemory(VAddr cpu_addr, u64 size) { | 132 | void 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 | ||
| 572 | template <class P> | 139 | template <class P> |
| 140 | void 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 | |||
| 155 | template <class P> | ||
| 573 | void BufferCache<P>::ClearDownload(IntervalType subtract_interval) { | 156 | void 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 | ||
| 867 | template <class P> | 454 | template <class P> |
| 868 | void BufferCache<P>::FlushCachedWrites() { | 455 | void 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 | ||
| 875 | template <class P> | 459 | template <class P> |
| @@ -879,10 +463,6 @@ bool BufferCache<P>::HasUncommittedFlushes() const noexcept { | |||
| 879 | 463 | ||
| 880 | template <class P> | 464 | template <class P> |
| 881 | void BufferCache<P>::AccumulateFlushes() { | 465 | void 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 | ||
| 892 | template <class P> | 472 | template <class P> |
| 893 | bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept { | 473 | bool 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 | ||
| 897 | template <class P> | 481 | template <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 | ||
| 996 | template <class P> | 613 | template <class P> |
| 997 | void BufferCache<P>::CommitAsyncFlushes() { | 614 | void 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 | ||
| 1006 | template <class P> | 618 | template <class P> |
| 1007 | void BufferCache<P>::PopAsyncFlushes() {} | 619 | void BufferCache<P>::PopAsyncFlushes() { |
| 620 | MICROPROFILE_SCOPE(GPU_DownloadMemory); | ||
| 621 | PopAsyncBuffers(); | ||
| 622 | } | ||
| 1008 | 623 | ||
| 1009 | template <class P> | 624 | template <class P> |
| 1010 | bool BufferCache<P>::IsRegionGpuModified(VAddr addr, size_t size) { | 625 | void 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 | |||
| 660 | template <class P> | ||
| 661 | bool 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 | ||
| 1028 | template <class P> | 667 | template <class P> |
| 1029 | bool BufferCache<P>::IsRegionRegistered(VAddr addr, size_t size) { | 668 | bool 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 | ||
| 1049 | template <class P> | 688 | template <class P> |
| 1050 | bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) { | 689 | bool 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 | ||
| 1068 | template <class P> | 693 | template <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 | ||
| 1592 | template <class P> | 1224 | template <class P> |
| 1593 | void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) { | 1225 | void 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 | ||
| 1607 | template <class P> | 1238 | template <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 | ||
| 1710 | template <class P> | 1335 | template <class P> |
| 1711 | BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) { | 1336 | BufferId 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 | ||
| 1767 | template <class P> | 1395 | template <class P> |
| 1768 | bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size) { | 1396 | bool 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 | ||
| 1797 | template <class P> | 1423 | template <class P> |
| 1424 | bool 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 | |||
| 1468 | template <class P> | ||
| 1798 | void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy, | 1469 | void 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 | ||
| 1807 | template <class P> | 1478 | template <class P> |
| 1808 | void BufferCache<P>::ImmediateUploadMemory(Buffer& buffer, u64 largest_copy, | 1479 | void 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 | ||
| 1827 | template <class P> | 1501 | template <class P> |
| 1828 | void BufferCache<P>::MappedUploadMemory(Buffer& buffer, u64 total_size_bytes, | 1502 | void 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 | ||
| 1843 | template <class P> | 1520 | template <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 | ||
| 1945 | template <class P> | 1625 | template <class P> |
| 1946 | void BufferCache<P>::DeleteBuffer(BufferId buffer_id) { | 1626 | void 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 | |||
| 49 | namespace boost { | ||
| 50 | template <typename T> | ||
| 51 | class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>; | ||
| 52 | } | ||
| 53 | |||
| 54 | namespace VideoCommon { | ||
| 55 | |||
| 56 | MICROPROFILE_DECLARE(GPU_PrepareBuffers); | ||
| 57 | MICROPROFILE_DECLARE(GPU_BindUploadBuffers); | ||
| 58 | MICROPROFILE_DECLARE(GPU_DownloadMemory); | ||
| 59 | |||
| 60 | using BufferId = SlotId; | ||
| 61 | |||
| 62 | using VideoCore::Surface::PixelFormat; | ||
| 63 | using namespace Common::Literals; | ||
| 64 | |||
| 65 | constexpr u32 NUM_VERTEX_BUFFERS = 32; | ||
| 66 | constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4; | ||
| 67 | constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18; | ||
| 68 | constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8; | ||
| 69 | constexpr u32 NUM_STORAGE_BUFFERS = 16; | ||
| 70 | constexpr u32 NUM_TEXTURE_BUFFERS = 16; | ||
| 71 | constexpr u32 NUM_STAGES = 5; | ||
| 72 | |||
| 73 | using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; | ||
| 74 | using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>; | ||
| 75 | |||
| 76 | enum class ObtainBufferSynchronize : u32 { | ||
| 77 | NoSynchronize = 0, | ||
| 78 | FullSynchronize = 1, | ||
| 79 | SynchronizeNoDirty = 2, | ||
| 80 | }; | ||
| 81 | |||
| 82 | enum class ObtainBufferOperation : u32 { | ||
| 83 | DoNothing = 0, | ||
| 84 | MarkAsWritten = 1, | ||
| 85 | DiscardWrite = 2, | ||
| 86 | MarkQuery = 3, | ||
| 87 | }; | ||
| 88 | |||
| 89 | template <typename P> | ||
| 90 | class 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 | |||
| 177 | public: | ||
| 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 | |||
| 280 | private: | ||
| 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 | |||
| 18 | namespace VideoCommon { | ||
| 19 | |||
| 20 | template <class RasterizerInterface> | ||
| 21 | class 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 | |||
| 31 | public: | ||
| 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 | |||
| 190 | private: | ||
| 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 | |||
| 18 | namespace VideoCommon { | ||
| 19 | |||
| 20 | constexpr u64 PAGES_PER_WORD = 64; | ||
| 21 | constexpr u64 BYTES_PER_PAGE = Core::Memory::YUZU_PAGESIZE; | ||
| 22 | constexpr u64 BYTES_PER_WORD = PAGES_PER_WORD * BYTES_PER_PAGE; | ||
| 23 | |||
| 24 | enum 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 | ||
| 33 | template <size_t stack_words = 1> | ||
| 34 | struct 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 | |||
| 49 | template <size_t stack_words = 1> | ||
| 50 | struct 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 | |||
| 166 | template <class RasterizerInterface, size_t stack_words = 1> | ||
| 167 | class WordManager { | ||
| 168 | public: | ||
| 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 | |||
| 434 | private: | ||
| 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: | 129 | constexpr 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 | ||
| 136 | constexpr std::array VIEW_CLASS_ASTC_10x6_RGBA{ | 134 | constexpr 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 | ||
| 140 | constexpr std::array VIEW_CLASS_ASTC_10x8_RGBA{ | 139 | constexpr 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 | 149 | constexpr 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 | ||
| 154 | constexpr std::array VIEW_CLASS_ASTC_12x12_RGBA{ | 154 | constexpr 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 { | |||
| 23 | public: | 30 | public: |
| 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 | |||
| 26 | protected: | 37 | protected: |
| 27 | bool is_stubbed; | 38 | bool is_stubbed; |
| 28 | }; | 39 | }; |
| 29 | 40 | ||
| 30 | template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache> | 41 | template <typename Traits> |
| 31 | class FenceManager { | 42 | class 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 | |||
| 32 | public: | 49 | public: |
| 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 | ||
| 84 | protected: | 113 | protected: |
| 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 | ||
| 110 | private: | 150 | private: |
| 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 | ||
| 556 | VideoCore::RasterizerDownloadArea GPU::OnCPURead(VAddr addr, u64 size) { | ||
| 557 | return impl->OnCPURead(addr, size); | ||
| 558 | } | ||
| 559 | |||
| 541 | void GPU::FlushRegion(VAddr addr, u64 size) { | 560 | void 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 | ||
| 14 | namespace Core { | 15 | namespace Core { |
| 15 | class System; | 16 | class 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 | ||
| 84 | PTEKind MemoryManager::GetPageKind(GPUVAddr gpu_addr) const { | 84 | PTEKind 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 | ||
| 555 | size_t MemoryManager::GetMemoryLayoutSize(GPUVAddr gpu_addr, size_t max_size) const { | 559 | size_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 | ||
| 25 | namespace VideoCommon { | 28 | namespace VideoCommon { |
| 26 | 29 | ||
| 30 | using AsyncJobId = SlotId; | ||
| 31 | |||
| 32 | static constexpr AsyncJobId NULL_ASYNC_JOB_ID{0}; | ||
| 33 | |||
| 27 | template <class QueryCache, class HostCounter> | 34 | template <class QueryCache, class HostCounter> |
| 28 | class CounterStreamBase { | 35 | class CounterStreamBase { |
| 29 | public: | 36 | public: |
| @@ -93,9 +100,13 @@ private: | |||
| 93 | template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter> | 100 | template <class QueryCache, class CachedQuery, class CounterStream, class HostCounter> |
| 94 | class QueryCacheBase : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { | 101 | class QueryCacheBase : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { |
| 95 | public: | 102 | public: |
| 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 | ||
| 206 | private: | 229 | private: |
| 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), ×tamp_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 | ||
| 278 | template <class QueryCache, class HostCounter> | 349 | template <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 | ||
| 318 | protected: | 389 | protected: |
| 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 | ||
| 322 | private: | 393 | private: |
| 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 | |||
| 377 | protected: | 463 | protected: |
| 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 | |||
| 8 | namespace VideoCore { | ||
| 9 | |||
| 10 | struct 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 | ||
| 16 | namespace Tegra { | 17 | namespace Tegra { |
| 17 | class MemoryManager; | 18 | class 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 | } |
| 47 | void RasterizerNull::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {} | 49 | void RasterizerNull::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType) {} |
| 48 | void RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {} | 50 | void RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {} |
| 51 | VideoCore::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 | } | ||
| 49 | void RasterizerNull::InvalidateGPUCache() {} | 59 | void RasterizerNull::InvalidateGPUCache() {} |
| 50 | void RasterizerNull::UnmapMemory(VAddr addr, u64 size) {} | 60 | void RasterizerNull::UnmapMemory(VAddr addr, u64 size) {} |
| 51 | void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {} | 61 | void 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: | |||
| 200 | struct BufferCacheParams { | 201 | struct 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 | ||
| 213 | using BufferCache = VideoCommon::BufferCache<BufferCacheParams>; | 217 | using 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 | |||
| 7 | namespace VideoCommon { | ||
| 8 | template 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 | ||
| 32 | using Fence = std::shared_ptr<GLInnerFence>; | 32 | using Fence = std::shared_ptr<GLInnerFence>; |
| 33 | using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCache, BufferCache, QueryCache>; | 33 | |
| 34 | struct 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 | |||
| 43 | using GenericFenceManager = VideoCommon::FenceManager<FenceManagerParams>; | ||
| 34 | 44 | ||
| 35 | class FenceManagerOpenGL final : public GenericFenceManager { | 45 | class FenceManagerOpenGL final : public GenericFenceManager { |
| 36 | public: | 46 | public: |
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 | ||
| 29 | QueryCache::QueryCache(RasterizerOpenGL& rasterizer_) | 29 | QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_) |
| 30 | : QueryCacheBase(rasterizer_), gl_rasterizer{rasterizer_} {} | 30 | : QueryCacheBase(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {} |
| 31 | 31 | ||
| 32 | QueryCache::~QueryCache() = default; | 32 | QueryCache::~QueryCache() = default; |
| 33 | 33 | ||
| @@ -74,7 +74,7 @@ void HostCounter::EndQuery() { | |||
| 74 | glEndQuery(GetTarget(type)); | 74 | glEndQuery(GetTarget(type)); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | u64 HostCounter::BlockingQuery() const { | 77 | u64 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 | ||
| 99 | void CachedQuery::Flush() { | 99 | u64 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>; | |||
| 28 | class QueryCache final | 28 | class QueryCache final |
| 29 | : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { | 29 | : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { |
| 30 | public: | 30 | public: |
| 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 | ||
| 53 | private: | 53 | private: |
| 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 | ||
| 75 | private: | 75 | private: |
| 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 | ||
| 436 | VideoCore::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 | |||
| 436 | void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { | 459 | void 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 | ||
| 1124 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | 1127 | ImageView::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 | ||
| 1215 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | 1219 | ImageView::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 | ||
| 1220 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | 1224 | ImageView::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 | ||
| 1224 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageViewParams& params) | 1228 | ImageView::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 | ||
| 123 | BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_, | 123 | BlitScreen::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 | |||
| 135 | BlitScreen::~BlitScreen() = default; | 137 | BlitScreen::~BlitScreen() = default; |
| 136 | 138 | ||
| 137 | void BlitScreen::Recreate() { | 139 | void BlitScreen::Recreate() { |
| 140 | present_manager.WaitPresent(); | ||
| 141 | scheduler.Finish(); | ||
| 142 | device.GetLogical().WaitIdle(); | ||
| 138 | CreateDynamicResources(); | 143 | CreateDynamicResources(); |
| 139 | } | 144 | } |
| 140 | 145 | ||
| 141 | VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | 146 | void 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 | ||
| 441 | VkSemaphore BlitScreen::DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, | 438 | void 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 | ||
| 449 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { | 465 | vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { |
| @@ -471,13 +487,11 @@ void BlitScreen::CreateStaticResources() { | |||
| 471 | } | 487 | } |
| 472 | 488 | ||
| 473 | void BlitScreen::CreateDynamicResources() { | 489 | void 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 | ||
| 528 | void BlitScreen::CreateSemaphores() { | ||
| 529 | semaphores.resize(image_count); | ||
| 530 | std::ranges::generate(semaphores, [this] { return device.GetLogical().CreateSemaphore(); }); | ||
| 531 | } | ||
| 532 | |||
| 533 | void BlitScreen::CreateDescriptorPool() { | 542 | void 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 | ||
| 573 | void BlitScreen::CreateRenderPass() { | 582 | void BlitScreen::CreateRenderPass() { |
| 574 | renderpass = CreateRenderPassImpl(swapchain.GetImageViewFormat()); | 583 | renderpass = CreateRenderPassImpl(image_view_format); |
| 575 | } | 584 | } |
| 576 | 585 | ||
| 577 | vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format, bool is_present) { | 586 | vk::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 | ||
| 1055 | void 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 | |||
| 1065 | void BlitScreen::ReleaseRawImages() { | 1064 | void 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 | ||
| 1322 | void BlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView image_view, | 1321 | void 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 | ||
| 1359 | void BlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view, | 1357 | void 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 | ||
| 1483 | u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, | 1480 | u64 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; | |||
| 42 | class Scheduler; | 43 | class Scheduler; |
| 43 | class SMAA; | 44 | class SMAA; |
| 44 | class Swapchain; | 45 | class Swapchain; |
| 46 | class PresentManager; | ||
| 47 | |||
| 48 | struct Frame; | ||
| 45 | 49 | ||
| 46 | struct ScreenInfo { | 50 | struct ScreenInfo { |
| 47 | VkImage image{}; | 51 | VkImage image{}; |
| @@ -55,18 +59,17 @@ class BlitScreen { | |||
| 55 | public: | 59 | public: |
| 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 | ||
| 317 | StagingBufferRef BufferCacheRuntime::DownloadStagingBuffer(size_t size) { | 317 | StagingBufferRef 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 | |||
| 321 | void BufferCacheRuntime::FreeDeferredStagingBuffer(StagingBufferRef& ref) { | ||
| 322 | staging_pool.FreeDeferred(ref); | ||
| 319 | } | 323 | } |
| 320 | 324 | ||
| 321 | u64 BufferCacheRuntime::GetDeviceLocalMemory() const { | 325 | u64 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: | |||
| 142 | struct BufferCacheParams { | 145 | struct 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 | ||
| 155 | using BufferCache = VideoCommon::BufferCache<BufferCacheParams>; | 161 | using 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 | |||
| 7 | namespace VideoCommon { | ||
| 8 | template 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 | }; |
| 41 | using Fence = std::shared_ptr<InnerFence>; | 41 | using Fence = std::shared_ptr<InnerFence>; |
| 42 | 42 | ||
| 43 | using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCache, BufferCache, QueryCache>; | 43 | struct 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 | |||
| 52 | using GenericFenceManager = VideoCommon::FenceManager<FenceManagerParams>; | ||
| 44 | 53 | ||
| 45 | class FenceManager final : public GenericFenceManager { | 54 | class FenceManager final : public GenericFenceManager { |
| 46 | public: | 55 | public: |
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 | |||
| 12 | namespace Vulkan { | ||
| 13 | |||
| 14 | MICROPROFILE_DEFINE(Vulkan_WaitPresent, "Vulkan", "Wait For Present", MP_RGB(128, 128, 128)); | ||
| 15 | MICROPROFILE_DEFINE(Vulkan_CopyToSwapchain, "Vulkan", "Copy to swapchain", MP_RGB(192, 255, 192)); | ||
| 16 | |||
| 17 | namespace { | ||
| 18 | |||
| 19 | bool 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 | |||
| 95 | PresentManager::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 | |||
| 136 | PresentManager::~PresentManager() = default; | ||
| 137 | |||
| 138 | Frame* 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 | |||
| 156 | void 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 | |||
| 171 | void 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 | |||
| 242 | void 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 | |||
| 259 | void 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 | |||
| 289 | void 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 | |||
| 15 | namespace Core::Frontend { | ||
| 16 | class EmuWindow; | ||
| 17 | } // namespace Core::Frontend | ||
| 18 | |||
| 19 | namespace Vulkan { | ||
| 20 | |||
| 21 | class Device; | ||
| 22 | class Scheduler; | ||
| 23 | class Swapchain; | ||
| 24 | |||
| 25 | struct 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 | |||
| 38 | class PresentManager { | ||
| 39 | public: | ||
| 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 | |||
| 57 | private: | ||
| 58 | void PresentThread(std::stop_token token); | ||
| 59 | |||
| 60 | void CopyToSwapchain(Frame* frame); | ||
| 61 | |||
| 62 | private: | ||
| 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 | ||
| 69 | QueryCache::QueryCache(VideoCore::RasterizerInterface& rasterizer_, const Device& device_, | 69 | QueryCache::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 | ||
| 115 | u64 HostCounter::BlockingQuery() const { | 118 | u64 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: | |||
| 52 | class QueryCache final | 52 | class QueryCache final |
| 53 | : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { | 53 | : public VideoCommon::QueryCacheBase<QueryCache, CachedQuery, CounterStream, HostCounter> { |
| 54 | public: | 54 | public: |
| 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 | ||
| 85 | private: | 86 | private: |
| 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 | ||
| 505 | VideoCore::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 | |||
| 504 | void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size, VideoCommon::CacheType which) { | 521 | void 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 | ||
| 599 | void RasterizerVulkan::SignalReference() { | 616 | void RasterizerVulkan::SignalReference() { |
| 600 | fence_manager.SignalOrdering(); | 617 | fence_manager.SignalReference(); |
| 601 | } | 618 | } |
| 602 | 619 | ||
| 603 | void RasterizerVulkan::ReleaseFences() { | 620 | void 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 | ||
| 636 | void RasterizerVulkan::FragmentBarrier() { | 653 | void 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 | ||
| 47 | Scheduler::~Scheduler() = default; | 47 | Scheduler::~Scheduler() = default; |
| 48 | 48 | ||
| 49 | void Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { | 49 | u64 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 | ||
| 55 | void Scheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { | 56 | void Scheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { |
| @@ -205,7 +206,7 @@ void Scheduler::AllocateWorkerCommandBuffer() { | |||
| 205 | }); | 206 | }); |
| 206 | } | 207 | } |
| 207 | 208 | ||
| 208 | void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { | 209 | u64 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 | ||
| 236 | void Scheduler::AllocateNewContext() { | 239 | void 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 | |||
| 109 | private: | 111 | private: |
| 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 | ||
| 18 | namespace Vulkan { | 19 | namespace 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 | ||
| 36 | VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { | 37 | static 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 | ||
| 55 | VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) { | 80 | VkExtent2D 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 | ||
| 113 | void Swapchain::AcquireNextImage() { | 136 | bool 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 | ||
| 134 | void Swapchain::Present(VkSemaphore render_semaphore) { | 160 | void 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) { | |||
| 165 | void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { | 192 | void 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, | |
| 246 | void 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 | ||
| 278 | void Swapchain::Destroy() { | 281 | void 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 | ||
| 286 | bool Swapchain::HasFpsUnlockChanged() const { | ||
| 287 | return current_fps_unlocked != !Settings::values.use_speed_limit.GetValue(); | ||
| 288 | } | ||
| 289 | |||
| 290 | bool Swapchain::NeedsPresentModeUpdate() const { | 287 | bool 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 | |||
| 91 | private: | 112 | private: |
| 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 | ||
| 1585 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | 1585 | ImageView::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 | ||
| 1673 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | 1674 | ImageView::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 | ||
| 1678 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams& params) | 1679 | ImageView::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 | ||
| 15 | UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_) | 15 | UpdateDescriptorQueue::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 | ||
| 20 | UpdateDescriptorQueue::~UpdateDescriptorQueue() = default; | 21 | UpdateDescriptorQueue::~UpdateDescriptorQueue() = default; |
| 21 | 22 | ||
| 22 | void UpdateDescriptorQueue::TickFrame() { | 23 | void 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 | ||
| 26 | void UpdateDescriptorQueue::Acquire() { | 31 | void 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 | ||
| 31 | class UpdateDescriptorQueue final { | 31 | class 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 | |||
| 32 | public: | 38 | public: |
| 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() { | |||
| 170 | void GenericEnvironment::SetCachedSize(size_t size_bytes) { | 170 | void 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 | ||
| 177 | size_t GenericEnvironment::CachedSize() const noexcept { | 177 | size_t GenericEnvironment::CachedSizeWords() const noexcept { |
| 178 | return cached_highest - cached_lowest + INST_SIZE; | 178 | return CachedSizeBytes() / INST_SIZE; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | size_t GenericEnvironment::ReadSize() const noexcept { | 181 | size_t GenericEnvironment::CachedSizeBytes() const noexcept { |
| 182 | return static_cast<size_t>(cached_highest) - cached_lowest + INST_SIZE; | ||
| 183 | } | ||
| 184 | |||
| 185 | size_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 | ||
| 189 | u64 GenericEnvironment::CalculateHash() const { | 193 | u64 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 | ||
| 200 | void GenericEnvironment::Serialize(std::ofstream& file) const { | 204 | void 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 | ||
| 49 | std::string Name(const ImageViewBase& image_view) { | 49 | std::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; | |||
| 22 | using VideoCore::Surface::SurfaceType; | 23 | using VideoCore::Surface::SurfaceType; |
| 23 | 24 | ||
| 24 | ImageInfo::ImageInfo(const TICEntry& config) noexcept { | 25 | ImageInfo::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 | ||
| 118 | ImageInfo::ImageInfo(const Maxwell3D::Regs::RenderTargetConfig& ct, | 121 | ImageInfo::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 | ||
| 156 | ImageInfo::ImageInfo(const Maxwell3D::Regs::Zeta& zt, const Maxwell3D::Regs::ZetaSize& zt_size, | 162 | ImageInfo::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 | ||
| 196 | ImageInfo::ImageInfo(const Fermi2D::Surface& config) noexcept { | 205 | ImageInfo::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 @@ | |||
| 16 | namespace VideoCommon { | 15 | namespace VideoCommon { |
| 17 | 16 | ||
| 18 | ImageViewBase::ImageViewBase(const ImageViewInfo& info, const ImageInfo& image_info, | 17 | ImageViewBase::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 | ||
| 38 | ImageViewBase::ImageViewBase(const ImageInfo& info, const ImageViewInfo& view_info) | 36 | ImageViewBase::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 { | |||
| 24 | DECLARE_ENUM_FLAG_OPERATORS(ImageViewFlagBits) | 24 | DECLARE_ENUM_FLAG_OPERATORS(ImageViewFlagBits) |
| 25 | 25 | ||
| 26 | struct ImageViewBase { | 26 | struct 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 | ||
| 493 | template <class P> | 493 | template <class P> |
| 494 | std::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 | |||
| 519 | template <class P> | ||
| 494 | void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) { | 520 | void 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 | ||
| 785 | template <class P> | 813 | template <class P> |
| 786 | ImageId TextureCache<P>::DmaImageId(const Tegra::DMA::ImageOperand& operand) { | 814 | ImageId 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 | ||
| 623 | bool Device::GetSuitability(bool requires_swapchain) { | 625 | bool 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 | ||
| 24 | namespace Vulkan { | 24 | namespace Vulkan { |
| 25 | 25 | ||
| 26 | vk::SurfaceKHR CreateSurface(const vk::Instance& instance, | 26 | vk::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 | ||
| 8 | namespace Core::Frontend { | ||
| 9 | class EmuWindow; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Vulkan { | 9 | namespace 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 @@ | |||
| 22 | QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent, | 22 | QtAmiiboSettingsDialog::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 { | |||
| 261 | void QtAmiiboSettings::ShowCabinetApplet( | 261 | void 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 { | |||
| 23 | class QtAmiiboSettingsDialog; | 23 | class QtAmiiboSettingsDialog; |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | namespace Service::NFP { | 26 | namespace Service::NFC { |
| 27 | class NfpDevice; | 27 | class NfcDevice; |
| 28 | } // namespace Service::NFP | 28 | } // namespace Service::NFC |
| 29 | 29 | ||
| 30 | class QtAmiiboSettingsDialog final : public QDialog { | 30 | class QtAmiiboSettingsDialog final : public QDialog { |
| 31 | Q_OBJECT | 31 | Q_OBJECT |
| @@ -33,7 +33,7 @@ class QtAmiiboSettingsDialog final : public QDialog { | |||
| 33 | public: | 33 | public: |
| 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 | ||
| 76 | signals: | 76 | signals: |
| 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 | ||
| 81 | private: | 81 | private: |
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 | ||
| 47 | static Core::Frontend::WindowSystemType GetWindowSystemType(); | 62 | class QObject; |
| 63 | class QPaintEngine; | ||
| 64 | class QSurface; | ||
| 48 | 65 | ||
| 49 | EmuThread::EmuThread(Core::System& system) : m_system{system} {} | 66 | EmuThread::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 | ||
| 262 | static 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 | |||
| 282 | static 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 | |||
| 302 | GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | 282 | GRenderWindow::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 | ||
| 21 | class GRenderWindow; | ||
| 22 | class GMainWindow; | 32 | class GMainWindow; |
| 23 | class QCamera; | 33 | class QCamera; |
| 24 | class QCameraImageCapture; | 34 | class QCameraImageCapture; |
| 35 | class QCloseEvent; | ||
| 36 | class QFocusEvent; | ||
| 25 | class QKeyEvent; | 37 | class QKeyEvent; |
| 38 | class QMouseEvent; | ||
| 39 | class QObject; | ||
| 40 | class QResizeEvent; | ||
| 41 | class QShowEvent; | ||
| 42 | class QTimer; | ||
| 43 | class QTouchEvent; | ||
| 44 | class QWheelEvent; | ||
| 26 | 45 | ||
| 27 | namespace Core { | 46 | namespace Core { |
| 28 | enum class SystemResultStatus : u32; | ||
| 29 | class System; | 47 | class System; |
| 30 | } // namespace Core | 48 | } // namespace Core |
| 31 | 49 | ||
| @@ -40,7 +58,6 @@ enum class TasState; | |||
| 40 | 58 | ||
| 41 | namespace VideoCore { | 59 | namespace VideoCore { |
| 42 | enum class LoadCallbackStage; | 60 | enum class LoadCallbackStage; |
| 43 | class RendererBase; | ||
| 44 | } // namespace VideoCore | 61 | } // namespace VideoCore |
| 45 | 62 | ||
| 46 | class EmuThread final : public QThread { | 63 | class 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() { | |||
| 79 | void ConfigureGeneral::ApplyConfiguration() { | 76 | void 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 | ||
| 43 | static 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) | ||
| 47 | static 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 | |||
| 62 | static 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 | |||
| 21 | ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) | 77 | ConfigureGraphics::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 | ||
| 132 | void 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 | |||
| 73 | void ConfigureGraphics::UpdateDeviceSelection(int device) { | 169 | void 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 | ||
| 176 | void ConfigureGraphics::SetFSRIndicatorText(int percentage) { | 292 | void 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 | ||
| 297 | const 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 | |||
| 181 | void ConfigureGraphics::ApplyConfiguration() { | 318 | void 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 | |||
| 15 | class QEvent; | ||
| 16 | class QObject; | ||
| 17 | |||
| 18 | namespace Settings { | ||
| 19 | enum class NvdecEmulation : u32; | ||
| 20 | enum class RendererBackend : u32; | ||
| 21 | enum class ShaderBackend : u32; | ||
| 22 | } // namespace Settings | ||
| 11 | 23 | ||
| 12 | namespace Core { | 24 | namespace Core { |
| 13 | class System; | 25 | class 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. | ||
| 217 | FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. | ||
| 218 | Mailbox can have lower latency than FIFO and does not tear but may drop frames. | ||
| 219 | Immediate (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 | ||
| 22 | void ConfigureGraphicsAdvanced::SetConfiguration() { | 22 | void 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 | ||
| 55 | void ConfigureGraphicsAdvanced::ApplyConfiguration() { | 56 | void 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 | ||
| 2926 | void 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 | |||
| 2874 | template <size_t N> | 2965 | template <size_t N> |
| 2875 | void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) { | 2966 | void 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 | ||
| 601 | void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, | 602 | void 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 | ||
| 4244 | bool 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 | |||
| 4230 | std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, | 4263 | std::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; | |||
| 93 | enum class WebExitReason : u32; | 93 | enum class WebExitReason : u32; |
| 94 | } // namespace Service::AM::Applets | 94 | } // namespace Service::AM::Applets |
| 95 | 95 | ||
| 96 | namespace Service::NFP { | 96 | namespace Service::NFC { |
| 97 | class NfpDevice; | 97 | class NfcDevice; |
| 98 | } // namespace Service::NFP | 98 | } // namespace Service::NFC |
| 99 | 99 | ||
| 100 | namespace Ui { | 100 | namespace Ui { |
| 101 | class MainWindow; | 101 | class 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 | |||
| 15 | namespace QtCommon { | ||
| 16 | Core::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 | |||
| 36 | Core::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 | |||
| 9 | namespace QtCommon { | ||
| 10 | |||
| 11 | Core::Frontend::WindowSystemType GetWindowSystemType(); | ||
| 12 | |||
| 13 | Core::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 |
| 164 | use_multi_core = | 164 | use_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 |
| 168 | use_extended_memory_layout = | 168 | use_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 |
| 265 | backend = | 265 | backend = |
| 266 | 266 | ||
| 267 | # Whether to enable asynchronous presentation (Vulkan only) | ||
| 268 | # 0 (default): Off, 1: On | ||
| 269 | async_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 |
| 269 | debug = | 273 | debug = |
| @@ -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 |
| 322 | max_anisotropy = | 326 | max_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 | ||
| 326 | use_vsync = | 336 | use_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 |
| 331 | shader_backend = | 341 | shader_backend = |
| 332 | 342 | ||
| 343 | # Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. | ||
| 344 | # 0: Off, 1 (default): On | ||
| 345 | use_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 |
| 335 | use_asynchronous_shaders = | 349 | use_asynchronous_shaders = |
| @@ -370,10 +384,6 @@ use_asynchronous_gpu_emulation = | |||
| 370 | # 0: Off, 1 (default): On | 384 | # 0: Off, 1 (default): On |
| 371 | use_fast_gpu_time = | 385 | use_fast_gpu_time = |
| 372 | 386 | ||
| 373 | # Force unmodified buffers to be flushed, which can cost performance. | ||
| 374 | # 0: Off (default), 1: On | ||
| 375 | use_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 |
| 379 | use_caches_gc = | 389 | use_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", |