From d241867c7b443e7de6bc3c93f6eccadd9d91fd24 Mon Sep 17 00:00:00 2001 From: "Daniel R." <47796739+polybiusproxy@users.noreply.github.com> Date: Sat, 24 Aug 2024 23:18:04 +0200 Subject: [PATCH 01/23] shader_recompiler/frontend: implement V_NOP --- src/shader_recompiler/frontend/translate/vector_alu.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index 1bbc3c162..1b49999a6 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -305,6 +305,9 @@ void Translator::EmitVectorAlu(const GcnInst& inst) { return V_MBCNT_U32_B32(true, inst); case Opcode::V_MBCNT_HI_U32_B32: return V_MBCNT_U32_B32(false, inst); + + case Opcode::V_NOP: + return; default: LogMissingOpcode(inst); } From 5691838eca048826edd64a3d11fca9141160609d Mon Sep 17 00:00:00 2001 From: Daniel R <47796739+polybiusproxy@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:17:24 +0200 Subject: [PATCH 02/23] shader_recompiler/frontend: fix V_NOP instruction format --- src/shader_recompiler/frontend/format.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shader_recompiler/frontend/format.cpp b/src/shader_recompiler/frontend/format.cpp index 8df3ac364..9c4be07b9 100644 --- a/src/shader_recompiler/frontend/format.cpp +++ b/src/shader_recompiler/frontend/format.cpp @@ -1786,8 +1786,7 @@ constexpr std::array InstructionFormatVOP3 = {{ constexpr std::array InstructionFormatVOP1 = {{ // 0 = V_NOP - {InstClass::VectorMisc, InstCategory::VectorALU, 0, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMisc, InstCategory::VectorALU, 0, 1, ScalarType::Any, ScalarType::Any}, // 1 = V_MOV_B32 {InstClass::VectorRegMov, InstCategory::VectorALU, 1, 1, ScalarType::Uint32, ScalarType::Uint32}, From ba140b968063eac7f10524b251a1ffe1f73bc279 Mon Sep 17 00:00:00 2001 From: Daniel R <47796739+polybiusproxy@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:17:59 +0200 Subject: [PATCH 03/23] shader_recompiler/frontend: add information on instruction format assert --- src/shader_recompiler/frontend/decode.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shader_recompiler/frontend/decode.cpp b/src/shader_recompiler/frontend/decode.cpp index b5c02d747..dda984d57 100644 --- a/src/shader_recompiler/frontend/decode.cpp +++ b/src/shader_recompiler/frontend/decode.cpp @@ -5,6 +5,10 @@ #include "common/assert.h" #include "shader_recompiler/frontend/decode.h" +#define MAGIC_ENUM_RANGE_MIN 0 +#define MAGIC_ENUM_RANGE_MAX 1515 +#include "magic_enum.hpp" + namespace Shader::Gcn { namespace bit { @@ -253,7 +257,9 @@ void GcnDecodeContext::updateInstructionMeta(InstEncoding encoding) { ASSERT_MSG(instFormat.src_type != ScalarType::Undefined && instFormat.dst_type != ScalarType::Undefined, - "TODO: Instruction format table not complete, please fix it manually."); + "Instruction format table incomplete for opcode {} ({}, encoding = {})", + magic_enum::enum_name(m_instruction.opcode), u32(m_instruction.opcode), + magic_enum::enum_name(encoding)); m_instruction.inst_class = instFormat.inst_class; m_instruction.category = instFormat.inst_category; From 977371e7e1888c18f3adc4e77d78421784178c38 Mon Sep 17 00:00:00 2001 From: "Daniel R." <47796739+polybiusproxy@users.noreply.github.com> Date: Sun, 25 Aug 2024 14:06:41 +0200 Subject: [PATCH 04/23] shader_recompiler/frontend: fix `IMAGE_GATHER4_C_LZ` format --- src/shader_recompiler/frontend/format.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shader_recompiler/frontend/format.cpp b/src/shader_recompiler/frontend/format.cpp index 9c4be07b9..36b447b38 100644 --- a/src/shader_recompiler/frontend/format.cpp +++ b/src/shader_recompiler/frontend/format.cpp @@ -3602,8 +3602,8 @@ constexpr std::array InstructionFormatMIMG = {{ {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, ScalarType::Undefined}, // 79 = IMAGE_GATHER4_C_LZ - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Uint32}, // 80 = IMAGE_GATHER4_O {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, ScalarType::Undefined}, From 3a8a666df0235cfe2b3204d7012f852eddcf92ee Mon Sep 17 00:00:00 2001 From: Daniel R <47796739+polybiusproxy@users.noreply.github.com> Date: Sun, 25 Aug 2024 19:53:45 +0200 Subject: [PATCH 05/23] shader_recompiler/frontend: fix `IMAGE_SAMPLE_CD` format * Seen on Dark Souls --- src/shader_recompiler/frontend/decode.cpp | 2 -- src/shader_recompiler/frontend/format.cpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/shader_recompiler/frontend/decode.cpp b/src/shader_recompiler/frontend/decode.cpp index dda984d57..4452b4fda 100644 --- a/src/shader_recompiler/frontend/decode.cpp +++ b/src/shader_recompiler/frontend/decode.cpp @@ -5,8 +5,6 @@ #include "common/assert.h" #include "shader_recompiler/frontend/decode.h" -#define MAGIC_ENUM_RANGE_MIN 0 -#define MAGIC_ENUM_RANGE_MAX 1515 #include "magic_enum.hpp" namespace Shader::Gcn { diff --git a/src/shader_recompiler/frontend/format.cpp b/src/shader_recompiler/frontend/format.cpp index 36b447b38..34bd618cc 100644 --- a/src/shader_recompiler/frontend/format.cpp +++ b/src/shader_recompiler/frontend/format.cpp @@ -3655,8 +3655,8 @@ constexpr std::array InstructionFormatMIMG = {{ {}, {}, // 104 = IMAGE_SAMPLE_CD - {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Float32, + ScalarType::Float32}, // 105 = IMAGE_SAMPLE_CD_CL {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, ScalarType::Undefined}, From 51610cba438adb5c1047477986e9da164d39bb1a Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 3 Sep 2024 13:27:51 -0300 Subject: [PATCH 06/23] add TR for PR 700 --- src/qt_gui/translations/ar.ts | 5 +++++ src/qt_gui/translations/da_DK.ts | 5 +++++ src/qt_gui/translations/de.ts | 5 +++++ src/qt_gui/translations/el.ts | 5 +++++ src/qt_gui/translations/en.ts | 5 +++++ src/qt_gui/translations/es_ES.ts | 5 +++++ src/qt_gui/translations/fa_IR.ts | 5 +++++ src/qt_gui/translations/fi.ts | 5 +++++ src/qt_gui/translations/fr.ts | 5 +++++ src/qt_gui/translations/hu_HU.ts | 5 +++++ src/qt_gui/translations/id.ts | 5 +++++ src/qt_gui/translations/it.ts | 5 +++++ src/qt_gui/translations/ja_JP.ts | 5 +++++ src/qt_gui/translations/ko_KR.ts | 5 +++++ src/qt_gui/translations/lt_LT.ts | 5 +++++ src/qt_gui/translations/nb.ts | 5 +++++ src/qt_gui/translations/nl.ts | 5 +++++ src/qt_gui/translations/pl_PL.ts | 5 +++++ src/qt_gui/translations/pt_BR.ts | 5 +++++ src/qt_gui/translations/ro_RO.ts | 5 +++++ src/qt_gui/translations/ru_RU.ts | 5 +++++ src/qt_gui/translations/sq.ts | 5 +++++ src/qt_gui/translations/tr_TR.ts | 5 +++++ src/qt_gui/translations/vi_VN.ts | 5 +++++ src/qt_gui/translations/zh_CN.ts | 5 +++++ src/qt_gui/translations/zh_TW.ts | 5 +++++ 26 files changed, 130 insertions(+) diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index d35bbbf86..106f10e22 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -911,5 +911,10 @@ Name: :الاسم + + + Can't apply cheats before the game is started + لا يمكن تطبيق الغش قبل بدء اللعبة. + diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index c67d29b1d..b22ea6934 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -898,5 +898,10 @@ Name: Navn: + + + Can't apply cheats before the game is started + Kan ikke anvende snyd før spillet er startet. + \ No newline at end of file diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index c208ad441..8a6769543 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -898,5 +898,10 @@ Name: Name: + + + Can't apply cheats before the game is started + Kann keine Cheats anwenden, bevor das Spiel gestartet ist. + \ No newline at end of file diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index ef831fb09..a25e3bc74 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -898,5 +898,10 @@ Name: Όνομα: + + + Can't apply cheats before the game is started + Δεν μπορείτε να εφαρμόσετε cheats πριν ξεκινήσει το παιχνίδι. + \ No newline at end of file diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index b3c3b699b..6258663d1 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -898,5 +898,10 @@ Name: Name: + + + Can't apply cheats before the game is started + Can't apply cheats before the game is started. + \ No newline at end of file diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index c34dc3d44..3dd975db3 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -898,5 +898,10 @@ Name: Nombre: + + + Can't apply cheats before the game is started + No se pueden aplicar trucos antes de que se inicie el juego. + \ No newline at end of file diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 129d54792..f8de76ed7 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -895,5 +895,10 @@ Name: نام: + + + Can't apply cheats before the game is started + قبل از شروع بازی نمی توانید تقلب ها را اعمال کنید. + diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index d667dd379..1dc12091a 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -898,5 +898,10 @@ Name: Nimi: + + + Can't apply cheats before the game is started + Ei voi käyttää huijauksia ennen kuin peli on aloitettu. + \ No newline at end of file diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index 388912d23..b2bf828ca 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -898,5 +898,10 @@ Name: Nom : + + + Can't apply cheats before the game is started + Impossible d'appliquer les triches avant que le jeu ne commence. + diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index e5fb25a5d..2f706128d 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -898,5 +898,10 @@ Name: Név: + + + Can't apply cheats before the game is started + Nem lehet csalásokat alkalmazni, mielőtt a játék elindul. + diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index b8ce27cde..a64be232f 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -898,5 +898,10 @@ Name: Nama: + + + Can't apply cheats before the game is started + Tidak bisa menerapkan cheat sebelum permainan dimulai. + \ No newline at end of file diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index 380a8e43b..6f3e12928 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -898,5 +898,10 @@ Name: Nome: + + + Can't apply cheats before the game is started + Non è possibile applicare i trucchi prima dell'inizio del gioco. + diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index 3d62de0de..53b7d2771 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -898,5 +898,10 @@ Name: 名前: + + + Can't apply cheats before the game is started + ゲームが開始される前にチートを適用することはできません。 + \ No newline at end of file diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index f7f171dc6..9a6266c3b 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -898,5 +898,10 @@ Name: Name: + + + Can't apply cheats before the game is started + Can't apply cheats before the game is started. + \ No newline at end of file diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 7aa4402e6..95246e556 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -898,5 +898,10 @@ Name: Pavadinimas: + + + Can't apply cheats before the game is started + Negalima taikyti sukčiavimų prieš pradedant žaidimą. + \ No newline at end of file diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 76cad45b2..0d37232ff 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -898,5 +898,10 @@ Name: Navn: + + + Can't apply cheats before the game is started + Kan ikke bruke juksetriks før spillet er startet. + \ No newline at end of file diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index b00460479..3af24c98e 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -898,5 +898,10 @@ Name: Naam: + + + Can't apply cheats before the game is started + Je kunt geen cheats toepassen voordat het spel is gestart. + \ No newline at end of file diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index deaab42fb..46c0f911a 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -898,5 +898,10 @@ Failed to parse JSON: Nie udało się przeanlizować JSON: + + + Can't apply cheats before the game is started + Nie można zastosować cheatów przed rozpoczęciem gry. + diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index 8b4538b9d..9c5650a81 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -898,5 +898,10 @@ Name: Nome: + + + Can't apply cheats before the game is started + Não é possível aplicar cheats antes que o jogo comece. + \ No newline at end of file diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index 8b2fda0c1..925ac8014 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -898,5 +898,10 @@ Name: Nume: + + + Can't apply cheats before the game is started + Nu poți aplica cheats înainte ca jocul să înceapă. + \ No newline at end of file diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index 9e3446ad4..ebbd3e656 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -898,5 +898,10 @@ Name: Имя: + + + Can't apply cheats before the game is started + Невозможно применить читы до начала игрыs + \ No newline at end of file diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index cd1ee74fb..09a416098 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -898,5 +898,10 @@ Name: Emri: + + + Can't apply cheats before the game is started + nuk mund të aplikoni mashtrime para se të fillojë loja. + diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index e11a2d960..3ca4cfa03 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -969,5 +969,10 @@ Apply Changes Değişiklikleri Uygula + + + Can't apply cheats before the game is started + Hileleri oyuna başlamadan önce uygulayamazsınız. + \ No newline at end of file diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index aead45a63..621d33e2c 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -898,5 +898,10 @@ Name: Tên: + + + Can't apply cheats before the game is started + Không thể áp dụng cheat trước khi trò chơi bắt đầu. + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 7584fd5ea..8533696e6 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -898,5 +898,10 @@ Name: 名称: + + + Can't apply cheats before the game is started + 在游戏开始之前无法应用作弊。 + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 3836ed18a..dc5d1b96d 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -898,5 +898,10 @@ Name: 名稱: + + + Can't apply cheats before the game is started + 在遊戲開始之前無法應用作弊。 + \ No newline at end of file From 83a7bac945565a65ce55c4115b9b7da80b540eb6 Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 3 Sep 2024 13:45:43 -0300 Subject: [PATCH 07/23] Update src/qt_gui/translations/pl_PL.ts Co-authored-by: Marcin Mitura --- src/qt_gui/translations/pl_PL.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 46c0f911a..0275ffadb 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -901,7 +901,7 @@ Can't apply cheats before the game is started - Nie można zastosować cheatów przed rozpoczęciem gry. + Nie można zastosować kodów przed uruchomieniem gry. From ee7e6f0b1d0616d479ec7a6b146299b867c2c0cb Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 3 Sep 2024 14:17:57 -0300 Subject: [PATCH 08/23] add more information download patches If the patch does not appear, it may be that it does not exist for the specific serial and version of the game. It may be necessary to update the game. --- src/qt_gui/translations/ar.ts | 2 +- src/qt_gui/translations/da_DK.ts | 2 +- src/qt_gui/translations/de.ts | 2 +- src/qt_gui/translations/el.ts | 2 +- src/qt_gui/translations/en.ts | 2 +- src/qt_gui/translations/es_ES.ts | 2 +- src/qt_gui/translations/fa_IR.ts | 2 +- src/qt_gui/translations/fi.ts | 2 +- src/qt_gui/translations/fr.ts | 2 +- src/qt_gui/translations/hu_HU.ts | 2 +- src/qt_gui/translations/id.ts | 2 +- src/qt_gui/translations/it.ts | 2 +- src/qt_gui/translations/ja_JP.ts | 2 +- src/qt_gui/translations/ko_KR.ts | 2 +- src/qt_gui/translations/lt_LT.ts | 2 +- src/qt_gui/translations/nb.ts | 2 +- src/qt_gui/translations/nl.ts | 2 +- src/qt_gui/translations/pl_PL.ts | 2 +- src/qt_gui/translations/pt_BR.ts | 2 +- src/qt_gui/translations/ro_RO.ts | 2 +- src/qt_gui/translations/ru_RU.ts | 2 +- src/qt_gui/translations/sq.ts | 2 +- src/qt_gui/translations/tr_TR.ts | 2 +- src/qt_gui/translations/vi_VN.ts | 2 +- src/qt_gui/translations/zh_CN.ts | 2 +- src/qt_gui/translations/zh_TW.ts | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index 106f10e22..c0205c503 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -864,7 +864,7 @@ DownloadComplete_MSG - تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات لجميع الألعاب، ولا داعي لتنزيلها بشكل فردي لكل لعبة كما هو الحال مع الغش. + تم تنزيل التصحيحات بنجاح! تم تنزيل جميع التصحيحات لجميع الألعاب، ولا داعي لتنزيلها بشكل فردي لكل لعبة كما هو الحال مع الغش. إذا لم يظهر التحديث، قد يكون السبب أنه غير متوفر للإصدار وسيريال اللعبة المحدد. قد تحتاج إلى تحديث اللعبة. diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index b22ea6934..62a70c8cc 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patcher hentet med succes! Alle patches til alle spil er blevet hentet, der er ikke behov for at hente dem individuelt for hvert spil, som det sker med snyd. + Patcher hentet med succes! Alle patches til alle spil er blevet hentet, der er ikke behov for at hente dem individuelt for hvert spil, som det sker med snyd. Hvis opdateringen ikke vises, kan det være, at den ikke findes for den specifikke serie og version af spillet. Det kan være nødvendigt at opdatere spillet. diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index 8a6769543..e9b88513b 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patches erfolgreich heruntergeladen! Alle Patches für alle Spiele wurden heruntergeladen, es ist nicht notwendig, sie einzeln für jedes Spiel herunterzuladen, wie es bei Cheats der Fall ist. + Patches erfolgreich heruntergeladen! Alle Patches für alle Spiele wurden heruntergeladen, es ist nicht notwendig, sie einzeln für jedes Spiel herunterzuladen, wie es bei Cheats der Fall ist. Wenn der Patch nicht angezeigt wird, könnte es sein, dass er für die spezifische Seriennummer und Version des Spiels nicht existiert. Möglicherweise müssen Sie das Spiel aktualisieren. diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index a25e3bc74..487e99a0f 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Τα Patches κατεβάστηκαν επιτυχώς! Όλα τα Patches για όλα τα παιχνίδια έχουν κατέβει, δεν είναι απαραίτητο να τα κατεβάσετε ένα-ένα για κάθε παιχνίδι, όπως με τα Cheats. + Τα Patches κατεβάστηκαν επιτυχώς! Όλα τα Patches για όλα τα παιχνίδια έχουν κατέβει, δεν είναι απαραίτητο να τα κατεβάσετε ένα-ένα για κάθε παιχνίδι, όπως με τα Cheats. Εάν η ενημέρωση δεν εμφανίζεται, μπορεί να μην υπάρχει για τον συγκεκριμένο σειριακό αριθμό και έκδοση του παιχνιδιού. Μπορεί να χρειαστεί να ενημερώσετε το παιχνίδι. diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 6258663d1..0d4543591 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats. + Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats. If the patch does not appear, it may be that it does not exist for the specific serial and version of the game. It may be necessary to update the game. diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index 3dd975db3..5394655d1 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - ¡Parches descargados exitosamente! Todos los parches disponibles para todos los juegos han sido descargados, no es necesario descargarlos individualmente para cada juego como ocurre con los trucos. + ¡Parches descargados exitosamente! Todos los parches disponibles para todos los juegos han sido descargados, no es necesario descargarlos individualmente para cada juego como ocurre con los trucos. Si el parche no aparece, puede ser que no exista para el número de serie y versión específicos del juego. Puede ser necesario actualizar el juego. diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index f8de76ed7..6a3a28bcc 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -843,7 +843,7 @@ Download Complete - دانلود موفقیت آمیز بود✅ + پچ ها با موفقیت بارگیری شدند! تمام وصله های موجود برای همه بازی ها دانلود شده اند، نیازی به دانلود جداگانه آنها برای هر بازی نیست، همانطور که در Cheats اتفاق می افتد. اگر پچ ظاهر نشد، ممکن است برای سریال و نسخه خاصی از بازی وجود نداشته باشد. ممکن است نیاز به آپدیت بازی باشد.✅ diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index 1dc12091a..b4016ad53 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Korjaukset ladattu onnistuneesti! Kaikki saatavilla olevat korjaukset kaikille peleille on ladattu, eikä niitä tarvitse ladata yksittäin jokaiselle pelille kuten huijauksissa. + Korjaukset ladattu onnistuneesti! Kaikki saatavilla olevat korjaukset kaikille peleille on ladattu, eikä niitä tarvitse ladata yksittäin jokaiselle pelille kuten huijauksissa. Jos päivitystä ei näy, se saattaa olla, että sitä ei ole saatavilla tietylle sarjanumerolle ja peliversiolle. Saattaa olla tarpeen päivittää peli. diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index b2bf828ca..96243523f 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patchs téléchargés avec succès ! Tous les patches disponibles pour tous les jeux ont été téléchargés, il n'est pas nécessaire de les télécharger individuellement pour chaque jeu comme c'est le cas pour les Cheats. + Patchs téléchargés avec succès ! Tous les patches disponibles pour tous les jeux ont été téléchargés, il n'est pas nécessaire de les télécharger individuellement pour chaque jeu comme c'est le cas pour les Cheats. Si le correctif n'apparaît pas, il se peut qu'il n'existe pas pour le numéro de série et la version spécifiques du jeu. Il peut être nécessaire de mettre à jour le jeu. diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 2f706128d..28a4033ef 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Frissítések sikeresen letöltve! Minden elérhető frissítés letöltésre került, nem szükséges egyesével letölteni őket minden játékhoz, mint a csalások esetében. + Frissítések sikeresen letöltve! Minden elérhető frissítés letöltésre került, nem szükséges egyesével letölteni őket minden játékhoz, mint a csalások esetében. Ha a javítás nem jelenik meg, lehet, hogy nem létezik a játék adott sorozatszámához és verziójához. Lehet, hogy frissítenie kell a játékot. diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index a64be232f..f0471ba82 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patch Berhasil Diunduh! Semua Patch yang tersedia untuk semua game telah diunduh, tidak perlu mengunduhnya satu per satu seperti yang terjadi pada Cheat. + Patch Berhasil Diunduh! Semua Patch yang tersedia untuk semua game telah diunduh, tidak perlu mengunduhnya satu per satu seperti yang terjadi pada Cheat. Jika patch tidak muncul, mungkin patch tersebut tidak ada untuk nomor seri dan versi game yang spesifik. Mungkin perlu memperbarui game. diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index 6f3e12928..fe62c2687 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patch scaricata con successo! Vengono scaricate tutte le patch disponibili per tutti i giochi, non è necessario scaricarle singolarmente per ogni gioco come nel caso dei trucchi. + Patch scaricata con successo! Vengono scaricate tutte le patch disponibili per tutti i giochi, non è necessario scaricarle singolarmente per ogni gioco come nel caso dei trucchi. Se la patch non appare, potrebbe essere che non esista per il numero di serie e la versione specifica del gioco. Potrebbe essere necessario aggiornare il gioco. diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index 53b7d2771..adbc5e51c 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - パッチが正常にダウンロードされました! すべてのゲームに利用可能なパッチがダウンロードされました。チートとは異なり、各ゲームごとに個別にダウンロードする必要はありません。 + パッチが正常にダウンロードされました! すべてのゲームに利用可能なパッチがダウンロードされました。チートとは異なり、各ゲームごとに個別にダウンロードする必要はありません。 パッチが表示されない場合、特定のシリアル番号とバージョンのゲームには存在しない可能性があります。ゲームを更新する必要があるかもしれません。 diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index 9a6266c3b..8e1eb2734 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats. + Patches Downloaded Successfully! All Patches available for all games have been downloaded, there is no need to download them individually for each game as happens in Cheats. If the patch does not appear, it may be that it does not exist for the specific serial and version of the game. It may be necessary to update the game. diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 95246e556..26f506c4c 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Pataisos sėkmingai atsisiųstos! Visos pataisos visiems žaidimams buvo atsisiųstos, nebėra reikalo jas atsisiųsti atskirai kiekvienam žaidimui, kaip tai vyksta su sukčiavimais. + Pataisos sėkmingai atsisiųstos! Visos pataisos visiems žaidimams buvo atsisiųstos, nebėra reikalo jas atsisiųsti atskirai kiekvienam žaidimui, kaip tai vyksta su sukčiavimais. Jei pleistras nepasirodo, gali būti, kad jo nėra tam tikram žaidimo serijos numeriui ir versijai. Gali prireikti atnaujinti žaidimą. diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 0d37232ff..8158e2e2a 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Oppdateringer lastet ned vellykket! Alle oppdateringer tilgjengelige for alle spill har blitt lastet ned, det er ikke nødvendig å laste dem ned individuelt for hvert spill som skjer med jukser. + Oppdateringer lastet ned vellykket! Alle oppdateringer tilgjengelige for alle spill har blitt lastet ned, det er ikke nødvendig å laste dem ned individuelt for hvert spill som skjer med jukser. Hvis oppdateringen ikke vises, kan det hende at den ikke finnes for den spesifikke serienummeret og versjonen av spillet. Det kan være nødvendig å oppdatere spillet. diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index 3af24c98e..a298f5d73 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patches succesvol gedownload! Alle beschikbare patches voor alle spellen zijn gedownload. Het is niet nodig om ze afzonderlijk te downloaden voor elk spel dat cheats heeft. + Patches succesvol gedownload! Alle beschikbare patches voor alle spellen zijn gedownload. Het is niet nodig om ze afzonderlijk te downloaden voor elk spel dat cheats heeft. Als de patch niet verschijnt, kan het zijn dat deze niet bestaat voor het specifieke serienummer en de versie van het spel. Het kan nodig zijn om het spel bij te werken. diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 46c0f911a..f26cfe0e5 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Poprawki zostały pomyślnie pobrane! Wszystkie dostępne poprawki dla wszystkich gier zostały pobrane. Nie ma potrzeby pobierania ich osobno dla każdej gry, która ma kody. + Poprawki zostały pomyślnie pobrane! Wszystkie dostępne poprawki dla wszystkich gier zostały pobrane. Nie ma potrzeby pobierania ich osobno dla każdej gry, która ma kody. Jeśli poprawka się nie pojawia, możliwe, że nie istnieje dla konkretnego numeru seryjnego i wersji gry. Może być konieczne zaktualizowanie gry. diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index 9c5650a81..b4c272d52 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patches Baixados com Sucesso! Todos os patches disponíveis para todos os jogos foram baixados, não é necessário baixá-los individualmente para cada jogo como acontece com os Cheats. + Patches Baixados com Sucesso! Todos os patches disponíveis para todos os jogos foram baixados, não é necessário baixá-los individualmente para cada jogo como acontece com os Cheats. Se o patch não aparecer, pode ser que ele não exista para o número de série e a versão específicos do jogo. Pode ser necessário atualizar o jogo. diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index 925ac8014..7cd5dab36 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Patches descărcate cu succes! Toate Patches disponibile pentru toate jocurile au fost descărcate; nu este nevoie să le descarci individual pentru fiecare joc, așa cum se întâmplă cu Cheats. + Patches descărcate cu succes! Toate Patches disponibile pentru toate jocurile au fost descărcate; nu este nevoie să le descarci individual pentru fiecare joc, așa cum se întâmplă cu Cheats. Dacă patch-ul nu apare, este posibil să nu existe pentru seria și versiunea specifică a jocului. Poate fi necesar să actualizați jocul. diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index ebbd3e656..da73d7cf1 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Патчи успешно скачаны! Все доступные патчи для всех игр были скачаны, нет необходимости скачивать их по отдельности для каждой игры, как это происходит с читами. + Патчи успешно скачаны! Все доступные патчи для всех игр были скачаны, нет необходимости скачивать их по отдельности для каждой игры, как это происходит с читами. Если патч не появляется, возможно, его не существует для конкретного серийного номера и версии игры. Возможно, потребуется обновить игру. diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index 09a416098..a3425111b 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Arnat u shkarkuan me sukses! Të gjitha arnat e ofruara për të gjitha lojërat janë shkarkuar, nuk ka nevojë t'i shkarkosh ato individualisht për secilën lojë siç ndodh me Mashtrimet. + Arnat u shkarkuan me sukses! Të gjitha arnat e ofruara për të gjitha lojërat janë shkarkuar, nuk ka nevojë t'i shkarkosh ato individualisht për secilën lojë siç ndodh me Mashtrimet. Nëse patch-i nuk shfaqet, mund të mos ekzistojë për numrin e serisë dhe versionin specifik të lojës. Mund të jetë e nevojshme të përditësoni lojën. diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 3ca4cfa03..452cf4f23 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Yamalar başarıyla indirildi! Tüm oyunlar için mevcut tüm yamalar indirildi, her oyun için ayrı ayrı indirme yapmanız gerekmez, hilelerle olduğu gibi. + Yamalar başarıyla indirildi! Tüm oyunlar için mevcut tüm yamalar indirildi, her oyun için ayrı ayrı indirme yapmanız gerekmez, hilelerle olduğu gibi. Yamanın görünmemesi durumunda, belirli seri numarası ve oyun sürümü için mevcut olmayabilir. Oyunu güncellemeniz gerekebilir. diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 621d33e2c..08f2f7cbc 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - Bản vá đã tải xuống thành công! Tất cả các bản vá có sẵn cho tất cả các trò chơi đã được tải xuống, không cần tải xuống riêng lẻ cho mỗi trò chơi như trong Cheat. + Bản vá đã tải xuống thành công! Tất cả các bản vá có sẵn cho tất cả các trò chơi đã được tải xuống, không cần tải xuống riêng lẻ cho mỗi trò chơi như trong Cheat. Nếu bản vá không xuất hiện, có thể là nó không tồn tại cho số seri và phiên bản cụ thể của trò chơi. Có thể bạn cần phải cập nhật trò chơi. diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 8533696e6..22d08cc81 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - 补丁下载成功!所有可用的补丁已下载完成,无需像作弊码那样单独下载每个游戏的补丁。 + 补丁下载成功!所有可用的补丁已下载完成,无需像作弊码那样单独下载每个游戏的补丁。如果补丁没有出现,可能是该补丁不存在于特定的序列号和游戏版本中。可能需要更新游戏。 diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index dc5d1b96d..6cb28dffd 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -851,7 +851,7 @@ DownloadComplete_MSG - 修補檔下載成功!所有遊戲的修補檔已下載完成,無需像作弊碼那樣為每個遊戲單獨下載。 + 修補檔下載成功!所有遊戲的修補檔已下載完成,無需像作弊碼那樣為每個遊戲單獨下載。如果補丁未顯示,可能是該補丁不適用於特定的序號和遊戲版本。可能需要更新遊戲。 From 3a388fec1e9f00c6a8cafc2a9af0a12d952e7ad5 Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 3 Sep 2024 16:08:49 -0300 Subject: [PATCH 09/23] Save,Apply,Restore Defaults,Close Save,Apply,Restore Defaults,Close --- src/qt_gui/settings_dialog.cpp | 10 +- src/qt_gui/translations/ar.ts | 23 + src/qt_gui/translations/da_DK.ts | 23 + src/qt_gui/translations/de.ts | 23 + src/qt_gui/translations/el.ts | 23 + src/qt_gui/translations/en.ts | 25 +- src/qt_gui/translations/es_ES.ts | 23 + src/qt_gui/translations/fa_IR.ts | 1825 +++++++++++++++--------------- src/qt_gui/translations/fi.ts | 23 + src/qt_gui/translations/fr.ts | 23 + src/qt_gui/translations/hu_HU.ts | 23 + src/qt_gui/translations/id.ts | 23 + src/qt_gui/translations/it.ts | 23 + src/qt_gui/translations/ja_JP.ts | 25 +- src/qt_gui/translations/ko_KR.ts | 25 +- src/qt_gui/translations/lt_LT.ts | 23 + src/qt_gui/translations/nb.ts | 25 +- src/qt_gui/translations/nl.ts | 23 + src/qt_gui/translations/pl_PL.ts | 23 + src/qt_gui/translations/pt_BR.ts | 23 + src/qt_gui/translations/ro_RO.ts | 23 + src/qt_gui/translations/ru_RU.ts | 23 + src/qt_gui/translations/sq.ts | 23 + src/qt_gui/translations/tr_TR.ts | 23 + src/qt_gui/translations/vi_VN.ts | 23 + src/qt_gui/translations/zh_CN.ts | 25 +- src/qt_gui/translations/zh_TW.ts | 23 + 27 files changed, 1511 insertions(+), 909 deletions(-) diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index d572915c6..4206c4463 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -80,9 +80,13 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge } }); - connect(ui->tabWidgetSettings, &QTabWidget::currentChanged, this, [this]() { - ui->buttonBox->button(QDialogButtonBox::StandardButton::Close)->setFocus(); - }); + ui->buttonBox->button(QDialogButtonBox::Save)->setText(tr("Save")); + ui->buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Apply")); + ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setText(tr("Restore Defaults")); + ui->buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close")); + + connect(ui->tabWidgetSettings, &QTabWidget::currentChanged, this, + [this]() { ui->buttonBox->button(QDialogButtonBox::Close)->setFocus(); }); // GENERAL TAB { diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index c0205c503..b2b4b550e 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -917,4 +917,27 @@ لا يمكن تطبيق الغش قبل بدء اللعبة. + + SettingsDialog + + + Save + حفظ + + + + Apply + تطبيق + + + + Restore Defaults + استعادة الإعدادات الافتراضية + + + + Close + إغلاق + + diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index 62a70c8cc..48fd7cda8 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -904,4 +904,27 @@ Kan ikke anvende snyd før spillet er startet. + + SettingsDialog + + + Save + Gem + + + + Apply + Anvend + + + + Restore Defaults + Gendan standardindstillinger + + + + Close + Luk + + \ No newline at end of file diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index e9b88513b..f5f2154f3 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -904,4 +904,27 @@ Kann keine Cheats anwenden, bevor das Spiel gestartet ist. + + SettingsDialog + + + Save + Speichern + + + + Apply + Übernehmen + + + + Restore Defaults + Werkseinstellungen wiederherstellen + + + + Close + Schließen + + \ No newline at end of file diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index 487e99a0f..278b11655 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -904,4 +904,27 @@ Δεν μπορείτε να εφαρμόσετε cheats πριν ξεκινήσει το παιχνίδι. + + SettingsDialog + + + Save + Αποθήκευση + + + + Apply + Εφαρμογή + + + + Restore Defaults + Επαναφορά Προεπιλογών + + + + Close + Κλείσιμο + + \ No newline at end of file diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 0d4543591..06fda99e2 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -903,5 +903,28 @@ Can't apply cheats before the game is started Can't apply cheats before the game is started. - + + + SettingsDialog + + + Save + Save + + + + Apply + Apply + + + + Restore Defaults + Restore Defaults + + + + Close + Close + + \ No newline at end of file diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index 5394655d1..aba1dffbc 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -904,4 +904,27 @@ No se pueden aplicar trucos antes de que se inicie el juego. + + SettingsDialog + + + Save + Guardar + + + + Apply + Aplicar + + + + Restore Defaults + Restaurar Valores Predeterminados + + + + Close + Cerrar + + \ No newline at end of file diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 6a3a28bcc..4604db0f8 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -1,904 +1,927 @@ - - AboutDialog - - - About shadPS4 - درباره ShadPS4 - - - - shadPS4 - ShadPS4 - - - - shadPS4 is an experimental open-source emulator for the PlayStation 4. - یک شبیه ساز متن باز برای پلی استیشن 4 است. - - - - This software should not be used to play games you have not legally obtained. - این برنامه نباید برای بازی هایی که شما به صورت غیرقانونی به دست آوردید استفاده شود. - - - - ElfViewer - - - Open Folder - فولدر را بازکن - - - - GameInfoClass - - - Loading game list, please wait :3 - درحال بارگیری لیست بازی ها,لطفا کمی صبرکنید :3 - - - - Cancel - لغو - - - - Loading... - ...درحال بارگیری - - - - GameInstallDialog - - - shadPS4 - Choose directory - ShadPS4 - انتخاب محل نصب بازی - - - - Directory to install games - محل نصب بازی ها - - - - Browse - انتخاب دستی - - - - Error - ارور - - - - The value for location to install games is not valid. - .مکان داده شده برای نصب بازی درست نمی باشد - - - - GuiContextMenus - - - Create Shortcut - ساخت شورتکات - - - - Open Game Folder - بازکردن محل نصب بازی - - - - Cheats / Patches - چیت/پچ ها - - - - SFO Viewer - SFO مشاهده - - - - Trophy Viewer - مشاهده تروفی ها - - - - Copy info - کپی کردن اطلاعات - - - - Copy Name - کپی کردن نام - - - - Copy Serial - کپی کردن سریال - - - - Copy All - کپی کردن تمامی مقادیر - - - - Shortcut creation - سازنده شورتکات - - - - Shortcut created successfully!\n %1 - شورتکات با موفقیت ساخته شد! \n %1 - - - - Error - ارور - - - - Error creating shortcut!\n %1 - مشکلی در هنگام ساخت شورتکات بوجود آمد!\n %1 - - - - Install PKG - نصب PKG - - - - MainWindow - - - Open/Add Elf Folder - ELF بازکردن/ساختن پوشه - - - - Install Packages (PKG) - نصب بسته (PKG) - - - - Boot Game - اجرای بازی - - - - About shadPS4 - ShadPS4 درباره - - - - Configure... - ...تنظیمات - - - - Install application from a .pkg file - .PKG نصب بازی از فایل - - - - Recent Games - بازی های اخیر - - - - Exit - خروج - - - - Exit shadPS4 - ShadPS4 بستن - - - - Exit the application. - بستن برنامه - - - - Show Game List - نشان دادن بازی ها - - - - Game List Refresh - رفرش لیست بازی ها - - - - Tiny - کوچک ترین - - - - Small - کوچک - - - - Medium - متوسط - - - - Large - بزرگ - - - - List View - لیستی - - - - Grid View - شبکه ای (چهارخونه) - - - - Elf Viewer - Elf Viewer - - - - Game Install Directory - محل نصب بازی - - - - Download Cheats/Patches - دانلود چیت/پچ - - - - Dump Game List - استخراج لیست بازی ها - - - - PKG Viewer - PKG مشاهده گر - - - - Search... - جست و جو... - - - - File - فایل - - - - View - شخصی سازی - - - - Game List Icons - آیکون ها - - - - Game List Mode - حالت نمایش لیست بازی ها - - - - Settings - تنظیمات - - - - Utils - ابزارها - - - - Themes - تم ها - - - - About - درباره ما - - - - Dark - تیره - - - - Light - روشن - - - - Green - سبز - - - - Blue - آبی - - - - Violet - بنفش - - - - toolBar - نوار ابزار - - - - * Unsupported Vulkan Version - شما پشتیبانی نمیشود Vulkan ورژن* - - - - Download Cheats For All Installed Games - دانلود چیت برای همه بازی ها - - - - Download Patches For All Games - دانلود پچ برای همه بازی ها - - - - Download Complete - دانلود کامل شد✅ - - - - You have downloaded cheats for all the games you have installed. - چیت برای همه بازی های شما دانلودشد✅ - - - - Patches Downloaded Successfully! - پچ ها با موفقیت دانلود شد✅ - - - - All Patches available for all games have been downloaded. - ✅تمام پچ های موجود برای همه بازی های شما دانلود شد - - - - Games: - بازی ها: - - - - PKG File (*.PKG) - PKG فایل (*.PKG) - - - - ELF files (*.bin *.elf *.oelf) - ELF فایل های (*.bin *.elf *.oelf) - - - - Game Boot - اجرای بازی - - - - Only one file can be selected! - فقط یک فایل انتخاب کنید! - - - - PKG Extraction - PKG استخراج فایل - - - - Patch detected! - پچ شناسایی شد! - - - - PKG and Game versions match: - و نسخه بازی همخوانی دارد PKG فایل: - - - - Would you like to overwrite? - آیا مایل به جایگزینی فایل هستید؟ - - - - PKG Version %1 is older than installed version: - نسخه فایل PKG %1 قدیمی تر از نسخه نصب شده است: - - - - Game is installed: - بازی نصب شد: - - - - Would you like to install Patch: - آیا مایل به نصب پچ هستید: - - - - DLC Installation - نصب DLC - - - - Would you like to install DLC: %1? - آیا مایل به نصب DLC هستید: %1 - - - - DLC already installed: - قبلا نصب شده DLC این: - - - - Game already installed - این بازی قبلا نصب شده - - - - PKG is a patch, please install the game first! - فایل انتخاب شده یک پچ است, لطفا اول بازی را نصب کنید - - - - PKG ERROR - PKG ارور فایل - - - - Extracting PKG %1/%2 - درحال استخراج PKG %1/%2 - - - - Extraction Finished - استخراج به پایان رسید - - - - Game successfully installed at %1 - بازی با موفقیت در %1 نصب شد - - - - File doesn't appear to be a valid PKG file - این فایل یک PKG درست به نظر نمی آید - - - - PKGViewer - - - Open Folder - بازکردن پوشه - - - - TrophyViewer - - - Trophy Viewer - تروفی ها - - - - SettingsDialog - - - Settings - تنظیمات - - - - General - عمومی - - - - System - سیستم - - - - Console Language - زبان کنسول - - - - Emulator Language - زبان شبیه ساز - - - - Emulator - شبیه ساز - - - - Enable Fullscreen - تمام صفحه - - - - Show Splash - Splash نمایش - - - - Is PS4 Pro - PS4 Pro حالت - - - - Username - نام کاربری - - - - Logger - Logger - - - - Log Type - Log نوع - - - - Log Filter - Log فیلتر - - - - Graphics - گرافیک - - - - Graphics Device - کارت گرافیک مورداستفاده - - - - Width - عرض - - - - Height - طول - - - - Vblank Divider - Vblank Divider - - - - Advanced - ...بیشتر - - - - Enable Shaders Dumping - Shaders Dumping فعال کردن - - - - Enable NULL GPU - NULL GPU فعال کردن - - - - Enable PM4 Dumping - PM4 Dumping فعال کردن - - - - Debug - Debug - - - - Enable Debug Dumping - Debug Dumping - - - - Enable Vulkan Validation Layers - Vulkan Validation Layers - - - - Enable Vulkan Synchronization Validation - Vulkan Synchronization Validation - - - - Enable RenderDoc Debugging - RenderDoc Debugging - - - - CheatsPatches - - - Cheats / Patches - چیت / پچ ها - - - - defaultTextEdit_MSG - defaultTextEdit_MSG - - - - No Image Available - تصویری موجود نمی باشد - - - - Serial: - سریال: - - - - Version: - ورژن: - - - - Size: - حجم: - - - - Select Cheat File: - فایل چیت را انتخاب کنید: - - - - Repository: - :منبع - - - - Download Cheats - دانلود چیت ها - - - - Delete File - پاک کردن فایل - - - - No files selected. - فایلی انتخاب نشده. - - - - You can delete the cheats you don't want after downloading them. - شما میتوانید بعد از دانلود چیت هایی که نمیخواهید را پاک کنید - - - - Do you want to delete the selected file?\n%1 - آیا میخواهید فایل های انتخاب شده را پاک کنید؟ \n%1 - - - - Select Patch File: - فایل پچ را انتخاب کنید - - - - Download Patches - دانلود کردن پچ ها - - - - Save - ذخیره - - - - Cheats - چیت ها - - - - Patches - پچ ها - - - - Error - ارور - - - - No patch selected. - هیچ پچ انتخاب نشده - - - - Unable to open files.json for reading. - .json مشکل در خواندن فایل - - - - No patch file found for the current serial. - هیچ فایل پچ برای سریال بازی شما پیدا نشد. - - - - Unable to open the file for reading. - خطا در خواندن فایل - - - - Unable to open the file for writing. - خطا در نوشتن فایل - - - - Failed to parse XML: - انجام نشد XML تجزیه فایل: - - - - Success - عملیات موفق بود - - - - Options saved successfully. - تغییرات با موفقیت ذخیره شد✅ - - - - Invalid Source - منبع نامعتبر❌ - - - - The selected source is invalid. - منبع انتخاب شده نامعتبر است - - - - File Exists - فایل وجود دارد - - - - File already exists. Do you want to replace it? - فایل از قبل وجود دارد. آیا می خواهید آن را جایگزین کنید؟ - - - - Failed to save file: - ذخیره فایل موفقیت آمیز نبود: - - - - Failed to download file: - خطا در دانلود فایل: - - - - Cheats Not Found - چیت یافت نشد - - - - CheatsNotFound_MSG - متاسفانه هیچ چیتی از منبع انتخاب شده پیدا نشد! شما میتوانید منابع دیگری را برای دانلود انتخاب و یا چیت های خود را به صورت دستی واردکنید. - - - - Cheats Downloaded Successfully - دانلود چیت ها موفقیت آمیز بود✅ - - - - CheatsDownloadedSuccessfully_MSG - تمامی چیت های موجود برای این بازی از منبع انتخاب شده دانلود شد! شما همچنان میتوانید چیت های دیگری را ازمنابع مختلف دانلود کنید و درصورت موجود بودن از آنها استفاده کنید. - - - - Failed to save: - خطا در ذخیره اطلاعات: - - - - Failed to download: - خطا در دانلود❌ - - - - Download Complete - پچ ها با موفقیت بارگیری شدند! تمام وصله های موجود برای همه بازی ها دانلود شده اند، نیازی به دانلود جداگانه آنها برای هر بازی نیست، همانطور که در Cheats اتفاق می افتد. اگر پچ ظاهر نشد، ممکن است برای سریال و نسخه خاصی از بازی وجود نداشته باشد. ممکن است نیاز به آپدیت بازی باشد.✅ - - - - DownloadComplete_MSG - دانلود با موفقیت به اتمام رسید✅ - - - - Failed to parse JSON data from HTML. - HTML از JSON خطا در تجزیه اطلاعات. - - - - Failed to retrieve HTML page. - HTML خطا دربازیابی صفحه - - - - Failed to open file: - خطا در اجرای فایل: - - - - XML ERROR: - XML ERROR: - - - - Failed to open files.json for writing - .json خطا در نوشتن فایل - - - - Author: - تولید کننده: - - - - Directory does not exist: - پوشه وجود ندارد: - - - - Failed to open files.json for reading. - .json خطا در خواندن فایل - - - - Name: - نام: - - - - Can't apply cheats before the game is started - قبل از شروع بازی نمی توانید تقلب ها را اعمال کنید. - - - + + AboutDialog + + + About shadPS4 + درباره ShadPS4 + + + + shadPS4 + ShadPS4 + + + + shadPS4 is an experimental open-source emulator for the PlayStation 4. + یک شبیه ساز متن باز برای پلی استیشن 4 است. + + + + This software should not be used to play games you have not legally obtained. + این برنامه نباید برای بازی هایی که شما به صورت غیرقانونی به دست آوردید استفاده شود. + + + + ElfViewer + + + Open Folder + فولدر را بازکن + + + + GameInfoClass + + + Loading game list, please wait :3 + درحال بارگیری لیست بازی ها,لطفا کمی صبرکنید :3 + + + + Cancel + لغو + + + + Loading... + ...درحال بارگیری + + + + GameInstallDialog + + + shadPS4 - Choose directory + ShadPS4 - انتخاب محل نصب بازی + + + + Directory to install games + محل نصب بازی ها + + + + Browse + انتخاب دستی + + + + Error + ارور + + + + The value for location to install games is not valid. + .مکان داده شده برای نصب بازی درست نمی باشد + + + + GuiContextMenus + + + Create Shortcut + ساخت شورتکات + + + + Open Game Folder + بازکردن محل نصب بازی + + + + Cheats / Patches + چیت/پچ ها + + + + SFO Viewer + SFO مشاهده + + + + Trophy Viewer + مشاهده تروفی ها + + + + Copy info + کپی کردن اطلاعات + + + + Copy Name + کپی کردن نام + + + + Copy Serial + کپی کردن سریال + + + + Copy All + کپی کردن تمامی مقادیر + + + + Shortcut creation + سازنده شورتکات + + + + Shortcut created successfully!\n %1 + شورتکات با موفقیت ساخته شد! \n %1 + + + + Error + ارور + + + + Error creating shortcut!\n %1 + مشکلی در هنگام ساخت شورتکات بوجود آمد!\n %1 + + + + Install PKG + نصب PKG + + + + MainWindow + + + Open/Add Elf Folder + ELF بازکردن/ساختن پوشه + + + + Install Packages (PKG) + نصب بسته (PKG) + + + + Boot Game + اجرای بازی + + + + About shadPS4 + ShadPS4 درباره + + + + Configure... + ...تنظیمات + + + + Install application from a .pkg file + .PKG نصب بازی از فایل + + + + Recent Games + بازی های اخیر + + + + Exit + خروج + + + + Exit shadPS4 + ShadPS4 بستن + + + + Exit the application. + بستن برنامه + + + + Show Game List + نشان دادن بازی ها + + + + Game List Refresh + رفرش لیست بازی ها + + + + Tiny + کوچک ترین + + + + Small + کوچک + + + + Medium + متوسط + + + + Large + بزرگ + + + + List View + لیستی + + + + Grid View + شبکه ای (چهارخونه) + + + + Elf Viewer + Elf Viewer + + + + Game Install Directory + محل نصب بازی + + + + Download Cheats/Patches + دانلود چیت/پچ + + + + Dump Game List + استخراج لیست بازی ها + + + + PKG Viewer + PKG مشاهده گر + + + + Search... + جست و جو... + + + + File + فایل + + + + View + شخصی سازی + + + + Game List Icons + آیکون ها + + + + Game List Mode + حالت نمایش لیست بازی ها + + + + Settings + تنظیمات + + + + Utils + ابزارها + + + + Themes + تم ها + + + + About + درباره ما + + + + Dark + تیره + + + + Light + روشن + + + + Green + سبز + + + + Blue + آبی + + + + Violet + بنفش + + + + toolBar + نوار ابزار + + + + * Unsupported Vulkan Version + شما پشتیبانی نمیشود Vulkan ورژن* + + + + Download Cheats For All Installed Games + دانلود چیت برای همه بازی ها + + + + Download Patches For All Games + دانلود پچ برای همه بازی ها + + + + Download Complete + دانلود کامل شد✅ + + + + You have downloaded cheats for all the games you have installed. + چیت برای همه بازی های شما دانلودشد✅ + + + + Patches Downloaded Successfully! + پچ ها با موفقیت دانلود شد✅ + + + + All Patches available for all games have been downloaded. + ✅تمام پچ های موجود برای همه بازی های شما دانلود شد + + + + Games: + بازی ها: + + + + PKG File (*.PKG) + PKG فایل (*.PKG) + + + + ELF files (*.bin *.elf *.oelf) + ELF فایل های (*.bin *.elf *.oelf) + + + + Game Boot + اجرای بازی + + + + Only one file can be selected! + فقط یک فایل انتخاب کنید! + + + + PKG Extraction + PKG استخراج فایل + + + + Patch detected! + پچ شناسایی شد! + + + + PKG and Game versions match: + و نسخه بازی همخوانی دارد PKG فایل: + + + + Would you like to overwrite? + آیا مایل به جایگزینی فایل هستید؟ + + + + PKG Version %1 is older than installed version: + نسخه فایل PKG %1 قدیمی تر از نسخه نصب شده است: + + + + Game is installed: + بازی نصب شد: + + + + Would you like to install Patch: + آیا مایل به نصب پچ هستید: + + + + DLC Installation + نصب DLC + + + + Would you like to install DLC: %1? + آیا مایل به نصب DLC هستید: %1 + + + + DLC already installed: + قبلا نصب شده DLC این: + + + + Game already installed + این بازی قبلا نصب شده + + + + PKG is a patch, please install the game first! + فایل انتخاب شده یک پچ است, لطفا اول بازی را نصب کنید + + + + PKG ERROR + PKG ارور فایل + + + + Extracting PKG %1/%2 + درحال استخراج PKG %1/%2 + + + + Extraction Finished + استخراج به پایان رسید + + + + Game successfully installed at %1 + بازی با موفقیت در %1 نصب شد + + + + File doesn't appear to be a valid PKG file + این فایل یک PKG درست به نظر نمی آید + + + + PKGViewer + + + Open Folder + بازکردن پوشه + + + + TrophyViewer + + + Trophy Viewer + تروفی ها + + + + SettingsDialog + + + Settings + تنظیمات + + + + General + عمومی + + + + System + سیستم + + + + Console Language + زبان کنسول + + + + Emulator Language + زبان شبیه ساز + + + + Emulator + شبیه ساز + + + + Enable Fullscreen + تمام صفحه + + + + Show Splash + Splash نمایش + + + + Is PS4 Pro + PS4 Pro حالت + + + + Username + نام کاربری + + + + Logger + Logger + + + + Log Type + Log نوع + + + + Log Filter + Log فیلتر + + + + Graphics + گرافیک + + + + Graphics Device + کارت گرافیک مورداستفاده + + + + Width + عرض + + + + Height + طول + + + + Vblank Divider + Vblank Divider + + + + Advanced + ...بیشتر + + + + Enable Shaders Dumping + Shaders Dumping فعال کردن + + + + Enable NULL GPU + NULL GPU فعال کردن + + + + Enable PM4 Dumping + PM4 Dumping فعال کردن + + + + Debug + Debug + + + + Enable Debug Dumping + Debug Dumping + + + + Enable Vulkan Validation Layers + Vulkan Validation Layers + + + + Enable Vulkan Synchronization Validation + Vulkan Synchronization Validation + + + + Enable RenderDoc Debugging + RenderDoc Debugging + + + + CheatsPatches + + + Cheats / Patches + چیت / پچ ها + + + + defaultTextEdit_MSG + defaultTextEdit_MSG + + + + No Image Available + تصویری موجود نمی باشد + + + + Serial: + سریال: + + + + Version: + ورژن: + + + + Size: + حجم: + + + + Select Cheat File: + فایل چیت را انتخاب کنید: + + + + Repository: + :منبع + + + + Download Cheats + دانلود چیت ها + + + + Delete File + پاک کردن فایل + + + + No files selected. + فایلی انتخاب نشده. + + + + You can delete the cheats you don't want after downloading them. + شما میتوانید بعد از دانلود چیت هایی که نمیخواهید را پاک کنید + + + + Do you want to delete the selected file?\n%1 + آیا میخواهید فایل های انتخاب شده را پاک کنید؟ \n%1 + + + + Select Patch File: + فایل پچ را انتخاب کنید + + + + Download Patches + دانلود کردن پچ ها + + + + Save + ذخیره + + + + Cheats + چیت ها + + + + Patches + پچ ها + + + + Error + ارور + + + + No patch selected. + هیچ پچ انتخاب نشده + + + + Unable to open files.json for reading. + .json مشکل در خواندن فایل + + + + No patch file found for the current serial. + هیچ فایل پچ برای سریال بازی شما پیدا نشد. + + + + Unable to open the file for reading. + خطا در خواندن فایل + + + + Unable to open the file for writing. + خطا در نوشتن فایل + + + + Failed to parse XML: + انجام نشد XML تجزیه فایل: + + + + Success + عملیات موفق بود + + + + Options saved successfully. + تغییرات با موفقیت ذخیره شد✅ + + + + Invalid Source + منبع نامعتبر❌ + + + + The selected source is invalid. + منبع انتخاب شده نامعتبر است + + + + File Exists + فایل وجود دارد + + + + File already exists. Do you want to replace it? + فایل از قبل وجود دارد. آیا می خواهید آن را جایگزین کنید؟ + + + + Failed to save file: + ذخیره فایل موفقیت آمیز نبود: + + + + Failed to download file: + خطا در دانلود فایل: + + + + Cheats Not Found + چیت یافت نشد + + + + CheatsNotFound_MSG + متاسفانه هیچ چیتی از منبع انتخاب شده پیدا نشد! شما میتوانید منابع دیگری را برای دانلود انتخاب و یا چیت های خود را به صورت دستی واردکنید. + + + + Cheats Downloaded Successfully + دانلود چیت ها موفقیت آمیز بود✅ + + + + CheatsDownloadedSuccessfully_MSG + تمامی چیت های موجود برای این بازی از منبع انتخاب شده دانلود شد! شما همچنان میتوانید چیت های دیگری را ازمنابع مختلف دانلود کنید و درصورت موجود بودن از آنها استفاده کنید. + + + + Failed to save: + خطا در ذخیره اطلاعات: + + + + Failed to download: + خطا در دانلود❌ + + + + Download Complete + پچ ها با موفقیت بارگیری شدند! تمام وصله های موجود برای همه بازی ها دانلود شده اند، نیازی به دانلود جداگانه آنها برای هر بازی نیست، همانطور که در Cheats اتفاق می افتد. اگر پچ ظاهر نشد، ممکن است برای سریال و نسخه خاصی از بازی وجود نداشته باشد. ممکن است نیاز به آپدیت بازی باشد.✅ + + + + DownloadComplete_MSG + دانلود با موفقیت به اتمام رسید✅ + + + + Failed to parse JSON data from HTML. + HTML از JSON خطا در تجزیه اطلاعات. + + + + Failed to retrieve HTML page. + HTML خطا دربازیابی صفحه + + + + Failed to open file: + خطا در اجرای فایل: + + + + XML ERROR: + XML ERROR: + + + + Failed to open files.json for writing + .json خطا در نوشتن فایل + + + + Author: + تولید کننده: + + + + Directory does not exist: + پوشه وجود ندارد: + + + + Failed to open files.json for reading. + .json خطا در خواندن فایل + + + + Name: + نام: + + + + Can't apply cheats before the game is started + قبل از شروع بازی نمی توانید تقلب ها را اعمال کنید. + + + + SettingsDialog + + + Save + ذخیره + + + + Apply + اعمال + + + + Restore Defaults + بازیابی پیش فرض ها + + + + Close + بستن + + + \ No newline at end of file diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index b4016ad53..272335388 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -904,4 +904,27 @@ Ei voi käyttää huijauksia ennen kuin peli on aloitettu. + + SettingsDialog + + + Save + Tallenna + + + + Apply + Ota käyttöön + + + + Restore Defaults + Palauta oletukset + + + + Close + Sulje + + \ No newline at end of file diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index 96243523f..52b8878a0 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -904,4 +904,27 @@ Impossible d'appliquer les triches avant que le jeu ne commence. + + SettingsDialog + + + Save + Enregistrer + + + + Apply + Appliquer + + + + Restore Defaults + Restaurer les paramètres par défaut + + + + Close + Fermer + + diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 28a4033ef..4128d8917 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -904,4 +904,27 @@ Nem lehet csalásokat alkalmazni, mielőtt a játék elindul. + + SettingsDialog + + + Save + Mentés + + + + Apply + Alkalmaz + + + + Restore Defaults + Alapértelmezett értékek visszaállítása + + + + Close + Bezárás + + diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index f0471ba82..485ccd1bf 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -904,4 +904,27 @@ Tidak bisa menerapkan cheat sebelum permainan dimulai. + + SettingsDialog + + + Save + Simpan + + + + Apply + Terapkan + + + + Restore Defaults + Kembalikan Pengaturan Default + + + + Close + Tutup + + \ No newline at end of file diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index fe62c2687..38070a14c 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -904,4 +904,27 @@ Non è possibile applicare i trucchi prima dell'inizio del gioco. + + SettingsDialog + + + Save + Salva + + + + Apply + Applica + + + + Restore Defaults + Ripristina Impostazioni Predefinite + + + + Close + Chiudi + + diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index adbc5e51c..9dbc4d0d9 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -903,5 +903,28 @@ Can't apply cheats before the game is started ゲームが開始される前にチートを適用することはできません。 - + + + SettingsDialog + + + Save + 保存 + + + + Apply + 適用 + + + + Restore Defaults + デフォルトに戻す + + + + Close + 閉じる + + \ No newline at end of file diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index 8e1eb2734..4fc2f2a53 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -903,5 +903,28 @@ Can't apply cheats before the game is started Can't apply cheats before the game is started. - + + + SettingsDialog + + + Save + Save + + + + Apply + Apply + + + + Restore Defaults + Restore Defaults + + + + Close + Close + + \ No newline at end of file diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 26f506c4c..19674c7ea 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -904,4 +904,27 @@ Negalima taikyti sukčiavimų prieš pradedant žaidimą. + + SettingsDialog + + + Save + Įrašyti + + + + Apply + Taikyti + + + + Restore Defaults + Atkurti numatytuosius nustatymus + + + + Close + Uždaryti + + \ No newline at end of file diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 8158e2e2a..4b1d3fd48 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -903,5 +903,28 @@ Can't apply cheats before the game is started Kan ikke bruke juksetriks før spillet er startet. - + + + SettingsDialog + + + Save + Lag + + + + Apply + Bruk + + + + Restore Defaults + Gjenopprett standardinnstillinger + + + + Close + Lukk + + \ No newline at end of file diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index a298f5d73..449eba896 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -904,4 +904,27 @@ Je kunt geen cheats toepassen voordat het spel is gestart. + + SettingsDialog + + + Save + Opslaan + + + + Apply + Toepassen + + + + Restore Defaults + Standaardinstellingen herstellen + + + + Close + Sluiten + + \ No newline at end of file diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 1b79c0f08..049ae83de 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -904,4 +904,27 @@ Nie można zastosować kodów przed uruchomieniem gry. + + SettingsDialog + + + Save + Zapisz + + + + Apply + Zastosuj + + + + Restore Defaults + Przywróć ustawienia domyślne + + + + Close + Zamknij + + diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index b4c272d52..1f21e106a 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -904,4 +904,27 @@ Não é possível aplicar cheats antes que o jogo comece. + + SettingsDialog + + + Save + Salvar + + + + Apply + Aplicar + + + + Restore Defaults + Restaurar Padrões + + + + Close + Fechar + + \ No newline at end of file diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index 7cd5dab36..decb8f64e 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -904,4 +904,27 @@ Nu poți aplica cheats înainte ca jocul să înceapă. + + SettingsDialog + + + Save + Salvează + + + + Apply + Aplică + + + + Restore Defaults + Restabilește Impozitivele + + + + Close + Închide + + \ No newline at end of file diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index da73d7cf1..228944167 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -904,4 +904,27 @@ Невозможно применить читы до начала игрыs + + SettingsDialog + + + Save + Сохранить + + + + Apply + Применить + + + + Restore Defaults + Восстановить умолчания + + + + Close + Закрыть + + \ No newline at end of file diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index a3425111b..4d7fc321d 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -904,4 +904,27 @@ nuk mund të aplikoni mashtrime para se të fillojë loja. + + SettingsDialog + + + Save + Ruaj + + + + Apply + Përdor + + + + Restore Defaults + Rikthe parazgjedhjet + + + + Close + Mbyll + + diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 452cf4f23..f1b5bdeee 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -975,4 +975,27 @@ Hileleri oyuna başlamadan önce uygulayamazsınız. + + SettingsDialog + + + Save + Kaydet + + + + Apply + Uygula + + + + Restore Defaults + Varsayılanları Geri Yükle + + + + Close + Kapat + + \ No newline at end of file diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 08f2f7cbc..773c915f4 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -904,4 +904,27 @@ Không thể áp dụng cheat trước khi trò chơi bắt đầu. + + SettingsDialog + + + Save + Lưu + + + + Apply + Áp dụng + + + + Restore Defaults + Khôi phục cài đặt mặc định + + + + Close + Đóng + + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 22d08cc81..050b17aee 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -903,5 +903,28 @@ Can't apply cheats before the game is started 在游戏开始之前无法应用作弊。 - + + + SettingsDialog + + + Save + 保存 + + + + Apply + 应用 + + + + Restore Defaults + 恢复默认 + + + + Close + 关闭 + + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 6cb28dffd..04e06db80 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -904,4 +904,27 @@ 在遊戲開始之前無法應用作弊。 + + SettingsDialog + + + Save + 儲存 + + + + Apply + 應用 + + + + Restore Defaults + 還原預設值 + + + + Close + 關閉 + + \ No newline at end of file From d7f799c6b73ea1e2857a0f1fddd3b8eeccc4c25e Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 3 Sep 2024 16:19:16 -0300 Subject: [PATCH 10/23] fix PL text --- src/qt_gui/translations/pl_PL.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 049ae83de..910ead147 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -251,7 +251,7 @@ Game Install Directory - Katalog zainstalowanych gry + Katalog zainstalowanych gier From d24f8ddf03f4a1ca4d08e16d6c14c8848ee8c2fc Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 3 Sep 2024 18:42:43 -0300 Subject: [PATCH 11/23] Icon,Name,Serial,Region,Firmware,Size,Version,Path --- src/qt_gui/game_list_frame.cpp | 10 +- src/qt_gui/main_window.cpp | 4 +- src/qt_gui/translations/ar.ts | 48 +++++ src/qt_gui/translations/da_DK.ts | 48 +++++ src/qt_gui/translations/de.ts | 48 +++++ src/qt_gui/translations/el.ts | 48 +++++ src/qt_gui/translations/en.ts | 48 +++++ src/qt_gui/translations/es_ES.ts | 48 +++++ src/qt_gui/translations/fa_IR.ts | 341 ++++++++++++++++++------------- src/qt_gui/translations/fi.ts | 48 +++++ src/qt_gui/translations/fr.ts | 50 ++++- src/qt_gui/translations/hu_HU.ts | 48 +++++ src/qt_gui/translations/id.ts | 48 +++++ src/qt_gui/translations/it.ts | 48 +++++ src/qt_gui/translations/ja_JP.ts | 48 +++++ src/qt_gui/translations/ko_KR.ts | 48 +++++ src/qt_gui/translations/lt_LT.ts | 48 +++++ src/qt_gui/translations/nb.ts | 48 +++++ src/qt_gui/translations/nl.ts | 48 +++++ src/qt_gui/translations/pl_PL.ts | 48 +++++ src/qt_gui/translations/pt_BR.ts | 48 +++++ src/qt_gui/translations/ro_RO.ts | 48 +++++ src/qt_gui/translations/ru_RU.ts | 48 +++++ src/qt_gui/translations/sq.ts | 50 ++++- src/qt_gui/translations/tr_TR.ts | 48 +++++ src/qt_gui/translations/vi_VN.ts | 48 +++++ src/qt_gui/translations/zh_CN.ts | 48 +++++ src/qt_gui/translations/zh_TW.ts | 48 +++++ 28 files changed, 1402 insertions(+), 157 deletions(-) diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp index f5c2facbe..f8f6c6c78 100644 --- a/src/qt_gui/game_list_frame.cpp +++ b/src/qt_gui/game_list_frame.cpp @@ -31,14 +31,8 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, QWidg this->setColumnWidth(5, 90); // Size this->setColumnWidth(6, 90); // Version QStringList headers; - headers << "Icon" - << "Name" - << "Serial" - << "Region" - << "Firmware" - << "Size" - << "Version" - << "Path"; + headers << tr("Icon") << tr("Name") << tr("Serial") << tr("Region") << tr("Firmware") + << tr("Size") << tr("Version") << tr("Path"); this->setHorizontalHeaderLabels(headers); this->horizontalHeader()->setSortIndicatorShown(true); this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 988e01a50..7b4f19b23 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -34,12 +34,12 @@ bool MainWindow::Init() { CreateActions(); CreateRecentGameActions(); ConfigureGuiFromSettings(); + LoadTranslation(); CreateDockWindows(); CreateConnects(); SetLastUsedTheme(); SetLastIconSizeBullet(); GetPhysicalDevices(); - LoadTranslation(); // show ui setMinimumSize(350, minimumSizeHint().height()); setWindowTitle(QString::fromStdString("shadPS4 v" + std::string(Common::VERSION))); @@ -103,7 +103,7 @@ void MainWindow::CreateDockWindows() { QWidget* phCentralWidget = new QWidget(this); setCentralWidget(phCentralWidget); - m_dock_widget.reset(new QDockWidget("Game List", this)); + m_dock_widget.reset(new QDockWidget(tr("Game Lists"), this)); m_game_list_frame.reset(new GameListFrame(m_game_info, this)); m_game_list_frame->setObjectName("gamelist"); m_game_grid_frame.reset(new GameGridFrame(m_game_info, this)); diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index b2b4b550e..2d8f56476 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -502,6 +502,11 @@ MainWindow + + + Game Lists + قوائم الألعاب + * Unsupported Vulkan Version @@ -940,4 +945,47 @@ إغلاق + + GameListFrame + + + Icon + أيقونة + + + + Name + اسم + + + + Serial + سيريال + + + + Region + منطقة + + + + Firmware + البرمجيات الثابتة + + + + Size + حجم + + + + Version + إصدار + + + + Path + مسار + + diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index 48fd7cda8..e35379c84 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Spillister + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Luk + + GameListFrame + + + Icon + Ikon + + + + Name + Navn + + + + Serial + Seriel + + + + Region + Region + + + + Firmware + Firmware + + + + Size + Størrelse + + + + Version + Version + + + + Path + Sti + + \ No newline at end of file diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index f5f2154f3..23ffbe223 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Spiellisten + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Schließen + + GameListFrame + + + Icon + Symbol + + + + Name + Name + + + + Serial + Seriennummer + + + + Region + Region + + + + Firmware + Firmware + + + + Size + Größe + + + + Version + Version + + + + Path + Pfad + + \ No newline at end of file diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index 278b11655..d8d257bb1 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Λίστες παιχνιδιών + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Κλείσιμο + + GameListFrame + + + Icon + Εικονίδιο + + + + Name + Όνομα + + + + Serial + Σειριακός αριθμός + + + + Region + Περιοχή + + + + Firmware + Λογισμικό + + + + Size + Μέγεθος + + + + Version + Έκδοση + + + + Path + Διαδρομή + + \ No newline at end of file diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 06fda99e2..4c85e3374 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Game Lists + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Close + + GameListFrame + + + Icon + Icon + + + + Name + Name + + + + Serial + Serial + + + + Region + Region + + + + Firmware + Firmware + + + + Size + Size + + + + Version + Version + + + + Path + Path + + \ No newline at end of file diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index aba1dffbc..5de2e4fcc 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Listas de Juegos + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Cerrar + + GameListFrame + + + Icon + Ícono + + + + Name + Nombre + + + + Serial + Serie + + + + Region + Región + + + + Firmware + Firmware + + + + Size + Tamaño + + + + Version + Versión + + + + Path + Ruta + + \ No newline at end of file diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 4604db0f8..78f65e0e0 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -343,151 +343,6 @@ toolBar نوار ابزار - - - * Unsupported Vulkan Version - شما پشتیبانی نمیشود Vulkan ورژن* - - - - Download Cheats For All Installed Games - دانلود چیت برای همه بازی ها - - - - Download Patches For All Games - دانلود پچ برای همه بازی ها - - - - Download Complete - دانلود کامل شد✅ - - - - You have downloaded cheats for all the games you have installed. - چیت برای همه بازی های شما دانلودشد✅ - - - - Patches Downloaded Successfully! - پچ ها با موفقیت دانلود شد✅ - - - - All Patches available for all games have been downloaded. - ✅تمام پچ های موجود برای همه بازی های شما دانلود شد - - - - Games: - بازی ها: - - - - PKG File (*.PKG) - PKG فایل (*.PKG) - - - - ELF files (*.bin *.elf *.oelf) - ELF فایل های (*.bin *.elf *.oelf) - - - - Game Boot - اجرای بازی - - - - Only one file can be selected! - فقط یک فایل انتخاب کنید! - - - - PKG Extraction - PKG استخراج فایل - - - - Patch detected! - پچ شناسایی شد! - - - - PKG and Game versions match: - و نسخه بازی همخوانی دارد PKG فایل: - - - - Would you like to overwrite? - آیا مایل به جایگزینی فایل هستید؟ - - - - PKG Version %1 is older than installed version: - نسخه فایل PKG %1 قدیمی تر از نسخه نصب شده است: - - - - Game is installed: - بازی نصب شد: - - - - Would you like to install Patch: - آیا مایل به نصب پچ هستید: - - - - DLC Installation - نصب DLC - - - - Would you like to install DLC: %1? - آیا مایل به نصب DLC هستید: %1 - - - - DLC already installed: - قبلا نصب شده DLC این: - - - - Game already installed - این بازی قبلا نصب شده - - - - PKG is a patch, please install the game first! - فایل انتخاب شده یک پچ است, لطفا اول بازی را نصب کنید - - - - PKG ERROR - PKG ارور فایل - - - - Extracting PKG %1/%2 - درحال استخراج PKG %1/%2 - - - - Extraction Finished - استخراج به پایان رسید - - - - Game successfully installed at %1 - بازی با موفقیت در %1 نصب شد - - - - File doesn't appear to be a valid PKG file - این فایل یک PKG درست به نظر نمی آید - PKGViewer @@ -643,6 +498,159 @@ RenderDoc Debugging + + MainWindow + + + Game Lists + لیست بازی ها + + + + * Unsupported Vulkan Version + شما پشتیبانی نمیشود Vulkan ورژن* + + + + Download Cheats For All Installed Games + دانلود چیت برای همه بازی ها + + + + Download Patches For All Games + دانلود پچ برای همه بازی ها + + + + Download Complete + دانلود کامل شد✅ + + + + You have downloaded cheats for all the games you have installed. + چیت برای همه بازی های شما دانلودشد✅ + + + + Patches Downloaded Successfully! + پچ ها با موفقیت دانلود شد✅ + + + + All Patches available for all games have been downloaded. + ✅تمام پچ های موجود برای همه بازی های شما دانلود شد + + + + Games: + بازی ها: + + + + PKG File (*.PKG) + PKG فایل (*.PKG) + + + + ELF files (*.bin *.elf *.oelf) + ELF فایل های (*.bin *.elf *.oelf) + + + + Game Boot + اجرای بازی + + + + Only one file can be selected! + فقط یک فایل انتخاب کنید! + + + + PKG Extraction + PKG استخراج فایل + + + + Patch detected! + پچ شناسایی شد! + + + + PKG and Game versions match: + و نسخه بازی همخوانی دارد PKG فایل: + + + + Would you like to overwrite? + آیا مایل به جایگزینی فایل هستید؟ + + + + PKG Version %1 is older than installed version: + نسخه فایل PKG %1 قدیمی تر از نسخه نصب شده است: + + + + Game is installed: + بازی نصب شد: + + + + Would you like to install Patch: + آیا مایل به نصب پچ هستید: + + + + DLC Installation + نصب DLC + + + + Would you like to install DLC: %1? + آیا مایل به نصب DLC هستید: %1 + + + + DLC already installed: + قبلا نصب شده DLC این: + + + + Game already installed + این بازی قبلا نصب شده + + + + PKG is a patch, please install the game first! + فایل انتخاب شده یک پچ است, لطفا اول بازی را نصب کنید + + + + PKG ERROR + PKG ارور فایل + + + + Extracting PKG %1/%2 + درحال استخراج PKG %1/%2 + + + + Extraction Finished + استخراج به پایان رسید + + + + Game successfully installed at %1 + بازی با موفقیت در %1 نصب شد + + + + File doesn't appear to be a valid PKG file + این فایل یک PKG درست به نظر نمی آید + + CheatsPatches @@ -924,4 +932,47 @@ بستن + + GameListFrame + + + Icon + آیکون + + + + Name + نام + + + + Serial + سریال + + + + Region + منطقه + + + + Firmware + فریمور + + + + Size + اندازه + + + + Version + نسخه + + + + Path + مسیر + + \ No newline at end of file diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index 272335388..44e19d252 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Pelilista + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Sulje + + GameListFrame + + + Icon + Ikoni + + + + Name + Nimi + + + + Serial + Sarjanumero + + + + Region + Alue + + + + Firmware + Ohjelmisto + + + + Size + Koko + + + + Version + Versio + + + + Path + Polku + + \ No newline at end of file diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index 52b8878a0..a737620c1 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Listes de Jeux + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Fermer - + + GameListFrame + + + Icon + Icône + + + + Name + Nom + + + + Serial + Série + + + + Region + Région + + + + Firmware + Firmware + + + + Size + Taille + + + + Version + Version + + + + Path + Chemin + + + \ No newline at end of file diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 4128d8917..d3f191c9e 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Játéklisták + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Bezárás + + GameListFrame + + + Icon + Ikon + + + + Name + Név + + + + Serial + Sorozatszám + + + + Region + Régió + + + + Firmware + Firmware + + + + Size + Méret + + + + Version + Verzió + + + + Path + Útvonal + + diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index 485ccd1bf..b33ec0109 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Daftar Permainan + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Tutup + + GameListFrame + + + Icon + Ikon + + + + Name + Nama + + + + Serial + Serial + + + + Region + Wilayah + + + + Firmware + Firmware + + + + Size + Ukuran + + + + Version + Versi + + + + Path + Jalur + + \ No newline at end of file diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index 38070a14c..f8d1555e5 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Elenco Giochi + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Chiudi + + GameListFrame + + + Icon + Icona + + + + Name + Nome + + + + Serial + Seriale + + + + Region + Regione + + + + Firmware + Firmware + + + + Size + Dimensione + + + + Version + Versione + + + + Path + Percorso + + diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index 9dbc4d0d9..b01c43875 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + ゲームリスト + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ 閉じる + + GameListFrame + + + Icon + アイコン + + + + Name + 名前 + + + + Serial + シリアル + + + + Region + 地域 + + + + Firmware + ファームウェア + + + + Size + サイズ + + + + Version + バージョン + + + + Path + パス + + \ No newline at end of file diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index 4fc2f2a53..f7939a5e0 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Game Lists + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Close + + GameListFrame + + + Icon + Icon + + + + Name + Name + + + + Serial + Serial + + + + Region + Region + + + + Firmware + Firmware + + + + Size + Size + + + + Version + Version + + + + Path + Path + + \ No newline at end of file diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 19674c7ea..4a1612535 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Žaidimų sąrašai + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Uždaryti + + GameListFrame + + + Icon + Ikona + + + + Name + Vardas + + + + Serial + Serijinis numeris + + + + Region + Regionas + + + + Firmware + Firmvare + + + + Size + Dydis + + + + Version + Versija + + + + Path + Kelias + + \ No newline at end of file diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 4b1d3fd48..719b499b6 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Spillister + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Lukk + + GameListFrame + + + Icon + Ikon + + + + Name + Navn + + + + Serial + Serienummer + + + + Region + Region + + + + Firmware + Firmware + + + + Size + Størrelse + + + + Version + Versjon + + + + Path + Sti + + \ No newline at end of file diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index 449eba896..f1633ae1a 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Spillister + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Sluiten + + GameListFrame + + + Icon + Pictogram + + + + Name + Naam + + + + Serial + Serienummer + + + + Region + Regio + + + + Firmware + Firmware + + + + Size + Grootte + + + + Version + Versie + + + + Path + Pad + + \ No newline at end of file diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 910ead147..793d339bb 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Listy Gier + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Zamknij + + GameListFrame + + + Icon + Ikona + + + + Name + Nazwa + + + + Serial + Numer seryjny + + + + Region + Region + + + + Firmware + Oprogramowanie + + + + Size + Rozmiar + + + + Version + Wersja + + + + Path + Ścieżka + + diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index 1f21e106a..2489c76af 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Listas de jogos + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Fechar + + GameListFrame + + + Icon + Icone + + + + Name + Nome + + + + Serial + Serial + + + + Region + Região + + + + Firmware + Firmware + + + + Size + Tamanho + + + + Version + Versão + + + + Path + Diretório + + \ No newline at end of file diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index decb8f64e..75f3b1cc2 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -499,6 +499,11 @@ + + + Game Lists + Liste de Jocuri + MainWindow @@ -927,4 +932,47 @@ Închide + + GameListFrame + + + Icon + Icon + + + + Name + Nume + + + + Serial + Serie + + + + Region + Regiune + + + + Firmware + Firmware + + + + Size + Dimensiune + + + + Version + Versiune + + + + Path + Drum + + \ No newline at end of file diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index 228944167..582c68aed 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Списки игр + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Закрыть + + GameListFrame + + + Icon + Иконка + + + + Name + Название + + + + Serial + Серийный номер + + + + Region + Регион + + + + Firmware + Прошивка + + + + Size + Размер + + + + Version + Версия + + + + Path + Путь + + \ No newline at end of file diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index 4d7fc321d..66c1d21ff 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Listat e Lojërave + * Unsupported Vulkan Version @@ -901,7 +906,7 @@ Can't apply cheats before the game is started - nuk mund të aplikoni mashtrime para se të fillojë loja. + Nuk mund të aplikoni mashtrime para se të fillojë loja. @@ -927,4 +932,47 @@ Mbyll + + GameListFrame + + + Icon + Ikonë + + + + Name + Emri + + + + Serial + Seri + + + + Region + Rajoni + + + + Firmware + Firmware + + + + Size + Madësia + + + + Version + Versioni + + + + Path + Rrugë + + diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index f1b5bdeee..8c392b65c 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Oyun Listeleri + * Unsupported Vulkan Version @@ -998,4 +1003,47 @@ Kapat + + GameListFrame + + + Icon + Simge + + + + Name + Ad + + + + Serial + Seri Numarası + + + + Region + Bölge + + + + Firmware + Yazılım + + + + Size + Boyut + + + + Version + Sürüm + + + + Path + Yol + + \ No newline at end of file diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 773c915f4..e5769a32a 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + Danh sách trò chơi + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ Đóng + + GameListFrame + + + Icon + Biểu tượng + + + + Name + Tên + + + + Serial + Số seri + + + + Region + Khu vực + + + + Firmware + Phần mềm + + + + Size + Kích thước + + + + Version + Phiên bản + + + + Path + Đường dẫn + + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 050b17aee..29a7eef9f 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + 游戏列表 + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ 关闭 + + GameListFrame + + + Icon + 图标 + + + + Name + 名称 + + + + Serial + 序列号 + + + + Region + 区域 + + + + Firmware + 固件 + + + + Size + 大小 + + + + Version + 版本 + + + + Path + 路径 + + \ No newline at end of file diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 04e06db80..582331619 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -500,6 +500,11 @@ MainWindow + + + Game Lists + 遊戲列表 + * Unsupported Vulkan Version @@ -927,4 +932,47 @@ 關閉 + + GameListFrame + + + Icon + 圖示 + + + + Name + 名稱 + + + + Serial + 序號 + + + + Region + 區域 + + + + Firmware + 固件 + + + + Size + 大小 + + + + Version + 版本 + + + + Path + 路徑 + + \ No newline at end of file From 8ccec1b9569942dbb6099efef99306cf37ec818a Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 3 Sep 2024 20:41:55 -0300 Subject: [PATCH 12/23] Game List --- src/qt_gui/main_window.cpp | 2 +- src/qt_gui/translations/ar.ts | 4 ++-- src/qt_gui/translations/da_DK.ts | 4 ++-- src/qt_gui/translations/de.ts | 4 ++-- src/qt_gui/translations/el.ts | 4 ++-- src/qt_gui/translations/en.ts | 4 ++-- src/qt_gui/translations/es_ES.ts | 4 ++-- src/qt_gui/translations/fa_IR.ts | 4 ++-- src/qt_gui/translations/fi.ts | 2 +- src/qt_gui/translations/fr.ts | 4 ++-- src/qt_gui/translations/hu_HU.ts | 4 ++-- src/qt_gui/translations/id.ts | 4 ++-- src/qt_gui/translations/it.ts | 4 ++-- src/qt_gui/translations/ja_JP.ts | 2 +- src/qt_gui/translations/ko_KR.ts | 4 ++-- src/qt_gui/translations/lt_LT.ts | 4 ++-- src/qt_gui/translations/nb.ts | 4 ++-- src/qt_gui/translations/nl.ts | 4 ++-- src/qt_gui/translations/pl_PL.ts | 4 ++-- src/qt_gui/translations/pt_BR.ts | 4 ++-- src/qt_gui/translations/ro_RO.ts | 4 ++-- src/qt_gui/translations/ru_RU.ts | 4 ++-- src/qt_gui/translations/sq.ts | 4 ++-- src/qt_gui/translations/tr_TR.ts | 4 ++-- src/qt_gui/translations/vi_VN.ts | 2 +- src/qt_gui/translations/zh_CN.ts | 2 +- src/qt_gui/translations/zh_TW.ts | 2 +- 27 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 7b4f19b23..93969100d 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -103,7 +103,7 @@ void MainWindow::CreateDockWindows() { QWidget* phCentralWidget = new QWidget(this); setCentralWidget(phCentralWidget); - m_dock_widget.reset(new QDockWidget(tr("Game Lists"), this)); + m_dock_widget.reset(new QDockWidget(tr("Game List"), this)); m_game_list_frame.reset(new GameListFrame(m_game_info, this)); m_game_list_frame->setObjectName("gamelist"); m_game_grid_frame.reset(new GameGridFrame(m_game_info, this)); diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index 2d8f56476..12b1e7ba6 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -504,8 +504,8 @@ MainWindow - Game Lists - قوائم الألعاب + Game List + ققائمة الألعاب diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index e35379c84..bb405ec0a 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Spillister + Game List + Spiloversigt diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index 23ffbe223..1482686ce 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Spiellisten + Game List + Spieleliste diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index d8d257bb1..4a3aa54ff 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Λίστες παιχνιδιών + Game List + Λίστα παιχνιδιών diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 4c85e3374..9696610bc 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Game Lists + Game List + Game List diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index 5de2e4fcc..e1bc91809 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Listas de Juegos + Game List + Lista de juegos diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 78f65e0e0..089653069 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - لیست بازی ها + Game List + لیست بازی diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index 44e19d252..50e24fce6 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -502,7 +502,7 @@ MainWindow - Game Lists + Game List Pelilista diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index a737620c1..33e2990c0 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Listes de Jeux + Game List + Liste de jeux diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index d3f191c9e..0f69822e7 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Játéklisták + Game List + Játéklista diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index b33ec0109..6108ffa20 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Daftar Permainan + Game List + Daftar game diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index f8d1555e5..39cb35dd3 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Elenco Giochi + Game List + Elenco giochi diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index b01c43875..680d4ebd5 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -502,7 +502,7 @@ MainWindow - Game Lists + Game List ゲームリスト diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index f7939a5e0..a167311b9 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Game Lists + Game List + Game List diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 4a1612535..2c86ec0a0 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Žaidimų sąrašai + Game List + Žaidimų sąrašas diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 719b499b6..b62791e05 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Spillister + Game List + Spilliste diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index f1633ae1a..3d5edfc5d 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Spillister + Game List + Lijst met spellen diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 793d339bb..af8330bbd 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Listy Gier + Game List + Lista gier diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index 2489c76af..e774a30b4 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Listas de jogos + Game List + Lista de Jogos diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index 75f3b1cc2..56df113f5 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -501,8 +501,8 @@ - Game Lists - Liste de Jocuri + Game List + Lista jocurilor MainWindow diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index 582c68aed..1eac3e515 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Списки игр + Game List + Список игр diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index 66c1d21ff..f5dd55949 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Listat e Lojërave + Game List + Lista e lojërave diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 8c392b65c..83f62c85e 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -502,8 +502,8 @@ MainWindow - Game Lists - Oyun Listeleri + Game List + Oyun Listesi diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index e5769a32a..017e61af5 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -502,7 +502,7 @@ MainWindow - Game Lists + Game List Danh sách trò chơi diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 29a7eef9f..f8675ed01 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -502,7 +502,7 @@ MainWindow - Game Lists + Game List 游戏列表 diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 582331619..77fe691fe 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -502,7 +502,7 @@ MainWindow - Game Lists + Game List 遊戲列表 From 0b0c82452ed3d12f04331e1122ee7c39cc41380b Mon Sep 17 00:00:00 2001 From: Stephen Miller Date: Tue, 3 Sep 2024 19:57:24 -0500 Subject: [PATCH 13/23] Add "support" for pad type remote control Needed for the Dragon Ball Xenoverse titles. --- src/core/libraries/pad/pad.cpp | 4 ++-- src/core/libraries/pad/pad.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index cb0da552a..b8a27fdc2 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -250,7 +250,7 @@ int PS4_SYSV_ABI scePadOpen(s32 userId, s32 type, s32 index, const OrbisPadOpenP if (type != ORBIS_PAD_PORT_TYPE_SPECIAL) return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; } else { - if (type != ORBIS_PAD_PORT_TYPE_STANDARD) + if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL) return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; } return 1; // dummy @@ -263,7 +263,7 @@ int PS4_SYSV_ABI scePadOpenExt(s32 userId, s32 type, s32 index, if (type != ORBIS_PAD_PORT_TYPE_SPECIAL) return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; } else { - if (type != ORBIS_PAD_PORT_TYPE_STANDARD) + if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL) return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED; } return 1; // dummy diff --git a/src/core/libraries/pad/pad.h b/src/core/libraries/pad/pad.h index b18bbc355..f94a642cf 100644 --- a/src/core/libraries/pad/pad.h +++ b/src/core/libraries/pad/pad.h @@ -16,6 +16,7 @@ constexpr int ORBIS_PAD_MAX_DEVICE_UNIQUE_DATA_SIZE = 12; constexpr int ORBIS_PAD_PORT_TYPE_STANDARD = 0; constexpr int ORBIS_PAD_PORT_TYPE_SPECIAL = 2; +constexpr int ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL = 16; enum OrbisPadDeviceClass { ORBIS_PAD_DEVICE_CLASS_INVALID = -1, From 9eadec849cc99af90242bdd42a2596432e6f4b7e Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 3 Sep 2024 21:32:19 -0700 Subject: [PATCH 14/23] misc: Fix a few compiler warnings. --- src/core/libraries/network/net.h | 4 ++++ src/video_core/renderer_vulkan/vk_common.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/core/libraries/network/net.h b/src/core/libraries/network/net.h index 965b76809..eababdb67 100644 --- a/src/core/libraries/network/net.h +++ b/src/core/libraries/network/net.h @@ -10,8 +10,12 @@ class SymbolsResolver; } // Define our own htonll and ntohll because its not available in some systems/platforms +#ifndef HTONLL #define HTONLL(x) (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)) +#endif +#ifndef NTOHLL #define NTOHLL(x) (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)) +#endif namespace Libraries::Net { diff --git a/src/video_core/renderer_vulkan/vk_common.h b/src/video_core/renderer_vulkan/vk_common.h index 3e048749f..a2f9cbcaf 100644 --- a/src/video_core/renderer_vulkan/vk_common.h +++ b/src/video_core/renderer_vulkan/vk_common.h @@ -13,6 +13,7 @@ #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_NO_CONSTRUCTORS #define VULKAN_HPP_NO_STRUCT_SETTERS +#define VULKAN_HPP_HAS_SPACESHIP_OPERATOR #include #define VMA_STATIC_VULKAN_FUNCTIONS 0 From 0a5c36482e8ad82fca2427bb359d33b030a07a06 Mon Sep 17 00:00:00 2001 From: Sebastian Kassai <8061077+xezrunner@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:30:43 +0200 Subject: [PATCH 15/23] shader_recompiler: change ir.SetScalarReg() -> SetDst() (#777) Fixes an out-of-bounds crash on Amplitude and Rock Band 4 startup. --- src/shader_recompiler/frontend/translate/data_share.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shader_recompiler/frontend/translate/data_share.cpp b/src/shader_recompiler/frontend/translate/data_share.cpp index 7c23c7284..c0f0fa274 100644 --- a/src/shader_recompiler/frontend/translate/data_share.cpp +++ b/src/shader_recompiler/frontend/translate/data_share.cpp @@ -171,9 +171,9 @@ void Translator::V_READFIRSTLANE_B32(const GcnInst& inst) { const IR::U32 value{GetSrc(inst.src[0])}; if (info.stage != Stage::Compute) { - ir.SetScalarReg(dst, value); + SetDst(inst.dst[0], value); } else { - ir.SetScalarReg(dst, ir.ReadFirstLane(value)); + SetDst(inst.dst[0], ir.ReadFirstLane(value)); } } From b9c6093717bd75ff8963667b52628c6e9f1c70c4 Mon Sep 17 00:00:00 2001 From: menaman123 <53198002+menaman123@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:36:23 -0400 Subject: [PATCH 16/23] Implemented sceKernelMTypeProtect and sceKernelMProtect (#387) * Fixed ORBIS_KERNEL_MAP_OP_TYPE_PROTECT for batchmap2 * Fix merge * Changed 4 to ORBIS_KERNEL_MAP_OP_TYPE_PROTECT * Removed MProtect from AddressSpace * Added Mtyprotect and moved Mprotect to ORBIS_KERNEL_MAP_OP_PROTECT * Changed Protect for Windows * reverted the previous function * Fixed Mtypeprotect and MProtect * '' * '' * Took out logs stopping build * clang-format issues * Fixed the order of mtypeprotect and mprotect in batchmap2 * '' * update branch * '' * Fixed nits * '' * Update submodules to latest commits * '' * reverted ffmpeg * '' * Fixed the nits * '' * '' * '' * '' * '' * Fix clang formatting, DEBUG_ASSERT, and extra spacing * Fix build issues * Revert "Fix build issues" This reverts commit 9185f96ec93ce9414d98aaf2560df4fb6c17f49b. * '' * '' * '' * Changes for MemoryProt Format * '' * '' * '' --- src/core/address_space.cpp | 41 ++++--- src/core/libraries/kernel/libkernel.cpp | 2 + .../libraries/kernel/memory_management.cpp | 62 ++++++++-- src/core/libraries/kernel/memory_management.h | 4 + src/core/memory.cpp | 113 ++++++++++++++++++ src/core/memory.h | 5 + 6 files changed, 202 insertions(+), 25 deletions(-) diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp index 235113700..0dd7a76f2 100644 --- a/src/core/address_space.cpp +++ b/src/core/address_space.cpp @@ -15,6 +15,7 @@ #include #include #endif +#include "libraries/error_codes.h" #ifdef __APPLE__ // Reserve space for the system address space using a zerofill section. @@ -231,27 +232,36 @@ struct AddressSpace::Impl { void Protect(VAddr virtual_addr, size_t size, bool read, bool write, bool execute) { DWORD new_flags{}; - if (read && write) { + + if (read && write && execute) { + new_flags = PAGE_EXECUTE_READWRITE; + } else if (read && write) { new_flags = PAGE_READWRITE; } else if (read && !write) { new_flags = PAGE_READONLY; - } else if (!read && !write) { + } else if (execute && !read && not write) { + new_flags = PAGE_EXECUTE; + } else if (!read && !write && !execute) { new_flags = PAGE_NOACCESS; } else { - UNIMPLEMENTED_MSG("Protection flag combination read={} write={}", read, write); + LOG_CRITICAL(Common_Memory, + "Unsupported protection flag combination for address {:#x}, size {}", + virtual_addr, size); + return; } - const VAddr virtual_end = virtual_addr + size; - auto [it, end] = placeholders.equal_range({virtual_addr, virtual_end}); - while (it != end) { - const size_t offset = std::max(it->lower(), virtual_addr); - const size_t protect_length = std::min(it->upper(), virtual_end) - offset; - DWORD old_flags{}; - if (!VirtualProtect(virtual_base + offset, protect_length, new_flags, &old_flags)) { - LOG_CRITICAL(Common_Memory, "Failed to change virtual memory protect rules"); - } - ++it; + DWORD old_flags{}; + bool success = + VirtualProtect(reinterpret_cast(virtual_addr), size, new_flags, &old_flags); + + if (!success) { + LOG_ERROR(Common_Memory, + "Failed to change virtual memory protection for address {:#x}, size {}", + virtual_addr, size); } + + // Use assert to ensure success in debug builds + DEBUG_ASSERT(success && "Failed to change virtual memory protection"); } HANDLE process{}; @@ -493,7 +503,10 @@ void AddressSpace::Unmap(VAddr virtual_addr, size_t size, VAddr start_in_vma, VA } void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission perms) { - return impl->Protect(virtual_addr, size, true, true, true); + const bool read = True(perms & MemoryPermission::Read); + const bool write = True(perms & MemoryPermission::Write); + const bool execute = True(perms & MemoryPermission::Execute); + return impl->Protect(virtual_addr, size, read, write, execute); } } // namespace Core diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index 2634e25c8..d56f4dc41 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -454,6 +454,8 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent); LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent); LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId); + LIB_FUNCTION("9bfdLIyuwCY", "libkernel", 1, "libkernel", 1, 1, sceKernelMTypeProtect); + LIB_FUNCTION("vSMAm3cxYTY", "libkernel", 1, "libkernel", 1, 1, sceKernelMProtect); LIB_FUNCTION("23CPPI1tyBY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventFilter); // misc diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index a5288a656..08cd106d8 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -7,6 +7,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/singleton.h" +#include "core/address_space.h" #include "core/libraries/error_codes.h" #include "core/libraries/kernel/memory_management.h" #include "core/linker.h" @@ -218,6 +219,19 @@ int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** return memory->QueryProtection(std::bit_cast(addr), start, end, prot); } +int PS4_SYSV_ABI sceKernelMProtect(const void* addr, size_t size, int prot) { + Core::MemoryManager* memory_manager = Core::Memory::Instance(); + Core::MemoryProt protection_flags = static_cast(prot); + return memory_manager->Protect(std::bit_cast(addr), size, protection_flags); +} + +int PS4_SYSV_ABI sceKernelMTypeProtect(const void* addr, size_t size, int mtype, int prot) { + Core::MemoryManager* memory_manager = Core::Memory::Instance(); + Core::MemoryProt protection_flags = static_cast(prot); + return memory_manager->MTypeProtect(std::bit_cast(addr), size, + static_cast(mtype), protection_flags); +} + int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info, size_t infoSize) { LOG_WARNING(Kernel_Vmm, "called offset = {:#x}, flags = {:#x}", offset, flags); @@ -258,7 +272,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn int* numEntriesOut, int flags) { int result = ORBIS_OK; int processed = 0; - for (int i = 0; i < numEntries; i++, processed++) { + for (int i = 0; i < numEntries; i++) { if (entries == nullptr || entries[i].length == 0 || entries[i].operation > 4) { result = ORBIS_KERNEL_ERROR_EINVAL; break; // break and assign a value to numEntriesOut. @@ -278,10 +292,41 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn } case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_UNMAP: { result = sceKernelMunmap(entries[i].start, entries[i].length); - LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i, - entries[i].operation, entries[i].length, result); + LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", + i, entries[i].operation, entries[i].length, result); + + if (result == 0) + processed++; + } + case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_PROTECT: { + result = sceKernelMProtect(entries[i].start, entries[i].length, entries[i].protection); + LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", + i, entries[i].operation, entries[i].length, result); + if (result != ORBIS_OK) { + LOG_ERROR(Kernel_Vmm, "BatchMap: MProtect failed on entry {} with result {}", i, + result); + } + if (result == 0) { + processed++; + } break; } + + case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_TYPE_PROTECT: { + result = sceKernelMTypeProtect(entries[i].start, entries[i].length, entries[i].type, + entries[i].protection); + LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", + i, entries[i].operation, entries[i].length, result); + if (result != ORBIS_OK) { + LOG_ERROR(Kernel_Vmm, "BatchMap: MProtect failed on entry {} with result {}", i, + result); + } + if (result == 0) { + processed++; + } + break; + } + case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE: { result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length, entries[i].protection, flags, ""); @@ -291,14 +336,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn i, entries[i].operation, entries[i].length, (u8)entries[i].type, result); break; } - case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_TYPE_PROTECT: { - // By now, ignore protection and log it instead - LOG_WARNING(Kernel_Vmm, - "entry = {}, operation = {}, len = {:#x}, type = {} " - "is UNSUPPORTED and skipped", - i, entries[i].operation, entries[i].length, (u8)entries[i].type); - break; - } + default: { UNREACHABLE(); } @@ -308,6 +346,8 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn break; } } + LOG_INFO(Kernel_Vmm, "sceKernelBatchMap2 finished: processed = {}, result = {}", processed, + result); if (numEntriesOut != NULL) { // can be zero. do not return an error code. *numEntriesOut = processed; } diff --git a/src/core/libraries/kernel/memory_management.h b/src/core/libraries/kernel/memory_management.h index 761cb0844..205b2274f 100644 --- a/src/core/libraries/kernel/memory_management.h +++ b/src/core/libraries/kernel/memory_management.h @@ -95,6 +95,10 @@ s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int flags); int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void** end, u32* prot); +int PS4_SYSV_ABI sceKernelMProtect(const void* addr, size_t size, int prot); + +int PS4_SYSV_ABI sceKernelMTypeProtect(const void* addr, size_t size, int mtype, int prot); + int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info, size_t infoSize); s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 640751477..44f96a001 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -7,6 +7,7 @@ #include "core/libraries/error_codes.h" #include "core/libraries/kernel/memory_management.h" #include "core/memory.h" +#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" namespace Core { @@ -292,6 +293,118 @@ int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* pr return ORBIS_OK; } +int MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) { + std::scoped_lock lk{mutex}; + + // Find the virtual memory area that contains the specified address range. + auto it = FindVMA(addr); + if (it == vma_map.end() || !it->second.Contains(addr, size)) { + LOG_ERROR(Core, "Address range not mapped"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + VirtualMemoryArea& vma = it->second; + if (vma.type == VMAType::Free) { + LOG_ERROR(Core, "Cannot change protection on free memory region"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + // Validate protection flags + constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead | + MemoryProt::CpuReadWrite | MemoryProt::GpuRead | + MemoryProt::GpuWrite | MemoryProt::GpuReadWrite; + + MemoryProt invalid_flags = prot & ~valid_flags; + if (u32(invalid_flags) != 0 && u32(invalid_flags) != u32(MemoryProt::NoAccess)) { + LOG_ERROR(Core, "Invalid protection flags: prot = {:#x}, invalid flags = {:#x}", u32(prot), + u32(invalid_flags)); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + // Change protection + vma.prot = prot; + + // Set permissions + Core::MemoryPermission perms{}; + + if (True(prot & MemoryProt::CpuRead)) { + perms |= Core::MemoryPermission::Read; + } + if (True(prot & MemoryProt::CpuReadWrite)) { + perms |= Core::MemoryPermission::ReadWrite; + } + if (True(prot & MemoryProt::GpuRead)) { + perms |= Core::MemoryPermission::Read; + } + if (True(prot & MemoryProt::GpuWrite)) { + perms |= Core::MemoryPermission::Write; + } + if (True(prot & MemoryProt::GpuReadWrite)) { + perms |= Core::MemoryPermission::ReadWrite; + } + + impl.Protect(addr, size, perms); + + return ORBIS_OK; +} + +int MemoryManager::MTypeProtect(VAddr addr, size_t size, VMAType mtype, MemoryProt prot) { + std::scoped_lock lk{mutex}; + + // Find the virtual memory area that contains the specified address range. + auto it = FindVMA(addr); + if (it == vma_map.end() || !it->second.Contains(addr, size)) { + LOG_ERROR(Core, "Address range not mapped"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + VirtualMemoryArea& vma = it->second; + + if (vma.type == VMAType::Free) { + LOG_ERROR(Core, "Cannot change protection on free memory region"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + // Validate protection flags + constexpr static MemoryProt valid_flags = MemoryProt::NoAccess | MemoryProt::CpuRead | + MemoryProt::CpuReadWrite | MemoryProt::GpuRead | + MemoryProt::GpuWrite | MemoryProt::GpuReadWrite; + + MemoryProt invalid_flags = prot & ~valid_flags; + if (u32(invalid_flags) != 0 && u32(invalid_flags) != u32(MemoryProt::NoAccess)) { + LOG_ERROR(Core, "Invalid protection flags: prot = {:#x}, invalid flags = {:#x}", u32(prot), + u32(invalid_flags)); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + // Change type and protection + vma.type = mtype; + vma.prot = prot; + + // Set permissions + Core::MemoryPermission perms{}; + + if (True(prot & MemoryProt::CpuRead)) { + perms |= Core::MemoryPermission::Read; + } + if (True(prot & MemoryProt::CpuReadWrite)) { + perms |= Core::MemoryPermission::ReadWrite; + } + if (True(prot & MemoryProt::GpuRead)) { + perms |= Core::MemoryPermission::Read; + } + if (True(prot & MemoryProt::GpuWrite)) { + perms |= Core::MemoryPermission::Write; + } + if (True(prot & MemoryProt::GpuReadWrite)) { + perms |= Core::MemoryPermission::ReadWrite; + } + + impl.Protect(addr, size, perms); + + return ORBIS_OK; +} + int MemoryManager::VirtualQuery(VAddr addr, int flags, ::Libraries::Kernel::OrbisVirtualQueryInfo* info) { std::scoped_lock lk{mutex}; diff --git a/src/core/memory.h b/src/core/memory.h index 919995b0c..d0935ffb7 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -30,6 +30,7 @@ enum class MemoryProt : u32 { GpuWrite = 32, GpuReadWrite = 38, }; +DECLARE_ENUM_FLAG_OPERATORS(MemoryProt) enum class MemoryMapFlags : u32 { NoFlags = 0, @@ -163,6 +164,10 @@ public: int QueryProtection(VAddr addr, void** start, void** end, u32* prot); + int Protect(VAddr addr, size_t size, MemoryProt prot); + + int MTypeProtect(VAddr addr, size_t size, VMAType mtype, MemoryProt prot); + int VirtualQuery(VAddr addr, int flags, ::Libraries::Kernel::OrbisVirtualQueryInfo* info); int DirectMemoryQuery(PAddr addr, bool find_next, From 28feb779821a00b5c2d944e991d813de662cd921 Mon Sep 17 00:00:00 2001 From: psucien <168137814+psucien@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:47:57 +0200 Subject: [PATCH 17/23] Surface management rework (3/3) (#370) * texture_cache: images overlap support * renderer_vk: log messages on surfaces which require degamma * missing barriers * forced sync2 + better barriers * Handling of depth target aliasing; added formats compatibility check * Don't bind empty texel buffers * Promote r32f textures to depth target if shader expects so * Promote textures to depth if they use depth tiling * fix for image leaking; detiler stream buffer removed --- CMakeLists.txt | 1 + src/video_core/buffer_cache/buffer.h | 21 + src/video_core/buffer_cache/buffer_cache.cpp | 4 +- src/video_core/buffer_cache/buffer_cache.h | 2 +- .../renderer_vulkan/vk_compute_pipeline.cpp | 24 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 25 +- .../renderer_vulkan/vk_instance.cpp | 1 + .../renderer_vulkan/vk_pipeline_cache.cpp | 8 + .../renderer_vulkan/vk_rasterizer.cpp | 4 + .../texture_cache/host_compatibility.h | 391 ++++++++++++++++++ src/video_core/texture_cache/image.cpp | 68 +++ src/video_core/texture_cache/image.h | 5 + src/video_core/texture_cache/image_info.cpp | 83 +++- src/video_core/texture_cache/image_info.h | 12 +- .../texture_cache/texture_cache.cpp | 236 ++++++++--- src/video_core/texture_cache/texture_cache.h | 21 +- src/video_core/texture_cache/tile_manager.cpp | 10 +- src/video_core/texture_cache/tile_manager.h | 1 - src/video_core/texture_cache/types.h | 2 + 19 files changed, 847 insertions(+), 72 deletions(-) create mode 100644 src/video_core/texture_cache/host_compatibility.h diff --git a/CMakeLists.txt b/CMakeLists.txt index de8753dbe..2da9465cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -553,6 +553,7 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp src/video_core/texture_cache/tile_manager.cpp src/video_core/texture_cache/tile_manager.h src/video_core/texture_cache/types.h + src/video_core/texture_cache/host_compatibility.h src/video_core/page_manager.cpp src/video_core/page_manager.h src/video_core/multi_level_page_table.h diff --git a/src/video_core/buffer_cache/buffer.h b/src/video_core/buffer_cache/buffer.h index 26d48eaef..334975788 100644 --- a/src/video_core/buffer_cache/buffer.h +++ b/src/video_core/buffer_cache/buffer.h @@ -118,6 +118,25 @@ public: return buffer; } + std::optional GetBarrier(vk::AccessFlagBits2 dst_acess_mask, + vk::PipelineStageFlagBits2 dst_stage) { + if (dst_acess_mask == access_mask && stage == dst_stage) { + return {}; + } + + auto barrier = vk::BufferMemoryBarrier2{ + .srcStageMask = stage, + .srcAccessMask = access_mask, + .dstStageMask = dst_stage, + .dstAccessMask = dst_acess_mask, + .buffer = buffer.buffer, + .size = size_bytes, + }; + access_mask = dst_acess_mask; + stage = dst_stage; + return barrier; + } + public: VAddr cpu_addr = 0; bool is_picked{}; @@ -128,6 +147,8 @@ public: const Vulkan::Instance* instance{}; MemoryUsage usage; UniqueBuffer buffer; + vk::AccessFlagBits2 access_mask{vk::AccessFlagBits2::eNone}; + vk::PipelineStageFlagBits2 stage{vk::PipelineStageFlagBits2::eNone}; struct BufferView { u32 offset; u32 size; diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index 93e05085d..d67e953eb 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -248,11 +248,11 @@ std::pair BufferCache::ObtainBuffer(VAddr device_addr, u32 size, b return {&buffer, buffer.Offset(device_addr)}; } -std::pair BufferCache::ObtainTempBuffer(VAddr gpu_addr, u32 size) { +std::pair BufferCache::ObtainTempBuffer(VAddr gpu_addr, u32 size) { const u64 page = gpu_addr >> CACHING_PAGEBITS; const BufferId buffer_id = page_table[page]; if (buffer_id) { - const Buffer& buffer = slot_buffers[buffer_id]; + Buffer& buffer = slot_buffers[buffer_id]; if (buffer.IsInBounds(gpu_addr, size)) { return {&buffer, buffer.Offset(gpu_addr)}; } diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index b9002cea2..9be258ab9 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -70,7 +70,7 @@ public: bool is_texel_buffer = false); /// Obtains a temporary buffer for usage in texture cache. - [[nodiscard]] std::pair ObtainTempBuffer(VAddr gpu_addr, u32 size); + [[nodiscard]] std::pair ObtainTempBuffer(VAddr gpu_addr, u32 size); /// Return true when a region is registered on the cache [[nodiscard]] bool IsRegionRegistered(VAddr addr, size_t size); diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 1d9001238..b1a23532d 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -104,6 +104,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, boost::container::static_vector buffer_infos; boost::container::static_vector image_infos; boost::container::small_vector set_writes; + boost::container::small_vector buffer_barriers; Shader::PushData push_data{}; u32 binding{}; @@ -153,9 +154,9 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, for (const auto& desc : info->texture_buffers) { const auto vsharp = desc.GetSharp(*info); vk::BufferView& buffer_view = buffer_views.emplace_back(VK_NULL_HANDLE); - if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) { + const u32 size = vsharp.GetSize(); + if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) { const VAddr address = vsharp.base_address; - const u32 size = vsharp.GetSize(); if (desc.is_written) { if (texture_cache.TouchMeta(address, true)) { LOG_TRACE(Render_Vulkan, "Metadata update skipped"); @@ -183,6 +184,13 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, } buffer_view = vk_buffer->View(offset_aligned, size + adjust, desc.is_written, vsharp.GetDataFmt(), vsharp.GetNumberFmt()); + + if (auto barrier = + vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite + : vk::AccessFlagBits2::eShaderRead, + vk::PipelineStageFlagBits2::eComputeShader)) { + buffer_barriers.emplace_back(*barrier); + } } set_writes.push_back({ .dstSet = VK_NULL_HANDLE, @@ -222,6 +230,9 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, } for (const auto& sampler : info->samplers) { const auto ssharp = sampler.GetSharp(*info); + if (ssharp.force_degamma) { + LOG_WARNING(Render_Vulkan, "Texture requires gamma correction"); + } const auto vk_sampler = texture_cache.GetSampler(ssharp); image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral); set_writes.push_back({ @@ -239,6 +250,15 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, } const auto cmdbuf = scheduler.CommandBuffer(); + + if (!buffer_barriers.empty()) { + auto dependencies = vk::DependencyInfo{ + .bufferMemoryBarrierCount = u32(buffer_barriers.size()), + .pBufferMemoryBarriers = buffer_barriers.data(), + }; + cmdbuf.pipelineBarrier2(dependencies); + } + cmdbuf.pushConstants(*pipeline_layout, vk::ShaderStageFlagBits::eCompute, 0u, sizeof(push_data), &push_data); cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0, set_writes); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index f03e5d5de..5aec456fb 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -359,6 +359,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, boost::container::static_vector buffer_infos; boost::container::static_vector image_infos; boost::container::small_vector set_writes; + boost::container::small_vector buffer_barriers; Shader::PushData push_data{}; u32 binding{}; @@ -407,9 +408,9 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, for (const auto& tex_buffer : stage->texture_buffers) { const auto vsharp = tex_buffer.GetSharp(*stage); vk::BufferView& buffer_view = buffer_views.emplace_back(VK_NULL_HANDLE); - if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) { + const u32 size = vsharp.GetSize(); + if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) { const VAddr address = vsharp.base_address; - const u32 size = vsharp.GetSize(); const u32 alignment = instance.TexelBufferMinAlignment(); const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(address, size, tex_buffer.is_written, true); @@ -424,6 +425,12 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, } buffer_view = vk_buffer->View(offset_aligned, size + adjust, tex_buffer.is_written, vsharp.GetDataFmt(), vsharp.GetNumberFmt()); + const auto dst_access = tex_buffer.is_written ? vk::AccessFlagBits2::eShaderWrite + : vk::AccessFlagBits2::eShaderRead; + if (auto barrier = vk_buffer->GetBarrier( + dst_access, vk::PipelineStageFlagBits2::eVertexShader)) { + buffer_barriers.emplace_back(*barrier); + } } set_writes.push_back({ .dstSet = VK_NULL_HANDLE, @@ -441,7 +448,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, const auto tsharp = image_desc.GetSharp(*stage); if (tsharp) { tsharps.emplace_back(tsharp); - VideoCore::ImageInfo image_info{tsharp}; + VideoCore::ImageInfo image_info{tsharp, image_desc.is_depth}; VideoCore::ImageViewInfo view_info{tsharp, image_desc.is_storage}; const auto& image_view = texture_cache.FindTexture(image_info, view_info); const auto& image = texture_cache.GetImage(image_view.image_id); @@ -465,6 +472,9 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, } for (const auto& sampler : stage->samplers) { auto ssharp = sampler.GetSharp(*stage); + if (ssharp.force_degamma) { + LOG_WARNING(Render_Vulkan, "Texture requires gamma correction"); + } if (sampler.disable_aniso) { const auto& tsharp = tsharps[sampler.associated_image]; if (tsharp.base_level == 0 && tsharp.last_level == 0) { @@ -485,6 +495,15 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, } const auto cmdbuf = scheduler.CommandBuffer(); + + if (!buffer_barriers.empty()) { + auto dependencies = vk::DependencyInfo{ + .bufferMemoryBarrierCount = u32(buffer_barriers.size()), + .pBufferMemoryBarriers = buffer_barriers.data(), + }; + cmdbuf.pipelineBarrier2(dependencies); + } + if (!set_writes.empty()) { cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0, set_writes); diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 395f71981..c0105d8f9 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -228,6 +228,7 @@ bool Instance::CreateDevice() { const bool maintenance5 = add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); add_extension(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME); + add_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME); #ifdef __APPLE__ // Required by Vulkan spec if supported. diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 6a8e0f137..33971cc5a 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -145,6 +145,14 @@ const GraphicsPipeline* PipelineCache::GetGraphicsPipeline() { LOG_TRACE(Render_Vulkan, "FMask decompression pass skipped"); return nullptr; } + if (regs.depth_render_control.depth_compress_disable) { + LOG_TRACE(Render_Vulkan, "HTile decompress skipped (depth)"); + return nullptr; + } + if (regs.depth_render_control.stencil_compress_disable) { + LOG_TRACE(Render_Vulkan, "HTile decompress skipped (stencil)"); + return nullptr; + } if (!RefreshGraphicsKey()) { return nullptr; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 5a20899db..4207c18d6 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -179,6 +179,10 @@ void Rasterizer::BeginRendering() { const auto& regs = liverpool->regs; RenderState state; + if (regs.color_control.degamma_enable) { + LOG_WARNING(Render_Vulkan, "Color buffers require gamma correction"); + } + for (auto col_buf_id = 0u; col_buf_id < Liverpool::NumColorBuffers; ++col_buf_id) { const auto& col_buf = regs.color_buffers[col_buf_id]; if (!col_buf) { diff --git a/src/video_core/texture_cache/host_compatibility.h b/src/video_core/texture_cache/host_compatibility.h new file mode 100644 index 000000000..0b4b6764e --- /dev/null +++ b/src/video_core/texture_cache/host_compatibility.h @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) +// Copyright © 2015-2023 The Khronos Group Inc. +// Copyright © 2015-2023 Valve Corporation +// Copyright © 2015-2023 LunarG, Inc. + +#pragma once + +#include +#include + +namespace VideoCore { +/** + * @brief All classes of format compatibility according to the Vulkan specification + * @url + * https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/d37c676f75f545a3e5a98d7dfb89864391a1db1e/layers/generated/vk_format_utils.h#L47-L131 + * @note This is copied directly from Vulkan Validation Layers and doesn't follow the Skyline naming + * conventions + */ +enum class FORMAT_COMPATIBILITY_CLASS { + NONE = 0, + _10BIT_2PLANE_420, + _10BIT_2PLANE_422, + _10BIT_2PLANE_444, + _10BIT_3PLANE_420, + _10BIT_3PLANE_422, + _10BIT_3PLANE_444, + _12BIT_2PLANE_420, + _12BIT_2PLANE_422, + _12BIT_2PLANE_444, + _12BIT_3PLANE_420, + _12BIT_3PLANE_422, + _12BIT_3PLANE_444, + _128BIT, + _16BIT, + _16BIT_2PLANE_420, + _16BIT_2PLANE_422, + _16BIT_2PLANE_444, + _16BIT_3PLANE_420, + _16BIT_3PLANE_422, + _16BIT_3PLANE_444, + _192BIT, + _24BIT, + _256BIT, + _32BIT, + _32BIT_B8G8R8G8, + _32BIT_G8B8G8R8, + _48BIT, + _64BIT, + _64BIT_B10G10R10G10, + _64BIT_B12G12R12G12, + _64BIT_B16G16R16G16, + _64BIT_G10B10G10R10, + _64BIT_G12B12G12R12, + _64BIT_G16B16G16R16, + _64BIT_R10G10B10A10, + _64BIT_R12G12B12A12, + _8BIT, + _8BIT_2PLANE_420, + _8BIT_2PLANE_422, + _8BIT_2PLANE_444, + _8BIT_3PLANE_420, + _8BIT_3PLANE_422, + _8BIT_3PLANE_444, + _96BIT, + ASTC_10X10, + ASTC_10X5, + ASTC_10X6, + ASTC_10X8, + ASTC_12X10, + ASTC_12X12, + ASTC_4X4, + ASTC_5X4, + ASTC_5X5, + ASTC_6X5, + ASTC_6X6, + ASTC_8X5, + ASTC_8X6, + ASTC_8X8, + BC1_RGB, + BC1_RGBA, + BC2, + BC3, + BC4, + BC5, + BC6H, + BC7, + D16, + D16S8, + D24, + D24S8, + D32, + D32S8, + EAC_R, + EAC_RG, + ETC2_EAC_RGBA, + ETC2_RGB, + ETC2_RGBA, + PVRTC1_2BPP, + PVRTC1_4BPP, + PVRTC2_2BPP, + PVRTC2_4BPP, + S8 +}; + +/** + * @brief The format compatibility class according to the Vulkan specification + * @url + * https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#formats-compatibility-classes + * @url + * https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/d37c676f75f545a3e5a98d7dfb89864391a1db1e/layers/generated/vk_format_utils.cpp#L70-L812 + * @note This is copied directly from Vulkan Validation Layers and doesn't follow the Skyline naming + * conventions + */ +static const std::unordered_map vkFormatClassTable{ + {VK_FORMAT_A1R5G5B5_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_A2B10G10R10_SINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2B10G10R10_SNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2B10G10R10_SSCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2B10G10R10_UINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2B10G10R10_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2B10G10R10_USCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2R10G10B10_SINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2R10G10B10_SNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2R10G10B10_SSCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2R10G10B10_UINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2R10G10B10_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A2R10G10B10_USCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_A8B8G8R8_SINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A8B8G8R8_SNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A8B8G8R8_SRGB_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A8B8G8R8_SSCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A8B8G8R8_UINT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A8B8G8R8_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_A8B8G8R8_USCALED_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X10}, + {VK_FORMAT_ASTC_10x10_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X10}, + {VK_FORMAT_ASTC_10x10_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X10}, + {VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X5}, + {VK_FORMAT_ASTC_10x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X5}, + {VK_FORMAT_ASTC_10x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X5}, + {VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X6}, + {VK_FORMAT_ASTC_10x6_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X6}, + {VK_FORMAT_ASTC_10x6_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X6}, + {VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_10X8}, + {VK_FORMAT_ASTC_10x8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X8}, + {VK_FORMAT_ASTC_10x8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_10X8}, + {VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_12X10}, + {VK_FORMAT_ASTC_12x10_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X10}, + {VK_FORMAT_ASTC_12x10_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X10}, + {VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_12X12}, + {VK_FORMAT_ASTC_12x12_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X12}, + {VK_FORMAT_ASTC_12x12_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_12X12}, + {VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_4X4}, + {VK_FORMAT_ASTC_4x4_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_4X4}, + {VK_FORMAT_ASTC_4x4_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_4X4}, + {VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_5X4}, + {VK_FORMAT_ASTC_5x4_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X4}, + {VK_FORMAT_ASTC_5x4_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X4}, + {VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_5X5}, + {VK_FORMAT_ASTC_5x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X5}, + {VK_FORMAT_ASTC_5x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_5X5}, + {VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_6X5}, + {VK_FORMAT_ASTC_6x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X5}, + {VK_FORMAT_ASTC_6x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X5}, + {VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_6X6}, + {VK_FORMAT_ASTC_6x6_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X6}, + {VK_FORMAT_ASTC_6x6_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_6X6}, + {VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_8X5}, + {VK_FORMAT_ASTC_8x5_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X5}, + {VK_FORMAT_ASTC_8x5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X5}, + {VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_8X6}, + {VK_FORMAT_ASTC_8x6_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X6}, + {VK_FORMAT_ASTC_8x6_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X6}, + {VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT, FORMAT_COMPATIBILITY_CLASS::ASTC_8X8}, + {VK_FORMAT_ASTC_8x8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X8}, + {VK_FORMAT_ASTC_8x8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ASTC_8X8}, + {VK_FORMAT_B10G11R11_UFLOAT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, + FORMAT_COMPATIBILITY_CLASS::_64BIT_B10G10R10G10}, + {VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, + FORMAT_COMPATIBILITY_CLASS::_64BIT_B12G12R12G12}, + {VK_FORMAT_B16G16R16G16_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT_B16G16R16G16}, + {VK_FORMAT_B4G4R4A4_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_B5G5R5A1_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_B5G6R5_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_B8G8R8A8_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B8G8R8A8_SNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B8G8R8A8_SRGB, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B8G8R8A8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B8G8R8A8_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B8G8R8A8_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B8G8R8A8_USCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_B8G8R8G8_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT_B8G8R8G8}, + {VK_FORMAT_B8G8R8_SINT, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_B8G8R8_SNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_B8G8R8_SRGB, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_B8G8R8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_B8G8R8_UINT, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_B8G8R8_UNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_B8G8R8_USCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_BC1_RGBA_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGBA}, + {VK_FORMAT_BC1_RGBA_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGBA}, + {VK_FORMAT_BC1_RGB_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGB}, + {VK_FORMAT_BC1_RGB_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC1_RGB}, + {VK_FORMAT_BC2_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC2}, + {VK_FORMAT_BC2_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC2}, + {VK_FORMAT_BC3_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC3}, + {VK_FORMAT_BC3_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC3}, + {VK_FORMAT_BC4_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC4}, + {VK_FORMAT_BC4_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC4}, + {VK_FORMAT_BC5_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC5}, + {VK_FORMAT_BC5_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC5}, + {VK_FORMAT_BC6H_SFLOAT_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC6H}, + {VK_FORMAT_BC6H_UFLOAT_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC6H}, + {VK_FORMAT_BC7_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC7}, + {VK_FORMAT_BC7_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::BC7}, + {VK_FORMAT_D16_UNORM, FORMAT_COMPATIBILITY_CLASS::D16}, + {VK_FORMAT_D16_UNORM_S8_UINT, FORMAT_COMPATIBILITY_CLASS::D16S8}, + {VK_FORMAT_D24_UNORM_S8_UINT, FORMAT_COMPATIBILITY_CLASS::D24S8}, + {VK_FORMAT_D32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::D32}, + {VK_FORMAT_D32_SFLOAT_S8_UINT, FORMAT_COMPATIBILITY_CLASS::D32S8}, + {VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_EAC_R11G11_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_RG}, + {VK_FORMAT_EAC_R11G11_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_RG}, + {VK_FORMAT_EAC_R11_SNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_R}, + {VK_FORMAT_EAC_R11_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::EAC_R}, + {VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGBA}, + {VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGBA}, + {VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_EAC_RGBA}, + {VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_EAC_RGBA}, + {VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGB}, + {VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, FORMAT_COMPATIBILITY_CLASS::ETC2_RGB}, + {VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, + FORMAT_COMPATIBILITY_CLASS::_64BIT_G10B10G10R10}, + {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_10BIT_2PLANE_420}, + {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_10BIT_2PLANE_422}, + {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT, + FORMAT_COMPATIBILITY_CLASS::_10BIT_2PLANE_444}, + {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_10BIT_3PLANE_420}, + {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_10BIT_3PLANE_422}, + {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_10BIT_3PLANE_444}, + {VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, + FORMAT_COMPATIBILITY_CLASS::_64BIT_G12B12G12R12}, + {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_12BIT_2PLANE_420}, + {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_12BIT_2PLANE_422}, + {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT, + FORMAT_COMPATIBILITY_CLASS::_12BIT_2PLANE_444}, + {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_12BIT_3PLANE_420}, + {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_12BIT_3PLANE_422}, + {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, + FORMAT_COMPATIBILITY_CLASS::_12BIT_3PLANE_444}, + {VK_FORMAT_G16B16G16R16_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT_G16B16G16R16}, + {VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_2PLANE_420}, + {VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_2PLANE_422}, + {VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT, FORMAT_COMPATIBILITY_CLASS::_16BIT_2PLANE_444}, + {VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_3PLANE_420}, + {VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_3PLANE_422}, + {VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT_3PLANE_444}, + {VK_FORMAT_G8B8G8R8_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT_G8B8G8R8}, + {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_2PLANE_420}, + {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_2PLANE_422}, + {VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT, FORMAT_COMPATIBILITY_CLASS::_8BIT_2PLANE_444}, + {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_3PLANE_420}, + {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_3PLANE_422}, + {VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT_3PLANE_444}, + {VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_2BPP}, + {VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_2BPP}, + {VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_4BPP}, + {VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC1_4BPP}, + {VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_2BPP}, + {VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_2BPP}, + {VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_4BPP}, + {VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, FORMAT_COMPATIBILITY_CLASS::PVRTC2_4BPP}, + {VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, FORMAT_COMPATIBILITY_CLASS::_64BIT_R10G10B10A10}, + {VK_FORMAT_R10X6G10X6_UNORM_2PACK16, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R10X6_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, FORMAT_COMPATIBILITY_CLASS::_64BIT_R12G12B12A12}, + {VK_FORMAT_R12X4G12X4_UNORM_2PACK16, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R12X4_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R16G16B16A16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R16G16B16A16_SINT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R16G16B16A16_SNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R16G16B16A16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R16G16B16A16_UINT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R16G16B16A16_UNORM, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R16G16B16A16_USCALED, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R16G16B16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_48BIT}, + {VK_FORMAT_R16G16B16_SINT, FORMAT_COMPATIBILITY_CLASS::_48BIT}, + {VK_FORMAT_R16G16B16_SNORM, FORMAT_COMPATIBILITY_CLASS::_48BIT}, + {VK_FORMAT_R16G16B16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_48BIT}, + {VK_FORMAT_R16G16B16_UINT, FORMAT_COMPATIBILITY_CLASS::_48BIT}, + {VK_FORMAT_R16G16B16_UNORM, FORMAT_COMPATIBILITY_CLASS::_48BIT}, + {VK_FORMAT_R16G16B16_USCALED, FORMAT_COMPATIBILITY_CLASS::_48BIT}, + {VK_FORMAT_R16G16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R16G16_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R16G16_SNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R16G16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R16G16_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R16G16_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R16G16_USCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R16_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R16_SINT, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R16_SNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R16_SSCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R16_UINT, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R16_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R16_USCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R32G32B32A32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_128BIT}, + {VK_FORMAT_R32G32B32A32_SINT, FORMAT_COMPATIBILITY_CLASS::_128BIT}, + {VK_FORMAT_R32G32B32A32_UINT, FORMAT_COMPATIBILITY_CLASS::_128BIT}, + {VK_FORMAT_R32G32B32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_96BIT}, + {VK_FORMAT_R32G32B32_SINT, FORMAT_COMPATIBILITY_CLASS::_96BIT}, + {VK_FORMAT_R32G32B32_UINT, FORMAT_COMPATIBILITY_CLASS::_96BIT}, + {VK_FORMAT_R32G32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R32G32_SINT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R32G32_UINT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R32_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R32_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R32_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R4G4B4A4_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R4G4_UNORM_PACK8, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_R5G5B5A1_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R5G6B5_UNORM_PACK16, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R64G64B64A64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_256BIT}, + {VK_FORMAT_R64G64B64A64_SINT, FORMAT_COMPATIBILITY_CLASS::_256BIT}, + {VK_FORMAT_R64G64B64A64_UINT, FORMAT_COMPATIBILITY_CLASS::_256BIT}, + {VK_FORMAT_R64G64B64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_192BIT}, + {VK_FORMAT_R64G64B64_SINT, FORMAT_COMPATIBILITY_CLASS::_192BIT}, + {VK_FORMAT_R64G64B64_UINT, FORMAT_COMPATIBILITY_CLASS::_192BIT}, + {VK_FORMAT_R64G64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_128BIT}, + {VK_FORMAT_R64G64_SINT, FORMAT_COMPATIBILITY_CLASS::_128BIT}, + {VK_FORMAT_R64G64_UINT, FORMAT_COMPATIBILITY_CLASS::_128BIT}, + {VK_FORMAT_R64_SFLOAT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R64_SINT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R64_UINT, FORMAT_COMPATIBILITY_CLASS::_64BIT}, + {VK_FORMAT_R8G8B8A8_SINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R8G8B8A8_SNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R8G8B8A8_SRGB, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R8G8B8A8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R8G8B8A8_UINT, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R8G8B8A8_UNORM, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R8G8B8A8_USCALED, FORMAT_COMPATIBILITY_CLASS::_32BIT}, + {VK_FORMAT_R8G8B8_SINT, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_R8G8B8_SNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_R8G8B8_SRGB, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_R8G8B8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_R8G8B8_UINT, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_R8G8B8_UNORM, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_R8G8B8_USCALED, FORMAT_COMPATIBILITY_CLASS::_24BIT}, + {VK_FORMAT_R8G8_SINT, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R8G8_SNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R8G8_SRGB, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R8G8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R8G8_UINT, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R8G8_UNORM, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R8G8_USCALED, FORMAT_COMPATIBILITY_CLASS::_16BIT}, + {VK_FORMAT_R8_SINT, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_R8_SNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_R8_SRGB, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_R8_SSCALED, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_R8_UINT, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_R8_UNORM, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_R8_USCALED, FORMAT_COMPATIBILITY_CLASS::_8BIT}, + {VK_FORMAT_S8_UINT, FORMAT_COMPATIBILITY_CLASS::S8}, + {VK_FORMAT_X8_D24_UNORM_PACK32, FORMAT_COMPATIBILITY_CLASS::D24}, + {VK_FORMAT_UNDEFINED, FORMAT_COMPATIBILITY_CLASS::NONE}, +}; + +/** + * @return If the two formats are compatible according to Vulkan's format compatibility rules + * @url + * https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#formats-compatibility + */ +static bool IsVulkanFormatCompatible(VkFormat lhs, VkFormat rhs) { + if (lhs == rhs) + return true; + return vkFormatClassTable.at(lhs) == vkFormatClassTable.at(rhs); +} +} // namespace VideoCore diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index 0d20eaeab..13ea7ce93 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -242,6 +242,74 @@ void Image::Upload(vk::Buffer buffer, u64 offset) { vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead); } +void Image::CopyImage(const Image& image) { + scheduler->EndRendering(); + Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite); + + auto cmdbuf = scheduler->CommandBuffer(); + + boost::container::small_vector image_copy{}; + for (u32 m = 0; m < image.info.resources.levels; ++m) { + const auto mip_w = std::max(info.size.width >> m, 1u); + const auto mip_h = std::max(info.size.height >> m, 1u); + const auto mip_d = std::max(info.size.depth >> m, 1u); + + image_copy.emplace_back(vk::ImageCopy{ + .srcSubresource{ + .aspectMask = image.aspect_mask, + .mipLevel = m, + .baseArrayLayer = 0, + .layerCount = image.info.resources.layers, + }, + .dstSubresource{ + .aspectMask = image.aspect_mask, + .mipLevel = m, + .baseArrayLayer = 0, + .layerCount = image.info.resources.layers, + }, + .extent = {mip_w, mip_h, mip_d}, + }); + } + cmdbuf.copyImage(image.image, image.layout, this->image, this->layout, image_copy); + + Transit(vk::ImageLayout::eGeneral, + vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead); +} + +void Image::CopyMip(const Image& image, u32 mip) { + scheduler->EndRendering(); + Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eTransferWrite); + + auto cmdbuf = scheduler->CommandBuffer(); + + const auto mip_w = std::max(info.size.width >> mip, 1u); + const auto mip_h = std::max(info.size.height >> mip, 1u); + const auto mip_d = std::max(info.size.depth >> mip, 1u); + + ASSERT(mip_w == image.info.size.width); + ASSERT(mip_h == image.info.size.height); + + const vk::ImageCopy image_copy{ + .srcSubresource{ + .aspectMask = image.aspect_mask, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = image.info.resources.layers, + }, + .dstSubresource{ + .aspectMask = image.aspect_mask, + .mipLevel = mip, + .baseArrayLayer = 0, + .layerCount = info.resources.layers, + }, + .extent = {mip_w, mip_h, mip_d}, + }; + cmdbuf.copyImage(image.image, image.layout, this->image, this->layout, image_copy); + + Transit(vk::ImageLayout::eGeneral, + vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead); +} + Image::~Image() = default; } // namespace VideoCore diff --git a/src/video_core/texture_cache/image.h b/src/video_core/texture_cache/image.h index 3df8ddb70..f932b25a0 100644 --- a/src/video_core/texture_cache/image.h +++ b/src/video_core/texture_cache/image.h @@ -32,6 +32,7 @@ enum ImageFlagBits : u32 { Registered = 1 << 6, ///< True when the image is registered Picked = 1 << 7, ///< Temporary flag to mark the image as picked MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered + Deleted = 1 << 9, ///< Indicates that images was marked for deletion once frame is done }; DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits) @@ -95,6 +96,9 @@ struct Image { vk::CommandBuffer cmdbuf = {}); void Upload(vk::Buffer buffer, u64 offset); + void CopyImage(const Image& image); + void CopyMip(const Image& image, u32 mip); + const Vulkan::Instance* instance; Vulkan::Scheduler* scheduler; ImageInfo info; @@ -112,6 +116,7 @@ struct Image { vk::Flags access_mask = vk::AccessFlagBits::eNone; vk::ImageLayout layout = vk::ImageLayout::eUndefined; boost::container::small_vector mip_hashes; + u64 tick_accessed_last{0}; }; } // namespace VideoCore diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index 4ac4aee8f..bd4671688 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp @@ -174,6 +174,7 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, const auto color_slice_sz = buffer.GetColorSliceSize(); guest_size_bytes = color_slice_sz * buffer.NumSlices(); mips_layout.emplace_back(color_slice_sz, pitch, 0); + tiling_idx = static_cast(buffer.attrib.tile_mode_index.Value()); } ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, @@ -199,9 +200,19 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slice mips_layout.emplace_back(depth_slice_sz, pitch, 0); } -ImageInfo::ImageInfo(const AmdGpu::Image& image) noexcept { +ImageInfo::ImageInfo(const AmdGpu::Image& image, bool force_depth /*= false*/) noexcept { tiling_mode = image.GetTilingMode(); pixel_format = LiverpoolToVK::SurfaceFormat(image.GetDataFmt(), image.GetNumberFmt()); + // Override format if image is forced to be a depth target + if (force_depth || tiling_mode == AmdGpu::TilingMode::Depth_MacroTiled) { + if (pixel_format == vk::Format::eR32Sfloat) { + pixel_format = vk::Format::eD32SfloatS8Uint; + } else if (pixel_format == vk::Format::eR16Sfloat) { + pixel_format = vk::Format::eD16UnormS8Uint; + } else { + UNREACHABLE(); + } + } type = ConvertImageType(image.GetType()); props.is_tiled = image.IsTiled(); props.is_cube = image.GetType() == AmdGpu::ImageType::Cube; @@ -287,4 +298,74 @@ void ImageInfo::UpdateSize() { guest_size_bytes *= resources.layers; } +bool ImageInfo::IsMipOf(const ImageInfo& info) const { + if (!IsCompatible(info)) { + return false; + } + + // Currently we expect only on level to be copied. + if (resources.levels != 1) { + return false; + } + + const int mip = info.resources.levels - resources.levels; + if (mip < 1) { + return false; + } + + const auto mip_w = std::max(info.size.width >> mip, 1u); + const auto mip_h = std::max(info.size.height >> mip, 1u); + if ((size.width != mip_w) || (size.height != mip_h)) { + return false; + } + + const auto mip_d = std::max(info.size.depth >> mip, 1u); + if (info.type == vk::ImageType::e3D && type == vk::ImageType::e2D) { + // In case of 2D array to 3D copy, make sure we have proper number of layers. + if (resources.layers != mip_d) { + return false; + } + } else { + if (type != info.type) { + return false; + } + } + + // Check if the mip has correct size. + if (info.mips_layout.size() <= mip || info.mips_layout[mip].size != guest_size_bytes) { + return false; + } + + return true; +} + +bool ImageInfo::IsSliceOf(const ImageInfo& info) const { + if (!IsCompatible(info)) { + return false; + } + + // Array slices should be of the same type. + if (type != info.type) { + return false; + } + + // 2D dimensions of both images should be the same. + if ((size.width != info.size.width) || (size.height != info.size.height)) { + return false; + } + + // Check for size alignment. + const bool slice_size = info.guest_size_bytes / info.resources.layers; + if (guest_size_bytes % slice_size != 0) { + return false; + } + + // Ensure that address is aligned too. + if (((info.guest_address - guest_address) % guest_size_bytes) != 0) { + return false; + } + + return true; +} + } // namespace VideoCore diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h index ddad318d9..ba8985b8f 100644 --- a/src/video_core/texture_cache/image_info.h +++ b/src/video_core/texture_cache/image_info.h @@ -3,7 +3,6 @@ #pragma once -#include "common/enum.h" #include "common/types.h" #include "core/libraries/videoout/buffer.h" #include "video_core/amdgpu/liverpool.h" @@ -20,7 +19,7 @@ struct ImageInfo { const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, VAddr htile_address, const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; - ImageInfo(const AmdGpu::Image& image) noexcept; + ImageInfo(const AmdGpu::Image& image, bool force_depth = false) noexcept; bool IsTiled() const { return tiling_mode != AmdGpu::TilingMode::Display_Linear; @@ -29,6 +28,15 @@ struct ImageInfo { bool IsPacked() const; bool IsDepthStencil() const; + bool IsMipOf(const ImageInfo& info) const; + bool IsSliceOf(const ImageInfo& info) const; + + /// Verifies if images are compatible for subresource merging. + bool IsCompatible(const ImageInfo& info) const { + return (pixel_format == info.pixel_format && tiling_idx == info.tiling_idx && + num_samples == info.num_samples && num_bits == info.num_bits); + } + void UpdateSize(); struct { diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 3354a8ecb..90dc71409 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -1,18 +1,21 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include "common/assert.h" #include "video_core/buffer_cache/buffer_cache.h" #include "video_core/page_manager.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_scheduler.h" +#include "video_core/texture_cache/host_compatibility.h" #include "video_core/texture_cache/texture_cache.h" #include "video_core/texture_cache/tile_manager.h" namespace VideoCore { static constexpr u64 PageShift = 12; +static constexpr u64 NumFramesBeforeRemoval = 32; TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, BufferCache& buffer_cache_, PageManager& tracker_) @@ -43,7 +46,7 @@ void TextureCache::InvalidateMemory(VAddr address, size_t size) { // Ensure image is reuploaded when accessed again. image.flags |= ImageFlagBits::CpuModified; // Untrack image, so the range is unprotected and the guest can write freely. - UntrackImage(image, image_id); + UntrackImage(image_id); }); } @@ -53,46 +56,183 @@ void TextureCache::UnmapMemory(VAddr cpu_addr, size_t size) { boost::container::small_vector deleted_images; ForEachImageInRegion(cpu_addr, size, [&](ImageId id, Image&) { deleted_images.push_back(id); }); for (const ImageId id : deleted_images) { - Image& image = slot_images[id]; - if (True(image.flags & ImageFlagBits::Tracked)) { - UntrackImage(image, id); - } // TODO: Download image data back to host. - UnregisterImage(id); - DeleteImage(id); + FreeImage(id); } } +ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested_info, ImageId cache_image_id) { + const auto& cache_info = slot_images[cache_image_id].info; + + const bool was_bound_as_texture = + !cache_info.usage.depth_target && (cache_info.usage.texture || cache_info.usage.storage); + if (requested_info.usage.depth_target && was_bound_as_texture) { + auto new_image_id = slot_images.insert(instance, scheduler, requested_info); + RegisterImage(new_image_id); + + // auto& new_image = slot_images[new_image_id]; + // TODO: need to run a helper for depth copy here + + FreeImage(cache_image_id); + return new_image_id; + } + + const bool should_bind_as_texture = + !requested_info.usage.depth_target && + (requested_info.usage.texture || requested_info.usage.storage); + if (cache_info.usage.depth_target && should_bind_as_texture) { + return cache_image_id; + } + + return {}; +} + +ImageId TextureCache::ResolveOverlap(const ImageInfo& image_info, ImageId cache_image_id, + ImageId merged_image_id) { + auto& tex_cache_image = slot_images[cache_image_id]; + + if (image_info.guest_address == tex_cache_image.info.guest_address) { // Equal address + if (image_info.size != tex_cache_image.info.size) { + // Very likely this kind of overlap is caused by allocation from a pool. We can assume + // it is safe to delete the image if it wasn't accessed in some amount of frames. + if (scheduler.CurrentTick() - tex_cache_image.tick_accessed_last > + NumFramesBeforeRemoval) { + + FreeImage(cache_image_id); + } + return merged_image_id; + } + + if (auto depth_image_id = ResolveDepthOverlap(image_info, cache_image_id)) { + return depth_image_id; + } + + if (image_info.pixel_format != tex_cache_image.info.pixel_format || + image_info.size != tex_cache_image.info.size || + image_info.guest_size_bytes <= tex_cache_image.info.guest_size_bytes) { + return merged_image_id ? merged_image_id : cache_image_id; + } + + ImageId new_image_id{}; + if (image_info.type == tex_cache_image.info.type) { + new_image_id = ExpandImage(image_info, cache_image_id); + } else { + UNREACHABLE(); + } + return new_image_id; + } + + // Right overlap, the image requested is a possible subresource of the image from cache. + if (image_info.guest_address > tex_cache_image.info.guest_address) { + // Should be handled by view. No additional actions needed. + } else { + // Left overlap, the image from cache is a possible subresource of the image requested + if (!merged_image_id) { + // We need to have a larger, already allocated image to copy this one into + return {}; + } + + if (tex_cache_image.info.IsMipOf(image_info)) { + tex_cache_image.Transit(vk::ImageLayout::eTransferSrcOptimal, + vk::AccessFlagBits::eTransferRead); + + const auto num_mips_to_copy = tex_cache_image.info.resources.levels; + ASSERT(num_mips_to_copy == 1); + + auto& merged_image = slot_images[merged_image_id]; + merged_image.CopyMip(tex_cache_image, image_info.resources.levels - 1); + + FreeImage(cache_image_id); + } + + if (tex_cache_image.info.IsSliceOf(image_info)) { + UNREACHABLE(); + } + } + + return merged_image_id; +} + +ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId image_id) { + + const auto new_image_id = slot_images.insert(instance, scheduler, info); + RegisterImage(new_image_id); + + auto& src_image = slot_images[image_id]; + auto& new_image = slot_images[new_image_id]; + + src_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits::eTransferRead); + new_image.CopyImage(src_image); + + FreeImage(image_id); + + TrackImage(new_image_id); + new_image.flags &= ~ImageFlagBits::CpuModified; + return new_image_id; +} + ImageId TextureCache::FindImage(const ImageInfo& info) { if (info.guest_address == 0) [[unlikely]] { return NULL_IMAGE_VIEW_ID; } std::unique_lock lock{mutex}; - boost::container::small_vector image_ids; + boost::container::small_vector image_ids; ForEachImageInRegion( info.guest_address, info.guest_size_bytes, [&](ImageId image_id, Image& image) { - // Address and width must match. - if (image.cpu_addr != info.guest_address || image.info.size.width != info.size.width) { + // Ignore images scheduled for deletion + if (True(image.flags & ImageFlagBits::Deleted)) { return; } - if (info.IsDepthStencil() != image.info.IsDepthStencil() && - info.pixel_format != vk::Format::eR32Sfloat) { + + // Check if image is fully outside of the region + const auto in_image_cpu_addr = info.guest_address; + const auto in_image_cpu_addr_end = info.guest_address + info.guest_size_bytes; + if (in_image_cpu_addr_end <= image.cpu_addr) { return; } + if (in_image_cpu_addr >= image.cpu_addr_end) { + return; + } + image_ids.push_back(image_id); }); - // ASSERT_MSG(image_ids.size() <= 1, "Overlapping images not allowed!"); - ImageId image_id{}; - if (image_ids.empty()) { + + // Check for a perfect match first + for (const auto& cache_id : image_ids) { + auto& cache_image = slot_images[cache_id]; + + if (cache_image.info.guest_address == info.guest_address && + cache_image.info.guest_size_bytes == info.guest_size_bytes && + cache_image.info.size == info.size) { + + ASSERT(cache_image.info.type == info.type); + if (IsVulkanFormatCompatible((VkFormat)info.pixel_format, + (VkFormat)cache_image.info.pixel_format)) { + image_id = cache_id; + } + break; + } + } + + // Try to resolve overlaps (if any) + if (!image_id) { + for (const auto& cache_id : image_ids) { + const auto& merged_info = image_id ? slot_images[image_id].info : info; + image_id = ResolveOverlap(merged_info, cache_id, image_id); + } + } + + // Create and register a new image + if (!image_id) { image_id = slot_images.insert(instance, scheduler, info); RegisterImage(image_id); - } else { - image_id = image_ids[image_ids.size() > 1 ? 1 : 0]; } + slot_images[image_id].tick_accessed_last = scheduler.CurrentTick(); + return image_id; } @@ -135,31 +275,7 @@ ImageView& TextureCache::FindTexture(const ImageInfo& info, const ImageViewInfo& usage.texture = true; } - // These changes are temporary and should be removed once texture cache will handle subresources - // merging - auto view_info_tmp = view_info; - if (view_info_tmp.range.base.level > image.info.resources.levels - 1 || - view_info_tmp.range.base.layer > image.info.resources.layers - 1 || - view_info_tmp.range.extent.levels > image.info.resources.levels || - view_info_tmp.range.extent.layers > image.info.resources.layers) { - - LOG_DEBUG(Render_Vulkan, - "Subresource range ({}~{},{}~{}) exceeds base image extents ({},{})", - view_info_tmp.range.base.level, view_info_tmp.range.extent.levels, - view_info_tmp.range.base.layer, view_info_tmp.range.extent.layers, - image.info.resources.levels, image.info.resources.layers); - - view_info_tmp.range.base.level = - std::min(view_info_tmp.range.base.level, image.info.resources.levels - 1); - view_info_tmp.range.base.layer = - std::min(view_info_tmp.range.base.layer, image.info.resources.layers - 1); - view_info_tmp.range.extent.levels = - std::min(view_info_tmp.range.extent.levels, image.info.resources.levels); - view_info_tmp.range.extent.layers = - std::min(view_info_tmp.range.extent.layers, image.info.resources.layers); - } - - return RegisterImageView(image_id, view_info_tmp); + return RegisterImageView(image_id, view_info); } ImageView& TextureCache::FindRenderTarget(const ImageInfo& image_info, @@ -204,10 +320,18 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info, Image& image = slot_images[image_id]; image.flags |= ImageFlagBits::GpuModified; image.flags &= ~ImageFlagBits::CpuModified; - image.aspect_mask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil; + image.aspect_mask = vk::ImageAspectFlagBits::eDepth; - const auto new_layout = view_info.is_storage ? vk::ImageLayout::eDepthStencilAttachmentOptimal - : vk::ImageLayout::eDepthStencilReadOnlyOptimal; + const bool has_stencil = image_info.usage.stencil; + if (has_stencil) { + image.aspect_mask |= vk::ImageAspectFlagBits::eStencil; + } + + const auto new_layout = view_info.is_storage + ? has_stencil ? vk::ImageLayout::eDepthStencilAttachmentOptimal + : vk::ImageLayout::eDepthAttachmentOptimal + : has_stencil ? vk::ImageLayout::eDepthStencilReadOnlyOptimal + : vk::ImageLayout::eDepthReadOnlyOptimal; image.Transit(new_layout, vk::AccessFlagBits::eDepthStencilAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentRead); @@ -224,6 +348,7 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info, // Update tracked image usage image.info.usage.depth_target = true; + image.info.usage.stencil = has_stencil; return RegisterImageView(image_id, view_info); } @@ -260,7 +385,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule .bufferRowLength = static_cast(mip_pitch), .bufferImageHeight = static_cast(mip_height), .imageSubresource{ - .aspectMask = vk::ImageAspectFlagBits::eColor, + .aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .mipLevel = m, .baseArrayLayer = 0, .layerCount = num_layers, @@ -290,6 +415,17 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule const auto [vk_buffer, buf_offset] = buffer_cache.ObtainTempBuffer(image_addr, image_size); buffer = vk_buffer->Handle(); offset = buf_offset; + + // The obtained buffer may be written by a shader so we need to emit a barrier to prevent + // RAW hazard + if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead, + vk::PipelineStageFlagBits2::eTransfer)) { + auto dependencies = vk::DependencyInfo{ + .bufferMemoryBarrierCount = 1, + .pBufferMemoryBarriers = &barrier.value(), + }; + cmdbuf.pipelineBarrier2(dependencies); + } } for (auto& copy : image_copy) { @@ -335,7 +471,8 @@ void TextureCache::UnregisterImage(ImageId image_id) { }); } -void TextureCache::TrackImage(Image& image, ImageId image_id) { +void TextureCache::TrackImage(ImageId image_id) { + auto& image = slot_images[image_id]; if (True(image.flags & ImageFlagBits::Tracked)) { return; } @@ -343,7 +480,8 @@ void TextureCache::TrackImage(Image& image, ImageId image_id) { tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, 1); } -void TextureCache::UntrackImage(Image& image, ImageId image_id) { +void TextureCache::UntrackImage(ImageId image_id) { + auto& image = slot_images[image_id]; if (False(image.flags & ImageFlagBits::Tracked)) { return; } @@ -356,6 +494,8 @@ void TextureCache::DeleteImage(ImageId image_id) { ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked"); ASSERT_MSG(False(image.flags & ImageFlagBits::Registered), "Image was not unregistered"); + image.flags |= ImageFlagBits::Deleted; + // Remove any registered meta areas. const auto& meta_info = image.info.meta_info; if (meta_info.cmask_addr) { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 31b1e3939..142093967 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -65,9 +65,18 @@ public: return; } RefreshImage(image, custom_scheduler); - TrackImage(image, image_id); + TrackImage(image_id); } + [[nodiscard]] ImageId ResolveOverlap(const ImageInfo& info, ImageId cache_img_id, + ImageId merged_image_id); + + /// Resolves depth overlap and either re-creates the image or returns existing one + [[nodiscard]] ImageId ResolveDepthOverlap(const ImageInfo& requested_info, + ImageId cache_img_id); + + [[nodiscard]] ImageId ExpandImage(const ImageInfo& info, ImageId image_id); + /// Reuploads image contents. void RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler = nullptr); @@ -167,14 +176,20 @@ private: void UnregisterImage(ImageId image); /// Track CPU reads and writes for image - void TrackImage(Image& image, ImageId image_id); + void TrackImage(ImageId image_id); /// Stop tracking CPU reads and writes for image - void UntrackImage(Image& image, ImageId image_id); + void UntrackImage(ImageId image_id); /// Removes the image and any views/surface metas that reference it. void DeleteImage(ImageId image_id); + void FreeImage(ImageId image_id) { + UntrackImage(image_id); + UnregisterImage(image_id); + DeleteImage(image_id); + } + private: const Vulkan::Instance& instance; Vulkan::Scheduler& scheduler; diff --git a/src/video_core/texture_cache/tile_manager.cpp b/src/video_core/texture_cache/tile_manager.cpp index 5f3ed0f89..7fe5598d4 100644 --- a/src/video_core/texture_cache/tile_manager.cpp +++ b/src/video_core/texture_cache/tile_manager.cpp @@ -254,11 +254,8 @@ struct DetilerParams { u32 sizes[14]; }; -static constexpr size_t StreamBufferSize = 1_GB; - TileManager::TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler) - : instance{instance}, scheduler{scheduler}, - stream_buffer{instance, scheduler, MemoryUsage::Upload, StreamBufferSize} { + : instance{instance}, scheduler{scheduler} { static const std::array detiler_shaders{ HostShaders::DETILE_M8X1_COMP, HostShaders::DETILE_M8X2_COMP, HostShaders::DETILE_M32X1_COMP, HostShaders::DETILE_M32X2_COMP, @@ -397,11 +394,6 @@ std::optional TileManager::TryDetile(Image& image) { // Prepare input buffer const u32 image_size = image.info.guest_size_bytes; const auto [in_buffer, in_offset] = [&] -> std::pair { - // Use stream buffer for smaller textures. - if (image_size <= stream_buffer.GetFreeSize()) { - u32 offset = stream_buffer.Copy(image.info.guest_address, image_size); - return {stream_buffer.Handle(), offset}; - } // Request temporary host buffer for larger sizes. auto in_buffer = AllocBuffer(image_size); const auto addr = reinterpret_cast(image.info.guest_address); diff --git a/src/video_core/texture_cache/tile_manager.h b/src/video_core/texture_cache/tile_manager.h index 00765b1f8..0baabf98d 100644 --- a/src/video_core/texture_cache/tile_manager.h +++ b/src/video_core/texture_cache/tile_manager.h @@ -51,7 +51,6 @@ private: private: const Vulkan::Instance& instance; Vulkan::Scheduler& scheduler; - StreamBuffer stream_buffer; std::array detilers; }; diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h index 45ffe2511..bcef19355 100644 --- a/src/video_core/texture_cache/types.h +++ b/src/video_core/texture_cache/types.h @@ -36,6 +36,8 @@ struct Extent3D { u32 width; u32 height; u32 depth; + + auto operator<=>(const Extent3D&) const = default; }; struct SubresourceLayers { From 89fb1a024f9e5380c690436d385b45cba241c45c Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:12:04 -0500 Subject: [PATCH 18/23] Update sceBatchMap2 (#782) * Update sceKernelBatchMap2 Improves placement of new BatchMap op types, and re-adds the BatchMap2 changes from https://github.com/shadps4-emu/shadPS4/pull/602. * Update some logs. --- .../libraries/kernel/memory_management.cpp | 45 +++++-------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index 08cd106d8..a23c94478 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -292,41 +292,16 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn } case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_UNMAP: { result = sceKernelMunmap(entries[i].start, entries[i].length); - LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", - i, entries[i].operation, entries[i].length, result); - - if (result == 0) - processed++; + LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i, + entries[i].operation, entries[i].length, result); + break; } case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_PROTECT: { result = sceKernelMProtect(entries[i].start, entries[i].length, entries[i].protection); - LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", - i, entries[i].operation, entries[i].length, result); - if (result != ORBIS_OK) { - LOG_ERROR(Kernel_Vmm, "BatchMap: MProtect failed on entry {} with result {}", i, - result); - } - if (result == 0) { - processed++; - } + LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i, + entries[i].operation, entries[i].length, result); break; } - - case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_TYPE_PROTECT: { - result = sceKernelMTypeProtect(entries[i].start, entries[i].length, entries[i].type, - entries[i].protection); - LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", - i, entries[i].operation, entries[i].length, result); - if (result != ORBIS_OK) { - LOG_ERROR(Kernel_Vmm, "BatchMap: MProtect failed on entry {} with result {}", i, - result); - } - if (result == 0) { - processed++; - } - break; - } - case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE: { result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length, entries[i].protection, flags, ""); @@ -336,7 +311,13 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn i, entries[i].operation, entries[i].length, (u8)entries[i].type, result); break; } - + case MemoryOpTypes::ORBIS_KERNEL_MAP_OP_TYPE_PROTECT: { + result = sceKernelMTypeProtect(entries[i].start, entries[i].length, entries[i].type, + entries[i].protection); + LOG_INFO(Kernel_Vmm, "entry = {}, operation = {}, len = {:#x}, result = {}", i, + entries[i].operation, entries[i].length, result); + break; + } default: { UNREACHABLE(); } @@ -346,8 +327,6 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn break; } } - LOG_INFO(Kernel_Vmm, "sceKernelBatchMap2 finished: processed = {}, result = {}", processed, - result); if (numEntriesOut != NULL) { // can be zero. do not return an error code. *numEntriesOut = processed; } From 76f4ceda31dde5b975eacc9061d5afdb5d133970 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:24:30 -0500 Subject: [PATCH 19/23] Forgot one (#783) I forgot to readd the processed variable to the for loop. --- src/core/libraries/kernel/memory_management.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index a23c94478..af3542912 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -272,7 +272,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn int* numEntriesOut, int flags) { int result = ORBIS_OK; int processed = 0; - for (int i = 0; i < numEntries; i++) { + for (int i = 0; i < numEntries; i++, processed++) { if (entries == nullptr || entries[i].length == 0 || entries[i].operation > 4) { result = ORBIS_KERNEL_ERROR_EINVAL; break; // break and assign a value to numEntriesOut. From eb2520a2405452be31cd3934c4b4e11a3886aea5 Mon Sep 17 00:00:00 2001 From: "Daniel R." <47796739+polybiusproxy@users.noreply.github.com> Date: Wed, 4 Sep 2024 23:55:06 +0200 Subject: [PATCH 20/23] video_core/renderer_vulkan: Ignore unsupported shader stages (#778) * video_core/renderer_vulkan: Ignore unsupported shader stages * clang-format --- src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 33971cc5a..2c40bcb2d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -298,6 +298,11 @@ bool PipelineCache::RefreshGraphicsKey() { } const auto stage = Shader::StageFromIndex(i); const auto params = Liverpool::GetParams(*pgm); + + if (stage != Shader::Stage::Vertex && stage != Shader::Stage::Fragment) { + return false; + } + std::tie(infos[i], modules[i], key.stage_hashes[i]) = GetProgram(stage, params, binding); } return true; From 4e0dc9104033e826fa94289a1a84dc235ef501b9 Mon Sep 17 00:00:00 2001 From: psucien Date: Thu, 5 Sep 2024 09:58:51 +0200 Subject: [PATCH 21/23] hot-fix: don't skip draws with DS decompression --- src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 2c40bcb2d..b5435af1f 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -145,14 +145,6 @@ const GraphicsPipeline* PipelineCache::GetGraphicsPipeline() { LOG_TRACE(Render_Vulkan, "FMask decompression pass skipped"); return nullptr; } - if (regs.depth_render_control.depth_compress_disable) { - LOG_TRACE(Render_Vulkan, "HTile decompress skipped (depth)"); - return nullptr; - } - if (regs.depth_render_control.stencil_compress_disable) { - LOG_TRACE(Render_Vulkan, "HTile decompress skipped (stencil)"); - return nullptr; - } if (!RefreshGraphicsKey()) { return nullptr; } From b08baaeb136007051c748f49dd64889204cb5d3c Mon Sep 17 00:00:00 2001 From: TheTurtle <47210458+raphaelthegreat@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:25:45 +0300 Subject: [PATCH 22/23] video_core: Improve handling of image buffer aliases (#757) * texture_cache: Use invalidate threshhold * It's possible for shaders to bind huge buffers and only write to lower portion of it. This is a problem if upper parts of the buffer overlap with render targets. If the image is very far away from buffer base it's unlikely the shader will want to write it, so skip invalidation for it * video_core: Allow using texture cache to validate texture buffers * texture_cache: Use buffer cache in all cases for data source * Allows to correctly handle compute written micro tiled textures * texture_cache: Fix depth pitch * kernel: Remove missed code * clang format * video_core: Adjust depth format * buffer_cache: Do not cache buffer views * thread_management: Do not call createMutex on unlock * temp: Revert this when pr is done * buffer_cache: Dont skip cpu uploads with image sync * Sometimes image does not fully overlap with a region * fix build * video_core: Improve invalidate heuristic * small fixes * video_core: Hopefully fix some vertex explosions --- .../libraries/kernel/thread_management.cpp | 8 +- src/video_core/buffer_cache/buffer.cpp | 36 ++---- src/video_core/buffer_cache/buffer.h | 18 +-- src/video_core/buffer_cache/buffer_cache.cpp | 107 +++++++++++++--- src/video_core/buffer_cache/buffer_cache.h | 10 +- .../renderer_vulkan/vk_compute_pipeline.cpp | 13 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 23 ++-- .../renderer_vulkan/vk_instance.cpp | 1 + .../renderer_vulkan/vk_platform.cpp | 2 + .../renderer_vulkan/vk_rasterizer.cpp | 2 +- .../texture_cache/host_compatibility.h | 9 +- src/video_core/texture_cache/image.cpp | 5 +- src/video_core/texture_cache/image_info.cpp | 4 +- src/video_core/texture_cache/image_view.cpp | 3 +- .../texture_cache/texture_cache.cpp | 114 ++++++++---------- src/video_core/texture_cache/texture_cache.h | 61 ++++++---- src/video_core/texture_cache/tile_manager.cpp | 21 ++-- src/video_core/texture_cache/tile_manager.h | 2 +- 18 files changed, 248 insertions(+), 191 deletions(-) diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 11d472a49..919afcb47 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -414,11 +414,6 @@ ScePthreadMutex* createMutex(ScePthreadMutex* addr) { if (addr == nullptr || *addr != nullptr) { return addr; } - static std::mutex mutex; - std::scoped_lock lk{mutex}; - if (*addr != nullptr) { - return addr; - } const VAddr vaddr = reinterpret_cast(addr); std::string name = fmt::format("mutex{:#x}", vaddr); scePthreadMutexInit(addr, nullptr, name.c_str()); @@ -584,8 +579,7 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) { } int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) { - mutex = createMutex(mutex); - if (mutex == nullptr) { + if (mutex == nullptr || *mutex == nullptr) { return SCE_KERNEL_ERROR_EINVAL; } diff --git a/src/video_core/buffer_cache/buffer.cpp b/src/video_core/buffer_cache/buffer.cpp index adcea000b..702958034 100644 --- a/src/video_core/buffer_cache/buffer.cpp +++ b/src/video_core/buffer_cache/buffer.cpp @@ -91,10 +91,10 @@ void UniqueBuffer::Create(const vk::BufferCreateInfo& buffer_ci, MemoryUsage usa buffer = vk::Buffer{unsafe_buffer}; } -Buffer::Buffer(const Vulkan::Instance& instance_, MemoryUsage usage_, VAddr cpu_addr_, - vk::BufferUsageFlags flags, u64 size_bytes_) - : cpu_addr{cpu_addr_}, size_bytes{size_bytes_}, instance{&instance_}, usage{usage_}, - buffer{instance->GetDevice(), instance->GetAllocator()} { +Buffer::Buffer(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, MemoryUsage usage_, + VAddr cpu_addr_, vk::BufferUsageFlags flags, u64 size_bytes_) + : cpu_addr{cpu_addr_}, size_bytes{size_bytes_}, instance{&instance_}, scheduler{&scheduler_}, + usage{usage_}, buffer{instance->GetDevice(), instance->GetAllocator()} { // Create buffer object. const vk::BufferCreateInfo buffer_ci = { .size = size_bytes, @@ -117,13 +117,6 @@ Buffer::Buffer(const Vulkan::Instance& instance_, MemoryUsage usage_, VAddr cpu_ vk::BufferView Buffer::View(u32 offset, u32 size, bool is_written, AmdGpu::DataFormat dfmt, AmdGpu::NumberFormat nfmt) { - const auto it{std::ranges::find_if(views, [=](const BufferView& view) { - return offset == view.offset && size == view.size && is_written == view.is_written && - dfmt == view.dfmt && nfmt == view.nfmt; - })}; - if (it != views.end()) { - return *it->handle; - } const vk::BufferUsageFlags2CreateInfoKHR usage_flags = { .usage = is_written ? vk::BufferUsageFlagBits2KHR::eStorageTexelBuffer : vk::BufferUsageFlagBits2KHR::eUniformTexelBuffer, @@ -135,23 +128,18 @@ vk::BufferView Buffer::View(u32 offset, u32 size, bool is_written, AmdGpu::DataF .offset = offset, .range = size, }; - views.push_back({ - .offset = offset, - .size = size, - .is_written = is_written, - .dfmt = dfmt, - .nfmt = nfmt, - .handle = instance->GetDevice().createBufferViewUnique(view_ci), - }); - return *views.back().handle; + const auto view = instance->GetDevice().createBufferView(view_ci); + scheduler->DeferOperation( + [view, device = instance->GetDevice()] { device.destroyBufferView(view); }); + return view; } constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000; constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000; -StreamBuffer::StreamBuffer(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler_, +StreamBuffer::StreamBuffer(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, MemoryUsage usage, u64 size_bytes) - : Buffer{instance, usage, 0, AllFlags, size_bytes}, scheduler{scheduler_} { + : Buffer{instance, scheduler, usage, 0, AllFlags, size_bytes} { ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE); ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE); const auto device = instance.GetDevice(); @@ -206,7 +194,7 @@ void StreamBuffer::Commit() { auto& watch = current_watches[current_watch_cursor++]; watch.upper_bound = offset; - watch.tick = scheduler.CurrentTick(); + watch.tick = scheduler->CurrentTick(); } void StreamBuffer::ReserveWatches(std::vector& watches, std::size_t grow_size) { @@ -220,7 +208,7 @@ void StreamBuffer::WaitPendingOperations(u64 requested_upper_bound) { while (requested_upper_bound > wait_bound && wait_cursor < *invalidation_mark) { auto& watch = previous_watches[wait_cursor]; wait_bound = watch.upper_bound; - scheduler.Wait(watch.tick); + scheduler->Wait(watch.tick); ++wait_cursor; } } diff --git a/src/video_core/buffer_cache/buffer.h b/src/video_core/buffer_cache/buffer.h index 334975788..403d4ed85 100644 --- a/src/video_core/buffer_cache/buffer.h +++ b/src/video_core/buffer_cache/buffer.h @@ -73,8 +73,9 @@ struct UniqueBuffer { class Buffer { public: - explicit Buffer(const Vulkan::Instance& instance, MemoryUsage usage, VAddr cpu_addr_, - vk::BufferUsageFlags flags, u64 size_bytes_); + explicit Buffer(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, + MemoryUsage usage, VAddr cpu_addr_, vk::BufferUsageFlags flags, + u64 size_bytes_); Buffer& operator=(const Buffer&) = delete; Buffer(const Buffer&) = delete; @@ -144,20 +145,12 @@ public: int stream_score = 0; size_t size_bytes = 0; std::span mapped_data; - const Vulkan::Instance* instance{}; + const Vulkan::Instance* instance; + Vulkan::Scheduler* scheduler; MemoryUsage usage; UniqueBuffer buffer; vk::AccessFlagBits2 access_mask{vk::AccessFlagBits2::eNone}; vk::PipelineStageFlagBits2 stage{vk::PipelineStageFlagBits2::eNone}; - struct BufferView { - u32 offset; - u32 size; - bool is_written; - AmdGpu::DataFormat dfmt; - AmdGpu::NumberFormat nfmt; - vk::UniqueBufferView handle; - }; - std::vector views; }; class StreamBuffer : public Buffer { @@ -196,7 +189,6 @@ private: void WaitPendingOperations(u64 requested_upper_bound); private: - Vulkan::Scheduler& scheduler; u64 offset{}; u64 mapped_size{}; std::vector current_watches; diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index d67e953eb..89032e990 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -10,20 +10,24 @@ #include "video_core/renderer_vulkan/liverpool_to_vk.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_scheduler.h" +#include "video_core/texture_cache/texture_cache.h" namespace VideoCore { +static constexpr size_t NumVertexBuffers = 32; static constexpr size_t StagingBufferSize = 512_MB; static constexpr size_t UboStreamBufferSize = 64_MB; BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, - const AmdGpu::Liverpool* liverpool_, PageManager& tracker_) - : instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_}, tracker{tracker_}, + const AmdGpu::Liverpool* liverpool_, TextureCache& texture_cache_, + PageManager& tracker_) + : instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_}, + texture_cache{texture_cache_}, tracker{tracker_}, staging_buffer{instance, scheduler, MemoryUsage::Upload, StagingBufferSize}, stream_buffer{instance, scheduler, MemoryUsage::Stream, UboStreamBufferSize}, memory_tracker{&tracker} { // Ensure the first slot is used for the null buffer - void(slot_buffers.insert(instance, MemoryUsage::DeviceLocal, 0, ReadFlags, 1)); + void(slot_buffers.insert(instance, scheduler, MemoryUsage::DeviceLocal, 0, ReadFlags, 1)); } BufferCache::~BufferCache() = default; @@ -100,9 +104,9 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { return false; } - std::array host_buffers; - std::array host_offsets; - boost::container::static_vector guest_buffers; + std::array host_buffers; + std::array host_offsets; + boost::container::static_vector guest_buffers; struct BufferRange { VAddr base_address; @@ -117,7 +121,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { // Calculate buffers memory overlaps bool has_step_rate = false; - boost::container::static_vector ranges{}; + boost::container::static_vector ranges{}; for (const auto& input : vs_info.vs_inputs) { if (input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate0 || input.instance_step_rate == Shader::Info::VsInput::InstanceIdType::OverStepRate1) { @@ -152,7 +156,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { return lhv.base_address < rhv.base_address; }); - boost::container::static_vector ranges_merged{ranges[0]}; + boost::container::static_vector ranges_merged{ranges[0]}; for (auto range : ranges) { auto& prev_range = ranges_merged.back(); if (prev_range.end_address < range.base_address) { @@ -232,7 +236,7 @@ std::pair BufferCache::ObtainBuffer(VAddr device_addr, u32 size, b bool is_texel_buffer) { static constexpr u64 StreamThreshold = CACHING_PAGESIZE; const bool is_gpu_dirty = memory_tracker.IsRegionGpuModified(device_addr, size); - if (!is_written && !is_texel_buffer && size <= StreamThreshold && !is_gpu_dirty) { + if (!is_written && size <= StreamThreshold && !is_gpu_dirty) { // For small uniform buffers that have not been modified by gpu // use device local stream buffer to reduce renderpass breaks. const u64 offset = stream_buffer.Copy(device_addr, size, instance.UniformMinAlignment()); @@ -241,7 +245,7 @@ std::pair BufferCache::ObtainBuffer(VAddr device_addr, u32 size, b const BufferId buffer_id = FindBuffer(device_addr, size); Buffer& buffer = slot_buffers[buffer_id]; - SynchronizeBuffer(buffer, device_addr, size); + SynchronizeBuffer(buffer, device_addr, size, is_texel_buffer); if (is_written) { memory_tracker.MarkRegionAsGpuModified(device_addr, size); } @@ -420,8 +424,8 @@ BufferId BufferCache::CreateBuffer(VAddr device_addr, u32 wanted_size) { wanted_size = static_cast(device_addr_end - device_addr); const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size); const u32 size = static_cast(overlap.end - overlap.begin); - const BufferId new_buffer_id = - slot_buffers.insert(instance, MemoryUsage::DeviceLocal, overlap.begin, AllFlags, size); + const BufferId new_buffer_id = slot_buffers.insert( + instance, scheduler, MemoryUsage::DeviceLocal, overlap.begin, AllFlags, size); auto& new_buffer = slot_buffers[new_buffer_id]; const size_t size_bytes = new_buffer.SizeBytes(); const auto cmdbuf = scheduler.CommandBuffer(); @@ -459,7 +463,8 @@ void BufferCache::ChangeRegister(BufferId buffer_id) { } } -bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size) { +void BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, + bool is_texel_buffer) { std::scoped_lock lk{mutex}; boost::container::small_vector copies; u64 total_size_bytes = 0; @@ -479,8 +484,13 @@ bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size) // Prevent uploading to gpu modified regions. // gpu_modified_ranges.ForEachNotInRange(device_addr_out, range_size, add_copy); }); + SCOPE_EXIT { + if (is_texel_buffer) { + SynchronizeBufferFromImage(buffer, device_addr, size); + } + }; if (total_size_bytes == 0) { - return true; + return; } vk::Buffer src_buffer = staging_buffer.Handle(); if (total_size_bytes < StagingBufferSize) { @@ -496,7 +506,11 @@ bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size) } else { // For large one time transfers use a temporary host buffer. // RenderDoc can lag quite a bit if the stream buffer is too large. - Buffer temp_buffer{instance, MemoryUsage::Upload, 0, vk::BufferUsageFlagBits::eTransferSrc, + Buffer temp_buffer{instance, + scheduler, + MemoryUsage::Upload, + 0, + vk::BufferUsageFlagBits::eTransferSrc, total_size_bytes}; src_buffer = temp_buffer.Handle(); u8* const staging = temp_buffer.mapped_data.data(); @@ -524,7 +538,68 @@ bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size) cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands, vk::DependencyFlagBits::eByRegion, WRITE_BARRIER, {}, {}); - return false; +} + +bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size) { + boost::container::small_vector image_ids; + const u32 inv_size = std::min(size, MaxInvalidateDist); + texture_cache.ForEachImageInRegion(device_addr, inv_size, [&](ImageId image_id, Image& image) { + // Only consider GPU modified images, i.e render targets or storage images. + // Also avoid any CPU modified images as the image data is likely to be stale. + if (True(image.flags & ImageFlagBits::CpuModified) || + False(image.flags & ImageFlagBits::GpuModified)) { + return; + } + // Image must fully overlap with the provided buffer range. + if (image.cpu_addr < device_addr || image.cpu_addr_end > device_addr + size) { + return; + } + image_ids.push_back(image_id); + }); + if (image_ids.empty()) { + return false; + } + // Sort images by modification tick. If there are overlaps we want to + // copy from least to most recently modified. + std::ranges::sort(image_ids, [&](ImageId lhs_id, ImageId rhs_id) { + const Image& lhs = texture_cache.GetImage(lhs_id); + const Image& rhs = texture_cache.GetImage(rhs_id); + return lhs.tick_accessed_last < rhs.tick_accessed_last; + }); + boost::container::small_vector copies; + for (const ImageId image_id : image_ids) { + copies.clear(); + Image& image = texture_cache.GetImage(image_id); + u32 offset = buffer.Offset(image.cpu_addr); + const u32 num_layers = image.info.resources.layers; + for (u32 m = 0; m < image.info.resources.levels; m++) { + const u32 width = std::max(image.info.size.width >> m, 1u); + const u32 height = std::max(image.info.size.height >> m, 1u); + const u32 depth = + image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u; + const auto& [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m]; + copies.push_back({ + .bufferOffset = offset, + .bufferRowLength = static_cast(mip_pitch), + .bufferImageHeight = static_cast(mip_height), + .imageSubresource{ + .aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, + .mipLevel = m, + .baseArrayLayer = 0, + .layerCount = num_layers, + }, + .imageOffset = {0, 0, 0}, + .imageExtent = {width, height, depth}, + }); + offset += mip_ofs * num_layers; + } + scheduler.EndRendering(); + image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits::eTransferRead); + const auto cmdbuf = scheduler.CommandBuffer(); + cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, buffer.buffer, + copies); + } + return true; } void BufferCache::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 9be258ab9..b38b00f07 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -28,7 +28,7 @@ using BufferId = Common::SlotId; static constexpr BufferId NULL_BUFFER_ID{0}; -static constexpr u32 NUM_VERTEX_BUFFERS = 32; +class TextureCache; class BufferCache { public: @@ -53,7 +53,8 @@ public: public: explicit BufferCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, - const AmdGpu::Liverpool* liverpool, PageManager& tracker); + const AmdGpu::Liverpool* liverpool, TextureCache& texture_cache, + PageManager& tracker); ~BufferCache(); /// Invalidates any buffer in the logical page range. @@ -116,13 +117,16 @@ private: template void ChangeRegister(BufferId buffer_id); - bool SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size); + void SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, bool is_texel_buffer); + + bool SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, u32 size); void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false); const Vulkan::Instance& instance; Vulkan::Scheduler& scheduler; const AmdGpu::Liverpool* liverpool; + TextureCache& texture_cache; PageManager& tracker; StreamBuffer staging_buffer; StreamBuffer stream_buffer; diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index b1a23532d..b87d3c915 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -167,9 +167,6 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)"); } } - if (desc.is_written) { - texture_cache.InvalidateMemory(address, size); - } const u32 alignment = instance.TexelBufferMinAlignment(); const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(address, size, desc.is_written, true); @@ -184,13 +181,15 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, } buffer_view = vk_buffer->View(offset_aligned, size + adjust, desc.is_written, vsharp.GetDataFmt(), vsharp.GetNumberFmt()); - if (auto barrier = vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite : vk::AccessFlagBits2::eShaderRead, vk::PipelineStageFlagBits2::eComputeShader)) { buffer_barriers.emplace_back(*barrier); } + if (desc.is_written) { + texture_cache.InvalidateMemory(address, size); + } } set_writes.push_back({ .dstSet = VK_NULL_HANDLE, @@ -206,7 +205,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, for (const auto& image_desc : info->images) { const auto tsharp = image_desc.GetSharp(*info); if (tsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid) { - VideoCore::ImageInfo image_info{tsharp}; + VideoCore::ImageInfo image_info{tsharp, image_desc.is_depth}; VideoCore::ImageViewInfo view_info{tsharp, image_desc.is_storage}; const auto& image_view = texture_cache.FindTexture(image_info, view_info); const auto& image = texture_cache.GetImage(image_view.image_id); @@ -252,10 +251,12 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, const auto cmdbuf = scheduler.CommandBuffer(); if (!buffer_barriers.empty()) { - auto dependencies = vk::DependencyInfo{ + const auto dependencies = vk::DependencyInfo{ + .dependencyFlags = vk::DependencyFlagBits::eByRegion, .bufferMemoryBarrierCount = u32(buffer_barriers.size()), .pBufferMemoryBarriers = buffer_barriers.data(), }; + scheduler.EndRendering(); cmdbuf.pipelineBarrier2(dependencies); } diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 5aec456fb..6ac4dcf14 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -405,15 +405,15 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, }); } - for (const auto& tex_buffer : stage->texture_buffers) { - const auto vsharp = tex_buffer.GetSharp(*stage); + for (const auto& desc : stage->texture_buffers) { + const auto vsharp = desc.GetSharp(*stage); vk::BufferView& buffer_view = buffer_views.emplace_back(VK_NULL_HANDLE); const u32 size = vsharp.GetSize(); if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) { const VAddr address = vsharp.base_address; const u32 alignment = instance.TexelBufferMinAlignment(); const auto [vk_buffer, offset] = - buffer_cache.ObtainBuffer(address, size, tex_buffer.is_written, true); + buffer_cache.ObtainBuffer(address, size, desc.is_written, true); const u32 fmt_stride = AmdGpu::NumBits(vsharp.GetDataFmt()) >> 3; ASSERT_MSG(fmt_stride == vsharp.GetStride(), "Texel buffer stride must match format stride"); @@ -423,22 +423,25 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, ASSERT(adjust % fmt_stride == 0); push_data.AddOffset(binding, adjust / fmt_stride); } - buffer_view = vk_buffer->View(offset_aligned, size + adjust, tex_buffer.is_written, + buffer_view = vk_buffer->View(offset_aligned, size + adjust, desc.is_written, vsharp.GetDataFmt(), vsharp.GetNumberFmt()); - const auto dst_access = tex_buffer.is_written ? vk::AccessFlagBits2::eShaderWrite - : vk::AccessFlagBits2::eShaderRead; + const auto dst_access = desc.is_written ? vk::AccessFlagBits2::eShaderWrite + : vk::AccessFlagBits2::eShaderRead; if (auto barrier = vk_buffer->GetBarrier( dst_access, vk::PipelineStageFlagBits2::eVertexShader)) { buffer_barriers.emplace_back(*barrier); } + if (desc.is_written) { + texture_cache.InvalidateMemory(address, size); + } } set_writes.push_back({ .dstSet = VK_NULL_HANDLE, .dstBinding = binding++, .dstArrayElement = 0, .descriptorCount = 1, - .descriptorType = tex_buffer.is_written ? vk::DescriptorType::eStorageTexelBuffer - : vk::DescriptorType::eUniformTexelBuffer, + .descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer + : vk::DescriptorType::eUniformTexelBuffer, .pTexelBufferView = &buffer_view, }); } @@ -497,10 +500,12 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, const auto cmdbuf = scheduler.CommandBuffer(); if (!buffer_barriers.empty()) { - auto dependencies = vk::DependencyInfo{ + const auto dependencies = vk::DependencyInfo{ + .dependencyFlags = vk::DependencyFlagBits::eByRegion, .bufferMemoryBarrierCount = u32(buffer_barriers.size()), .pBufferMemoryBarriers = buffer_barriers.data(), }; + scheduler.EndRendering(); cmdbuf.pipelineBarrier2(dependencies); } diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index c0105d8f9..a055cf3bc 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -297,6 +297,7 @@ bool Instance::CreateDevice() { .shaderFloat16 = vk12_features.shaderFloat16, .scalarBlockLayout = vk12_features.scalarBlockLayout, .uniformBufferStandardLayout = vk12_features.uniformBufferStandardLayout, + .separateDepthStencilLayouts = vk12_features.separateDepthStencilLayouts, .hostQueryReset = vk12_features.hostQueryReset, .timelineSemaphore = vk12_features.timelineSemaphore, }, diff --git a/src/video_core/renderer_vulkan/vk_platform.cpp b/src/video_core/renderer_vulkan/vk_platform.cpp index 2318bb247..feadda96c 100644 --- a/src/video_core/renderer_vulkan/vk_platform.cpp +++ b/src/video_core/renderer_vulkan/vk_platform.cpp @@ -42,6 +42,8 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback( switch (static_cast(callback_data->messageIdNumber)) { case 0x609a13b: // Vertex attribute at location not consumed by shader case 0xc81ad50e: + case 0xb7c39078: + case 0x32868fde: // vkCreateBufferView(): pCreateInfo->range does not equal VK_WHOLE_SIZE case 0x92d66fc1: // `pMultisampleState is NULL` for depth only passes (confirmed VL error) return VK_FALSE; default: diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 4207c18d6..9f72d0448 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -17,7 +17,7 @@ namespace Vulkan { Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_, AmdGpu::Liverpool* liverpool_) : instance{instance_}, scheduler{scheduler_}, page_manager{this}, - buffer_cache{instance, scheduler, liverpool_, page_manager}, + buffer_cache{instance, scheduler, liverpool_, texture_cache, page_manager}, texture_cache{instance, scheduler, buffer_cache, page_manager}, liverpool{liverpool_}, memory{Core::Memory::Instance()}, pipeline_cache{instance, scheduler, liverpool} { if (!Config::nullGpu()) { diff --git a/src/video_core/texture_cache/host_compatibility.h b/src/video_core/texture_cache/host_compatibility.h index 0b4b6764e..a73f7e6be 100644 --- a/src/video_core/texture_cache/host_compatibility.h +++ b/src/video_core/texture_cache/host_compatibility.h @@ -7,7 +7,7 @@ #pragma once #include -#include +#include "video_core/renderer_vulkan/vk_common.h" namespace VideoCore { /** @@ -383,9 +383,10 @@ static const std::unordered_map vkFormatCl * @url * https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#formats-compatibility */ -static bool IsVulkanFormatCompatible(VkFormat lhs, VkFormat rhs) { - if (lhs == rhs) +static bool IsVulkanFormatCompatible(vk::Format lhs, vk::Format rhs) { + if (lhs == rhs) { return true; - return vkFormatClassTable.at(lhs) == vkFormatClassTable.at(rhs); + } + return vkFormatClassTable.at(VkFormat(lhs)) == vkFormatClassTable.at(VkFormat(rhs)); } } // namespace VideoCore diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index 13ea7ce93..2a5c4c434 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -166,8 +166,9 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, image.Create(image_ci); - Vulkan::SetObjectName(instance->GetDevice(), (vk::Image)image, "Image {:#x}:{:#x}", - info.guest_address, info.guest_size_bytes); + Vulkan::SetObjectName(instance->GetDevice(), (vk::Image)image, "Image {}x{}x{} {:#x}:{:#x}", + info.size.width, info.size.height, info.size.depth, info.guest_address, + info.guest_size_bytes); } void Image::Transit(vk::ImageLayout dst_layout, vk::Flags dst_mask, diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index bd4671688..66fde5c83 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp @@ -187,7 +187,7 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slice size.width = hint.Valid() ? hint.width : buffer.Pitch(); size.height = hint.Valid() ? hint.height : buffer.Height(); size.depth = 1; - pitch = size.width; + pitch = buffer.Pitch(); resources.layers = num_slices; meta_info.htile_addr = buffer.z_info.tile_surface_en ? htile_address : 0; usage.depth_target = true; @@ -207,7 +207,7 @@ ImageInfo::ImageInfo(const AmdGpu::Image& image, bool force_depth /*= false*/) n if (force_depth || tiling_mode == AmdGpu::TilingMode::Depth_MacroTiled) { if (pixel_format == vk::Format::eR32Sfloat) { pixel_format = vk::Format::eD32SfloatS8Uint; - } else if (pixel_format == vk::Format::eR16Sfloat) { + } else if (pixel_format == vk::Format::eR16Unorm) { pixel_format = vk::Format::eD16UnormS8Uint; } else { UNREACHABLE(); diff --git a/src/video_core/texture_cache/image_view.cpp b/src/video_core/texture_cache/image_view.cpp index bcdc11ad9..e554bad7e 100644 --- a/src/video_core/texture_cache/image_view.cpp +++ b/src/video_core/texture_cache/image_view.cpp @@ -123,7 +123,8 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info // When sampling D32 texture from shader, the T# specifies R32 Float format so adjust it. vk::Format format = info.format; vk::ImageAspectFlags aspect = image.aspect_mask; - if (image.aspect_mask & vk::ImageAspectFlagBits::eDepth && format == vk::Format::eR32Sfloat) { + if (image.aspect_mask & vk::ImageAspectFlagBits::eDepth && + (format == vk::Format::eR32Sfloat || format == vk::Format::eD32Sfloat)) { format = image.info.pixel_format; aspect = vk::ImageAspectFlagBits::eDepth; } diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 90dc71409..0d0c81f5d 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -38,13 +38,14 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& TextureCache::~TextureCache() = default; void TextureCache::InvalidateMemory(VAddr address, size_t size) { - std::unique_lock lock{mutex}; + std::scoped_lock lock{mutex}; ForEachImageInRegion(address, size, [&](ImageId image_id, Image& image) { - if (!image.Overlaps(address, size)) { - return; + const size_t image_dist = + image.cpu_addr > address ? image.cpu_addr - address : address - image.cpu_addr; + if (image_dist < MaxInvalidateDist) { + // Ensure image is reuploaded when accessed again. + image.flags |= ImageFlagBits::CpuModified; } - // Ensure image is reuploaded when accessed again. - image.flags |= ImageFlagBits::CpuModified; // Untrack image, so the range is unprotected and the guest can write freely. UntrackImage(image_id); }); @@ -144,17 +145,12 @@ ImageId TextureCache::ResolveOverlap(const ImageInfo& image_info, ImageId cache_ FreeImage(cache_image_id); } - - if (tex_cache_image.info.IsSliceOf(image_info)) { - UNREACHABLE(); - } } return merged_image_id; } ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId image_id) { - const auto new_image_id = slot_images.insert(instance, scheduler, info); RegisterImage(new_image_id); @@ -171,50 +167,37 @@ ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId image_id) { return new_image_id; } -ImageId TextureCache::FindImage(const ImageInfo& info) { +ImageId TextureCache::FindImage(const ImageInfo& info, FindFlags flags) { if (info.guest_address == 0) [[unlikely]] { return NULL_IMAGE_VIEW_ID; } - std::unique_lock lock{mutex}; + std::scoped_lock lock{mutex}; boost::container::small_vector image_ids; - ForEachImageInRegion( - info.guest_address, info.guest_size_bytes, [&](ImageId image_id, Image& image) { - // Ignore images scheduled for deletion - if (True(image.flags & ImageFlagBits::Deleted)) { - return; - } - - // Check if image is fully outside of the region - const auto in_image_cpu_addr = info.guest_address; - const auto in_image_cpu_addr_end = info.guest_address + info.guest_size_bytes; - if (in_image_cpu_addr_end <= image.cpu_addr) { - return; - } - if (in_image_cpu_addr >= image.cpu_addr_end) { - return; - } - - image_ids.push_back(image_id); - }); + ForEachImageInRegion(info.guest_address, info.guest_size_bytes, + [&](ImageId image_id, Image& image) { image_ids.push_back(image_id); }); ImageId image_id{}; // Check for a perfect match first for (const auto& cache_id : image_ids) { auto& cache_image = slot_images[cache_id]; - - if (cache_image.info.guest_address == info.guest_address && - cache_image.info.guest_size_bytes == info.guest_size_bytes && - cache_image.info.size == info.size) { - - ASSERT(cache_image.info.type == info.type); - if (IsVulkanFormatCompatible((VkFormat)info.pixel_format, - (VkFormat)cache_image.info.pixel_format)) { - image_id = cache_id; - } - break; + if (cache_image.info.guest_address != info.guest_address) { + continue; } + if (False(flags & FindFlags::RelaxSize) && + cache_image.info.guest_size_bytes != info.guest_size_bytes) { + continue; + } + if (False(flags & FindFlags::RelaxDim) && cache_image.info.size != info.size) { + continue; + } + if (False(flags & FindFlags::RelaxFmt) && + !IsVulkanFormatCompatible(info.pixel_format, cache_image.info.pixel_format)) { + continue; + } + ASSERT(cache_image.info.type == info.type); + image_id = cache_id; } // Try to resolve overlaps (if any) @@ -225,13 +208,18 @@ ImageId TextureCache::FindImage(const ImageInfo& info) { } } + if (True(flags & FindFlags::NoCreate) && !image_id) { + return {}; + } + // Create and register a new image if (!image_id) { image_id = slot_images.insert(instance, scheduler, info); RegisterImage(image_id); } - slot_images[image_id].tick_accessed_last = scheduler.CurrentTick(); + Image& image = slot_images[image_id]; + image.tick_accessed_last = scheduler.CurrentTick(); return image_id; } @@ -259,8 +247,11 @@ ImageView& TextureCache::RegisterImageView(ImageId image_id, const ImageViewInfo ImageView& TextureCache::FindTexture(const ImageInfo& info, const ImageViewInfo& view_info) { const ImageId image_id = FindImage(info); - UpdateImage(image_id); Image& image = slot_images[image_id]; + if (view_info.is_storage) { + image.flags |= ImageFlagBits::GpuModified; + } + UpdateImage(image_id); auto& usage = image.info.usage; if (view_info.is_storage) { @@ -354,6 +345,10 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info, } void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler /*= nullptr*/) { + if (False(image.flags & ImageFlagBits::CpuModified)) { + return; + } + // Mark image as validated. image.flags &= ~ImageFlagBits::CpuModified; @@ -407,27 +402,20 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule const VAddr image_addr = image.info.guest_address; const size_t image_size = image.info.guest_size_bytes; - vk::Buffer buffer{}; - u32 offset{}; - if (auto upload_buffer = tile_manager.TryDetile(image); upload_buffer) { - buffer = *upload_buffer; - } else { - const auto [vk_buffer, buf_offset] = buffer_cache.ObtainTempBuffer(image_addr, image_size); - buffer = vk_buffer->Handle(); - offset = buf_offset; - - // The obtained buffer may be written by a shader so we need to emit a barrier to prevent - // RAW hazard - if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead, - vk::PipelineStageFlagBits2::eTransfer)) { - auto dependencies = vk::DependencyInfo{ - .bufferMemoryBarrierCount = 1, - .pBufferMemoryBarriers = &barrier.value(), - }; - cmdbuf.pipelineBarrier2(dependencies); - } + const auto [vk_buffer, buf_offset] = buffer_cache.ObtainTempBuffer(image_addr, image_size); + // The obtained buffer may be written by a shader so we need to emit a barrier to prevent RAW + // hazard + if (auto barrier = vk_buffer->GetBarrier(vk::AccessFlagBits2::eTransferRead, + vk::PipelineStageFlagBits2::eTransfer)) { + const auto dependencies = vk::DependencyInfo{ + .dependencyFlags = vk::DependencyFlagBits::eByRegion, + .bufferMemoryBarrierCount = 1, + .pBufferMemoryBarriers = &barrier.value(), + }; + cmdbuf.pipelineBarrier2(dependencies); } + const auto [buffer, offset] = tile_manager.TryDetile(vk_buffer->Handle(), buf_offset, image); for (auto& copy : image_copy) { copy.bufferOffset += offset; } diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 142093967..44bc2b431 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -23,6 +23,16 @@ namespace VideoCore { class BufferCache; class PageManager; +enum class FindFlags { + NoCreate = 1 << 0, ///< Do not create an image if searching for one fails. + RelaxDim = 1 << 1, ///< Do not check the dimentions of image, only address. + RelaxSize = 1 << 2, ///< Do not check that the size matches exactly. + RelaxFmt = 1 << 3, ///< Do not check that format is compatible. +}; +DECLARE_ENUM_FLAG_OPERATORS(FindFlags) + +static constexpr u32 MaxInvalidateDist = 12_MB; + class TextureCache { struct Traits { using Entry = boost::container::small_vector; @@ -44,7 +54,7 @@ public: void UnmapMemory(VAddr cpu_addr, size_t size); /// Retrieves the image handle of the image with the provided attributes. - [[nodiscard]] ImageId FindImage(const ImageInfo& info); + [[nodiscard]] ImageId FindImage(const ImageInfo& info, FindFlags flags = {}); /// Retrieves an image view with the properties of the specified image descriptor. [[nodiscard]] ImageView& FindTexture(const ImageInfo& image_info, @@ -61,11 +71,8 @@ public: /// Updates image contents if it was modified by CPU. void UpdateImage(ImageId image_id, Vulkan::Scheduler* custom_scheduler = nullptr) { Image& image = slot_images[image_id]; - if (False(image.flags & ImageFlagBits::CpuModified)) { - return; - } - RefreshImage(image, custom_scheduler); TrackImage(image_id); + RefreshImage(image, custom_scheduler); } [[nodiscard]] ImageId ResolveOverlap(const ImageInfo& info, ImageId cache_img_id, @@ -109,31 +116,12 @@ public: return false; } -private: - ImageView& RegisterImageView(ImageId image_id, const ImageViewInfo& view_info); - - /// Iterate over all page indices in a range - template - static void ForEachPage(PAddr addr, size_t size, Func&& func) { - static constexpr bool RETURNS_BOOL = std::is_same_v, bool>; - const u64 page_end = (addr + size - 1) >> Traits::PageBits; - for (u64 page = addr >> Traits::PageBits; page <= page_end; ++page) { - if constexpr (RETURNS_BOOL) { - if (func(page)) { - break; - } - } else { - func(page); - } - } - } - template void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func) { using FuncReturn = typename std::invoke_result::type; static constexpr bool BOOL_BREAK = std::is_same_v; boost::container::small_vector images; - ForEachPage(cpu_addr, size, [this, &images, func](u64 page) { + ForEachPage(cpu_addr, size, [this, &images, cpu_addr, size, func](u64 page) { const auto it = page_table.find(page); if (it == nullptr) { if constexpr (BOOL_BREAK) { @@ -147,6 +135,9 @@ private: if (image.flags & ImageFlagBits::Picked) { continue; } + if (!image.Overlaps(cpu_addr, size)) { + continue; + } image.flags |= ImageFlagBits::Picked; images.push_back(image_id); if constexpr (BOOL_BREAK) { @@ -166,6 +157,26 @@ private: } } +private: + /// Iterate over all page indices in a range + template + static void ForEachPage(PAddr addr, size_t size, Func&& func) { + static constexpr bool RETURNS_BOOL = std::is_same_v, bool>; + const u64 page_end = (addr + size - 1) >> Traits::PageBits; + for (u64 page = addr >> Traits::PageBits; page <= page_end; ++page) { + if constexpr (RETURNS_BOOL) { + if (func(page)) { + break; + } + } else { + func(page); + } + } + } + + /// Registers an image view for provided image + ImageView& RegisterImageView(ImageId image_id, const ImageViewInfo& view_info); + /// Create an image from the given parameters [[nodiscard]] ImageId InsertImage(const ImageInfo& info, VAddr cpu_addr); diff --git a/src/video_core/texture_cache/tile_manager.cpp b/src/video_core/texture_cache/tile_manager.cpp index 7fe5598d4..7e06291e7 100644 --- a/src/video_core/texture_cache/tile_manager.cpp +++ b/src/video_core/texture_cache/tile_manager.cpp @@ -377,30 +377,23 @@ void TileManager::FreeBuffer(ScratchBuffer buffer) { vmaDestroyBuffer(instance.GetAllocator(), buffer.first, buffer.second); } -std::optional TileManager::TryDetile(Image& image) { +std::pair TileManager::TryDetile(vk::Buffer in_buffer, u32 in_offset, + Image& image) { if (!image.info.props.is_tiled) { - return std::nullopt; + return {in_buffer, in_offset}; } const auto* detiler = GetDetiler(image); if (!detiler) { - if (image.info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled) { + if (image.info.tiling_mode != AmdGpu::TilingMode::Texture_MacroTiled && + image.info.tiling_mode != AmdGpu::TilingMode::Display_MacroTiled) { LOG_ERROR(Render_Vulkan, "Unsupported tiled image: {} ({})", vk::to_string(image.info.pixel_format), NameOf(image.info.tiling_mode)); } - return std::nullopt; + return {in_buffer, in_offset}; } - // Prepare input buffer const u32 image_size = image.info.guest_size_bytes; - const auto [in_buffer, in_offset] = [&] -> std::pair { - // Request temporary host buffer for larger sizes. - auto in_buffer = AllocBuffer(image_size); - const auto addr = reinterpret_cast(image.info.guest_address); - Upload(in_buffer, addr, image_size); - scheduler.DeferOperation([=, this]() { FreeBuffer(in_buffer); }); - return {in_buffer.first, 0}; - }(); // Prepare output buffer auto out_buffer = AllocBuffer(image_size, true); @@ -471,7 +464,7 @@ std::optional TileManager::TryDetile(Image& image) { vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, {}, post_barrier, {}); - return {out_buffer.first}; + return {out_buffer.first, 0}; } } // namespace VideoCore diff --git a/src/video_core/texture_cache/tile_manager.h b/src/video_core/texture_cache/tile_manager.h index 0baabf98d..d0e5eb0f3 100644 --- a/src/video_core/texture_cache/tile_manager.h +++ b/src/video_core/texture_cache/tile_manager.h @@ -39,7 +39,7 @@ public: TileManager(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler); ~TileManager(); - std::optional TryDetile(Image& image); + std::pair TryDetile(vk::Buffer in_buffer, u32 in_offset, Image& image); ScratchBuffer AllocBuffer(u32 size, bool is_storage = false); void Upload(ScratchBuffer buffer, const void* data, size_t size); From bad3d5a68e63c9918fa0b28bf01b9d9d0b64bae4 Mon Sep 17 00:00:00 2001 From: psucien Date: Thu, 5 Sep 2024 18:25:56 +0200 Subject: [PATCH 23/23] `sceKernelWaitEventFlag` log noise reduced --- src/core/libraries/kernel/event_flag/event_flag.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libraries/kernel/event_flag/event_flag.cpp b/src/core/libraries/kernel/event_flag/event_flag.cpp index 0fd0c3bb7..ec5d6ded2 100644 --- a/src/core/libraries/kernel/event_flag/event_flag.cpp +++ b/src/core/libraries/kernel/event_flag/event_flag.cpp @@ -145,7 +145,7 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, } int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode, u64* pResultPat, OrbisKernelUseconds* pTimeout) { - LOG_INFO(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode); + LOG_DEBUG(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode); if (ef == nullptr) { return ORBIS_KERNEL_ERROR_ESRCH; }