diff options
Diffstat (limited to '')
160 files changed, 8954 insertions, 1087 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 957df54f5..b625743ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -541,9 +541,9 @@ add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY # Adjustments for MSVC + Ninja if (MSVC AND CMAKE_GENERATOR STREQUAL "Ninja") add_compile_options( - /wd4711 # function 'function' selected for automatic inline expansion /wd4464 # relative include path contains '..' - /wd4820 # 'identifier1': '4' bytes padding added after data member 'identifier2' + /wd4711 # function 'function' selected for automatic inline expansion + /wd4820 # 'bytes' bytes padding added after construct 'member_name' ) endif() diff --git a/dist/icons/controller/applet_pro_controller_dark_disabled.png b/dist/icons/controller/applet_pro_controller_dark_disabled.png Binary files differindex 416e1e2fb..d45f91db5 100644 --- a/dist/icons/controller/applet_pro_controller_dark_disabled.png +++ b/dist/icons/controller/applet_pro_controller_dark_disabled.png diff --git a/dist/icons/controller/applet_pro_controller_disabled.png b/dist/icons/controller/applet_pro_controller_disabled.png Binary files differindex 72a549ea9..8c6bcd308 100644 --- a/dist/icons/controller/applet_pro_controller_disabled.png +++ b/dist/icons/controller/applet_pro_controller_disabled.png diff --git a/dist/icons/controller/applet_pro_controller_midnight_disabled.png b/dist/icons/controller/applet_pro_controller_midnight_disabled.png Binary files differindex 2907f3be4..d27dbfc66 100644 --- a/dist/icons/controller/applet_pro_controller_midnight_disabled.png +++ b/dist/icons/controller/applet_pro_controller_midnight_disabled.png diff --git a/dist/icons/overlay/button_A.png b/dist/icons/overlay/button_A.png Binary files differindex fd90f8b42..aafafecff 100644 --- a/dist/icons/overlay/button_A.png +++ b/dist/icons/overlay/button_A.png diff --git a/dist/icons/overlay/button_B.png b/dist/icons/overlay/button_B.png Binary files differindex e8927addc..4a19d8176 100644 --- a/dist/icons/overlay/button_B.png +++ b/dist/icons/overlay/button_B.png diff --git a/dist/icons/overlay/button_X.png b/dist/icons/overlay/button_X.png Binary files differindex fe70fb685..f50a53974 100644 --- a/dist/icons/overlay/button_X.png +++ b/dist/icons/overlay/button_X.png diff --git a/dist/icons/overlay/button_Y.png b/dist/icons/overlay/button_Y.png Binary files differindex ca0de569d..435ec30d5 100644 --- a/dist/icons/overlay/button_Y.png +++ b/dist/icons/overlay/button_Y.png diff --git a/dist/icons/overlay/button_press_stick.png b/dist/icons/overlay/button_press_stick.png Binary files differindex 6d0254d50..13bbff9ef 100644 --- a/dist/icons/overlay/button_press_stick.png +++ b/dist/icons/overlay/button_press_stick.png diff --git a/dist/icons/overlay/controller_dual_joycon.png b/dist/icons/overlay/controller_dual_joycon.png Binary files differindex 8e8b5ad41..286b8d8aa 100644 --- a/dist/icons/overlay/controller_dual_joycon.png +++ b/dist/icons/overlay/controller_dual_joycon.png diff --git a/dist/icons/overlay/controller_dual_joycon_dark.png b/dist/icons/overlay/controller_dual_joycon_dark.png Binary files differindex 63e03eb4e..3fba54618 100644 --- a/dist/icons/overlay/controller_dual_joycon_dark.png +++ b/dist/icons/overlay/controller_dual_joycon_dark.png diff --git a/dist/icons/overlay/controller_handheld.png b/dist/icons/overlay/controller_handheld.png Binary files differindex deb375011..38c38c0da 100644 --- a/dist/icons/overlay/controller_handheld.png +++ b/dist/icons/overlay/controller_handheld.png diff --git a/dist/icons/overlay/controller_handheld_dark.png b/dist/icons/overlay/controller_handheld_dark.png Binary files differindex 1f5317aa0..2b73b812e 100644 --- a/dist/icons/overlay/controller_handheld_dark.png +++ b/dist/icons/overlay/controller_handheld_dark.png diff --git a/dist/icons/overlay/controller_pro.png b/dist/icons/overlay/controller_pro.png Binary files differindex 67cf86d5c..78273fe57 100644 --- a/dist/icons/overlay/controller_pro.png +++ b/dist/icons/overlay/controller_pro.png diff --git a/dist/icons/overlay/controller_pro_dark.png b/dist/icons/overlay/controller_pro_dark.png Binary files differindex 7be655b96..8d261f1f7 100644 --- a/dist/icons/overlay/controller_pro_dark.png +++ b/dist/icons/overlay/controller_pro_dark.png diff --git a/dist/icons/overlay/controller_single_joycon_left.png b/dist/icons/overlay/controller_single_joycon_left.png Binary files differindex 340ddc71b..34f0a424e 100644 --- a/dist/icons/overlay/controller_single_joycon_left.png +++ b/dist/icons/overlay/controller_single_joycon_left.png diff --git a/dist/icons/overlay/controller_single_joycon_left_dark.png b/dist/icons/overlay/controller_single_joycon_left_dark.png Binary files differindex 24ed2c44c..740647a2b 100644 --- a/dist/icons/overlay/controller_single_joycon_left_dark.png +++ b/dist/icons/overlay/controller_single_joycon_left_dark.png diff --git a/dist/icons/overlay/controller_single_joycon_left_y_dark.png b/dist/icons/overlay/controller_single_joycon_left_y_dark.png Binary files differindex fdf177c12..725bec62d 100644 --- a/dist/icons/overlay/controller_single_joycon_left_y_dark.png +++ b/dist/icons/overlay/controller_single_joycon_left_y_dark.png diff --git a/dist/icons/overlay/controller_single_joycon_right.png b/dist/icons/overlay/controller_single_joycon_right.png Binary files differindex 5b8fc0eff..65e7686ca 100644 --- a/dist/icons/overlay/controller_single_joycon_right.png +++ b/dist/icons/overlay/controller_single_joycon_right.png diff --git a/dist/icons/overlay/controller_single_joycon_right_dark.png b/dist/icons/overlay/controller_single_joycon_right_dark.png Binary files differindex afa80e6ef..81cb94a1d 100644 --- a/dist/icons/overlay/controller_single_joycon_right_dark.png +++ b/dist/icons/overlay/controller_single_joycon_right_dark.png diff --git a/dist/icons/overlay/osk_button_backspace.png b/dist/icons/overlay/osk_button_backspace.png Binary files differindex 4ad284720..b7dc33228 100644 --- a/dist/icons/overlay/osk_button_backspace.png +++ b/dist/icons/overlay/osk_button_backspace.png diff --git a/dist/icons/overlay/osk_button_backspace_dark.png b/dist/icons/overlay/osk_button_backspace_dark.png Binary files differindex 19ac8847e..542038bef 100644 --- a/dist/icons/overlay/osk_button_backspace_dark.png +++ b/dist/icons/overlay/osk_button_backspace_dark.png diff --git a/dist/languages/uk.ts b/dist/languages/uk.ts new file mode 100644 index 000000000..66a3ac96e --- /dev/null +++ b/dist/languages/uk.ts @@ -0,0 +1,7321 @@ +<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="uk" sourcelanguage="en_US"> +<context> + <name>AboutDialog</name> + <message> + <location filename="../../src/yuzu/aboutdialog.ui" line="14"/> + <source>About yuzu</source> + <translation>Про yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/aboutdialog.ui" line="72"/> + <source><html><head/><body><p><span style=" font-size:28pt;">yuzu</span></p></body></html></source> + <translation><html><head/><body><p><span style=" font-size:28pt;">yuzu</span></p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/aboutdialog.ui" line="85"/> + <source><html><head/><body><p>%1 (%2)</p></body></html></source> + <translation><html><head/><body><p>%1 (%2)</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/aboutdialog.ui" line="98"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<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> +<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> +<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> + <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<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 є експериментальним емулятором Nintendo Switch з відкритим кодом ліцензований під GPLv3.0+.</span></p> +<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> +<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;">Це програмне забезпечення не слід використовувати для ігор, які ви отримали незаконним шляхом.</span></p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/aboutdialog.ui" line="130"/> + <source><html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source> + <translation><html><head/><body><p><a href="https://yuzu-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Веб-сайт</span></a> | <a href="https://github.com/yuzu-emu"><span style=" text-decoration: underline; color:#039be5;">Вихідний код</span></a> | <a href="https://github.com/yuzu-emu/yuzu/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Вкладники</span></a> | <a href="https://github.com/yuzu-emu/yuzu/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Ліцензія</span></a></p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/aboutdialog.ui" line="146"/> + <source><html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; is a trademark of Nintendo. yuzu is not affiliated with Nintendo in any way.</span></p></body></html></source> + <translation><html><head/><body><p><span style=" font-size:7pt;">&quot;Nintendo Switch&quot; є торговою маркою Nintendo. yuzu не пов'язаний з Nintendo у будь-якому вигляді.</span></p></body></html></translation> + </message> +</context> +<context> + <name>CalibrationConfigurationDialog</name> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="23"/> + <source>Communicating with the server...</source> + <translation>Зв'язок із сервером...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="24"/> + <source>Cancel</source> + <translation>Скасувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="43"/> + <source>Touch the top left corner <br>of your touchpad.</source> + <translation>Торкніться верхнього лівого кута <br> вашого тачпаду.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="46"/> + <source>Now touch the bottom right corner <br>of your touchpad.</source> + <translation>Тепер торкніться правого нижнього кута <br> вашого тачпаду.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="49"/> + <source>Configuration completed!</source> + <translation>Налаштування завершено!</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="57"/> + <source>OK</source> + <translation>ОК</translation> + </message> +</context> +<context> + <name>ChatRoom</name> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="14"/> + <source>Room Window</source> + <translation>Вікно кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="40"/> + <source>Send Chat Message</source> + <translation>Надіслати повідомлення в чат</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.ui" line="47"/> + <source>Send Message</source> + <translation>Надіслати повідомлення</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="181"/> + <source>Members</source> + <translation>Члени</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="318"/> + <source>%1 has joined</source> + <translation>%1 приєднався</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="321"/> + <source>%1 has left</source> + <translation>%1 вийшов</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="324"/> + <source>%1 has been kicked</source> + <translation>%1 вигнано</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="327"/> + <source>%1 has been banned</source> + <translation>%1 заблоковано</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="330"/> + <source>%1 has been unbanned</source> + <translation>%1 розблоковано</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="446"/> + <source>View Profile</source> + <translation>Переглянути профіль</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="459"/> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="469"/> + <source>Block Player</source> + <translation>Заблокувати гравця</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="470"/> + <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> + <translation>Коли ви блокуєте гравця, ви більше не отримуватиме від нього повідомлення у чаті. <br><br>Ви впевнені що бажаєте заблокувати %1?</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="483"/> + <source>Kick</source> + <translation>Вигнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="484"/> + <source>Ban</source> + <translation>Заблокувати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="488"/> + <source>Kick Player</source> + <translation>Вигнати гравця</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="489"/> + <source>Are you sure you would like to <b>kick</b> %1?</source> + <translation>Ви впевнені що бажаєте <b>вигнати</b> %1?</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="497"/> + <source>Ban Player</source> + <translation>Заблокувати гравця</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="498"/> + <source>Are you sure you would like to <b>kick and ban</b> %1? + +This would ban both their forum username and their IP address.</source> + <translation>Ви впевнені що бажаєте <b>вигнати і заблокувати</b> %1? + +Ця дія заблокує ім'я користувача на форумі та IP-адресу.</translation> + </message> +</context> +<context> + <name>ClientRoom</name> + <message> + <location filename="../../src/yuzu/multiplayer/client_room.ui" line="14"/> + <source>Room Window</source> + <translation>Вікно кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/client_room.ui" line="27"/> + <source>Room Description</source> + <translation>Опис кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/client_room.ui" line="47"/> + <source>Moderation...</source> + <translation>Модерація...</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/client_room.ui" line="57"/> + <source>Leave Room</source> + <translation>Залишити кімнату</translation> + </message> +</context> +<context> + <name>ClientRoomWindow</name> + <message> + <location filename="../../src/yuzu/multiplayer/client_room.cpp" line="78"/> + <source>Connected</source> + <translation>З'єднано</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/client_room.cpp" line="87"/> + <source>Disconnected</source> + <translation>Роз'єднано</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/client_room.cpp" line="100"/> + <source>%1 - %2 (%3/%4 members) - connected</source> + <translation>%1 - %2 (%3/%4 члени) - з'єднано</translation> + </message> +</context> +<context> + <name>CompatDB</name> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="20"/> + <source>Report Compatibility</source> + <translation>Повідомити про сумісність</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="27"/> + <location filename="../../src/yuzu/compatdb.ui" line="63"/> + <source>Report Game Compatibility</source> + <translation>Повідомити про сумісність гри</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="36"/> + <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> + <translation><html><head/><body><p><span style=" font-size:10pt;">Якщо ви бажаєте надіслати звіт до </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">списку сумісності yuzu</span></a><span style=" font-size:10pt;">, наступна інформація буде зібрана та відображена на сайті:</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;">Інформація про залізо (ЦП / ГП / Операційна система)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Версія yuzu</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Підключений акаунт yuzu</li></ul></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="72"/> + <source>Perfect</source> + <translation>Ідеально</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="79"/> + <source><html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html></source> + <translation><html><head/><body><p>Гра працює ідеально, без звукових чи графічних артефактів.</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="89"/> + <source>Great</source> + <translation>Чудово</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="96"/> + <source><html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html></source> + <translation><html><head/><body><p>Гра працює з невеликими графічними або звуковими артефактами та може бути пройдена від початку до кінця. Можуть знадобитися обхідні шляхи.</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="106"/> + <source>Okay</source> + <translation>Добре</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="113"/> + <source><html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html></source> + <translation><html><head/><body><p>Гра працює зі суттєвими графічними або звуковими артефактами, але з обхідними шляхами може бути пройдена.</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="123"/> + <source>Bad</source> + <translation>Погано</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="130"/> + <source><html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html></source> + <translation><html><head/><body><p>Гра працює, але з суттєвими графічними чи звуковими артефактами. У деяких місцях неможливо пройти навіть із обхідними шляхами.</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="140"/> + <source>Intro/Menu</source> + <translation>Вступ/Меню</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="147"/> + <source><html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html></source> + <translation><html><head/><body><p>У гру неможливо грати через серйозні графічні або звукові артефакти. Неможливо просунутися далі за стартове меню.</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="157"/> + <source>Won't Boot</source> + <translation>Не запускається</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="170"/> + <source><html><head/><body><p>The game crashes when attempting to startup.</p></body></html></source> + <translation><html><head/><body><p>Гра вилітає при спробі запуску.</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="182"/> + <source><html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?</p></body></html></source> + <translation><html><head/><body><p>Незалежно від швидкості або продуктивності, наскільки добре ця гра працює від початку до кінця у поточній версії yuzu?</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.ui" line="206"/> + <source>Thank you for your submission!</source> + <translation>Дякуємо за ваш звіт!</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.cpp" line="58"/> + <source>Submitting</source> + <translation>Надсилання</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.cpp" line="71"/> + <source>Communication error</source> + <translation>Помилка з'єднання</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.cpp" line="72"/> + <source>An error occurred while sending the Testcase</source> + <translation>Сталася помилка під час надсилання звіту</translation> + </message> + <message> + <location filename="../../src/yuzu/compatdb.cpp" line="74"/> + <source>Next</source> + <translation>Далі</translation> + </message> +</context> +<context> + <name>ConfigureAudio</name> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="14"/> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="20"/> + <source>Audio</source> + <translation>Аудіо</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="28"/> + <source>Output Engine:</source> + <translation>Рушій виводу:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="42"/> + <source>Output Device</source> + <translation>Пристрій виводу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="56"/> + <source>Input Device</source> + <translation>Пристрій вводу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="84"/> + <source>Use global volume</source> + <translation>Використовувати загальну гучність</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="89"/> + <source>Set volume:</source> + <translation>Встановити гучність:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="97"/> + <source>Volume:</source> + <translation>Гучність</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.ui" line="142"/> + <source>0 %</source> + <translation>0 %</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_audio.cpp" line="108"/> + <source>%1%</source> + <comment>Volume percentage (e.g. 50%)</comment> + <translation>%1%</translation> + </message> +</context> +<context> + <name>ConfigureCamera</name> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="14"/> + <source>Configure Infrared Camera</source> + <translation>Налаштування інфрачервоної камери</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="26"/> + <source>Select where the image of the emulated camera comes from. It may be a virtual camera or a real camera.</source> + <translation>Виберіть, звідки береться зображення емульованої камери. Це може бути віртуальна або реальна камера.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="52"/> + <source>Camera Image Source:</source> + <translation>Джерело зображення камери:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="71"/> + <source>Input device:</source> + <translation>Пристрій вводу:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="96"/> + <source>Preview</source> + <translation>Попередній перегляд</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="108"/> + <source>Resolution: 320*240</source> + <translation>Роздільна здатність: 320*240</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="115"/> + <source>Click to preview</source> + <translation>Натисніть для попереднього перегляду</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.ui" line="140"/> + <source>Restore Defaults</source> + <translation>Значення за замовчуванням</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_camera.cpp" line="135"/> + <source>Auto</source> + <translation>Авто</translation> + </message> +</context> +<context> + <name>ConfigureCpu</name> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="17"/> + <source>CPU</source> + <translation>ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="25"/> + <source>General</source> + <translation>Загальні</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="34"/> + <source>Accuracy:</source> + <translation>Точність:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="42"/> + <source>Auto</source> + <translation>Авто</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="47"/> + <source>Accurate</source> + <translation>Точно</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="52"/> + <source>Unsafe</source> + <translation>Небезпечно</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="57"/> + <source>Paranoid (disables most optimizations)</source> + <translation>Параноїк (відключає більшість оптимізацій)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="68"/> + <source>We recommend setting accuracy to "Auto".</source> + <translation>Ми рекомендуємо встановити точність на "Авто".</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="85"/> + <source>Unsafe CPU Optimization Settings</source> + <translation>Небезпечні налаштування оптимізації ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="91"/> + <source>These settings reduce accuracy for speed.</source> + <translation>Ці налаштування зменшують точність заради швидкості. </translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="101"/> + <source> + <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="106"/> + <source>Unfuse FMA (improve performance on CPUs without FMA)</source> + <translation>Не використовувати FMA (покращує продуктивність на ЦП без FMA)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="113"/> + <source> + <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="118"/> + <source>Faster FRSQRTE and FRECPE</source> + <translation>Прискорені FRSQRTE та FRECPE</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="125"/> + <source> + <div>This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="130"/> + <source>Faster ASIMD instructions (32 bits only)</source> + <translation>Швидші інструкції ASIMD (лише 32 біт)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="137"/> + <source> + <div>This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="142"/> + <source>Inaccurate NaN handling</source> + <translation>Неправильна обробка NaN</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="149"/> + <source> + <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> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="154"/> + <source>Disable address space checks</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="161"/> + <source> + <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> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="166"/> + <source>Ignore global monitor</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu.ui" line="191"/> + <source>CPU settings are available only when game is not running.</source> + <translation>Налаштування ЦП недоступні, поки запущена гра.</translation> + </message> +</context> +<context> + <name>ConfigureCpuDebug</name> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="17"/> + <source>CPU</source> + <translation>ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="25"/> + <source>Toggle CPU Optimizations</source> + <translation>Увімкнути оптимізації ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="31"/> + <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> + <translation><html><head/><body><p><span style=" font-weight:600;">Тільки для налагодження.</span><br/>Якщо ви не впевнені в тому, що вони роблять, залиште всі ці параметри увімкненими. <br/>Коли їх вимкнено, ці параметри набувають чинності лише за увімкненого налагодження ЦП. </p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="41"/> + <source> + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> + <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="48"/> + <source>Enable inline page tables</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="55"/> + <source> + <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> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="60"/> + <source>Enable block linking</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="67"/> + <source> + <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> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="72"/> + <source>Enable return stack buffer</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="79"/> + <source> + <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> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="84"/> + <source>Enable fast dispatcher</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="91"/> + <source> + <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="96"/> + <source>Enable context elimination</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="103"/> + <source> + <div>Enables IR optimizations that involve constant propagation.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="108"/> + <source>Enable constant propagation</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="115"/> + <source> + <div>Enables miscellaneous IR optimizations.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="120"/> + <source>Enable miscellaneous optimizations</source> + <translation>Увімкнути різні оптимізації</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="127"/> + <source> + <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> + <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="133"/> + <source>Enable misalignment check reduction</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="140"/> + <source> + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <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> + <div style="white-space: nowrap">Disabling this forces all memory accesses to use Software MMU Emulation.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="147"/> + <source>Enable Host MMU Emulation (general memory instructions)</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="154"/> + <source> + <div style="white-space: nowrap">This optimization speeds up exclusive memory accesses by the guest program.</div> + <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> + <div style="white-space: nowrap">Disabling this forces all exclusive memory accesses to use Software MMU Emulation.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="161"/> + <source>Enable Host MMU Emulation (exclusive memory instructions)</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="168"/> + <source> + <div style="white-space: nowrap">This optimization speeds up exclusive memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it reduces the overhead of fastmem failure of exclusive memory accesses.</div> + </source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="174"/> + <source>Enable recompilation of exclusive memory instructions</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_cpu_debug.ui" line="199"/> + <source>CPU settings are available only when game is not running.</source> + <translation>Налаштування ЦП доступні тільки тоді, коли гру не запущено.</translation> + </message> +</context> +<context> + <name>ConfigureDebug</name> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="15"/> + <source>Debugger</source> + <translation>Налагоджувач</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="23"/> + <source>Enable GDB Stub</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="43"/> + <source>Port:</source> + <translation>Порт:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="67"/> + <source>Logging</source> + <translation>Журналювання</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="75"/> + <source>Global Log Filter</source> + <translation>Глобальний фільтр журналів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="87"/> + <source>Show Log in Console</source> + <translation>Показувати журнал у консолі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="94"/> + <source>Open Log Location</source> + <translation>Відкрити папку для журналів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="104"/> + <source>When checked, the max size of the log increases from 100 MB to 1 GB</source> + <translation>Якщо увімкнено, максимальний розмір журналу збільшується зі 100 МБ до 1 ГБ</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="107"/> + <source>Enable Extended Logging**</source> + <translation>Увімкнути розширене ведення журналу**</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="117"/> + <source>Homebrew</source> + <translation>Homebrew</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="125"/> + <source>Arguments String</source> + <translation>Рядок аргументів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="140"/> + <source>Graphics</source> + <translation>Графіка</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="149"/> + <source>When checked, the graphics API enters a slower debugging mode</source> + <translation>Якщо увімкнено, графічний API переходить у повільніший режим налагодження</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="152"/> + <source>Enable Graphics Debugging</source> + <translation>Увімкнути налагодження графіки</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="159"/> + <source>When checked, it enables Nsight Aftermath crash dumps</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="162"/> + <source>Enable Nsight Aftermath</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="172"/> + <source>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</source> + <translation>Якщо ввімкнено, буде дампити всі оригінальні шейдери асемблера з кешу шейдерів на диску або гри як знайдені</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="175"/> + <source>Dump Game Shaders</source> + <translation>Дамп ігрових шейдерів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="185"/> + <source>When checked, it will dump all the macro programs of the GPU</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="188"/> + <source>Dump Maxwell Macros</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="198"/> + <source>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="201"/> + <source>Disable Macro JIT</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="208"/> + <source>When checked, yuzu will log statistics about the compiled pipeline cache</source> + <translation>Якщо увімкнено, yuzu записуватиме статистику про скомпільований кеш конвеєра</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="211"/> + <source>Enable Shader Feedback</source> + <translation>Увімкнути зворотний зв'язок про шейдери</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="218"/> + <source>When checked, it executes shaders without loop logic changes</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="221"/> + <source>Disable Loop safety checks</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="231"/> + <source>Debugging</source> + <translation>Налагодження</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="237"/> + <source>Enable Verbose Reporting Services**</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="244"/> + <source>Enable FS Access Log</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="251"/> + <source>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="254"/> + <source>Dump Audio Commands To Console**</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="261"/> + <source>Create Minidump After Crash</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="271"/> + <source>Advanced</source> + <translation>Розширені</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="277"/> + <source>Kiosk (Quest) Mode</source> + <translation>Режим кіоску (Квест)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="284"/> + <source>Enable CPU Debugging</source> + <translation>Увімкнути налагодження ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="291"/> + <source>Enable Debug Asserts</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="298"/> + <source>Enable Auto-Stub**</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="305"/> + <source>Enable All Controller Types</source> + <translation>Увімкнути всі типи контролерів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="312"/> + <source>Disable Web Applet</source> + <translation>Вимкнути веб-аплет</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="319"/> + <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> + <translation>Дозволяє yuzu перевіряти наявність робочого середовища Vulkan під час запуску програми. Вимкніть цю опцію, якщо це викликає проблеми з тим, що зовнішні програми бачать yuzu.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="322"/> + <source>Perform Startup Vulkan Check</source> + <translation>Виконувати перевірку Vulkan під час запуску</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.ui" line="337"/> + <source>**This will be reset automatically when yuzu closes.</source> + <translation>**Це буде автоматично скинуто після закриття yuzu.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="35"/> + <source>Restart Required</source> + <translation>Потрібен перезапуск</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="36"/> + <source>yuzu is required to restart in order to apply this setting.</source> + <translation>yuzu потрібно перезапустити, щоб застосувати це налаштування.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="86"/> + <source>Web applet not compiled</source> + <translation>Веб-аплет не скомпільовано</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug.cpp" line="93"/> + <source>MiniDump creation not compiled</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>ConfigureDebugController</name> + <message> + <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="14"/> + <source>Configure Debug Controller</source> + <translation>Налаштування налагоджувального контролера</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="40"/> + <source>Clear</source> + <translation>Очистити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug_controller.ui" line="47"/> + <source>Defaults</source> + <translation>За замовчуванням</translation> + </message> +</context> +<context> + <name>ConfigureDebugTab</name> + <message> + <location filename="../../src/yuzu/configuration/configure_debug_tab.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug_tab.ui" line="17"/> + <location filename="../../src/yuzu/configuration/configure_debug_tab.cpp" line="16"/> + <source>Debug</source> + <translation>Налагодження</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_debug_tab.cpp" line="17"/> + <source>CPU</source> + <translation>ЦП</translation> + </message> +</context> +<context> + <name>ConfigureDialog</name> + <message> + <location filename="../../src/yuzu/configuration/configure.ui" line="20"/> + <source>yuzu Configuration</source> + <translation>Налаштування yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="52"/> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="156"/> + <source>Audio</source> + <translation>Аудіо</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="53"/> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="154"/> + <source>CPU</source> + <translation>ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="54"/> + <source>Debug</source> + <translation>Налагодження</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="55"/> + <source>Filesystem</source> + <translation>Файлова система</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="56"/> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="150"/> + <source>General</source> + <translation>Загальні</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="57"/> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="155"/> + <source>Graphics</source> + <translation>Графіка</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="58"/> + <source>GraphicsAdvanced</source> + <translation>ГрафікаРозширені</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="59"/> + <source>Hotkeys</source> + <translation>Гарячі клавіші</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="60"/> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="157"/> + <source>Controls</source> + <translation>Керування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="61"/> + <source>Profiles</source> + <translation>Профілі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="62"/> + <source>Network</source> + <translation>Мережа</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="63"/> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="152"/> + <source>System</source> + <translation>Система</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="64"/> + <source>Game List</source> + <translation>Список ігор</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_dialog.cpp" line="65"/> + <source>Web</source> + <translation>Мережа</translation> + </message> +</context> +<context> + <name>ConfigureFilesystem</name> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="17"/> + <source>Filesystem</source> + <translation>Файлова система</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="25"/> + <source>Storage Directories</source> + <translation>Каталоги зберігання</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="31"/> + <source>NAND</source> + <translation>NAND</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="38"/> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="58"/> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="114"/> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="136"/> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="143"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="51"/> + <source>SD Card</source> + <translation>SD карта</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="84"/> + <source>Gamecard</source> + <translation>Картридж</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="90"/> + <source>Path</source> + <translation>Шлях</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="100"/> + <source>Inserted</source> + <translation>Вставлений</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="107"/> + <source>Current Game</source> + <translation>Поточна гра</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="124"/> + <source>Patch Manager</source> + <translation>Керування патчами</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="152"/> + <source>Dump Decompressed NSOs</source> + <translation>Дамп розпакованих NSO</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="159"/> + <source>Dump ExeFS</source> + <translation>Дамп ExeFS</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="168"/> + <source>Mod Load Root</source> + <translation>Папка з модами</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="175"/> + <source>Dump Root</source> + <translation>Корінь дампу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="201"/> + <source>Caching</source> + <translation>Кешування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="209"/> + <source>Cache Game List Metadata</source> + <translation>Кешувати метадані списку ігор</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.ui" line="216"/> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="131"/> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="135"/> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="140"/> + <source>Reset Metadata Cache</source> + <translation>Скинути кеш метаданих</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="93"/> + <source>Select Emulated NAND Directory...</source> + <translation>Виберіть папку для емульованого NAND...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="96"/> + <source>Select Emulated SD Directory...</source> + <translation>Виберіть папку для емульованого SD...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="99"/> + <source>Select Gamecard Path...</source> + <translation>Оберіть папку для картриджів...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="102"/> + <source>Select Dump Directory...</source> + <translation>Оберіть папку для дампів...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="105"/> + <source>Select Mod Load Directory...</source> + <translation>Оберіть папку для модів...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="132"/> + <source>The metadata cache is already empty.</source> + <translation>Кеш метаданих вже порожній.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="136"/> + <source>The operation completed successfully.</source> + <translation>Операція завершилася успішно.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_filesystem.cpp" line="141"/> + <source>The metadata cache couldn't be deleted. It might be in use or non-existent.</source> + <translation>Кеш метаданих не можна видалити. Можливо, він використовується або відсутній.</translation> + </message> +</context> +<context> + <name>ConfigureGeneral</name> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="17"/> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="25"/> + <source>General</source> + <translation>Загальні</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="35"/> + <source>Limit Speed Percent</source> + <translation>Обмеження відсотка швидкості</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="42"/> + <source>%</source> + <translation>%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="60"/> + <source>Multicore CPU Emulation</source> + <translation>Багатоядерна емуляція ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="67"/> + <source>Extended memory layout (6GB DRAM)</source> + <translation>Розширене компонування пам'яті (6 ГБ DRAM)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="74"/> + <source>Confirm exit while emulation is running</source> + <translation>Підтверджувати вихід під час емуляції</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="81"/> + <source>Prompt for user on game boot</source> + <translation>Запитувати користувача під час запуску гри</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="88"/> + <source>Pause emulation when in background</source> + <translation>Призупиняти емуляцію у фоновому режимі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="95"/> + <source>Mute audio when in background</source> + <translation>Приглушити звук у фоновому режимі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="102"/> + <source>Hide mouse on inactivity</source> + <translation>Приховування миші при бездіяльності</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.ui" line="144"/> + <source>Reset All Settings</source> + <translation>Скинути всі налаштування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.cpp" line="68"/> + <source>yuzu</source> + <translation>yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_general.cpp" line="69"/> + <source>This reset all settings and remove all per-game configurations. This will not delete game directories, profiles, or input profiles. Proceed?</source> + <translation>Це скине всі налаштування і видалить усі конфігурації під окремі ігри. При цьому не будуть видалені шляхи до ігор, профілів або профілів вводу. Продовжити?</translation> + </message> +</context> +<context> + <name>ConfigureGraphics</name> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="17"/> + <source>Graphics</source> + <translation>Графіка</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="25"/> + <source>API Settings</source> + <translation>Налаштування API</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="64"/> + <source>Shader Backend:</source> + <translation>Бекенд шейдерів:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="92"/> + <source>Device:</source> + <translation>Пристрій:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="120"/> + <source>API:</source> + <translation>API:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="156"/> + <source>Graphics Settings</source> + <translation>Налаштування графіки</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="162"/> + <source>Use disk pipeline cache</source> + <translation>Використовувати кеш конвеєра на диску</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="169"/> + <source>Use asynchronous GPU emulation</source> + <translation>Використовувати асинхронну емуляцію ГП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="176"/> + <source>Accelerate ASTC texture decoding</source> + <translation>Прискорення декодування текстур ASTC</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="198"/> + <source>NVDEC emulation:</source> + <translation>Емуляція NVDEC:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="206"/> + <source>No Video Output</source> + <translation>Відсутність відеовиходу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="211"/> + <source>CPU Video Decoding</source> + <translation>Декодування відео на ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="216"/> + <source>GPU Video Decoding (Default)</source> + <translation>Декодування відео на ГП (за замовчуванням)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="242"/> + <source>Fullscreen Mode:</source> + <translation>Повноекранний режим:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="250"/> + <source>Borderless Windowed</source> + <translation>Вікно без рамок</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="255"/> + <source>Exclusive Fullscreen</source> + <translation>Ексклюзивний повноекранний</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="281"/> + <source>Aspect Ratio:</source> + <translation>Співвідношення сторін:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="289"/> + <source>Default (16:9)</source> + <translation>За замовчуванням (16:9)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="294"/> + <source>Force 4:3</source> + <translation>Змусити 4:3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="299"/> + <source>Force 21:9</source> + <translation>Змусити 21:9</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="304"/> + <source>Force 16:10</source> + <translation>Змусити 16:10</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="309"/> + <source>Stretch to Window</source> + <translation>Розтягнути до вікна</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="335"/> + <source>Resolution:</source> + <translation>Роздільна здатність:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="343"/> + <source>0.5X (360p/540p) [EXPERIMENTAL]</source> + <translation>0.5X (360p/540p) [ЕКСПЕРИМЕНТАЛЬНЕ]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="348"/> + <source>0.75X (540p/810p) [EXPERIMENTAL]</source> + <translation>0.75X (540p/810p) [ЕКСПЕРИМЕНТАЛЬНЕ]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="353"/> + <source>1X (720p/1080p)</source> + <translation>1X (720p/1080p)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="358"/> + <source>2X (1440p/2160p)</source> + <translation>2X (1440p/2160p)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="363"/> + <source>3X (2160p/3240p)</source> + <translation>3X (2160p/3240p)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="368"/> + <source>4X (2880p/4320p)</source> + <translation>4X (2880p/4320p)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="373"/> + <source>5X (3600p/5400p)</source> + <translation>5X (3600p/5400p)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="378"/> + <source>6X (4320p/6480p)</source> + <translation>6X (4320p/6480p)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="404"/> + <source>Window Adapting Filter:</source> + <translation>Фільтр адаптації вікна:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="412"/> + <source>Nearest Neighbor</source> + <translation>Найближчий сусід</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="417"/> + <source>Bilinear</source> + <translation>Білінійне</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="422"/> + <source>Bicubic</source> + <translation>Бікубічне</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="427"/> + <source>Gaussian</source> + <translation>Гауса</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="432"/> + <source>ScaleForce</source> + <translation>ScaleForce</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="437"/> + <source>AMD FidelityFX™️ Super Resolution (Vulkan Only)</source> + <translation>AMD FidelityFX™️ Super Resolution (Лише для Vulkan)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="463"/> + <source>Anti-Aliasing Method:</source> + <translation>Метод згладжування:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="471"/> + <source>None</source> + <translation>Вимкнено</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="476"/> + <source>FXAA</source> + <translation>FXAA</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="511"/> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="521"/> + <source>Use global background color</source> + <translation>Використовувати глобальний фоновий колір</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="526"/> + <source>Set background color:</source> + <translation>Встановити фоновий колір:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.ui" line="534"/> + <source>Background Color:</source> + <translation>Фоновий колір:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics.cpp" line="33"/> + <source>GLASM (Assembly Shaders, NVIDIA Only)</source> + <translation>GLASM (асемблерні шейдери, лише для NVIDIA)</translation> + </message> +</context> +<context> + <name>ConfigureGraphicsAdvanced</name> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="17"/> + <source>Advanced</source> + <translation>Розширені</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="25"/> + <source>Advanced Graphics Settings</source> + <translation>Розширені налаштування графіки</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="46"/> + <source>Accuracy Level:</source> + <translation>Рівень точності:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="75"/> + <source>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.</source> + <translation>Вертикальна синхронізація запобігає розривам екрана, але деякі відеокарти мають нижчу продуктивність при вертикальній синхронізації. Залишайте увімкненим, якщо ви не помічаєте різниці в продуктивності.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="78"/> + <source>Use VSync</source> + <translation>Використувати вертикальну сінхронізацію</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="85"/> + <source>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</source> + <translation>Вмикає асинхронну компіляцію шейдерів, що зменшить зависання через шейдери. Функція є експериментальною.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="88"/> + <source>Use asynchronous shader building (Hack)</source> + <translation>Використовувати асинхронну побудову шейдерів (хак)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="95"/> + <source>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</source> + <translation>Вмикає функцію Fast GPU Time. Цей параметр змусить більшість ігор працювати в максимальній рідній роздільній здатності.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="98"/> + <source>Use Fast GPU Time (Hack)</source> + <translation>Увімкнути Fast GPU Time (Хак)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="105"/> + <source>Enables pessimistic buffer flushes. This option will force unmodified buffers to be flushed, which can cost performance.</source> + <translation>Вмикає песимістичне очищення буферів. Ця опція змушує промивати немодифіковані буфери, що може знизити продуктивність.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="108"/> + <source>Use pessimistic buffer flushes (Hack)</source> + <translation>Використовувати песимістичне очищення буферів (Хак)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="130"/> + <source>Anisotropic Filtering:</source> + <translation>Анізотропна фільтрація:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="138"/> + <source>Automatic</source> + <translation>Автоматично</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="143"/> + <source>Default</source> + <translation>За замовчуванням</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="148"/> + <source>2x</source> + <translation>2x</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="153"/> + <source>4x</source> + <translation>4x</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="158"/> + <source>8x</source> + <translation>8x</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_graphics_advanced.ui" line="163"/> + <source>16x</source> + <translation>16x</translation> + </message> +</context> +<context> + <name>ConfigureHotkeys</name> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="14"/> + <source>Hotkey Settings</source> + <translation>Налаштування гарячих клавіш</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="17"/> + <source>Hotkeys</source> + <translation>Гарячі клавіші</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="25"/> + <source>Double-click on a binding to change it.</source> + <translation>Натисніть двічі на прив'язці, щоб змінити її.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="45"/> + <source>Clear All</source> + <translation>Очистити все</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.ui" line="52"/> + <source>Restore Defaults</source> + <translation>Відновити значення за замовчуванням.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/> + <source>Action</source> + <translation>Дія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/> + <source>Hotkey</source> + <translation>Гаряча клавіша</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="98"/> + <source>Controller Hotkey</source> + <translation>Гаряча клавіша контролера</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="138"/> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="164"/> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="379"/> + <source>Conflicting Key Sequence</source> + <translation>Конфліктуюча комбінація клавіш</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="139"/> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="165"/> + <source>The entered key sequence is already assigned to: %1</source> + <translation>Введена комбінація вже призначена до: %1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="158"/> + <source>Home+%1</source> + <translation>Home+%1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="172"/> + <source>[waiting]</source> + <translation>[очікування]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="242"/> + <source>Invalid</source> + <translation>Неприпустимо</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="343"/> + <source>Restore Default</source> + <translation>Відновити значення за замовчуванням</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="344"/> + <source>Clear</source> + <translation>Очистити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="365"/> + <source>Conflicting Button Sequence</source> + <translation>Конфліктуюче поєднання кнопок</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="366"/> + <source>The default button sequence is already assigned to: %1</source> + <translation>Типова комбінація кнопок вже призначена до: %1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_hotkeys.cpp" line="380"/> + <source>The default key sequence is already assigned to: %1</source> + <translation>Типова комбінація клавіш вже призначена до: %1</translation> + </message> +</context> +<context> + <name>ConfigureInput</name> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="14"/> + <source>ConfigureInput</source> + <translation>НалаштуванняВводу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="39"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="42"/> + <source>Player 1</source> + <translation>Гравець 1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="47"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="50"/> + <source>Player 2</source> + <translation>Гравець 2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="55"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="58"/> + <source>Player 3</source> + <translation>Гравець 3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="63"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="66"/> + <source>Player 4</source> + <translation>Гравець 4</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="71"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="74"/> + <source>Player 5</source> + <translation>Гравець 5</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="79"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="82"/> + <source>Player 6</source> + <translation>Гравець 6</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="87"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="90"/> + <source>Player 7</source> + <translation>Гравець 7</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="95"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="98"/> + <source>Player 8</source> + <translation>Гравець 8</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="103"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="106"/> + <source>Advanced</source> + <translation>Розширені</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="138"/> + <source>Console Mode</source> + <translation>Режим консолі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="159"/> + <source>Docked</source> + <translation>У док-станції</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="169"/> + <source>Handheld</source> + <translation>Портативний</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="179"/> + <source>Vibration</source> + <translation>Вібрація</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="215"/> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="261"/> + <source>Configure</source> + <translation>Налаштувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="225"/> + <source>Motion</source> + <translation>Рух</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="296"/> + <source>Controllers</source> + <translation>Контролери</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="324"/> + <source>1</source> + <translation>1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="365"/> + <source>2</source> + <translation>2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="375"/> + <source>3</source> + <translation>3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="385"/> + <source>4</source> + <translation>4</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="395"/> + <source>5</source> + <translation>5</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="405"/> + <source>6</source> + <translation>6</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="415"/> + <source>7</source> + <translation>7</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="425"/> + <source>8</source> + <translation>8</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="435"/> + <source>Connected</source> + <translation>З'єднано</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="494"/> + <source>Defaults</source> + <translation>За замовчуванням</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input.ui" line="537"/> + <source>Clear</source> + <translation>Очистити</translation> + </message> +</context> +<context> + <name>ConfigureInputAdvanced</name> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="14"/> + <source>Configure Input</source> + <translation>Налаштування вводу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="74"/> + <source>Joycon Colors</source> + <translation>Кольори Joy-Con'ів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="125"/> + <source>Player 1</source> + <translation>Гравець 1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="164"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="450"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="754"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1040"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1365"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1651"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1955"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2241"/> + <source>L Body</source> + <translation>Лівий контролер</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="219"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="505"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="809"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1095"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1420"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1706"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2010"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2296"/> + <source>L Button</source> + <translation>Кнопка L</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="295"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="581"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="885"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1171"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1496"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1782"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2086"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2372"/> + <source>R Body</source> + <translation>Правий контролер</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="350"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="636"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="940"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1226"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1551"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1837"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2141"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2427"/> + <source>R Button</source> + <translation>Кнопка R</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="411"/> + <source>Player 2</source> + <translation>Гравець 2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="715"/> + <source>Player 3</source> + <translation>Гравець 3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1001"/> + <source>Player 4</source> + <translation>Гравець 4</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1326"/> + <source>Player 5</source> + <translation>Гравець 5</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1612"/> + <source>Player 6</source> + <translation>Гравець 6</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="1916"/> + <source>Player 7</source> + <translation>Гравець 7</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2202"/> + <source>Player 8</source> + <translation>Гравець 8</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2533"/> + <source>Emulated Devices</source> + <translation>Емульовані пристрої</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2545"/> + <source>Keyboard</source> + <translation>Клавіатура</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2558"/> + <source>Mouse</source> + <translation>Миша</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2565"/> + <source>Touchscreen</source> + <translation>Сенсорний екран</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2588"/> + <source>Advanced</source> + <translation>Розширені</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2595"/> + <source>Debug Controller</source> + <translation>Налагоджувальний контролер</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2602"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2616"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2630"/> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2743"/> + <source>Configure</source> + <translation>Налаштувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2609"/> + <source>Ring Controller</source> + <translation>Контролер Ring</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2623"/> + <source>Infrared Camera</source> + <translation>Інфрачервона камера</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2640"/> + <source>Other</source> + <translation>Інше</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2652"/> + <source>Emulate Analog with Keyboard Input</source> + <translation>Емуляція аналогового вводу з клавіатури</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2659"/> + <source>Requires restarting yuzu</source> + <translation>Потребує перезапуску yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2668"/> + <source>Enable XInput 8 player support (disables web applet)</source> + <translation>Увімкнути підтримку 8-ми гравців на XInput (відключає веб-аплет)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2681"/> + <source>Enable UDP controllers (not needed for motion)</source> + <translation>Увімкнути UDP контролери (не обов'язково для руху)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2694"/> + <source>Controller navigation</source> + <translation>Навігація контролера</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2707"/> + <source>Enable mouse panning</source> + <translation>Увімкнути панорамування миші</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2714"/> + <source>Mouse sensitivity</source> + <translation>Чутливість миші</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2720"/> + <source>%</source> + <translation>%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_advanced.ui" line="2736"/> + <source>Motion / Touch</source> + <translation>Рух і сенсор</translation> + </message> +</context> +<context> + <name>ConfigureInputPlayer</name> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="14"/> + <source>Configure Input</source> + <translation>Налаштування вводу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="63"/> + <source>Connect Controller</source> + <translation>Підключити контролер</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="100"/> + <source>Input Device</source> + <translation>Пристрій вводу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="156"/> + <source>Profile</source> + <translation>Профіль</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="196"/> + <source>Save</source> + <translation>Зберегти</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="212"/> + <source>New</source> + <translation>Новий</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="228"/> + <source>Delete</source> + <translation>Видалити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="291"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1291"/> + <source>Left Stick</source> + <translation>Лівий міні-джойстик</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="349"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="391"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="925"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="964"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2583"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2622"/> + <source>Up</source> + <translation>Вгору</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="422"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="461"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="995"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1034"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2069"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2653"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2692"/> + <source>Left</source> + <translation>Вліво</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="471"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="510"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1044"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1083"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2118"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2702"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2741"/> + <source>Right</source> + <translation>Вправо</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="553"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="592"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1126"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1165"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2784"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2823"/> + <source>Down</source> + <translation>Вниз</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="623"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="662"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2854"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2893"/> + <source>Pressed</source> + <translation>Натиснення</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="672"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="711"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2903"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2942"/> + <source>Modifier</source> + <translation>Модифікатор</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="721"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2952"/> + <source>Range</source> + <translation>Діапазон</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="754"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2985"/> + <source>%</source> + <translation>%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="797"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="3025"/> + <source>Deadzone: 0%</source> + <translation>Мертва зона: 0%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="821"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="3049"/> + <source>Modifier Range: 0%</source> + <translation>Діапазон модифікатора: 0%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="867"/> + <source>D-Pad</source> + <translation>Кнопки напрямків</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1251"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1290"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1296"/> + <source>L</source> + <translation>L</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1306"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1345"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1288"/> + <source>ZL</source> + <translation>ZL</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1426"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1465"/> + <source>Minus</source> + <translation>Мінус</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1475"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1514"/> + <source>Capture</source> + <translation>Захоплення</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1545"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1584"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1287"/> + <source>Plus</source> + <translation>Плюс</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1594"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1633"/> + <source>Home</source> + <translation>Home</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1698"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1737"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1290"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1297"/> + <source>R</source> + <translation>R</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1753"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1792"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1289"/> + <source>ZR</source> + <translation>ZR</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1873"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1912"/> + <source>SL</source> + <translation>SL</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1922"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="1961"/> + <source>SR</source> + <translation>SR</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2030"/> + <source>Motion 1</source> + <translation>Рух 1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2079"/> + <source>Motion 2</source> + <translation>Рух 2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2170"/> + <source>Face Buttons</source> + <translation>Кнопки A/B/X/Y</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2228"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2267"/> + <source>X</source> + <translation>X</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2298"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2337"/> + <source>Y</source> + <translation>Y</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2347"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2386"/> + <source>A</source> + <translation>A</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2429"/> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2468"/> + <source>B</source> + <translation>B</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.ui" line="2516"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1292"/> + <source>Right Stick</source> + <translation>Правий міні-джойстик</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="361"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="434"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="529"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="624"/> + <source>Clear</source> + <translation>Очистити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="363"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="436"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="533"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="552"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="626"/> + <source>[not set]</source> + <translation>[не задано]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="366"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="638"/> + <source>Invert button</source> + <translation>Інвертувати кнопку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="372"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="629"/> + <source>Toggle button</source> + <translation>Переключити кнопку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="380"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="580"/> + <source>Invert axis</source> + <translation>Інвертувати осі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="386"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="390"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="443"/> + <source>Set threshold</source> + <translation>Встановити поріг</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="390"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="443"/> + <source>Choose a value between 0% and 100%</source> + <translation>Оберіть значення між 0% і 100%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="402"/> + <source>Toggle axis</source> + <translation>Переключити осі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="439"/> + <source>Set gyro threshold</source> + <translation>Встановити поріг гіроскопа</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="485"/> + <source>Map Analog Stick</source> + <translation>Задати аналоговий міні-джойстик</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="486"/> + <source>After pressing OK, first move your joystick horizontally, and then vertically. +To invert the axes, first move your joystick vertically, and then horizontally.</source> + <translation>Після натискання на ОК, рухайте ваш міні-джойстик горизонтально, а потім вертикально. +Щоб інвертувати осі, спочатку рухайте ваш міні-джойстик вертикально, а потім горизонтально.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="554"/> + <source>Center axis</source> + <translation>Центрувати осі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="662"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1016"/> + <source>Deadzone: %1%</source> + <translation>Мертва зона: %1%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="671"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1021"/> + <source>Modifier Range: %1%</source> + <translation>Діапазон модифікатора: %1%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="697"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1046"/> + <source>Pro Controller</source> + <translation>Контролер Pro</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1050"/> + <source>Dual Joycons</source> + <translation>Подвійні Joy-Con'и</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1054"/> + <source>Left Joycon</source> + <translation>Лівий Joy-Con</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1058"/> + <source>Right Joycon</source> + <translation>Правий Joy-Con</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1062"/> + <source>Handheld</source> + <translation>Портативний</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1066"/> + <source>GameCube Controller</source> + <translation>Контролер GameCube</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1075"/> + <source>Poke Ball Plus</source> + <translation>Poke Ball Plus</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1079"/> + <source>NES Controller</source> + <translation>Контролер NES</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1083"/> + <source>SNES Controller</source> + <translation>Контролер SNES</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1087"/> + <source>N64 Controller</source> + <translation>Контролер N64</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1091"/> + <source>Sega Genesis</source> + <translation>Sega Genesis</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1295"/> + <source>Start / Pause</source> + <translation>Старт / Пауза</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1298"/> + <source>Z</source> + <translation>Z</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1299"/> + <source>Control Stick</source> + <translation>Міні-джойстик керування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1300"/> + <source>C-Stick</source> + <translation>C-Джойстик</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1401"/> + <source>Shake!</source> + <translation>Потрусіть!</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1403"/> + <source>[waiting]</source> + <translation>[очікування]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1485"/> + <source>New Profile</source> + <translation>Новий профіль</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1485"/> + <source>Enter a profile name:</source> + <translation>Введіть ім'я профілю:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1493"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1501"/> + <source>Create Input Profile</source> + <translation>Створити профіль контролю</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1494"/> + <source>The given profile name is not valid!</source> + <translation>Задане ім'я профілю недійсне!</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1502"/> + <source>Failed to create the input profile "%1"</source> + <translation>Не вдалося створити профіль контролю "%1"</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1522"/> + <source>Delete Input Profile</source> + <translation>Видалити профіль контролю</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1523"/> + <source>Failed to delete the input profile "%1"</source> + <translation>Не вдалося видалити профіль контролю "%1"</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1545"/> + <source>Load Input Profile</source> + <translation>Завантажити профіль контролю</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1546"/> + <source>Failed to load the input profile "%1"</source> + <translation>Не вдалося завантажити профіль контролю "%1"</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1565"/> + <source>Save Input Profile</source> + <translation>Зберегти профіль контролю</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="1566"/> + <source>Failed to save the input profile "%1"</source> + <translation>Не вдалося зберегти профіль контролю "%1"</translation> + </message> +</context> +<context> + <name>ConfigureInputProfileDialog</name> + <message> + <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="14"/> + <source>Create Input Profile</source> + <translation>Створити профіль контролю</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="40"/> + <source>Clear</source> + <translation>Очистити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_profile_dialog.ui" line="47"/> + <source>Defaults</source> + <translation>За замовчуванням</translation> + </message> +</context> +<context> + <name>ConfigureMotionTouch</name> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="6"/> + <source>Configure Motion / Touch</source> + <translation>Налаштування руху та сенсора</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="15"/> + <source>Touch</source> + <translation>Сенсор</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="23"/> + <source>UDP Calibration:</source> + <translation>Калібрація UDP:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="30"/> + <source>(100, 50) - (1800, 850)</source> + <translation>(100, 50) - (1800, 850)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="46"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="73"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="243"/> + <source>Configure</source> + <translation>Налаштувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="57"/> + <source>Touch from button profile:</source> + <translation>Торкніться з профілю кнопки:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="85"/> + <source>CemuhookUDP Config</source> + <translation>Налаштування CemuhookUDP</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="91"/> + <source>You may use any Cemuhook compatible UDP input source to provide motion and touch input.</source> + <translation>Ви можете використовувати будь-яке сумісне з Cemuhook джерело UDP сигналу для руху і сенсора.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="134"/> + <source>Server:</source> + <translation>Сервер:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="161"/> + <source>Port:</source> + <translation>Порт:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="188"/> + <source>Learn More</source> + <translation>Дізнатися більше</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="201"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="266"/> + <source>Test</source> + <translation>Тест</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="214"/> + <source>Add Server</source> + <translation>Додати сервер</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.ui" line="247"/> + <source>Remove Server</source> + <translation>Видалити сервер</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="87"/> + <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> + <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;">Дізнатися більше</span></a></translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="169"/> + <source>%1:%2</source> + <translation>%1:%2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="174"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="178"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="182"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="188"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="194"/> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="288"/> + <source>yuzu</source> + <translation>yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="174"/> + <source>Port number has invalid characters</source> + <translation>Номер порту містить неприпустимі символи</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="178"/> + <source>Port has to be in range 0 and 65353</source> + <translation>Порт повинен бути в районі від 0 до 65353</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="182"/> + <source>IP address is not valid</source> + <translation>IP-адреса недійсна</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="188"/> + <source>This UDP server already exists</source> + <translation>Цей UDP сервер уже існує</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="194"/> + <source>Unable to add more than 8 servers</source> + <translation>Неможливо додати більше 8 серверів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="210"/> + <source>Testing</source> + <translation>Тестування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="226"/> + <source>Configuring</source> + <translation>Налаштування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="257"/> + <source>Test Successful</source> + <translation>Тест успішний</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="258"/> + <source>Successfully received data from the server.</source> + <translation>Успішно отримано інформацію із сервера</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="260"/> + <source>Test Failed</source> + <translation>Тест провалено</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="261"/> + <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> + <translation>Не вдалося отримати дійсні дані з сервера.<br>Переконайтеся, що сервер правильно налаштований, а також перевірте адресу та порт.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_motion_touch.cpp" line="289"/> + <source>UDP Test or calibration configuration is in progress.<br>Please wait for them to finish.</source> + <translation>Тест UDP або калібрація в процесі.<br>Будь ласка, зачекайте завершення.</translation> + </message> +</context> +<context> + <name>ConfigureNetwork</name> + <message> + <location filename="../../src/yuzu/configuration/configure_network.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_network.ui" line="17"/> + <source>Network</source> + <translation>Мережа</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_network.ui" line="25"/> + <source>General</source> + <translation>Загальні</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_network.ui" line="34"/> + <source>Network Interface</source> + <translation>Інтерфейс мережі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_network.cpp" line="15"/> + <source>None</source> + <translation>Нічого</translation> + </message> +</context> +<context> + <name>ConfigurePerGame</name> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="12"/> + <source>Dialog</source> + <translation>Діалог</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="26"/> + <source>Info</source> + <translation>Інформація</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="85"/> + <source>Name</source> + <translation>Назва</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="92"/> + <source>Title ID</source> + <translation>Ідентифікатор гри</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="129"/> + <source>Filename</source> + <translation>Ім'я файлу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="156"/> + <source>Format</source> + <translation>Формат</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="163"/> + <source>Version</source> + <translation>Версія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="170"/> + <source>Size</source> + <translation>Розмір</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.ui" line="177"/> + <source>Developer</source> + <translation>Розробник</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="57"/> + <source>Add-Ons</source> + <translation>Доповнення</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="58"/> + <source>General</source> + <translation>Загальні</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="59"/> + <source>System</source> + <translation>Система</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="60"/> + <source>CPU</source> + <translation>ЦП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="61"/> + <source>Graphics</source> + <translation>Графіка</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="62"/> + <source>Adv. Graphics</source> + <translation>Розш. Графіка</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="63"/> + <source>Audio</source> + <translation>Аудіо</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game.cpp" line="66"/> + <source>Properties</source> + <translation>Властивості</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configuration_shared.cpp" line="91"/> + <source>Use global configuration (%1)</source> + <translation>Використовувати глобальне налаштування (%1)</translation> + </message> +</context> +<context> + <name>ConfigurePerGameAddons</name> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game_addons.ui" line="17"/> + <source>Add-Ons</source> + <translation>Доповнення</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="46"/> + <source>Patch Name</source> + <translation>Назва патчу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_per_game_addons.cpp" line="47"/> + <source>Version</source> + <translation>Версія</translation> + </message> +</context> +<context> + <name>ConfigureProfileManager</name> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="17"/> + <source>Profiles</source> + <translation>Профілі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="25"/> + <source>Profile Manager</source> + <translation>Керування профілями</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="42"/> + <source>Current User</source> + <translation>Поточний користувач</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="80"/> + <source>Username</source> + <translation>Ім'я користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="110"/> + <source>Set Image</source> + <translation>Обрати зображення</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="130"/> + <source>Add</source> + <translation>Додати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="140"/> + <source>Rename</source> + <translation>Перейменувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="150"/> + <source>Remove</source> + <translation>Видалити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.ui" line="162"/> + <source>Profile management is available only when game is not running.</source> + <translation>Керування профілями недоступне, поки запущена гра.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="52"/> + <source>%1 +%2</source> + <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment> + <translation>%1 +%2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="70"/> + <source>Enter Username</source> + <translation>Введіть ім'я користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="133"/> + <source>Users</source> + <translation>Користувачі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="195"/> + <source>Enter a username for the new user:</source> + <translation>Введіть ім'я користувача для нового профілю:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="215"/> + <source>Enter a new username:</source> + <translation>Введіть нове ім'я користувача:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="240"/> + <source>Confirm Delete</source> + <translation>Підтвердити видалення</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="241"/> + <source>You are about to delete user with name "%1". Are you sure?</source> + <translation>Ви збираєтеся видалити користувача "%1". Ви впевнені?</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="268"/> + <source>Select User Image</source> + <translation>Оберіть зображення користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="269"/> + <source>JPEG Images (*.jpg *.jpeg)</source> + <translation>Зображення JPEG (*.jpg *.jpeg)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="278"/> + <source>Error deleting image</source> + <translation>Помилка під час видалення зображення</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="279"/> + <source>Error occurred attempting to overwrite previous image at: %1.</source> + <translation>Помилка під час спроби перезапису попереднього зображення в: %1.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="287"/> + <source>Error deleting file</source> + <translation>Помилка під час видалення файлу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="288"/> + <source>Unable to delete existing file: %1.</source> + <translation>Не вдалося видалити наявний файл: %1.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="295"/> + <source>Error creating user image directory</source> + <translation>Помилка під час створення папки користувацьких зображень</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="296"/> + <source>Unable to create directory %1 for storing user images.</source> + <translation>Не вийшло створити папку %1 для зберігання зображень користувача.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="301"/> + <source>Error copying user image</source> + <translation>Помилка під час копіювання зображення користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="302"/> + <source>Unable to copy image from %1 to %2</source> + <translation>Не вийшло скопіювати зображення з %1 у %2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="311"/> + <source>Error resizing user image</source> + <translation>Помилка під час зміни розміру зображення користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_profile_manager.cpp" line="312"/> + <source>Unable to resize image</source> + <translation>Неможливо змінити розмір зображення</translation> + </message> +</context> +<context> + <name>ConfigureRingController</name> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="14"/> + <source>Configure Ring Controller</source> + <translation>Налаштування контролера Ring</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="26"/> + <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> + <translation>Якщо ви хочете використовувати цей контролер, налаштуйте гравця 1 як правий контролер, а гравця 2 як подвійний Joy-Соп перед початком гри, щоб цей контролер був виявлений правильно.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="52"/> + <source>Ring Sensor Parameters</source> + <translation>Параметри сенсора Ring</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="84"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="123"/> + <source>Pull</source> + <translation>Потягнути</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="133"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="172"/> + <source>Push</source> + <translation>Натиснути</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="206"/> + <source>Deadzone: 0%</source> + <translation>Мертва зона: 0%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.ui" line="248"/> + <source>Restore Defaults</source> + <translation>За замовчуванням</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="159"/> + <source>Clear</source> + <translation>Очистити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="161"/> + <source>[not set]</source> + <translation>[не задано]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="163"/> + <source>Invert axis</source> + <translation>Інвертувати осі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="182"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="238"/> + <source>Deadzone: %1%</source> + <translation>Мертва зона: %1%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="262"/> + <source>[waiting]</source> + <translation>[очікування]</translation> + </message> +</context> +<context> + <name>ConfigureSystem</name> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="17"/> + <source>System</source> + <translation>Система</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="25"/> + <source>System Settings</source> + <translation>Налаштування системи</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="33"/> + <source>Region:</source> + <translation>Регіон:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="41"/> + <source>Auto</source> + <translation>Авто</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="46"/> + <source>Default</source> + <translation>За замовчуванням</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="51"/> + <source>CET</source> + <translation>CET</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="56"/> + <source>CST6CDT</source> + <translation>CST6CDT</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="61"/> + <source>Cuba</source> + <translation>Куба</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="66"/> + <source>EET</source> + <translation>EET</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="71"/> + <source>Egypt</source> + <translation>Єгипет</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="76"/> + <source>Eire</source> + <translation>Ейре</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="81"/> + <source>EST</source> + <translation>EST</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="86"/> + <source>EST5EDT</source> + <translation>EST5EDT</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="91"/> + <source>GB</source> + <translation>GB</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="96"/> + <source>GB-Eire</source> + <translation>GB-Ейре</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="101"/> + <source>GMT</source> + <translation>GMT</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="106"/> + <source>GMT+0</source> + <translation>GMT+0</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="111"/> + <source>GMT-0</source> + <translation>GMT-0</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="116"/> + <source>GMT0</source> + <translation>GMT0</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="121"/> + <source>Greenwich</source> + <translation>Гринвіч</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="126"/> + <source>Hongkong</source> + <translation>Гонконг</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="131"/> + <source>HST</source> + <translation>HST</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="136"/> + <source>Iceland</source> + <translation>Ісландія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="141"/> + <source>Iran</source> + <translation>Іран</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="146"/> + <source>Israel</source> + <translation>Ізраїль</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="151"/> + <source>Jamaica</source> + <translation>Ямайка</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="156"/> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="275"/> + <source>Japan</source> + <translation>Японія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="161"/> + <source>Kwajalein</source> + <translation>Кваджалейн</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="166"/> + <source>Libya</source> + <translation>Лівія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="171"/> + <source>MET</source> + <translation>MET</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="176"/> + <source>MST</source> + <translation>MST</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="181"/> + <source>MST7MDT</source> + <translation>MST7MDT</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="186"/> + <source>Navajo</source> + <translation>Навахо</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="191"/> + <source>NZ</source> + <translation>NZ</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="196"/> + <source>NZ-CHAT</source> + <translation>NZ-CHAT</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="201"/> + <source>Poland</source> + <translation>Польща</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="206"/> + <source>Portugal</source> + <translation>Португалія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="211"/> + <source>PRC</source> + <translation>PRC</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="216"/> + <source>PST8PDT</source> + <translation>PST8PDT</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="221"/> + <source>ROC</source> + <translation>ROC</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="226"/> + <source>ROK</source> + <translation>ROK</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="231"/> + <source>Singapore</source> + <translation>Сінгапур</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="236"/> + <source>Turkey</source> + <translation>Туреччина</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="241"/> + <source>UCT</source> + <translation>UCT</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="246"/> + <source>Universal</source> + <translation>Універсальний</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="251"/> + <source>UTC</source> + <translation>UTC</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="256"/> + <source>W-SU</source> + <translation>W-SU</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="261"/> + <source>WET</source> + <translation>WET</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="266"/> + <source>Zulu</source> + <translation>Зулуси</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="280"/> + <source>USA</source> + <translation>США</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="285"/> + <source>Europe</source> + <translation>Європа</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="290"/> + <source>Australia</source> + <translation>Австралія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="295"/> + <source>China</source> + <translation>Китай</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="300"/> + <source>Korea</source> + <translation>Корея</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="305"/> + <source>Taiwan</source> + <translation>Тайвань</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="313"/> + <source>Time Zone:</source> + <translation>Часовий пояс:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="320"/> + <source>Note: this can be overridden when region setting is auto-select</source> + <translation>Примітка: може бути перезаписано якщо регіон вибирається автоматично</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="324"/> + <source>Japanese (日本語)</source> + <translation>Японська (日本語)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="329"/> + <source>English</source> + <translation>Англійська (English)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="334"/> + <source>French (français)</source> + <translation>Французька (français)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="339"/> + <source>German (Deutsch)</source> + <translation>Німецька (Deutsch)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="344"/> + <source>Italian (italiano)</source> + <translation>Італійська (italiano)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="349"/> + <source>Spanish (español)</source> + <translation>Іспанська (español)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="354"/> + <source>Chinese</source> + <translation>Китайська</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="359"/> + <source>Korean (한국어)</source> + <translation>Корейська (한국어)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="364"/> + <source>Dutch (Nederlands)</source> + <translation>Голландська (Nederlands)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="369"/> + <source>Portuguese (português)</source> + <translation>Португальська (português)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="374"/> + <source>Russian (Русский)</source> + <translation>Російська (Русский)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="379"/> + <source>Taiwanese</source> + <translation>Тайванська</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="384"/> + <source>British English</source> + <translation>Британська Англійська</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="389"/> + <source>Canadian French</source> + <translation>Канадська Французька</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="394"/> + <source>Latin American Spanish</source> + <translation>Латиноамериканська Іспанська</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="399"/> + <source>Simplified Chinese</source> + <translation>Спрощена Китайська</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="404"/> + <source>Traditional Chinese (正體中文)</source> + <translation>Традиційна Китайська (正體中文)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="409"/> + <source>Brazilian Portuguese (português do Brasil)</source> + <translation>Бразильська Португальська (português do Brasil)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="417"/> + <source>Custom RTC</source> + <translation>Користувацький RTC</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="424"/> + <source>Language</source> + <translation>Мова</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="431"/> + <source>RNG Seed</source> + <translation>Сід RNG</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="439"/> + <source>Mono</source> + <translation>Моно</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="444"/> + <source>Stereo</source> + <translation>Стерео</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="449"/> + <source>Surround</source> + <translation>Об'ємний звук</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="457"/> + <source>Console ID:</source> + <translation>Ідентифікатор консолі:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="464"/> + <source>Sound output mode</source> + <translation>Режим виводу звуку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="512"/> + <source>Regenerate</source> + <translation>Перегенерувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.ui" line="537"/> + <source>System settings are available only when game is not running.</source> + <translation>Налаштування системи доступні тільки тоді, коли гру не запущено.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.cpp" line="161"/> + <source>This will replace your current virtual Switch with a new one. Your current virtual Switch will not be recoverable. This might have unexpected effects in games. This might fail, if you use an outdated config savegame. Continue?</source> + <translation>Це замінить ваш поточний віртуальний Switch новим. Ваш поточний віртуальний Switch буде безповоротно втрачено. Це може мати несподівані наслідки в іграх. Може не спрацювати, якщо ви використовуєте застарілу конфігурацію збережених ігор. Продовжити?</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.cpp" line="165"/> + <source>Warning</source> + <translation>Увага</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_system.cpp" line="173"/> + <source>Console ID: 0x%1</source> + <translation>Ідентифікатор консолі: 0x%1</translation> + </message> +</context> +<context> + <name>ConfigureTas</name> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="11"/> + <source>TAS</source> + <translation>TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="17"/> + <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> + <translation><html><head/><body><p>Зчитує вхідні дані контролера зі скриптів у тому ж форматі, що і скрипти TAS-nx.<br/>Для більш детального пояснення зверніться до <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">сторінки допомоги</span></a> на сайті yuzu.</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="27"/> + <source>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys).</source> + <translation>Щоб перевірити, які гарячі клавіші керують відтворенням/записом, зверніться до налаштувань гарячих клавіш (Налаштування - Загальні -> Гарячі клавіші).</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="37"/> + <source>WARNING: This is an experimental feature.<br/>It will not play back scripts frame perfectly with the current, imperfect syncing method.</source> + <translation>ПОПЕРЕДЖЕННЯ: Це експериментальна функція.<br/>Вона не буде ідеально відтворювати кадри сценаріїв за поточного недосконалого методу синхронізації.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="54"/> + <source>Settings</source> + <translation>Налаштування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="60"/> + <source>Enable TAS features</source> + <translation>Увімкнути функції TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="67"/> + <source>Loop script</source> + <translation>Зациклити скрипт</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="77"/> + <source>Pause execution during loads</source> + <translation>Призупинити виконання під час завантаження</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="91"/> + <source>Script Directory</source> + <translation>Папка для скриптів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="97"/> + <source>Path</source> + <translation>Шлях</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.ui" line="104"/> + <source>...</source> + <translation>...</translation> + </message> +</context> +<context> + <name>ConfigureTasDialog</name> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.cpp" line="19"/> + <source>TAS Configuration</source> + <translation>Налаштування TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_tas.cpp" line="50"/> + <source>Select TAS Load Directory...</source> + <translation>Обрати папку завантаження TAS...</translation> + </message> +</context> +<context> + <name>ConfigureTouchFromButton</name> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="14"/> + <source>Configure Touchscreen Mappings</source> + <translation>Налаштування відображення сенсорного екрана</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="22"/> + <source>Mapping:</source> + <translation>Прив'язки:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="48"/> + <source>New</source> + <translation>Новий</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="61"/> + <source>Delete</source> + <translation>Видалити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="74"/> + <source>Rename</source> + <translation>Перейменувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="92"/> + <source>Click the bottom area to add a point, then press a button to bind. +Drag points to change position, or double-click table cells to edit values.</source> + <translation>Натисніть на нижній області, щоб додати точку, після чого натисніть кнопку для прив'язки. +Перетягніть точки, щоб змінити позицію, або натисніть двічі на комірки таблиці для зміни значень.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.ui" line="116"/> + <source>Delete Point</source> + <translation>Видалити точку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="78"/> + <source>Button</source> + <translation>Кнопка</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="78"/> + <source>X</source> + <comment>X axis</comment> + <translation>X</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="78"/> + <source>Y</source> + <comment>Y axis</comment> + <translation>Y</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="195"/> + <source>New Profile</source> + <translation>Новий профіль</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="195"/> + <source>Enter the name for the new profile.</source> + <translation>Введіть ім'я вашого нового профілю.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="206"/> + <source>Delete Profile</source> + <translation>Видалити профіль</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="206"/> + <source>Delete profile %1?</source> + <translation>Видалити профіль %1?</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="219"/> + <source>Rename Profile</source> + <translation>Перейменувати профіль</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="219"/> + <source>New name:</source> + <translation>Нова назва:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="231"/> + <source>[press key]</source> + <translation>[натисніть клавішу]</translation> + </message> +</context> +<context> + <name>ConfigureTouchscreenAdvanced</name> + <message> + <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="14"/> + <source>Configure Touchscreen</source> + <translation>Налаштування сенсорного екрана</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="26"/> + <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> + <translation>Увага: Налаштування на цій сторінці впливають на внутрішню роботу емульованого сенсорного екрана yuzu. Їх зміна може призвести до небажаної поведінки, як часткова або повна непрацездатність сенсорного екрана. Використовуйте цю сторінку лише якщо ви знаєте, що робите.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="52"/> + <source>Touch Parameters</source> + <translation>Параметри сенсора</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="71"/> + <source>Touch Diameter Y</source> + <translation>Діаметр сенсора Y</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="91"/> + <source>Touch Diameter X</source> + <translation>Діаметр сенсора X</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="98"/> + <source>Rotational Angle</source> + <translation>Кут повороту</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touchscreen_advanced.ui" line="132"/> + <source>Restore Defaults</source> + <translation>За замовчуванням</translation> + </message> +</context> +<context> + <name>ConfigureUI</name> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="20"/> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="28"/> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="40"/> + <source>None</source> + <translation>Нічого</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="21"/> + <source>Small (32x32)</source> + <translation>Маленький (32х32)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="22"/> + <source>Standard (64x64)</source> + <translation>Стандартний (64х64)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="23"/> + <source>Large (128x128)</source> + <translation>Великий (128х128)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="24"/> + <source>Full Size (256x256)</source> + <translation>Повнорозмірний (256х256)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="29"/> + <source>Small (24x24)</source> + <translation>Маленький (24х24)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="30"/> + <source>Standard (48x48)</source> + <translation>Стандартний (48х48)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="31"/> + <source>Large (72x72)</source> + <translation>Великий (72х72)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="36"/> + <source>Filename</source> + <translation>Ім'я файлу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="37"/> + <source>Filetype</source> + <translation>Тип файлу</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="38"/> + <source>Title ID</source> + <translation>Ідентифікатор гри</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="39"/> + <source>Title Name</source> + <translation>Назва гри</translation> + </message> +</context> +<context> + <name>ConfigureUi</name> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="17"/> + <source>UI</source> + <translation>Інтерфейс</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="23"/> + <source>General</source> + <translation>Загальні</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="31"/> + <source>Note: Changing language will apply your configuration.</source> + <translation>Примітка: Зміна мови призведе до застосування налаштувань.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="43"/> + <source>Interface language:</source> + <translation>Мова інтерфейсу:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="57"/> + <source>Theme:</source> + <translation>Тема:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="74"/> + <source>Game List</source> + <translation>Список ігор</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="82"/> + <source>Show Compatibility List</source> + <translation>Показати список сумісності</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="89"/> + <source>Show Add-Ons Column</source> + <translation>Показувати стовпець доповнень</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="98"/> + <source>Game Icon Size:</source> + <translation>Розмір іконки гри:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="112"/> + <source>Folder Icon Size:</source> + <translation>Розмір іконки папки:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="126"/> + <source>Row 1 Text:</source> + <translation>Текст 1-го рядку:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="140"/> + <source>Row 2 Text:</source> + <translation>Текст 2-го рядку:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="157"/> + <source>Screenshots</source> + <translation>Знімки екрану</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="165"/> + <source>Ask Where To Save Screenshots (Windows Only)</source> + <translation>Запитувати куди зберігати знімки екрану (Тільки для Windows)</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="174"/> + <source>Screenshots Path: </source> + <translation>Папка для знімків екрану:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.ui" line="184"/> + <source>...</source> + <translation>...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="94"/> + <source>Select Screenshots Path...</source> + <translation>Виберіть папку для знімків екрану...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ui.cpp" line="219"/> + <source><System></source> + <translation><System></translation> + </message> +</context> +<context> + <name>ConfigureVibration</name> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="14"/> + <source>Configure Vibration</source> + <translation>Налаштування вібрації</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="23"/> + <source>Press any controller button to vibrate the controller.</source> + <translation>Натисніть будь-яку кнопку контролера, щоб викликати вібрацію.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="30"/> + <source>Vibration</source> + <translation>Вібрація</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="63"/> + <source>Player 1</source> + <translation>Гравець 1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="96"/> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="148"/> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="200"/> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="252"/> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="322"/> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="374"/> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="426"/> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="478"/> + <source>%</source> + <translation>%</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="115"/> + <source>Player 2</source> + <translation>Гравець 2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="167"/> + <source>Player 3</source> + <translation>Гравець 3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="219"/> + <source>Player 4</source> + <translation>Гравець 4</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="289"/> + <source>Player 5</source> + <translation>Гравець 5</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="341"/> + <source>Player 6</source> + <translation>Гравець 6</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="393"/> + <source>Player 7</source> + <translation>Гравець 7</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="445"/> + <source>Player 8</source> + <translation>Гравець 8</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="503"/> + <source>Settings</source> + <translation>Налаштування</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_vibration.ui" line="509"/> + <source>Enable Accurate Vibration</source> + <translation>Увімкнути точну вібрацію</translation> + </message> +</context> +<context> + <name>ConfigureWeb</name> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="14"/> + <source>Form</source> + <translation>Форма</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="17"/> + <source>Web</source> + <translation>Мережа</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="25"/> + <source>yuzu Web Service</source> + <translation>Веб-сервіс yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="31"/> + <source>By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information.</source> + <translation>Надаючи своє ім'я користувача і токен, ви погоджуєтеся дозволити yuzu збирати додаткові дані про використання, які можуть включати інформацію, що ідентифікує користувача.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="49"/> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="159"/> + <source>Verify</source> + <translation>Підтвердити</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="56"/> + <source>Sign up</source> + <translation>Реєстрація</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="66"/> + <source>Token: </source> + <translation>Токен:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="76"/> + <source>Username: </source> + <translation>Ім'я користувача:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="93"/> + <source>What is my token?</source> + <translation>Що таке токен і де його знайти?</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="118"/> + <source>Web Service configuration can only be changed when a public room isn't being hosted.</source> + <translation>Налаштування веб-служби можуть бути змінені тільки в тому випадку, коли не хоститься публічна кімната.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="128"/> + <source>Telemetry</source> + <translation>Телеметрія</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="134"/> + <source>Share anonymous usage data with the yuzu team</source> + <translation>Ділитися анонімною інформацією про використання з командою yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="141"/> + <source>Learn more</source> + <translation>Дізнатися більше</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="150"/> + <source>Telemetry ID:</source> + <translation>Ідентифікатор телеметрії:</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="166"/> + <source>Regenerate</source> + <translation>Перегенерувати</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="180"/> + <source>Discord Presence</source> + <translation>Discord Presence</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.ui" line="186"/> + <source>Show Current Game in your Discord Status</source> + <translation>Показувати поточну гру у вашому статусі Discord</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="68"/> + <source><a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Learn more</span></a></source> + <translation><a href='https://yuzu-emu.org/help/feature/telemetry/'><span style="text-decoration: underline; color:#039be5;">Дізнатися більше</span></a></translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="72"/> + <source><a href='https://profile.yuzu-emu.org/'><span style="text-decoration: underline; color:#039be5;">Sign up</span></a></source> + <translation><a href='https://profile.yuzu-emu.org/'><span style="text-decoration: underline; color:#039be5;">Реєстрація</span></a></translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="76"/> + <source><a href='https://yuzu-emu.org/wiki/yuzu-web-service/'><span style="text-decoration: underline; color:#039be5;">What is my token?</span></a></source> + <translation><a href='https://yuzu-emu.org/wiki/yuzu-web-service/'><span style="text-decoration: underline; color:#039be5;">Що таке токен і де його знайти?</span></a></translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="80"/> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="125"/> + <source>Telemetry ID: 0x%1</source> + <translation>Ідентифікатор телеметрії: 0x%1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="91"/> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="170"/> + <source>Unspecified</source> + <translation>Відсутній</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="117"/> + <source>Token not verified</source> + <translation>Токен не підтверджено</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="118"/> + <source>Token was not verified. The change to your token has not been saved.</source> + <translation>Токен не було підтверджено. Зміну вашого токена не було збережено.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="141"/> + <source>Unverified, please click Verify before saving configuration</source> + <comment>Tooltip</comment> + <translation>Не підтверджено, будь ласка, натисніть кнопку Підтвердити, перш ніж зберігати конфігурацію.</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="147"/> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="149"/> + <source>Verifying...</source> + <translation>Підтверждення...</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="164"/> + <source>Verified</source> + <comment>Tooltip</comment> + <translation>Підтверджено</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="169"/> + <source>Verification failed</source> + <comment>Tooltip</comment> + <translation>Підтверждення не було успішним</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="171"/> + <source>Verification failed</source> + <translation>Підтверждення не було успішним</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_web.cpp" line="172"/> + <source>Verification failed. Check that you have entered your token correctly, and that your internet connection is working.</source> + <translation>Підтверждення не було успішним. Переконайтеся, що ви правильно ввели свій токен і що ваше інтернет-з'єднання працює.</translation> + </message> +</context> +<context> + <name>ControllerDialog</name> + <message> + <location filename="../../src/yuzu/debugger/controller.cpp" line="20"/> + <source>Controller P1</source> + <translation>Контролер P1</translation> + </message> + <message> + <location filename="../../src/yuzu/debugger/controller.cpp" line="59"/> + <source>&Controller P1</source> + <translation>[&C] Контролер P1</translation> + </message> +</context> +<context> + <name>DirectConnect</name> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="14"/> + <source>Direct Connect</source> + <translation>Пряме підключення</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="33"/> + <source>IP Address</source> + <translation>IP-адреса</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="56"/> + <source>IP</source> + <translation>IP</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="63"/> + <source><html><head/><body><p>IPv4 address of the host</p></body></html></source> + <translation><html><head/><body><p>IPv4 адреса хоста</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="73"/> + <source>Port</source> + <translation>Порт</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="80"/> + <source><html><head/><body><p>Port number the host is listening on</p></body></html></source> + <translation><html><head/><body><p>Номер порту, який прослуховується хостом</p></body></html></translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="100"/> + <source>Nickname</source> + <translation>Псевдонім</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="114"/> + <source>Password</source> + <translation>Пароль</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.ui" line="156"/> + <source>Connect</source> + <translation>Підключитися</translation> + </message> +</context> +<context> + <name>DirectConnectWindow</name> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="127"/> + <source>Connecting</source> + <translation>Підключення</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/direct_connect.cpp" line="132"/> + <source>Connect</source> + <translation>Підключитися</translation> + </message> +</context> +<context> + <name>GMainWindow</name> + <message> + <location filename="../../src/yuzu/main.cpp" line="188"/> + <source><a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous data is collected</a> to help improve yuzu. <br/><br/>Would you like to share your usage data with us?</source> + <translation><a href='https://yuzu-emu.org/help/feature/telemetry/'>Анонімні дані збираються для того,</a> щоб допомогти поліпшити роботу yuzu. <br/><br/>Хотіли б ви ділитися даними про використання з нами?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="191"/> + <source>Telemetry</source> + <translation>Телеметрія</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="405"/> + <source>Broken Vulkan Installation Detected</source> + <translation>Виявлено пошкоджену інсталяцію Vulkan</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="406"/> + <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> + <translation>Не вдалося виконати ініціалізацію Vulkan під час завантаження.<br><br>Натисніть <a href='https://yuzu-emu.org/wiki/faq/#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>тут для отримання інструкцій щодо усунення проблеми</a>.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="734"/> + <source>Loading Web Applet...</source> + <translation>Завантаження веб-аплета...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="781"/> + <location filename="../../src/yuzu/main.cpp" line="784"/> + <source>Disable Web Applet</source> + <translation>Вимкнути веб-аплет</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="785"/> + <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? +(This can be re-enabled in the Debug settings.)</source> + <translation>Вимкнення веб-апплета може призвести до несподіваної поведінки, і його слід вимикати лише заради Super Mario 3D All-Stars. Ви впевнені, що хочете вимкнути веб-апплет? +(Його можна знову ввімкнути в налаштуваннях налагодження.)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="892"/> + <source>The amount of shaders currently being built</source> + <translation>Кількість створюваних шейдерів на цей момент</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="894"/> + <source>The current selected resolution scaling multiplier.</source> + <translation>Поточний обраний множник масштабування роздільної здатності.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="897"/> + <source>Current emulation speed. Values higher or lower than 100% indicate emulation is running faster or slower than a Switch.</source> + <translation>Поточна швидкість емуляції. Значення вище або нижче 100% вказують на те, що емуляція йде швидше або повільніше, ніж на Switch.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="900"/> + <source>How many frames per second the game is currently displaying. This will vary from game to game and scene to scene.</source> + <translation>Кількість кадрів на секунду в цей момент. Значення буде змінюватися між іграми та сценами.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="904"/> + <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> + <translation>Час, який потрібен для емуляції 1 кадру Switch, не беручи до уваги обмеження FPS або вертикальну синхронізацію. Для емуляції в повній швидкості значення має бути не більше 16,67 мс.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="983"/> + <source>VULKAN</source> + <translation>VULKAN</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="983"/> + <source>OPENGL</source> + <translation>OPENGL</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1045"/> + <source>&Clear Recent Files</source> + <translation>[&C] Очистити нещодавні файли</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1353"/> + <source>&Continue</source> + <translation>[&C] Продовжити</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1355"/> + <source>&Pause</source> + <translation>[&P] Пауза</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1435"/> + <source>yuzu is running a game</source> + <extracomment>TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the computer from sleeping</extracomment> + <translation>В yuzu запущено гру</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1566"/> + <source>Warning Outdated Game Format</source> + <translation>Попередження застарілий формат гри</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1567"/> + <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> + <translation>Для цієї гри ви використовуєте розархівований формат ROM'а, який є застарілим і був замінений іншими, такими як NCA, NAX, XCI або NSP. У розархівованих каталогах ROM'а відсутні іконки, метадані та підтримка оновлень. <br><br>Для отримання інформації про різні формати Switch, підтримувані yuzu, <a href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>перегляньте нашу вікі</a>. Це повідомлення більше не буде відображатися.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1579"/> + <location filename="../../src/yuzu/main.cpp" line="1613"/> + <source>Error while loading ROM!</source> + <translation>Помилка під час завантаження ROM!</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1580"/> + <source>The ROM format is not supported.</source> + <translation>Формат ROM'а не підтримується.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1584"/> + <source>An error occurred initializing the video core.</source> + <translation>Сталася помилка під час ініціалізації відеоядра.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1585"/> + <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> + <translation>yuzu зіткнувся з помилкою під час запуску відеоядра. Зазвичай це спричинено застарілими драйверами ГП, включно з інтегрованими. Перевірте журнал для отримання більш детальної інформації. Додаткову інформацію про доступ до журналу дивіться на наступній сторінці: <a href='https://yuzu-emu.org/help/reference/log-files/'>Як завантажити файл журналу</a>. </translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1600"/> + <source>Error while loading ROM! %1</source> + <comment>%1 signifies a numeric error code.</comment> + <translation>Помилка під час завантаження ROM'а! %1</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1603"/> + <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> + <comment>%1 signifies an error string.</comment> + <translation>%1<br>Будь ласка, дотримуйтесь <a href='https://yuzu-emu.org/help/quickstart/'>короткого керівництва користувача yuzu</a> щоб пере-дампити ваші файли<br>Ви можете звернутися до вікі yuzu</a> або Discord yuzu</a> для допомоги</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1614"/> + <source>An unknown error occurred. Please see the log for more details.</source> + <translation>Сталася невідома помилка. Будь ласка, перевірте журнал для подробиць.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1746"/> + <source>(64-bit)</source> + <translation>(64-бітний)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1746"/> + <source>(32-bit)</source> + <translation>(32-бітний)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1747"/> + <source>%1 %2</source> + <comment>%1 is the title name. %2 indicates if the title is 64-bit or 32-bit</comment> + <translation>%1 %2</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1897"/> + <source>Save Data</source> + <translation>Збереження</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1947"/> + <source>Mod Data</source> + <translation>Дані модів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1959"/> + <source>Error Opening %1 Folder</source> + <translation>Помилка під час відкриття папки %1</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1960"/> + <location filename="../../src/yuzu/main.cpp" line="2366"/> + <source>Folder does not exist!</source> + <translation>Папка не існує!</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1972"/> + <source>Error Opening Transferable Shader Cache</source> + <translation>Помилка під час відкриття переносного кешу шейдерів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="1973"/> + <source>Failed to create the shader cache directory for this title.</source> + <translation>Не вдалося створити папку кешу шейдерів для цієї гри.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2025"/> + <source>Contents</source> + <translation>Зміст</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2027"/> + <source>Update</source> + <translation>Оновлення</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2029"/> + <source>DLC</source> + <translation>DLC</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2036"/> + <source>Remove Entry</source> + <translation>Видалити запис</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2036"/> + <source>Remove Installed Game %1?</source> + <translation>Видалити встановлену гру %1?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2066"/> + <location filename="../../src/yuzu/main.cpp" line="2082"/> + <location filename="../../src/yuzu/main.cpp" line="2113"/> + <location filename="../../src/yuzu/main.cpp" line="2174"/> + <location filename="../../src/yuzu/main.cpp" line="2192"/> + <location filename="../../src/yuzu/main.cpp" line="2215"/> + <source>Successfully Removed</source> + <translation>Успішно видалено</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2067"/> + <source>Successfully removed the installed base game.</source> + <translation>Встановлену гру успішно видалено.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2070"/> + <location filename="../../src/yuzu/main.cpp" line="2085"/> + <location filename="../../src/yuzu/main.cpp" line="2108"/> + <source>Error Removing %1</source> + <translation>Помилка під час видалення %1</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2071"/> + <source>The base game is not installed in the NAND and cannot be removed.</source> + <translation>Гру не встановлено в NAND і не може буде видалено.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2083"/> + <source>Successfully removed the installed update.</source> + <translation>Встановлене оновлення успішно видалено.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2086"/> + <source>There is no update installed for this title.</source> + <translation>Для цієї гри не було встановлено оновлення.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2109"/> + <source>There are no DLC installed for this title.</source> + <translation>Для цієї гри не було встановлено DLC.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2114"/> + <source>Successfully removed %1 installed DLC.</source> + <translation>Встановлений DLC %1 було успішно видалено</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2122"/> + <source>Delete OpenGL Transferable Shader Cache?</source> + <translation>Видалити переносний кеш шейдерів OpenGL?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2124"/> + <source>Delete Vulkan Transferable Shader Cache?</source> + <translation>Видалити переносний кеш шейдерів Vulakn?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2126"/> + <source>Delete All Transferable Shader Caches?</source> + <translation>Видалити весь переносний кеш шейдерів?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2128"/> + <source>Remove Custom Game Configuration?</source> + <translation>Видалити користувацьке налаштування гри?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2134"/> + <source>Remove File</source> + <translation>Видалити файл</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2169"/> + <location filename="../../src/yuzu/main.cpp" line="2177"/> + <source>Error Removing Transferable Shader Cache</source> + <translation>Помилка під час видалення переносного кешу шейдерів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2170"/> + <location filename="../../src/yuzu/main.cpp" line="2188"/> + <source>A shader cache for this title does not exist.</source> + <translation>Кеш шейдерів для цієї гри не існує.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2175"/> + <source>Successfully removed the transferable shader cache.</source> + <translation>Переносний кеш шейдерів успішно видалено.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2178"/> + <source>Failed to remove the transferable shader cache.</source> + <translation>Не вдалося видалити переносний кеш шейдерів.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2187"/> + <location filename="../../src/yuzu/main.cpp" line="2195"/> + <source>Error Removing Transferable Shader Caches</source> + <translation>Помилка під час видалення переносного кешу шейдерів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2193"/> + <source>Successfully removed the transferable shader caches.</source> + <translation>Переносний кеш шейдерів успішно видалено.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2196"/> + <source>Failed to remove the transferable shader cache directory.</source> + <translation>Помилка під час видалення папки переносного кешу шейдерів.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2209"/> + <location filename="../../src/yuzu/main.cpp" line="2218"/> + <source>Error Removing Custom Configuration</source> + <translation>Помилка під час видалення користувацького налаштування</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2210"/> + <source>A custom configuration for this title does not exist.</source> + <translation>Користувацьких налаштувань для цієї гри не існує.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2216"/> + <source>Successfully removed the custom game configuration.</source> + <translation>Користувацьке налаштування гри успішно видалено.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2219"/> + <source>Failed to remove the custom game configuration.</source> + <translation>Не вдалося видалити користувацьке налаштування гри.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2226"/> + <location filename="../../src/yuzu/main.cpp" line="2305"/> + <source>RomFS Extraction Failed!</source> + <translation>Не вдалося вилучити RomFS!</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2227"/> + <source>There was an error copying the RomFS files or the user cancelled the operation.</source> + <translation>Сталася помилка під час копіювання файлів RomFS або користувач скасував операцію.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2285"/> + <source>Full</source> + <translation>Повний</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2285"/> + <source>Skeleton</source> + <translation>Скелет</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2287"/> + <source>Select RomFS Dump Mode</source> + <translation>Виберіть режим дампа RomFS</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2288"/> + <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> + <translation>Будь ласка, виберіть, як ви хочете виконати дамп RomFS <br>Повний скопіює всі файли в нову папку, тоді як <br>скелет створить лише структуру папок.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2306"/> + <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> + <translation>В %1 недостатньо вільного місця для вилучення RomFS. Будь ласка, звільніть місце або виберіть іншу папку для дампа в Емуляція > Налаштування > Система > Файлова система > Корінь дампа</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2313"/> + <source>Extracting RomFS...</source> + <translation>Вилучення RomFS...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2313"/> + <location filename="../../src/yuzu/main.cpp" line="2499"/> + <source>Cancel</source> + <translation>Скасувати</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2320"/> + <source>RomFS Extraction Succeeded!</source> + <translation>Вилучення RomFS пройшло успішно!</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2321"/> + <source>The operation completed successfully.</source> + <translation>Операція завершилася успішно.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2365"/> + <source>Error Opening %1</source> + <translation>Помилка відкриття %1</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2374"/> + <source>Select Directory</source> + <translation>Обрати папку</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2401"/> + <source>Properties</source> + <translation>Властивості</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2402"/> + <source>The game properties could not be loaded.</source> + <translation>Не вдалося завантажити властивості гри.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2419"/> + <source>Switch Executable (%1);;All Files (*.*)</source> + <comment>%1 is an identifier for the Switch executable file extensions.</comment> + <translation>Виконуваний файл Switch (%1);;Усі файли (*.*)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2423"/> + <source>Load File</source> + <translation>Завантажити файл</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2436"/> + <source>Open Extracted ROM Directory</source> + <translation>Відкрити папку вилученого ROM'а</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2447"/> + <source>Invalid Directory Selected</source> + <translation>Вибрано неприпустиму папку</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2448"/> + <source>The directory you have selected does not contain a 'main' file.</source> + <translation>Папка, яку ви вибрали, не містить файлу 'main'.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2458"/> + <source>Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive (*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge Image (*.xci)</source> + <translation>Встановлюваний файл Switch (*.nca, *.nsp, *.xci);;Архів контенту Nintendo (*.nca);;Пакет подачі Nintendo (*.nsp);;Образ картриджа NX (*.xci)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2463"/> + <source>Install Files</source> + <translation>Встановити файли</translation> + </message> + <message numerus="yes"> + <location filename="../../src/yuzu/main.cpp" line="2507"/> + <source>%n file(s) remaining</source> + <translation><numerusform>Залишився %n файл</numerusform><numerusform>Залишилося %n файл(ів)</numerusform><numerusform>Залишилося %n файл(ів)</numerusform><numerusform>Залишилося %n файл(ів)</numerusform></translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2509"/> + <source>Installing file "%1"...</source> + <translation>Встановлення файлу "%1"...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2555"/> + <location filename="../../src/yuzu/main.cpp" line="2569"/> + <source>Install Results</source> + <translation>Результати встановлення</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2556"/> + <source>To avoid possible conflicts, we discourage users from installing base games to the NAND. +Please, only use this feature to install updates and DLC.</source> + <translation>Щоб уникнути можливих конфліктів, ми не рекомендуємо користувачам встановлювати ігри в NAND. +Будь ласка, використовуйте цю функцію тільки для встановлення оновлень і завантажуваного контенту.</translation> + </message> + <message numerus="yes"> + <location filename="../../src/yuzu/main.cpp" line="2562"/> + <source>%n file(s) were newly installed +</source> + <translation><numerusform>%n файл було нещодавно встановлено +</numerusform><numerusform>%n файл(ів) було нещодавно встановлено +</numerusform><numerusform>%n файл(ів) було нещодавно встановлено +</numerusform><numerusform>%n файл(ів) було нещодавно встановлено +</numerusform></translation> + </message> + <message numerus="yes"> + <location filename="../../src/yuzu/main.cpp" line="2565"/> + <source>%n file(s) were overwritten +</source> + <translation><numerusform>%n файл було перезаписано +</numerusform><numerusform>%n файл(ів) було перезаписано +</numerusform><numerusform>%n файл(ів) було перезаписано +</numerusform><numerusform>%n файл(ів) було перезаписано +</numerusform></translation> + </message> + <message numerus="yes"> + <location filename="../../src/yuzu/main.cpp" line="2567"/> + <source>%n file(s) failed to install +</source> + <translation><numerusform>%n файл не вдалося встановити +</numerusform><numerusform>%n файл(ів) не вдалося встановити +</numerusform><numerusform>%n файл(ів) не вдалося встановити +</numerusform><numerusform>%n файл(ів) не вдалося встановити +</numerusform></translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2668"/> + <source>System Application</source> + <translation>Системний додаток</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2669"/> + <source>System Archive</source> + <translation>Системний архів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2670"/> + <source>System Application Update</source> + <translation>Оновлення системного додатку</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2671"/> + <source>Firmware Package (Type A)</source> + <translation>Пакет прошивки (Тип А)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2672"/> + <source>Firmware Package (Type B)</source> + <translation>Пакет прошивки (Тип Б)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2673"/> + <source>Game</source> + <translation>Гра</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2674"/> + <source>Game Update</source> + <translation>Оновлення гри</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2675"/> + <source>Game DLC</source> + <translation>DLC до гри</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2676"/> + <source>Delta Title</source> + <translation>Дельта-титул</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2679"/> + <source>Select NCA Install Type...</source> + <translation>Виберіть тип установки NCA...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2680"/> + <source>Please select the type of title you would like to install this NCA as: +(In most instances, the default 'Game' is fine.)</source> + <translation>Будь ласка, виберіть тип додатку, який ви хочете встановити для цього NCA: +(У більшості випадків, підходить стандартний вибір "Гра".)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2686"/> + <source>Failed to Install</source> + <translation>Помилка встановлення</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2687"/> + <source>The title type you selected for the NCA is invalid.</source> + <translation>Тип додатку, який ви вибрали для NCA, недійсний.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2722"/> + <source>File not found</source> + <translation>Файл не знайдено</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2723"/> + <source>File "%1" not found</source> + <translation>Файл "%1" не знайдено</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2798"/> + <source>OK</source> + <translation>ОК</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2812"/> + <source>Missing yuzu Account</source> + <translation>Відсутній обліковий запис yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2813"/> + <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> + <translation>Щоб надіслати звіт про сумісність гри, необхідно прив'язати свій обліковий запис yuzu. <br><br/>Щоб прив'язати свій обліковий запис yuzu, перейдіть у розділ Емуляція &gt; Параметри &gt; Мережа.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2823"/> + <source>Error opening URL</source> + <translation>Помилка під час відкриття URL</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="2824"/> + <source>Unable to open the URL "%1".</source> + <translation>Не вдалося відкрити URL: "%1".</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3120"/> + <source>TAS Recording</source> + <translation>Запис TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3121"/> + <source>Overwrite file of player 1?</source> + <translation>Перезаписати файл гравця 1?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3147"/> + <source>Invalid config detected</source> + <translation>Виявлено неприпустиму конфігурацію</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3148"/> + <source>Handheld controller can't be used on docked mode. Pro controller will be selected.</source> + <translation>Портативний контролер не може бути використаний у режимі док-станції. Буде обрано контролер Pro.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3243"/> + <location filename="../../src/yuzu/main.cpp" line="3271"/> + <source>Amiibo</source> + <translation>Amiibo</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3243"/> + <location filename="../../src/yuzu/main.cpp" line="3271"/> + <source>The current amiibo has been removed</source> + <translation>Поточний amiibo було прибрано</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3248"/> + <source>Error</source> + <translation>Помилка</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3248"/> + <location filename="../../src/yuzu/main.cpp" line="3283"/> + <source>The current game is not looking for amiibos</source> + <translation>Поточна гра не шукає amiibo</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3254"/> + <source>Amiibo File (%1);; All Files (*.*)</source> + <translation>Файл Amiibo (%1);; Всі Файли (*.*)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3255"/> + <source>Load Amiibo</source> + <translation>Завантажити Amiibo</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3267"/> + <source>Error loading Amiibo data</source> + <translation>Помилка під час завантаження даних Amiibo</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3277"/> + <source>The selected file is not a valid amiibo</source> + <translation>Обраний файл не є допустимим amiibo</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3280"/> + <source>The selected file is already on use</source> + <translation>Обраний файл уже використовується</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3286"/> + <source>An unknown error occurred</source> + <translation>Виникла невідома помилка</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3338"/> + <source>Capture Screenshot</source> + <translation>Зробити знімок екрану</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3339"/> + <source>PNG Image (*.png)</source> + <translation>Зображення PNG (*.png)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3405"/> + <source>TAS state: Running %1/%2</source> + <translation>Стан TAS: Виконується %1/%2</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3407"/> + <source>TAS state: Recording %1</source> + <translation>Стан TAS: Записується %1</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3409"/> + <source>TAS state: Idle %1/%2</source> + <translation>Стан TAS: Простий %1/%2</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3411"/> + <source>TAS State: Invalid</source> + <translation>Стан TAS: Неприпустимий</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3425"/> + <source>&Stop Running</source> + <translation>[&S] Зупинка</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3425"/> + <source>&Start</source> + <translation>[&S] Почати</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3426"/> + <source>Stop R&ecording</source> + <translation>[&E] Закінчити запис</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3426"/> + <source>R&ecord</source> + <translation>[&E] Запис</translation> + </message> + <message numerus="yes"> + <location filename="../../src/yuzu/main.cpp" line="3450"/> + <source>Building: %n shader(s)</source> + <translation><numerusform>Побудова: %n шейдер</numerusform><numerusform>Побудова: %n шейдер(ів)</numerusform><numerusform>Побудова: %n шейдер(ів)</numerusform><numerusform>Побудова: %n шейдер(ів)</numerusform></translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3459"/> + <source>Scale: %1x</source> + <comment>%1 is the resolution scaling factor</comment> + <translation>Масштаб: %1x</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3462"/> + <source>Speed: %1% / %2%</source> + <translation>Швидкість: %1% / %2%</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3466"/> + <source>Speed: %1%</source> + <translation>Швидкість: %1%</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3470"/> + <source>Game: %1 FPS (Unlocked)</source> + <translation>Гра: %1 FPS (Необмежено)</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3473"/> + <source>Game: %1 FPS</source> + <translation>Гра: %1 FPS</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3475"/> + <source>Frame: %1 ms</source> + <translation>Кадр: %1 мс</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3486"/> + <source>GPU NORMAL</source> + <translation>ГП НОРМАЛЬНО</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3491"/> + <source>GPU HIGH</source> + <translation>ГП ВИСОКО</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3496"/> + <source>GPU EXTREME</source> + <translation>ГП ЕКСТРИМ</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3501"/> + <source>GPU ERROR</source> + <translation>ГП ПОМИЛКА</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3510"/> + <source>DOCKED</source> + <translation>В ДОК-СТАНЦІЇ</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3510"/> + <source>HANDHELD</source> + <translation>ПОРТАТИВНИЙ</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3517"/> + <source>NEAREST</source> + <translation>НАЙБЛИЖЧІЙ</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3520"/> + <location filename="../../src/yuzu/main.cpp" line="3535"/> + <source>BILINEAR</source> + <translation>БІЛІНІЙНИЙ</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3523"/> + <source>BICUBIC</source> + <translation>БІКУБІЧНИЙ</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3526"/> + <source>GAUSSIAN</source> + <translation>ГАУС</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3529"/> + <source>SCALEFORCE</source> + <translation>SCALEFORCE</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3532"/> + <source>FSR</source> + <translation>FSR</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3544"/> + <location filename="../../src/yuzu/main.cpp" line="3550"/> + <source>NO AA</source> + <translation>БЕЗ ЗГЛАДЖУВАННЯ</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3547"/> + <source>FXAA</source> + <translation>FXAA</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3624"/> + <source>The game you are trying to load requires additional files from your Switch to be dumped before playing.<br/><br/>For more information on dumping these files, please see the following wiki page: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source> + <translation>Гра, яку ви намагаєтеся завантажити, вимагає, щоб додаткові файли були здамплені з вашого Switch перед початком гри. <br/><br/>Для отримання додаткової інформації про дамп цих файлів див. наступну вікі: <a href='https://yuzu-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Дамп системних архівів і загальних шрифтів з консолі</a>. <br/><br/>Хочете повернутися до списку ігор? Продовження емуляції може призвести до збоїв, пошкодження збережених даних або інших помилок.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3639"/> + <source>yuzu was unable to locate a Switch system archive. %1</source> + <translation>yuzu не вдалося знайти системний архів Switch. %1</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3641"/> + <source>yuzu was unable to locate a Switch system archive: %1. %2</source> + <translation>yuzu не вдалося знайти системний архів Switch: %1. %2</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3645"/> + <source>System Archive Not Found</source> + <translation>Системний архів не знайдено</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3647"/> + <source>System Archive Missing</source> + <translation>Відсутній системний архів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3653"/> + <source>yuzu was unable to locate the Switch shared fonts. %1</source> + <translation>yuzu не вдалося знайти загальні шрифти Switch. %1</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3654"/> + <source>Shared Fonts Not Found</source> + <translation>Загальні шрифти не знайдено</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3656"/> + <source>Shared Font Missing</source> + <translation>Загальні шрифти відсутні</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3662"/> + <source>Fatal Error</source> + <translation>Фатальна помилка</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3663"/> + <source>yuzu has encountered a fatal error, please see the log for more details. For more information on accessing the log, please see the following page: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? Continuing emulation may result in crashes, corrupted save data, or other bugs.</source> + <translation>yuzu зіткнувся з фатальною помилкою, перевірте журнал для отримання більш детальної інформації. Для отримання додаткової інформації про доступ до журналу відкрийте наступну сторінку: <a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Як завантажити файл журналу</a>.<br/><br/>Ви хочете повернутися до списку ігор? Продовження емуляції може призвести до збоїв, пошкодження збережень або інших помилок.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3672"/> + <source>Fatal Error encountered</source> + <translation>Сталася фатальна помилка</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3695"/> + <source>Confirm Key Rederivation</source> + <translation>Підтвердіть перерахунок ключа</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3696"/> + <source>You are about to force rederive all of your keys. +If you do not know what this means or what you are doing, +this is a potentially destructive action. +Please make sure this is what you want +and optionally make backups. + +This will delete your autogenerated key files and re-run the key derivation module.</source> + <translation>Ви збираєтеся примусово перерахувати всі ваші ключі. +Якщо ви не знаєте, що це означає або що ви робите, +це потенційно руйнівна дія. +Будь ласка, переконайтеся, що це те, що ви хочете +і, по бажанню, зробіть резервні копії. + +Це видалить ваші автоматично згенеровані файли ключів і повторно запустить модуль розрахунку ключів.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3728"/> + <source>Missing fuses</source> + <translation>Відсутні запобіжники</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3731"/> + <source> - Missing BOOT0</source> + <translation>- Відсутній BOOT0</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3734"/> + <source> - Missing BCPKG2-1-Normal-Main</source> + <translation>- Відсутній BCPKG2-1-Normal-Main</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3737"/> + <source> - Missing PRODINFO</source> + <translation> - Відсутній PRODINFO</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3741"/> + <source>Derivation Components Missing</source> + <translation>Компоненти розрахунку відсутні</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3742"/> + <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> + <translation>Ключі шифрування відсутні.<br>Будь ласка, дотримуйтесь <a href='https://yuzu-emu.org/help/quickstart/'>короткого керівництва користувача yuzu</a>, щоб отримати всі ваші ключі, прошивку та ігри<br><br><small>(%1)</small></translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3751"/> + <source>Deriving keys... +This may take up to a minute depending +on your system's performance.</source> + <translation>Отримання ключів... +Це може зайняти до хвилини залежно від +від продуктивності вашої системи.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3753"/> + <source>Deriving Keys</source> + <translation>Отримання ключів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3798"/> + <source>Select RomFS Dump Target</source> + <translation>Оберіть ціль для дампа RomFS</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3799"/> + <source>Please select which RomFS you would like to dump.</source> + <translation>Будь ласка, виберіть, який RomFS ви хочете здампити.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3814"/> + <source>Are you sure you want to close yuzu?</source> + <translation>Ви впевнені, що хочете закрити yuzu?</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3815"/> + <location filename="../../src/yuzu/main.cpp" line="3913"/> + <location filename="../../src/yuzu/main.cpp" line="3926"/> + <source>yuzu</source> + <translation>yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3914"/> + <source>Are you sure you want to stop the emulation? Any unsaved progress will be lost.</source> + <translation>Ви впевнені, що хочете зупинити емуляцію? Будь-який незбережений прогрес буде втрачено.</translation> + </message> + <message> + <location filename="../../src/yuzu/main.cpp" line="3923"/> + <source>The currently running application has requested yuzu to not exit. + +Would you like to bypass this and exit anyway?</source> + <translation>Запущений на даний момент додаток просить yuzu не завершувати роботу. + +Чи хочете ви обійти це і вийти в будь-якому випадку?</translation> + </message> +</context> +<context> + <name>GRenderWindow</name> + <message> + <location filename="../../src/yuzu/bootmanager.cpp" line="1047"/> + <source>OpenGL not available!</source> + <translation>OpenGL недоступний!</translation> + </message> + <message> + <location filename="../../src/yuzu/bootmanager.cpp" line="1048"/> + <source>yuzu has not been compiled with OpenGL support.</source> + <translation>yuzu не було зібрано з підтримкою OpenGL.</translation> + </message> + <message> + <location filename="../../src/yuzu/bootmanager.cpp" line="1067"/> + <location filename="../../src/yuzu/bootmanager.cpp" line="1087"/> + <source>Error while initializing OpenGL!</source> + <translation>Помилка під час ініціалізації OpenGL!</translation> + </message> + <message> + <location filename="../../src/yuzu/bootmanager.cpp" line="1068"/> + <source>Your GPU may not support OpenGL, or you do not have the latest graphics driver.</source> + <translation>Ваш ГП може не підтримувати OpenGL, або у вас встановлено застарілий графічний драйвер.</translation> + </message> + <message> + <location filename="../../src/yuzu/bootmanager.cpp" line="1077"/> + <source>Error while initializing OpenGL 4.6!</source> + <translation>Помилка під час ініціалізації OpenGL 4.6!</translation> + </message> + <message> + <location filename="../../src/yuzu/bootmanager.cpp" line="1078"/> + <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> + <translation>Ваш ГП може не підтримувати OpenGL 4.6, або у вас встановлено застарілий графічний драйвер.<br><br>Рендерер GL:<br>%1</translation> + </message> + <message> + <location filename="../../src/yuzu/bootmanager.cpp" line="1088"/> + <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> + <translation>Ваш ГП може не підтримувати одне або кілька необхідних розширень OpenGL. Будь ласка, переконайтеся в тому, що у вас встановлено останній графічний драйвер.<br><br>Рендерер GL:<br>%1<br><br>Розширення, що не підтримуються:<br>%2</translation> + </message> +</context> +<context> + <name>GameList</name> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="532"/> + <source>Favorite</source> + <translation>Улюблені</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="534"/> + <source>Start Game</source> + <translation>Запустити гру</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="536"/> + <source>Start Game without Custom Configuration</source> + <translation>Запустити гру без користувацького налаштування</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="538"/> + <source>Open Save Data Location</source> + <translation>Відкрити папку для збережень</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="539"/> + <source>Open Mod Data Location</source> + <translation>Відкрити папку для модів</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="541"/> + <source>Open Transferable Pipeline Cache</source> + <translation>Відкрити переносний кеш конвеєра</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="543"/> + <source>Remove</source> + <translation>Видалити</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="544"/> + <source>Remove Installed Update</source> + <translation>Видалити встановлене оновлення</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="545"/> + <source>Remove All Installed DLC</source> + <translation>Видалити усі DLC</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="546"/> + <source>Remove Custom Configuration</source> + <translation>Видалити користувацьке налаштування</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="547"/> + <source>Remove OpenGL Pipeline Cache</source> + <translation>Видалити кеш конвеєра OpenGL</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="548"/> + <source>Remove Vulkan Pipeline Cache</source> + <translation>Видалити кеш конвеєра Vulkan</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="550"/> + <source>Remove All Pipeline Caches</source> + <translation>Видалити весь кеш конвеєра </translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="551"/> + <source>Remove All Installed Contents</source> + <translation>Видалити весь встановлений вміст</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="552"/> + <location filename="../../src/yuzu/game_list.cpp" line="553"/> + <source>Dump RomFS</source> + <translation>Дамп RomFS</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="554"/> + <source>Dump RomFS to SDMC</source> + <translation>Здампити RomFS у SDMC</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="555"/> + <source>Copy Title ID to Clipboard</source> + <translation>Скопіювати ідентифікатор додатку в буфер обміну</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="556"/> + <source>Navigate to GameDB entry</source> + <translation>Перейти до сторінки GameDB</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="558"/> + <source>Properties</source> + <translation>Властивості</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="630"/> + <source>Scan Subfolders</source> + <translation>Сканувати підпапки</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="631"/> + <source>Remove Game Directory</source> + <translation>Видалити директорію гри</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="650"/> + <source>▲ Move Up</source> + <translation>▲ Перемістити вверх</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="651"/> + <source>▼ Move Down</source> + <translation>▼ Перемістити вниз</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="652"/> + <source>Open Directory Location</source> + <translation>Відкрити розташування папки</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="697"/> + <source>Clear</source> + <translation>Очистити</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="761"/> + <source>Name</source> + <translation>Назва</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="762"/> + <source>Compatibility</source> + <translation>Сумісність</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="763"/> + <source>Add-ons</source> + <translation>Доповнення</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="764"/> + <source>File type</source> + <translation>Тип файлу</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="765"/> + <source>Size</source> + <translation>Розмір</translation> + </message> +</context> +<context> + <name>GameListItemCompat</name> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="149"/> + <source>Perfect</source> + <translation>Ідеально</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="149"/> + <source>Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without +any workarounds needed.</source> + <translation>Гра працює бездоганно, без звукових або графічних артефактів, усі протестовані функції працюють без обхідних шляхів.</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="150"/> + <source>Great</source> + <translation>Чудово</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="150"/> + <source>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some +workarounds.</source> + <translation>Гра працює з невеликими графічними або звуковими артефактами і може бути пройдена від + початку до кінця. Можуть знадобитися обхідні шляхи.</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="151"/> + <source>Okay</source> + <translation>Добре</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="151"/> + <source>Game functions with major graphical or audio glitches, but game is playable from start to finish with +workarounds.</source> + <translation>Гра працює з істотними графічними або звуковими артефактами, але може бути пройдена +з використанням обхідних шляхів.</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="152"/> + <source>Bad</source> + <translation>Погано</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="152"/> + <source>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches +even with workarounds.</source> + <translation>Гра працює, але з істотними графічними або звуковими артефактами. +У деяких частинах неможливо просунутися навіть з обхідними шляхами.</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="153"/> + <source>Intro/Menu</source> + <translation>Вступ/Меню</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="153"/> + <source>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start +Screen.</source> + <translation>У гру неможливо грати через графічні або звукові артефакти. +Неможливо просунутися далі стартового екрана.</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="154"/> + <source>Won't Boot</source> + <translation>Не запускається</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="154"/> + <source>The game crashes when attempting to startup.</source> + <translation>Гра вилітає під час запуску.</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="155"/> + <source>Not Tested</source> + <translation>Не перевірено</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="155"/> + <source>The game has not yet been tested.</source> + <translation>Гру ще не перевіряли на сумісність.</translation> + </message> +</context> +<context> + <name>GameListPlaceholder</name> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="935"/> + <source>Double-click to add a new folder to the game list</source> + <translation>Натисніть двічі, щоб додати нову папку до списку ігор</translation> + </message> +</context> +<context> + <name>GameListSearchField</name> + <message numerus="yes"> + <location filename="../../src/yuzu/game_list.cpp" line="86"/> + <source>%1 of %n result(s)</source> + <translation><numerusform>%1 із %n результат(ів)</numerusform><numerusform>%1 із %n результат(ів)</numerusform><numerusform>%1 із %n результат(ів)</numerusform><numerusform>%1 із %n результат(ів)</numerusform></translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="777"/> + <source>Filter:</source> + <translation>Пошук:</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list.cpp" line="778"/> + <source>Enter pattern to filter</source> + <translation>Введіть текст для пошуку</translation> + </message> +</context> +<context> + <name>HostRoom</name> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="14"/> + <source>Create Room</source> + <translation>Створити кімнату</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="37"/> + <source>Room Name</source> + <translation>Назва кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="51"/> + <source>Preferred Game</source> + <translation>Переважна гра</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="61"/> + <source>Max Players</source> + <translation>Максимальна кількість гравців</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="91"/> + <source>Username</source> + <translation>Ім'я користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="101"/> + <source>(Leave blank for open game)</source> + <translation>(Залиште порожнім для відкритої гри)</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="118"/> + <source>Password</source> + <translation>Пароль</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="125"/> + <source>Port</source> + <translation>Порт</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="139"/> + <source>Room Description</source> + <translation>Опис кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="153"/> + <source>Load Previous Ban List</source> + <translation>Завантажити попередній список заблокованих</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="184"/> + <source>Public</source> + <translation>Публічна</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="189"/> + <source>Unlisted</source> + <translation>Прихована</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.ui" line="197"/> + <source>Host Room</source> + <translation>Створити кімнату</translation> + </message> +</context> +<context> + <name>HostRoomWindow</name> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.cpp" line="182"/> + <source>Error</source> + <translation>Помилка</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/host_room.cpp" line="183"/> + <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. +Debug Message: </source> + <translation>Не вдалося оголосити кімнату в публічному фойє. Щоб хостити публічну кімнату, у вас має бути діючий обліковий запис yuzu, налаштований в Емуляція -> Налаштування -> Мережа. Якщо ви не хочете оголошувати кімнату в публічному лобі, виберіть замість цього прихований тип. +Повідомлення налагодження:</translation> + </message> +</context> +<context> + <name>Hotkeys</name> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="73"/> + <source>Audio Mute/Unmute</source> + <translation>Увімкнення/вимкнення звуку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="73"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="74"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="75"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="76"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="77"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="78"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="79"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="80"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="81"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="82"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="83"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="84"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="85"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="86"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="87"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="88"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="89"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="90"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="91"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="92"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="93"/> + <location filename="../../src/yuzu/configuration/config.cpp" line="94"/> + <source>Main Window</source> + <translation>Основне вікно</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="74"/> + <source>Audio Volume Down</source> + <translation>Зменшити гучність звуку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="75"/> + <source>Audio Volume Up</source> + <translation>Підвищити гучність звуку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="76"/> + <source>Capture Screenshot</source> + <translation>Зробити знімок екрану</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="77"/> + <source>Change Adapting Filter</source> + <translation>Змінити адаптуючий фільтр</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="78"/> + <source>Change Docked Mode</source> + <translation>Змінити режим консолі</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="79"/> + <source>Change GPU Accuracy</source> + <translation>Змінити точність ГП</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="80"/> + <source>Continue/Pause Emulation</source> + <translation>Продовження/Пауза емуляції</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="81"/> + <source>Exit Fullscreen</source> + <translation>Вийти з повноекранного режиму</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="82"/> + <source>Exit yuzu</source> + <translation>Вийти з yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="83"/> + <source>Fullscreen</source> + <translation>Повний екран</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="84"/> + <source>Load File</source> + <translation>Завантажити файл</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="85"/> + <source>Load/Remove Amiibo</source> + <translation>Завантажити/видалити Amiibo</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="86"/> + <source>Restart Emulation</source> + <translation>Перезапустити емуляцію</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="87"/> + <source>Stop Emulation</source> + <translation>Зупинити емуляцію</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="88"/> + <source>TAS Record</source> + <translation>Запис TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="89"/> + <source>TAS Reset</source> + <translation>Скидання TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="90"/> + <source>TAS Start/Stop</source> + <translation>Старт/Стоп TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="91"/> + <source>Toggle Filter Bar</source> + <translation>Переключити панель пошуку</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="92"/> + <source>Toggle Framerate Limit</source> + <translation>Переключити обмеження частоти кадрів</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="93"/> + <source>Toggle Mouse Panning</source> + <translation>Переключити панорамування миші</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/config.cpp" line="94"/> + <source>Toggle Status Bar</source> + <translation>Переключити панель стану</translation> + </message> +</context> +<context> + <name>InstallDialog</name> + <message> + <location filename="../../src/yuzu/install_dialog.cpp" line="29"/> + <source>Please confirm these are the files you wish to install.</source> + <translation>Будь ласка, переконайтеся, що це ті файли, які ви хочете встановити.</translation> + </message> + <message> + <location filename="../../src/yuzu/install_dialog.cpp" line="32"/> + <source>Installing an Update or DLC will overwrite the previously installed one.</source> + <translation>Встановлення оновлення або завантажуваного контенту перезапише раніше встановлене.</translation> + </message> + <message> + <location filename="../../src/yuzu/install_dialog.cpp" line="36"/> + <source>Install</source> + <translation>Встановити</translation> + </message> + <message> + <location filename="../../src/yuzu/install_dialog.cpp" line="50"/> + <source>Install Files to NAND</source> + <translation>Встановити файли в NAND</translation> + </message> +</context> +<context> + <name>LimitableInputDialog</name> + <message> + <location filename="../../src/yuzu/util/limitable_input_dialog.cpp" line="61"/> + <source>The text can't contain any of the following characters: +%1</source> + <translation>У тексті неприпустимі такі символи: +%1</translation> + </message> +</context> +<context> + <name>LoadingScreen</name> + <message> + <location filename="../../src/yuzu/loading_screen.ui" line="84"/> + <source>Loading Shaders 387 / 1628</source> + <translation>Завантаження шейдерів 387 / 1628</translation> + </message> + <message> + <location filename="../../src/yuzu/loading_screen.ui" line="121"/> + <source>Loading Shaders %v out of %m</source> + <translation>Завантаження шейдерів %v із %m</translation> + </message> + <message> + <location filename="../../src/yuzu/loading_screen.ui" line="135"/> + <source>Estimated Time 5m 4s</source> + <translation>Залишилося приблизно 5м 4с</translation> + </message> + <message> + <location filename="../../src/yuzu/loading_screen.cpp" line="83"/> + <source>Loading...</source> + <translation>Завантаження...</translation> + </message> + <message> + <location filename="../../src/yuzu/loading_screen.cpp" line="84"/> + <source>Loading Shaders %1 / %2</source> + <translation>Завантаження шейдерів %1 / %2</translation> + </message> + <message> + <location filename="../../src/yuzu/loading_screen.cpp" line="85"/> + <source>Launching...</source> + <translation>Запуск...</translation> + </message> + <message> + <location filename="../../src/yuzu/loading_screen.cpp" line="170"/> + <source>Estimated Time %1</source> + <translation>Залишилося приблизно %1</translation> + </message> +</context> +<context> + <name>Lobby</name> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="14"/> + <source>Public Room Browser</source> + <translation>Браузер публічних кімнат</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="32"/> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="39"/> + <source>Nickname</source> + <translation>Псевдонім</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="59"/> + <source>Filters</source> + <translation>Фільтри</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="66"/> + <source>Search</source> + <translation>Пошук</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="76"/> + <source>Games I Own</source> + <translation>Ігри, якими я володію</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="83"/> + <source>Hide Full Rooms</source> + <translation>Приховати повні кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.ui" line="103"/> + <source>Refresh Lobby</source> + <translation>Оновити фойє</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="112"/> + <source>Password Required to Join</source> + <translation>Для входу необхідний пароль</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="112"/> + <source>Password:</source> + <translation>Пароль:</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="215"/> + <source>Players</source> + <translation>Гравці</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="216"/> + <source>Room Name</source> + <translation>Назва кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="217"/> + <source>Preferred Game</source> + <translation>Переважна гра</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="218"/> + <source>Host</source> + <translation>Хост</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="225"/> + <source>Refreshing</source> + <translation>Оновлення</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby.cpp" line="282"/> + <source>Refresh List</source> + <translation>Оновити список</translation> + </message> +</context> +<context> + <name>MainWindow</name> + <message> + <location filename="../../src/yuzu/main.ui" line="14"/> + <source>yuzu</source> + <translation>yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="44"/> + <source>&File</source> + <translation>[&F] Файл</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="48"/> + <source>&Recent Files</source> + <translation>[&R] Нещодавні файли</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="67"/> + <source>&Emulation</source> + <translation>[&E] Емуляція</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="78"/> + <source>&View</source> + <translation>[&V] Вигляд</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="82"/> + <source>&Reset Window Size</source> + <translation>[&R] Скинути розмір вікна</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="87"/> + <source>&Debugging</source> + <translation>[&D] Налагодження</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="92"/> + <source>Reset Window Size to &720p</source> + <translation>Скинути розмір вікна до &720p</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="95"/> + <source>Reset Window Size to 720p</source> + <translation>Скинути розмір вікна до 720p</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="100"/> + <source>Reset Window Size to &900p</source> + <translation>Скинути розмір вікна до &900p</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="103"/> + <source>Reset Window Size to 900p</source> + <translation>Скинути розмір вікна до 900p</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="108"/> + <source>Reset Window Size to &1080p</source> + <translation>Скинути розмір вікна до &1080p</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="111"/> + <source>Reset Window Size to 1080p</source> + <translation>Скинути розмір вікна до 1080p</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="128"/> + <source>&Multiplayer</source> + <translation>[&M] Мультиплеєр</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="139"/> + <source>&Tools</source> + <translation>[&T] Інструменти</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="143"/> + <source>&TAS</source> + <translation>[&T] TAS</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="158"/> + <source>&Help</source> + <translation>[&H] Допомога</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="179"/> + <source>&Install Files to NAND...</source> + <translation>[&I] Встановити файли в NAND...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="184"/> + <source>L&oad File...</source> + <translation>[&O] Завантажити файл...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="189"/> + <source>Load &Folder...</source> + <translation>[&F] Завантажити папку...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="194"/> + <source>E&xit</source> + <translation>[&X] Вихід</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="202"/> + <source>&Pause</source> + <translation>[&P] Пауза</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="210"/> + <source>&Stop</source> + <translation>[&S] Стоп</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="215"/> + <source>&Reinitialize keys...</source> + <translation>[&R] Переініціалізувати ключі...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="220"/> + <source>&About yuzu</source> + <translation>[&A] Про yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="228"/> + <source>Single &Window Mode</source> + <translation>[&W] Режим одного вікна</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="233"/> + <source>Con&figure...</source> + <translation>[&F] Налаштування...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="241"/> + <source>Display D&ock Widget Headers</source> + <translation>[&O] Відображати заголовки віджетів дока</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="249"/> + <source>Show &Filter Bar</source> + <translation>[&F] Показати панель пошуку</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="257"/> + <source>Show &Status Bar</source> + <translation>[&S] Показати панель статусу</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="260"/> + <source>Show Status Bar</source> + <translation>Показати панель статусу</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="268"/> + <source>&Browse Public Game Lobby</source> + <translation>[&B] Переглянути публічні ігрові фойє</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="276"/> + <source>&Create Room</source> + <translation>[&C] Створити кімнату</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="284"/> + <source>&Leave Room</source> + <translation>[&L] Залишити кімнату</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="289"/> + <source>&Direct Connect to Room</source> + <translation>[&D] Пряме під'єднання до кімнати</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="297"/> + <source>&Show Current Room</source> + <translation>[&S] Показати поточну кімнату</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="305"/> + <source>F&ullscreen</source> + <translation>[&U] Повноекранний</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="313"/> + <source>&Restart</source> + <translation>[&R] Перезапустити</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="321"/> + <source>Load/Remove &Amiibo...</source> + <translation>[&A] Завантажити/Видалити Amiibo...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="329"/> + <source>&Report Compatibility</source> + <translation>[&R] Повідомити про сумісність</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="337"/> + <source>Open &Mods Page</source> + <translation>[&M] Відкрити сторінку модів</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="342"/> + <source>Open &Quickstart Guide</source> + <translation>[&Q] Відкрити посібник користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="347"/> + <source>&FAQ</source> + <translation>[&F] ЧАП</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="352"/> + <source>Open &yuzu Folder</source> + <translation>[&Y] Відкрити папку yuzu</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="360"/> + <source>&Capture Screenshot</source> + <translation>[&C] Зробити знімок екрану</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="365"/> + <source>&Configure TAS...</source> + <translation>[&C] Налаштування TAS...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="373"/> + <source>Configure C&urrent Game...</source> + <translation>[&U] Налаштувати поточну гру...</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="381"/> + <source>&Start</source> + <translation>[&S] Почати</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="389"/> + <source>&Reset</source> + <translation>[&S] Скинути</translation> + </message> + <message> + <location filename="../../src/yuzu/main.ui" line="397"/> + <source>R&ecord</source> + <translation>[&E] Запис</translation> + </message> +</context> +<context> + <name>MicroProfileDialog</name> + <message> + <location filename="../../src/yuzu/debugger/profiler.cpp" line="50"/> + <source>&MicroProfile</source> + <translation>[&M] MicroProfile</translation> + </message> +</context> +<context> + <name>ModerationDialog</name> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="6"/> + <source>Moderation</source> + <translation>Модерація</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="20"/> + <source>Ban List</source> + <translation>Список заблокованих</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="41"/> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="73"/> + <source>Refreshing</source> + <translation>Оновлення</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.ui" line="51"/> + <source>Unban</source> + <translation>Розблокувати</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="40"/> + <source>Subject</source> + <translation>Суб'єкт</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="41"/> + <source>Type</source> + <translation>Тип</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="83"/> + <source>Forum Username</source> + <translation>Ім'я користувача на форумі</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="88"/> + <source>IP Address</source> + <translation>IP-адреса</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/moderation_dialog.cpp" line="95"/> + <source>Refresh</source> + <translation>Оновити</translation> + </message> +</context> +<context> + <name>MultiplayerState</name> + <message> + <location filename="../../src/yuzu/multiplayer/state.cpp" line="90"/> + <source>Current connection status</source> + <translation>Поточний стан з'єднання</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/state.cpp" line="117"/> + <source>Not Connected. Click here to find a room!</source> + <translation>Не з'єднано. Натисніть тут, щоб знайти кімнату!</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/state.cpp" line="123"/> + <source>Not Connected</source> + <translation>Не з'єднано</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/state.cpp" line="129"/> + <source>Connected</source> + <translation>З'єднано</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/state.cpp" line="136"/> + <source>New Messages Received</source> + <translation>Отримано нові повідомлення</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/state.cpp" line="207"/> + <source>Error</source> + <translation>Помилка</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/state.cpp" line="208"/> + <source>Failed to update the room information. Please check your Internet connection and try hosting the room again. +Debug Message: </source> + <translation>Не вдалося оновити інформацію про кімнату. Будь ласка, перевірте підключення до Інтернету та спробуйте знову зайти в кімнату. +Повідомлення налагодження:</translation> + </message> +</context> +<context> + <name>NetworkMessage</name> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="11"/> + <source>Username is not valid. Must be 4 to 20 alphanumeric characters.</source> + <translation>Ім'я користувача неприпустиме. Має бути від 4 до 20 буквено-цифрових символів.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="13"/> + <source>Room name is not valid. Must be 4 to 20 alphanumeric characters.</source> + <translation>Назва кімнати неприпустима. Має бути від 4 до 20 буквено-цифрових символів.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="15"/> + <source>Username is already in use or not valid. Please choose another.</source> + <translation>Ім'я користувача вже використовується або недійсне. Будь ласка, виберіть інше.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="17"/> + <source>IP is not a valid IPv4 address.</source> + <translation>IP-адреса не є дійсною адресою IPv4.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="19"/> + <source>Port must be a number between 0 to 65535.</source> + <translation>Порт повинен бути числом від 0 до 65535.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="20"/> + <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> + <translation>Ви повинні вибрати бажану гру, щоб хостити кімнату. Якщо у вашому списку ігор ще немає жодної гри, додайте папку з грою, натиснувши на значок плюса у списку ігор.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="24"/> + <source>Unable to find an internet connection. Check your internet settings.</source> + <translation>Неможливо знайти підключення до Інтернету. Перевірте налаштування інтернету.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="26"/> + <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> + <translation>Неможливо підключитися до хоста. Перевірте правильність налаштувань підключення. Якщо під'єднання, як і раніше, неможливе, зв'яжіться з хостом кімнати та переконайтеся, що хост правильно налаштований із прокинутим зовнішнім портом.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="30"/> + <source>Unable to connect to the room because it is already full.</source> + <translation>Неможливо підключитися до кімнати, оскільки вона вже заповнена.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="32"/> + <source>Creating a room failed. Please retry. Restarting yuzu might be necessary.</source> + <translation>Створення кімнати не вдалося. Будь ласка, повторіть спробу. Можливо, потрібно перезапустити yuzu.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="34"/> + <source>The host of the room has banned you. Speak with the host to unban you or try a different room.</source> + <translation>Хост кімнати заблокував вас. Поговоріть із хостом, щоб він розблокував вас, або спробуйте іншу кімнату.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="37"/> + <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> + <translation>Невідповідність версій! Будь ласка, оновіть yuzu до останньої версії. Якщо проблема не зникне, зверніться до хосту кімнати і попросіть його оновити сервер.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="39"/> + <source>Incorrect password.</source> + <translation>Невірний пароль.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="40"/> + <source>An unknown error occurred. If this error continues to occur, please open an issue</source> + <translation>Сталася невідома помилка. Якщо ця помилка продовжує виникати, будь ласка, відкрийте проблему</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="43"/> + <source>Connection to room lost. Try to reconnect.</source> + <translation>З'єднання з кімнатою втрачено. Спробуйте підключитися знову.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="45"/> + <source>You have been kicked by the room host.</source> + <translation>Вас вигнав хост кімнати.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="47"/> + <source>IP address is already in use. Please choose another.</source> + <translation>IP-адреса вже використовується. Будь ласка, виберіть іншу.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="49"/> + <source>You do not have enough permission to perform this action.</source> + <translation>У вас немає достатніх дозволів для виконання цієї дії.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="50"/> + <source>The user you are trying to kick/ban could not be found. +They may have left the room.</source> + <translation>Користувача, якого ви намагаєтеся вигнати/заблокувати, не знайдено. +Можливо, вони покинули кімнату.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="52"/> + <source>No valid network interface is selected. +Please go to Configure -> System -> Network and make a selection.</source> + <translation>Не вибрано припустимий інтерфейс мережі. +Будь ласка, перейдіть у Налаштування -> Система -> Мережа та зробіть вибір.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="68"/> + <source>Game already running</source> + <translation>Гру вже запущено</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="69"/> + <source>Joining a room when the game is already running is discouraged and can cause the room feature not to work correctly. +Proceed anyway?</source> + <translation>Приєднуватися до кімнати, коли гру вже запущено, не рекомендується, це може призвести до неправильної роботи функції кімнати. +Все одно продовжити?</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="75"/> + <source>Leave Room</source> + <translation>Залишити кімнату</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="76"/> + <source>You are about to close the room. Any network connections will be closed.</source> + <translation>Ви збираєтеся закрити кімнату. Усі мережеві підключення буде закрито.</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="81"/> + <source>Disconnect</source> + <translation>Від'єднатися</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="82"/> + <source>You are about to leave the room. Any network connections will be closed.</source> + <translation>Ви збираєтеся покинути кімнату. Усі мережеві підключення буде закрито.</translation> + </message> +</context> +<context> + <name>NetworkMessage::ErrorManager</name> + <message> + <location filename="../../src/yuzu/multiplayer/message.cpp" line="63"/> + <source>Error</source> + <translation>Помилка</translation> + </message> +</context> +<context> + <name>OverlayDialog</name> + <message> + <location filename="../../src/yuzu/util/overlay_dialog.ui" line="14"/> + <source>Dialog</source> + <translation>Діалог</translation> + </message> + <message> + <location filename="../../src/yuzu/util/overlay_dialog.ui" line="134"/> + <location filename="../../src/yuzu/util/overlay_dialog.ui" line="353"/> + <source>Cancel</source> + <translation>Скасувати</translation> + </message> + <message> + <location filename="../../src/yuzu/util/overlay_dialog.ui" line="152"/> + <location filename="../../src/yuzu/util/overlay_dialog.ui" line="371"/> + <source>OK</source> + <translation>ОК</translation> + </message> + <message> + <location filename="../../src/yuzu/util/overlay_dialog.ui" line="313"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;"> +<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> + <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:18pt; font-weight:400; font-style:normal;"> +<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> + </message> +</context> +<context> + <name>PlayerControlPreview</name> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player_widget.cpp" line="1575"/> + <source>START/PAUSE</source> + <translation>СТАРТ/ПАУЗА</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <location filename="../../src/yuzu/multiplayer/lobby_p.h" line="236"/> + <source>%1 is not playing a game</source> + <translation>%1 не грає у гру</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/lobby_p.h" line="238"/> + <source>%1 is playing %2</source> + <translation>%1 грає в %2</translation> + </message> + <message> + <location filename="../../src/yuzu/multiplayer/chat_room.cpp" line="142"/> + <source>Not playing a game</source> + <translation>Не грає в гру</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="242"/> + <source>Installed SD Titles</source> + <translation>Встановлені SD ігри</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="250"/> + <source>Installed NAND Titles</source> + <translation>Встановлені NAND ігри</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="258"/> + <source>System Titles</source> + <translation>Системні ігри</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="301"/> + <source>Add New Game Directory</source> + <translation>Додати нову папку з іграми</translation> + </message> + <message> + <location filename="../../src/yuzu/game_list_p.h" line="324"/> + <source>Favorites</source> + <translation>Улюблені</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="21"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="30"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="41"/> + <source>Shift</source> + <translation>Shift</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="23"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="32"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="43"/> + <source>Ctrl</source> + <translation>Ctrl</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="25"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="34"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="45"/> + <source>Alt</source> + <translation>Alt</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="35"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="318"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="384"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="159"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="226"/> + <source>[not set]</source> + <translation>[не задано]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="47"/> + <source>Hat %1 %2</source> + <translation>Напр. %1 %2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="54"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="407"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="411"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="415"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="419"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="249"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="253"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="257"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="261"/> + <source>Axis %1%2</source> + <translation>Ось %1%2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="60"/> + <source>Button %1</source> + <translation>Кнопка %1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_touch_from_button.cpp" line="66"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="378"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="392"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="422"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="220"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="234"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="264"/> + <source>[unknown]</source> + <translation>[невідомо]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="45"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="56"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="124"/> + <source>Left</source> + <translation>Вліво</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="47"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="58"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="127"/> + <source>Right</source> + <translation>Вправо</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="49"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="60"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="133"/> + <source>Down</source> + <translation>Вниз</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="51"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="62"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="130"/> + <source>Up</source> + <translation>Вгору</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="53"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="64"/> + <source>Z</source> + <translation>Z</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="55"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="66"/> + <source>R</source> + <translation>R</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="57"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="68"/> + <source>L</source> + <translation>L</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="59"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="70"/> + <source>A</source> + <translation>A</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="61"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="72"/> + <source>B</source> + <translation>B</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="63"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="74"/> + <source>X</source> + <translation>X</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="65"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="76"/> + <source>Y</source> + <translation>Y</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="67"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="78"/> + <source>Start</source> + <translation>Start</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="69"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="80"/> + <source>L1</source> + <translation>L1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="71"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="82"/> + <source>L2</source> + <translation>L2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="73"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="84"/> + <source>L3</source> + <translation>L3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="75"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="86"/> + <source>R1</source> + <translation>R1</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="77"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="88"/> + <source>R2</source> + <translation>R2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="79"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="90"/> + <source>R3</source> + <translation>R3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="81"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="92"/> + <source>Circle</source> + <translation>Кружечок</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="83"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="94"/> + <source>Cross</source> + <translation>Хрестик</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="85"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="96"/> + <source>Square</source> + <translation>Квадратик</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="87"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="98"/> + <source>Triangle</source> + <translation>Трикутничок</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="89"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="100"/> + <source>Share</source> + <translation>Share</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="91"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="102"/> + <source>Options</source> + <translation>Options</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="93"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="118"/> + <source>[undefined]</source> + <translation>[невизначено]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="328"/> + <source>%1%2</source> + <translation>%1%2</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="332"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="174"/> + <source>[invalid]</source> + <translation>[неприпустимо]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="342"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="366"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="184"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="208"/> + <source>%1%2Hat %3</source> + <translation>%1%2Напр. %3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="346"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="369"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="372"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="188"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="211"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="214"/> + <source>%1%2Axis %3</source> + <translation>%1%2Ось %3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="352"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="194"/> + <source>%1%2Axis %3,%4,%5</source> + <translation>%1%2Ось %3,%4,%5</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="356"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="198"/> + <source>%1%2Motion %3</source> + <translation>%1%2Рух %3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="360"/> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="375"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="202"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="217"/> + <source>%1%2Button %3</source> + <translation>%1%2Кнопка %3</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_ringcon.cpp" line="402"/> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="244"/> + <source>[unused]</source> + <translation>[не використаний]</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="104"/> + <source>Home</source> + <translation>Home</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="106"/> + <source>Touch</source> + <translation>Сенсор</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="108"/> + <source>Wheel</source> + <comment>Indicates the mouse wheel</comment> + <translation>Коліщатко</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="110"/> + <source>Backward</source> + <translation>Назад</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="112"/> + <source>Forward</source> + <translation>Вперед</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="114"/> + <source>Task</source> + <translation>Задача</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="116"/> + <source>Extra</source> + <translation>Додаткова</translation> + </message> + <message> + <location filename="../../src/yuzu/configuration/configure_input_player.cpp" line="170"/> + <source>%1%2%3</source> + <translation>%1%2%3</translation> + </message> +</context> +<context> + <name>QtControllerSelectorDialog</name> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="14"/> + <source>Controller Applet</source> + <translation>Аплет контролера</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="129"/> + <source>Supported Controller Types:</source> + <translation>Підтримувані типи контролерів:</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="282"/> + <source>Players:</source> + <translation>Гравці:</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="300"/> + <source>1 - 8</source> + <translation>1 - 8</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="418"/> + <source>P4</source> + <translation>P4</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="514"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="711"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="912"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1222"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1459"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1656"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1857"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2054"/> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="414"/> + <source>Pro Controller</source> + <translation>Контролер Pro</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="519"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="716"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="917"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1227"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1464"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1661"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1862"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2059"/> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="418"/> + <source>Dual Joycons</source> + <translation>Подвійні Joy-Con'и</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="524"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="721"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="922"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1232"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1469"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1666"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1867"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2064"/> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="422"/> + <source>Left Joycon</source> + <translation>Лівий Joy-Con</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="529"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="726"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="927"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1237"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1474"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1671"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1872"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2069"/> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="426"/> + <source>Right Joycon</source> + <translation>Правий Joy-Con</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="538"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="735"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="941"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1246"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1483"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1680"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1881"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2078"/> + <source>Use Current Config</source> + <translation>Використовувати поточну конфігурацію</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="615"/> + <source>P2</source> + <translation>P2</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="812"/> + <source>P1</source> + <translation>P1</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="932"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2303"/> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="430"/> + <source>Handheld</source> + <translation>Портативний</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1126"/> + <source>P3</source> + <translation>P3</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1363"/> + <source>P7</source> + <translation>P7</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1560"/> + <source>P8</source> + <translation>P8</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1757"/> + <source>P5</source> + <translation>P5</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="1958"/> + <source>P6</source> + <translation>P6</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2272"/> + <source>Console Mode</source> + <translation>Режим консолі</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2293"/> + <source>Docked</source> + <translation>У док-станції</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2313"/> + <source>Vibration</source> + <translation>Вібрація</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2349"/> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2395"/> + <source>Configure</source> + <translation>Налаштувати</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2359"/> + <source>Motion</source> + <translation>Рух</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2405"/> + <source>Profiles</source> + <translation>Профілі</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2432"/> + <source>Create</source> + <translation>Створити</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2467"/> + <source>Controllers</source> + <translation>Контролери</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2481"/> + <source>1</source> + <translation>1</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2508"/> + <source>2</source> + <translation>2</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2518"/> + <source>4</source> + <translation>4</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2528"/> + <source>3</source> + <translation>3</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2538"/> + <source>Connected</source> + <translation>З'єднано</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2552"/> + <source>5</source> + <translation>5</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2569"/> + <source>7</source> + <translation>7</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2586"/> + <source>6</source> + <translation>6</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.ui" line="2596"/> + <source>8</source> + <translation>8</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="434"/> + <source>GameCube Controller</source> + <translation>Контролер GameCube</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="443"/> + <source>Poke Ball Plus</source> + <translation>Poke Ball Plus</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="447"/> + <source>NES Controller</source> + <translation>Контролер NES</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="451"/> + <source>SNES Controller</source> + <translation>Контролер SNES</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="455"/> + <source>N64 Controller</source> + <translation>Контролер N64</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_controller.cpp" line="459"/> + <source>Sega Genesis</source> + <translation>Sega Genesis</translation> + </message> +</context> +<context> + <name>QtErrorDisplay</name> + <message> + <location filename="../../src/yuzu/applets/qt_error.cpp" line="20"/> + <location filename="../../src/yuzu/applets/qt_error.cpp" line="33"/> + <location filename="../../src/yuzu/applets/qt_error.cpp" line="48"/> + <source>Error Code: %1-%2 (0x%3)</source> + <translation>Код помилки: %1-%2 (0x%3)</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_error.cpp" line="24"/> + <source>An error has occurred. +Please try again or contact the developer of the software.</source> + <translation>Сталася помилка. +Будь ласка, спробуйте ще раз або зв'яжіться з розробником ПЗ.</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_error.cpp" line="37"/> + <source>An error occurred on %1 at %2. +Please try again or contact the developer of the software.</source> + <translation>Сталася помилка на %1 у %2. +Будь ласка, спробуйте ще раз або зв'яжіться з розробником ПЗ.</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_error.cpp" line="52"/> + <source>An error has occurred. + +%1 + +%2</source> + <translation>Сталася помилка. + +%1 + +%2</translation> + </message> +</context> +<context> + <name>QtProfileSelectionDialog</name> + <message> + <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="23"/> + <source>%1 +%2</source> + <comment>%1 is the profile username, %2 is the formatted UUID (e.g. 00112233-4455-6677-8899-AABBCCDDEEFF))</comment> + <translation>%1 +%2</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="53"/> + <source>Select a user:</source> + <translation>Оберить користувача</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="83"/> + <source>Users</source> + <translation>Користувачі</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_profile_select.cpp" line="123"/> + <source>Profile Selector</source> + <translation>Вибір профілю</translation> + </message> +</context> +<context> + <name>QtSoftwareKeyboardDialog</name> + <message> + <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="14"/> + <source>Software Keyboard</source> + <translation>Віртуальна клавіатура</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="199"/> + <source>Enter Text</source> + <translation>Введіть текст</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_software_keyboard.ui" line="479"/> + <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> +<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> + <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:26pt; font-weight:400; font-style:normal;"> +<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> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_software_keyboard.cpp" line="403"/> + <location filename="../../src/yuzu/applets/qt_software_keyboard.cpp" line="413"/> + <source>OK</source> + <translation>ОК</translation> + </message> + <message> + <location filename="../../src/yuzu/applets/qt_software_keyboard.cpp" line="413"/> + <source>Cancel</source> + <translation>Скасувати</translation> + </message> +</context> +<context> + <name>SequenceDialog</name> + <message> + <location filename="../../src/yuzu/util/sequence_dialog/sequence_dialog.cpp" line="10"/> + <source>Enter a hotkey</source> + <translation>Введіть комбінацію</translation> + </message> +</context> +<context> + <name>WaitTreeCallstack</name> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="147"/> + <source>Call stack</source> + <translation>Стек викликів</translation> + </message> +</context> +<context> + <name>WaitTreeMutexInfo</name> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="126"/> + <source>waiting for mutex 0x%1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="133"/> + <source>has waiters: %1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="135"/> + <source>owner handle: 0x%1</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>WaitTreeObjectList</name> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="228"/> + <source>waiting for all objects</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="229"/> + <source>waiting for one of the following objects</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>WaitTreeSynchronizationObject</name> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="185"/> + <source>[%1] %2 %3</source> + <translation>[%1] %2 %3</translation> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="212"/> + <source>waited by no thread</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>WaitTreeThread</name> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="250"/> + <source>runnable</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="252"/> + <source>paused</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="258"/> + <source>sleeping</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="261"/> + <source>waiting for IPC reply</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="264"/> + <source>waiting for objects</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="267"/> + <source>waiting for condition variable</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="270"/> + <source>waiting for address arbiter</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="273"/> + <source>waiting for suspend resume</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="276"/> + <source>waiting</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="281"/> + <source>initialized</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="284"/> + <source>terminated</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="287"/> + <source>unknown</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="292"/> + <source> PC = 0x%1 LR = 0x%2</source> + <translation> PC = 0x%1 LR = 0x%2</translation> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="342"/> + <source>ideal</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="345"/> + <source>core %1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="349"/> + <source>processor = %1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="351"/> + <source>ideal core = %1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="353"/> + <source>affinity mask = %1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="354"/> + <source>thread id = %1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="355"/> + <source>priority = %1(current) / %2(normal)</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="359"/> + <source>last running ticks = %1</source> + <translation type="unfinished"/> + </message> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="367"/> + <source>not waiting for mutex</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>WaitTreeThreadList</name> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="391"/> + <source>waited by thread</source> + <translation type="unfinished"/> + </message> +</context> +<context> + <name>WaitTreeWidget</name> + <message> + <location filename="../../src/yuzu/debugger/wait_tree.cpp" line="465"/> + <source>&Wait Tree</source> + <translation>[&W] Дерево очікування</translation> + </message> +</context> +</TS>
\ No newline at end of file diff --git a/dist/qt_themes/colorful/icons/48x48/bad_folder.png b/dist/qt_themes/colorful/icons/48x48/bad_folder.png Binary files differindex a7ab7a1f6..34069c6b2 100644 --- a/dist/qt_themes/colorful/icons/48x48/bad_folder.png +++ b/dist/qt_themes/colorful/icons/48x48/bad_folder.png diff --git a/dist/qt_themes/default/icons/256x256/plus_folder.png b/dist/qt_themes/default/icons/256x256/plus_folder.png Binary files differindex 3a49669a3..f44c80c3a 100644 --- a/dist/qt_themes/default/icons/256x256/plus_folder.png +++ b/dist/qt_themes/default/icons/256x256/plus_folder.png diff --git a/dist/qt_themes/default/icons/256x256/yuzu.png b/dist/qt_themes/default/icons/256x256/yuzu.png Binary files differindex bd5cf533f..238adeb89 100644 --- a/dist/qt_themes/default/icons/256x256/yuzu.png +++ b/dist/qt_themes/default/icons/256x256/yuzu.png diff --git a/dist/qt_themes/qdarkstyle/icons/256x256/plus_folder.png b/dist/qt_themes/qdarkstyle/icons/256x256/plus_folder.png Binary files differindex 002101114..14c90fea5 100644 --- a/dist/qt_themes/qdarkstyle/icons/256x256/plus_folder.png +++ b/dist/qt_themes/qdarkstyle/icons/256x256/plus_folder.png diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3575a3cb3..0ac3d254e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,13 +58,11 @@ if (MSVC) # Warnings /W3 - /we4018 # 'expression': signed/unsigned mismatch + /WX + /we4062 # Enumerator 'identifier' in a switch of enum 'enumeration' is not handled - /we4101 # 'identifier': unreferenced local variable /we4189 # 'identifier': local variable is initialized but not referenced /we4265 # 'class': class has virtual functions, but destructor is not virtual - /we4267 # 'var': conversion from 'size_t' to 'type', possible loss of data - /we4305 # 'context': truncation from 'type1' to 'type2' /we4388 # 'expression': signed/unsigned mismatch /we4389 # 'operator': signed/unsigned mismatch /we4456 # Declaration of 'identifier' hides previous local declaration @@ -75,10 +73,13 @@ if (MSVC) /we4547 # 'operator': operator before comma has no effect; expected operator with side-effect /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? /we4555 # Expression has no effect; expected expression with side-effect - /we4715 # 'function': not all control paths return a value - /we4834 # Discarding return value of function with 'nodiscard' attribute + /we4826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior. /we5038 # data member 'member1' will be initialized after data member 'member2' + /we5233 # explicit lambda capture 'identifier' is not used /we5245 # 'function': unreferenced function with internal linkage has been removed + + /wd4100 # 'identifier': unreferenced formal parameter + /wd4324 # 'struct_name': structure was padded due to __declspec(align()) ) if (USE_CCACHE) @@ -99,24 +100,18 @@ if (MSVC) set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) else() add_compile_options( - -Wall - -Werror=array-bounds - -Werror=implicit-fallthrough + -Werror=all + -Werror=extra -Werror=missing-declarations - -Werror=missing-field-initializers - -Werror=reorder -Werror=shadow - -Werror=sign-compare - -Werror=switch - -Werror=uninitialized - -Werror=unused-function - -Werror=unused-result - -Werror=unused-variable - -Wextra - -Wmissing-declarations + -Werror=unused + -Wno-attributes -Wno-invalid-offsetof -Wno-unused-parameter + + $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init> + $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field> ) if (ARCHITECTURE_x86_64) diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 144f1bab2..0a1f3bf18 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -206,20 +206,11 @@ if (MSVC) /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data - /we4456 # Declaration of 'identifier' hides previous local declaration - /we4457 # Declaration of 'identifier' hides function parameter - /we4458 # Declaration of 'identifier' hides class member - /we4459 # Declaration of 'identifier' hides global declaration + /we4800 # Implicit conversion from 'type' to bool. Possible information loss ) else() target_compile_options(audio_core PRIVATE -Werror=conversion - -Werror=ignored-qualifiers - -Werror=shadow - -Werror=unused-variable - - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> -Wno-sign-conversion ) diff --git a/src/audio_core/in/audio_in_system.cpp b/src/audio_core/in/audio_in_system.cpp index 6b7e6715c..4324cafd8 100644 --- a/src/audio_core/in/audio_in_system.cpp +++ b/src/audio_core/in/audio_in_system.cpp @@ -56,7 +56,7 @@ Result System::IsConfigValid(const std::string_view device_name, return ResultSuccess; } -Result System::Initialize(std::string& device_name, const AudioInParameter& in_params, +Result System::Initialize(std::string device_name, const AudioInParameter& in_params, const u32 handle_, const u64 applet_resource_user_id_) { auto result{IsConfigValid(device_name, in_params)}; if (result.IsError()) { diff --git a/src/audio_core/in/audio_in_system.h b/src/audio_core/in/audio_in_system.h index b9dc0e60f..1c5154638 100644 --- a/src/audio_core/in/audio_in_system.h +++ b/src/audio_core/in/audio_in_system.h @@ -97,7 +97,7 @@ public: * @param applet_resource_user_id - Unused. * @return Result code. */ - Result Initialize(std::string& device_name, const AudioInParameter& in_params, u32 handle, + Result Initialize(std::string device_name, const AudioInParameter& in_params, u32 handle, u64 applet_resource_user_id); /** diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp index 48a801923..a66208ed9 100644 --- a/src/audio_core/out/audio_out_system.cpp +++ b/src/audio_core/out/audio_out_system.cpp @@ -49,8 +49,8 @@ Result System::IsConfigValid(std::string_view device_name, return Service::Audio::ERR_INVALID_CHANNEL_COUNT; } -Result System::Initialize(std::string& device_name, const AudioOutParameter& in_params, u32 handle_, - u64& applet_resource_user_id_) { +Result System::Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle_, + u64 applet_resource_user_id_) { auto result = IsConfigValid(device_name, in_params); if (result.IsError()) { return result; diff --git a/src/audio_core/out/audio_out_system.h b/src/audio_core/out/audio_out_system.h index 0817b2f37..b95cb91be 100644 --- a/src/audio_core/out/audio_out_system.h +++ b/src/audio_core/out/audio_out_system.h @@ -88,8 +88,8 @@ public: * @param applet_resource_user_id - Unused. * @return Result code. */ - Result Initialize(std::string& device_name, const AudioOutParameter& in_params, u32 handle, - u64& applet_resource_user_id); + Result Initialize(std::string device_name, const AudioOutParameter& in_params, u32 handle, + u64 applet_resource_user_id); /** * Start this system. diff --git a/src/audio_core/renderer/behavior/info_updater.cpp b/src/audio_core/renderer/behavior/info_updater.cpp index c0a307b89..574cf0982 100644 --- a/src/audio_core/renderer/behavior/info_updater.cpp +++ b/src/audio_core/renderer/behavior/info_updater.cpp @@ -91,7 +91,7 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context, voice_info.Initialize(); for (u32 channel = 0; channel < in_param.channel_count; channel++) { - std::memset(voice_states[channel], 0, sizeof(VoiceState)); + *voice_states[channel] = {}; } } diff --git a/src/audio_core/renderer/command/effect/biquad_filter.cpp b/src/audio_core/renderer/command/effect/biquad_filter.cpp index 1baae74fd..edb30ce72 100644 --- a/src/audio_core/renderer/command/effect/biquad_filter.cpp +++ b/src/audio_core/renderer/command/effect/biquad_filter.cpp @@ -94,7 +94,7 @@ void BiquadFilterCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor void BiquadFilterCommand::Process(const ADSP::CommandListProcessor& processor) { auto state_{reinterpret_cast<VoiceState::BiquadFilterState*>(state)}; if (needs_init) { - std::memset(state_, 0, sizeof(VoiceState::BiquadFilterState)); + *state_ = {}; } auto input_buffer{ diff --git a/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp b/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp index b3c3ba4ba..48a7cba8a 100644 --- a/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp +++ b/src/audio_core/renderer/command/effect/multi_tap_biquad_filter.cpp @@ -30,7 +30,7 @@ void MultiTapBiquadFilterCommand::Process(const ADSP::CommandListProcessor& proc for (u32 i = 0; i < filter_tap_count; i++) { auto state{reinterpret_cast<VoiceState::BiquadFilterState*>(states[i])}; if (needs_init[i]) { - std::memset(state, 0, sizeof(VoiceState::BiquadFilterState)); + *state = {}; } ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state, diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp index bde794cd1..4fac30c7c 100644 --- a/src/audio_core/renderer/system.cpp +++ b/src/audio_core/renderer/system.cpp @@ -98,9 +98,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_) : core{core_}, adsp{core.AudioCore().GetADSP()}, adsp_rendered_event{adsp_rendered_event_} {} Result System::Initialize(const AudioRendererParameterInternal& params, - Kernel::KTransferMemory* transfer_memory, const u64 transfer_memory_size, - const u32 process_handle_, const u64 applet_resource_user_id_, - const s32 session_id_) { + Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, + u32 process_handle_, u64 applet_resource_user_id_, s32 session_id_) { if (!CheckValidRevision(params.revision)) { return Service::Audio::ERR_INVALID_REVISION; } @@ -354,6 +353,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params, render_time_limit_percent = 100; drop_voice = params.voice_drop_enabled && params.execution_mode == ExecutionMode::Auto; + drop_voice_param = 1.0f; + num_voices_dropped = 0; allocator.Align(0x40); command_workbuffer_size = allocator.GetRemainingSize(); @@ -547,7 +548,7 @@ u32 System::GetRenderingTimeLimit() const { return render_time_limit_percent; } -void System::SetRenderingTimeLimit(const u32 limit) { +void System::SetRenderingTimeLimit(u32 limit) { render_time_limit_percent = limit; } @@ -635,7 +636,7 @@ void System::SendCommandToDsp() { } u64 System::GenerateCommand(std::span<u8> in_command_buffer, - [[maybe_unused]] const u64 command_buffer_size_) { + [[maybe_unused]] u64 command_buffer_size_) { PoolMapper::ClearUseState(memory_pool_workbuffer, memory_pool_count); const auto start_time{core.CoreTiming().GetClockTicks()}; @@ -693,7 +694,8 @@ u64 System::GenerateCommand(std::span<u8> in_command_buffer, voice_context.SortInfo(); - const auto start_estimated_time{command_buffer.estimated_process_time}; + const auto start_estimated_time{drop_voice_param * + static_cast<f32>(command_buffer.estimated_process_time)}; command_generator.GenerateVoiceCommands(); command_generator.GenerateSubMixCommands(); @@ -712,11 +714,16 @@ u64 System::GenerateCommand(std::span<u8> in_command_buffer, render_context.behavior->IsAudioRendererProcessingTimeLimit70PercentSupported(); time_limit_percent = 70.0f; } + + const auto end_estimated_time{drop_voice_param * + static_cast<f32>(command_buffer.estimated_process_time)}; + const auto estimated_time{start_estimated_time - end_estimated_time}; + const auto time_limit{static_cast<u32>( - static_cast<f32>(start_estimated_time - command_buffer.estimated_process_time) + - (((time_limit_percent / 100.0f) * 2'880'000.0) * - (static_cast<f32>(render_time_limit_percent) / 100.0f)))}; - num_voices_dropped = DropVoices(command_buffer, start_estimated_time, time_limit); + estimated_time + (((time_limit_percent / 100.0f) * 2'880'000.0) * + (static_cast<f32>(render_time_limit_percent) / 100.0f)))}; + num_voices_dropped = + DropVoices(command_buffer, static_cast<u32>(start_estimated_time), time_limit); } command_list_header->buffer_size = command_buffer.size; @@ -737,24 +744,33 @@ u64 System::GenerateCommand(std::span<u8> in_command_buffer, return command_buffer.size; } -u32 System::DropVoices(CommandBuffer& command_buffer, const u32 estimated_process_time, - const u32 time_limit) { +f32 System::GetVoiceDropParameter() const { + return drop_voice_param; +} + +void System::SetVoiceDropParameter(f32 voice_drop_) { + drop_voice_param = voice_drop_; +} + +u32 System::DropVoices(CommandBuffer& command_buffer, u32 estimated_process_time, u32 time_limit) { u32 i{0}; auto command_list{command_buffer.command_list.data() + sizeof(CommandListHeader)}; - ICommand* cmd{}; + ICommand* cmd{nullptr}; - for (; i < command_buffer.count; i++) { + // Find a first valid voice to drop + while (i < command_buffer.count) { cmd = reinterpret_cast<ICommand*>(command_list); - if (cmd->type != CommandId::Performance && - cmd->type != CommandId::DataSourcePcmInt16Version1 && - cmd->type != CommandId::DataSourcePcmInt16Version2 && - cmd->type != CommandId::DataSourcePcmFloatVersion1 && - cmd->type != CommandId::DataSourcePcmFloatVersion2 && - cmd->type != CommandId::DataSourceAdpcmVersion1 && - cmd->type != CommandId::DataSourceAdpcmVersion2) { + if (cmd->type == CommandId::Performance || + cmd->type == CommandId::DataSourcePcmInt16Version1 || + cmd->type == CommandId::DataSourcePcmInt16Version2 || + cmd->type == CommandId::DataSourcePcmFloatVersion1 || + cmd->type == CommandId::DataSourcePcmFloatVersion2 || + cmd->type == CommandId::DataSourceAdpcmVersion1 || + cmd->type == CommandId::DataSourceAdpcmVersion2) { break; } command_list += cmd->size; + i++; } if (cmd == nullptr || command_buffer.count == 0 || i >= command_buffer.count) { @@ -767,6 +783,7 @@ u32 System::DropVoices(CommandBuffer& command_buffer, const u32 estimated_proces const auto node_id_type{cmd->node_id >> 28}; const auto node_id_base{cmd->node_id & 0xFFF}; + // If the new estimated process time falls below the limit, we're done dropping. if (estimated_process_time <= time_limit) { break; } @@ -775,6 +792,7 @@ u32 System::DropVoices(CommandBuffer& command_buffer, const u32 estimated_proces break; } + // Don't drop voices marked with the highest priority. auto& voice_info{voice_context.GetInfo(node_id_base)}; if (voice_info.priority == HighestVoicePriority) { break; @@ -783,18 +801,23 @@ u32 System::DropVoices(CommandBuffer& command_buffer, const u32 estimated_proces voices_dropped++; voice_info.voice_dropped = true; - if (i < command_buffer.count) { - while (cmd->node_id == node_id) { - if (cmd->type == CommandId::DepopPrepare) { - cmd->enabled = true; - } else if (cmd->type == CommandId::Performance || !cmd->enabled) { - cmd->enabled = false; - } - i++; - command_list += cmd->size; - cmd = reinterpret_cast<ICommand*>(command_list); + // First iteration should drop the voice, and then iterate through all of the commands tied + // to the voice. We don't need reverb on a voice which we've just removed, for example. + // Depops can't be removed otherwise we'll introduce audio popping, and we don't + // remove perf commands. Lower the estimated time for each command dropped. + while (i < command_buffer.count && cmd->node_id == node_id) { + if (cmd->type == CommandId::DepopPrepare) { + cmd->enabled = true; + } else if (cmd->enabled && cmd->type != CommandId::Performance) { + cmd->enabled = false; + estimated_process_time -= static_cast<u32>( + drop_voice_param * static_cast<f32>(cmd->estimated_process_time)); } + command_list += cmd->size; + cmd = reinterpret_cast<ICommand*>(command_list); + i++; } + i++; } return voices_dropped; } diff --git a/src/audio_core/renderer/system.h b/src/audio_core/renderer/system.h index bcbe65b07..429196e41 100644 --- a/src/audio_core/renderer/system.h +++ b/src/audio_core/renderer/system.h @@ -196,6 +196,20 @@ public: */ u32 DropVoices(CommandBuffer& command_buffer, u32 estimated_process_time, u32 time_limit); + /** + * Get the current voice drop parameter. + * + * @return The current voice drop. + */ + f32 GetVoiceDropParameter() const; + + /** + * Set the voice drop parameter. + * + * @param The new voice drop. + */ + void SetVoiceDropParameter(f32 voice_drop); + private: /// Core system Core::System& core; @@ -301,6 +315,8 @@ private: u32 num_voices_dropped{}; /// Tick that rendering started u64 render_start_tick{}; + /// Parameter to control the threshold for dropping voices if the audio graph gets too large + f32 drop_voice_param{1.0f}; }; } // namespace AudioRenderer diff --git a/src/audio_core/renderer/voice/voice_context.cpp b/src/audio_core/renderer/voice/voice_context.cpp index eafb51b01..a501a677d 100644 --- a/src/audio_core/renderer/voice/voice_context.cpp +++ b/src/audio_core/renderer/voice/voice_context.cpp @@ -74,8 +74,8 @@ void VoiceContext::SortInfo() { } std::ranges::sort(sorted_voice_info, [](const VoiceInfo* a, const VoiceInfo* b) { - return a->priority != b->priority ? a->priority < b->priority - : a->sort_order < b->sort_order; + return a->priority != b->priority ? a->priority > b->priority + : a->sort_order > b->sort_order; }); } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 46cf75fde..c0555f840 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -156,12 +156,13 @@ if (MSVC) ) target_compile_options(common PRIVATE /W4 - /WX + + /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data + /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /we4800 # Implicit conversion from 'type' to bool. Possible information loss ) else() target_compile_options(common PRIVATE - -Werror - $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation> ) endif() diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 7e1df62b1..e4e58ea45 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h @@ -141,10 +141,6 @@ public: constexpr BitField(BitField&&) noexcept = default; constexpr BitField& operator=(BitField&&) noexcept = default; - [[nodiscard]] constexpr operator T() const { - return Value(); - } - constexpr void Assign(const T& value) { #ifdef _MSC_VER storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value)); @@ -162,6 +158,17 @@ public: return ExtractValue(storage); } + template <typename ConvertedToType> + [[nodiscard]] constexpr ConvertedToType As() const { + static_assert(!std::is_same_v<T, ConvertedToType>, + "Unnecessary cast. Use Value() instead."); + return static_cast<ConvertedToType>(Value()); + } + + [[nodiscard]] constexpr operator T() const { + return Value(); + } + [[nodiscard]] constexpr explicit operator bool() const { return Value() != 0; } diff --git a/src/common/bounded_threadsafe_queue.h b/src/common/bounded_threadsafe_queue.h index 7e465549b..21217801e 100644 --- a/src/common/bounded_threadsafe_queue.h +++ b/src/common/bounded_threadsafe_queue.h @@ -21,11 +21,6 @@ constexpr size_t hardware_interference_size = std::hardware_destructive_interfer constexpr size_t hardware_interference_size = 64; #endif -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4324) -#endif - template <typename T, size_t capacity = 0x400> class MPSCQueue { public: @@ -160,8 +155,4 @@ private: static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible"); }; -#ifdef _MSC_VER -#pragma warning(pop) -#endif - } // namespace Common diff --git a/src/common/concepts.h b/src/common/concepts.h index a97555f6a..a9acff3e7 100644 --- a/src/common/concepts.h +++ b/src/common/concepts.h @@ -3,24 +3,14 @@ #pragma once +#include <iterator> #include <type_traits> namespace Common { -// Check if type is like an STL container +// Check if type satisfies the ContiguousContainer named requirement. template <typename T> -concept IsSTLContainer = requires(T t) { - typename T::value_type; - typename T::iterator; - typename T::const_iterator; - // TODO(ogniK): Replace below is std::same_as<void> when MSVC supports it. - t.begin(); - t.end(); - t.cbegin(); - t.cend(); - t.data(); - t.size(); -}; +concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>; // TODO: Replace with std::derived_from when the <concepts> header // is available on all supported platforms. @@ -34,4 +24,12 @@ concept DerivedFrom = requires { template <typename From, typename To> concept ConvertibleTo = std::is_convertible_v<From, To>; +// No equivalents in the stdlib + +template <typename T> +concept IsArithmetic = std::is_arithmetic_v<T>; + +template <typename T> +concept IsIntegral = std::is_integral_v<T>; + } // namespace Common diff --git a/src/common/fixed_point.h b/src/common/fixed_point.h index 6eb6afe2f..f899b0d54 100644 --- a/src/common/fixed_point.h +++ b/src/common/fixed_point.h @@ -12,6 +12,8 @@ #include <ostream> #include <type_traits> +#include <common/concepts.h> + namespace Common { template <size_t I, size_t F> @@ -50,8 +52,8 @@ struct type_from_size<64> { static constexpr size_t size = 64; using value_type = int64_t; - using unsigned_type = std::make_unsigned<value_type>::type; - using signed_type = std::make_signed<value_type>::type; + using unsigned_type = std::make_unsigned_t<value_type>; + using signed_type = std::make_signed_t<value_type>; using next_size = type_from_size<128>; }; @@ -61,8 +63,8 @@ struct type_from_size<32> { static constexpr size_t size = 32; using value_type = int32_t; - using unsigned_type = std::make_unsigned<value_type>::type; - using signed_type = std::make_signed<value_type>::type; + using unsigned_type = std::make_unsigned_t<value_type>; + using signed_type = std::make_signed_t<value_type>; using next_size = type_from_size<64>; }; @@ -72,8 +74,8 @@ struct type_from_size<16> { static constexpr size_t size = 16; using value_type = int16_t; - using unsigned_type = std::make_unsigned<value_type>::type; - using signed_type = std::make_signed<value_type>::type; + using unsigned_type = std::make_unsigned_t<value_type>; + using signed_type = std::make_signed_t<value_type>; using next_size = type_from_size<32>; }; @@ -83,8 +85,8 @@ struct type_from_size<8> { static constexpr size_t size = 8; using value_type = int8_t; - using unsigned_type = std::make_unsigned<value_type>::type; - using signed_type = std::make_signed<value_type>::type; + using unsigned_type = std::make_unsigned_t<value_type>; + using signed_type = std::make_signed_t<value_type>; using next_size = type_from_size<16>; }; @@ -101,7 +103,7 @@ struct divide_by_zero : std::exception {}; template <size_t I, size_t F> constexpr FixedPoint<I, F> divide( FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder, - typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { + std::enable_if_t<type_from_size<I + F>::next_size::is_specialized>* = nullptr) { using next_type = typename FixedPoint<I, F>::next_type; using base_type = typename FixedPoint<I, F>::base_type; @@ -121,7 +123,7 @@ constexpr FixedPoint<I, F> divide( template <size_t I, size_t F> constexpr FixedPoint<I, F> divide( FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder, - typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { + std::enable_if_t<!type_from_size<I + F>::next_size::is_specialized>* = nullptr) { using unsigned_type = typename FixedPoint<I, F>::unsigned_type; @@ -191,7 +193,7 @@ constexpr FixedPoint<I, F> divide( template <size_t I, size_t F> constexpr FixedPoint<I, F> multiply( FixedPoint<I, F> lhs, FixedPoint<I, F> rhs, - typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { + std::enable_if_t<type_from_size<I + F>::next_size::is_specialized>* = nullptr) { using next_type = typename FixedPoint<I, F>::next_type; using base_type = typename FixedPoint<I, F>::base_type; @@ -210,7 +212,7 @@ constexpr FixedPoint<I, F> multiply( template <size_t I, size_t F> constexpr FixedPoint<I, F> multiply( FixedPoint<I, F> lhs, FixedPoint<I, F> rhs, - typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) { + std::enable_if_t<!type_from_size<I + F>::next_size::is_specialized>* = nullptr) { using base_type = typename FixedPoint<I, F>::base_type; @@ -265,15 +267,16 @@ public: static constexpr base_type one = base_type(1) << fractional_bits; public: // constructors - FixedPoint() = default; - FixedPoint(const FixedPoint&) = default; - FixedPoint(FixedPoint&&) = default; - FixedPoint& operator=(const FixedPoint&) = default; + constexpr FixedPoint() = default; + + constexpr FixedPoint(const FixedPoint&) = default; + constexpr FixedPoint& operator=(const FixedPoint&) = default; - template <class Number> - constexpr FixedPoint( - Number n, typename std::enable_if<std::is_arithmetic<Number>::value>::type* = nullptr) - : data_(static_cast<base_type>(n * one)) {} + constexpr FixedPoint(FixedPoint&&) noexcept = default; + constexpr FixedPoint& operator=(FixedPoint&&) noexcept = default; + + template <IsArithmetic Number> + constexpr FixedPoint(Number n) : data_(static_cast<base_type>(n * one)) {} public: // conversion template <size_t I2, size_t F2> @@ -301,36 +304,14 @@ public: } public: // comparison operators - constexpr bool operator==(FixedPoint rhs) const { - return data_ == rhs.data_; - } - - constexpr bool operator!=(FixedPoint rhs) const { - return data_ != rhs.data_; - } - - constexpr bool operator<(FixedPoint rhs) const { - return data_ < rhs.data_; - } - - constexpr bool operator>(FixedPoint rhs) const { - return data_ > rhs.data_; - } - - constexpr bool operator<=(FixedPoint rhs) const { - return data_ <= rhs.data_; - } - - constexpr bool operator>=(FixedPoint rhs) const { - return data_ >= rhs.data_; - } + friend constexpr auto operator<=>(FixedPoint lhs, FixedPoint rhs) = default; public: // unary operators - constexpr bool operator!() const { + [[nodiscard]] constexpr bool operator!() const { return !data_; } - constexpr FixedPoint operator~() const { + [[nodiscard]] constexpr FixedPoint operator~() const { // NOTE(eteran): this will often appear to "just negate" the value // that is not an error, it is because -x == (~x+1) // and that "+1" is adding an infinitesimally small fraction to the @@ -338,11 +319,11 @@ public: // unary operators return FixedPoint::from_base(~data_); } - constexpr FixedPoint operator-() const { + [[nodiscard]] constexpr FixedPoint operator-() const { return FixedPoint::from_base(-data_); } - constexpr FixedPoint operator+() const { + [[nodiscard]] constexpr FixedPoint operator+() const { return FixedPoint::from_base(+data_); } @@ -411,15 +392,13 @@ public: // binary math operators, effects underlying bit pattern since these return *this; } - template <class Integer, - class = typename std::enable_if<std::is_integral<Integer>::value>::type> + template <IsIntegral Integer> constexpr FixedPoint& operator>>=(Integer n) { data_ >>= n; return *this; } - template <class Integer, - class = typename std::enable_if<std::is_integral<Integer>::value>::type> + template <IsIntegral Integer> constexpr FixedPoint& operator<<=(Integer n) { data_ <<= n; return *this; @@ -430,42 +409,42 @@ public: // conversion to basic types data_ += (data_ & fractional_mask) >> 1; } - constexpr int to_int() { + [[nodiscard]] constexpr int to_int() { round_up(); return static_cast<int>((data_ & integer_mask) >> fractional_bits); } - constexpr unsigned int to_uint() const { + [[nodiscard]] constexpr unsigned int to_uint() { round_up(); return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits); } - constexpr int64_t to_long() { + [[nodiscard]] constexpr int64_t to_long() { round_up(); return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits); } - constexpr int to_int_floor() const { + [[nodiscard]] constexpr int to_int_floor() const { return static_cast<int>((data_ & integer_mask) >> fractional_bits); } - constexpr int64_t to_long_floor() { + [[nodiscard]] constexpr int64_t to_long_floor() const { return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits); } - constexpr unsigned int to_uint_floor() const { + [[nodiscard]] constexpr unsigned int to_uint_floor() const { return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits); } - constexpr float to_float() const { + [[nodiscard]] constexpr float to_float() const { return static_cast<float>(data_) / FixedPoint::one; } - constexpr double to_double() const { + [[nodiscard]] constexpr double to_double() const { return static_cast<double>(data_) / FixedPoint::one; } - constexpr base_type to_raw() const { + [[nodiscard]] constexpr base_type to_raw() const { return data_; } @@ -473,27 +452,27 @@ public: // conversion to basic types data_ &= fractional_mask; } - constexpr base_type get_frac() const { + [[nodiscard]] constexpr base_type get_frac() const { return data_ & fractional_mask; } public: - constexpr void swap(FixedPoint& rhs) { + constexpr void swap(FixedPoint& rhs) noexcept { using std::swap; swap(data_, rhs.data_); } public: - base_type data_; + base_type data_{}; }; // if we have the same fractional portion, but differing integer portions, we trivially upgrade the // smaller type template <size_t I1, size_t I2, size_t F> -constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator+( +constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator+( FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { - using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; + using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>; const T l = T::from_base(lhs.to_raw()); const T r = T::from_base(rhs.to_raw()); @@ -501,10 +480,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, } template <size_t I1, size_t I2, size_t F> -constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator-( +constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator-( FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { - using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; + using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>; const T l = T::from_base(lhs.to_raw()); const T r = T::from_base(rhs.to_raw()); @@ -512,10 +491,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, } template <size_t I1, size_t I2, size_t F> -constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator*( +constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator*( FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { - using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; + using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>; const T l = T::from_base(lhs.to_raw()); const T r = T::from_base(rhs.to_raw()); @@ -523,10 +502,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, } template <size_t I1, size_t I2, size_t F> -constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator/( +constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator/( FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) { - using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type; + using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>; const T l = T::from_base(lhs.to_raw()); const T r = T::from_base(rhs.to_raw()); @@ -561,54 +540,46 @@ constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs) return lhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, Number rhs) { lhs += FixedPoint<I, F>(rhs); return lhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, Number rhs) { lhs -= FixedPoint<I, F>(rhs); return lhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, Number rhs) { lhs *= FixedPoint<I, F>(rhs); return lhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, Number rhs) { lhs /= FixedPoint<I, F>(rhs); return lhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator+(Number lhs, FixedPoint<I, F> rhs) { FixedPoint<I, F> tmp(lhs); tmp += rhs; return tmp; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator-(Number lhs, FixedPoint<I, F> rhs) { FixedPoint<I, F> tmp(lhs); tmp -= rhs; return tmp; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator*(Number lhs, FixedPoint<I, F> rhs) { FixedPoint<I, F> tmp(lhs); tmp *= rhs; return tmp; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) { FixedPoint<I, F> tmp(lhs); tmp /= rhs; @@ -616,78 +587,64 @@ constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) { } // shift operators -template <size_t I, size_t F, class Integer, - class = typename std::enable_if<std::is_integral<Integer>::value>::type> +template <size_t I, size_t F, IsIntegral Integer> constexpr FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) { lhs <<= rhs; return lhs; } -template <size_t I, size_t F, class Integer, - class = typename std::enable_if<std::is_integral<Integer>::value>::type> +template <size_t I, size_t F, IsIntegral Integer> constexpr FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) { lhs >>= rhs; return lhs; } // comparison operators -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator>(FixedPoint<I, F> lhs, Number rhs) { return lhs > FixedPoint<I, F>(rhs); } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator<(FixedPoint<I, F> lhs, Number rhs) { return lhs < FixedPoint<I, F>(rhs); } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator>=(FixedPoint<I, F> lhs, Number rhs) { return lhs >= FixedPoint<I, F>(rhs); } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator<=(FixedPoint<I, F> lhs, Number rhs) { return lhs <= FixedPoint<I, F>(rhs); } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator==(FixedPoint<I, F> lhs, Number rhs) { return lhs == FixedPoint<I, F>(rhs); } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator!=(FixedPoint<I, F> lhs, Number rhs) { return lhs != FixedPoint<I, F>(rhs); } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator>(Number lhs, FixedPoint<I, F> rhs) { return FixedPoint<I, F>(lhs) > rhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator<(Number lhs, FixedPoint<I, F> rhs) { return FixedPoint<I, F>(lhs) < rhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator>=(Number lhs, FixedPoint<I, F> rhs) { return FixedPoint<I, F>(lhs) >= rhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator<=(Number lhs, FixedPoint<I, F> rhs) { return FixedPoint<I, F>(lhs) <= rhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator==(Number lhs, FixedPoint<I, F> rhs) { return FixedPoint<I, F>(lhs) == rhs; } -template <size_t I, size_t F, class Number, - class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> +template <size_t I, size_t F, IsArithmetic Number> constexpr bool operator!=(Number lhs, FixedPoint<I, F> rhs) { return FixedPoint<I, F>(lhs) != rhs; } diff --git a/src/common/fs/file.h b/src/common/fs/file.h index 69b53384c..167c4d826 100644 --- a/src/common/fs/file.h +++ b/src/common/fs/file.h @@ -209,8 +209,8 @@ public: /** * Helper function which deduces the value type of a contiguous STL container used in ReadSpan. - * If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls - * ReadObject and T must be a trivially copyable object. + * If T is not a contiguous container as defined by the concept IsContiguousContainer, this + * calls ReadObject and T must be a trivially copyable object. * * See ReadSpan for more details if T is a contiguous container. * See ReadObject for more details if T is a trivially copyable object. @@ -223,7 +223,7 @@ public: */ template <typename T> [[nodiscard]] size_t Read(T& data) const { - if constexpr (IsSTLContainer<T>) { + if constexpr (IsContiguousContainer<T>) { using ContiguousType = typename T::value_type; static_assert(std::is_trivially_copyable_v<ContiguousType>, "Data type must be trivially copyable."); @@ -235,8 +235,8 @@ public: /** * Helper function which deduces the value type of a contiguous STL container used in WriteSpan. - * If T is not a contiguous STL container as defined by the concept IsSTLContainer, this calls - * WriteObject and T must be a trivially copyable object. + * If T is not a contiguous STL container as defined by the concept IsContiguousContainer, this + * calls WriteObject and T must be a trivially copyable object. * * See WriteSpan for more details if T is a contiguous container. * See WriteObject for more details if T is a trivially copyable object. @@ -249,7 +249,7 @@ public: */ template <typename T> [[nodiscard]] size_t Write(const T& data) const { - if constexpr (IsSTLContainer<T>) { + if constexpr (IsContiguousContainer<T>) { using ContiguousType = typename T::value_type; static_assert(std::is_trivially_copyable_v<ContiguousType>, "Data type must be trivially copyable."); diff --git a/src/common/input.h b/src/common/input.h index b533f3844..cb30b7254 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -100,7 +100,6 @@ enum class CameraError { enum class VibrationAmplificationType { Linear, Exponential, - Test, }; // Analog properties for calibration @@ -325,6 +324,10 @@ public: return VibrationError::NotSupported; } + virtual bool IsVibrationEnabled() { + return false; + } + virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { return PollingError::NotSupported; } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e7fe675cb..113e663b5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -243,6 +243,8 @@ add_library(core STATIC hle/kernel/k_server_session.h hle/kernel/k_session.cpp hle/kernel/k_session.h + hle/kernel/k_session_request.cpp + hle/kernel/k_session_request.h hle/kernel/k_shared_memory.cpp hle/kernel/k_shared_memory.h hle/kernel/k_shared_memory_info.h @@ -772,19 +774,15 @@ if (MSVC) /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /we4800 # Implicit conversion from 'type' to bool. Possible information loss ) else() target_compile_options(core PRIVATE -Werror=conversion - -Werror=ignored-qualifiers - $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> + -Wno-sign-conversion $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation> - - -Wno-sign-conversion ) endif() diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index d1e70f19d..287ba102e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -450,7 +450,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::S // Frame records are two words long: // fp+0 : pointer to previous frame record // fp+4 : value of lr for frame - while (true) { + for (size_t i = 0; i < 256; i++) { out.push_back({"", 0, lr, 0, ""}); if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) { break; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 22b5d5656..afb7fb3a0 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -517,7 +517,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S // Frame records are two words long: // fp+0 : pointer to previous frame record // fp+8 : value of lr for frame - while (true) { + for (size_t i = 0; i < 256; i++) { out.push_back({"", 0, lr, 0, ""}); if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) { break; diff --git a/src/core/core.cpp b/src/core/core.cpp index 7fb8bc019..d8934be52 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -137,6 +137,7 @@ struct System::Impl { device_memory = std::make_unique<Core::DeviceMemory>(); is_multicore = Settings::values.use_multi_core.GetValue(); + extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); core_timing.SetMulticore(is_multicore); core_timing.Initialize([&system]() { system.RegisterHostThread(); }); @@ -166,13 +167,18 @@ struct System::Impl { } void ReinitializeIfNecessary(System& system) { - if (is_multicore == Settings::values.use_multi_core.GetValue()) { + const bool must_reinitialize = + is_multicore != Settings::values.use_multi_core.GetValue() || + extended_memory_layout != Settings::values.use_extended_memory_layout.GetValue(); + + if (!must_reinitialize) { return; } LOG_DEBUG(Kernel, "Re-initializing"); is_multicore = Settings::values.use_multi_core.GetValue(); + extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue(); Initialize(system); } @@ -384,6 +390,7 @@ struct System::Impl { kernel.ShutdownCores(); cpu_manager.Shutdown(); debugger.reset(); + services->KillNVNFlinger(); kernel.CloseServices(); services.reset(); service_manager.reset(); @@ -520,6 +527,7 @@ struct System::Impl { bool is_multicore{}; bool is_async_gpu{}; + bool extended_memory_layout{}; ExecuteProgramCallback execute_program_callback; ExitCallback exit_callback; diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index f23d9373b..5d02865f4 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -232,8 +232,8 @@ const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const { std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { const auto program_id = secure_partition->GetProgramTitleID(); - const auto iter = std::find_if( - ncas.begin(), ncas.end(), [this, type, program_id](const std::shared_ptr<NCA>& nca) { + const auto iter = + std::find_if(ncas.begin(), ncas.end(), [type, program_id](const std::shared_ptr<NCA>& nca) { return nca->GetType() == type && nca->GetTitleId() == program_id; }); return iter == ncas.end() ? nullptr : *iter; diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index be25da2f6..50f44f598 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/settings.h" #include "common/string_util.h" #include "common/swap.h" #include "core/file_sys/control_metadata.h" @@ -37,6 +38,27 @@ std::string LanguageEntry::GetDeveloperName() const { developer_name.size()); } +constexpr std::array<Language, 18> language_to_codes = {{ + Language::Japanese, + Language::AmericanEnglish, + Language::French, + Language::German, + Language::Italian, + Language::Spanish, + Language::Chinese, + Language::Korean, + Language::Dutch, + Language::Portuguese, + Language::Russian, + Language::Taiwanese, + Language::BritishEnglish, + Language::CanadianFrench, + Language::LatinAmericanSpanish, + Language::Chinese, + Language::Taiwanese, + Language::BrazilianPortuguese, +}}; + NACP::NACP() = default; NACP::NACP(VirtualFile file) { @@ -45,9 +67,13 @@ NACP::NACP(VirtualFile file) { NACP::~NACP() = default; -const LanguageEntry& NACP::GetLanguageEntry(Language language) const { - if (language != Language::Default) { - return raw.language_entries.at(static_cast<u8>(language)); +const LanguageEntry& NACP::GetLanguageEntry() const { + Language language = language_to_codes[Settings::values.language_index.GetValue()]; + + { + const auto& language_entry = raw.language_entries.at(static_cast<u8>(language)); + if (!language_entry.GetApplicationName().empty()) + return language_entry; } for (const auto& language_entry : raw.language_entries) { @@ -55,16 +81,15 @@ const LanguageEntry& NACP::GetLanguageEntry(Language language) const { return language_entry; } - // Fallback to English - return GetLanguageEntry(Language::AmericanEnglish); + return raw.language_entries.at(static_cast<u8>(Language::AmericanEnglish)); } -std::string NACP::GetApplicationName(Language language) const { - return GetLanguageEntry(language).GetApplicationName(); +std::string NACP::GetApplicationName() const { + return GetLanguageEntry().GetApplicationName(); } -std::string NACP::GetDeveloperName(Language language) const { - return GetLanguageEntry(language).GetDeveloperName(); +std::string NACP::GetDeveloperName() const { + return GetLanguageEntry().GetDeveloperName(); } u64 NACP::GetTitleId() const { diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 75295519c..6a81873b1 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -101,9 +101,9 @@ public: explicit NACP(VirtualFile file); ~NACP(); - const LanguageEntry& GetLanguageEntry(Language language = Language::Default) const; - std::string GetApplicationName(Language language = Language::Default) const; - std::string GetDeveloperName(Language language = Language::Default) const; + const LanguageEntry& GetLanguageEntry() const; + std::string GetApplicationName() const; + std::string GetDeveloperName() const; u64 GetTitleId() const; u64 GetDLCBaseTitleId() const; std::string GetVersionString() const; diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 08d489eab..f00479bd3 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -127,7 +127,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address } bool ProgramMetadata::Is64BitProgram() const { - return npdm_header.has_64_bit_instructions; + return npdm_header.has_64_bit_instructions.As<bool>(); } ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 025f1c78e..ec1364452 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -970,14 +970,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v Common::Input::VibrationError::None; } -bool EmulatedController::TestVibration(std::size_t device_index) { - if (device_index >= output_devices.size()) { - return false; - } - if (!output_devices[device_index]) { - return false; - } - +bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; @@ -985,31 +978,15 @@ bool EmulatedController::TestVibration(std::size_t device_index) { return false; } - const Common::Input::VibrationStatus test_vibration = { - .low_amplitude = 0.001f, - .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency, - .high_amplitude = 0.001f, - .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency, - .type = Common::Input::VibrationAmplificationType::Test, - }; - - const Common::Input::VibrationStatus zero_vibration = { - .low_amplitude = DEFAULT_VIBRATION_VALUE.low_amplitude, - .low_frequency = DEFAULT_VIBRATION_VALUE.low_frequency, - .high_amplitude = DEFAULT_VIBRATION_VALUE.high_amplitude, - .high_frequency = DEFAULT_VIBRATION_VALUE.high_frequency, - .type = Common::Input::VibrationAmplificationType::Test, - }; - - // Send a slight vibration to test for rumble support - output_devices[device_index]->SetVibration(test_vibration); + if (device_index >= output_devices.size()) { + return false; + } - // Wait for about 15ms to ensure the controller is ready for the stop command - std::this_thread::sleep_for(std::chrono::milliseconds(15)); + if (!output_devices[device_index]) { + return false; + } - // Stop any vibration and return the result - return output_devices[device_index]->SetVibration(zero_vibration) == - Common::Input::VibrationError::None; + return output_devices[device_index]->IsVibrationEnabled(); } bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { @@ -1048,6 +1025,7 @@ bool EmulatedController::HasNfc() const { case NpadStyleIndex::JoyconRight: case NpadStyleIndex::JoyconDual: case NpadStyleIndex::ProController: + case NpadStyleIndex::Handheld: break; default: return false; @@ -1158,27 +1136,27 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; switch (type) { case NpadStyleIndex::ProController: - return supported_style_tag.fullkey; + return supported_style_tag.fullkey.As<bool>(); case NpadStyleIndex::Handheld: - return supported_style_tag.handheld; + return supported_style_tag.handheld.As<bool>(); case NpadStyleIndex::JoyconDual: - return supported_style_tag.joycon_dual; + return supported_style_tag.joycon_dual.As<bool>(); case NpadStyleIndex::JoyconLeft: - return supported_style_tag.joycon_left; + return supported_style_tag.joycon_left.As<bool>(); case NpadStyleIndex::JoyconRight: - return supported_style_tag.joycon_right; + return supported_style_tag.joycon_right.As<bool>(); case NpadStyleIndex::GameCube: - return supported_style_tag.gamecube; + return supported_style_tag.gamecube.As<bool>(); case NpadStyleIndex::Pokeball: - return supported_style_tag.palma; + return supported_style_tag.palma.As<bool>(); case NpadStyleIndex::NES: - return supported_style_tag.lark; + return supported_style_tag.lark.As<bool>(); case NpadStyleIndex::SNES: - return supported_style_tag.lucia; + return supported_style_tag.lucia.As<bool>(); case NpadStyleIndex::N64: - return supported_style_tag.lagoon; + return supported_style_tag.lagoon.As<bool>(); case NpadStyleIndex::SegaGenesis: - return supported_style_tag.lager; + return supported_style_tag.lager.As<bool>(); default: return false; } @@ -1234,12 +1212,6 @@ bool EmulatedController::IsConnected(bool get_temporary_value) const { return is_connected; } -bool EmulatedController::IsVibrationEnabled() const { - const auto player_index = NpadIdTypeToIndex(npad_id_type); - const auto& player = Settings::values.players.GetValue()[player_index]; - return player.vibration_enabled; -} - NpadIdType EmulatedController::GetNpadIdType() const { std::scoped_lock lock{mutex}; return npad_id_type; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 319226bf8..d004ca56a 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -206,9 +206,6 @@ public: */ bool IsConnected(bool get_temporary_value = false) const; - /// Returns true if vibration is enabled - bool IsVibrationEnabled() const; - /// Removes all callbacks created from input devices void UnloadInput(); @@ -339,7 +336,7 @@ public: * Sends a small vibration to the output device * @return true if SetVibration was successfull */ - bool TestVibration(std::size_t device_index); + bool IsVibrationEnabled(std::size_t device_index); /** * Sets the desired data to be polled from a controller diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 0cc26a211..18fde8bd6 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -86,13 +86,13 @@ public: u32 num_domain_objects{}; const bool always_move_handles{ (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0}; - if (!ctx.Session()->IsDomain() || always_move_handles) { + if (!ctx.Session()->GetSessionRequestManager()->IsDomain() || always_move_handles) { num_handles_to_move = num_objects_to_move; } else { num_domain_objects = num_objects_to_move; } - if (ctx.Session()->IsDomain()) { + if (ctx.Session()->GetSessionRequestManager()->IsDomain()) { raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); ctx.write_size += num_domain_objects; @@ -125,7 +125,8 @@ public: if (!ctx.IsTipc()) { AlignWithPadding(); - if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) { + if (ctx.Session()->GetSessionRequestManager()->IsDomain() && + ctx.HasDomainMessageHeader()) { IPC::DomainMessageHeader domain_header{}; domain_header.num_objects = num_domain_objects; PushRaw(domain_header); @@ -145,7 +146,7 @@ public: template <class T> void PushIpcInterface(std::shared_ptr<T> iface) { - if (context->Session()->IsDomain()) { + if (context->Session()->GetSessionRequestManager()->IsDomain()) { context->AddDomainObject(std::move(iface)); } else { kernel.CurrentProcess()->GetResourceLimit()->Reserve( @@ -386,7 +387,7 @@ public: template <class T> std::weak_ptr<T> PopIpcInterface() { - ASSERT(context->Session()->IsDomain()); + ASSERT(context->Session()->GetSessionRequestManager()->IsDomain()); ASSERT(context->GetDomainMessageHeader().input_object_count > 0); return context->GetDomainHandler<T>(Pop<u32>() - 1); } @@ -405,7 +406,7 @@ inline s32 RequestParser::Pop() { } // Ignore the -Wclass-memaccess warning on memcpy for non-trivially default constructible objects. -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" #endif @@ -416,7 +417,7 @@ void RequestParser::PopRaw(T& value) { std::memcpy(&value, cmdbuf + index, sizeof(T)); index += (sizeof(T) + 3) / 4; // round up to word length } -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) #pragma GCC diagnostic pop #endif diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index 65576b8c4..fd911a3a5 100644 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp @@ -49,4 +49,26 @@ bool GlobalSchedulerContext::IsLocked() const { return scheduler_lock.IsLockedByCurrentThread(); } +void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) { + ASSERT(IsLocked()); + + woken_dummy_threads.insert(thread); +} + +void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) { + ASSERT(IsLocked()); + + woken_dummy_threads.erase(thread); +} + +void GlobalSchedulerContext::WakeupWaitingDummyThreads() { + ASSERT(IsLocked()); + + for (auto* thread : woken_dummy_threads) { + thread->DummyThreadEndWait(); + } + + woken_dummy_threads.clear(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 67bb9852d..220ed6192 100644 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -4,6 +4,7 @@ #pragma once #include <atomic> +#include <set> #include <vector> #include "common/common_types.h" @@ -58,6 +59,10 @@ public: /// Returns true if the global scheduler lock is acquired bool IsLocked() const; + void UnregisterDummyThreadForWakeup(KThread* thread); + void RegisterDummyThreadForWakeup(KThread* thread); + void WakeupWaitingDummyThreads(); + [[nodiscard]] LockType& SchedulerLock() { return scheduler_lock; } @@ -76,6 +81,9 @@ private: KSchedulerPriorityQueue priority_queue; LockType scheduler_lock; + /// Lists dummy threads pending wakeup on lock release + std::set<KThread*> woken_dummy_threads; + /// Lists all thread ids that aren't deleted/etc. std::vector<KThread*> thread_list; std::mutex global_list_guard; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 5b3feec66..e4f43a053 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -19,6 +19,7 @@ #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/service_thread.h" #include "core/memory.h" namespace Kernel { @@ -56,16 +57,103 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co } } +Result SessionRequestManager::CompleteSyncRequest(KServerSession* server_session, + HLERequestContext& context) { + Result result = ResultSuccess; + + // If the session has been converted to a domain, handle the domain request + if (this->HasSessionRequestHandler(context)) { + if (IsDomain() && context.HasDomainMessageHeader()) { + result = HandleDomainSyncRequest(server_session, context); + // If there is no domain header, the regular session handler is used + } else if (this->HasSessionHandler()) { + // If this manager has an associated HLE handler, forward the request to it. + result = this->SessionHandler().HandleSyncRequest(*server_session, context); + } + } else { + ASSERT_MSG(false, "Session handler is invalid, stubbing response!"); + IPC::ResponseBuilder rb(context, 2); + rb.Push(ResultSuccess); + } + + if (convert_to_domain) { + ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); + this->ConvertToDomain(); + convert_to_domain = false; + } + + return result; +} + +Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_session, + HLERequestContext& context) { + if (!context.HasDomainMessageHeader()) { + return ResultSuccess; + } + + // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs + context.SetSessionRequestManager(server_session->GetSessionRequestManager()); + + // If there is a DomainMessageHeader, then this is CommandType "Request" + const auto& domain_message_header = context.GetDomainMessageHeader(); + const u32 object_id{domain_message_header.object_id}; + switch (domain_message_header.command) { + case IPC::DomainMessageHeader::CommandType::SendMessage: + if (object_id > this->DomainHandlerCount()) { + LOG_CRITICAL(IPC, + "object_id {} is too big! This probably means a recent service call " + "needed to return a new interface!", + object_id); + ASSERT(false); + return ResultSuccess; // Ignore error if asserts are off + } + if (auto strong_ptr = this->DomainHandler(object_id - 1).lock()) { + return strong_ptr->HandleSyncRequest(*server_session, context); + } else { + ASSERT(false); + return ResultSuccess; + } + + case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { + LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); + + this->CloseDomainHandler(object_id - 1); + + IPC::ResponseBuilder rb{context, 2}; + rb.Push(ResultSuccess); + return ResultSuccess; + } + } + + LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value()); + ASSERT(false); + return ResultSuccess; +} + +Result SessionRequestManager::QueueSyncRequest(KSession* parent, + std::shared_ptr<HLERequestContext>&& context) { + // Ensure we have a session request handler + if (this->HasSessionRequestHandler(*context)) { + if (auto strong_ptr = this->GetServiceThread().lock()) { + strong_ptr->QueueSyncRequest(*parent, std::move(context)); + } else { + ASSERT_MSG(false, "strong_ptr is nullptr!"); + } + } else { + ASSERT_MSG(false, "handler is invalid!"); + } + + return ResultSuccess; +} + void SessionRequestHandler::ClientConnected(KServerSession* session) { - session->ClientConnected(shared_from_this()); + session->GetSessionRequestManager()->SetSessionHandler(shared_from_this()); // Ensure our server session is tracked globally. kernel.RegisterServerObject(session); } -void SessionRequestHandler::ClientDisconnected(KServerSession* session) { - session->ClientDisconnected(); -} +void SessionRequestHandler::ClientDisconnected(KServerSession* session) {} HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, KServerSession* server_session_, KThread* thread_) @@ -126,7 +214,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 // Padding to align to 16 bytes rp.AlignWithPadding(); - if (Session()->IsDomain() && + if (Session()->GetSessionRequestManager()->IsDomain() && ((command_header->type == IPC::CommandType::Request || command_header->type == IPC::CommandType::RequestWithContext) || !incoming)) { @@ -135,7 +223,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 if (incoming || domain_message_header) { domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); } else { - if (Session()->IsDomain()) { + if (Session()->GetSessionRequestManager()->IsDomain()) { LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); } } @@ -228,12 +316,12 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa // Write the domain objects to the command buffer, these go after the raw untranslated data. // TODO(Subv): This completely ignores C buffers. - if (Session()->IsDomain()) { + if (server_session->GetSessionRequestManager()->IsDomain()) { current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); - for (const auto& object : outgoing_domain_objects) { - server_session->AppendDomainHandler(object); - cmd_buf[current_offset++] = - static_cast<u32_le>(server_session->NumDomainRequestHandlers()); + for (auto& object : outgoing_domain_objects) { + server_session->GetSessionRequestManager()->AppendDomainHandler(std::move(object)); + cmd_buf[current_offset++] = static_cast<u32_le>( + server_session->GetSessionRequestManager()->DomainHandlerCount()); } } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index e258e2cdf..1083638a9 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -121,6 +121,10 @@ public: is_domain = true; } + void ConvertToDomainOnRequestEnd() { + convert_to_domain = true; + } + std::size_t DomainHandlerCount() const { return domain_handlers.size(); } @@ -164,7 +168,12 @@ public: bool HasSessionRequestHandler(const HLERequestContext& context) const; + Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context); + Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context); + Result QueueSyncRequest(KSession* parent, std::shared_ptr<HLERequestContext>&& context); + private: + bool convert_to_domain{}; bool is_domain{}; SessionRequestHandlerPtr session_handler; std::vector<SessionRequestHandlerPtr> domain_handlers; @@ -295,7 +304,7 @@ public: */ template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>> std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const { - if constexpr (Common::IsSTLContainer<T>) { + if constexpr (Common::IsContiguousContainer<T>) { using ContiguousType = typename T::value_type; static_assert(std::is_trivially_copyable_v<ContiguousType>, "Container to WriteBuffer must contain trivially copyable objects"); diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index c84d36c8c..477e4e407 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -18,6 +18,7 @@ #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_session_request.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory_info.h" #include "core/hle/kernel/k_system_control.h" @@ -34,6 +35,7 @@ namespace Kernel::Init { HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ + HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ##__VA_ARGS__) \ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \ HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp index 8892c5b7c..b4197a8d5 100644 --- a/src/core/hle/kernel/k_client_session.cpp +++ b/src/core/hle/kernel/k_client_session.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/scope_exit.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_server_session.h" @@ -10,6 +11,8 @@ namespace Kernel { +static constexpr u32 MessageBufferSize = 0x100; + KClientSession::KClientSession(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {} KClientSession::~KClientSession() = default; @@ -22,8 +25,16 @@ void KClientSession::Destroy() { void KClientSession::OnServerClosed() {} Result KClientSession::SendSyncRequest() { - // Signal the server session that new data is available - return parent->GetServerSession().OnRequest(); + // Create a session request. + KSessionRequest* request = KSessionRequest::Create(kernel); + R_UNLESS(request != nullptr, ResultOutOfResource); + SCOPE_EXIT({ request->Close(); }); + + // Initialize the request. + request->Initialize(nullptr, GetCurrentThread(kernel).GetTLSAddress(), MessageBufferSize); + + // Send the request. + return parent->GetServerSession().OnRequest(request); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h index 78859ced3..29ebd16b7 100644 --- a/src/core/hle/kernel/k_linked_list.h +++ b/src/core/hle/kernel/k_linked_list.h @@ -16,6 +16,7 @@ class KLinkedListNode : public boost::intrusive::list_base_hook<>, public KSlabAllocated<KLinkedListNode> { public: + explicit KLinkedListNode(KernelCore&) {} KLinkedListNode() = default; void Initialize(void* it) { diff --git a/src/core/hle/kernel/k_page_buffer.h b/src/core/hle/kernel/k_page_buffer.h index 7e50dc1d1..aef06e213 100644 --- a/src/core/hle/kernel/k_page_buffer.h +++ b/src/core/hle/kernel/k_page_buffer.h @@ -13,6 +13,7 @@ namespace Kernel { class KPageBuffer final : public KSlabAllocated<KPageBuffer> { public: + explicit KPageBuffer(KernelCore&) {} KPageBuffer() = default; static KPageBuffer* FromPhysicalAddress(Core::System& system, PAddr phys_addr); diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index c34ce7a17..b1cabbca0 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -81,8 +81,8 @@ void KScheduler::RescheduleCurrentHLEThread(KernelCore& kernel) { // HACK: we cannot schedule from this thread, it is not a core thread ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1); - // Special case to ensure dummy threads that are waiting block - GetCurrentThread(kernel).IfDummyThreadTryWait(); + // Ensure dummy threads that are waiting block. + GetCurrentThread(kernel).DummyThreadBeginWait(); ASSERT(GetCurrentThread(kernel).GetState() != ThreadState::Waiting); GetCurrentThread(kernel).EnableDispatch(); @@ -314,6 +314,16 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { idle_cores &= ~(1ULL << core_id); } + // HACK: any waiting dummy threads can wake up now. + kernel.GlobalSchedulerContext().WakeupWaitingDummyThreads(); + + // HACK: if we are a dummy thread, and we need to go sleep, indicate + // that for when the lock is released. + KThread* const cur_thread = GetCurrentThreadPointer(kernel); + if (cur_thread->IsDummyThread() && cur_thread->GetState() != ThreadState::Runnable) { + cur_thread->RequestDummyThreadWait(); + } + return cores_needing_scheduling; } @@ -531,11 +541,23 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, Threa GetPriorityQueue(kernel).Remove(thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(kernel); + + if (thread->IsDummyThread()) { + // HACK: if this is a dummy thread, it should no longer wake up when the + // scheduler lock is released. + kernel.GlobalSchedulerContext().UnregisterDummyThreadForWakeup(thread); + } } else if (cur_state == ThreadState::Runnable) { // If we're now runnable, then we weren't previously, and we should add. GetPriorityQueue(kernel).PushBack(thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(kernel); + + if (thread->IsDummyThread()) { + // HACK: if this is a dummy thread, it should wake up when the scheduler + // lock is released. + kernel.GlobalSchedulerContext().RegisterDummyThreadForWakeup(thread); + } } } diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 4252c9adb..faf03fcc8 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -22,15 +22,12 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/service_thread.h" #include "core/memory.h" namespace Kernel { using ThreadQueueImplForKServerSessionRequest = KThreadQueue; -static constexpr u32 MessageBufferSize = 0x100; - KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_}, m_lock{kernel_} {} @@ -73,59 +70,7 @@ bool KServerSession::IsSignaled() const { } // Otherwise, we're signaled if we have a request and aren't handling one. - return !m_thread_request_list.empty() && m_current_thread_request == nullptr; -} - -void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { - manager->AppendDomainHandler(std::move(handler)); -} - -std::size_t KServerSession::NumDomainRequestHandlers() const { - return manager->DomainHandlerCount(); -} - -Result KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { - if (!context.HasDomainMessageHeader()) { - return ResultSuccess; - } - - // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs - context.SetSessionRequestManager(manager); - - // If there is a DomainMessageHeader, then this is CommandType "Request" - const auto& domain_message_header = context.GetDomainMessageHeader(); - const u32 object_id{domain_message_header.object_id}; - switch (domain_message_header.command) { - case IPC::DomainMessageHeader::CommandType::SendMessage: - if (object_id > manager->DomainHandlerCount()) { - LOG_CRITICAL(IPC, - "object_id {} is too big! This probably means a recent service call " - "to {} needed to return a new interface!", - object_id, name); - ASSERT(false); - return ResultSuccess; // Ignore error if asserts are off - } - if (auto strong_ptr = manager->DomainHandler(object_id - 1).lock()) { - return strong_ptr->HandleSyncRequest(*this, context); - } else { - ASSERT(false); - return ResultSuccess; - } - - case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { - LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); - - manager->CloseDomainHandler(object_id - 1); - - IPC::ResponseBuilder rb{context, 2}; - rb.Push(ResultSuccess); - return ResultSuccess; - } - } - - LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value()); - ASSERT(false); - return ResultSuccess; + return !m_request_list.empty() && m_current_request == nullptr; } Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { @@ -134,43 +79,11 @@ Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& m context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); - // Ensure we have a session request handler - if (manager->HasSessionRequestHandler(*context)) { - if (auto strong_ptr = manager->GetServiceThread().lock()) { - strong_ptr->QueueSyncRequest(*parent, std::move(context)); - } else { - ASSERT_MSG(false, "strong_ptr is nullptr!"); - } - } else { - ASSERT_MSG(false, "handler is invalid!"); - } - - return ResultSuccess; + return manager->QueueSyncRequest(parent, std::move(context)); } Result KServerSession::CompleteSyncRequest(HLERequestContext& context) { - Result result = ResultSuccess; - - // If the session has been converted to a domain, handle the domain request - if (manager->HasSessionRequestHandler(context)) { - if (IsDomain() && context.HasDomainMessageHeader()) { - result = HandleDomainSyncRequest(context); - // If there is no domain header, the regular session handler is used - } else if (manager->HasSessionHandler()) { - // If this ServerSession has an associated HLE handler, forward the request to it. - result = manager->SessionHandler().HandleSyncRequest(*this, context); - } - } else { - ASSERT_MSG(false, "Session handler is invalid, stubbing response!"); - IPC::ResponseBuilder rb(context, 2); - rb.Push(ResultSuccess); - } - - if (convert_to_domain) { - ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); - manager->ConvertToDomain(); - convert_to_domain = false; - } + Result result = manager->CompleteSyncRequest(this, context); // The calling thread is waiting for this request to complete, so wake it up. context.GetThread().EndWait(result); @@ -178,7 +91,7 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) { return result; } -Result KServerSession::OnRequest() { +Result KServerSession::OnRequest(KSessionRequest* request) { // Create the wait queue. ThreadQueueImplForKServerSessionRequest wait_queue{kernel}; @@ -198,14 +111,13 @@ Result KServerSession::OnRequest() { this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory); } else { // Non-HLE request. - auto* thread{GetCurrentThreadPointer(kernel)}; // Get whether we're empty. - const bool was_empty = m_thread_request_list.empty(); + const bool was_empty = m_request_list.empty(); - // Add the thread to the list. - thread->Open(); - m_thread_request_list.push_back(thread); + // Add the request to the list. + request->Open(); + m_request_list.push_back(*request); // If we were empty, signal. if (was_empty) { @@ -213,6 +125,9 @@ Result KServerSession::OnRequest() { } } + // If we have a request event, this is asynchronous, and we don't need to wait. + R_SUCCEED_IF(request->GetEvent() != nullptr); + // This is a synchronous request, so we should wait for our request to complete. GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); GetCurrentThread(kernel).BeginWait(&wait_queue); @@ -223,32 +138,32 @@ Result KServerSession::OnRequest() { Result KServerSession::SendReply() { // Lock the session. - KScopedLightLock lk(m_lock); + KScopedLightLock lk{m_lock}; // Get the request. - KThread* client_thread; + KSessionRequest* request; { KScopedSchedulerLock sl{kernel}; // Get the current request. - client_thread = m_current_thread_request; - R_UNLESS(client_thread != nullptr, ResultInvalidState); + request = m_current_request; + R_UNLESS(request != nullptr, ResultInvalidState); // Clear the current request, since we're processing it. - m_current_thread_request = nullptr; - if (!m_thread_request_list.empty()) { + m_current_request = nullptr; + if (!m_request_list.empty()) { this->NotifyAvailable(); } } // Close reference to the request once we're done processing it. - SCOPE_EXIT({ client_thread->Close(); }); + SCOPE_EXIT({ request->Close(); }); // Extract relevant information from the request. - // const uintptr_t client_message = request->GetAddress(); - // const size_t client_buffer_size = request->GetSize(); - // KThread *client_thread = request->GetThread(); - // KEvent *event = request->GetEvent(); + const uintptr_t client_message = request->GetAddress(); + const size_t client_buffer_size = request->GetSize(); + KThread* client_thread = request->GetThread(); + KEvent* event = request->GetEvent(); // Check whether we're closed. const bool closed = (client_thread == nullptr || parent->IsClientClosed()); @@ -261,8 +176,8 @@ Result KServerSession::SendReply() { UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); - auto* dst_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); - std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); + auto* dst_msg_buffer = memory.GetPointer(client_message); + std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); } else { result = ResultSessionClosed; } @@ -278,11 +193,30 @@ Result KServerSession::SendReply() { // If there's a client thread, update it. if (client_thread != nullptr) { - // End the client thread's wait. - KScopedSchedulerLock sl{kernel}; + if (event != nullptr) { + // // Get the client process/page table. + // KProcess *client_process = client_thread->GetOwnerProcess(); + // KPageTable *client_page_table = &client_process->PageTable(); + + // // If we need to, reply with an async error. + // if (R_FAILED(client_result)) { + // ReplyAsyncError(client_process, client_message, client_buffer_size, + // client_result); + // } + + // // Unlock the client buffer. + // // NOTE: Nintendo does not check the result of this. + // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size); + + // Signal the event. + event->Signal(); + } else { + // End the client thread's wait. + KScopedSchedulerLock sl{kernel}; - if (!client_thread->IsTerminationRequested()) { - client_thread->EndWait(client_result); + if (!client_thread->IsTerminationRequested()) { + client_thread->EndWait(client_result); + } } } @@ -291,10 +225,10 @@ Result KServerSession::SendReply() { Result KServerSession::ReceiveRequest() { // Lock the session. - KScopedLightLock lk(m_lock); + KScopedLightLock lk{m_lock}; // Get the request and client thread. - // KSessionRequest *request; + KSessionRequest* request; KThread* client_thread; { @@ -304,35 +238,41 @@ Result KServerSession::ReceiveRequest() { R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed); // Ensure we aren't already servicing a request. - R_UNLESS(m_current_thread_request == nullptr, ResultNotFound); + R_UNLESS(m_current_request == nullptr, ResultNotFound); // Ensure we have a request to service. - R_UNLESS(!m_thread_request_list.empty(), ResultNotFound); + R_UNLESS(!m_request_list.empty(), ResultNotFound); // Pop the first request from the list. - client_thread = m_thread_request_list.front(); - m_thread_request_list.pop_front(); + request = &m_request_list.front(); + m_request_list.pop_front(); // Get the thread for the request. + client_thread = request->GetThread(); R_UNLESS(client_thread != nullptr, ResultSessionClosed); // Open the client thread. client_thread->Open(); } - // SCOPE_EXIT({ client_thread->Close(); }); + SCOPE_EXIT({ client_thread->Close(); }); // Set the request as our current. - m_current_thread_request = client_thread; + m_current_request = request; + + // Get the client address. + uintptr_t client_message = request->GetAddress(); + size_t client_buffer_size = request->GetSize(); + // bool recv_list_broken = false; // Receive the message. Core::Memory::Memory& memory{kernel.System().Memory()}; KThread* server_thread{GetCurrentThreadPointer(kernel)}; UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); - auto* src_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); + auto* src_msg_buffer = memory.GetPointer(client_message); auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); - std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); + std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); // We succeeded. return ResultSuccess; @@ -344,35 +284,34 @@ void KServerSession::CleanupRequests() { // Clean up any pending requests. while (true) { // Get the next request. - // KSessionRequest *request = nullptr; - KThread* client_thread = nullptr; + KSessionRequest* request = nullptr; { KScopedSchedulerLock sl{kernel}; - if (m_current_thread_request) { + if (m_current_request) { // Choose the current request if we have one. - client_thread = m_current_thread_request; - m_current_thread_request = nullptr; - } else if (!m_thread_request_list.empty()) { + request = m_current_request; + m_current_request = nullptr; + } else if (!m_request_list.empty()) { // Pop the request from the front of the list. - client_thread = m_thread_request_list.front(); - m_thread_request_list.pop_front(); + request = &m_request_list.front(); + m_request_list.pop_front(); } } // If there's no request, we're done. - if (client_thread == nullptr) { + if (request == nullptr) { break; } // Close a reference to the request once it's cleaned up. - SCOPE_EXIT({ client_thread->Close(); }); + SCOPE_EXIT({ request->Close(); }); // Extract relevant information from the request. // const uintptr_t client_message = request->GetAddress(); // const size_t client_buffer_size = request->GetSize(); - // KThread *client_thread = request->GetThread(); - // KEvent *event = request->GetEvent(); + KThread* client_thread = request->GetThread(); + KEvent* event = request->GetEvent(); // KProcess *server_process = request->GetServerProcess(); // KProcess *client_process = (client_thread != nullptr) ? @@ -385,11 +324,24 @@ void KServerSession::CleanupRequests() { // If there's a client thread, update it. if (client_thread != nullptr) { - // End the client thread's wait. - KScopedSchedulerLock sl{kernel}; - - if (!client_thread->IsTerminationRequested()) { - client_thread->EndWait(ResultSessionClosed); + if (event != nullptr) { + // // We need to reply async. + // ReplyAsyncError(client_process, client_message, client_buffer_size, + // (R_SUCCEEDED(result) ? ResultSessionClosed : result)); + + // // Unlock the client buffer. + // NOTE: Nintendo does not check the result of this. + // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size); + + // Signal the event. + event->Signal(); + } else { + // End the client thread's wait. + KScopedSchedulerLock sl{kernel}; + + if (!client_thread->IsTerminationRequested()) { + client_thread->EndWait(ResultSessionClosed); + } } } } diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 748d52826..188aef4af 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -12,6 +12,7 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_light_lock.h" +#include "core/hle/kernel/k_session_request.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/result.h" @@ -57,44 +58,15 @@ public: } bool IsSignaled() const override; - void OnClientClosed(); - void ClientConnected(SessionRequestHandlerPtr handler) { - if (manager) { - manager->SetSessionHandler(std::move(handler)); - } - } - - void ClientDisconnected() { - manager = nullptr; - } - - /// Adds a new domain request handler to the collection of request handlers within - /// this ServerSession instance. - void AppendDomainHandler(SessionRequestHandlerPtr handler); - - /// Retrieves the total number of domain request handlers that have been - /// appended to this ServerSession instance. - std::size_t NumDomainRequestHandlers() const; - - /// Returns true if the session has been converted to a domain, otherwise False - bool IsDomain() const { - return manager && manager->IsDomain(); - } - - /// Converts the session to a domain at the end of the current command - void ConvertToDomain() { - convert_to_domain = true; - } - /// Gets the session request manager, which forwards requests to the underlying service std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { return manager; } /// TODO: flesh these out to match the real kernel - Result OnRequest(); + Result OnRequest(KSessionRequest* request); Result SendReply(); Result ReceiveRequest(); @@ -108,10 +80,6 @@ private: /// Completes a sync request from the emulated application. Result CompleteSyncRequest(HLERequestContext& context); - /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an - /// object handle. - Result HandleDomainSyncRequest(Kernel::HLERequestContext& context); - /// This session's HLE request handlers; if nullptr, this is not an HLE server std::shared_ptr<SessionRequestManager> manager; @@ -122,9 +90,8 @@ private: KSession* parent{}; /// List of threads which are pending a reply. - /// FIXME: KSessionRequest - std::list<KThread*> m_thread_request_list; - KThread* m_current_thread_request{}; + boost::intrusive::list<KSessionRequest> m_request_list; + KSessionRequest* m_current_request{}; KLightLock m_lock; }; diff --git a/src/core/hle/kernel/k_session_request.cpp b/src/core/hle/kernel/k_session_request.cpp new file mode 100644 index 000000000..520da6aa7 --- /dev/null +++ b/src/core/hle/kernel/k_session_request.cpp @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_page_buffer.h" +#include "core/hle/kernel/k_session_request.h" + +namespace Kernel { + +Result KSessionRequest::SessionMappings::PushMap(VAddr client, VAddr server, size_t size, + KMemoryState state, size_t index) { + // At most 15 buffers of each type (4-bit descriptor counts). + ASSERT(index < ((1ul << 4) - 1) * 3); + + // Get the mapping. + Mapping* mapping; + if (index < NumStaticMappings) { + mapping = &m_static_mappings[index]; + } else { + // Allocate a page for the extra mappings. + if (m_mappings == nullptr) { + KPageBuffer* page_buffer = KPageBuffer::Allocate(kernel); + R_UNLESS(page_buffer != nullptr, ResultOutOfMemory); + + m_mappings = reinterpret_cast<Mapping*>(page_buffer); + } + + mapping = &m_mappings[index - NumStaticMappings]; + } + + // Set the mapping. + mapping->Set(client, server, size, state); + + return ResultSuccess; +} + +Result KSessionRequest::SessionMappings::PushSend(VAddr client, VAddr server, size_t size, + KMemoryState state) { + ASSERT(m_num_recv == 0); + ASSERT(m_num_exch == 0); + return this->PushMap(client, server, size, state, m_num_send++); +} + +Result KSessionRequest::SessionMappings::PushReceive(VAddr client, VAddr server, size_t size, + KMemoryState state) { + ASSERT(m_num_exch == 0); + return this->PushMap(client, server, size, state, m_num_send + m_num_recv++); +} + +Result KSessionRequest::SessionMappings::PushExchange(VAddr client, VAddr server, size_t size, + KMemoryState state) { + return this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++); +} + +void KSessionRequest::SessionMappings::Finalize() { + if (m_mappings) { + KPageBuffer::Free(kernel, reinterpret_cast<KPageBuffer*>(m_mappings)); + m_mappings = nullptr; + } +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_session_request.h b/src/core/hle/kernel/k_session_request.h new file mode 100644 index 000000000..e5558bc2c --- /dev/null +++ b/src/core/hle/kernel/k_session_request.h @@ -0,0 +1,306 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_memory_block.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/slab_helpers.h" + +namespace Kernel { + +class KSessionRequest final : public KSlabAllocated<KSessionRequest>, + public KAutoObject, + public boost::intrusive::list_base_hook<> { + KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject); + +public: + class SessionMappings { + private: + static constexpr size_t NumStaticMappings = 8; + + class Mapping { + public: + constexpr void Set(VAddr c, VAddr s, size_t sz, KMemoryState st) { + m_client_address = c; + m_server_address = s; + m_size = sz; + m_state = st; + } + + constexpr VAddr GetClientAddress() const { + return m_client_address; + } + constexpr VAddr GetServerAddress() const { + return m_server_address; + } + constexpr size_t GetSize() const { + return m_size; + } + constexpr KMemoryState GetMemoryState() const { + return m_state; + } + + private: + VAddr m_client_address; + VAddr m_server_address; + size_t m_size; + KMemoryState m_state; + }; + + public: + explicit SessionMappings(KernelCore& kernel_) : kernel(kernel_) {} + + void Initialize() {} + void Finalize(); + + size_t GetSendCount() const { + return m_num_send; + } + size_t GetReceiveCount() const { + return m_num_recv; + } + size_t GetExchangeCount() const { + return m_num_exch; + } + + Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state); + Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state); + Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state); + + VAddr GetSendClientAddress(size_t i) const { + return GetSendMapping(i).GetClientAddress(); + } + VAddr GetSendServerAddress(size_t i) const { + return GetSendMapping(i).GetServerAddress(); + } + size_t GetSendSize(size_t i) const { + return GetSendMapping(i).GetSize(); + } + KMemoryState GetSendMemoryState(size_t i) const { + return GetSendMapping(i).GetMemoryState(); + } + + VAddr GetReceiveClientAddress(size_t i) const { + return GetReceiveMapping(i).GetClientAddress(); + } + VAddr GetReceiveServerAddress(size_t i) const { + return GetReceiveMapping(i).GetServerAddress(); + } + size_t GetReceiveSize(size_t i) const { + return GetReceiveMapping(i).GetSize(); + } + KMemoryState GetReceiveMemoryState(size_t i) const { + return GetReceiveMapping(i).GetMemoryState(); + } + + VAddr GetExchangeClientAddress(size_t i) const { + return GetExchangeMapping(i).GetClientAddress(); + } + VAddr GetExchangeServerAddress(size_t i) const { + return GetExchangeMapping(i).GetServerAddress(); + } + size_t GetExchangeSize(size_t i) const { + return GetExchangeMapping(i).GetSize(); + } + KMemoryState GetExchangeMemoryState(size_t i) const { + return GetExchangeMapping(i).GetMemoryState(); + } + + private: + Result PushMap(VAddr client, VAddr server, size_t size, KMemoryState state, size_t index); + + const Mapping& GetSendMapping(size_t i) const { + ASSERT(i < m_num_send); + + const size_t index = i; + if (index < NumStaticMappings) { + return m_static_mappings[index]; + } else { + return m_mappings[index - NumStaticMappings]; + } + } + + const Mapping& GetReceiveMapping(size_t i) const { + ASSERT(i < m_num_recv); + + const size_t index = m_num_send + i; + if (index < NumStaticMappings) { + return m_static_mappings[index]; + } else { + return m_mappings[index - NumStaticMappings]; + } + } + + const Mapping& GetExchangeMapping(size_t i) const { + ASSERT(i < m_num_exch); + + const size_t index = m_num_send + m_num_recv + i; + if (index < NumStaticMappings) { + return m_static_mappings[index]; + } else { + return m_mappings[index - NumStaticMappings]; + } + } + + private: + KernelCore& kernel; + std::array<Mapping, NumStaticMappings> m_static_mappings; + Mapping* m_mappings{}; + u8 m_num_send{}; + u8 m_num_recv{}; + u8 m_num_exch{}; + }; + +public: + explicit KSessionRequest(KernelCore& kernel_) : KAutoObject(kernel_), m_mappings(kernel_) {} + + static KSessionRequest* Create(KernelCore& kernel) { + KSessionRequest* req = KSessionRequest::Allocate(kernel); + if (req != nullptr) [[likely]] { + KAutoObject::Create(req); + } + return req; + } + + void Destroy() override { + this->Finalize(); + KSessionRequest::Free(kernel, this); + } + + void Initialize(KEvent* event, uintptr_t address, size_t size) { + m_mappings.Initialize(); + + m_thread = GetCurrentThreadPointer(kernel); + m_event = event; + m_address = address; + m_size = size; + + m_thread->Open(); + if (m_event != nullptr) { + m_event->Open(); + } + } + + static void PostDestroy(uintptr_t arg) {} + + KThread* GetThread() const { + return m_thread; + } + KEvent* GetEvent() const { + return m_event; + } + uintptr_t GetAddress() const { + return m_address; + } + size_t GetSize() const { + return m_size; + } + KProcess* GetServerProcess() const { + return m_server; + } + + void SetServerProcess(KProcess* process) { + m_server = process; + m_server->Open(); + } + + void ClearThread() { + m_thread = nullptr; + } + void ClearEvent() { + m_event = nullptr; + } + + size_t GetSendCount() const { + return m_mappings.GetSendCount(); + } + size_t GetReceiveCount() const { + return m_mappings.GetReceiveCount(); + } + size_t GetExchangeCount() const { + return m_mappings.GetExchangeCount(); + } + + Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state) { + return m_mappings.PushSend(client, server, size, state); + } + + Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state) { + return m_mappings.PushReceive(client, server, size, state); + } + + Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state) { + return m_mappings.PushExchange(client, server, size, state); + } + + VAddr GetSendClientAddress(size_t i) const { + return m_mappings.GetSendClientAddress(i); + } + VAddr GetSendServerAddress(size_t i) const { + return m_mappings.GetSendServerAddress(i); + } + size_t GetSendSize(size_t i) const { + return m_mappings.GetSendSize(i); + } + KMemoryState GetSendMemoryState(size_t i) const { + return m_mappings.GetSendMemoryState(i); + } + + VAddr GetReceiveClientAddress(size_t i) const { + return m_mappings.GetReceiveClientAddress(i); + } + VAddr GetReceiveServerAddress(size_t i) const { + return m_mappings.GetReceiveServerAddress(i); + } + size_t GetReceiveSize(size_t i) const { + return m_mappings.GetReceiveSize(i); + } + KMemoryState GetReceiveMemoryState(size_t i) const { + return m_mappings.GetReceiveMemoryState(i); + } + + VAddr GetExchangeClientAddress(size_t i) const { + return m_mappings.GetExchangeClientAddress(i); + } + VAddr GetExchangeServerAddress(size_t i) const { + return m_mappings.GetExchangeServerAddress(i); + } + size_t GetExchangeSize(size_t i) const { + return m_mappings.GetExchangeSize(i); + } + KMemoryState GetExchangeMemoryState(size_t i) const { + return m_mappings.GetExchangeMemoryState(i); + } + +private: + // NOTE: This is public and virtual in Nintendo's kernel. + void Finalize() override { + m_mappings.Finalize(); + + if (m_thread) { + m_thread->Close(); + } + if (m_event) { + m_event->Close(); + } + if (m_server) { + m_server->Close(); + } + } + +private: + SessionMappings m_mappings; + KThread* m_thread{}; + KProcess* m_server{}; + KEvent* m_event{}; + uintptr_t m_address{}; + size_t m_size{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory_info.h b/src/core/hle/kernel/k_shared_memory_info.h index e43db8515..2bb6b6d08 100644 --- a/src/core/hle/kernel/k_shared_memory_info.h +++ b/src/core/hle/kernel/k_shared_memory_info.h @@ -15,7 +15,8 @@ class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>, public boost::intrusive::list_base_hook<> { public: - explicit KSharedMemoryInfo() = default; + explicit KSharedMemoryInfo(KernelCore&) {} + KSharedMemoryInfo() = default; constexpr void Initialize(KSharedMemory* shmem) { shared_memory = shmem; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index b7bfcdce3..cc88d08f0 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -148,7 +148,9 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack physical_affinity_mask.SetAffinity(phys_core, true); // Set the thread state. - thread_state = (type == ThreadType::Main) ? ThreadState::Runnable : ThreadState::Initialized; + thread_state = (type == ThreadType::Main || type == ThreadType::Dummy) + ? ThreadState::Runnable + : ThreadState::Initialized; // Set TLS address. tls_address = 0; @@ -1174,30 +1176,31 @@ Result KThread::Sleep(s64 timeout) { R_SUCCEED(); } -void KThread::IfDummyThreadTryWait() { - if (!IsDummyThread()) { - return; - } +void KThread::RequestDummyThreadWait() { + ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); + ASSERT(this->IsDummyThread()); + + // We will block when the scheduler lock is released. + dummy_thread_runnable.store(false); +} - if (GetState() != ThreadState::Waiting) { +void KThread::DummyThreadBeginWait() { + if (!this->IsDummyThread() || kernel.IsPhantomModeForSingleCore()) { + // Occurs in single core mode. return; } - ASSERT(!kernel.IsPhantomModeForSingleCore()); - - // Block until we are no longer waiting. - std::unique_lock lk(dummy_wait_lock); - dummy_wait_cv.wait( - lk, [&] { return GetState() != ThreadState::Waiting || kernel.IsShuttingDown(); }); + // Block until runnable is no longer false. + dummy_thread_runnable.wait(false); } -void KThread::IfDummyThreadEndWait() { - if (!IsDummyThread()) { - return; - } +void KThread::DummyThreadEndWait() { + ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); + ASSERT(this->IsDummyThread()); // Wake up the waiting thread. - dummy_wait_cv.notify_one(); + dummy_thread_runnable.store(true); + dummy_thread_runnable.notify_one(); } void KThread::BeginWait(KThreadQueue* queue) { @@ -1231,9 +1234,6 @@ void KThread::EndWait(Result wait_result_) { } wait_queue->EndWait(this, wait_result_); - - // Special case for dummy threads to wakeup if necessary. - IfDummyThreadEndWait(); } } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index e2a27d603..30aa10c9a 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -643,8 +643,9 @@ public: // therefore will not block on guest kernel synchronization primitives. These methods handle // blocking as needed. - void IfDummyThreadTryWait(); - void IfDummyThreadEndWait(); + void RequestDummyThreadWait(); + void DummyThreadBeginWait(); + void DummyThreadEndWait(); [[nodiscard]] uintptr_t GetArgument() const { return argument; @@ -777,8 +778,7 @@ private: bool is_single_core{}; ThreadType thread_type{}; StepState step_state{}; - std::mutex dummy_wait_lock; - std::condition_variable dummy_wait_cv; + std::atomic<bool> dummy_thread_runnable{true}; // For debugging std::vector<KSynchronizationObject*> wait_objects_for_debugging; diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h index 0a7f22680..5d466ace7 100644 --- a/src/core/hle/kernel/k_thread_local_page.h +++ b/src/core/hle/kernel/k_thread_local_page.h @@ -26,7 +26,7 @@ public: static_assert(RegionsPerPage > 0); public: - constexpr explicit KThreadLocalPage(VAddr addr = {}) : m_virt_addr(addr) { + constexpr explicit KThreadLocalPage(KernelCore&, VAddr addr = {}) : m_virt_addr(addr) { m_is_region_free.fill(true); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index eed2dc9f3..fdc774e30 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -48,8 +48,8 @@ namespace Kernel { struct KernelCore::Impl { explicit Impl(Core::System& system_, KernelCore& kernel_) - : time_manager{system_}, - service_threads_manager{1, "ServiceThreadsManager"}, system{system_} {} + : time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"}, + service_thread_barrier{2}, system{system_} {} void SetMulticore(bool is_multi) { is_multicore = is_multi; @@ -737,7 +737,12 @@ struct KernelCore::Impl { } void ClearServiceThreads() { - service_threads_manager.QueueWork([this]() { service_threads.clear(); }); + service_threads_manager.QueueWork([this] { + service_threads.clear(); + default_service_thread.reset(); + service_thread_barrier.Sync(); + }); + service_thread_barrier.Sync(); } std::mutex server_objects_lock; @@ -802,6 +807,7 @@ struct KernelCore::Impl { std::unordered_set<std::shared_ptr<ServiceThread>> service_threads; std::weak_ptr<ServiceThread> default_service_thread; Common::ThreadWorker service_threads_manager; + Common::Barrier service_thread_barrier; std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 6eded9539..266be2bc4 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -47,6 +47,7 @@ class KResourceLimit; class KScheduler; class KServerSession; class KSession; +class KSessionRequest; class KSharedMemory; class KSharedMemoryInfo; class KThread; @@ -360,6 +361,8 @@ public: return slab_heap_container->page_buffer; } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { return slab_heap_container->thread_local_page; + } else if constexpr (std::is_same_v<T, KSessionRequest>) { + return slab_heap_container->session_request; } } @@ -422,6 +425,7 @@ private: KSlabHeap<KCodeMemory> code_memory; KSlabHeap<KPageBuffer> page_buffer; KSlabHeap<KThreadLocalPage> thread_local_page; + KSlabHeap<KSessionRequest> session_request; }; std::unique_ptr<SlabHeapContainer> slab_heap_container; diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index 299a981a8..06b51e919 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h @@ -24,7 +24,7 @@ public: } static Derived* Allocate(KernelCore& kernel) { - return kernel.SlabHeap<Derived>().Allocate(); + return kernel.SlabHeap<Derived>().Allocate(kernel); } static void Free(KernelCore& kernel, Derived* obj) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b07ae3f02..4aca5b27d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -751,8 +751,8 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { } system.GetReporter().SaveSvcBreakReport( - static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger, info1, - info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); + static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger.As<bool>(), + info1, info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); if (!break_reason.signal_debugger) { LOG_CRITICAL( diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index bb838e285..85a3f0802 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -512,10 +512,11 @@ protected: class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { public: - explicit IManagerForApplication(Core::System& system_, Common::UUID user_id_) + explicit IManagerForApplication(Core::System& system_, + const std::shared_ptr<ProfileManager>& profile_manager_) : ServiceFramework{system_, "IManagerForApplication"}, ensure_token_id{std::make_shared<EnsureTokenIdCacheAsyncInterface>(system)}, - user_id{user_id_} { + profile_manager{profile_manager_} { // clang-format off static const FunctionInfo functions[] = { {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, @@ -545,7 +546,7 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushRaw<u64>(user_id.Hash()); + rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash()); } void EnsureIdTokenCacheAsync(Kernel::HLERequestContext& ctx) { @@ -575,17 +576,20 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushRaw<u64>(user_id.Hash()); + rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash()); } void StoreOpenContext(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); + LOG_DEBUG(Service_ACC, "called"); + + profile_manager->StoreOpenedUsers(); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } std::shared_ptr<EnsureTokenIdCacheAsyncInterface> ensure_token_id{}; - Common::UUID user_id{}; + std::shared_ptr<ProfileManager> profile_manager; }; // 6.0.0+ @@ -790,7 +794,7 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo LOG_DEBUG(Service_ACC, "called"); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser()); + rb.PushIpcInterface<IManagerForApplication>(system, profile_manager); } void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) { @@ -849,22 +853,10 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } -void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); - - // This is similar to GetBaasAccountManagerForApplication - // This command is used concurrently with ListOpenContextStoredUsers - // TODO: Find the differences between this and GetBaasAccountManagerForApplication - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser()); -} - void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); + LOG_DEBUG(Service_ACC, "called"); - // TODO(ogniK): Handle open contexts - ctx.WriteBuffer(profile_manager->GetOpenUsers()); + ctx.WriteBuffer(profile_manager->GetStoredOpenedUsers()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 1621e7c0a..9411b0b92 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -35,7 +35,6 @@ public: void InitializeApplicationInfoV2(Kernel::HLERequestContext& ctx); void GetProfileEditor(Kernel::HLERequestContext& ctx); void ListQualifiedUsers(Kernel::HLERequestContext& ctx); - void LoadOpenContext(Kernel::HLERequestContext& ctx); void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); void StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx); void StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 65023b8c2..54844bfe7 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -28,7 +28,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> {110, &ACC_U0::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"}, {111, nullptr, "ClearSaveDataThumbnail"}, {120, nullptr, "CreateGuestLoginRequest"}, - {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+ + {130, nullptr, "LoadOpenContext"}, // 5.0.0+ {131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+ {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index a58da4d5f..481e0d141 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -261,6 +261,31 @@ UUID ProfileManager::GetLastOpenedUser() const { return last_opened_user; } +/// Gets the list of stored opened users. +UserIDArray ProfileManager::GetStoredOpenedUsers() const { + UserIDArray output{}; + std::ranges::transform(stored_opened_profiles, output.begin(), [](const ProfileInfo& p) { + if (p.is_open) + return p.user_uuid; + return Common::InvalidUUID; + }); + std::stable_partition(output.begin(), output.end(), + [](const UUID& uuid) { return uuid.IsValid(); }); + return output; +} + +/// Captures the opened users, which can be queried across process launches with +/// ListOpenContextStoredUsers. +void ProfileManager::StoreOpenedUsers() { + size_t profile_index{}; + stored_opened_profiles = {}; + std::for_each(profiles.begin(), profiles.end(), [&](const auto& profile) { + if (profile.is_open) { + stored_opened_profiles[profile_index++] = profile; + } + }); +} + /// Return the users profile base and the unknown arbitary data. bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile, UserData& data) const { diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 135f7d0d5..993a5a57a 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -86,6 +86,8 @@ public: UserIDArray GetOpenUsers() const; UserIDArray GetAllUsers() const; Common::UUID GetLastOpenedUser() const; + UserIDArray GetStoredOpenedUsers() const; + void StoreOpenedUsers(); bool CanSystemRegisterUser() const; @@ -101,6 +103,7 @@ private: bool RemoveProfileAtIndex(std::size_t index); std::array<ProfileInfo, MAX_USERS> profiles{}; + std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; std::size_t user_count{}; Common::UUID last_opened_user{}; }; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index e55233054..8ea7fd760 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -299,7 +299,7 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, {110, nullptr, "SetApplicationAlbumUserData"}, {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, - {130, nullptr, "SetRecordVolumeMuted"}, + {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"}, {1000, nullptr, "GetDebugStorageChannel"}, }; // clang-format on @@ -597,6 +597,17 @@ void ISelfController::SaveCurrentScreenshot(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void ISelfController::SetRecordVolumeMuted(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto is_record_volume_muted = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + AppletMessageQueue::AppletMessageQueue(Core::System& system) : service_context{system, "AppletMessageQueue"} { on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index bb75c6281..a0fbfcfc5 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -182,6 +182,7 @@ private: void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx); void SaveCurrentScreenshot(Kernel::HLERequestContext& ctx); + void SetRecordVolumeMuted(Kernel::HLERequestContext& ctx); enum class ScreenshotPermission : u32 { Inherit = 0, diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index e78a57657..12c6a5b1a 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -164,7 +164,7 @@ protected: u32_le size; u32_le library_version; u32_le theme_color; - u8 play_startup_sound; + bool play_startup_sound; u64_le system_tick; }; static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 4a2ae5f88..5abf22ba4 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp @@ -45,9 +45,25 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} { {32, nullptr, "GetActiveOutputTarget"}, {33, nullptr, "GetTargetDeviceInfo"}, {34, nullptr, "AcquireTargetNotification"}, + {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, + {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, + {37, nullptr, "SetHearingProtectionSafeguardEnabled"}, + {38, nullptr, "IsHearingProtectionSafeguardEnabled"}, + {39, nullptr, "IsHearingProtectionSafeguardMonitoringOutputForDebug"}, + {40, nullptr, "GetSystemInformationForDebug"}, + {41, nullptr, "SetVolumeButtonLongPressTime"}, + {42, nullptr, "SetNativeVolumeForDebug"}, {10000, nullptr, "NotifyAudioOutputTargetForPlayReport"}, {10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"}, {10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"}, + {10100, nullptr, "GetAudioVolumeDataForPlayReport"}, + {10101, nullptr, "BindAudioVolumeUpdateEventForPlayReport"}, + {10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"}, + {10103, nullptr, "GetAudioOutputTargetForPlayReport"}, + {10104, nullptr, "GetAudioOutputChannelCountForPlayReport"}, + {10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, + {10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"}, + {50000, nullptr, "SetAnalogInputBoostGainForPrototyping"}, }; // clang-format on diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 48a9a73a0..608925dfc 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -17,7 +17,7 @@ using namespace AudioCore::AudioIn; class IAudioIn final : public ServiceFramework<IAudioIn> { public: explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, - std::string& device_name, const AudioInParameter& in_params, u32 handle, + const std::string& device_name, const AudioInParameter& in_params, u32 handle, u64 applet_resource_user_id) : ServiceFramework{system_, "IAudioIn"}, service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 49c092301..122290c6a 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -24,7 +24,7 @@ using namespace AudioCore::AudioOut; class IAudioOut final : public ServiceFramework<IAudioOut> { public: explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, - size_t session_id, std::string& device_name, + size_t session_id, const std::string& device_name, const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew}, service_context{system_, "IAudioOut"}, event{service_context.CreateEvent( diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 60c30cd5b..13423dca6 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -52,6 +52,8 @@ public: {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"}, {11, nullptr, "ExecuteAudioRendererRendering"}, + {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"}, + {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"}, }; // clang-format on RegisterHandlers(functions); @@ -205,6 +207,30 @@ private: LOG_DEBUG(Service_Audio, "called"); } + void SetVoiceDropParameter(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Audio, "called"); + + IPC::RequestParser rp{ctx}; + auto voice_drop_param{rp.Pop<f32>()}; + + auto& system_ = impl->GetSystem(); + system_.SetVoiceDropParameter(voice_drop_param); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void GetVoiceDropParameter(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_Audio, "called"); + + auto& system_ = impl->GetSystem(); + auto voice_drop_param{system_.GetVoiceDropParameter()}; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(voice_drop_param); + } + KernelHelpers::ServiceContext service_context; Kernel::KEvent* rendered_event; Manager& manager; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 98e4f2af7..2f871de31 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -745,8 +745,9 @@ void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { } void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { - ASSERT(max_length < supported_npad_id_types.size()); - std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size()); + const auto copy_amount = supported_npad_id_types.size() * sizeof(u32); + ASSERT(max_length <= copy_amount); + std::memcpy(data, supported_npad_id_types.data(), copy_amount); } std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { @@ -867,7 +868,7 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, return false; } - if (!controller.device->IsVibrationEnabled()) { + if (!controller.device->IsVibrationEnabled(device_index)) { if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { // Send an empty vibration to stop any vibrations. @@ -1000,7 +1001,7 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npa } controller.vibration[device_index].device_mounted = - controller.device->TestVibration(device_index); + controller.device->IsVibrationEnabled(device_index); } void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { @@ -1501,25 +1502,25 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller Core::HID::NpadStyleTag style = GetSupportedStyleSet(); switch (controller) { case Core::HID::NpadStyleIndex::ProController: - return style.fullkey; + return style.fullkey.As<bool>(); case Core::HID::NpadStyleIndex::JoyconDual: - return style.joycon_dual; + return style.joycon_dual.As<bool>(); case Core::HID::NpadStyleIndex::JoyconLeft: - return style.joycon_left; + return style.joycon_left.As<bool>(); case Core::HID::NpadStyleIndex::JoyconRight: - return style.joycon_right; + return style.joycon_right.As<bool>(); case Core::HID::NpadStyleIndex::GameCube: - return style.gamecube; + return style.gamecube.As<bool>(); case Core::HID::NpadStyleIndex::Pokeball: - return style.palma; + return style.palma.As<bool>(); case Core::HID::NpadStyleIndex::NES: - return style.lark; + return style.lark.As<bool>(); case Core::HID::NpadStyleIndex::SNES: - return style.lucia; + return style.lucia.As<bool>(); case Core::HID::NpadStyleIndex::N64: - return style.lagoon; + return style.lagoon.As<bool>(); case Core::HID::NpadStyleIndex::SegaGenesis: - return style.lager; + return style.lager.As<bool>(); default: return false; } diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index c32a6816b..167e29572 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp @@ -9,6 +9,7 @@ #include <mbedtls/hmac_drbg.h> #include "common/fs/file.h" +#include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging/log.h" #include "core/hle/service/mii/mii_manager.h" @@ -279,7 +280,7 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) { Common::FS::FileType::BinaryFile}; if (!keys_file.IsOpen()) { - LOG_ERROR(Service_NFP, "No keys detected"); + LOG_ERROR(Service_NFP, "Failed to open key file"); return false; } @@ -295,6 +296,11 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) { return true; } +bool IsKeyAvailable() { + const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); + return Common::FS::Exists(yuzu_keys_dir / "key_retail.bin"); +} + bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data) { InternalKey locked_secret{}; InternalKey unfixed_info{}; diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfp/amiibo_crypto.h index 0175ced91..1fa61174e 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.h +++ b/src/core/hle/service/nfp/amiibo_crypto.h @@ -91,6 +91,9 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou /// Loads both amiibo keys from key_retail.bin bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info); +/// Returns true if key_retail.bin exist +bool IsKeyAvailable(); + /// Decodes encripted amiibo data returns true if output is valid bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data); diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 76f8a267a..b19672560 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -17,6 +17,7 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/mii/types.h" #include "core/hle/service/nfp/amiibo_crypto.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nfp/nfp_device.h" @@ -233,6 +234,14 @@ Result NfpDevice::Mount(MountTarget mount_target_) { return NotAnAmiibo; } + // Mark amiibos as read only when keys are missing + if (!AmiiboCrypto::IsKeyAvailable()) { + LOG_ERROR(Service_NFP, "No keys detected"); + device_state = DeviceState::TagMounted; + mount_target = MountTarget::Rom; + return ResultSuccess; + } + if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) { LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state); return CorruptedData; diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index a5b72cf19..76d0e9ae4 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -8,7 +8,6 @@ #include "common/common_funcs.h" #include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/mii/types.h" #include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/service.h" diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index c09f9ddb6..63d5917cb 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -17,11 +17,6 @@ enum class ServiceType : u32 { System, }; -enum class State : u32 { - NonInitialized, - Initialized, -}; - enum class DeviceState : u32 { Initialized, SearchingForTag, diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 4ed53b534..33e2ef518 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -6,12 +6,9 @@ #include "common/logging/log.h" #include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_event.h" -#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/nfp/nfp_device.h" #include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/nfp/nfp_user.h" diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 68c60ae82..47aff3695 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h @@ -4,8 +4,7 @@ #pragma once #include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/nfp/nfp.h" -#include "core/hle/service/nfp/nfp_types.h" +#include "core/hle/service/service.h" namespace Service::NFP { class NfpDevice; @@ -15,6 +14,11 @@ public: explicit IUser(Core::System& system_); private: + enum class State : u32 { + NonInitialized, + Initialized, + }; + void Initialize(Kernel::HLERequestContext& ctx); void Finalize(Kernel::HLERequestContext& ctx); void ListDevices(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index fbd8a74a5..a51ca5444 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -255,15 +255,16 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna .address = handle_description->address, .size = handle_description->size, .was_uncached = handle_description->flags.map_uncached.Value() != 0, + .can_unlock = true, }; } else { return std::nullopt; } - // Handle hasn't been freed from memory, set address to 0 to mark that the handle wasn't freed + // If the handle hasn't been freed from memory, mark that if (!hWeak.expired()) { LOG_DEBUG(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle); - freeInfo.address = 0; + freeInfo.can_unlock = false; } return freeInfo; diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index b9dd3801f..a8e573890 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -105,6 +105,7 @@ public: u64 address; //!< Address the handle referred to before deletion u64 size; //!< Page-aligned handle size bool was_uncached; //!< If the handle was allocated as uncached + bool can_unlock; //!< If the address region is ready to be unlocked }; explicit NvMap(Tegra::Host1x::Host1x& host1x); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index b60679021..44388655d 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -251,10 +251,12 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { } if (auto freeInfo{file.FreeHandle(params.handle, false)}) { - ASSERT(system.CurrentProcess() - ->PageTable() - .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) - .IsSuccess()); + if (freeInfo->can_unlock) { + ASSERT(system.CurrentProcess() + ->PageTable() + .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) + .IsSuccess()); + } params.address = freeInfo->address; params.size = static_cast<u32>(freeInfo->size); params.flags.raw = 0; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9d9924395..9f4c7c99a 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -53,7 +53,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger } Module::Module(Core::System& system) - : service_context{system, "nvdrv"}, events_interface{*this}, container{system.Host1x()} { + : container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} { builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { std::shared_ptr<Devices::nvdevice> device = std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 146d046a9..f3c81bd88 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -97,6 +97,9 @@ private: friend class EventInterface; friend class Service::NVFlinger::NVFlinger; + /// Manages syncpoints on the host + NvCore::Container container; + /// Id to use for the next open file descriptor. DeviceFD next_fd = 1; @@ -108,9 +111,6 @@ private: EventInterface events_interface; - /// Manages syncpoints on the host - NvCore::Container container; - std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders; }; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 77ddbb6ef..41ba44b21 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -742,6 +742,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) { return Status::NoError; } + // HACK: We are not Android. Remove handle for items in queue, and clear queue. + // Allows synchronous destruction of nvmap handles. + for (auto& item : core->queue) { + nvmap.FreeHandle(item.graphic_buffer->BufferId(), true); + } + core->queue.clear(); + switch (api) { case NativeWindowApi::Egl: case NativeWindowApi::Cpu: diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index aa14d2cbc..c3af12c90 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -102,15 +102,19 @@ NVFlinger::~NVFlinger() { system.CoreTiming().UnscheduleEvent(single_composition_event, {}); } + ShutdownLayers(); + + if (nvdrv) { + nvdrv->Close(disp_fd); + } +} + +void NVFlinger::ShutdownLayers() { for (auto& display : displays) { for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { display.GetLayer(layer).Core().NotifyShutdown(); } } - - if (nvdrv) { - nvdrv->Close(disp_fd); - } } void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { @@ -134,6 +138,19 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { return itr->GetID(); } +bool NVFlinger::CloseDisplay(u64 display_id) { + const auto lock_guard = Lock(); + auto* const display = FindDisplay(display_id); + + if (display == nullptr) { + return false; + } + + display->Reset(); + + return true; +} + std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { const auto lock_guard = Lock(); auto* const display = FindDisplay(display_id); diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 99509bc5b..460bef976 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -48,6 +48,8 @@ public: explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_); ~NVFlinger(); + void ShutdownLayers(); + /// Sets the NVDrv module instance to use to send buffers to the GPU. void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); @@ -56,6 +58,11 @@ public: /// If an invalid display name is provided, then an empty optional is returned. [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name); + /// Closes the specified display by its ID. + /// + /// Returns false if an invalid display ID is provided. + [[nodiscard]] bool CloseDisplay(u64 display_id); + /// Creates a layer on the specified display and returns the layer ID. /// /// If an invalid display ID is specified, then an empty optional is returned. diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index dadaf897f..5db6588e4 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -303,4 +303,8 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system Services::~Services() = default; +void Services::KillNVNFlinger() { + nv_flinger->ShutdownLayers(); +} + } // namespace Service diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 5bf197c51..ec9deeee4 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -238,6 +238,8 @@ public: explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); ~Services(); + void KillNVNFlinger(); + private: std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server; std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 48e70f93c..cb6c0e96f 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -80,7 +80,6 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name } auto* port = Kernel::KPort::Create(kernel); - SCOPE_EXIT({ port->Close(); }); port->Initialize(ServerSessionCountMax, false, name); auto handler = it->second; @@ -150,9 +149,10 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& return port_result.Code(); } auto& port = port_result.Unwrap(); - SCOPE_EXIT({ port->GetClientPort().Close(); }); - - kernel.RegisterServerObject(&port->GetServerPort()); + SCOPE_EXIT({ + port->GetClientPort().Close(); + port->GetServerPort().Close(); + }); // Create a new session. Kernel::KClientSession* session{}; diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp index 2a4bd64ab..46a8439d8 100644 --- a/src/core/hle/service/sm/sm_controller.cpp +++ b/src/core/hle/service/sm/sm_controller.cpp @@ -15,9 +15,10 @@ namespace Service::SM { void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { - ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); + ASSERT_MSG(!ctx.Session()->GetSessionRequestManager()->IsDomain(), + "Session is already a domain"); LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); - ctx.Session()->ConvertToDomain(); + ctx.Session()->GetSessionRequestManager()->ConvertToDomainOnRequestEnd(); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -27,23 +28,36 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service, "called"); + auto& process = *ctx.GetThread().GetOwnerProcess(); auto& parent_session = *ctx.Session()->GetParent(); - auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort(); auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); + auto& session_handler = session_manager->SessionHandler(); - // Create a session. - Kernel::KClientSession* session{}; - const Result result = parent_port.CreateSession(std::addressof(session), session_manager); - if (result.IsError()) { - LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } + // FIXME: this is duplicated from the SVC, it should just call it instead + // once this is a proper process + + // Reserve a new session from the process resource limit. + Kernel::KScopedResourceReservation session_reservation(&process, + Kernel::LimitableResource::Sessions); + ASSERT(session_reservation.Succeeded()); + + // Create the session. + Kernel::KSession* session = Kernel::KSession::Create(system.Kernel()); + ASSERT(session != nullptr); + + // Initialize the session. + session->Initialize(nullptr, parent_session.GetName(), session_manager); + + // Commit the session reservation. + session_reservation.Commit(); + + // Register the session. + session_handler.ClientConnected(&session->GetServerSession()); // We succeeded. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(ResultSuccess); - rb.PushMoveObjects(session); + rb.PushMoveObjects(session->GetClientSession()); } void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 33d5f398c..0b65a65da 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -106,6 +106,12 @@ public: /// void CloseLayer(u64 layer_id); + /// Resets the display for a new connection. + void Reset() { + layers.clear(); + got_vsync_event = false; + } + /// Attempts to find a layer with the given ID. /// /// @param layer_id The layer ID. diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 9c917cacf..bb283e74e 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -324,10 +324,10 @@ private: IPC::RequestParser rp{ctx}; const u64 display = rp.Pop<u64>(); - LOG_WARNING(Service_VI, "(STUBBED) called. display=0x{:016X}", display); + const Result rc = nv_flinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(rc); } void CreateManagedLayer(Kernel::HLERequestContext& ctx) { @@ -508,10 +508,10 @@ private: IPC::RequestParser rp{ctx}; const u64 display_id = rp.Pop<u64>(); - LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); + const Result rc = nv_flinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(rc); } // This literally does nothing internally in the actual service itself, diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9637cb5b1..3ca80c8ff 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -233,18 +233,17 @@ struct Memory::Impl { current_vaddr, src_addr, size); std::memset(dest_buffer, 0, copy_amount); }, - [&dest_buffer](const std::size_t copy_amount, const u8* const src_ptr) { + [&](const std::size_t copy_amount, const u8* const src_ptr) { std::memcpy(dest_buffer, src_ptr, copy_amount); }, - [&system = system, &dest_buffer](const VAddr current_vaddr, - const std::size_t copy_amount, - const u8* const host_ptr) { + [&](const VAddr current_vaddr, const std::size_t copy_amount, + const u8* const host_ptr) { if constexpr (!UNSAFE) { system.GPU().FlushRegion(current_vaddr, copy_amount); } std::memcpy(dest_buffer, host_ptr, copy_amount); }, - [&dest_buffer](const std::size_t copy_amount) { + [&](const std::size_t copy_amount) { dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; }); } @@ -267,17 +266,16 @@ struct Memory::Impl { "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", current_vaddr, dest_addr, size); }, - [&src_buffer](const std::size_t copy_amount, u8* const dest_ptr) { + [&](const std::size_t copy_amount, u8* const dest_ptr) { std::memcpy(dest_ptr, src_buffer, copy_amount); }, - [&system = system, &src_buffer](const VAddr current_vaddr, - const std::size_t copy_amount, u8* const host_ptr) { + [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { if constexpr (!UNSAFE) { system.GPU().InvalidateRegion(current_vaddr, copy_amount); } std::memcpy(host_ptr, src_buffer, copy_amount); }, - [&src_buffer](const std::size_t copy_amount) { + [&](const std::size_t copy_amount) { src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; }); } @@ -301,8 +299,7 @@ struct Memory::Impl { [](const std::size_t copy_amount, u8* const dest_ptr) { std::memset(dest_ptr, 0, copy_amount); }, - [&system = system](const VAddr current_vaddr, const std::size_t copy_amount, - u8* const host_ptr) { + [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { system.GPU().InvalidateRegion(current_vaddr, copy_amount); std::memset(host_ptr, 0, copy_amount); }, @@ -313,22 +310,20 @@ struct Memory::Impl { const std::size_t size) { WalkBlock( process, dest_addr, size, - [this, &process, &dest_addr, &src_addr, size](const std::size_t copy_amount, - const VAddr current_vaddr) { + [&](const std::size_t copy_amount, const VAddr current_vaddr) { LOG_ERROR(HW_Memory, "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", current_vaddr, src_addr, size); ZeroBlock(process, dest_addr, copy_amount); }, - [this, &process, &dest_addr](const std::size_t copy_amount, const u8* const src_ptr) { + [&](const std::size_t copy_amount, const u8* const src_ptr) { WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount); }, - [this, &system = system, &process, &dest_addr]( - const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { + [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { system.GPU().FlushRegion(current_vaddr, copy_amount); WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount); }, - [&dest_addr, &src_addr](const std::size_t copy_amount) { + [&](const std::size_t copy_amount) { dest_addr += static_cast<VAddr>(copy_amount); src_addr += static_cast<VAddr>(copy_amount); }); @@ -575,7 +570,7 @@ struct Memory::Impl { [vaddr]() { LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, vaddr); }, - [&system = system, vaddr]() { system.GPU().FlushRegion(vaddr, sizeof(T)); }); + [&]() { system.GPU().FlushRegion(vaddr, sizeof(T)); }); if (ptr) { std::memcpy(&result, ptr, sizeof(T)); } @@ -599,7 +594,7 @@ struct Memory::Impl { LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, vaddr, static_cast<u64>(data)); }, - [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); + [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); if (ptr) { std::memcpy(ptr, &data, sizeof(T)); } @@ -613,7 +608,7 @@ struct Memory::Impl { LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, vaddr, static_cast<u64>(data)); }, - [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); + [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); }); if (ptr) { const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr); return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); @@ -628,7 +623,7 @@ struct Memory::Impl { LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}", vaddr, static_cast<u64>(data[1]), static_cast<u64>(data[0])); }, - [&system = system, vaddr]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); }); + [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); }); if (ptr) { const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr); return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 2cf9eb97f..cc6f0ffc0 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -39,21 +39,14 @@ add_library(input_common STATIC if (MSVC) target_compile_options(input_common PRIVATE /W4 - /WX /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data - /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data - /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /we4800 # Implicit conversion from 'type' to bool. Possible information loss ) else() target_compile_options(input_common PRIVATE - -Werror -Werror=conversion - -Werror=ignored-qualifiers - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> - -Werror=unused-variable ) endif() diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index f4dd24e7d..826fa2109 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -324,7 +324,7 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Common::Input::VibrationError GCAdapter::SetRumble( +Common::Input::VibrationError GCAdapter::SetVibration( const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = @@ -338,6 +338,10 @@ Common::Input::VibrationError GCAdapter::SetRumble( return Common::Input::VibrationError::None; } +bool GCAdapter::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { + return rumble_enabled; +} + void GCAdapter::UpdateVibrations() { // Use 8 states to keep the switching between on/off fast enough for // a human to feel different vibration strenght diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 8682da847..7f81767f7 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -25,9 +25,11 @@ public: explicit GCAdapter(std::string input_engine_); ~GCAdapter() override; - Common::Input::VibrationError SetRumble( + Common::Input::VibrationError SetVibration( const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; + bool IsVibrationEnabled(const PadIdentifier& identifier) override; + /// Used for automapping features std::vector<Common::ParamPackage> GetInputDevices() const override; ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index b72e4b397..45ce588f0 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -40,8 +40,8 @@ public: void EnableMotion() { if (sdl_controller) { SDL_GameController* controller = sdl_controller.get(); - has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL); - has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO); + has_accel = SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) == SDL_TRUE; + has_gyro = SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) == SDL_TRUE; if (has_accel) { SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); } @@ -114,6 +114,20 @@ public: } return false; } + + void EnableVibration(bool is_enabled) { + has_vibration = is_enabled; + is_vibration_tested = true; + } + + bool HasVibration() const { + return has_vibration; + } + + bool IsVibrationTested() const { + return is_vibration_tested; + } + /** * The Pad identifier of the joystick */ @@ -236,6 +250,8 @@ private: u64 last_motion_update{}; bool has_gyro{false}; bool has_accel{false}; + bool has_vibration{false}; + bool is_vibration_tested{false}; BasicMotion motion; }; @@ -517,7 +533,7 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const { return devices; } -Common::Input::VibrationError SDLDriver::SetRumble( +Common::Input::VibrationError SDLDriver::SetVibration( const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); @@ -546,13 +562,6 @@ Common::Input::VibrationError SDLDriver::SetRumble( .type = Common::Input::VibrationAmplificationType::Exponential, }; - if (vibration.type == Common::Input::VibrationAmplificationType::Test) { - if (!joystick->RumblePlay(new_vibration)) { - return Common::Input::VibrationError::Unknown; - } - return Common::Input::VibrationError::None; - } - vibration_queue.Push(VibrationRequest{ .identifier = identifier, .vibration = new_vibration, @@ -561,6 +570,45 @@ Common::Input::VibrationError SDLDriver::SetRumble( return Common::Input::VibrationError::None; } +bool SDLDriver::IsVibrationEnabled(const PadIdentifier& identifier) { + const auto joystick = + GetSDLJoystickByGUID(identifier.guid.RawString(), static_cast<int>(identifier.port)); + + constexpr Common::Input::VibrationStatus test_vibration{ + .low_amplitude = 1, + .low_frequency = 160.0f, + .high_amplitude = 1, + .high_frequency = 320.0f, + .type = Common::Input::VibrationAmplificationType::Exponential, + }; + + constexpr Common::Input::VibrationStatus zero_vibration{ + .low_amplitude = 0, + .low_frequency = 160.0f, + .high_amplitude = 0, + .high_frequency = 320.0f, + .type = Common::Input::VibrationAmplificationType::Exponential, + }; + + if (joystick->IsVibrationTested()) { + return joystick->HasVibration(); + } + + // First vibration might fail + joystick->RumblePlay(test_vibration); + + // Wait for about 15ms to ensure the controller is ready for the stop command + std::this_thread::sleep_for(std::chrono::milliseconds(15)); + + if (!joystick->RumblePlay(zero_vibration)) { + joystick->EnableVibration(false); + return false; + } + + joystick->EnableVibration(true); + return true; +} + void SDLDriver::SendVibrations() { while (!vibration_queue.Empty()) { VibrationRequest request; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index fc3a44572..d1b4471cf 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -61,9 +61,11 @@ public: bool IsStickInverted(const Common::ParamPackage& params) override; - Common::Input::VibrationError SetRumble( + Common::Input::VibrationError SetVibration( const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; + bool IsVibrationEnabled(const PadIdentifier& identifier) override; + private: struct VibrationRequest { PadIdentifier identifier; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index cfbdb26bd..d4c264a8e 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -108,12 +108,17 @@ public: [[maybe_unused]] const Common::Input::LedStatus& led_status) {} // Sets rumble to a controller - virtual Common::Input::VibrationError SetRumble( + virtual Common::Input::VibrationError SetVibration( [[maybe_unused]] const PadIdentifier& identifier, [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { return Common::Input::VibrationError::NotSupported; } + // Returns true if device supports vibrations + virtual bool IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { + return false; + } + // Sets polling mode to a controller virtual Common::Input::PollingError SetPollingMode( [[maybe_unused]] const PadIdentifier& identifier, diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index ca33fb4eb..4ac182147 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -763,7 +763,11 @@ public: Common::Input::VibrationError SetVibration( const Common::Input::VibrationStatus& vibration_status) override { - return input_engine->SetRumble(identifier, vibration_status); + return input_engine->SetVibration(identifier, vibration_status); + } + + bool IsVibrationEnabled() override { + return input_engine->IsVibrationEnabled(identifier); } Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override { @@ -797,8 +801,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateButtonDevice( const auto button_id = params.Get("button", 0); const auto keyboard_key = params.Get("code", 0); - const auto toggle = params.Get("toggle", false); - const auto inverted = params.Get("inverted", false); + const auto toggle = params.Get("toggle", false) != 0; + const auto inverted = params.Get("inverted", false) != 0; input_engine->PreSetController(identifier); input_engine->PreSetButton(identifier, button_id); input_engine->PreSetButton(identifier, keyboard_key); @@ -820,8 +824,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateHatButtonDevice( const auto button_id = params.Get("hat", 0); const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); - const auto toggle = params.Get("toggle", false); - const auto inverted = params.Get("inverted", false); + const auto toggle = params.Get("toggle", false) != 0; + const auto inverted = params.Get("inverted", false) != 0; input_engine->PreSetController(identifier); input_engine->PreSetHatButton(identifier, button_id); @@ -879,7 +883,7 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateAnalogDevice( .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), .offset = std::clamp(params.Get("offset", 0.0f), -1.0f, 1.0f), .inverted = params.Get("invert", "+") == "-", - .toggle = static_cast<bool>(params.Get("toggle", false)), + .toggle = params.Get("toggle", false) != 0, }; input_engine->PreSetController(identifier); input_engine->PreSetAxis(identifier, axis); @@ -895,8 +899,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTriggerDevice( }; const auto button = params.Get("button", 0); - const auto toggle = params.Get("toggle", false); - const auto inverted = params.Get("inverted", false); + const auto toggle = params.Get("toggle", false) != 0; + const auto inverted = params.Get("inverted", false) != 0; const auto axis = params.Get("axis", 0); const Common::Input::AnalogProperties properties = { @@ -926,8 +930,8 @@ std::unique_ptr<Common::Input::InputDevice> InputFactory::CreateTouchDevice( }; const auto button = params.Get("button", 0); - const auto toggle = params.Get("toggle", false); - const auto inverted = params.Get("inverted", false); + const auto toggle = params.Get("toggle", false) != 0; + const auto inverted = params.Get("inverted", false) != 0; const auto axis_x = params.Get("axis_x", 0); const Common::Input::AnalogProperties properties_x = { diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index af8e51fe8..bcdd60db9 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -241,24 +241,14 @@ target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit) if (MSVC) target_compile_options(shader_recompiler PRIVATE /W4 - /WX - /we4018 # 'expression' : signed/unsigned mismatch - /we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) - /we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch + + /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data - /we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data - /we4305 # 'context' : truncation from 'type1' to 'type2' /we4800 # Implicit conversion from 'type' to bool. Possible information loss - /we4826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior. ) else() target_compile_options(shader_recompiler PRIVATE - -Werror -Werror=conversion - -Werror=ignored-qualifiers - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> - -Werror=unused-variable # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. # And this in turns limits the size of a std::array. diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp index 7094d8e42..1f4ffdd62 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_not_implemented.cpp @@ -5,10 +5,6 @@ #include "shader_recompiler/backend/glasm/glasm_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" -#ifdef _MSC_VER -#pragma warning(disable : 4100) -#endif - namespace Shader::Backend::GLASM { #define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__) diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp index b03a8ba1e..9f1ed95a4 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp @@ -7,10 +7,6 @@ #include "shader_recompiler/backend/glsl/glsl_emit_context.h" #include "shader_recompiler/frontend/ir/value.h" -#ifdef _MSC_VER -#pragma warning(disable : 4100) -#endif - namespace Shader::Backend::GLSL { void EmitGetRegister(EmitContext& ctx) { diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp index 468782eb1..84417980b 100644 --- a/src/shader_recompiler/frontend/ir/microinstruction.cpp +++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp @@ -325,11 +325,6 @@ void Inst::AddPhiOperand(Block* predecessor, const Value& value) { phi_args.emplace_back(predecessor, value); } -void Inst::ErasePhiOperand(size_t index) { - const auto operand_it{phi_args.begin() + static_cast<ptrdiff_t>(index)}; - phi_args.erase(operand_it); -} - void Inst::OrderPhiArgs() { if (op != Opcode::Phi) { throw LogicError("{} is not a Phi instruction", op); diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index 1a2e4ccb6..6a673ca05 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h @@ -178,13 +178,9 @@ public: /// Get a pointer to the block of a phi argument. [[nodiscard]] Block* PhiBlock(size_t index) const; - /// Add phi operand to a phi instruction. void AddPhiOperand(Block* predecessor, const Value& value); - // Erase the phi operand at the given index. - void ErasePhiOperand(size_t index); - /// Orders the Phi arguments from farthest away to nearest. void OrderPhiArgs(); diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 77efb4f57..b58741d4d 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -137,28 +137,35 @@ bool IsLegacyAttribute(IR::Attribute attribute) { } std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings( - const VaryingState& state, std::queue<IR::Attribute> ununsed_generics) { + const VaryingState& state, std::queue<IR::Attribute> unused_generics, + const std::map<IR::Attribute, IR::Attribute>& previous_stage_mapping) { std::map<IR::Attribute, IR::Attribute> mapping; + auto update_mapping = [&mapping, &unused_generics, previous_stage_mapping](IR::Attribute attr, + size_t count) { + if (previous_stage_mapping.find(attr) != previous_stage_mapping.end()) { + for (size_t i = 0; i < count; ++i) { + mapping.insert({attr + i, previous_stage_mapping.at(attr + i)}); + } + } else { + for (size_t i = 0; i < count; ++i) { + mapping.insert({attr + i, unused_generics.front() + i}); + } + unused_generics.pop(); + } + }; for (size_t index = 0; index < 4; ++index) { auto attr = IR::Attribute::ColorFrontDiffuseR + index * 4; if (state.AnyComponent(attr)) { - for (size_t i = 0; i < 4; ++i) { - mapping.insert({attr + i, ununsed_generics.front() + i}); - } - ununsed_generics.pop(); + update_mapping(attr, 4); } } if (state[IR::Attribute::FogCoordinate]) { - mapping.insert({IR::Attribute::FogCoordinate, ununsed_generics.front()}); - ununsed_generics.pop(); + update_mapping(IR::Attribute::FogCoordinate, 1); } for (size_t index = 0; index < IR::NUM_FIXEDFNCTEXTURE; ++index) { auto attr = IR::Attribute::FixedFncTexture0S + index * 4; if (state.AnyComponent(attr)) { - for (size_t i = 0; i < 4; ++i) { - mapping.insert({attr + i, ununsed_generics.front() + i}); - } - ununsed_generics.pop(); + update_mapping(attr, 4); } } return mapping; @@ -265,21 +272,22 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) { auto& stores = program.info.stores; if (stores.Legacy()) { - std::queue<IR::Attribute> ununsed_output_generics{}; + std::queue<IR::Attribute> unused_output_generics{}; for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { if (!stores.Generic(index)) { - ununsed_output_generics.push(IR::Attribute::Generic0X + index * 4); + unused_output_generics.push(IR::Attribute::Generic0X + index * 4); } } - auto mappings = GenerateLegacyToGenericMappings(stores, ununsed_output_generics); + program.info.legacy_stores_mapping = + GenerateLegacyToGenericMappings(stores, unused_output_generics, {}); for (IR::Block* const block : program.post_order_blocks) { for (IR::Inst& inst : block->Instructions()) { switch (inst.GetOpcode()) { case IR::Opcode::SetAttribute: { const auto attr = inst.Arg(0).Attribute(); if (IsLegacyAttribute(attr)) { - stores.Set(mappings[attr], true); - inst.SetArg(0, Shader::IR::Value(mappings[attr])); + stores.Set(program.info.legacy_stores_mapping[attr], true); + inst.SetArg(0, Shader::IR::Value(program.info.legacy_stores_mapping[attr])); } break; } @@ -292,15 +300,16 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run auto& loads = program.info.loads; if (loads.Legacy()) { - std::queue<IR::Attribute> ununsed_input_generics{}; + std::queue<IR::Attribute> unused_input_generics{}; for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { const AttributeType input_type{runtime_info.generic_input_types[index]}; if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) || input_type == AttributeType::Disabled) { - ununsed_input_generics.push(IR::Attribute::Generic0X + index * 4); + unused_input_generics.push(IR::Attribute::Generic0X + index * 4); } } - auto mappings = GenerateLegacyToGenericMappings(loads, ununsed_input_generics); + auto mappings = GenerateLegacyToGenericMappings( + loads, unused_input_generics, runtime_info.previous_stage_legacy_stores_mapping); for (IR::Block* const block : program.post_order_blocks) { for (IR::Inst& inst : block->Instructions()) { switch (inst.GetOpcode()) { diff --git a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp index 9a7d47344..1bd8afd6f 100644 --- a/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp +++ b/src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp @@ -1,104 +1,24 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <algorithm> - -#include <boost/container/small_vector.hpp> - #include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/value.h" #include "shader_recompiler/ir_opt/passes.h" namespace Shader::Optimization { -namespace { -template <bool TEST_USES> -void DeadInstElimination(IR::Block* const block) { + +void DeadCodeEliminationPass(IR::Program& program) { // We iterate over the instructions in reverse order. // This is because removing an instruction reduces the number of uses for earlier instructions. - auto it{block->end()}; - while (it != block->begin()) { - --it; - if constexpr (TEST_USES) { - if (it->HasUses() || it->MayHaveSideEffects()) { - continue; - } - } - it->Invalidate(); - it = block->Instructions().erase(it); - } -} - -void DeletedPhiArgElimination(IR::Program& program, std::span<const IR::Block*> dead_blocks) { - for (IR::Block* const block : program.blocks) { - for (IR::Inst& phi : *block) { - if (!IR::IsPhi(phi)) { - continue; - } - for (size_t i = 0; i < phi.NumArgs(); ++i) { - if (std::ranges::find(dead_blocks, phi.PhiBlock(i)) == dead_blocks.end()) { - continue; - } - // Phi operand at this index is an unreachable block - phi.ErasePhiOperand(i); - --i; - } - } - } -} - -void DeadBranchElimination(IR::Program& program) { - boost::container::small_vector<const IR::Block*, 3> dead_blocks; - const auto begin_it{program.syntax_list.begin()}; - for (auto node_it = begin_it; node_it != program.syntax_list.end(); ++node_it) { - if (node_it->type != IR::AbstractSyntaxNode::Type::If) { - continue; - } - IR::Inst* const cond_ref{node_it->data.if_node.cond.Inst()}; - const IR::U1 cond{cond_ref->Arg(0)}; - if (!cond.IsImmediate()) { - continue; - } - if (cond.U1()) { - continue; - } - // False immediate condition. Remove condition ref, erase the entire branch. - cond_ref->Invalidate(); - // Account for nested if-statements within the if(false) branch - u32 nested_ifs{1u}; - while (node_it->type != IR::AbstractSyntaxNode::Type::EndIf || nested_ifs > 0) { - node_it = program.syntax_list.erase(node_it); - switch (node_it->type) { - case IR::AbstractSyntaxNode::Type::If: - ++nested_ifs; - break; - case IR::AbstractSyntaxNode::Type::EndIf: - --nested_ifs; - break; - case IR::AbstractSyntaxNode::Type::Block: { - IR::Block* const block{node_it->data.block}; - DeadInstElimination<false>(block); - dead_blocks.push_back(block); - break; - } - default: - break; + for (IR::Block* const block : program.post_order_blocks) { + auto it{block->end()}; + while (it != block->begin()) { + --it; + if (!it->HasUses() && !it->MayHaveSideEffects()) { + it->Invalidate(); + it = block->Instructions().erase(it); } } - // Erase EndIf node of the if(false) branch - node_it = program.syntax_list.erase(node_it); - // Account for loop increment - --node_it; - } - if (!dead_blocks.empty()) { - DeletedPhiArgElimination(program, std::span(dead_blocks.data(), dead_blocks.size())); - } -} -} // namespace - -void DeadCodeEliminationPass(IR::Program& program) { - DeadBranchElimination(program); - for (IR::Block* const block : program.post_order_blocks) { - DeadInstElimination<true>(block); } } diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index dcb5ab158..549b81ef7 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -4,6 +4,7 @@ #pragma once #include <array> +#include <map> #include <optional> #include <vector> @@ -60,6 +61,7 @@ struct TransformFeedbackVarying { struct RuntimeInfo { std::array<AttributeType, 32> generic_input_types{}; VaryingState previous_stage_stores; + std::map<IR::Attribute, IR::Attribute> previous_stage_legacy_stores_mapping; bool convert_depth_mode{}; bool force_early_z{}; diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index cc596da4f..81097bf1a 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -5,6 +5,7 @@ #include <array> #include <bitset> +#include <map> #include "common/common_types.h" #include "shader_recompiler/frontend/ir/type.h" @@ -127,6 +128,8 @@ struct Info { VaryingState stores; VaryingState passthrough; + std::map<IR::Attribute, IR::Attribute> legacy_stores_mapping; + bool loads_indexed_attributes{}; std::array<bool, 8> stores_frag_color{}; diff --git a/src/tests/video_core/buffer_base.cpp b/src/tests/video_core/buffer_base.cpp index 71121e42a..f7236afab 100644 --- a/src/tests/video_core/buffer_base.cpp +++ b/src/tests/video_core/buffer_base.cpp @@ -44,7 +44,7 @@ public: [[nodiscard]] unsigned Count() const noexcept { unsigned count = 0; - for (const auto [index, value] : page_table) { + for (const auto& [index, value] : page_table) { count += value; } return count; diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index cb8b46edf..106991969 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -279,14 +279,8 @@ if (MSVC) else() target_compile_options(video_core PRIVATE -Werror=conversion - -Wno-error=sign-conversion - -Werror=pessimizing-move - -Werror=redundant-move - -Werror=type-limits - $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> - $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> + -Wno-sign-conversion ) endif() diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 89a9d1f5a..f9794dfe4 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -117,10 +117,15 @@ void Maxwell3D::InitializeRegisterDefaults() { shadow_state = regs; - mme_inline[MAXWELL3D_REG_INDEX(draw.end)] = true; - mme_inline[MAXWELL3D_REG_INDEX(draw.begin)] = true; - mme_inline[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; - mme_inline[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; + draw_command[MAXWELL3D_REG_INDEX(draw.end)] = true; + draw_command[MAXWELL3D_REG_INDEX(draw.begin)] = true; + draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.first)] = true; + draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; + draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true; + draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; + draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true; + draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true; + draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; } void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { @@ -208,25 +213,21 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume return ProcessCBBind(3); case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): return ProcessCBBind(4); - case MAXWELL3D_REG_INDEX(draw.end): - return DrawArrays(); case MAXWELL3D_REG_INDEX(index_buffer32_first): regs.index_buffer.count = regs.index_buffer32_first.count; regs.index_buffer.first = regs.index_buffer32_first.first; dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - return DrawArrays(); + return ProcessDraw(); case MAXWELL3D_REG_INDEX(index_buffer16_first): regs.index_buffer.count = regs.index_buffer16_first.count; regs.index_buffer.first = regs.index_buffer16_first.first; dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - return DrawArrays(); + return ProcessDraw(); case MAXWELL3D_REG_INDEX(index_buffer8_first): regs.index_buffer.count = regs.index_buffer8_first.count; regs.index_buffer.first = regs.index_buffer8_first.first; dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - // a macro calls this one over and over, should it increase instancing? - // Used by Hades and likely other Vulkan games. - return DrawArrays(); + return ProcessDraw(); case MAXWELL3D_REG_INDEX(topology_override): use_topology_override = true; return; @@ -261,14 +262,13 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) // Execute the current macro. macro_engine->Execute(macro_positions[entry], parameters); - if (mme_draw.current_mode != MMEDrawMode::Undefined) { - FlushMMEInlineDraw(); - } + + ProcessDeferredDraw(); } void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { - // It is an error to write to a register other than the current macro's ARG register before it - // has finished execution. + // It is an error to write to a register other than the current macro's ARG register before + // it has finished execution. if (executing_macro != 0) { ASSERT(method == executing_macro + 1); } @@ -283,9 +283,33 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register, increase the size of the Regs structure"); - const u32 argument = ProcessShadowRam(method, method_argument); - ProcessDirtyRegisters(method, argument); - ProcessMethodCall(method, argument, method_argument, is_last_call); + if (draw_command[method]) { + regs.reg_array[method] = method_argument; + deferred_draw_method.push_back(method); + auto u32_to_u8 = [&](const u32 argument) { + inline_index_draw_indexes.push_back(static_cast<u8>(argument & 0x000000ff)); + inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x0000ff00) >> 8)); + inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0x00ff0000) >> 16)); + inline_index_draw_indexes.push_back(static_cast<u8>((argument & 0xff000000) >> 24)); + }; + if (MAXWELL3D_REG_INDEX(draw_inline_index) == method) { + u32_to_u8(method_argument); + } else if (MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method) { + u32_to_u8(regs.inline_index_2x16.even); + u32_to_u8(regs.inline_index_2x16.odd); + } else if (MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) { + u32_to_u8(regs.inline_index_4x8.index0); + u32_to_u8(regs.inline_index_4x8.index1); + u32_to_u8(regs.inline_index_4x8.index2); + u32_to_u8(regs.inline_index_4x8.index3); + } + } else { + ProcessDeferredDraw(); + + const u32 argument = ProcessShadowRam(method, method_argument); + ProcessDirtyRegisters(method, argument); + ProcessMethodCall(method, argument, method_argument, is_last_call); + } } void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, @@ -326,55 +350,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, } } -void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) { - if (mme_draw.current_mode == MMEDrawMode::Undefined) { - if (mme_draw.gl_begin_consume) { - mme_draw.current_mode = expected_mode; - mme_draw.current_count = count; - mme_draw.instance_count = 1; - mme_draw.gl_begin_consume = false; - mme_draw.gl_end_count = 0; - } - return; - } else { - if (mme_draw.current_mode == expected_mode && count == mme_draw.current_count && - mme_draw.instance_mode && mme_draw.gl_begin_consume) { - mme_draw.instance_count++; - mme_draw.gl_begin_consume = false; - return; - } else { - FlushMMEInlineDraw(); - } - } - // Tail call in case it needs to retry. - StepInstance(expected_mode, count); -} - -void Maxwell3D::CallMethodFromMME(u32 method, u32 method_argument) { - if (mme_inline[method]) { - regs.reg_array[method] = method_argument; - if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count) || - method == MAXWELL3D_REG_INDEX(index_buffer.count)) { - const MMEDrawMode expected_mode = method == MAXWELL3D_REG_INDEX(vertex_buffer.count) - ? MMEDrawMode::Array - : MMEDrawMode::Indexed; - StepInstance(expected_mode, method_argument); - } else if (method == MAXWELL3D_REG_INDEX(draw.begin)) { - mme_draw.instance_mode = - (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || - (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged); - mme_draw.gl_begin_consume = true; - } else { - mme_draw.gl_end_count++; - } - } else { - if (mme_draw.current_mode != MMEDrawMode::Undefined) { - FlushMMEInlineDraw(); - } - CallMethod(method, method_argument, true); - } -} - void Maxwell3D::ProcessTopologyOverride() { using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; @@ -404,41 +379,6 @@ void Maxwell3D::ProcessTopologyOverride() { } } -void Maxwell3D::FlushMMEInlineDraw() { - LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), - regs.vertex_buffer.count); - ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); - ASSERT(mme_draw.instance_count == mme_draw.gl_end_count); - - // Both instance configuration registers can not be set at the same time. - ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || - regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, - "Illegal combination of instancing parameters"); - - ProcessTopologyOverride(); - - const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed; - if (ShouldExecute()) { - rasterizer->Draw(is_indexed, true); - } - - // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if - // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - - // it's possible that it is incorrect and that there is some other register used to specify the - // drawing mode. - if (is_indexed) { - regs.index_buffer.count = 0; - } else { - regs.vertex_buffer.count = 0; - } - mme_draw.current_mode = MMEDrawMode::Undefined; - mme_draw.current_count = 0; - mme_draw.instance_count = 0; - mme_draw.instance_mode = false; - mme_draw.gl_begin_consume = false; - mme_draw.gl_end_count = 0; -} - void Maxwell3D::ProcessMacroUpload(u32 data) { macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); } @@ -473,9 +413,7 @@ void Maxwell3D::ProcessQueryGet() { switch (regs.report_semaphore.query.operation) { case Regs::ReportSemaphore::Operation::Release: - if (regs.report_semaphore.query.release == - Regs::ReportSemaphore::Release::AfterAllPreceedingWrites || - regs.report_semaphore.query.short_query != 0) { + if (regs.report_semaphore.query.short_query != 0) { const GPUVAddr sequence_address{regs.report_semaphore.Address()}; const u32 payload = regs.report_semaphore.payload; std::function<void()> operation([this, sequence_address, payload] { @@ -489,11 +427,10 @@ void Maxwell3D::ProcessQueryGet() { }; const GPUVAddr sequence_address{regs.report_semaphore.Address()}; const u32 payload = regs.report_semaphore.payload; - std::function<void()> operation([this, sequence_address, payload] { + [this, sequence_address, payload] { memory_manager.Write<u64>(sequence_address + sizeof(u64), system.GPU().GetTicks()); memory_manager.Write<u64>(sequence_address, payload); - }); - rasterizer->SyncOperation(std::move(operation)); + }(); } break; case Regs::ReportSemaphore::Operation::Acquire: @@ -569,47 +506,11 @@ void Maxwell3D::ProcessCounterReset() { void Maxwell3D::ProcessSyncPoint() { const u32 sync_point = regs.sync_info.sync_point.Value(); - const auto condition = regs.sync_info.condition.Value(); - [[maybe_unused]] const u32 cache_flush = regs.sync_info.clean_l2.Value(); - if (condition == Regs::SyncInfo::Condition::RopWritesDone) { - rasterizer->SignalSyncPoint(sync_point); - } -} - -void Maxwell3D::DrawArrays() { - LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), - regs.vertex_buffer.count); - ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); - - // Both instance configuration registers can not be set at the same time. - ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || - regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, - "Illegal combination of instancing parameters"); - - ProcessTopologyOverride(); - - if (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) { - // Increment the current instance *before* drawing. - state.current_instance++; - } else if (regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged) { - // Reset the current instance to 0. - state.current_instance = 0; - } - - const bool is_indexed{regs.index_buffer.count && !regs.vertex_buffer.count}; - if (ShouldExecute()) { - rasterizer->Draw(is_indexed, false); - } - - // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if - // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - - // it's possible that it is incorrect and that there is some other register used to specify the - // drawing mode. - if (is_indexed) { - regs.index_buffer.count = 0; - } else { - regs.vertex_buffer.count = 0; + const u32 cache_flush = regs.sync_info.clean_l2.Value(); + if (cache_flush != 0) { + rasterizer->InvalidateGPUCache(); } + rasterizer->SignalSyncPoint(sync_point); } std::optional<u64> Maxwell3D::GetQueryResult() { @@ -694,4 +595,90 @@ void Maxwell3D::ProcessClearBuffers() { rasterizer->Clear(); } +void Maxwell3D::ProcessDraw(u32 instance_count) { + LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), + regs.vertex_buffer.count); + + ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); + + // Both instance configuration registers can not be set at the same time. + ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || + regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, + "Illegal combination of instancing parameters"); + + ProcessTopologyOverride(); + + const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count; + if (ShouldExecute()) { + rasterizer->Draw(is_indexed, instance_count); + } + + if (is_indexed) { + regs.index_buffer.count = 0; + } else { + regs.vertex_buffer.count = 0; + } +} + +void Maxwell3D::ProcessDeferredDraw() { + if (deferred_draw_method.empty()) { + return; + } + + enum class DrawMode { + Undefined, + General, + Instance, + }; + DrawMode draw_mode{DrawMode::Undefined}; + u32 instance_count = 1; + + u32 index = 0; + u32 method = 0; + u32 method_count = static_cast<u32>(deferred_draw_method.size()); + for (; index < method_count && + (method = deferred_draw_method[index]) != MAXWELL3D_REG_INDEX(draw.begin); + ++index) + ; + + if (MAXWELL3D_REG_INDEX(draw.begin) != method) { + return; + } + + // The minimum number of methods for drawing must be greater than or equal to + // 3[draw.begin->vertex(index)count(first)->draw.end] to avoid errors in index mode drawing + if ((method_count - index) < 3) { + return; + } + draw_mode = (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || + (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) + ? DrawMode::Instance + : DrawMode::General; + + // Drawing will only begin with draw.begin or index_buffer method, other methods directly + // clear + if (draw_mode == DrawMode::Undefined) { + deferred_draw_method.clear(); + return; + } + + if (draw_mode == DrawMode::Instance) { + ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error"); + instance_count = static_cast<u32>(method_count - index) / 4; + } else { + method = deferred_draw_method[index + 1]; + if (MAXWELL3D_REG_INDEX(draw_inline_index) == method || + MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method || + MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) { + regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4); + regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; + } + } + + ProcessDraw(instance_count); + + deferred_draw_method.clear(); + inline_index_draw_indexes.clear(); +} + } // namespace Tegra::Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 75e3b868d..a948fcb14 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -1739,14 +1739,11 @@ public: Footprint_1x1_Virtual = 2, }; - struct InlineIndex4x8Align { + struct InlineIndex4x8 { union { BitField<0, 30, u32> count; BitField<30, 2, u32> start; }; - }; - - struct InlineIndex4x8Index { union { BitField<0, 8, u32> index0; BitField<8, 8, u32> index1; @@ -2836,8 +2833,7 @@ public: u32 depth_write_enabled; ///< 0x12E8 u32 alpha_test_enabled; ///< 0x12EC INSERT_PADDING_BYTES_NOINIT(0x10); - InlineIndex4x8Align inline_index_4x8_align; ///< 0x1300 - InlineIndex4x8Index inline_index_4x8_index; ///< 0x1304 + InlineIndex4x8 inline_index_4x8; ///< 0x1300 D3DCullMode d3d_cull_mode; ///< 0x1308 ComparisonOp depth_test_func; ///< 0x130C f32 alpha_test_ref; ///< 0x1310 @@ -3048,8 +3044,6 @@ public: }; std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages; - - u32 current_instance = 0; ///< Current instance to be used to simulate instanced rendering. }; State state{}; @@ -3064,11 +3058,6 @@ public: void CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32 methods_pending) override; - /// Write the value to the register identified by method. - void CallMethodFromMME(u32 method, u32 method_argument); - - void FlushMMEInlineDraw(); - bool ShouldExecute() const { return execute_on; } @@ -3081,21 +3070,6 @@ public: return *rasterizer; } - enum class MMEDrawMode : u32 { - Undefined, - Array, - Indexed, - }; - - struct MMEDrawState { - MMEDrawMode current_mode{MMEDrawMode::Undefined}; - u32 current_count{}; - u32 instance_count{}; - bool instance_mode{}; - bool gl_begin_consume{}; - u32 gl_end_count{}; - } mme_draw; - struct DirtyState { using Flags = std::bitset<std::numeric_limits<u8>::max()>; using Table = std::array<u8, Regs::NUM_REGS>; @@ -3105,6 +3079,8 @@ public: Tables tables{}; } dirty; + std::vector<u8> inline_index_draw_indexes; + private: void InitializeRegisterDefaults(); @@ -3164,14 +3140,12 @@ private: /// Handles a write to the CB_BIND register. void ProcessCBBind(size_t stage_index); - /// Handles a write to the VERTEX_END_GL register, triggering a draw. - void DrawArrays(); - /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) void ProcessTopologyOverride(); - // Handles a instance drawcall from MME - void StepInstance(MMEDrawMode expected_mode, u32 count); + void ProcessDraw(u32 instance_count = 1); + + void ProcessDeferredDraw(); /// Returns a query's value or an empty object if the value will be deferred through a cache. std::optional<u64> GetQueryResult(); @@ -3184,8 +3158,6 @@ private: /// Start offsets of each macro in macro_memory std::array<u32, 0x80> macro_positions{}; - std::array<bool, Regs::NUM_REGS> mme_inline{}; - /// Macro method that is currently being executed / being fed parameters. u32 executing_macro = 0; /// Parameters that have been submitted to the macro call so far. @@ -3198,6 +3170,9 @@ private: bool execute_on{true}; bool use_topology_override{false}; + + std::array<bool, Regs::NUM_REGS> draw_command{}; + std::vector<u32> deferred_draw_method; }; #define ASSERT_REG_POSITION(field_name, position) \ @@ -3402,8 +3377,7 @@ ASSERT_REG_POSITION(alpha_to_coverage_dither, 0x12E0); ASSERT_REG_POSITION(blend_per_target_enabled, 0x12E4); ASSERT_REG_POSITION(depth_write_enabled, 0x12E8); ASSERT_REG_POSITION(alpha_test_enabled, 0x12EC); -ASSERT_REG_POSITION(inline_index_4x8_align, 0x1300); -ASSERT_REG_POSITION(inline_index_4x8_index, 0x1304); +ASSERT_REG_POSITION(inline_index_4x8, 0x1300); ASSERT_REG_POSITION(d3d_cull_mode, 0x1308); ASSERT_REG_POSITION(depth_test_func, 0x130C); ASSERT_REG_POSITION(alpha_test_ref, 0x1310); diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index cca890792..3977bb0fb 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -75,11 +75,10 @@ void Puller::ProcessSemaphoreTriggerMethod() { if (op == GpuSemaphoreOperation::WriteLong) { const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()}; const u32 payload = regs.semaphore_sequence; - std::function<void()> operation([this, sequence_address, payload] { + [this, sequence_address, payload] { memory_manager.Write<u64>(sequence_address + sizeof(u64), gpu.GetTicks()); memory_manager.Write<u64>(sequence_address, payload); - }); - rasterizer->SignalFence(std::move(operation)); + }(); } else { do { const u32 word{memory_manager.Read<u32>(regs.semaphore_address.SemaphoreAddress())}; diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 8a8adbb42..f896591bf 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -22,35 +22,29 @@ void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& maxwell3d.regs.draw.topology.Assign( static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff)); maxwell3d.regs.global_base_instance_index = parameters[5]; - maxwell3d.mme_draw.instance_count = instance_count; maxwell3d.regs.global_base_vertex_index = parameters[3]; maxwell3d.regs.index_buffer.count = parameters[1]; maxwell3d.regs.index_buffer.first = parameters[4]; if (maxwell3d.ShouldExecute()) { - maxwell3d.Rasterizer().Draw(true, true); + maxwell3d.Rasterizer().Draw(true, instance_count); } maxwell3d.regs.index_buffer.count = 0; - maxwell3d.mme_draw.instance_count = 0; - maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; } void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { - const u32 count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); + const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); maxwell3d.regs.vertex_buffer.first = parameters[3]; maxwell3d.regs.vertex_buffer.count = parameters[1]; maxwell3d.regs.global_base_instance_index = parameters[4]; maxwell3d.regs.draw.topology.Assign( static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); - maxwell3d.mme_draw.instance_count = count; if (maxwell3d.ShouldExecute()) { - maxwell3d.Rasterizer().Draw(false, true); + maxwell3d.Rasterizer().Draw(false, instance_count); } maxwell3d.regs.vertex_buffer.count = 0; - maxwell3d.mme_draw.instance_count = 0; - maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; } void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { @@ -63,24 +57,21 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; maxwell3d.regs.global_base_vertex_index = element_base; maxwell3d.regs.global_base_instance_index = base_instance; - maxwell3d.mme_draw.instance_count = instance_count; - maxwell3d.CallMethodFromMME(0x8e3, 0x640); - maxwell3d.CallMethodFromMME(0x8e4, element_base); - maxwell3d.CallMethodFromMME(0x8e5, base_instance); + maxwell3d.CallMethod(0x8e3, 0x640, true); + maxwell3d.CallMethod(0x8e4, element_base, true); + maxwell3d.CallMethod(0x8e5, base_instance, true); maxwell3d.regs.draw.topology.Assign( static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); if (maxwell3d.ShouldExecute()) { - maxwell3d.Rasterizer().Draw(true, true); + maxwell3d.Rasterizer().Draw(true, instance_count); } maxwell3d.regs.vertex_id_base = 0x0; maxwell3d.regs.index_buffer.count = 0; maxwell3d.regs.global_base_vertex_index = 0x0; maxwell3d.regs.global_base_instance_index = 0x0; - maxwell3d.mme_draw.instance_count = 0; - maxwell3d.CallMethodFromMME(0x8e3, 0x640); - maxwell3d.CallMethodFromMME(0x8e4, 0x0); - maxwell3d.CallMethodFromMME(0x8e5, 0x0); - maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; + maxwell3d.CallMethod(0x8e3, 0x640, true); + maxwell3d.CallMethod(0x8e4, 0x0, true); + maxwell3d.CallMethod(0x8e5, 0x0, true); } // Multidraw Indirect @@ -91,11 +82,9 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& maxwell3d.regs.index_buffer.count = 0; maxwell3d.regs.global_base_vertex_index = 0x0; maxwell3d.regs.global_base_instance_index = 0x0; - maxwell3d.mme_draw.instance_count = 0; - maxwell3d.CallMethodFromMME(0x8e3, 0x640); - maxwell3d.CallMethodFromMME(0x8e4, 0x0); - maxwell3d.CallMethodFromMME(0x8e5, 0x0); - maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; + maxwell3d.CallMethod(0x8e3, 0x640, true); + maxwell3d.CallMethod(0x8e4, 0x0, true); + maxwell3d.CallMethod(0x8e5, 0x0, true); maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; }); const u32 start_indirect = parameters[0]; @@ -127,15 +116,13 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& maxwell3d.regs.index_buffer.count = num_vertices; maxwell3d.regs.global_base_vertex_index = base_vertex; maxwell3d.regs.global_base_instance_index = base_instance; - maxwell3d.mme_draw.instance_count = instance_count; - maxwell3d.CallMethodFromMME(0x8e3, 0x640); - maxwell3d.CallMethodFromMME(0x8e4, base_vertex); - maxwell3d.CallMethodFromMME(0x8e5, base_instance); + maxwell3d.CallMethod(0x8e3, 0x640, true); + maxwell3d.CallMethod(0x8e4, base_vertex, true); + maxwell3d.CallMethod(0x8e5, base_instance, true); maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; if (maxwell3d.ShouldExecute()) { - maxwell3d.Rasterizer().Draw(true, true); + maxwell3d.Rasterizer().Draw(true, instance_count); } - maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; } } diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index f670b1bca..c0d32c112 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp @@ -335,7 +335,7 @@ void MacroInterpreterImpl::SetMethodAddress(u32 address) { } void MacroInterpreterImpl::Send(u32 value) { - maxwell3d.CallMethodFromMME(method_address.address, value); + maxwell3d.CallMethod(method_address.address, value, true); // Increment the method address by the method increment. method_address.address.Assign(method_address.address.Value() + method_address.increment.Value()); diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index a302a9603..25c1ce798 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp @@ -346,7 +346,7 @@ void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) { } void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { - maxwell3d->CallMethodFromMME(method_address.address, value); + maxwell3d->CallMethod(method_address.address, value, true); } void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index d07b21bd6..384350dbd 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -133,7 +133,7 @@ inline void MemoryManager::SetBigPageContinous(size_t big_page_index, bool value template <MemoryManager::EntryType entry_type> GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size, PTEKind kind) { - u64 remaining_size{size}; + [[maybe_unused]] u64 remaining_size{size}; if constexpr (entry_type == EntryType::Mapped) { page_table.ReserveRange(gpu_addr, size); } @@ -159,7 +159,7 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cp template <MemoryManager::EntryType entry_type> GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] VAddr cpu_addr, size_t size, PTEKind kind) { - u64 remaining_size{size}; + [[maybe_unused]] u64 remaining_size{size}; for (u64 offset{}; offset < size; offset += big_page_size) { const GPUVAddr current_gpu_addr = gpu_addr + offset; [[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index d2d40884c..1cbfef090 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -40,7 +40,7 @@ public: virtual ~RasterizerInterface() = default; /// Dispatches a draw invocation - virtual void Draw(bool is_indexed, bool is_instanced) = 0; + virtual void Draw(bool is_indexed, u32 instance_count) = 0; /// Clear the current framebuffer virtual void Clear() = 0; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e5c09a969..1590b21de 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -205,7 +205,7 @@ void RasterizerOpenGL::Clear() { ++num_queued_commands; } -void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { +void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { MICROPROFILE_SCOPE(OpenGL_Drawing); SCOPE_EXIT({ gpu.TickWork(); }); @@ -222,14 +222,15 @@ void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); + BindInlineIndexBuffer(); + SyncState(); const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); BeginTransformFeedback(pipeline, primitive_mode); const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index); - const GLsizei num_instances = - static_cast<GLsizei>(is_instanced ? maxwell3d->mme_draw.instance_count : 1); + const GLsizei num_instances = static_cast<GLsizei>(instance_count); if (is_indexed) { const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index); const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count); @@ -1129,6 +1130,16 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) { query_cache.EraseChannel(channel_id); } +void RasterizerOpenGL::BindInlineIndexBuffer() { + if (maxwell3d->inline_index_draw_indexes.empty()) { + return; + } + const auto data_count = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size()); + auto buffer = Buffer(buffer_cache_runtime, *this, 0, data_count); + buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes); + buffer_cache_runtime.BindIndexBuffer(buffer, 0, data_count); +} + AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {} bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 45131b785..793e0d608 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -68,7 +68,7 @@ public: StateTracker& state_tracker_); ~RasterizerOpenGL() override; - void Draw(bool is_indexed, bool is_instanced) override; + void Draw(bool is_indexed, u32 instance_count) override; void Clear() override; void DispatchCompute() override; void ResetCounter(VideoCore::QueryType type) override; @@ -199,6 +199,8 @@ private: /// End a transform feedback void EndTransformFeedback(); + void BindInlineIndexBuffer(); + Tegra::GPU& gpu; const Device& device; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 609f0a772..e94cfdb1a 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -63,6 +63,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, Shader::RuntimeInfo info; if (previous_program) { info.previous_stage_stores = previous_program->info.stores; + info.previous_stage_legacy_stores_mapping = previous_program->info.legacy_stores_mapping; } else { // Mark all stores as available for vertex shaders info.previous_stage_stores.mask.set(); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 20f1d6584..13d5a1f67 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -134,6 +134,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program Shader::RuntimeInfo info; if (previous_program) { info.previous_stage_stores = previous_program->info.stores; + info.previous_stage_legacy_stores_mapping = previous_program->info.legacy_stores_mapping; if (previous_program->is_geometry_passthrough) { info.previous_stage_stores.mask |= previous_program->info.passthrough.mask; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 6d5ea99dd..d94dbf873 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -127,11 +127,10 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3 return scissor; } -DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_instanced, - bool is_indexed) { +DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_indexed) { DrawParams params{ .base_instance = regs.global_base_instance_index, - .num_instances = is_instanced ? num_instances : 1, + .num_instances = num_instances, .base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first, .num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count, .first_index = is_indexed ? regs.index_buffer.first : 0, @@ -175,7 +174,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra RasterizerVulkan::~RasterizerVulkan() = default; -void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { +void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { MICROPROFILE_SCOPE(Vulkan_Drawing); SCOPE_EXIT({ gpu.TickWork(); }); @@ -192,13 +191,15 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); + BindInlineIndexBuffer(); + BeginTransformFeedback(); UpdateDynamicStates(); const auto& regs{maxwell3d->regs}; - const u32 num_instances{maxwell3d->mme_draw.instance_count}; - const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_instanced, is_indexed)}; + const u32 num_instances{instance_count}; + const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_indexed)}; scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { if (draw_params.is_indexed) { cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, @@ -302,14 +303,19 @@ void RasterizerVulkan::Clear() { } } - scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { - const VkClearAttachment attachment{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .colorAttachment = color_attachment, - .clearValue = clear_value, - }; - cmdbuf.ClearAttachments(attachment, clear_rect); - }); + if (regs.clear_surface.R && regs.clear_surface.G && regs.clear_surface.B && + regs.clear_surface.A) { + scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { + const VkClearAttachment attachment{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .colorAttachment = color_attachment, + .clearValue = clear_value, + }; + cmdbuf.ClearAttachments(attachment, clear_rect); + }); + } else { + UNIMPLEMENTED_MSG("Unimplemented Clear only the specified channel"); + } } if (!use_depth && !use_stencil) { @@ -1007,4 +1013,17 @@ void RasterizerVulkan::ReleaseChannel(s32 channel_id) { query_cache.EraseChannel(channel_id); } +void RasterizerVulkan::BindInlineIndexBuffer() { + if (maxwell3d->inline_index_draw_indexes.empty()) { + return; + } + const auto data_count = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size()); + auto buffer = buffer_cache_runtime.UploadStagingBuffer(data_count); + std::memcpy(buffer.mapped_span.data(), maxwell3d->inline_index_draw_indexes.data(), data_count); + buffer_cache_runtime.BindIndexBuffer( + maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format, + maxwell3d->regs.index_buffer.first, maxwell3d->regs.index_buffer.count, buffer.buffer, + static_cast<u32>(buffer.offset), data_count); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index e7cdeaed1..b0bc306f5 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -64,7 +64,7 @@ public: StateTracker& state_tracker_, Scheduler& scheduler_); ~RasterizerVulkan() override; - void Draw(bool is_indexed, bool is_instanced) override; + void Draw(bool is_indexed, u32 instance_count) override; void Clear() override; void DispatchCompute() override; void ResetCounter(VideoCore::QueryType type) override; @@ -141,6 +141,8 @@ private: void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); + void BindInlineIndexBuffer(); + Tegra::GPU& gpu; ScreenInfo& screen_info; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index c04aad08f..929216749 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -144,7 +144,6 @@ private: using FuncType = TypedCommand<T>; static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large"); - recorded_counts++; command_offset = Common::AlignUp(command_offset, alignof(FuncType)); if (command_offset > sizeof(data) - sizeof(FuncType)) { return false; @@ -166,7 +165,7 @@ private: } bool Empty() const { - return recorded_counts == 0; + return command_offset == 0; } bool HasSubmit() const { @@ -177,7 +176,6 @@ private: Command* first = nullptr; Command* last = nullptr; - size_t recorded_counts = 0; size_t command_offset = 0; bool submit = false; alignas(std::max_align_t) std::array<u8, 0x8000> data{}; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 20e56b0d1..853b80d8a 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1787,17 +1787,17 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, const auto& resolution = runtime.resolution; - u32 width = 0; - u32 height = 0; + u32 width = std::numeric_limits<u32>::max(); + u32 height = std::numeric_limits<u32>::max(); for (size_t index = 0; index < NUM_RT; ++index) { const ImageView* const color_buffer = color_buffers[index]; if (!color_buffer) { renderpass_key.color_formats[index] = PixelFormat::Invalid; continue; } - width = std::max(width, is_rescaled ? resolution.ScaleUp(color_buffer->size.width) + width = std::min(width, is_rescaled ? resolution.ScaleUp(color_buffer->size.width) : color_buffer->size.width); - height = std::max(height, is_rescaled ? resolution.ScaleUp(color_buffer->size.height) + height = std::min(height, is_rescaled ? resolution.ScaleUp(color_buffer->size.height) : color_buffer->size.height); attachments.push_back(color_buffer->RenderTarget()); renderpass_key.color_formats[index] = color_buffer->format; @@ -1809,9 +1809,9 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime, } const size_t num_colors = attachments.size(); if (depth_buffer) { - width = std::max(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width) + width = std::min(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width) : depth_buffer->size.width); - height = std::max(height, is_rescaled ? resolution.ScaleUp(depth_buffer->size.height) + height = std::min(height, is_rescaled ? resolution.ScaleUp(depth_buffer->size.height) : depth_buffer->size.height); attachments.push_back(depth_buffer->RenderTarget()); renderpass_key.depth_format = depth_buffer->format; diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp index ad935d386..08aa8ca33 100644 --- a/src/video_core/texture_cache/format_lookup_table.cpp +++ b/src/video_core/texture_cache/format_lookup_table.cpp @@ -150,6 +150,8 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red, return PixelFormat::D24_UNORM_S8_UINT; case Hash(TextureFormat::D32S8, FLOAT, UINT, UNORM, UNORM, LINEAR): return PixelFormat::D32_FLOAT_S8_UINT; + case Hash(TextureFormat::R32_B24G8, FLOAT, UINT, UNORM, UNORM, LINEAR): + return PixelFormat::D32_FLOAT_S8_UINT; case Hash(TextureFormat::BC1_RGBA, UNORM, LINEAR): return PixelFormat::BC1_RGBA_UNORM; case Hash(TextureFormat::BC1_RGBA, UNORM, SRGB): diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 0e0fd410f..8ef75fe73 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -442,7 +442,7 @@ void TextureCache<P>::WriteMemory(VAddr cpu_addr, size_t size) { template <class P> void TextureCache<P>::DownloadMemory(VAddr cpu_addr, size_t size) { std::vector<ImageId> images; - ForEachImageInRegion(cpu_addr, size, [this, &images](ImageId image_id, ImageBase& image) { + ForEachImageInRegion(cpu_addr, size, [&images](ImageId image_id, ImageBase& image) { if (!image.IsSafeDownload()) { return; } @@ -1502,9 +1502,9 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) { image.flags &= ~ImageFlagBits::BadOverlap; lru_cache.Free(image.lru_index); const auto& clear_page_table = - [this, image_id](u64 page, - std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& - selected_page_table) { + [image_id](u64 page, + std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& + selected_page_table) { const auto page_it = selected_page_table.find(page); if (page_it == selected_page_table.end()) { ASSERT_MSG(false, "Unregistering unregistered page=0x{:x}", page << YUZU_PAGEBITS); diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp index 15b9d4182..69a32819a 100644 --- a/src/video_core/textures/astc.cpp +++ b/src/video_core/textures/astc.cpp @@ -1661,8 +1661,8 @@ void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, for (u32 z = 0; z < depth; ++z) { const u32 depth_offset = z * height * width * 4; for (u32 y_index = 0; y_index < rows; ++y_index) { - auto decompress_stride = [data, width, height, depth, block_width, block_height, output, - rows, cols, z, depth_offset, y_index] { + auto decompress_stride = [data, width, height, block_width, block_height, output, rows, + cols, z, depth_offset, y_index] { const u32 y = y_index * block_height; for (u32 x_index = 0; x_index < cols; ++x_index) { const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index; diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 52d067a2d..fd1a4b987 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -21,7 +21,7 @@ constexpr u32 pdep(u32 value) { u32 m = mask; for (u32 bit = 1; m; bit += bit) { if (value & bit) - result |= m & -m; + result |= m & (~m + 1); m &= m - 1; } return result; diff --git a/src/yuzu/applets/qt_controller.ui b/src/yuzu/applets/qt_controller.ui index c8cb6bcf3..f5eccba70 100644 --- a/src/yuzu/applets/qt_controller.ui +++ b/src/yuzu/applets/qt_controller.ui @@ -2300,7 +2300,7 @@ <item> <widget class="QRadioButton" name="radioUndocked"> <property name="text"> - <string>Undocked</string> + <string>Handheld</string> </property> </widget> </item> diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 195074bf2..927dd1069 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -819,6 +819,7 @@ void Config::ReadUIGamelistValues() { qt_config->beginGroup(QStringLiteral("UIGameList")); ReadBasicSetting(UISettings::values.show_add_ons); + ReadBasicSetting(UISettings::values.show_compat); ReadBasicSetting(UISettings::values.game_icon_size); ReadBasicSetting(UISettings::values.folder_icon_size); ReadBasicSetting(UISettings::values.row_1_text_id); @@ -1414,6 +1415,7 @@ void Config::SaveUIGamelistValues() { qt_config->beginGroup(QStringLiteral("UIGameList")); WriteBasicSetting(UISettings::values.show_add_ons); + WriteBasicSetting(UISettings::values.show_compat); WriteBasicSetting(UISettings::values.game_icon_size); WriteBasicSetting(UISettings::values.folder_icon_size); WriteBasicSetting(UISettings::values.row_1_text_id); diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 48f71b53c..92e6da6ee 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -72,6 +72,7 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent) // Force game list reload if any of the relevant settings are changed. connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); + connect(ui->show_compat, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ConfigureUi::RequestGameListUpdate); connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), @@ -109,6 +110,7 @@ void ConfigureUi::ApplyConfiguration() { UISettings::values.theme = ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); + UISettings::values.show_compat = ui->show_compat->isChecked(); UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt(); UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt(); UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); @@ -129,6 +131,7 @@ void ConfigureUi::SetConfiguration() { ui->language_combobox->setCurrentIndex( ui->language_combobox->findData(UISettings::values.language)); ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); + ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); ui->game_icon_size_combobox->setCurrentIndex( ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue())); ui->folder_icon_size_combobox->setCurrentIndex( diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui index a50df7f6f..f0b719ba3 100644 --- a/src/yuzu/configuration/configure_ui.ui +++ b/src/yuzu/configuration/configure_ui.ui @@ -77,6 +77,13 @@ <item> <layout class="QVBoxLayout" name="GeneralVerticalLayout"> <item> + <widget class="QCheckBox" name="show_compat"> + <property name="text"> + <string>Show Compatibility List</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="show_add_ons"> <property name="text"> <string>Show Add-Ons Column</string> diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index b127badc2..d6adfca16 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -335,6 +335,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid RetranslateUI(); tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons); + tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat); item_model->setSortRole(GameListItemPath::SortRole); connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons); @@ -786,6 +787,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) { // Update the columns in case UISettings has changed tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons); + tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat); // Delete any rows that might already exist if we're repopulating item_model->removeRows(0, item_model->rowCount()); diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 74d49dbd4..e670acc30 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -55,7 +55,6 @@ <addaction name="separator"/> <addaction name="menu_recent_files"/> <addaction name="separator"/> - <addaction name="separator"/> <addaction name="action_Load_Amiibo"/> <addaction name="separator"/> <addaction name="action_Open_yuzu_Folder"/> diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index ae2738ad4..285bb150d 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -268,7 +268,7 @@ bool MultiplayerState::OnCloseRoom() { return true; } // Save ban list - UISettings::values.multiplayer_ban_list = std::move(room->GetBanList()); + UISettings::values.multiplayer_ban_list = room->GetBanList(); room->Destroy(); announce_multiplayer_session->Stop(); diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index fc2693f9d..6a91212e2 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp @@ -49,7 +49,7 @@ bool CheckEnvVars(bool* is_child) { *is_child = true; return false; } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) { - std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n", + std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", IS_CHILD_ENV_VAR, GetLastError()); return true; } @@ -62,7 +62,7 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka // Set the startup variable for child processes const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); if (!env_var_set) { - std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n", + std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", STARTUP_CHECK_ENV_VAR, GetLastError()); return false; } @@ -81,22 +81,22 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka DWORD exit_code = STILL_ACTIVE; const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); if (err == 0) { - std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError()); + std::fprintf(stderr, "GetExitCodeProcess failed with error %lu\n", GetLastError()); } // Vulkan is broken if the child crashed (return value is not zero) *has_broken_vulkan = (exit_code != 0); if (CloseHandle(process_info.hProcess) == 0) { - std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); + std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); } if (CloseHandle(process_info.hThread) == 0) { - std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); + std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); } } if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { - std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %d\n", + std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %lu\n", STARTUP_CHECK_ENV_VAR, GetLastError()); } @@ -135,7 +135,8 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) { startup_info.cb = sizeof(startup_info); char p_name[255]; - std::strncpy(p_name, arg0, 255); + std::strncpy(p_name, arg0, 254); + p_name[254] = '\0'; const bool process_created = CreateProcessA(nullptr, // lpApplicationName p_name, // lpCommandLine @@ -149,7 +150,7 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) { pi // lpProcessInformation ); if (!process_created) { - std::fprintf(stderr, "CreateProcessA failed with error %d\n", GetLastError()); + std::fprintf(stderr, "CreateProcessA failed with error %lu\n", GetLastError()); return false; } diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 753797efc..4f5b2a99d 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -129,6 +129,9 @@ struct Values { Settings::Setting<bool> favorites_expanded{true, "favorites_expanded"}; QVector<u64> favorited_ids; + // Compatibility List + Settings::Setting<bool> show_compat{false, "show_compat"}; + bool configuration_applied; bool reset_to_defaults; Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"}; |