From 1dd2e46fce46532a1771659033424b60eb2ccc29 Mon Sep 17 00:00:00 2001 From: Yury <27062841+f1amy@users.noreply.github.com> Date: Sat, 28 Sep 2024 21:53:42 +0500 Subject: [PATCH 01/34] ru_RU translation fixes (#1118) --- src/qt_gui/translations/ru_RU.ts | 52 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index 87847de30..ca828c433 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -402,12 +402,12 @@ Enable Fullscreen - Включить полноэкранный режим + Полноэкранный режим Show Splash - Показать заставку + Показывать заставку @@ -457,7 +457,7 @@ Vblank Divider - Разделитель Vblank + Делитель Vblank @@ -527,12 +527,12 @@ GUI Settings - Настройки GUI + Настройки интерфейса Play title music - Воспроизвести музыку заголовка + Воспроизведение заглавной музыки @@ -943,7 +943,7 @@ Can't apply cheats before the game is started - Невозможно применить читы до начала игрыs + Невозможно применить читы до начала игры @@ -961,7 +961,7 @@ Restore Defaults - Восстановить умолчания + По умолчанию @@ -976,7 +976,7 @@ consoleLanguageGroupBox - Язык консоли:\nУстановите язык, который будет использоваться в играх PS4.\nРекомендуется устанавливать язык, поддерживаемый игрой, так как он может отличаться в зависимости от региона. + Язык консоли:\nУстановите язык, который будет использоваться в играх PS4.\nРекомендуется устанавливать язык который поддерживается игрой, так как он может отличаться в зависимости от региона. @@ -986,17 +986,17 @@ fullscreenCheckBox - Включить полноэкранный режим:\nАвтоматически переводит игровое окно в полноэкранный режим.\nВы можете отключить это, нажав клавишу F11. + Полноэкранный режим:\nАвтоматически переводит игровое окно в полноэкранный режим.\nВы можете отключить это, нажав клавишу F11. showSplashCheckBox - Показать заставку:\nОтображает заставку игры (специальное изображение) во время запуска игры. + Показывать заставку:\nОтображает заставку игры (специальное изображение) во время запуска игры. ps4proCheckBox - Это PS4 Pro:\nЗаставляет эмулятор работать как PS4 PRO, что может включить специальные функции в играх, поддерживающих это. + Режим PS4 Pro:\nЗаставляет эмулятор работать как PS4 Pro, что может включить специальные функции в играх, поддерживающих это. @@ -1006,22 +1006,22 @@ logTypeGroupBox - Тип журнала:\nУстановите, синхронизировать ли вывод окна журнала для производительности. Это может негативно сказаться на эмуляции. + Тип логов:\nУстановите, синхронизировать ли вывод окна логов ради производительности. Это может негативно сказаться на эмуляции. logFilter - Фильтр журнала: Фильтрует журнал, чтобы печатать только определенную информацию. Пример: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" Уровни: Trace, Debug, Info, Warning, Error, Critical - в этом порядке, конкретный уровень глушит все предыдущие уровни в списке и регистрирует все последующие уровни. + Фильтр логов: Фильтрует логи, чтобы показывать только определенную информацию. Примеры: "Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" Уровни: Trace, Debug, Info, Warning, Error, Critical - в этом порядке, конкретный уровень глушит все предыдущие уровни в списке и показывает все последующие уровни. updaterGroupBox - Обновление:\nСтабильная версия: Официальные версии, которые могут быть очень старыми и выпускаются каждый месяц, но они более надежные и проверенные.\nНестабильная версия: Версии разработки, которые содержат все последние функции и исправления, но могут содержать ошибки и менее стабильны. + Обновление:\nСтабильная версия: Официальные версии, которые выпускаются каждый месяц и могут быть очень старыми, но они более надежные и проверенные.\nНестабильная версия: Версии разработки, которые содержат все последние функции и исправления, но могут содержать ошибки и менее стабильны. GUIgroupBox - Воспроизведение музыки из заголовка:\nЕсли игра это поддерживает, включает воспроизведение специальной музыки при выборе игры в графическом интерфейсе. + Воспроизведение заглавной музыки:\nЕсли игра это поддерживает, включает воспроизведение специальной музыки при выборе игры в интерфейсе. @@ -1036,7 +1036,7 @@ heightDivider - Делитель Vblank:\nЧастота кадров, с которой обновляется эмулятор, умножается на это число. Изменение этого может иметь негативные последствия, такие как увеличение скорости игры или разрушение критических функций игры, которые не ожидают этого изменения! + Делитель Vblank:\nЧастота кадров, с которой обновляется эмулятор, умножается на это число. Изменение этого параметра может иметь негативные последствия, такие как увеличение скорости игры или нарушение критических функций игры, которые этого не ожидают! @@ -1046,7 +1046,7 @@ nullGpuCheckBox - Включить Null GPU:\nДля технической отладки отключает рендеринг игры так, как будто графической карты нет. + Включить NULL GPU:\nДля технической отладки отключает рендеринг игры так, как будто графической карты нет. @@ -1056,12 +1056,12 @@ debugDump - Включить дамп отладки:\nСохраняет символы импорта и экспорта и информацию о заголовке файла текущей исполняемой программы PS4 в каталоге + Включить отладочные дампы:\nСохраняет символы импорта, экспорта и информацию о заголовке файла текущей исполняемой программы PS4 в папку vkValidationCheckBox - Включить слои валидации Vulkan:\nВключает систему, которая проверяет состояние рендерера Vulkan и регистрирует информацию о его внутреннем состоянии. Это снизит производительность и, вероятно, изменит поведение эмуляции. + Включить слои валидации Vulkan:\nВключает систему, которая проверяет состояние рендерера Vulkan и логирует информацию о его внутреннем состоянии. Это снизит производительность и, вероятно, изменит поведение эмуляции. @@ -1132,7 +1132,7 @@ Network error: - Ошибка сети: + Сетевая ошибка: @@ -1182,12 +1182,12 @@ Do you want to update? - Вы хотите обновить? + Вы хотите обновиться? Show Changelog - Показать изменения + Показать журнал изменений @@ -1197,7 +1197,7 @@ Update - Обновить + Обновиться @@ -1207,17 +1207,17 @@ Hide Changelog - Скрыть изменения + Скрыть журнал изменений Changes - Изменения + Журнал изменений Network error occurred while trying to access the URL - Произошла ошибка сети при попытке доступа к URL + Произошла сетевая ошибка при попытке доступа к URL From 7b5d66e5c1a702e83d75c454eaf2ffde6e2c6093 Mon Sep 17 00:00:00 2001 From: tGecko Date: Sat, 28 Sep 2024 18:54:28 +0200 Subject: [PATCH 02/34] Add volume slider for title/background music (#1130) * add volume slider * add translations * stop music when checkbox unchecked * remove GUI build command args * combine functions * add accidentaly removed copyright and licencing information (thanks QT Designer) --- src/common/config.cpp | 12 ++++++ src/common/config.h | 3 ++ src/qt_gui/background_music_player.cpp | 6 +++ src/qt_gui/background_music_player.h | 3 +- src/qt_gui/main_window.cpp | 7 +++- src/qt_gui/settings_dialog.cpp | 16 ++++++-- src/qt_gui/settings_dialog.ui | 53 +++++++++++++++++++++++++- 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 +++ 33 files changed, 223 insertions(+), 7 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 4a8effbdf..0d9ff093d 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -32,6 +32,7 @@ namespace Config { static bool isNeo = false; static bool isFullscreen = false; static bool playBGM = false; +static int BGMvolume = 50; static u32 screenWidth = 1280; static u32 screenHeight = 720; static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select @@ -89,6 +90,10 @@ bool getPlayBGM() { return playBGM; } +int getBGMvolume() { + return BGMvolume; +} + u32 getScreenWidth() { return screenWidth; } @@ -249,6 +254,10 @@ void setPlayBGM(bool enable) { playBGM = enable; } +void setBGMvolume(int volume) { + BGMvolume = volume; +} + void setLanguage(u32 language) { m_language = language; } @@ -412,6 +421,7 @@ void load(const std::filesystem::path& path) { isNeo = toml::find_or(general, "isPS4Pro", false); isFullscreen = toml::find_or(general, "Fullscreen", false); playBGM = toml::find_or(general, "playBGM", false); + BGMvolume = toml::find_or(general, "BGMvolume", 50); logFilter = toml::find_or(general, "logFilter", ""); logType = toml::find_or(general, "logType", "sync"); userName = toml::find_or(general, "userName", "shadPS4"); @@ -513,6 +523,7 @@ void save(const std::filesystem::path& path) { data["General"]["isPS4Pro"] = isNeo; data["General"]["Fullscreen"] = isFullscreen; data["General"]["playBGM"] = playBGM; + data["General"]["BGMvolume"] = BGMvolume; data["General"]["logFilter"] = logFilter; data["General"]["logType"] = logType; data["General"]["userName"] = userName; @@ -565,6 +576,7 @@ void setDefaultValues() { isNeo = false; isFullscreen = false; playBGM = false; + BGMvolume = 50; screenWidth = 1280; screenHeight = 720; logFilter = ""; diff --git a/src/common/config.h b/src/common/config.h index f2b5187f8..eeeff0b2e 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -14,6 +14,8 @@ void save(const std::filesystem::path& path); bool isNeoMode(); bool isFullscreenMode(); bool getPlayBGM(); +int getBGMvolume(); + std::string getLogFilter(); std::string getLogType(); std::string getUserName(); @@ -49,6 +51,7 @@ void setScreenWidth(u32 width); void setScreenHeight(u32 height); void setFullscreenMode(bool enable); void setPlayBGM(bool enable); +void setBGMvolume(int volume); void setLanguage(u32 language); void setNeoMode(bool enable); void setUserName(const std::string& type); diff --git a/src/qt_gui/background_music_player.cpp b/src/qt_gui/background_music_player.cpp index 37d877098..a40c5bfae 100644 --- a/src/qt_gui/background_music_player.cpp +++ b/src/qt_gui/background_music_player.cpp @@ -10,6 +10,12 @@ BackgroundMusicPlayer::BackgroundMusicPlayer(QObject* parent) : QObject(parent) m_mediaPlayer->setLoops(QMediaPlayer::Infinite); } +void BackgroundMusicPlayer::setVolume(int volume) { + float linearVolume = QAudio::convertVolume(volume / 100.0f, QAudio::LogarithmicVolumeScale, + QAudio::LinearVolumeScale); + m_audioOutput->setVolume(linearVolume); +} + void BackgroundMusicPlayer::playMusic(const QString& snd0path) { if (snd0path.isEmpty()) { stopMusic(); diff --git a/src/qt_gui/background_music_player.h b/src/qt_gui/background_music_player.h index 52f44f431..6d70fe68c 100644 --- a/src/qt_gui/background_music_player.h +++ b/src/qt_gui/background_music_player.h @@ -16,6 +16,7 @@ public: return instance; } + void setVolume(int volume); void playMusic(const QString& snd0path); void stopMusic(); @@ -25,4 +26,4 @@ private: QMediaPlayer* m_mediaPlayer; QAudioOutput* m_audioOutput; QUrl m_currentMusic; -}; \ No newline at end of file +}; diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 759c6992e..18cbdac56 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -527,7 +527,11 @@ void MainWindow::PlayBackgroundMusic() { int itemID = isTableList ? m_game_list_frame->currentItem()->row() : m_game_grid_frame->crtRow * m_game_grid_frame->columnCnt + m_game_grid_frame->crtColumn; - + if (itemID > m_game_info->m_games.size() - 1) { + // Can happen in grid mode + BackgroundMusicPlayer::getInstance().stopMusic(); + return; + } QString snd0path; Common::FS::PathToQString(snd0path, m_game_info->m_games[itemID].snd0_path); BackgroundMusicPlayer::getInstance().playMusic(snd0path); @@ -619,6 +623,7 @@ void MainWindow::ConfigureGuiFromSettings() { } else { ui->setlistModeGridAct->setChecked(true); } + BackgroundMusicPlayer::getInstance().setVolume(Config::getBGMvolume()); } void MainWindow::SaveWindowState() const { diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index e02aeed9e..f8214f298 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -140,8 +140,17 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge checkUpdate->exec(); }); - connect(ui->playBGMCheckBox, &QCheckBox::stateChanged, this, - [](int val) { Config::setPlayBGM(val); }); + connect(ui->playBGMCheckBox, &QCheckBox::stateChanged, this, [](int val) { + Config::setPlayBGM(val); + if (val == Qt::Unchecked) { + BackgroundMusicPlayer::getInstance().stopMusic(); + } + }); + + connect(ui->BGMVolumeSlider, &QSlider::valueChanged, this, [](float val) { + Config::setBGMvolume(val); + BackgroundMusicPlayer::getInstance().setVolume(val); + }); } // GPU TAB @@ -231,6 +240,7 @@ void SettingsDialog::LoadValuesFromConfig() { ui->nullGpuCheckBox->setChecked(Config::nullGpu()); ui->dumpPM4CheckBox->setChecked(Config::dumpPM4()); ui->playBGMCheckBox->setChecked(Config::getPlayBGM()); + ui->BGMVolumeSlider->setValue((Config::getBGMvolume())); ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode()); ui->showSplashCheckBox->setChecked(Config::showSplash()); ui->ps4proCheckBox->setChecked(Config::isNeoMode()); @@ -371,4 +381,4 @@ bool SettingsDialog::eventFilter(QObject* obj, QEvent* event) { } } return QDialog::eventFilter(obj, event); -} \ No newline at end of file +} diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui index ca71d5ca4..2ca22253d 100644 --- a/src/qt_gui/settings_dialog.ui +++ b/src/qt_gui/settings_dialog.ui @@ -52,7 +52,7 @@ 0 0 836 - 442 + 446 @@ -369,7 +369,7 @@ 10 30 241 - 41 + 71 @@ -386,6 +386,55 @@ + + + + + + + + Volume + + + + + + + Set the volume of the background music. + + + 100 + + + 10 + + + 20 + + + 50 + + + Qt::Orientation::Horizontal + + + false + + + false + + + QSlider::TickPosition::NoTicks + + + 10 + + + + + + + diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index b62125a7a..0294dd138 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -534,6 +534,11 @@ Play title music تشغيل موسيقى العنوان + + + Volume + الصوت + MainWindow diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index c41b34431..da8ab5901 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -534,6 +534,11 @@ Play title music Afspil titelsang + + + Volume + Lydstyrke + MainWindow diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index 028f448bc..486b3ce02 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -534,6 +534,11 @@ Play title music Titelmusik abspielen + + + Volume + Lautstärke + MainWindow diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index ed3e0336d..35d2ddbea 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -534,6 +534,11 @@ Play title music Αναπαραγωγή μουσικής τίτλου + + + Volume + ένταση + MainWindow diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index b0da5bde2..3310ba1ca 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -534,6 +534,11 @@ Play title music Play title music + + + Volume + Volume + MainWindow diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index 730346d84..740624aea 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -534,6 +534,11 @@ Play title music Reproducir la música de apertura + + + Volume + Volumen + MainWindow diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 217edb780..5c566dab3 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -534,6 +534,11 @@ Play title music پخش موسیقی عنوان + + + Volume + صدا + MainWindow diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index 68e47a6b6..02202ed20 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -534,6 +534,11 @@ Play title music Soita otsikkomusiikkia + + + Volume + Äänenvoimakkuus + MainWindow diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index e47299964..6572f303b 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -534,6 +534,11 @@ Play title music Lire la musique du titre + + + Volume + Volume + MainWindow diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 0d0d45262..05973faf0 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -534,6 +534,11 @@ Play title music Címzene lejátszása + + + Volume + Hangerő + MainWindow diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index 9efa123fe..49abf2371 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -534,6 +534,11 @@ Play title music Putar musik judul + + + Volume + Volume + MainWindow diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index e3203862b..e83e15838 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -534,6 +534,11 @@ Play title music Riproduci musica del titolo + + + Volume + Volume + MainWindow diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index 4e079f1d3..290b6be9e 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -534,6 +534,11 @@ Play title music タイトル音楽を再生する + + + Volume + 音量 + MainWindow diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index 1476a893d..fba167632 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -534,6 +534,11 @@ Play title music Play title music + + + Volume + 음량 + MainWindow diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index abf084e0b..52fdbbc50 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -534,6 +534,11 @@ Play title music Groti antraštės muziką + + + Volume + Garsumas + MainWindow diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index b3797ae05..2dd1b431e 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -534,6 +534,11 @@ Play title music Spill tittelmusikk + + + Volume + Volum + MainWindow diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index cf659acbe..9636037cc 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -534,6 +534,11 @@ Play title music Titelmuziek afspelen + + + Volume + Volume + MainWindow diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 810971804..ae7e5cfae 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -534,6 +534,11 @@ Play title music Odtwórz muzykę tytułową + + + Volume + Głośność + MainWindow diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index 4676dfff6..a1e5d77ca 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -534,6 +534,11 @@ Play title music Reproduzir música de abertura + + + Volume + Volume + MainWindow diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index ac298469d..3667f699d 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -534,6 +534,11 @@ Play title music Redă muzica titlului + + + Volume + Volum + MainWindow diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index ca828c433..fbbe07f45 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -534,6 +534,11 @@ Play title music Воспроизведение заглавной музыки + + + Volume + Громкость + MainWindow diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index 710de63f9..ea377808e 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -534,6 +534,11 @@ Play title music Luaj muzikën e titullit + + + Volume + Volumi + MainWindow diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index a4fa289f2..87ebee69e 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -534,6 +534,11 @@ Play title music Başlık müziğini çal + + + Volume + Ses seviyesi + MainWindow diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index af5eb5249..485997019 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -534,6 +534,11 @@ Play title music Phát nhạc tiêu đề + + + Volume + Âm lượng + MainWindow diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 638fa08cb..2505e8acc 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -534,6 +534,11 @@ Play title music 播放标题音乐 + + + Volume + 音量 + MainWindow diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 4d508d2ad..826f843f4 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -534,6 +534,11 @@ Play title music 播放標題音樂 + + + Volume + 音量 + MainWindow From dc96338c2e972c9a660cdb68209877e67b961946 Mon Sep 17 00:00:00 2001 From: tGecko Date: Sat, 28 Sep 2024 20:04:47 +0200 Subject: [PATCH 03/34] Improve keyboard navigation in game list (#1132) * Improve keyboard navigation * don't start game in elf viewer mode or gridview mode with empty item selected * fix eventFilter return --- src/qt_gui/game_grid_frame.cpp | 39 +++++++++++++++++++++---------- src/qt_gui/game_grid_frame.h | 6 ++++- src/qt_gui/game_list_frame.cpp | 12 +++++++++- src/qt_gui/game_list_frame.h | 4 +++- src/qt_gui/main_window.cpp | 42 +++++++++++++++------------------- src/qt_gui/main_window.h | 2 ++ 6 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/qt_gui/game_grid_frame.cpp b/src/qt_gui/game_grid_frame.cpp index 3113aecc0..29ea31ebc 100644 --- a/src/qt_gui/game_grid_frame.cpp +++ b/src/qt_gui/game_grid_frame.cpp @@ -22,7 +22,7 @@ GameGridFrame::GameGridFrame(std::shared_ptr game_info_get, QWidg this->setContextMenuPolicy(Qt::CustomContextMenu); PopulateGameGrid(m_game_info->m_games, false); - connect(this, &QTableWidget::cellClicked, this, &GameGridFrame::SetGridBackgroundImage); + connect(this, &QTableWidget::currentCellChanged, this, &GameGridFrame::onCurrentCellChanged); connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &GameGridFrame::RefreshGridBackgroundImage); @@ -31,22 +31,33 @@ GameGridFrame::GameGridFrame(std::shared_ptr game_info_get, QWidg connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) { m_gui_context_menus.RequestGameMenu(pos, m_game_info->m_games, this, false); }); - connect(this, &QTableWidget::cellClicked, this, [&]() { - cellClicked = true; - crtRow = this->currentRow(); - crtColumn = this->currentColumn(); - columnCnt = this->columnCount(); - }); } -void GameGridFrame::PlayBackgroundMusic(QTableWidgetItem* item) { - if (!item) { +void GameGridFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow, + int previousColumn) { + cellClicked = true; + crtRow = currentRow; + crtColumn = currentColumn; + columnCnt = this->columnCount(); + + auto itemID = (crtRow * columnCnt) + currentColumn; + if (itemID > m_game_info->m_games.count() - 1) { + validCellSelected = false; BackgroundMusicPlayer::getInstance().stopMusic(); return; } - QString snd0path; - Common::FS::PathToQString(snd0path, m_game_info->m_games[item->row()].snd0_path); - BackgroundMusicPlayer::getInstance().playMusic(snd0path); + validCellSelected = true; + SetGridBackgroundImage(crtRow, crtColumn); + auto snd0Path = QString::fromStdString(m_game_info->m_games[itemID].snd0_path.string()); + PlayBackgroundMusic(snd0Path); +} + +void GameGridFrame::PlayBackgroundMusic(QString path) { + if (path.isEmpty()) { + BackgroundMusicPlayer::getInstance().stopMusic(); + return; + } + BackgroundMusicPlayer::getInstance().playMusic(path); } void GameGridFrame::PopulateGameGrid(QVector m_games_search, bool fromSearch) { @@ -157,3 +168,7 @@ void GameGridFrame::RefreshGridBackgroundImage() { this->setPalette(palette); } } + +bool GameGridFrame::IsValidCellSelected() { + return validCellSelected; +} diff --git a/src/qt_gui/game_grid_frame.h b/src/qt_gui/game_grid_frame.h index 0083fd688..c09767684 100644 --- a/src/qt_gui/game_grid_frame.h +++ b/src/qt_gui/game_grid_frame.h @@ -20,7 +20,9 @@ Q_SIGNALS: public Q_SLOTS: void SetGridBackgroundImage(int row, int column); void RefreshGridBackgroundImage(); - void PlayBackgroundMusic(QTableWidgetItem* item); + void PlayBackgroundMusic(QString path); + void onCurrentCellChanged(int currentRow, int currentColumn, int previousRow, + int previousColumn); private: QImage backgroundImage; @@ -28,10 +30,12 @@ private: GuiContextMenus m_gui_context_menus; std::shared_ptr m_game_info; std::shared_ptr> m_games_shared; + bool validCellSelected = false; public: explicit GameGridFrame(std::shared_ptr game_info_get, QWidget* parent = nullptr); void PopulateGameGrid(QVector m_games, bool fromSearch); + bool IsValidCellSelected(); bool cellClicked = false; int icon_size; diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp index 45e52f37d..818ee17ec 100644 --- a/src/qt_gui/game_list_frame.cpp +++ b/src/qt_gui/game_list_frame.cpp @@ -41,7 +41,7 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, QWidg this->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); PopulateGameList(); - connect(this, &QTableWidget::itemClicked, this, &GameListFrame::SetListBackgroundImage); + connect(this, &QTableWidget::currentCellChanged, this, &GameListFrame::onCurrentCellChanged); connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &GameListFrame::RefreshListBackgroundImage); connect(this->horizontalScrollBar(), &QScrollBar::valueChanged, this, @@ -69,6 +69,16 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, QWidg }); } +void GameListFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow, + int previousColumn) { + QTableWidgetItem* item = this->item(currentRow, currentColumn); + if (!item) { + return; + } + SetListBackgroundImage(item); + PlayBackgroundMusic(item); +} + void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) { if (!item) { BackgroundMusicPlayer::getInstance().stopMusic(); diff --git a/src/qt_gui/game_list_frame.h b/src/qt_gui/game_list_frame.h index a1ec5c563..2c3fffff9 100644 --- a/src/qt_gui/game_list_frame.h +++ b/src/qt_gui/game_list_frame.h @@ -23,6 +23,8 @@ public Q_SLOTS: void SortNameAscending(int columnIndex); void SortNameDescending(int columnIndex); void PlayBackgroundMusic(QTableWidgetItem* item); + void onCurrentCellChanged(int currentRow, int currentColumn, int previousRow, + int previousColumn); private: void SetTableItem(int row, int column, QString itemStr); @@ -63,4 +65,4 @@ public: } return false; } -}; \ No newline at end of file +}; diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 18cbdac56..6f4a4ef7b 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include @@ -21,6 +22,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); + installEventFilter(this); setAttribute(Qt::WA_DeleteOnClose); } @@ -306,6 +308,7 @@ void MainWindow::CreateConnects() { }); // List connect(ui->setlistModeListAct, &QAction::triggered, m_dock_widget.data(), [this]() { + BackgroundMusicPlayer::getInstance().stopMusic(); m_dock_widget->setWidget(m_game_list_frame.data()); m_game_grid_frame->hide(); m_elf_viewer->hide(); @@ -322,6 +325,7 @@ void MainWindow::CreateConnects() { }); // Grid connect(ui->setlistModeGridAct, &QAction::triggered, m_dock_widget.data(), [this]() { + BackgroundMusicPlayer::getInstance().stopMusic(); m_dock_widget->setWidget(m_game_grid_frame.data()); m_game_grid_frame->show(); m_game_list_frame->hide(); @@ -338,6 +342,7 @@ void MainWindow::CreateConnects() { }); // Elf connect(ui->setlistElfAct, &QAction::triggered, m_dock_widget.data(), [this]() { + BackgroundMusicPlayer::getInstance().stopMusic(); m_dock_widget->setWidget(m_elf_viewer.data()); m_game_grid_frame->hide(); m_game_list_frame->hide(); @@ -512,29 +517,6 @@ void MainWindow::CreateConnects() { isIconBlack = false; } }); - - connect(m_game_grid_frame.get(), &QTableWidget::cellClicked, this, - &MainWindow::PlayBackgroundMusic); - connect(m_game_list_frame.get(), &QTableWidget::cellClicked, this, - &MainWindow::PlayBackgroundMusic); -} - -void MainWindow::PlayBackgroundMusic() { - if (isGameRunning || !Config::getPlayBGM()) { - BackgroundMusicPlayer::getInstance().stopMusic(); - return; - } - int itemID = isTableList ? m_game_list_frame->currentItem()->row() - : m_game_grid_frame->crtRow * m_game_grid_frame->columnCnt + - m_game_grid_frame->crtColumn; - if (itemID > m_game_info->m_games.size() - 1) { - // Can happen in grid mode - BackgroundMusicPlayer::getInstance().stopMusic(); - return; - } - QString snd0path; - Common::FS::PathToQString(snd0path, m_game_info->m_games[itemID].snd0_path); - BackgroundMusicPlayer::getInstance().playMusic(snd0path); } void MainWindow::StartGame() { @@ -1047,3 +1029,17 @@ void MainWindow::OnLanguageChanged(const std::string& locale) { LoadTranslation(); } + +bool MainWindow::eventFilter(QObject* obj, QEvent* event) { + if (event->type() == QEvent::KeyPress) { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) { + auto tblMode = Config::getTableMode(); + if (tblMode != 2 && (tblMode != 1 || m_game_grid_frame->IsValidCellSelected())) { + StartGame(); + return true; + } + } + } + return QMainWindow::eventFilter(obj, event); +} diff --git a/src/qt_gui/main_window.h b/src/qt_gui/main_window.h index 9294ef8c9..c1d5cc26e 100644 --- a/src/qt_gui/main_window.h +++ b/src/qt_gui/main_window.h @@ -94,6 +94,8 @@ private: QTranslator* translator; protected: + bool eventFilter(QObject* obj, QEvent* event) override; + void dragEnterEvent(QDragEnterEvent* event1) override { if (event1->mimeData()->hasUrls()) { event1->acceptProposedAction(); From 36271b9cdf4626f62118e328d08007a05d05508c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=A5IGA?= <164882787+Xphalnos@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:49:48 +0200 Subject: [PATCH 04/34] Best icons for flags (#1133) --- src/images/flag_china.png | Bin 572 -> 324 bytes src/images/flag_eu.png | Bin 942 -> 453 bytes src/images/flag_jp.png | Bin 371 -> 278 bytes src/images/flag_us.png | Bin 321 -> 545 bytes src/images/flag_world.png | Bin 2995 -> 1476 bytes src/qt_gui/main_window.cpp | 2 +- 6 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/images/flag_china.png b/src/images/flag_china.png index 13bf221e982aad18c472337c2056b15b1d588ff7..33fcdfd86de4ccaea5c1d639686dbc9b5b5d7453 100644 GIT binary patch delta 277 zcmV+w0qXv|1jGW6IDY{4NklBJ2F8q&7!~-3kLZXl=5*!3C$f~%K%CFpd2t@4zQ&v9(BO#(I^-Vfx#03qhJ(_ bXaE3BwLVmQR1WYd00000NkvXXu0mjftniB= delta 527 zcmV+q0`UFB0=xu}IDY}|Nkl?wosP1YzE0zFm2} zn->e7uTzfze+l9wZebeab`b*aG-SDhx+Fmjp@%|H#ixPbV}GV?oIvlU?Z2af^ZpQE zGU9wN2&Ekba%vDN*sn7Y^rU_P#|ieai3FIo$uoffBvwRdK87K^CBX;wi}<}}6IVZ5 zvOpqgP6!}!3U>}CjQjnNJyf8Tj6m&HgNJ~xBcf~OVg$cYcFbimPWWel!Y!MrG8Z_e(XxxY4O%tJHTV;=cF}yHT zKo%!5Z!{b|y+^7S?e%SAJ9(Kn|@kj!2 z#d)^pt{q1GaO&_GTYyu?@7My|!d$@r5ire5>E(i_F|}(skz3dDd7Jt64HLN#Sx6^# R3jhEB00>D%PDHLkV1gaq>J0z@ diff --git a/src/images/flag_eu.png b/src/images/flag_eu.png index 0922e11ec850c85b89e72834c980147a6ff1a624..461f814e185fef05cd9924c664768c98dd9d6734 100644 GIT binary patch delta 407 zcmV;I0cifN2gL)BIDY|mNklLc-R4QBiMgQ)~V1Im<>xh8`bB|u1`zV>- z=l*D-!ay5i$blo>fNIz@IeSDS@iQ9NPx#x;Y0ZHPjT8feT9xh_Iz8MZXlSbHx-xLU zg$7zFJCL@Dw763ATwvfrBkc$VChESc+)d-z!0N^pRVzsv)8C8D3&4d2+Q0@%Ws4qf zTjmtUDs|Obv zDMct$hlZ!m8EB`>-5+_)Tq|FS0r7#QOo3jWB4lQEzMM10kOQZ4kC9>1^4c~(IGFg< zPBGBN80TEB;6MgM8x9XlMsNO*2$=@L2&1Rt4NA{i01$*jevAMB002ovPDHLkV1g3V Bz!U%g delta 899 zcmV-}1AP3&1Fi>gk+!o37Nk zxltE-;N|H(J8j#ysMA(iR7}${GyG#)=6|t8;RUyPZR;RJz7I*} zY|tiFKS6?O8tHis_MC!Pn1O`#h2p~(H+TT*Sx*pe@VJag^tYx#$Ztcu!o3QDERq12 zL+)HGOylhJF$#V~+lRUSSYT0v&vOT0x2Yf%Cg>j@6AU9k1K`dQlv6mDIf538j#kdC z#89&WAXYxk`hQ&1-_@LnIE9PA1OgEp07j)$?MCh0GAs_Cz{lBxuvxT7(e$FmY=FL` z0S$G9Q0lvoU)q3?&P({Qup2$iN)(hgdYA|gfG6Lw>^^*dv4>V%V=iMkcR?b!r~tW1 zR4#}WV|X=uoW{&J#1JdTBL_gDa$;fN6w7r6EOkYc5`X`q06wW*(>ZW4YYEWh>i z9#HdsOvK73;Ot3)T-UWK(NF;-YXRDZ~S&)b{ov1LH+4njiynuOdV|5i9 zKjGPo*jS0MK5IeCP%5~Qb+Z*6RyAIa9Ak{!XMgoEv_^&*dOHl2)mUPiRqm}u$n)&s z$E;` ziFdBUcr$tww~ao@CDp8_F+q03^vFr0E_I5N)vyDLK8g zGko&Zew*J*dxbj8N&@P+3(4bzx`7x1y~B@RKM9!Y$k@*?+r~MxSX~@?Fb6g>kdpa&Wqq@3d{- Zego|qA-I-;z?=(-(I%>CXDWobKrn;sZ*F>wIK`EK%S2%kzk4WJtFF!|Z4-Cu?WkX7XkAbA}gpwDw} z0E|rwP!vDd0wvnCm(budWX$Us>PbiZh!{)s5iO^UlXfM>KI6qi%X;JHd`|u{fC*#* g&>z(T66vpX1opD|%Y~=)5&!@I07*qoM6N<$g5xu4V*mgE delta 324 zcmV-K0lWT|0`mfpIDY{pNklI^grWkN+QcwEw?mX88Yt5DyrG*dQ^G98DeY@y@;f z*G%;PUl8QRia~N9H8gR+mrq~*U$-*DX*mpo)PU4d-2u;LOn)b6IShl;Qr!W!e7%Tv z07xy>9dJcMnP>-q)KcF8I_ktb0H~Jg4!9i}NVEe$YN_sk7fY59?SSWt7gOH>U%&nQ zf79E8pyePnAhpzY01$tA{__7#PgmTQ1LZzFdqI?0jA+KL(nP{bqu6u7%J{_H>cB6dR)03oo>eug{b3UB6-@RRqQ%yD1 zIF9pLXNKIyskL-*(d(EIhx$ioAdd_il;vA1-S3$tK}Z+jynkAF%g&&J+*+4V8t7>7 ziymJLOx=f2W{84!DNY!DjOSK_38Sww?ZW)xEfi>ZST{L9?y*oo9CKbM4K&;K5`pjo z433^dQB4GHZbicAV;rYV|e$#-qWe4K-G9WuAuHf)ANmh@H{@1*J^^Sm<2F!Y&h{dMo zu1V2G>pt|m&d9XL=zq;y>_-GlHJ~@|K~8yy6vcvM)#V|;I6nWBXQqMn_Rv%8PJ&r) z3~G$KfQF1d#&POYzR!6IlKcUM)jV4blRcz6;O&EQQ0q*Mgz}+JqfKWTJuBQP(ByEmaK&|3U+@ py)%GK{3ay3ZCU*tRZX=&VV~aAcNEb)_gw%0002ovPDHLkV1j(J_FVt~ delta 274 zcmV+t0qy>w1i=E3IDY{1NklKtM#ZxFPBmBkq=ESvFnFKIz;SGdG>dG+Sndf_Q`K zVAM@lP_(wEr8=VwlQ}k>fK!Th?p2_uXa#zgIUG~kp2B~551eCaFMw{}e3E{8d(Q9w zKKH}pJ+mh;1t3tmkfx^bK1E}Zf7*pvT7b{{KTQctSJTKoDv}A zzXXdZ8hh0=+$?CX6Oi_L@QJMzE37S8_oor^hptCrXt*gFMF#=VQ^8ekETCvu$xBr< zu+lV$)LI%LCtV1uu;RsAMR>)LiMjSHq}euMPRntuzV3v|%?Y`ya^uY>e}YpUe5j`3 zBrnS70pc!sFz%Ea&z*2#e0e`6{QLmXr>`;a+4hY{vu8tcrV?RF2d0(wAggoOBQ%^E z50;Jzu6E;97XFd>4ra8MApkZ#Y!41*S_#$A|ss}Lba??YUz zW8lfnC0_6-?IGZ?zxHA9UB<<0>=gj&o?k`CpQl{ z+KcB8_ae5s3NvmLdch~j&4{~Ff~mG`NVMi)iX|7Tj2*0q!qJqPe_KfpV7^&43}26# zHx(Q_^q2!-KiM%+dk^7<%!p8%z2K8}b%S53LxNd~Db^gsS#uHJUIc~P!-RqYrUi~Y z4JlE GV2=Q}oFj%hnmS`OkRql}69EZb&?Dr%U7dmKJ_rxB8x!yH^Xq% z*)rW0*!>>p$)DzTeoT5rgl|Wu1un{yO5#QvYzvH<)b6!`iOfj2FlpfAN?7i^$=pHiO@r$6qM- zA9GnJBJ+(99MT1aN0{@ltXj4@I$>HY~JLcLpGw`IwQl`|VHfa%CeKH_C zYR7Ge>lH!aVdi`+GhAi6<9ogyaA7t%l-?VFSXYDD_G}1#uSJ-~&fHvhLKhG&(4HL; zKGFOw)^-_(e+0NN%SV6~;FH5*=ODt5^g>W^1uqy2AUSg?=*^>ZJ0QMDjR+6vE`Yo* zND>kw^PGs7TiJ(Dbq~T+b_jo~LDE$P67&irG$|mi_yv&#w>fysmKzXgsvxM_2mZwa zh`zqd7j7;9zmZ~hhI(EgqiEzXZMfa(m2k-&J2B0+f0b*m!m>&Z&d+X#AhQj^j8=%g zx(4C8CQR!1&I>-?RDgFIF0ul)1QbvLq%f0<2BshF;oP2RkU#3}!*wohlS6Q<+zT%H zLJ#qpCPY@Mz2KoOd$8Y0Gp+alkQ`6|F|x@JrDUE*77fK*{70D=oJ%;vZXdX0bt7Vm z%Q^VCe=Zr88`{|H-_0Az4gw-}3;MXOZ>Y%>wlY)g@jB;M{OALZU0DywnhO};DZ@CE z4C!^JS-6FCTi$3_G4=35@>#>*;O7}3(eLqw*B3*yxy}b3x1tvD%P%AJoC5PMRk35Z zU*kqPZ!D(qU@0qNW5+`zoiFuyHu%63R@LDxSv$V0c0lDGD6E8Y7zwStiIl5AtEsKzXor#8P`&QvxxhpOXp7ewqbrug{DZ b7u@~@Ng9?sYKq$500000NkvXXu0mjf=3KRv literal 2995 zcmV;k3rzHhP)s0XZ`zt;#D(6d`yw1R7R4MiCK;|kd-2#gnH%f|KAr(vLUk<;FKv&@;uG= zueJ8s_uPY!I@3(Un%Q$6d+oLU=l6gA+HGyS$L_Iv{QnP=@Ue!nPruZh{oUhlw2mhk zlJ8o_k60(`Ey-rR@ZHJ7#>scelupFlm)x(Ko?=PPZ|h#N$IBMlcK7U!%Q(5qI$phR z((~q4^9IjcZ7uPQ#>oqoq`oT`=0eeqTHnZ)n|Cf8WF0TDPI|EK&J-RnOf@|V7Pn4r zF;1RtwNb~k<*&DnFS8^YRWQffjN^waF_kI%fKB=i=%{34hhHFLh9%j%%TA_PCy60m zj=4dZ&4y(5$n(~`u6h08?y<5V`LiLuxs>!CXsdGGt_h#;v6lF6*70cTnI?OrzFPeJHX z!e6zHFR_W#jLXi{b*eI<7>ecEV@Da1--WfFDpk@^{XHy~`}y^D>v*OmzGsJmmusu{ zN75kPkwmbbA^DYY(%H}QL3m5DI11A-t#3a|*%y$+x=z6ZC6|39{>FSme5!SP6P_o@b$@SLBZ{ZC?GJRmeIDSYMCw|eA%-iq0HE$};2?<+|h*Ykn2LXK`WSnzoci(Hv zjz3u@IU7J=NoK(H_+EB$jwLy_lw=9IT#bgp(RG4p`m8vplP^ zkYxC;F`>$zHzdCa3S0;+VVV9=sc5rxSXJH?JasZ$jAw&_AGD4q7xM)ngsb5Jgqoah z9seA8VH-ejb-`mmvrR*5^0tQYqzhg_n0gsyLoqtA`Aq9%Z6QwYHBP4F_la)|E}tJP zGRl&S$M+%C?CqB1hM~moZw{em1@iTh^cX|js~*a8iZ2LzEeLzf%R`aUiI(_&)TOqr zo;?-498b*`G)^u?^+a;u6NwY!5bzg@)K(pRJ~!0J=o$_%O;&3tpXN9AAX* z_z(9~ASdT&9yp#1OL~Zu%|jDD+*DSL2=KZwPgX5#>aF<*H7JNRf(V)vUos>=vQF;s zE|lX7-kB6))rXjqG1y4&P45}32@J0!y$2d66@*|!qM`>p+VC{Y33HG4VZ@UF5XSMh z%2oMT2;&E_XNlx91tX8KPPQ15?oiD?1aAOEjz)|}Dgdh$5k-^7|F4-}(A<9ybCr4| zQbP^Un_WG7VpCJg#v(~kosHvfqQ-<=7!L$9#6Jc^7S}eERYPvvl>O%!Z4rmj@#t`2Mm;;r-I`Ehw`L!k9uDpi$ zQRDdEmSmwC%gO0LGUQtHXjGt7N#7UpU_~L3uU8|H%u_U@-Xqo6miQV#WQlqYQ=yXd zBygaD2R2|aU^uFCbZgo1JCV46;2ceg7jmhVjYWv%e5r}hS>pQvnV>H!WK|{rzK0Qa zgn8>4a`4TDcrNaT;&(Ul3j)qEB>%(>Tu5NhfJW@`CgcUGG%N+{cu%Cq!E+uKrK^R2 zS4HmtHe0e%%Br9u5fWilZ^$Kk05njO3LZ!x2ln@LhPNw(dx(;{ek$LPdc^vM0_k?R z8lKWbb<&A2(U^C9CwP8CaDK`<`2nC;4FLr4aM`TDMlEn8XNM}=1?~f-N|kJ)?paU( z9#dseS4GleQM2P=|TrebSAW#vriy;IUMI{aY&jMLPLi*%V{9fTVkvXW?P!a@B zg>2~oo(p3k**%iU2|%`1Aq21ZJeBoGVngznca1hJUL$C%g{dkN3a)$DLt5{Vx=12t zXdw$!7=+AFb_gtp5X2`0gVnJXV9z-DNAS+3*aw6rs1sg@cps~Jp2W(1ayhyh`|@@$ z1$|B#VfWg-jFXjsxS;9E0{;5&a55iFPQc+jB#h%!H>k-GV4kRuNOpJ(&uRlh{G1{A zOQ`UG>!0L;QGi{Kc#~BD$F3Ph!GCLqK=px^8h<2nuxYs}M**LW<7e{N3prw) z_O}CDM8|)}V!9v%uBN9nlvlp9-V*;&(T?~@5HcvE^K02y?1{N(USi+vJ39q}oXSHc z^crY}LXyviSA25#>U(jBZFPBkut6nwn^tQdDvIfy%==d{%?VI~KQU>Vt>1(E{$rlL|z}fWxj3i!Y$4!GbxQ1s7^~ z03|BvsDctt#HKx*;&pVS_c8gXfnrR74RUf1KEjzf^0;= z)4AFJ$=U$jlllpt=K{%fVXI8pN1hJxP!84G;KI6r499VRN_+4T~Zjcu`2& z@VOSoXxrHUMMjpR_@Hd-gT!;aa(W=9h9(4p5CP)%=84)iJv z)97`t)T2j|8&FJ9903%#&=dc6t9C9NZ}JBiH}{002ovPDHLkV1j*Kp{oD@ diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 6f4a4ef7b..2981da3a7 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -5,12 +5,12 @@ #include #include -#include #include "about_dialog.h" #include "cheats_patches.h" #include "check_update.h" #include "common/io_file.h" #include "common/path_util.h" +#include "common/scm_rev.h" #include "common/string_util.h" #include "common/version.h" #include "core/file_format/pkg.h" From 545e94d2674e52b244c8510b081bffb59a86731c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=A5IGA?= <164882787+Xphalnos@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:01:15 +0200 Subject: [PATCH 05/34] Remove dead Links from readme (#1135) --- README.md | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 83f59a2c1..6d6e2d82c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ SPDX-License-Identifier: GPL-2.0-or-later # General information -shadPS4 is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++. +**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++. If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/Quickstart.md). @@ -44,7 +44,7 @@ To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Di To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/). -For those who'd like to donate to the project, we now have a [Kofi page!](https://ko-fi.com/shadps4) +For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)! # Status @@ -74,38 +74,9 @@ Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shad > [!IMPORTANT] > macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 11 on Intel-based Mac devices. -## Building status - -
-Windows - -| Windows | Build status | -|--------|--------| -|Windows SDL Build|[![Windows-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml) -|Windows Qt Build|[![Windows-qt](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows-qt.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows-qt.yml) -
- -
-Linux - -| Linux | Build status | -|--------|--------| -|Linux SDL Build|[![Linux-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml) -|Linux Qt Build|[![Linux-qt](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux-qt.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux-qt.yml) -
- -
-macOS - -| macOS | Build status | -|--------|--------| -|macOS SDL Build|[![macOS-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos.yml) -|macOS Qt Build|[![macOS-qt](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos-qt.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos-qt.yml) -
- # Debugging and reporting issues -For more information on how to test, debug and report issues with the emulator or games, read the [Debugging documentation](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md). +For more information on how to test, debug and report issues with the emulator or games, read the [**Debugging documentation**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md). # Keyboard mapping From a4168150eda5c4929827a6838c7e963739951ac0 Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Sat, 28 Sep 2024 18:01:35 -0300 Subject: [PATCH 06/34] + tr (#1136) --- src/qt_gui/settings_dialog.cpp | 2 +- src/qt_gui/translations/ar.ts | 6 +++--- src/qt_gui/translations/da_DK.ts | 6 +++--- src/qt_gui/translations/de.ts | 6 +++--- src/qt_gui/translations/el.ts | 6 +++--- src/qt_gui/translations/en.ts | 12 ++++++------ src/qt_gui/translations/es_ES.ts | 6 +++--- src/qt_gui/translations/fa_IR.ts | 8 ++++---- src/qt_gui/translations/fi.ts | 6 +++--- src/qt_gui/translations/fr.ts | 6 +++--- src/qt_gui/translations/hu_HU.ts | 8 ++++---- src/qt_gui/translations/id.ts | 8 ++++---- src/qt_gui/translations/it.ts | 8 ++++---- src/qt_gui/translations/ja_JP.ts | 6 +++--- src/qt_gui/translations/ko_KR.ts | 8 ++++---- src/qt_gui/translations/lt_LT.ts | 6 +++--- src/qt_gui/translations/nb.ts | 6 +++--- src/qt_gui/translations/nl.ts | 6 +++--- src/qt_gui/translations/pl_PL.ts | 6 +++--- src/qt_gui/translations/pt_BR.ts | 14 +++++++------- src/qt_gui/translations/ro_RO.ts | 6 +++--- src/qt_gui/translations/ru_RU.ts | 8 ++++---- src/qt_gui/translations/sq.ts | 6 +++--- src/qt_gui/translations/tr_TR.ts | 6 +++--- src/qt_gui/translations/vi_VN.ts | 6 +++--- src/qt_gui/translations/zh_CN.ts | 6 +++--- src/qt_gui/translations/zh_TW.ts | 6 +++--- 27 files changed, 92 insertions(+), 92 deletions(-) diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index f8214f298..478f7b986 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -70,7 +70,7 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge InitializeEmulatorLanguages(); LoadValuesFromConfig(); - defaultTextEdit = tr("Point your mouse at an options to display a description in here"); + defaultTextEdit = tr("Point your mouse at an option to display it's description."); ui->descriptionText->setText(defaultTextEdit); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close); diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index 0294dd138..d8e8e3e04 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - وجه مؤشر الفأرة إلى خيار لعرض الوصف هنا + Point your mouse at an option to display it's description. + وجّه الماوس نحو خيار لعرض وصفه. @@ -1021,7 +1021,7 @@ updaterGroupBox - التحديث:\nمستقر: إصدارات رسمية يتم إصدارها شهريًا، قد تكون قديمة جدًا ولكنها أكثر استقرارًا وتم اختبارها.\nغير مستقر: إصدارات التطوير التي تحتوي على أحدث الميزات والإصلاحات، لكنها قد تحتوي على أخطاء وأقل استقرارًا. + تحديث: Release: إصدارات رسمية تصدر شهريًا، قد تكون قديمة بعض الشيء، لكنها أكثر استقرارًا واختبارًا. Nightly: إصدارات تطوير تحتوي على أحدث الميزات والإصلاحات، لكنها قد تحتوي على أخطاء وأقل استقرارًا. diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index da8ab5901..f08fb07b4 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Placer musen på en indstilling for at vise en beskrivelse her + Point your mouse at an option to display it's description. + Peg musen over et valg for at vise dets beskrivelse. @@ -1021,7 +1021,7 @@ updaterGroupBox - Opdatering:\nStabil: Officielle builds, der frigives månedligt, som kan være meget ældre, men mere stabile og testet.\nUstabil: Udviklerbuilds med de nyeste funktioner og rettelser, men som kan indeholde fejl og være mindre stabile. + Opdatering:\nRelease: Officielle builds, der frigives månedligt, som kan være meget ældre, men mere stabile og testet.\nNightly: Udviklerbuilds med de nyeste funktioner og rettelser, men som kan indeholde fejl og være mindre stabile. diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index 486b3ce02..4f02b87ec 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Zeigen Sie mit der Maus auf eine Option, um hier eine Beschreibung anzuzeigen + Point your mouse at an option to display it's description. + Bewege die Maus über eine Option, um deren Beschreibung anzuzeigen. @@ -1021,7 +1021,7 @@ updaterGroupBox - Update:\nStabil: Offizielle Builds, die monatlich veröffentlicht werden, können viel älter sein, aber stabiler und getestet.\nUnstabil: Entwickler-Builds, die die neuesten Funktionen und Fehlerbehebungen enthalten, aber Fehler enthalten und weniger stabil sein können. + Update:\nRelease: Offizielle Builds, die monatlich veröffentlicht werden, können viel älter sein, aber stabiler und getestet.\nNightly: Entwickler-Builds, die die neuesten Funktionen und Fehlerbehebungen enthalten, aber Fehler enthalten und weniger stabil sein können. diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index 35d2ddbea..e6bafcac4 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Τοποθετήστε τον κέρσορα πάνω από μια επιλογή για να εμφανιστεί εδώ η περιγραφή + Point your mouse at an option to display it's description. + Τοποθετήστε το ποντίκι σας πάνω σε μια επιλογή για να εμφανίσετε την περιγραφή της. @@ -1021,7 +1021,7 @@ updaterGroupBox - Ενημερώσεις:\nΣταθερές: Επίσημες εκδόσεις που κυκλοφορούν μηνιαίως, είναι παλαιότερες αλλά πιο σταθερές και δοκιμασμένες.\nΑσταθείς: Εκδόσεις προγραμματιστών με νέες δυνατότητες και διορθώσεις, αλλά μπορεί να περιέχουν σφάλματα και να είναι λιγότερο σταθερές. + Ενημερώσεις:\nRelease: Επίσημες εκδόσεις που κυκλοφορούν μηνιαίως, είναι παλαιότερες αλλά πιο σταθερές και δοκιμασμένες.\nNightly: Εκδόσεις προγραμματιστών με νέες δυνατότητες και διορθώσεις, αλλά μπορεί να περιέχουν σφάλματα και να είναι λιγότερο σταθερές. diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 3310ba1ca..5915fc0ad 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Point your mouse at an options to display a description in here + Point your mouse at an option to display it's description. + Point your mouse at an option to display it's description. @@ -1021,7 +1021,7 @@ updaterGroupBox - Update:\nStable: Official versions released every month that may be very outdated, but are more reliable and tested.\nUnstable: Development versions that have all the latest features and fixes, but may contain bugs and are less stable. + Update:\nRelease: Official versions released every month that may be very outdated, but are more reliable and tested.\nNightly: Development versions that have all the latest features and fixes, but may contain bugs and are less stable. @@ -1061,17 +1061,17 @@ debugDump - Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory + Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory. vkValidationCheckBox - Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about it's internal state. This will reduce performance and likely change the behavior of emulation. + Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about it's internal state.\nThis will reduce performance and likely change the behavior of emulation. vkSyncValidationCheckBox - Enable Vulkan Synchronization Validation:\nEnables a system that validates the timing of Vulkan rendering tasks. This will reduce performance and likely change the behavior of emulation. + Enable Vulkan Synchronization Validation:\nEnables a system that validates the timing of Vulkan rendering tasks.\nThis will reduce performance and likely change the behavior of emulation. diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index 740624aea..ac0206b26 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Apunta con el ratón a una opción para mostrar una descripción aquí + Point your mouse at an option to display it's description. + Coloque el mouse sobre una opción para mostrar su descripción. @@ -1021,7 +1021,7 @@ updaterGroupBox - Actualización:\nEstable: Versiones oficiales lanzadas cada mes que pueden estar muy desactualizadas, pero son más confiables y están probadas.\nInestable: Versiones de desarrollo que tienen todas las últimas funciones y correcciones, pero pueden contener errores y son menos estables. + Actualización:\nRelease: Versiones oficiales lanzadas cada mes que pueden estar muy desactualizadas, pero son más confiables y están probadas.\nNightly: Versiones de desarrollo que tienen todas las últimas funciones y correcciones, pero pueden contener errores y son menos estables. diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index 5c566dab3..a944ddd5c 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Point your mouse at an options to display a description in here + Point your mouse at an option to display it's description. + ماوس خود را بر روی یک گزینه قرار دهید تا توضیحات آن نمایش داده شود. @@ -1021,7 +1021,7 @@ updaterGroupBox - Update:\nStable: Official versions released every month that may be very outdated, but are more reliable and tested.\nUnstable: Development versions that have all the latest features and fixes, but may contain bugs and are less stable. + Update:\nRelease: Official versions released every month that may be very outdated, but are more reliable and tested.\nNightly: Development versions that have all the latest features and fixes, but may contain bugs and are less stable. @@ -1061,7 +1061,7 @@ debugDump - Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory + Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory. diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index 02202ed20..47fdcd8e5 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Vie hiiri valinnan päälle näyttääksesi kuvauksen tähän + Point your mouse at an option to display it's description. + Siirrä hiiri vaihtoehdon päälle näyttämään sen kuvaus. @@ -1021,7 +1021,7 @@ updaterGroupBox - Päivitys:\nVakaa: Viralliset versiot, jotka julkaistaan joka kuukausi ja voivat olla hyvin vanhoja, mutta ovat luotettavampia ja testatumpia.\nEpävakaa: Kehitysversiot, joissa on kaikki uusimmat ominaisuudet ja korjaukset, mutta ne voivat sisältää bugeja ja ovat vähemmän vakaita. + Päivitys:\nRelease: Viralliset versiot, jotka julkaistaan joka kuukausi ja voivat olla hyvin vanhoja, mutta ovat luotettavampia ja testatumpia.\nNightly: Kehitysversiot, joissa on kaikki uusimmat ominaisuudet ja korjaukset, mutta ne voivat sisältää bugeja ja ovat vähemmän vakaita. diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index 6572f303b..34d28ce52 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Placez votre souris sur une option pour afficher une description ici + Point your mouse at an option to display it's description. + Pointez votre souris sur une option pour afficher sa description. @@ -1021,7 +1021,7 @@ updaterGroupBox - Mise à jour :\nStable : versions officielles publiées chaque mois qui peuvent être très anciennes, mais plus fiables et testées.\nInstable : versions de développement avec toutes les dernières fonctionnalités et correctifs, mais pouvant avoir des bogues et être moins stables. + Mise à jour :\nRelease: versions officielles publiées chaque mois qui peuvent être très anciennes, mais plus fiables et testées.\nNightly: versions de développement avec toutes les dernières fonctionnalités et correctifs, mais pouvant avoir des bogues et être moins stables. diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 05973faf0..43998c3a9 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Mutassa a kurzort a lehetőségeken, hogy itt leírást láthasson + Point your mouse at an option to display it's description. + Helyezze az egérmutatót egy lehetőség fölé, hogy megjelenítse annak leírását. @@ -1021,7 +1021,7 @@ updaterGroupBox - Frissítés:\nStabil: Hivatalos verziók, amelyeket havonta adnak ki, és amelyek nagyon elavultak lehetnek, de megbízhatóbbak és teszteltek.\nInstabil: Fejlesztési verziók, amelyek az összes legújabb funkciót és javítást tartalmazzák, de hibákat tartalmazhatnak és kevésbé stabilak. + Frissítés:\nRelease: Hivatalos verziók, amelyeket havonta adnak ki, és amelyek nagyon elavultak lehetnek, de megbízhatóbbak és teszteltek.\nNightly: Fejlesztési verziók, amelyek az összes legújabb funkciót és javítást tartalmazzák, de hibákat tartalmazhatnak és kevésbé stabilak. @@ -1061,7 +1061,7 @@ debugDump - Debug dumpolás engedélyezése:\nElmenti a futó PS4 program import- és exportszimbólumait, valamint a fájl fejlécinformációit egy könyvtárba + Debug dumpolás engedélyezése:\nElmenti a futó PS4 program import- és exportszimbólumait, valamint a fájl fejlécinformációit egy könyvtárba. diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index 49abf2371..a9412ebab 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Letakkan mouse Anda di atas opsi untuk menampilkan deskripsi di sini + Point your mouse at an option to display it's description. + Arahkan mouse Anda pada opsi untuk menampilkan deskripsinya. @@ -1021,7 +1021,7 @@ updaterGroupBox - Pembaruan:\nStabil: Versi resmi yang dirilis setiap bulan yang mungkin sangat ketinggalan zaman, tetapi lebih dapat diandalkan dan teruji.\nTidak Stabil: Versi pengembangan yang memiliki semua fitur dan perbaikan terbaru, tetapi mungkin mengandung bug dan kurang stabil. + Pembaruan:\nRelease: Versi resmi yang dirilis setiap bulan yang mungkin sangat ketinggalan zaman, tetapi lebih dapat diandalkan dan teruji.\nNightly: Versi pengembangan yang memiliki semua fitur dan perbaikan terbaru, tetapi mungkin mengandung bug dan kurang stabil. @@ -1061,7 +1061,7 @@ debugDump - Aktifkan Pembuangan Debug:\nMenyimpan simbol impor dan ekspor serta informasi header file dari program PS4 yang sedang berjalan ke direktori + Aktifkan Pembuangan Debug:\nMenyimpan simbol impor dan ekspor serta informasi header file dari program PS4 yang sedang berjalan ke direktori. diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index e83e15838..e66a9e034 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Posiziona il mouse su un'opzione per visualizzare una descrizione qui + Point your mouse at an option to display it's description. + Sposta il mouse su un'opzione per visualizzarne la descrizione. @@ -1021,7 +1021,7 @@ updaterGroupBox - Aggiornamento:\nStabile: Versioni ufficiali rilasciate ogni mese che potrebbero essere molto datate, ma sono più affidabili e testate.\nInstabile: Versioni di sviluppo che hanno tutte le ultime funzionalità e correzioni, ma potrebbero contenere bug e sono meno stabili. + Aggiornamento:\nRelease: Versioni ufficiali rilasciate ogni mese che potrebbero essere molto datate, ma sono più affidabili e testate.\nNightly: Versioni di sviluppo che hanno tutte le ultime funzionalità e correzioni, ma potrebbero contenere bug e sono meno stabili. @@ -1061,7 +1061,7 @@ debugDump - Abilita Pompaggio di Debug:\nSalva i simboli di importazione ed esportazione e le informazioni sull'intestazione del file del programma PS4 attualmente in esecuzione in una directory + Abilita Pompaggio di Debug:\nSalva i simboli di importazione ed esportazione e le informazioni sull'intestazione del file del programma PS4 attualmente in esecuzione in una directory. diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index 290b6be9e..979fe8a75 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - ここに説明を表示するには、オプションにマウスをポイントしてください + Point your mouse at an option to display it's description. + オプションにマウスをポイントすると、その説明が表示されます。 @@ -1021,7 +1021,7 @@ updaterGroupBox - 更新:\n安定版: 非常に古いかもしれないが、より信頼性が高くテスト済みの公式バージョンを毎月リリースします。\n不安定版: 最新の機能と修正がすべて含まれていますが、バグが含まれている可能性があり、安定性は低いです。 + 更新:\nRelease: 非常に古いかもしれないが、より信頼性が高くテスト済みの公式バージョンを毎月リリースします。\nNightly: 最新の機能と修正がすべて含まれていますが、バグが含まれている可能性があり、安定性は低いです。 diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index fba167632..19513929c 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Point your mouse at an options to display a description in here + Point your mouse at an option to display it's description. + Point your mouse at an option to display it's description. @@ -1021,7 +1021,7 @@ updaterGroupBox - Update:\nStable: Official versions released every month that may be very outdated, but are more reliable and tested.\nUnstable: Development versions that have all the latest features and fixes, but may contain bugs and are less stable. + Update:\nRelease: Official versions released every month that may be very outdated, but are more reliable and tested.\nNightly: Development versions that have all the latest features and fixes, but may contain bugs and are less stable. @@ -1061,7 +1061,7 @@ debugDump - Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory + Enable Debug Dumping:\nSaves the import and export symbols and file header information of the currently running PS4 program to a directory. diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 52fdbbc50..212a4c60a 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Rodykite pelę ant pasirinkimo, kad čia būtų rodoma aprašymas + Point your mouse at an option to display it's description. + Žymeklį nukreipkite ant pasirinkimo, kad pamatytumėte jo aprašymą. @@ -1021,7 +1021,7 @@ updaterGroupBox - Atnaujinti:\nStabilus: Oficialios versijos, išleidžiamos kiekvieną mėnesį, kurios gali būti labai pasenusios, tačiau yra patikimos ir išbandytos.\nNestabilus: Vystymo versijos, kuriose yra visos naujausios funkcijos ir taisymai, tačiau gali turėti klaidų ir būti mažiau stabilios. + Atnaujinti:\nRelease: Oficialios versijos, išleidžiamos kiekvieną mėnesį, kurios gali būti labai pasenusios, tačiau yra patikimos ir išbandytos.\nNightly: Vystymo versijos, kuriose yra visos naujausios funkcijos ir taisymai, tačiau gali turėti klaidų ir būti mažiau stabilios. diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 2dd1b431e..778b343c1 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Hold musen over et alternativ for å vise en beskrivelse her + Point your mouse at an option to display it's description. + Hold musen over et valg for at vise beskrivelsen. @@ -1021,7 +1021,7 @@ updaterGroupBox - Oppdatering:\nStabil: Offisielle versjoner utgitt hver måned som kan være veldig utdaterte, men er mer pålitelige og testet.\nUstabil: Utviklingsversjoner som har alle de nyeste funksjonene og feilrettingene, men som kan inneholde feil og er mindre stabile. + Oppdatering:\nRelease: Offisielle versjoner utgitt hver måned som kan være veldig utdaterte, men er mer pålitelige og testet.\nNightly: Utviklingsversjoner som har alle de nyeste funksjonene og feilrettingene, men som kan inneholde feil og er mindre stabile. diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index 9636037cc..86d868baa 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Beweeg je muis over een optie om hier een beschrijving weer te geven + Point your mouse at an option to display it's description. + Wijzig de muisaanwijzer naar een optie om de beschrijving weer te geven. @@ -1021,7 +1021,7 @@ updaterGroupBox - Updateren:\nStabiel: Officiële versies die elke maand worden uitgebracht, die zeer verouderd kunnen zijn, maar betrouwbaar en getest zijn.\nOnstabiel: Ontwikkelingsversies die alle nieuwste functies en bugfixes bevatten, maar mogelijk bugs bevatten en minder stabiel zijn. + Updateren:\nRelease: Officiële versies die elke maand worden uitgebracht, die zeer verouderd kunnen zijn, maar betrouwbaar en getest zijn.\nNightly: Ontwikkelingsversies die alle nieuwste functies en bugfixes bevatten, maar mogelijk bugs bevatten en minder stabiel zijn. diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index ae7e5cfae..5301bea04 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Najedź myszą na opcję, aby wyświetlić opis tutaj + Point your mouse at an option to display it's description. + Najedź kursorem na opcję, aby wyświetlić jej opis. @@ -1021,7 +1021,7 @@ updaterGroupBox - Aktualizator:\nStabilny: Oficjalne wersje wydawane co miesiąc, które mogą być bardzo przestarzałe, ale są niezawodne i przetestowane.\nNiestabilny: Wersje rozwojowe, które zawierają wszystkie najnowsze funkcje i poprawki błędów, ale mogą mieć błędy i być mniej stabilne. + Aktualizator:\nRelease: Oficjalne wersje wydawane co miesiąc, które mogą być bardzo przestarzałe, ale są niezawodne i przetestowane.\nNightly: Wersje rozwojowe, które zawierają wszystkie najnowsze funkcje i poprawki błędów, ale mogą mieć błędy i być mniej stabilne. diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index a1e5d77ca..6b78b80c9 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -975,13 +975,13 @@ - Point your mouse at an options to display a description in here - Passe o mouse sobre uma opção para exibir a descrição aqui + Point your mouse at an option to display it's description. + Passe o mouse sobre uma opção para exibir sua descrição. consoleLanguageGroupBox - Idioma do console:\nDefine o idioma usado pelo jogo PS4.\nRecomenda-se configurá-lo para um idioma que o jogo suporte, o que pode variar conforme a região. + Idioma do console:\nDefine o idioma usado pelo jogo no PS4.\nRecomenda-se configurá-lo para um idioma que o jogo suporte, o que pode variar conforme a região. @@ -1021,12 +1021,12 @@ updaterGroupBox - Atualizações:\nStable: versões oficiais que são lançadas todo mês e podem ser bastante antigas, mas são mais confiáveis e testadas.\nUnstable: versões de desenvolvimento que têm todos os novos recursos e correções, mas podem ter bugs e ser instáveis. + Atualizações:\nRelease: Versões oficiais que são lançadas todo mês e podem ser bastante antigas, mas são mais confiáveis e testadas.\nNightly: Versões de desenvolvimento que têm todos os novos recursos e correções, mas podem ter bugs e ser instáveis. GUIgroupBox - Reproduzir música de título:\nSe o jogo suportar, ativa a reprodução de música especial ao selecionar o jogo na interface. + Reproduzir música de abertura:\nSe o jogo suportar, ativa a reprodução de uma música especial ao selecionar o jogo na interface do menu. @@ -1066,12 +1066,12 @@ vkValidationCheckBox - Ativar Camadas de Validação do Vulkan:\nAtiva um sistema que valida o estado do renderizador Vulkan e registra informações sobre seu estado interno. Isso diminui o desempenho e pode alterar o comportamento da emulação. + Ativar Camadas de Validação do Vulkan:\nAtiva um sistema que valida o estado do renderizador Vulkan e registra informações sobre seu estado interno.\nIsso diminui o desempenho e pode alterar o comportamento da emulação. vkSyncValidationCheckBox - Ativar Validação de Sincronização do Vulkan:\nAtiva um sistema que valida o agendamento de tarefas de renderização Vulkan. Isso diminui o desempenho e pode alterar o comportamento da emulação. + Ativar Validação de Sincronização do Vulkan:\nAtiva um sistema que valida o agendamento de tarefas de renderização Vulkan.\nIsso diminui o desempenho e pode alterar o comportamento da emulação. diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index 3667f699d..a3c9a103c 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Pune mouse-ul pe o opțiune pentru a afișa o descriere aici + Point your mouse at an option to display it's description. + Indicați mouse-ul asupra unei opțiuni pentru a afișa descrierea acesteia. @@ -1021,7 +1021,7 @@ updaterGroupBox - Actualizare:\nStabil: Versiuni oficiale lansate în fiecare lună, care pot fi foarte învechite, dar sunt mai fiabile și testate.\nInstabil: Versiuni de dezvoltare care conțin toate cele mai recente funcții și corecții, dar pot conține erori și sunt mai puțin stabile. + Actualizare:\nRelease: Versiuni oficiale lansate în fiecare lună, care pot fi foarte învechite, dar sunt mai fiabile și testate.\nNightly: Versiuni de dezvoltare care conțin toate cele mai recente funcții și corecții, dar pot conține erori și sunt mai puțin stabile. diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index fbbe07f45..bfa6d4298 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Наведите курсор мыши на опцию, чтобы отобразить описание здесь + Point your mouse at an option to display it's description. + Наведите указатель мыши на опцию, чтобы отобразить ее описание. @@ -1021,7 +1021,7 @@ updaterGroupBox - Обновление:\nСтабильная версия: Официальные версии, которые выпускаются каждый месяц и могут быть очень старыми, но они более надежные и проверенные.\nНестабильная версия: Версии разработки, которые содержат все последние функции и исправления, но могут содержать ошибки и менее стабильны. + Обновление:\nRelease: Официальные версии, которые выпускаются каждый месяц и могут быть очень старыми, но они более надежные и проверенные.\nNightly: Версии разработки, которые содержат все последние функции и исправления, но могут содержать ошибки и менее стабильны. @@ -1061,7 +1061,7 @@ debugDump - Включить отладочные дампы:\nСохраняет символы импорта, экспорта и информацию о заголовке файла текущей исполняемой программы PS4 в папку + Включить отладочные дампы:\nСохраняет символы импорта, экспорта и информацию о заголовке файла текущей исполняемой программы PS4 в папку. diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index ea377808e..cc1a0ee27 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Vendosni miun në një opsion për të shfaqur një përshkrim këtu + Point your mouse at an option to display it's description. + Hidhni mouse-in mbi një opsion për të shfaqur përshkrimin e tij. @@ -1021,7 +1021,7 @@ updaterGroupBox - Aktualizimi:\nStabil: Versionet zyrtare të lëshuara çdo muaj që mund të jenë shumë të vjetra, por janë më të besueshme dhe të testuara.\nPanshkuar: Versionet e zhvillimit që kanë të gjitha veçoritë dhe rregullimet më të fundit, por mund të përmbajnë gabime dhe janë më pak të qëndrueshme. + Aktualizimi:\nRelease: Versionet zyrtare të lëshuara çdo muaj që mund të jenë shumë të vjetra, por janë më të besueshme dhe të testuara.\nNightly: Versionet e zhvillimit që kanë të gjitha veçoritë dhe rregullimet më të fundit, por mund të përmbajnë gabime dhe janë më pak të qëndrueshme. diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 87ebee69e..ec071b82f 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Buraya açıklama göstermek için bir seçeneğin üzerine fareyi getirin + Point your mouse at an option to display it's description. + Seçenek üzerinde farenizi tutarak açıklamasını görüntüleyin. @@ -1021,7 +1021,7 @@ updaterGroupBox - Güncelleme:\nStabil: Her ay yayınlanan resmi sürümler; çok eski olabilirler, ancak daha güvenilirdir ve test edilmiştir.\nKararsız: Tüm en son özellikler ve düzeltmeler ile birlikte geliştirme sürümleri; hatalar içerebilir ve daha az kararlıdırlar. + Güncelleme:\nRelease: Her ay yayınlanan resmi sürümler; çok eski olabilirler, ancak daha güvenilirdir ve test edilmiştir.\nNightly: Tüm en son özellikler ve düzeltmeler ile birlikte geliştirme sürümleri; hatalar içerebilir ve daha az kararlıdırlar. diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 485997019..0018966dc 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - Di chuột vào tùy chọn để hiển thị mô tả ở đây + Point your mouse at an option to display it's description. + Di chuyển chuột đến tùy chọn để hiển thị mô tả của nó. @@ -1021,7 +1021,7 @@ updaterGroupBox - Cập nhật:\nỔn định: Các phiên bản chính thức được phát hành hàng tháng; có thể khá cũ nhưng đáng tin cậy hơn và đã được thử nghiệm.\nKhông ổn định: Các phiên bản phát triển có tất cả các tính năng và sửa lỗi mới nhất; có thể có lỗi và ít ổn định hơn. + Cập nhật:\nRelease: Các phiên bản chính thức được phát hành hàng tháng; có thể khá cũ nhưng đáng tin cậy hơn và đã được thử nghiệm.\nNightly: Các phiên bản phát triển có tất cả các tính năng và sửa lỗi mới nhất; có thể có lỗi và ít ổn định hơn. diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index 2505e8acc..ea49a8575 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - 将鼠标指针放在选项上以在这里显示说明 + Point your mouse at an option to display it's description. + 将鼠标指针指向选项以显示其描述。 @@ -1021,7 +1021,7 @@ updaterGroupBox - 更新:\n稳定版本: 官方版本,可能非常旧,并且每月发布,但更可靠且经过测试。\n不稳定版本: 开发版本,包含所有最新功能和修复,但可能包含错误且不够稳定。 + 更新:\nRelease: 官方版本,可能非常旧,并且每月发布,但更可靠且经过测试。\nNightly: 开发版本,包含所有最新功能和修复,但可能包含错误且不够稳定。 diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 826f843f4..dd2e331ba 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -975,8 +975,8 @@ - Point your mouse at an options to display a description in here - 將鼠標懸停在選項上以在此顯示描述 + Point your mouse at an option to display it's description. + 將鼠標指向選項以顯示其描述。 @@ -1021,7 +1021,7 @@ updaterGroupBox - 更新:\n穩定版: 每月發布的官方版本,可能非常舊,但更可靠且經過測試。\n不穩定: 開發版本,擁有所有最新的功能和修復,但可能包含錯誤,穩定性較差。 + 更新:\nRelease: 每月發布的官方版本,可能非常舊,但更可靠且經過測試。\nNightly: 開發版本,擁有所有最新的功能和修復,但可能包含錯誤,穩定性較差。 From 40d00e3066e559766970dc23d5f06c0f79c82198 Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Sun, 29 Sep 2024 02:24:21 -0300 Subject: [PATCH 07/34] progressBar DownloadUpdate (#1141) --- src/qt_gui/check_update.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/qt_gui/check_update.cpp b/src/qt_gui/check_update.cpp index f5e284a26..b92974ba9 100644 --- a/src/qt_gui/check_update.cpp +++ b/src/qt_gui/check_update.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "check_update.h" using namespace Common::FS; @@ -313,15 +314,32 @@ void CheckUpdate::requestChangelog(const QString& currentRev, const QString& lat } void CheckUpdate::DownloadUpdate(const QString& url) { + QProgressBar* progressBar = new QProgressBar(this); + progressBar->setRange(0, 100); + progressBar->setTextVisible(true); + progressBar->setValue(0); + + layout()->addWidget(progressBar); + QNetworkRequest request(url); QNetworkReply* reply = networkManager->get(request); - connect(reply, &QNetworkReply::finished, this, [this, reply, url]() { + connect(reply, &QNetworkReply::downloadProgress, this, + [progressBar](qint64 bytesReceived, qint64 bytesTotal) { + if (bytesTotal > 0) { + int percentage = static_cast((bytesReceived * 100) / bytesTotal); + progressBar->setValue(percentage); + } + }); + + connect(reply, &QNetworkReply::finished, this, [this, reply, progressBar, url]() { + progressBar->setValue(100); if (reply->error() != QNetworkReply::NoError) { QMessageBox::warning(this, tr("Error"), tr("Network error occurred while trying to access the URL") + ":\n" + url + "\n" + reply->errorString()); reply->deleteLater(); + progressBar->deleteLater(); return; } @@ -348,6 +366,7 @@ void CheckUpdate::DownloadUpdate(const QString& url) { } reply->deleteLater(); + progressBar->deleteLater(); }); } From 5e98a3e1d84bea44c422d3daedbcd51f713e5d34 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sat, 28 Sep 2024 22:25:44 -0700 Subject: [PATCH 08/34] vulkan: Fix crash when resizing window. (#1142) --- src/video_core/renderer_vulkan/vk_swapchain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 13c0adb0b..8c268c9be 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -123,7 +123,7 @@ void Swapchain::Present() { }; auto result = instance.GetPresentQueue().presentKHR(present_info); - if (result == vk::Result::eErrorOutOfDateKHR) { + if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR) { needs_recreation = true; } else { ASSERT_MSG(result == vk::Result::eSuccess, "Swapchain presentation failed: {}", From 80bf46da4c2f4b1f780729c258cb2cd867332c5d Mon Sep 17 00:00:00 2001 From: "Daniel R." <47796739+polybiusproxy@users.noreply.github.com> Date: Sun, 29 Sep 2024 09:28:41 +0200 Subject: [PATCH 09/34] core/memory: Pooled memory implementation (#1085) --- src/common/alignment.h | 12 ++ src/core/libraries/kernel/file_system.cpp | 3 +- src/core/libraries/kernel/libkernel.cpp | 22 ++- .../libraries/kernel/memory_management.cpp | 98 +++++++++++++ src/core/libraries/kernel/memory_management.h | 7 + .../libraries/kernel/thread_management.cpp | 10 +- src/core/libraries/save_data/save_backup.cpp | 2 +- src/core/libraries/save_data/save_memory.cpp | 2 +- src/core/libraries/videoout/driver.cpp | 2 +- src/core/memory.cpp | 129 ++++++++++++++++++ src/core/memory.h | 23 +++- src/video_core/amdgpu/liverpool.cpp | 2 +- 12 files changed, 301 insertions(+), 11 deletions(-) diff --git a/src/common/alignment.h b/src/common/alignment.h index 367efb6bb..8480fae26 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -28,4 +28,16 @@ template return (value & 0x3FFF) == 0; } +template + requires std::is_integral_v +[[nodiscard]] constexpr bool Is64KBAligned(T value) { + return (value & 0xFFFF) == 0; +} + +template + requires std::is_integral_v +[[nodiscard]] constexpr bool Is2MBAligned(T value) { + return (value & 0x1FFFFF) == 0; +} + } // namespace Common diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 45ebb4be8..91fc7846a 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -290,7 +290,8 @@ int PS4_SYSV_ABI sceKernelMkdir(const char* path, u16 mode) { } // CUSA02456: path = /aotl after sceSaveDataMount(mode = 1) - if (dir_name.empty() || !std::filesystem::create_directory(dir_name)) { + std::error_code ec; + if (dir_name.empty() || !std::filesystem::create_directory(dir_name, ec)) { return SCE_KERNEL_ERROR_EIO; } diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index 65d3dde14..72f8f1d1d 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -56,7 +56,7 @@ void KernelSignalRequest() { } static void KernelServiceThread(std::stop_token stoken) { - Common::SetCurrentThreadName("Kernel_ServiceThread"); + Common::SetCurrentThreadName("shadPS4:Kernel_ServiceThread"); while (!stoken.stop_requested()) { HLE_TRACE; @@ -186,6 +186,16 @@ void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, return ptr; } +s32 PS4_SYSV_ABI sceKernelConfiguredFlexibleMemorySize(u64* sizeOut) { + if (sizeOut == nullptr) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + + auto* memory = Core::Memory::Instance(); + *sizeOut = memory->GetTotalFlexibleSize(); + return ORBIS_OK; +} + static uint64_t g_mspace_atomic_id_mask = 0; static uint64_t g_mstate_table[64] = {0}; @@ -403,10 +413,12 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { // obj LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); + // misc LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord); LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, posix_connect); LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask); + // memory LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException); LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory); @@ -443,6 +455,14 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("2SKEx6bSq-4", "libkernel", 1, "libkernel", 1, 1, sceKernelBatchMap); LIB_FUNCTION("kBJzF8x4SyE", "libkernel", 1, "libkernel", 1, 1, sceKernelBatchMap2); LIB_FUNCTION("DGMG3JshrZU", "libkernel", 1, "libkernel", 1, 1, sceKernelSetVirtualRangeName); + LIB_FUNCTION("n1-v6FgU7MQ", "libkernel", 1, "libkernel", 1, 1, + sceKernelConfiguredFlexibleMemorySize); + + // Memory pool + LIB_FUNCTION("qCSfqDILlns", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolExpand); + LIB_FUNCTION("pU-QydtGcGY", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolReserve); + LIB_FUNCTION("Vzl66WmfLvk", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolCommit); + LIB_FUNCTION("LXo1tpFqJGs", "libkernel", 1, "libkernel", 1, 1, sceKernelMemoryPoolDecommit); // equeue LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue); diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index 7853a77a4..5331f47f2 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -347,4 +347,102 @@ s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, cons memory->NameVirtualRange(std::bit_cast(addr), len, name); return ORBIS_OK; } + +s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_t len, + size_t alignment, u64* physAddrOut) { + if (searchStart < 0 || searchEnd <= searchStart) { + LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!"); + return SCE_KERNEL_ERROR_EINVAL; + } + const bool is_in_range = searchEnd - searchStart >= len; + if (len <= 0 || !Common::Is64KBAligned(len) || !is_in_range) { + LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!"); + return SCE_KERNEL_ERROR_EINVAL; + } + if (alignment != 0 && !Common::Is64KBAligned(alignment)) { + LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!"); + return SCE_KERNEL_ERROR_EINVAL; + } + if (physAddrOut == nullptr) { + LOG_ERROR(Kernel_Vmm, "Result physical address pointer is null!"); + return SCE_KERNEL_ERROR_EINVAL; + } + + auto* memory = Core::Memory::Instance(); + PAddr phys_addr = memory->PoolExpand(searchStart, searchEnd, len, alignment); + *physAddrOut = static_cast(phys_addr); + + LOG_INFO(Kernel_Vmm, + "searchStart = {:#x}, searchEnd = {:#x}, len = {:#x}, alignment = {:#x}, physAddrOut " + "= {:#x}", + searchStart, searchEnd, len, alignment, phys_addr); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t alignment, int flags, + void** addrOut) { + LOG_INFO(Kernel_Vmm, "addrIn = {}, len = {:#x}, alignment = {:#x}, flags = {:#x}", + fmt::ptr(addrIn), len, alignment, flags); + + if (addrIn == nullptr) { + LOG_ERROR(Kernel_Vmm, "Address is invalid!"); + return SCE_KERNEL_ERROR_EINVAL; + } + if (len == 0 || !Common::Is2MBAligned(len)) { + LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 2MB aligned!"); + return SCE_KERNEL_ERROR_EINVAL; + } + if (alignment != 0) { + if ((!std::has_single_bit(alignment) && !Common::Is2MBAligned(alignment))) { + LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!"); + return SCE_KERNEL_ERROR_EINVAL; + } + } + + auto* memory = Core::Memory::Instance(); + const VAddr in_addr = reinterpret_cast(addrIn); + const auto map_flags = static_cast(flags); + memory->PoolReserve(addrOut, in_addr, len, map_flags, alignment); + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags) { + if (addr == nullptr) { + LOG_ERROR(Kernel_Vmm, "Address is invalid!"); + return SCE_KERNEL_ERROR_EINVAL; + } + if (len == 0 || !Common::Is64KBAligned(len)) { + LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 64KB aligned!"); + return SCE_KERNEL_ERROR_EINVAL; + } + + LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, type = {:#x}, prot = {:#x}, flags = {:#x}", + fmt::ptr(addr), len, type, prot, flags); + + const VAddr in_addr = reinterpret_cast(addr); + const auto mem_prot = static_cast(prot); + auto* memory = Core::Memory::Instance(); + return memory->PoolCommit(in_addr, len, mem_prot); +} + +s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags) { + if (addr == nullptr) { + LOG_ERROR(Kernel_Vmm, "Address is invalid!"); + return SCE_KERNEL_ERROR_EINVAL; + } + if (len == 0 || !Common::Is64KBAligned(len)) { + LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 64KB aligned!"); + return SCE_KERNEL_ERROR_EINVAL; + } + + LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, flags = {:#x}", fmt::ptr(addr), len, flags); + + const VAddr pool_addr = reinterpret_cast(addr); + auto* memory = Core::Memory::Instance(); + memory->PoolDecommit(pool_addr, len); + + return ORBIS_OK; +} + } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/memory_management.h b/src/core/libraries/kernel/memory_management.h index 205b2274f..38898aa57 100644 --- a/src/core/libraries/kernel/memory_management.h +++ b/src/core/libraries/kernel/memory_management.h @@ -114,4 +114,11 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, const char* name); +s32 PS4_SYSV_ABI sceKernelMemoryPoolExpand(u64 searchStart, u64 searchEnd, size_t len, + size_t alignment, u64* physAddrOut); +s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t alignment, int flags, + void** addrOut); +s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags); +s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags); + } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 455ac24b1..90e03293b 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -414,6 +414,7 @@ ScePthreadMutex* createMutex(ScePthreadMutex* addr) { if (addr == nullptr || *addr != nullptr) { return addr; } + const VAddr vaddr = reinterpret_cast(addr); std::string name = fmt::format("mutex{:#x}", vaddr); scePthreadMutexInit(addr, nullptr, name.c_str()); @@ -515,9 +516,12 @@ int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type) ptype = PTHREAD_MUTEX_RECURSIVE; break; case ORBIS_PTHREAD_MUTEX_NORMAL: - case ORBIS_PTHREAD_MUTEX_ADAPTIVE: ptype = PTHREAD_MUTEX_NORMAL; break; + case ORBIS_PTHREAD_MUTEX_ADAPTIVE: + LOG_ERROR(Kernel_Pthread, "Unimplemented adaptive mutex"); + ptype = PTHREAD_MUTEX_ERRORCHECK; + break; default: return SCE_KERNEL_ERROR_EINVAL; } @@ -1620,6 +1624,10 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("upoVrzMHFeE", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexTrylock); LIB_FUNCTION("IafI2PxcPnQ", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexTimedlock); + // scePthreadMutexInitForInternalLibc, scePthreadMutexattrInitForInternalLibc + LIB_FUNCTION("qH1gXoq71RY", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexInit); + LIB_FUNCTION("n2MMpvU8igI", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexattrInit); + // cond calls LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, scePthreadCondInit); LIB_FUNCTION("m5-2bsNfv7s", "libkernel", 1, "libkernel", 1, 1, scePthreadCondattrInit); diff --git a/src/core/libraries/save_data/save_backup.cpp b/src/core/libraries/save_data/save_backup.cpp index 1d935aee1..da5172b15 100644 --- a/src/core/libraries/save_data/save_backup.cpp +++ b/src/core/libraries/save_data/save_backup.cpp @@ -79,7 +79,7 @@ static void backup(const std::filesystem::path& dir_name) { } static void BackupThreadBody() { - Common::SetCurrentThreadName("SaveData_BackupThread"); + Common::SetCurrentThreadName("shadPS4:SaveData_BackupThread"); while (g_backup_status != WorkerStatus::Stopping) { g_backup_status = WorkerStatus::Waiting; diff --git a/src/core/libraries/save_data/save_memory.cpp b/src/core/libraries/save_data/save_memory.cpp index 0a714a26f..c4d105612 100644 --- a/src/core/libraries/save_data/save_memory.cpp +++ b/src/core/libraries/save_data/save_memory.cpp @@ -66,7 +66,7 @@ static void SaveFileSafe(void* buf, size_t count, const std::filesystem::path& p } [[noreturn]] void SaveThreadLoop() { - Common::SetCurrentThreadName("SaveData_SaveDataMemoryThread"); + Common::SetCurrentThreadName("shadPS4:SaveData_SaveDataMemoryThread"); std::mutex mtx; while (true) { { diff --git a/src/core/libraries/videoout/driver.cpp b/src/core/libraries/videoout/driver.cpp index fa7577907..940a8c7d3 100644 --- a/src/core/libraries/videoout/driver.cpp +++ b/src/core/libraries/videoout/driver.cpp @@ -260,7 +260,7 @@ void VideoOutDriver::PresentThread(std::stop_token token) { static constexpr std::chrono::nanoseconds VblankPeriod{16666667}; const auto vblank_period = VblankPeriod / Config::vblankDiv(); - Common::SetCurrentThreadName("PresentThread"); + Common::SetCurrentThreadName("shadPS4:PresentThread"); Common::SetCurrentThreadRealtime(vblank_period); Common::AccurateTimer timer{vblank_period}; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index ebda00357..d21ebae83 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -51,6 +51,35 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size) { total_flexible_size, total_direct_size); } +PAddr MemoryManager::PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment) { + std::scoped_lock lk{mutex}; + + auto dmem_area = FindDmemArea(search_start); + + const auto is_suitable = [&] { + const auto aligned_base = alignment > 0 ? Common::AlignUp(dmem_area->second.base, alignment) + : dmem_area->second.base; + const auto alignment_size = aligned_base - dmem_area->second.base; + const auto remaining_size = + dmem_area->second.size >= alignment_size ? dmem_area->second.size - alignment_size : 0; + return dmem_area->second.is_free && remaining_size >= size; + }; + while (!is_suitable() && dmem_area->second.GetEnd() <= search_end) { + dmem_area++; + } + ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size); + + // Align free position + PAddr free_addr = dmem_area->second.base; + free_addr = alignment > 0 ? Common::AlignUp(free_addr, alignment) : free_addr; + + // Add the allocated region to the list and commit its pages. + auto& area = CarveDmemArea(free_addr, size)->second; + area.is_free = false; + area.is_pooled = true; + return free_addr; +} + PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment, int memory_type) { std::scoped_lock lk{mutex}; @@ -112,6 +141,43 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) { MergeAdjacent(dmem_map, dmem_area); } +int MemoryManager::PoolReserve(void** out_addr, VAddr virtual_addr, size_t size, + MemoryMapFlags flags, u64 alignment) { + std::scoped_lock lk{mutex}; + + virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr; + alignment = alignment > 0 ? alignment : 2_MB; + VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr; + + // Fixed mapping means the virtual address must exactly match the provided one. + if (True(flags & MemoryMapFlags::Fixed)) { + const auto& vma = FindVMA(mapped_addr)->second; + // If the VMA is mapped, unmap the region first. + if (vma.IsMapped()) { + UnmapMemoryImpl(mapped_addr, size); + } + const size_t remaining_size = vma.base + vma.size - mapped_addr; + ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size); + } + + // Find the first free area starting with provided virtual address. + if (False(flags & MemoryMapFlags::Fixed)) { + mapped_addr = SearchFree(mapped_addr, size, alignment); + } + + // Add virtual memory area + const auto new_vma_handle = CarveVMA(mapped_addr, size); + auto& new_vma = new_vma_handle->second; + new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); + new_vma.prot = MemoryProt::NoAccess; + new_vma.name = ""; + new_vma.type = VMAType::PoolReserved; + MergeAdjacent(vma_map, new_vma_handle); + + *out_addr = std::bit_cast(mapped_addr); + return ORBIS_OK; +} + int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags, u64 alignment) { std::scoped_lock lk{mutex}; @@ -149,6 +215,36 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem return ORBIS_OK; } +int MemoryManager::PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot) { + std::scoped_lock lk{mutex}; + + const u64 alignment = 64_KB; + + // When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed + // flag so we will take the branch that searches for free (or reserved) mappings. + virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr; + VAddr mapped_addr = Common::AlignUp(virtual_addr, alignment); + + // This should return SCE_KERNEL_ERROR_ENOMEM but shouldn't normally happen. + const auto& vma = FindVMA(mapped_addr)->second; + const size_t remaining_size = vma.base + vma.size - mapped_addr; + ASSERT_MSG(!vma.IsMapped() && remaining_size >= size); + + // Perform the mapping. + void* out_addr = impl.Map(mapped_addr, size, alignment, -1, false); + TRACK_ALLOC(out_addr, size, "VMEM"); + + auto& new_vma = CarveVMA(mapped_addr, size)->second; + new_vma.disallow_merge = false; + new_vma.prot = prot; + new_vma.name = ""; + new_vma.type = Core::VMAType::Pooled; + new_vma.is_exec = false; + new_vma.phys_base = 0; + + return ORBIS_OK; +} + int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, MemoryMapFlags flags, VMAType type, std::string_view name, bool is_exec, PAddr phys_addr, u64 alignment) { @@ -232,6 +328,39 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem return ORBIS_OK; } +void MemoryManager::PoolDecommit(VAddr virtual_addr, size_t size) { + std::scoped_lock lk{mutex}; + + const auto it = FindVMA(virtual_addr); + const auto& vma_base = it->second; + ASSERT_MSG(vma_base.Contains(virtual_addr, size), + "Existing mapping does not contain requested unmap range"); + + const auto vma_base_addr = vma_base.base; + const auto vma_base_size = vma_base.size; + const auto phys_base = vma_base.phys_base; + const bool is_exec = vma_base.is_exec; + const auto start_in_vma = virtual_addr - vma_base_addr; + const auto type = vma_base.type; + + rasterizer->UnmapMemory(virtual_addr, size); + + // Mark region as free and attempt to coalesce it with neighbours. + const auto new_it = CarveVMA(virtual_addr, size); + auto& vma = new_it->second; + vma.type = VMAType::PoolReserved; + vma.prot = MemoryProt::NoAccess; + vma.phys_base = 0; + vma.disallow_merge = false; + vma.name = ""; + MergeAdjacent(vma_map, new_it); + + // Unmap the memory region. + impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base, is_exec, + false, false); + TRACK_FREE(virtual_addr, "VMEM"); +} + void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) { std::scoped_lock lk{mutex}; UnmapMemoryImpl(virtual_addr, size); diff --git a/src/core/memory.h b/src/core/memory.h index 73ffab503..752209cfc 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -50,15 +50,17 @@ enum class VMAType : u32 { Direct = 2, Flexible = 3, Pooled = 4, - Stack = 5, - Code = 6, - File = 7, + PoolReserved = 5, + Stack = 6, + Code = 7, + File = 8, }; struct DirectMemoryArea { PAddr base = 0; size_t size = 0; int memory_type = 0; + bool is_pooled = false; bool is_free = true; PAddr GetEnd() const { @@ -96,7 +98,7 @@ struct VirtualMemoryArea { } bool IsMapped() const noexcept { - return type != VMAType::Free && type != VMAType::Reserved; + return type != VMAType::Free && type != VMAType::Reserved && type != VMAType::PoolReserved; } bool CanMergeWith(const VirtualMemoryArea& next) const { @@ -135,6 +137,10 @@ public: return total_direct_size; } + u64 GetTotalFlexibleSize() const { + return total_flexible_size; + } + u64 GetAvailableFlexibleSize() const { return total_flexible_size - flexible_usage; } @@ -145,14 +151,21 @@ public: void SetupMemoryRegions(u64 flexible_size); + PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment); + PAddr Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment, int memory_type); void Free(PAddr phys_addr, size_t size); + int PoolReserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags, + u64 alignment = 0); + int Reserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags, u64 alignment = 0); + int PoolCommit(VAddr virtual_addr, size_t size, MemoryProt prot); + int MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, MemoryMapFlags flags, VMAType type, std::string_view name = "", bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0); @@ -160,6 +173,8 @@ public: int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, MemoryMapFlags flags, uintptr_t fd, size_t offset); + void PoolDecommit(VAddr virtual_addr, size_t size); + void UnmapMemory(VAddr virtual_addr, size_t size); int QueryProtection(VAddr addr, void** start, void** end, u32* prot); diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index 74e623e3d..3dce871fe 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -44,7 +44,7 @@ Liverpool::~Liverpool() { } void Liverpool::Process(std::stop_token stoken) { - Common::SetCurrentThreadName("GPU_CommandProcessor"); + Common::SetCurrentThreadName("shadPS4:GPU_CommandProcessor"); while (!stoken.stop_requested()) { { From d9f287eaa21f8fc13cf753593781fa9d1182530c Mon Sep 17 00:00:00 2001 From: Paris Oplopoios Date: Sun, 29 Sep 2024 15:02:46 +0300 Subject: [PATCH 10/34] Fix fmt error (#1150) --- src/core/cpu_patches.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/cpu_patches.cpp b/src/core/cpu_patches.cpp index 3404496ce..b812e5444 100644 --- a/src/core/cpu_patches.cpp +++ b/src/core/cpu_patches.cpp @@ -1057,7 +1057,7 @@ static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) { // Undefined behavior if length + index is bigger than 64 according to the spec, // we'll warn and continue execution. LOG_WARNING(Core, - "extrq at {:x} with length {} and index {} is bigger than 64, " + "extrq at {} with length {} and index {} is bigger than 64, " "undefined behavior", fmt::ptr(code_address), length, index); } @@ -1117,7 +1117,7 @@ static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) { // Undefined behavior if length + index is bigger than 64 according to the spec, // we'll warn and continue execution. LOG_WARNING(Core, - "insertq at {:x} with length {} and index {} is bigger than 64, " + "insertq at {} with length {} and index {} is bigger than 64, " "undefined behavior", fmt::ptr(code_address), length, index); } From 398019867ba57e9cefb6ff0a67c34fca26291701 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sun, 29 Sep 2024 20:47:55 -0700 Subject: [PATCH 11/34] sdl: Fix use of functions that now return SDL_bool (#1160) --- src/audio_core/sdl_audio.cpp | 6 +++--- src/input/controller.cpp | 2 +- src/sdl_window.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/audio_core/sdl_audio.cpp b/src/audio_core/sdl_audio.cpp index f544c52f9..9aec70c24 100644 --- a/src/audio_core/sdl_audio.cpp +++ b/src/audio_core/sdl_audio.cpp @@ -101,14 +101,14 @@ s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) { return 0; } // TODO mixing channels - int result = SDL_PutAudioStreamData(port.stream, ptr, - port.samples_num * port.sample_size * port.channels_num); + SDL_bool result = SDL_PutAudioStreamData( + port.stream, ptr, port.samples_num * port.sample_size * port.channels_num); // TODO find a correct value 8192 is estimated while (SDL_GetAudioStreamAvailable(port.stream) > 65536) { SDL_Delay(0); } - return result; + return result ? ORBIS_OK : -1; } bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) { diff --git a/src/input/controller.cpp b/src/input/controller.cpp index 4de6d83b8..dcd8ed946 100644 --- a/src/input/controller.cpp +++ b/src/input/controller.cpp @@ -127,7 +127,7 @@ void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) { bool GameController::SetVibration(u8 smallMotor, u8 largeMotor) { if (m_sdl_gamepad != nullptr) { return SDL_RumbleGamepad(m_sdl_gamepad, (smallMotor / 255.0f) * 0xFFFF, - (largeMotor / 255.0f) * 0xFFFF, -1) == 0; + (largeMotor / 255.0f) * 0xFFFF, -1); } return true; } diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index f7835aabe..bd2cc39d2 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -23,7 +23,7 @@ namespace Frontend { WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_, std::string_view window_title) : width{width_}, height{height_}, controller{controller_} { - if (SDL_Init(SDL_INIT_VIDEO) < 0) { + if (!SDL_Init(SDL_INIT_VIDEO)) { UNREACHABLE_MSG("Failed to initialize SDL video subsystem: {}", SDL_GetError()); } SDL_InitSubSystem(SDL_INIT_AUDIO); From c7ff0419ad58bf85fc085069a49f3af0aee5155b Mon Sep 17 00:00:00 2001 From: dbz400 Date: Mon, 30 Sep 2024 16:36:26 +0800 Subject: [PATCH 12/34] Fix V_CMP_CLASS_F32 (#1153) --- src/shader_recompiler/frontend/translate/vector_alu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index cf92460d3..82769bd29 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -909,6 +909,8 @@ void Translator::V_CMP_CLASS_F32(const GcnInst& inst) { switch (inst.dst[1].field) { case OperandField::VccLo: return ir.SetVcc(value); + case OperandField::ScalarGPR: + return ir.SetThreadBitScalarReg(IR::ScalarReg(inst.dst[1].code), value); default: UNREACHABLE(); } From cbbf3505e70a1aad5bd8c2b3766cb55291269877 Mon Sep 17 00:00:00 2001 From: Paris Oplopoios Date: Mon, 30 Sep 2024 12:42:59 +0300 Subject: [PATCH 13/34] Fix path bugs & wrap seeks in an if (#1154) * Fix path bugs * Wrap most seeks in an if --- src/common/io_file.cpp | 12 +++++++ src/core/file_format/pkg.cpp | 39 ++++++++++++++++++----- src/core/file_format/pkg.h | 2 +- src/core/file_format/trp.cpp | 26 ++++++++++++--- src/core/libraries/kernel/file_system.cpp | 15 +++++++-- src/core/loader/elf.cpp | 15 +++++++-- src/qt_gui/gui_context_menus.h | 5 +-- src/qt_gui/main_window.cpp | 17 ++++------ src/qt_gui/main_window.h | 5 +-- src/qt_gui/pkg_viewer.cpp | 11 ++++--- src/qt_gui/trophy_viewer.cpp | 5 +-- 11 files changed, 105 insertions(+), 47 deletions(-) diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp index c1d9cc592..33dce5638 100644 --- a/src/common/io_file.cpp +++ b/src/common/io_file.cpp @@ -372,6 +372,18 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const { return false; } + u64 size = GetSize(); + if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) { + LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); + return false; + } else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) { + LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); + return false; + } else if (origin == SeekOrigin::End && offset > 0) { + LOG_ERROR(Common_Filesystem, "Seeking past the end of the file"); + return false; + } + errno = 0; const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0; diff --git a/src/core/file_format/pkg.cpp b/src/core/file_format/pkg.cpp index f329e81a6..8d038b062 100644 --- a/src/core/file_format/pkg.cpp +++ b/src/core/file_format/pkg.cpp @@ -44,7 +44,7 @@ PKG::PKG() = default; PKG::~PKG() = default; -bool PKG::Open(const std::filesystem::path& filepath) { +bool PKG::Open(const std::filesystem::path& filepath, std::string& failreason) { Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read); if (!file.IsOpen()) { return false; @@ -70,7 +70,11 @@ bool PKG::Open(const std::filesystem::path& filepath) { u32 offset = pkgheader.pkg_table_entry_offset; u32 n_files = pkgheader.pkg_table_entry_count; - file.Seek(offset); + if (!file.Seek(offset)) { + failreason = "Failed to seek to PKG table entry offset"; + return false; + } + for (int i = 0; i < n_files; i++) { PKGEntry entry{}; file.Read(entry.id); @@ -85,7 +89,10 @@ bool PKG::Open(const std::filesystem::path& filepath) { const auto name = GetEntryNameByType(entry.id); if (name == "param.sfo") { sfo.clear(); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to param.sfo offset"; + return false; + } sfo.resize(entry.size); file.ReadRaw(sfo.data(), entry.size); } @@ -127,7 +134,11 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: std::array, 7> key1; std::array imgkeydata; - file.Seek(offset); + if (!file.Seek(offset)) { + failreason = "Failed to seek to PKG table entry offset"; + return false; + } + for (int i = 0; i < n_files; i++) { PKGEntry entry{}; file.Read(entry.id); @@ -149,7 +160,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: // Just print with id Common::FS::IOFile out(extract_path / "sce_sys" / std::to_string(entry.id), Common::FS::FileAccessMode::Write); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to PKG entry offset"; + return false; + } std::vector data; data.resize(entry.size); @@ -195,7 +209,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: } Common::FS::IOFile out(extract_path / "sce_sys" / name, Common::FS::FileAccessMode::Write); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to PKG entry offset"; + return false; + } std::vector data; data.resize(entry.size); @@ -207,7 +224,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: if (entry.id == 0x400 || entry.id == 0x401 || entry.id == 0x402 || entry.id == 0x403) { // somehow 0x401 is not decrypting decNp.resize(entry.size); - file.Seek(entry.offset); + if (!file.Seek(entry.offset)) { + failreason = "Failed to seek to PKG entry offset"; + return false; + } std::vector data; data.resize(entry.size); @@ -237,7 +257,10 @@ bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem:: // Read the seed std::array seed; - file.Seek(pkgheader.pfs_image_offset + 0x370); + if (!file.Seek(pkgheader.pfs_image_offset + 0x370)) { + failreason = "Failed to seek to PFS image offset"; + return false; + } file.Read(seed); // Get data and tweak keys. diff --git a/src/core/file_format/pkg.h b/src/core/file_format/pkg.h index d30d50b44..a488a2df8 100644 --- a/src/core/file_format/pkg.h +++ b/src/core/file_format/pkg.h @@ -103,7 +103,7 @@ public: PKG(); ~PKG(); - bool Open(const std::filesystem::path& filepath); + bool Open(const std::filesystem::path& filepath, std::string& failreason); void ExtractFiles(const int index); bool Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract, std::string& failreason); diff --git a/src/core/file_format/trp.cpp b/src/core/file_format/trp.cpp index 724f90782..a1b47dfc8 100644 --- a/src/core/file_format/trp.cpp +++ b/src/core/file_format/trp.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/logging/log.h" #include "common/path_util.h" #include "trp.h" @@ -13,7 +14,10 @@ void TRP::GetNPcommID(const std::filesystem::path& trophyPath, int index) { if (!npbindFile.IsOpen()) { return; } - npbindFile.Seek(0x84 + (index * 0x180)); + if (!npbindFile.Seek(0x84 + (index * 0x180))) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to NPbind offset"); + return; + } npbindFile.ReadRaw(np_comm_id.data(), 12); std::fill(np_comm_id.begin() + 12, np_comm_id.end(), 0); // fill with 0, we need 16 bytes. } @@ -56,26 +60,38 @@ bool TRP::Extract(const std::filesystem::path& trophyPath) { std::filesystem::create_directory(trpFilesPath / "Xml"); for (int i = 0; i < header.entry_num; i++) { - file.Seek(seekPos); + if (!file.Seek(seekPos)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); + return false; + } seekPos += (s64)header.entry_size; TrpEntry entry; file.Read(entry); std::string_view name(entry.entry_name); if (entry.flag == 0 && name.find("TROP") != std::string::npos) { // PNG - file.Seek(entry.entry_pos); + if (file.Seek(entry.entry_pos)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); + return false; + } std::vector icon(entry.entry_len); file.Read(icon); Common::FS::IOFile::WriteBytes(trpFilesPath / "Icons" / name, icon); } if (entry.flag == 3 && np_comm_id[0] == 'N' && np_comm_id[1] == 'P') { // ESFM, encrypted. - file.Seek(entry.entry_pos); + if (file.Seek(entry.entry_pos)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); + return false; + } file.Read(esfmIv); // get iv key. // Skip the first 16 bytes which are the iv key on every entry as we want a // clean xml file. std::vector ESFM(entry.entry_len - iv_len); std::vector XML(entry.entry_len - iv_len); - file.Seek(entry.entry_pos + iv_len); + if (file.Seek(entry.entry_pos + iv_len)) { + LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry + iv offset"); + return false; + } file.Read(ESFM); crypto.decryptEFSM(np_comm_id, esfmIv, ESFM, XML); // decrypt removePadding(XML); diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 91fc7846a..7f88fc456 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -229,7 +229,10 @@ s64 PS4_SYSV_ABI sceKernelLseek(int d, s64 offset, int whence) { } std::scoped_lock lk{file->m_mutex}; - file->f.Seek(offset, origin); + if (!file->f.Seek(offset, origin)) { + LOG_CRITICAL(Kernel_Fs, "sceKernelLseek: failed to seek"); + return SCE_KERNEL_ERROR_EINVAL; + } return file->f.Tell(); } @@ -380,7 +383,10 @@ s64 PS4_SYSV_ABI sceKernelPread(int d, void* buf, size_t nbytes, s64 offset) { SCOPE_EXIT { file->f.Seek(pos); }; - file->f.Seek(offset); + if (!file->f.Seek(offset)) { + LOG_CRITICAL(Kernel_Fs, "sceKernelPread: failed to seek"); + return ORBIS_KERNEL_ERROR_EINVAL; + } return file->f.ReadRaw(buf, nbytes); } @@ -514,7 +520,10 @@ s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) { SCOPE_EXIT { file->f.Seek(pos); }; - file->f.Seek(offset); + if (!file->f.Seek(offset)) { + LOG_CRITICAL(Kernel_Fs, "sceKernelPwrite: failed to seek"); + return ORBIS_KERNEL_ERROR_EINVAL; + } return file->f.WriteRaw(buf, nbytes); } diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 6d7c8773a..4de20436f 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -204,7 +204,10 @@ void Elf::Open(const std::filesystem::path& file_name) { } out.resize(num); - m_f.Seek(offset, SeekOrigin::SetOrigin); + if (!m_f.Seek(offset, SeekOrigin::SetOrigin)) { + LOG_CRITICAL(Loader, "Failed to seek to header tables"); + return; + } m_f.Read(out); }; @@ -465,7 +468,10 @@ std::string Elf::ElfPHeaderStr(u16 no) { void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) { if (!is_self) { // It's elf file - m_f.Seek(file_offset, SeekOrigin::SetOrigin); + if (!m_f.Seek(file_offset, SeekOrigin::SetOrigin)) { + LOG_CRITICAL(Loader, "Failed to seek to ELF header"); + return; + } m_f.ReadRaw(reinterpret_cast(virtual_addr), size); return; } @@ -479,7 +485,10 @@ void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) { if (file_offset >= phdr.p_offset && file_offset < phdr.p_offset + phdr.p_filesz) { auto offset = file_offset - phdr.p_offset; - m_f.Seek(offset + seg.file_offset, SeekOrigin::SetOrigin); + if (!m_f.Seek(offset + seg.file_offset, SeekOrigin::SetOrigin)) { + LOG_CRITICAL(Loader, "Failed to seek to segment"); + return; + } m_f.ReadRaw(reinterpret_cast(virtual_addr), size); return; } diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 3218884d5..4eb657572 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -312,10 +312,7 @@ public: if (selected == &installPackage) { QStringList pkg_app_ = m_pkg_app_list[itemIndex].split(";;"); - std::filesystem::path path(pkg_app_[9].toStdString()); -#ifdef _WIN32 - path = std::filesystem::path(pkg_app_[9].toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(pkg_app_[9]); InstallDragDropPkg(path, 1, 1); } } diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 2981da3a7..837cdece3 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -625,10 +625,7 @@ void MainWindow::InstallPkg() { int pkgNum = 0; for (const QString& file : fileNames) { ++pkgNum; - std::filesystem::path path(file.toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(file.toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(file); MainWindow::InstallDragDropPkg(path, pkgNum, nPkg); } } @@ -646,10 +643,7 @@ void MainWindow::BootGame() { QMessageBox::critical(nullptr, tr("Game Boot"), QString(tr("Only one file can be selected!"))); } else { - std::filesystem::path path(fileNames[0].toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(fileNames[0].toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(fileNames[0]); Core::Emulator emulator; if (!std::filesystem::exists(path)) { QMessageBox::critical(nullptr, tr("Run Game"), @@ -663,9 +657,12 @@ void MainWindow::BootGame() { void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int nPkg) { if (Loader::DetectFileType(file) == Loader::FileTypes::Pkg) { - pkg = PKG(); - pkg.Open(file); std::string failreason; + pkg = PKG(); + if (!pkg.Open(file, failreason)) { + QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason)); + return; + } auto extract_path = Config::getGameInstallDir() / pkg.GetTitleID(); QString pkgType = QString::fromStdString(pkg.GetPkgFlags()); QString gameDirPath; diff --git a/src/qt_gui/main_window.h b/src/qt_gui/main_window.h index c1d5cc26e..a428f4317 100644 --- a/src/qt_gui/main_window.h +++ b/src/qt_gui/main_window.h @@ -110,10 +110,7 @@ protected: int nPkg = urlList.size(); for (const QUrl& url : urlList) { pkgNum++; - std::filesystem::path path(url.toLocalFile().toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(url.toLocalFile().toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(url.toLocalFile()); InstallDragDropPkg(path, pkgNum, nPkg); } } diff --git a/src/qt_gui/pkg_viewer.cpp b/src/qt_gui/pkg_viewer.cpp index 8f20f6929..0ffb9b579 100644 --- a/src/qt_gui/pkg_viewer.cpp +++ b/src/qt_gui/pkg_viewer.cpp @@ -104,11 +104,12 @@ void PKGViewer::ProcessPKGInfo() { m_pkg_patch_list.clear(); m_full_pkg_list.clear(); for (int i = 0; i < m_pkg_list.size(); i++) { - std::filesystem::path path(m_pkg_list[i].toStdString()); -#ifdef _WIN32 - path = std::filesystem::path(m_pkg_list[i].toStdWString()); -#endif - package.Open(path); + std::filesystem::path path = Common::FS::PathFromQString(m_pkg_list[i]); + std::string failreason; + if (!package.Open(path, failreason)) { + QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason)); + return; + } psf.Open(package.sfo); QString title_name = QString::fromStdString(std::string{psf.GetString("TITLE").value_or("Unknown")}); diff --git a/src/qt_gui/trophy_viewer.cpp b/src/qt_gui/trophy_viewer.cpp index 528beee0d..e4394c7e6 100644 --- a/src/qt_gui/trophy_viewer.cpp +++ b/src/qt_gui/trophy_viewer.cpp @@ -28,10 +28,7 @@ void TrophyViewer::PopulateTrophyWidget(QString title) { QDir dir(trophyDirQt); if (!dir.exists()) { - std::filesystem::path path(gameTrpPath_.toStdString()); -#ifdef _WIN64 - path = std::filesystem::path(gameTrpPath_.toStdWString()); -#endif + std::filesystem::path path = Common::FS::PathFromQString(gameTrpPath_); if (!trp.Extract(path)) return; } From 62c59d195f674f894e195dcb78bec10a481edb0d Mon Sep 17 00:00:00 2001 From: tGecko Date: Mon, 30 Sep 2024 11:49:20 +0200 Subject: [PATCH 14/34] add gstreamer to appimage build (#1166) --- .github/linux-appimage-qt.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/linux-appimage-qt.sh b/.github/linux-appimage-qt.sh index 203d214e3..e33a4b21f 100755 --- a/.github/linux-appimage-qt.sh +++ b/.github/linux-appimage-qt.sh @@ -14,11 +14,12 @@ export PATH="$Qt6_DIR/bin:$PATH" wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh +wget -q https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gstreamer/master/linuxdeploy-plugin-gstreamer.sh chmod a+x linuxdeploy-x86_64.AppImage chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh - +chmod a+x linuxdeploy-plugin-gstreamer.sh # Build AppImage ./linuxdeploy-x86_64.AppImage --appdir AppDir @@ -26,5 +27,5 @@ chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh cp -a "$GITHUB_WORKSPACE/build/translations" AppDir/usr/bin -./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt --output appimage +./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt --plugin gstreamer --output appimage mv Shadps4-x86_64.AppImage Shadps4-qt.AppImage From fc6c755e5a79b671f7a3214a79dfcaba5593616b Mon Sep 17 00:00:00 2001 From: hspir404 Date: Mon, 30 Sep 2024 11:24:28 +0000 Subject: [PATCH 15/34] Fix some typos (#1161) --- src/qt_gui/settings_dialog.cpp | 2 +- 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 | 6 +++--- src/qt_gui/translations/es_ES.ts | 2 +- src/qt_gui/translations/fa_IR.ts | 4 ++-- 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 | 6 +++--- 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 +- 27 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index 478f7b986..954762049 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -70,7 +70,7 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge InitializeEmulatorLanguages(); LoadValuesFromConfig(); - defaultTextEdit = tr("Point your mouse at an option to display it's description."); + defaultTextEdit = tr("Point your mouse at an option to display its description."); ui->descriptionText->setText(defaultTextEdit); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close); diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index d8e8e3e04..f7e43877e 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. وجّه الماوس نحو خيار لعرض وصفه. diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index f08fb07b4..5e130212d 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Peg musen over et valg for at vise dets beskrivelse. diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index 4f02b87ec..9c6906a11 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Bewege die Maus über eine Option, um deren Beschreibung anzuzeigen. diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index e6bafcac4..20e0d1b00 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Τοποθετήστε το ποντίκι σας πάνω σε μια επιλογή για να εμφανίσετε την περιγραφή της. diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 5915fc0ad..1dd11f69e 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -975,8 +975,8 @@ - Point your mouse at an option to display it's description. - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. + Point your mouse at an option to display its description. @@ -1066,7 +1066,7 @@ vkValidationCheckBox - Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about it's internal state.\nThis will reduce performance and likely change the behavior of emulation. + Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about its internal state.\nThis will reduce performance and likely change the behavior of emulation. diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index ac0206b26..9af0e45e0 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Coloque el mouse sobre una opción para mostrar su descripción. diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index a944ddd5c..15e07c886 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. ماوس خود را بر روی یک گزینه قرار دهید تا توضیحات آن نمایش داده شود. @@ -1066,7 +1066,7 @@ vkValidationCheckBox - Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about it's internal state. This will reduce performance and likely change the behavior of emulation. + Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about its internal state. This will reduce performance and likely change the behavior of emulation. diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index 47fdcd8e5..8c1f4c090 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Siirrä hiiri vaihtoehdon päälle näyttämään sen kuvaus. diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index 34d28ce52..f99ea2f5d 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Pointez votre souris sur une option pour afficher sa description. diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 43998c3a9..7759f3fb6 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Helyezze az egérmutatót egy lehetőség fölé, hogy megjelenítse annak leírását. diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index a9412ebab..0842df897 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Arahkan mouse Anda pada opsi untuk menampilkan deskripsinya. diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index e66a9e034..c42589d44 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Sposta il mouse su un'opzione per visualizzarne la descrizione. diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index 979fe8a75..166100db6 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. オプションにマウスをポイントすると、その説明が表示されます。 diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index 19513929c..303e9fd52 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -975,8 +975,8 @@ - Point your mouse at an option to display it's description. - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. + Point your mouse at an option to display its description. @@ -1066,7 +1066,7 @@ vkValidationCheckBox - Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about it's internal state. This will reduce performance and likely change the behavior of emulation. + Enable Vulkan Validation Layers:\nEnables a system that validates the state of the Vulkan renderer and logs information about its internal state. This will reduce performance and likely change the behavior of emulation. diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index 212a4c60a..bb5d185d6 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Žymeklį nukreipkite ant pasirinkimo, kad pamatytumėte jo aprašymą. diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 778b343c1..b5dd59f60 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Hold musen over et valg for at vise beskrivelsen. diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index 86d868baa..144eeeb5f 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Wijzig de muisaanwijzer naar een optie om de beschrijving weer te geven. diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index 5301bea04..880418715 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Najedź kursorem na opcję, aby wyświetlić jej opis. diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index 6b78b80c9..7ee5b92f6 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Passe o mouse sobre uma opção para exibir sua descrição. diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index a3c9a103c..783cb7822 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Indicați mouse-ul asupra unei opțiuni pentru a afișa descrierea acesteia. diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index bfa6d4298..f6a24dd2f 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Наведите указатель мыши на опцию, чтобы отобразить ее описание. diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index cc1a0ee27..d9f1d3859 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Hidhni mouse-in mbi një opsion për të shfaqur përshkrimin e tij. diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index ec071b82f..bb1c7c423 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Seçenek üzerinde farenizi tutarak açıklamasını görüntüleyin. diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 0018966dc..8dfd03e2d 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. Di chuyển chuột đến tùy chọn để hiển thị mô tả của nó. diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index ea49a8575..1c55cd26e 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. 将鼠标指针指向选项以显示其描述。 diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index dd2e331ba..dfb622a54 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -975,7 +975,7 @@ - Point your mouse at an option to display it's description. + Point your mouse at an option to display its description. 將鼠標指向選項以顯示其描述。 From 603f709784b4354f05d4219a9685283ba73db882 Mon Sep 17 00:00:00 2001 From: ElBread3 <92335081+ElBread3@users.noreply.github.com> Date: Mon, 30 Sep 2024 06:25:25 -0500 Subject: [PATCH 16/34] Added sceKernelRmdir (#1137) * add sceKernelRmdir * since result is remove count, probably don't use that * fixes + posix_rmdir * fix return value problem --- src/common/io_file.cpp | 5 ++- src/core/libraries/kernel/file_system.cpp | 54 +++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp index 33dce5638..1b28d2bba 100644 --- a/src/common/io_file.cpp +++ b/src/common/io_file.cpp @@ -192,8 +192,9 @@ int IOFile::Open(const fs::path& path, FileAccessMode mode, FileType type, FileS #endif if (!IsOpen()) { - LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}", - PathToUTF8String(file_path)); + const auto ec = std::error_code{result, std::generic_category()}; + LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}, error_message={}", + PathToUTF8String(file_path), ec.message()); } return result; diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 7f88fc456..91791fe87 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -314,6 +314,58 @@ int PS4_SYSV_ABI posix_mkdir(const char* path, u16 mode) { return result; } +int PS4_SYSV_ABI sceKernelRmdir(const char* path) { + auto* mnt = Common::Singleton::Instance(); + bool ro = false; + + const std::filesystem::path dir_name = mnt->GetHostPath(path, &ro); + + if (dir_name.empty()) { + LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, permission denied", + fmt::UTF(dir_name.u8string())); + return SCE_KERNEL_ERROR_EACCES; + } + + if (ro) { + LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, directory is read only", + fmt::UTF(dir_name.u8string())); + return SCE_KERNEL_ERROR_EROFS; + } + + if (!std::filesystem::is_directory(dir_name)) { + LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, path is not a directory", + fmt::UTF(dir_name.u8string())); + return ORBIS_KERNEL_ERROR_ENOTDIR; + } + + if (!std::filesystem::exists(dir_name)) { + LOG_INFO(Kernel_Fs, "Failed to remove directory: {}, no such file or directory", + fmt::UTF(dir_name.u8string())); + return ORBIS_KERNEL_ERROR_ENOENT; + } + + std::error_code ec; + int result = std::filesystem::remove_all(dir_name, ec); + + if (!ec) { + LOG_DEBUG(Kernel_Fs, "Removed directory: {}", fmt::UTF(dir_name.u8string())); + return ORBIS_OK; + } + LOG_ERROR(Kernel_Fs, "Failed to remove directory: {}, error_code={}", + fmt::UTF(dir_name.u8string()), ec.message()); + return ErrnoToSceKernelError(ec.value()); +} + +int PS4_SYSV_ABI posix_rmdir(const char* path) { + int result = sceKernelRmdir(path); + if (result < 0) { + LOG_ERROR(Kernel_Pthread, "posix_rmdir: error = {}", result); + ErrSceToPosix(result); + return -1; + } + return result; +} + int PS4_SYSV_ABI sceKernelStat(const char* path, OrbisKernelStat* sb) { LOG_INFO(Kernel_Fs, "(PARTIAL) path = {}", path); auto* mnt = Common::Singleton::Instance(); @@ -574,6 +626,8 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("AqBioC2vF3I", "libScePosix", 1, "libkernel", 1, 1, posix_read); LIB_FUNCTION("1-LFLmRFxxM", "libkernel", 1, "libkernel", 1, 1, sceKernelMkdir); LIB_FUNCTION("JGMio+21L4c", "libScePosix", 1, "libkernel", 1, 1, posix_mkdir); + LIB_FUNCTION("naInUjYt3so", "libkernel", 1, "libkernel", 1, 1, sceKernelRmdir); + LIB_FUNCTION("c7ZnT7V1B98", "libScePosix", 1, "libkernel", 1, 1, posix_rmdir); LIB_FUNCTION("eV9wAD2riIA", "libkernel", 1, "libkernel", 1, 1, sceKernelStat); LIB_FUNCTION("kBwCPsYX-m4", "libkernel", 1, "libkernel", 1, 1, sceKernelFStat); LIB_FUNCTION("mqQMh1zPPT8", "libScePosix", 1, "libkernel", 1, 1, posix_fstat); From afe32d1e0316e57ff2e7b40bcdd8d83f89116ecb Mon Sep 17 00:00:00 2001 From: Lander Gallastegi Date: Mon, 30 Sep 2024 13:25:49 +0200 Subject: [PATCH 17/34] documentation: fix Linux build instructions (#1107) * Fix linux build instructions * Validation layers and arch linux packages --- documents/building-linux.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/documents/building-linux.md b/documents/building-linux.md index 622de543b..6c2794347 100644 --- a/documents/building-linux.md +++ b/documents/building-linux.md @@ -3,28 +3,28 @@ SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project SPDX-License-Identifier: GPL-2.0-or-later --> -## Build shadPS4 for Linux +## Build shadPS4 for Linux ### Install the necessary tools to build shadPS4: #### Debian & Ubuntu ``` -sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev libjack-dev libsndio-dev qt6-base-dev qt6-tools-dev +sudo apt install build-essential clang git cmake libasound2-dev libpulse-dev libopenal-dev libssl-dev zlib1g-dev libedit-dev libudev-dev libevdev-dev libsdl2-dev libjack-dev libsndio-dev qt6-base-dev qt6-tools-dev qt6-multimedia-dev libvulkan-dev vulkan-validationlayers ``` #### Fedora ``` -sudo dnf install alsa-lib-devel cmake libatomic libevdev-devel libudev-devel openal-devel qt6-qtbase-devel qt6-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt6-qtmultimedia-devel qt6-qtsvg-devel +sudo dnf install clang cmake libatomic alsa-lib-devel pipewire-jack-audio-connection-kit-devel openal-devel openssl-devel libevdev-devel libudev-devel qt6-qtbase-devel qt6-qtbase-private-devel qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel vulkan-devel vulkan-validation-layers ``` #### Arch Linux ``` -sudo pacman -S openal cmake vulkan-validation-layers qt6-base qt6-declarative qt6-multimedia sdl2 sndio jack2 base-devel +sudo pacman -S base-devel clang git cmake sndio jack2 openal qt6-base qt6-declarative qt6-multimedia sdl2 vulkan-validation-layers ``` #### OpenSUSE ``` -sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt6-qtbase-devel libqt6-qtmultimedia-devel libqt6-qtsvg-devel libQt6Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel +sudo zypper install clang git cmake libasound2 libpulse-devel libsndio7 libjack-devel openal-soft-devel libopenssl-devel zlib-devel libedit-devel systemd-devel libevdev-devel qt6-base-devel qt6-multimedia-devel qt6-svg-devel qt6-linguist-devel qt6-gui-private-devel vulkan-devel vulkan-validationlayers ``` ### Cloning and compiling: @@ -34,9 +34,11 @@ git clone --recursive https://github.com/shadps4-emu/shadPS4.git cd shadPS4 ``` -Generate the build directory in the shadPS4 directory. To enable the QT GUI, pass the ```-DENABLE_QT_GUI=ON``` flag: +Generate the build directory in the shadPS4 directory. To disable the QT GUI, remove the ```-DENABLE_QT_GUI=ON``` flag: + +**Note**: Clang is the compiler used for official builds and CI. If you build with GCC, you might encounter issues—please report any you find. If you choose to use GCC, we recommend building with Clang at least once before submitting a pull request. ``` -cmake -S . -B build/ -DENABLE_QT_GUI=ON +cmake -S . -B build/ -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ``` Enter the directory: From cda2317ddb4c3b97ab91d22e68283572263e3dbc Mon Sep 17 00:00:00 2001 From: Paris Oplopoios Date: Mon, 30 Sep 2024 19:05:55 +0300 Subject: [PATCH 18/34] Fix loading (#1169) --- src/core/file_format/trp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/file_format/trp.cpp b/src/core/file_format/trp.cpp index a1b47dfc8..9c53c8588 100644 --- a/src/core/file_format/trp.cpp +++ b/src/core/file_format/trp.cpp @@ -69,7 +69,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath) { file.Read(entry); std::string_view name(entry.entry_name); if (entry.flag == 0 && name.find("TROP") != std::string::npos) { // PNG - if (file.Seek(entry.entry_pos)) { + if (!file.Seek(entry.entry_pos)) { LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); return false; } @@ -79,7 +79,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath) { } if (entry.flag == 3 && np_comm_id[0] == 'N' && np_comm_id[1] == 'P') { // ESFM, encrypted. - if (file.Seek(entry.entry_pos)) { + if (!file.Seek(entry.entry_pos)) { LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset"); return false; } @@ -88,7 +88,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath) { // clean xml file. std::vector ESFM(entry.entry_len - iv_len); std::vector XML(entry.entry_len - iv_len); - if (file.Seek(entry.entry_pos + iv_len)) { + if (!file.Seek(entry.entry_pos + iv_len)) { LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry + iv offset"); return false; } From 348da93ee6b1c4784deeba38392efe4717bfd3b1 Mon Sep 17 00:00:00 2001 From: bigol83 <38129260+bigol83@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:20:57 +0200 Subject: [PATCH 19/34] Fix BB random fmv hang (#1170) --- src/audio_core/sdl_audio.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/audio_core/sdl_audio.cpp b/src/audio_core/sdl_audio.cpp index 9aec70c24..bd27e4823 100644 --- a/src/audio_core/sdl_audio.cpp +++ b/src/audio_core/sdl_audio.cpp @@ -100,6 +100,7 @@ s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) { if (ptr == nullptr) { return 0; } + lock.unlock(); // TODO mixing channels SDL_bool result = SDL_PutAudioStreamData( port.stream, ptr, port.samples_num * port.sample_size * port.channels_num); From dda5cc411fd3758f450a2309ea89194e35434e29 Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 1 Oct 2024 01:53:20 -0300 Subject: [PATCH 20/34] fix wolf2022 cheats download (#1173) --- src/qt_gui/cheats_patches.cpp | 163 +++++++++++++++++++++------------- 1 file changed, 99 insertions(+), 64 deletions(-) diff --git a/src/qt_gui/cheats_patches.cpp b/src/qt_gui/cheats_patches.cpp index 655478d2b..c044c2c3c 100644 --- a/src/qt_gui/cheats_patches.cpp +++ b/src/qt_gui/cheats_patches.cpp @@ -456,10 +456,9 @@ void CheatsPatches::downloadCheats(const QString& source, const QString& gameSer if (source == "GoldHEN") { url = "https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/main/json.txt"; } else if (source == "wolf2022") { - url = "https://wolf2022.ir/trainer/" + gameSerial + "_" + gameVersion + ".json"; + url = "https://wolf2022.ir/trainer/list.json"; } else if (source == "shadPS4") { - url = "https://raw.githubusercontent.com/shadps4-emu/ps4_cheats/main/" - "CHEATS_JSON.txt"; + url = "https://raw.githubusercontent.com/shadps4-emu/ps4_cheats/main/CHEATS_JSON.txt"; } else { QMessageBox::warning(this, tr("Invalid Source"), QString(tr("The selected source is invalid.") + "\n%1").arg(source)); @@ -474,44 +473,32 @@ void CheatsPatches::downloadCheats(const QString& source, const QString& gameSer QByteArray jsonData = reply->readAll(); bool foundFiles = false; - if (source == "GoldHEN" || source == "shadPS4") { - QString textContent(jsonData); - QRegularExpression regex( - QString("%1_%2[^=]*\\.json").arg(gameSerial).arg(gameVersion)); - QRegularExpressionMatchIterator matches = regex.globalMatch(textContent); - QString baseUrl; + if (source == "wolf2022") { + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); + QJsonArray gamesArray = jsonDoc.object().value("games").toArray(); - if (source == "GoldHEN") { - baseUrl = "https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/" - "main/json/"; - } else { - baseUrl = "https://raw.githubusercontent.com/shadps4-emu/ps4_cheats/" - "main/CHEATS/"; - } + foreach (const QJsonValue& value, gamesArray) { + QJsonObject gameObject = value.toObject(); + QString title = gameObject.value("title").toString(); + QString version = gameObject.value("version").toString(); - while (matches.hasNext()) { - QRegularExpressionMatch match = matches.next(); - QString fileName = match.captured(0); + if (title == gameSerial && + (version == gameVersion || version == gameVersion.mid(1))) { + QString fileUrl = + "https://wolf2022.ir/trainer/" + gameObject.value("url").toString(); - if (!fileName.isEmpty()) { - QString newFileName = fileName; - int dotIndex = newFileName.lastIndexOf('.'); - if (dotIndex != -1) { + QString localFileName = gameObject.value("url").toString(); + localFileName = + localFileName.left(localFileName.lastIndexOf('.')) + "_wolf2022.json"; - if (source == "GoldHEN") { - newFileName.insert(dotIndex, "_GoldHEN"); - } else { - newFileName.insert(dotIndex, "_shadPS4"); - } - } - QString fileUrl = baseUrl + fileName; - QString localFilePath = dir.filePath(newFileName); + QString localFilePath = dir.filePath(localFileName); if (QFile::exists(localFilePath) && showMessageBox) { QMessageBox::StandardButton reply; reply = QMessageBox::question( this, tr("File Exists"), - tr("File already exists. Do you want to replace it?"), + tr("File already exists. Do you want to replace it?") + "\n" + + localFileName, QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::No) { continue; @@ -549,38 +536,81 @@ void CheatsPatches::downloadCheats(const QString& source, const QString& gameSer if (!foundFiles && showMessageBox) { QMessageBox::warning(this, tr("Cheats Not Found"), tr("CheatsNotFound_MSG")); } - } else if (source == "wolf2022") { - QString fileName = QFileInfo(QUrl(url).path()).fileName(); - QString baseFileName = fileName; - int dotIndex = baseFileName.lastIndexOf('.'); - if (dotIndex != -1) { - baseFileName.insert(dotIndex, "_wolf2022"); + } else if (source == "GoldHEN" || source == "shadPS4") { + QString textContent(jsonData); + QRegularExpression regex( + QString("%1_%2[^=]*\\.json").arg(gameSerial).arg(gameVersion)); + QRegularExpressionMatchIterator matches = regex.globalMatch(textContent); + QString baseUrl; + + if (source == "GoldHEN") { + baseUrl = "https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/" + "main/json/"; + } else { + baseUrl = "https://raw.githubusercontent.com/shadps4-emu/ps4_cheats/" + "main/CHEATS/"; } - QString filePath; - Common::FS::PathToQString(filePath, - Common::FS::GetUserPath(Common::FS::PathType::CheatsDir)); - filePath += "/" + baseFileName; - if (QFile::exists(filePath) && showMessageBox) { - QMessageBox::StandardButton reply2; - reply2 = - QMessageBox::question(this, tr("File Exists"), - tr("File already exists. Do you want to replace it?"), - QMessageBox::Yes | QMessageBox::No); - if (reply2 == QMessageBox::No) { - reply->deleteLater(); - return; + + while (matches.hasNext()) { + QRegularExpressionMatch match = matches.next(); + QString fileName = match.captured(0); + + if (!fileName.isEmpty()) { + QString newFileName = fileName; + int dotIndex = newFileName.lastIndexOf('.'); + if (dotIndex != -1) { + + if (source == "GoldHEN") { + newFileName.insert(dotIndex, "_GoldHEN"); + } else { + newFileName.insert(dotIndex, "_shadPS4"); + } + } + QString fileUrl = baseUrl + fileName; + QString localFilePath = dir.filePath(newFileName); + + if (QFile::exists(localFilePath) && showMessageBox) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question( + this, tr("File Exists"), + tr("File already exists. Do you want to replace it?") + "\n" + + newFileName, + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::No) { + continue; + } + } + QNetworkRequest fileRequest(fileUrl); + QNetworkReply* fileReply = manager->get(fileRequest); + + connect(fileReply, &QNetworkReply::finished, [=, this]() { + if (fileReply->error() == QNetworkReply::NoError) { + QByteArray fileData = fileReply->readAll(); + QFile localFile(localFilePath); + if (localFile.open(QIODevice::WriteOnly)) { + localFile.write(fileData); + localFile.close(); + } else { + QMessageBox::warning( + this, tr("Error"), + QString(tr("Failed to save file:") + "\n%1") + .arg(localFilePath)); + } + } else { + QMessageBox::warning(this, tr("Error"), + QString(tr("Failed to download file:") + + "%1\n\n" + tr("Error:") + "%2") + .arg(fileUrl) + .arg(fileReply->errorString())); + } + fileReply->deleteLater(); + }); + + foundFiles = true; } } - QFile cheatFile(filePath); - if (cheatFile.open(QIODevice::WriteOnly)) { - cheatFile.write(jsonData); - cheatFile.close(); - foundFiles = true; - populateFileListCheats(); - } else { - QMessageBox::warning( - this, tr("Error"), - QString(tr("Failed to save file:") + "\n%1").arg(filePath)); + if (!foundFiles && showMessageBox) { + QMessageBox::warning(this, tr("Cheats Not Found"), tr("CheatsNotFound_MSG")); } } if (foundFiles && showMessageBox) { @@ -910,11 +940,16 @@ void CheatsPatches::addCheatsToLayout(const QJsonArray& modsArray, const QJsonAr void CheatsPatches::populateFileListCheats() { QString cheatsDir; Common::FS::PathToQString(cheatsDir, Common::FS::GetUserPath(Common::FS::PathType::CheatsDir)); - QString pattern = m_gameSerial + "_" + m_gameVersion + "*.json"; + + QString fullGameVersion = m_gameVersion; + QString modifiedGameVersion = m_gameVersion.mid(1); + + QString patternWithFirstChar = m_gameSerial + "_" + fullGameVersion + "*.json"; + QString patternWithoutFirstChar = m_gameSerial + "_" + modifiedGameVersion + "*.json"; QDir dir(cheatsDir); QStringList filters; - filters << pattern; + filters << patternWithFirstChar << patternWithoutFirstChar; dir.setNameFilters(filters); QFileInfoList fileList = dir.entryInfoList(QDir::Files); @@ -1248,4 +1283,4 @@ void CheatsPatches::onPatchCheckBoxHovered(QCheckBox* checkBox, bool hovered) { } else { instructionsTextEdit->setText(defaultTextEdit); } -} +} \ No newline at end of file From 0be0f18764fcf3810238c50a3bcfa7153d921369 Mon Sep 17 00:00:00 2001 From: Lander Gallastegi Date: Tue, 1 Oct 2024 06:53:36 +0200 Subject: [PATCH 21/34] Fix fedora packages (#1174) --- documents/building-linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documents/building-linux.md b/documents/building-linux.md index 6c2794347..989669f4f 100644 --- a/documents/building-linux.md +++ b/documents/building-linux.md @@ -14,7 +14,7 @@ sudo apt install build-essential clang git cmake libasound2-dev libpulse-dev lib #### Fedora ``` -sudo dnf install clang cmake libatomic alsa-lib-devel pipewire-jack-audio-connection-kit-devel openal-devel openssl-devel libevdev-devel libudev-devel qt6-qtbase-devel qt6-qtbase-private-devel qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel vulkan-devel vulkan-validation-layers +sudo dnf install clang git cmake libatomic alsa-lib-devel pipewire-jack-audio-connection-kit-devel openal-devel openssl-devel libevdev-devel libudev-devel libXext-devel qt6-qtbase-devel qt6-qtbase-private-devel qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel vulkan-devel vulkan-validation-layers ``` #### Arch Linux From 7084fc4c41355395e199133c47155dd9b586c0f2 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:54:15 -0700 Subject: [PATCH 22/34] config: Add option to change DLC install path. (#1176) --- src/common/config.cpp | 15 +++++++ src/common/config.h | 2 + src/common/path_util.cpp | 1 - src/common/path_util.h | 1 - .../libraries/app_content/app_content.cpp | 6 +-- src/qt_gui/game_install_dialog.cpp | 45 ++++++++++++++++++- src/qt_gui/game_install_dialog.h | 5 ++- src/qt_gui/main_window.cpp | 4 +- 8 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 0d9ff093d..f04678eb7 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -8,6 +8,7 @@ #include // for wstring support #include #include "common/logging/formatter.h" +#include "common/path_util.h" #include "config.h" namespace toml { @@ -59,6 +60,7 @@ static bool vkCrashDiagnostic = false; // Gui std::filesystem::path settings_install_dir = {}; +std::filesystem::path settings_addon_install_dir = {}; u32 main_window_geometry_x = 400; u32 main_window_geometry_y = 400; u32 main_window_geometry_w = 1280; @@ -299,6 +301,9 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) { void setGameInstallDir(const std::filesystem::path& dir) { settings_install_dir = dir; } +void setAddonInstallDir(const std::filesystem::path& dir) { + settings_addon_install_dir = dir; +} void setMainWindowTheme(u32 theme) { mw_themes = theme; } @@ -355,6 +360,13 @@ u32 getMainWindowGeometryH() { std::filesystem::path getGameInstallDir() { return settings_install_dir; } +std::filesystem::path getAddonInstallDir() { + if (settings_addon_install_dir.empty()) { + // Default for users without a config file or a config file from before this option existed + return Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "addcont"; + } + return settings_addon_install_dir; +} u32 getMainWindowTheme() { return mw_themes; } @@ -482,6 +494,7 @@ void load(const std::filesystem::path& path) { m_window_size_W = toml::find_or(gui, "mw_width", 0); m_window_size_H = toml::find_or(gui, "mw_height", 0); settings_install_dir = toml::find_fs_path_or(gui, "installDir", {}); + settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {}); main_window_geometry_x = toml::find_or(gui, "geometry_x", 0); main_window_geometry_y = toml::find_or(gui, "geometry_y", 0); main_window_geometry_w = toml::find_or(gui, "geometry_w", 0); @@ -556,6 +569,8 @@ void save(const std::filesystem::path& path) { data["GUI"]["mw_width"] = m_window_size_W; data["GUI"]["mw_height"] = m_window_size_H; data["GUI"]["installDir"] = std::string{fmt::UTF(settings_install_dir.u8string()).data}; + data["GUI"]["addonInstallDir"] = + std::string{fmt::UTF(settings_addon_install_dir.u8string()).data}; data["GUI"]["geometry_x"] = main_window_geometry_x; data["GUI"]["geometry_y"] = main_window_geometry_y; data["GUI"]["geometry_w"] = main_window_geometry_w; diff --git a/src/common/config.h b/src/common/config.h index eeeff0b2e..402b8660e 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -76,6 +76,7 @@ bool vkCrashDiagnosticEnabled(); // Gui void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h); void setGameInstallDir(const std::filesystem::path& dir); +void setAddonInstallDir(const std::filesystem::path& dir); void setMainWindowTheme(u32 theme); void setIconSize(u32 size); void setIconSizeGrid(u32 size); @@ -94,6 +95,7 @@ u32 getMainWindowGeometryY(); u32 getMainWindowGeometryW(); u32 getMainWindowGeometryH(); std::filesystem::path getGameInstallDir(); +std::filesystem::path getAddonInstallDir(); u32 getMainWindowTheme(); u32 getIconSize(); u32 getIconSizeGrid(); diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index d7274fc74..f602f3513 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -119,7 +119,6 @@ static auto UserPaths = [] { create_path(PathType::CapturesDir, user_dir / CAPTURES_DIR); create_path(PathType::CheatsDir, user_dir / CHEATS_DIR); create_path(PathType::PatchesDir, user_dir / PATCHES_DIR); - create_path(PathType::AddonsDir, user_dir / ADDONS_DIR); create_path(PathType::MetaDataDir, user_dir / METADATA_DIR); return paths; diff --git a/src/common/path_util.h b/src/common/path_util.h index d40f4aab4..af0e91832 100644 --- a/src/common/path_util.h +++ b/src/common/path_util.h @@ -26,7 +26,6 @@ enum class PathType { CapturesDir, // Where rdoc captures are stored. CheatsDir, // Where cheats are stored. PatchesDir, // Where patches are stored. - AddonsDir, // Where additional content is stored. MetaDataDir, // Where game metadata (e.g. trophies and menu backgrounds) is stored. }; diff --git a/src/core/libraries/app_content/app_content.cpp b/src/core/libraries/app_content/app_content.cpp index 754343eef..f912639eb 100644 --- a/src/core/libraries/app_content/app_content.cpp +++ b/src/core/libraries/app_content/app_content.cpp @@ -5,6 +5,7 @@ #include "app_content.h" #include "common/assert.h" +#include "common/config.h" #include "common/io_file.h" #include "common/logging/log.h" #include "common/path_util.h" @@ -59,8 +60,7 @@ int PS4_SYSV_ABI sceAppContentAddcontMount(u32 service_label, OrbisAppContentMountPoint* mount_point) { LOG_INFO(Lib_AppContent, "called"); - const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir) / title_id / - entitlement_label->data; + const auto& mount_dir = Config::getAddonInstallDir() / title_id / entitlement_label->data; auto* mnt = Common::Singleton::Instance(); for (int i = 0; i < addcont_count; i++) { @@ -246,7 +246,7 @@ int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initPar LOG_ERROR(Lib_AppContent, "(DUMMY) called"); auto* param_sfo = Common::Singleton::Instance(); - const auto addons_dir = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir); + const auto addons_dir = Config::getAddonInstallDir(); if (const auto value = param_sfo->GetString("TITLE_ID"); value.has_value()) { title_id = *value; } else { diff --git a/src/qt_gui/game_install_dialog.cpp b/src/qt_gui/game_install_dialog.cpp index d8cc7a837..8f7ffd5d1 100644 --- a/src/qt_gui/game_install_dialog.cpp +++ b/src/qt_gui/game_install_dialog.cpp @@ -18,6 +18,7 @@ GameInstallDialog::GameInstallDialog() : m_gamesDirectory(nullptr) { auto layout = new QVBoxLayout(this); layout->addWidget(SetupGamesDirectory()); + layout->addWidget(SetupAddonsDirectory()); layout->addStretch(); layout->addWidget(SetupDialogActions()); @@ -27,7 +28,7 @@ GameInstallDialog::GameInstallDialog() : m_gamesDirectory(nullptr) { GameInstallDialog::~GameInstallDialog() {} -void GameInstallDialog::Browse() { +void GameInstallDialog::BrowseGamesDirectory() { auto path = QFileDialog::getExistingDirectory(this, tr("Directory to install games")); if (!path.isEmpty()) { @@ -35,6 +36,14 @@ void GameInstallDialog::Browse() { } } +void GameInstallDialog::BrowseAddonsDirectory() { + auto path = QFileDialog::getExistingDirectory(this, tr("Directory to install DLC")); + + if (!path.isEmpty()) { + m_addonsDirectory->setText(QDir::toNativeSeparators(path)); + } +} + QWidget* GameInstallDialog::SetupGamesDirectory() { auto group = new QGroupBox(tr("Directory to install games")); auto layout = new QHBoxLayout(group); @@ -51,7 +60,30 @@ QWidget* GameInstallDialog::SetupGamesDirectory() { // Browse button. auto browse = new QPushButton(tr("Browse")); - connect(browse, &QPushButton::clicked, this, &GameInstallDialog::Browse); + connect(browse, &QPushButton::clicked, this, &GameInstallDialog::BrowseGamesDirectory); + + layout->addWidget(browse); + + return group; +} + +QWidget* GameInstallDialog::SetupAddonsDirectory() { + auto group = new QGroupBox(tr("Directory to install DLC")); + auto layout = new QHBoxLayout(group); + + // Input. + m_addonsDirectory = new QLineEdit(); + QString install_dir; + Common::FS::PathToQString(install_dir, Config::getAddonInstallDir()); + m_addonsDirectory->setText(install_dir); + m_addonsDirectory->setMinimumWidth(400); + + layout->addWidget(m_addonsDirectory); + + // Browse button. + auto browse = new QPushButton(tr("Browse")); + + connect(browse, &QPushButton::clicked, this, &GameInstallDialog::BrowseAddonsDirectory); layout->addWidget(browse); @@ -70,6 +102,7 @@ QWidget* GameInstallDialog::SetupDialogActions() { void GameInstallDialog::Save() { // Check games directory. auto gamesDirectory = m_gamesDirectory->text(); + auto addonsDirectory = m_addonsDirectory->text(); if (gamesDirectory.isEmpty() || !QDir(gamesDirectory).exists() || !QDir::isAbsolutePath(gamesDirectory)) { @@ -78,7 +111,15 @@ void GameInstallDialog::Save() { return; } + if (addonsDirectory.isEmpty() || !QDir(addonsDirectory).exists() || + !QDir::isAbsolutePath(addonsDirectory)) { + QMessageBox::critical(this, tr("Error"), + "The value for location to install DLC is not valid."); + return; + } + Config::setGameInstallDir(Common::FS::PathFromQString(gamesDirectory)); + Config::setAddonInstallDir(Common::FS::PathFromQString(addonsDirectory)); const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); Config::save(config_dir / "config.toml"); accept(); diff --git a/src/qt_gui/game_install_dialog.h b/src/qt_gui/game_install_dialog.h index 6f439e81d..0a4e29357 100644 --- a/src/qt_gui/game_install_dialog.h +++ b/src/qt_gui/game_install_dialog.h @@ -16,13 +16,16 @@ public: ~GameInstallDialog(); private slots: - void Browse(); + void BrowseGamesDirectory(); + void BrowseAddonsDirectory(); private: QWidget* SetupGamesDirectory(); + QWidget* SetupAddonsDirectory(); QWidget* SetupDialogActions(); void Save(); private: QLineEdit* m_gamesDirectory; + QLineEdit* m_addonsDirectory; }; \ No newline at end of file diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 837cdece3..6f4b8ae7e 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -687,8 +687,8 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int } std::string entitlement_label = Common::SplitString(content_id, '-')[2]; - auto addon_extract_path = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir) / - pkg.GetTitleID() / entitlement_label; + auto addon_extract_path = + Config::getAddonInstallDir() / pkg.GetTitleID() / entitlement_label; QString addonDirPath; Common::FS::PathToQString(addonDirPath, addon_extract_path); QDir addon_dir(addonDirPath); From 98ea06e82deea35f33ab63c0539355d0120d597b Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 1 Oct 2024 01:54:36 -0300 Subject: [PATCH 23/34] cancel-in-progress (#1162) if 2 actions are being created to go to MAIN, the oldest one will be canceled --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f84ac330..b06a9c2d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,6 +9,10 @@ on: pull_request: branches: [ "*" ] +concurrency: + group: ci-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'push' }} + env: BUILD_TYPE: Release From 82c7c6aed163c1f9040ae9b2bb5e7f4a6b03f359 Mon Sep 17 00:00:00 2001 From: ElBread3 <92335081+ElBread3@users.noreply.github.com> Date: Tue, 1 Oct 2024 01:16:15 -0500 Subject: [PATCH 24/34] add mappings for kernel versions (#1171) --- src/core/libraries/kernel/file_system.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 91791fe87..e2093ce21 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -626,15 +626,19 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("AqBioC2vF3I", "libScePosix", 1, "libkernel", 1, 1, posix_read); LIB_FUNCTION("1-LFLmRFxxM", "libkernel", 1, "libkernel", 1, 1, sceKernelMkdir); LIB_FUNCTION("JGMio+21L4c", "libScePosix", 1, "libkernel", 1, 1, posix_mkdir); + LIB_FUNCTION("JGMio+21L4c", "libkernel", 1, "libkernel", 1, 1, posix_mkdir); LIB_FUNCTION("naInUjYt3so", "libkernel", 1, "libkernel", 1, 1, sceKernelRmdir); LIB_FUNCTION("c7ZnT7V1B98", "libScePosix", 1, "libkernel", 1, 1, posix_rmdir); + LIB_FUNCTION("c7ZnT7V1B98", "libkernel", 1, "libkernel", 1, 1, posix_rmdir); LIB_FUNCTION("eV9wAD2riIA", "libkernel", 1, "libkernel", 1, 1, sceKernelStat); LIB_FUNCTION("kBwCPsYX-m4", "libkernel", 1, "libkernel", 1, 1, sceKernelFStat); LIB_FUNCTION("mqQMh1zPPT8", "libScePosix", 1, "libkernel", 1, 1, posix_fstat); + LIB_FUNCTION("mqQMh1zPPT8", "libkernel", 1, "libkernel", 1, 1, posix_fstat); LIB_FUNCTION("VW3TVZiM4-E", "libkernel", 1, "libkernel", 1, 1, sceKernelFtruncate); LIB_FUNCTION("52NcYU9+lEo", "libkernel", 1, "libkernel", 1, 1, sceKernelRename); LIB_FUNCTION("E6ao34wPw+U", "libScePosix", 1, "libkernel", 1, 1, posix_stat); + LIB_FUNCTION("E6ao34wPw+U", "libkernel", 1, "libkernel", 1, 1, posix_stat); LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread); LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability); LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync); From bf3e43b01683bd783323e12237027103fae28d54 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Mon, 30 Sep 2024 23:54:06 -0700 Subject: [PATCH 25/34] vulkan: Use dynamic vertex buffer strides when dynamic bindings unavailable. (#1164) --- CMakeLists.txt | 2 +- README.md | 2 +- src/video_core/buffer_cache/buffer_cache.cpp | 11 +++- .../renderer_vulkan/vk_graphics_pipeline.cpp | 52 +++++++++++-------- .../renderer_vulkan/vk_graphics_pipeline.h | 1 + .../renderer_vulkan/vk_instance.cpp | 1 + .../renderer_vulkan/vk_pipeline_cache.cpp | 22 +++++++- 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9ea15918..598f59e11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) if(APPLE) enable_language(OBJC) - set(CMAKE_OSX_DEPLOYMENT_TARGET 11) + set(CMAKE_OSX_DEPLOYMENT_TARGET 14) endif() if (NOT CMAKE_BUILD_TYPE) diff --git a/README.md b/README.md index 6d6e2d82c..da01833e5 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shad Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md). > [!IMPORTANT] -> macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 11 on Intel-based Mac devices. +> macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 14 on Intel-based Mac devices. # Debugging and reporting issues diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index caffee6ba..607543a52 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -114,6 +114,8 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { std::array host_buffers; std::array host_offsets; + std::array host_sizes; + std::array host_strides; boost::container::static_vector guest_buffers; struct BufferRange { @@ -193,11 +195,18 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { host_buffers[i] = host_buffer->vk_buffer; host_offsets[i] = host_buffer->offset + buffer.base_address - host_buffer->base_address; + host_sizes[i] = buffer.GetSize(); + host_strides[i] = buffer.GetStride(); } if (num_buffers > 0) { const auto cmdbuf = scheduler.CommandBuffer(); - cmdbuf.bindVertexBuffers(0, num_buffers, host_buffers.data(), host_offsets.data()); + if (instance.IsVertexInputDynamicState()) { + cmdbuf.bindVertexBuffers(0, num_buffers, host_buffers.data(), host_offsets.data()); + } else { + cmdbuf.bindVertexBuffers2EXT(0, num_buffers, host_buffers.data(), host_offsets.data(), + host_sizes.data(), host_strides.data()); + } } return has_step_rate; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 3c191c4a1..ce79d4231 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -46,28 +46,34 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul boost::container::static_vector vertex_bindings; boost::container::static_vector vertex_attributes; - const auto& vs_info = stages[u32(Shader::Stage::Vertex)]; - 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) { - // Skip attribute binding as the data will be pulled by shader - continue; - } + if (!instance.IsVertexInputDynamicState()) { + const auto& vs_info = stages[u32(Shader::Stage::Vertex)]; + 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) { + // Skip attribute binding as the data will be pulled by shader + continue; + } - const auto buffer = vs_info->ReadUd(input.sgpr_base, input.dword_offset); - vertex_attributes.push_back({ - .location = input.binding, - .binding = input.binding, - .format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()), - .offset = 0, - }); - vertex_bindings.push_back({ - .binding = input.binding, - .stride = buffer.GetStride(), - .inputRate = input.instance_step_rate == Shader::Info::VsInput::None - ? vk::VertexInputRate::eVertex - : vk::VertexInputRate::eInstance, - }); + const auto buffer = + vs_info->ReadUd(input.sgpr_base, input.dword_offset); + if (buffer.GetSize() == 0) { + continue; + } + vertex_attributes.push_back({ + .location = input.binding, + .binding = input.binding, + .format = LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()), + .offset = 0, + }); + vertex_bindings.push_back({ + .binding = input.binding, + .stride = buffer.GetStride(), + .inputRate = input.instance_step_rate == Shader::Info::VsInput::None + ? vk::VertexInputRate::eVertex + : vk::VertexInputRate::eInstance, + }); + } } const vk::PipelineVertexInputStateCreateInfo vertex_input_info = { @@ -147,6 +153,8 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul } if (instance.IsVertexInputDynamicState()) { dynamic_states.push_back(vk::DynamicState::eVertexInputEXT); + } else { + dynamic_states.push_back(vk::DynamicState::eVertexInputBindingStrideEXT); } const vk::PipelineDynamicStateCreateInfo dynamic_info = { @@ -273,7 +281,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul .pNext = &pipeline_rendering_ci, .stageCount = static_cast(shader_stages.size()), .pStages = shader_stages.data(), - .pVertexInputState = &vertex_input_info, + .pVertexInputState = !instance.IsVertexInputDynamicState() ? &vertex_input_info : nullptr, .pInputAssemblyState = &input_assembly, .pViewportState = &viewport_info, .pRasterizationState = &raster_state, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 74817656a..dda9183a5 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -45,6 +45,7 @@ struct GraphicsPipelineKey { Liverpool::ColorBufferMask cb_shader_mask; std::array blend_controls; std::array write_masks; + std::array vertex_buffer_formats; bool operator==(const GraphicsPipelineKey& key) const noexcept { return std::memcmp(this, &key, sizeof(key)) == 0; diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index c09414a11..2aeb77ec8 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -272,6 +272,7 @@ bool Instance::CreateDevice() { 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); + add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_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 4aca00730..7a66fc0a2 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -247,6 +247,7 @@ bool PipelineCache::RefreshGraphicsKey() { key.blend_controls.fill({}); key.write_masks.fill({}); key.mrt_swizzles.fill(Liverpool::ColorBuffer::SwapMode::Standard); + key.vertex_buffer_formats.fill(vk::Format::eUndefined); // First pass of bindings check to idenitfy formats and swizzles and pass them to rhe shader // recompiler. @@ -310,7 +311,26 @@ bool PipelineCache::RefreshGraphicsKey() { std::tie(infos[i], modules[i], key.stage_hashes[i]) = GetProgram(stage, params, binding); } - const auto* fs_info = infos[u32(Shader::Stage::Fragment)]; + const auto* vs_info = infos[static_cast(Shader::Stage::Vertex)]; + if (vs_info && !instance.IsVertexInputDynamicState()) { + u32 vertex_binding = 0; + 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) { + continue; + } + const auto& buffer = + vs_info->ReadUd(input.sgpr_base, input.dword_offset); + if (buffer.GetSize() == 0) { + continue; + } + ASSERT(vertex_binding < MaxVertexBufferCount); + key.vertex_buffer_formats[vertex_binding++] = + Vulkan::LiverpoolToVK::SurfaceFormat(buffer.GetDataFmt(), buffer.GetNumberFmt()); + } + } + + const auto* fs_info = infos[static_cast(Shader::Stage::Fragment)]; key.mrt_mask = fs_info ? fs_info->mrt_mask : 0u; // Second pass to fill remain CB pipeline key data From e4c8626806ad78bc36e21222fbec5b6b20b7dad0 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 1 Oct 2024 05:49:30 -0700 Subject: [PATCH 26/34] qt: Fix message box for game overwrite. (#1181) --- src/qt_gui/main_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 6f4b8ae7e..8d8e17177 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -768,7 +768,7 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int } } } else { - msgBox.setText(QString(tr("Game already installed") + "\n" + addonDirPath + "\n" + + msgBox.setText(QString(tr("Game already installed") + "\n" + gameDirPath + "\n" + tr("Would you like to overwrite?"))); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); From b92dc8c714d462362a768d288691c0c6b8059a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quang=20Ng=C3=B4?= Date: Tue, 1 Oct 2024 20:11:08 +0700 Subject: [PATCH 27/34] ci: fix audio for Linux (#1177) --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b06a9c2d7..419f2e12f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -291,7 +291,7 @@ jobs: submodules: recursive - name: Install dependencies - run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential + run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev - name: Cache CMake Configuration uses: actions/cache@v4 @@ -347,7 +347,7 @@ jobs: submodules: recursive - name: Install dependencies - run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev + run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev - name: Cache CMake Configuration uses: actions/cache@v4 From 3a36615da75da9b8727e3abe3d3535b406ddda4a Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 1 Oct 2024 12:02:47 -0300 Subject: [PATCH 28/34] sort menu (#1183) --- src/qt_gui/game_list_frame.h | 38 +++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/qt_gui/game_list_frame.h b/src/qt_gui/game_list_frame.h index 2c3fffff9..af9ce9280 100644 --- a/src/qt_gui/game_list_frame.h +++ b/src/qt_gui/game_list_frame.h @@ -45,24 +45,44 @@ public: int icon_size; static bool CompareStringsAscending(GameInfo a, GameInfo b, int columnIndex) { - if (columnIndex == 1) { + switch (columnIndex) { + case 1: return a.name < b.name; - } else if (columnIndex == 2) { + case 2: return a.serial < b.serial; - } else if (columnIndex == 3) { + case 3: + return a.region < b.region; + case 4: return a.fw < b.fw; + case 5: + return a.size < b.size; + case 6: + return a.version < b.version; + case 7: + return a.path < b.path; + default: + return false; } - return false; } static bool CompareStringsDescending(GameInfo a, GameInfo b, int columnIndex) { - if (columnIndex == 1) { + switch (columnIndex) { + case 1: return a.name > b.name; - } else if (columnIndex == 2) { + case 2: return a.serial > b.serial; - } else if (columnIndex == 3) { + case 3: + return a.region > b.region; + case 4: return a.fw > b.fw; + case 5: + return a.size > b.size; + case 6: + return a.version > b.version; + case 7: + return a.path > b.path; + default: + return false; } - return false; } -}; +}; \ No newline at end of file From 3dea1a9f8189129d12fc852e8c012796d71ecec3 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:11:41 -0700 Subject: [PATCH 29/34] qt: Create addons directory if it does not exist. (#1186) --- src/common/path_util.h | 1 - src/qt_gui/game_install_dialog.cpp | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/common/path_util.h b/src/common/path_util.h index af0e91832..9bde2e287 100644 --- a/src/common/path_util.h +++ b/src/common/path_util.h @@ -44,7 +44,6 @@ constexpr auto DOWNLOAD_DIR = "download"; constexpr auto CAPTURES_DIR = "captures"; constexpr auto CHEATS_DIR = "cheats"; constexpr auto PATCHES_DIR = "patches"; -constexpr auto ADDONS_DIR = "addcont"; constexpr auto METADATA_DIR = "game_data"; // Filenames diff --git a/src/qt_gui/game_install_dialog.cpp b/src/qt_gui/game_install_dialog.cpp index 8f7ffd5d1..11daf2de0 100644 --- a/src/qt_gui/game_install_dialog.cpp +++ b/src/qt_gui/game_install_dialog.cpp @@ -111,12 +111,19 @@ void GameInstallDialog::Save() { return; } - if (addonsDirectory.isEmpty() || !QDir(addonsDirectory).exists() || - !QDir::isAbsolutePath(addonsDirectory)) { + if (addonsDirectory.isEmpty() || !QDir::isAbsolutePath(addonsDirectory)) { QMessageBox::critical(this, tr("Error"), "The value for location to install DLC is not valid."); return; } + QDir addonsDir(addonsDirectory); + if (!addonsDir.exists()) { + if (!addonsDir.mkpath(".")) { + QMessageBox::critical(this, tr("Error"), + "The DLC install location could not be created."); + return; + } + } Config::setGameInstallDir(Common::FS::PathFromQString(gamesDirectory)); Config::setAddonInstallDir(Common::FS::PathFromQString(addonsDirectory)); From 7d96c9d63453543204bbd1bf37d5901cbfea7072 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Tue, 1 Oct 2024 21:42:01 +0300 Subject: [PATCH 30/34] Use correct scissor rects (#1146) * WIP * Proper combination of scissors * convert static functions to lambdas --- src/video_core/amdgpu/liverpool.h | 53 +++++++++++++----- .../renderer_vulkan/vk_rasterizer.cpp | 54 +++++++++++++++++-- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 411b25ed1..b1036c019 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -253,6 +253,13 @@ struct Liverpool { } }; + struct ModeControl { + s32 msaa_enable : 1; + s32 vport_scissor_enable : 1; + s32 line_stripple_enable : 1; + s32 send_unlit_stiles_to_pkr : 1; + }; + enum class ZOrder : u32 { LateZ = 0, EarlyZLateZ = 1, @@ -559,29 +566,39 @@ struct Liverpool { s16 top_left_x; s16 top_left_y; }; - union { - BitField<0, 15, u32> bottom_right_x; - BitField<16, 15, u32> bottom_right_y; + struct { + s16 bottom_right_x; + s16 bottom_right_y; }; + // From AMD spec: 'Negative numbers clamped to 0' + static s16 Clamp(s16 value) { + return std::max(s16(0), value); + } + u32 GetWidth() const { - return static_cast(bottom_right_x - top_left_x); + return static_cast(Clamp(bottom_right_x) - Clamp(top_left_x)); } u32 GetHeight() const { - return static_cast(bottom_right_y - top_left_y); + return static_cast(Clamp(bottom_right_y) - Clamp(top_left_y)); } }; + struct WindowOffset { + s32 window_x_offset : 16; + s32 window_y_offset : 16; + }; + struct ViewportScissor { union { BitField<0, 15, s32> top_left_x; - BitField<15, 15, s32> top_left_y; - BitField<30, 1, s32> window_offset_disable; + BitField<16, 15, s32> top_left_y; + BitField<31, 1, s32> window_offset_disable; }; - union { - BitField<0, 15, s32> bottom_right_x; - BitField<15, 15, s32> bottom_right_y; + struct { + s16 bottom_right_x; + s16 bottom_right_y; }; u32 GetWidth() const { @@ -953,10 +970,14 @@ struct Liverpool { Scissor screen_scissor; INSERT_PADDING_WORDS(0xA010 - 0xA00C - 2); DepthBuffer depth_buffer; - INSERT_PADDING_WORDS(0xA08E - 0xA018); + INSERT_PADDING_WORDS(0xA080 - 0xA018); + WindowOffset window_offset; + ViewportScissor window_scissor; + INSERT_PADDING_WORDS(0xA08E - 0xA081 - 2); ColorBufferMask color_target_mask; ColorBufferMask color_shader_mask; - INSERT_PADDING_WORDS(0xA094 - 0xA08E - 2); + ViewportScissor generic_scissor; + INSERT_PADDING_WORDS(2); std::array viewport_scissors; std::array viewport_depths; INSERT_PADDING_WORDS(0xA103 - 0xA0D4); @@ -994,7 +1015,9 @@ struct Liverpool { PolygonControl polygon_control; ViewportControl viewport_control; VsOutputControl vs_output_control; - INSERT_PADDING_WORDS(0xA29E - 0xA207 - 2); + INSERT_PADDING_WORDS(0xA292 - 0xA207 - 1); + ModeControl mode_control; + INSERT_PADDING_WORDS(0xA29D - 0xA292 - 1); u32 index_size; u32 max_index_size; IndexBufferType index_buffer_type; @@ -1206,8 +1229,11 @@ static_assert(GFX6_3D_REG_INDEX(depth_htile_data_base) == 0xA005); static_assert(GFX6_3D_REG_INDEX(screen_scissor) == 0xA00C); static_assert(GFX6_3D_REG_INDEX(depth_buffer.z_info) == 0xA010); static_assert(GFX6_3D_REG_INDEX(depth_buffer.depth_slice) == 0xA017); +static_assert(GFX6_3D_REG_INDEX(window_offset) == 0xA080); +static_assert(GFX6_3D_REG_INDEX(window_scissor) == 0xA081); static_assert(GFX6_3D_REG_INDEX(color_target_mask) == 0xA08E); static_assert(GFX6_3D_REG_INDEX(color_shader_mask) == 0xA08F); +static_assert(GFX6_3D_REG_INDEX(generic_scissor) == 0xA090); static_assert(GFX6_3D_REG_INDEX(viewport_scissors) == 0xA094); static_assert(GFX6_3D_REG_INDEX(primitive_restart_index) == 0xA103); static_assert(GFX6_3D_REG_INDEX(stencil_control) == 0xA10B); @@ -1227,6 +1253,7 @@ static_assert(GFX6_3D_REG_INDEX(color_control) == 0xA202); static_assert(GFX6_3D_REG_INDEX(clipper_control) == 0xA204); static_assert(GFX6_3D_REG_INDEX(viewport_control) == 0xA206); static_assert(GFX6_3D_REG_INDEX(vs_output_control) == 0xA207); +static_assert(GFX6_3D_REG_INDEX(mode_control) == 0xA292); static_assert(GFX6_3D_REG_INDEX(index_size) == 0xA29D); static_assert(GFX6_3D_REG_INDEX(index_buffer_type) == 0xA29F); static_assert(GFX6_3D_REG_INDEX(enable_primitive_id) == 0xA2A1); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index e511c161e..159b489d8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -368,11 +368,55 @@ void Rasterizer::UpdateViewportScissorState() { .maxDepth = vp.zscale + vp.zoffset, }); } - const auto& sc = regs.screen_scissor; - scissors.push_back({ - .offset = {sc.top_left_x, sc.top_left_y}, - .extent = {sc.GetWidth(), sc.GetHeight()}, - }); + + const bool enable_offset = !regs.window_scissor.window_offset_disable.Value(); + Liverpool::Scissor scsr{}; + const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::max({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + + scsr.top_left_x = combined_scissor_value_tl( + regs.screen_scissor.top_left_x, s16(regs.window_scissor.top_left_x.Value()), + s16(regs.generic_scissor.top_left_x.Value()), + enable_offset ? regs.window_offset.window_x_offset : 0); + + scsr.top_left_y = combined_scissor_value_tl( + regs.screen_scissor.top_left_y, s16(regs.window_scissor.top_left_y.Value()), + s16(regs.generic_scissor.top_left_y.Value()), + enable_offset ? regs.window_offset.window_y_offset : 0); + + const auto combined_scissor_value_br = [](s16 scr, s16 win, s16 gen, s16 win_offset) { + return std::min({scr, s16(win + win_offset), s16(gen + win_offset)}); + }; + + scsr.bottom_right_x = combined_scissor_value_br( + regs.screen_scissor.bottom_right_x, regs.window_scissor.bottom_right_x, + regs.generic_scissor.bottom_right_x, + enable_offset ? regs.window_offset.window_x_offset : 0); + + scsr.bottom_right_y = combined_scissor_value_br( + regs.screen_scissor.bottom_right_y, regs.window_scissor.bottom_right_y, + regs.generic_scissor.bottom_right_y, + enable_offset ? regs.window_offset.window_y_offset : 0); + + for (u32 idx = 0; idx < Liverpool::NumViewports; idx++) { + auto vp_scsr = scsr; + if (regs.mode_control.vport_scissor_enable) { + vp_scsr.top_left_x = + std::max(vp_scsr.top_left_x, s16(regs.viewport_scissors[idx].top_left_x.Value())); + vp_scsr.top_left_y = + std::max(vp_scsr.top_left_y, s16(regs.viewport_scissors[idx].top_left_y.Value())); + vp_scsr.bottom_right_x = + std::min(vp_scsr.bottom_right_x, regs.viewport_scissors[idx].bottom_right_x); + vp_scsr.bottom_right_y = + std::min(vp_scsr.bottom_right_y, regs.viewport_scissors[idx].bottom_right_y); + } + scissors.push_back({ + .offset = {vp_scsr.top_left_x, vp_scsr.top_left_y}, + .extent = {vp_scsr.GetWidth(), vp_scsr.GetHeight()}, + }); + } + const auto cmdbuf = scheduler.CommandBuffer(); cmdbuf.setViewport(0, viewports); cmdbuf.setScissor(0, scissors); From f93b8c1e8df0e90854e7c3ddcef1dcb92b8f3984 Mon Sep 17 00:00:00 2001 From: qurious-pixel <62252937+qurious-pixel@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:43:18 -0700 Subject: [PATCH 31/34] remove libgstreamermediaplugin.so from qt multimedia plugins (#1187) --- .github/linux-appimage-qt.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/linux-appimage-qt.sh b/.github/linux-appimage-qt.sh index e33a4b21f..fe77c678c 100755 --- a/.github/linux-appimage-qt.sh +++ b/.github/linux-appimage-qt.sh @@ -14,12 +14,10 @@ export PATH="$Qt6_DIR/bin:$PATH" wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh -wget -q https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gstreamer/master/linuxdeploy-plugin-gstreamer.sh chmod a+x linuxdeploy-x86_64.AppImage chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh -chmod a+x linuxdeploy-plugin-gstreamer.sh # Build AppImage ./linuxdeploy-x86_64.AppImage --appdir AppDir @@ -27,5 +25,7 @@ chmod a+x linuxdeploy-plugin-gstreamer.sh cp -a "$GITHUB_WORKSPACE/build/translations" AppDir/usr/bin -./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt --plugin gstreamer --output appimage +./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt +rm AppDir/usr/plugins/multimedia/libgstreamermediaplugin.so +./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage mv Shadps4-x86_64.AppImage Shadps4-qt.AppImage From 65f72372f07cb835c0e842ddfc2c00a756a6cb09 Mon Sep 17 00:00:00 2001 From: CrazyBloo Date: Tue, 1 Oct 2024 16:39:43 -0400 Subject: [PATCH 32/34] trophy icon + platinum fixes (#1093) * trophy icon + platinum fixes cleaned up some parts too * format * implement turtles review * use fs native where possible, clang format * implement vinicius suggestions * format * final reviews * mutex for trophy queue, remove unneeded field * format --- src/core/libraries/np_trophy/np_trophy.cpp | 587 +++++++++------------ src/core/libraries/np_trophy/np_trophy.h | 58 +- src/core/libraries/np_trophy/trophy_ui.cpp | 102 ++-- src/core/libraries/np_trophy/trophy_ui.h | 26 +- src/qt_gui/trophy_viewer.cpp | 2 +- 5 files changed, 356 insertions(+), 419 deletions(-) diff --git a/src/core/libraries/np_trophy/np_trophy.cpp b/src/core/libraries/np_trophy/np_trophy.cpp index 91fdeb991..0641a2c06 100644 --- a/src/core/libraries/np_trophy/np_trophy.cpp +++ b/src/core/libraries/np_trophy/np_trophy.cpp @@ -14,8 +14,6 @@ namespace Libraries::NpTrophy { -static TrophyUI g_trophy_ui; - std::string game_serial; static constexpr auto MaxTrophyHandles = 4u; @@ -223,6 +221,14 @@ int PS4_SYSV_ABI sceNpTrophyGetGameIcon(OrbisNpTrophyContext context, OrbisNpTro return ORBIS_OK; } +struct GameTrophyInfo { + uint32_t num_groups; + uint32_t num_trophies; + uint32_t num_trophies_by_rarity[5]; + uint32_t unlocked_trophies; + uint32_t unlocked_trophies_by_rarity[5]; +}; + int PS4_SYSV_ABI sceNpTrophyGetGameInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle, OrbisNpTrophyGameDetails* details, OrbisNpTrophyGameData* data) { @@ -240,79 +246,66 @@ int PS4_SYSV_ABI sceNpTrophyGetGameInfo(OrbisNpTrophyContext context, OrbisNpTro if (details->size != 0x4A0 || data->size != 0x20) return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT; - const auto trophyDir = + const auto trophy_dir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles"; + auto trophy_file = trophy_dir / "trophy00" / "Xml" / "TROP.XML"; pugi::xml_document doc; - pugi::xml_parse_result result = - doc.load_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str()); + pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str()); - if (result) { + ASSERT_MSG(result, "Couldnt parse trophy XML : {}", result.description()); - uint32_t numGroups = 0; - uint32_t numTrophies = 0; - uint32_t numTrophiesByRarity[5]; - numTrophiesByRarity[1] = 0; - numTrophiesByRarity[2] = 0; - numTrophiesByRarity[3] = 0; - numTrophiesByRarity[4] = 0; - uint32_t unlockedTrophies = 0; - uint32_t unlockedTrophiesByRarity[5]; - unlockedTrophiesByRarity[1] = 0; - unlockedTrophiesByRarity[2] = 0; - unlockedTrophiesByRarity[3] = 0; - unlockedTrophiesByRarity[4] = 0; + GameTrophyInfo game_info{}; - auto trophyconf = doc.child("trophyconf"); - for (pugi::xml_node_iterator it = trophyconf.children().begin(); - it != trophyconf.children().end(); ++it) { + auto trophyconf = doc.child("trophyconf"); + for (const pugi::xml_node& node : trophyconf.children()) { + std::string_view node_name = node.name(); - if (std::string(it->name()) == "title-name") { - strncpy(details->title, it->text().as_string(), - ORBIS_NP_TROPHY_GAME_TITLE_MAX_SIZE); - } - - if (std::string(it->name()) == "title-detail") { - strncpy(details->description, it->text().as_string(), - ORBIS_NP_TROPHY_GAME_DESCR_MAX_SIZE); - } - - if (std::string(it->name()) == "group") - numGroups++; - - if (std::string(it->name()) == "trophy") { - std::string currentTrophyUnlockState = it->attribute("unlockstate").value(); - std::string currentTrophyGrade = it->attribute("ttype").value(); - - numTrophies++; - if (!currentTrophyGrade.empty()) { - int trophyGrade = GetTrophyGradeFromChar(currentTrophyGrade.at(0)); - numTrophiesByRarity[trophyGrade]++; - if (currentTrophyUnlockState == "unlocked") { - unlockedTrophies++; - unlockedTrophiesByRarity[trophyGrade]++; - } - } - } + if (node_name == "title-name") { + strncpy(details->title, node.text().as_string(), ORBIS_NP_TROPHY_GAME_TITLE_MAX_SIZE); } - details->numGroups = numGroups; - details->numTrophies = numTrophies; - details->numPlatinum = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; - details->numGold = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_GOLD]; - details->numSilver = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_SILVER]; - details->numBronze = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; - data->unlockedTrophies = unlockedTrophies; - data->unlockedPlatinum = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; - data->unlockedGold = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_GOLD]; - data->unlockedSilver = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_SILVER]; - data->unlockedBronze = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; + if (node_name == "title-detail") { + strncpy(details->description, node.text().as_string(), + ORBIS_NP_TROPHY_GAME_DESCR_MAX_SIZE); + } - // maybe this should be 1 instead of 100? - data->progressPercentage = 100; + if (node_name == "group") + game_info.num_groups++; - } else - LOG_INFO(Lib_NpTrophy, "couldnt parse xml : {}", result.description()); + if (node_name == "trophy") { + bool current_trophy_unlockstate = node.attribute("unlockstate").as_bool(); + std::string_view current_trophy_grade = node.attribute("ttype").value(); + + if (current_trophy_grade.empty()) { + continue; + } + + game_info.num_trophies++; + int trophy_grade = GetTrophyGradeFromChar(current_trophy_grade.at(0)); + game_info.num_trophies_by_rarity[trophy_grade]++; + + if (current_trophy_unlockstate) { + game_info.unlocked_trophies++; + game_info.unlocked_trophies_by_rarity[trophy_grade]++; + } + } + } + + details->num_groups = game_info.num_groups; + details->num_trophies = game_info.num_trophies; + details->num_platinum = game_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; + details->num_gold = game_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_GOLD]; + details->num_silver = game_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_SILVER]; + details->num_bronze = game_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; + data->unlocked_trophies = game_info.unlocked_trophies; + data->unlocked_platinum = game_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; + data->unlocked_gold = game_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_GOLD]; + data->unlocked_silver = game_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_SILVER]; + data->unlocked_bronze = game_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; + + // maybe this should be 1 instead of 100? + data->progress_percentage = 100; return ORBIS_OK; } @@ -323,6 +316,13 @@ int PS4_SYSV_ABI sceNpTrophyGetGroupIcon(OrbisNpTrophyContext context, OrbisNpTr return ORBIS_OK; } +struct GroupTrophyInfo { + uint32_t num_trophies; + uint32_t num_trophies_by_rarity[5]; + uint32_t unlocked_trophies; + uint32_t unlocked_trophies_by_rarity[5]; +}; + int PS4_SYSV_ABI sceNpTrophyGetGroupInfo(OrbisNpTrophyContext context, OrbisNpTrophyHandle handle, OrbisNpTrophyGroupId groupId, OrbisNpTrophyGroupDetails* details, @@ -341,89 +341,75 @@ int PS4_SYSV_ABI sceNpTrophyGetGroupInfo(OrbisNpTrophyContext context, OrbisNpTr if (details->size != 0x4A0 || data->size != 0x28) return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT; - const auto trophyDir = + const auto trophy_dir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles"; + auto trophy_file = trophy_dir / "trophy00" / "Xml" / "TROP.XML"; pugi::xml_document doc; - pugi::xml_parse_result result = - doc.load_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str()); + pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str()); - if (result) { + ASSERT_MSG(result, "Couldnt parse trophy XML : {}", result.description()); - uint32_t numGroups = 0; - uint32_t numTrophies = 0; - uint32_t numTrophiesByRarity[5]; - numTrophiesByRarity[1] = 0; - numTrophiesByRarity[2] = 0; - numTrophiesByRarity[3] = 0; - numTrophiesByRarity[4] = 0; - uint32_t unlockedTrophies = 0; - uint32_t unlockedTrophiesByRarity[5]; - unlockedTrophiesByRarity[1] = 0; - unlockedTrophiesByRarity[2] = 0; - unlockedTrophiesByRarity[3] = 0; - unlockedTrophiesByRarity[4] = 0; + GroupTrophyInfo group_info{}; - auto trophyconf = doc.child("trophyconf"); - for (pugi::xml_node_iterator it = trophyconf.children().begin(); - it != trophyconf.children().end(); ++it) { + auto trophyconf = doc.child("trophyconf"); + for (const pugi::xml_node& node : trophyconf.children()) { + std::string_view node_name = node.name(); - if (std::string(it->name()) == "group") { - numGroups++; - std::string currentGroupId = it->attribute("id").value(); - if (!currentGroupId.empty()) { - if (std::stoi(currentGroupId) == groupId) { - std::string currentGroupName = it->child("name").text().as_string(); - std::string currentGroupDescription = - it->child("detail").text().as_string(); + if (node_name == "group") { + int current_group_id = node.attribute("id").as_int(ORBIS_NP_TROPHY_INVALID_GROUP_ID); + if (current_group_id != ORBIS_NP_TROPHY_INVALID_GROUP_ID) { + if (current_group_id == groupId) { + std::string_view current_group_name = node.child("name").text().as_string(); + std::string_view current_group_description = + node.child("detail").text().as_string(); - strncpy(details->title, currentGroupName.c_str(), - ORBIS_NP_TROPHY_GROUP_TITLE_MAX_SIZE); - strncpy(details->description, currentGroupDescription.c_str(), - ORBIS_NP_TROPHY_GAME_DESCR_MAX_SIZE); - } - } - } - - data->groupId = groupId; - - if (std::string(it->name()) == "trophy") { - std::string currentTrophyUnlockState = it->attribute("unlockstate").value(); - std::string currentTrophyGrade = it->attribute("ttype").value(); - std::string currentTrophyGroupID = it->attribute("gid").value(); - - if (!currentTrophyGroupID.empty()) { - if (std::stoi(currentTrophyGroupID) == groupId) { - numTrophies++; - if (!currentTrophyGrade.empty()) { - int trophyGrade = GetTrophyGradeFromChar(currentTrophyGrade.at(0)); - numTrophiesByRarity[trophyGrade]++; - if (currentTrophyUnlockState == "unlocked") { - unlockedTrophies++; - unlockedTrophiesByRarity[trophyGrade]++; - } - } - } + strncpy(details->title, current_group_name.data(), + ORBIS_NP_TROPHY_GROUP_TITLE_MAX_SIZE); + strncpy(details->description, current_group_description.data(), + ORBIS_NP_TROPHY_GAME_DESCR_MAX_SIZE); } } } - details->numTrophies = numTrophies; - details->numPlatinum = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; - details->numGold = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_GOLD]; - details->numSilver = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_SILVER]; - details->numBronze = numTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; - data->unlockedTrophies = unlockedTrophies; - data->unlockedPlatinum = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; - data->unlockedGold = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_GOLD]; - data->unlockedSilver = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_SILVER]; - data->unlockedBronze = unlockedTrophiesByRarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; + details->group_id = groupId; + data->group_id = groupId; - // maybe this should be 1 instead of 100? - data->progressPercentage = 100; + if (node_name == "trophy") { + bool current_trophy_unlockstate = node.attribute("unlockstate").as_bool(); + std::string_view current_trophy_grade = node.attribute("ttype").value(); + int current_trophy_group_id = node.attribute("gid").as_int(-1); - } else - LOG_INFO(Lib_NpTrophy, "couldnt parse xml : {}", result.description()); + if (current_trophy_grade.empty()) { + continue; + } + + if (current_trophy_group_id == groupId) { + group_info.num_trophies++; + int trophyGrade = GetTrophyGradeFromChar(current_trophy_grade.at(0)); + group_info.num_trophies_by_rarity[trophyGrade]++; + if (current_trophy_unlockstate) { + group_info.unlocked_trophies++; + group_info.unlocked_trophies_by_rarity[trophyGrade]++; + } + } + } + } + + details->num_trophies = group_info.num_trophies; + details->num_platinum = group_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; + details->num_gold = group_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_GOLD]; + details->num_silver = group_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_SILVER]; + details->num_bronze = group_info.num_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; + data->unlocked_trophies = group_info.unlocked_trophies; + data->unlocked_platinum = + group_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_PLATINUM]; + data->unlocked_gold = group_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_GOLD]; + data->unlocked_silver = group_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_SILVER]; + data->unlocked_bronze = group_info.unlocked_trophies_by_rarity[ORBIS_NP_TROPHY_GRADE_BRONZE]; + + // maybe this should be 1 instead of 100? + data->progress_percentage = 100; return ORBIS_OK; } @@ -454,87 +440,48 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(OrbisNpTrophyContext context, OrbisNpT if (details->size != 0x498 || data->size != 0x18) return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT; - const auto trophyDir = + const auto trophy_dir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles"; + auto trophy_file = trophy_dir / "trophy00" / "Xml" / "TROP.XML"; pugi::xml_document doc; - pugi::xml_parse_result result = - doc.load_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str()); + pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str()); - if (result) { - auto trophyconf = doc.child("trophyconf"); - for (pugi::xml_node_iterator it = trophyconf.children().begin(); - it != trophyconf.children().end(); ++it) { + ASSERT_MSG(result, "Couldnt parse trophy XML : {}", result.description()); - if (std::string(it->name()) == "trophy") { - std::string currentTrophyId = it->attribute("id").value(); - if (std::stoi(currentTrophyId) == trophyId) { - std::string currentTrophyUnlockState = it->attribute("unlockstate").value(); - std::string currentTrophyTimestamp = it->attribute("timestamp").value(); - std::string currentTrophyGrade = it->attribute("ttype").value(); - std::string currentTrophyGroupID = it->attribute("gid").value(); - std::string currentTrophyHidden = it->attribute("hidden").value(); - std::string currentTrophyName = it->child("name").text().as_string(); - std::string currentTrophyDescription = it->child("detail").text().as_string(); + auto trophyconf = doc.child("trophyconf"); - if (currentTrophyUnlockState == "unlocked") { - details->trophyId = trophyId; - if (currentTrophyGrade.empty()) { - details->trophyGrade = ORBIS_NP_TROPHY_GRADE_UNKNOWN; - } else { - details->trophyGrade = GetTrophyGradeFromChar(currentTrophyGrade.at(0)); - } - if (currentTrophyGroupID.empty()) { - details->groupId = ORBIS_NP_TROPHY_BASE_GAME_GROUP_ID; - } else { - details->groupId = std::stoi(currentTrophyGroupID); - } - if (currentTrophyHidden == "yes") { - details->hidden = true; - } else { - details->hidden = false; - } + for (const pugi::xml_node& node : trophyconf.children()) { + std::string_view node_name = node.name(); - strncpy(details->name, currentTrophyName.c_str(), - ORBIS_NP_TROPHY_NAME_MAX_SIZE); - strncpy(details->description, currentTrophyDescription.c_str(), - ORBIS_NP_TROPHY_DESCR_MAX_SIZE); + if (node_name == "trophy") { + int current_trophy_id = node.attribute("id").as_int(ORBIS_NP_TROPHY_INVALID_TROPHY_ID); + if (current_trophy_id == trophyId) { + bool current_trophy_unlockstate = node.attribute("unlockstate").as_bool(); + std::string_view current_trophy_grade = node.attribute("ttype").value(); + std::string_view current_trophy_name = node.child("name").text().as_string(); + std::string_view current_trophy_description = + node.child("detail").text().as_string(); - data->trophyId = trophyId; - data->unlocked = true; - data->timestamp.tick = std::stoull(currentTrophyTimestamp); - } else { - details->trophyId = trophyId; - if (currentTrophyGrade.empty()) { - details->trophyGrade = ORBIS_NP_TROPHY_GRADE_UNKNOWN; - } else { - details->trophyGrade = GetTrophyGradeFromChar(currentTrophyGrade.at(0)); - } - if (currentTrophyGroupID.empty()) { - details->groupId = ORBIS_NP_TROPHY_BASE_GAME_GROUP_ID; - } else { - details->groupId = std::stoi(currentTrophyGroupID); - } - if (currentTrophyHidden == "yes") { - details->hidden = true; - } else { - details->hidden = false; - } + uint64_t current_trophy_timestamp = node.attribute("timestamp").as_ullong(); + int current_trophy_groupid = node.attribute("gid").as_int(-1); + bool current_trophy_hidden = node.attribute("hidden").as_bool(); - strncpy(details->name, currentTrophyName.c_str(), - ORBIS_NP_TROPHY_NAME_MAX_SIZE); - strncpy(details->description, currentTrophyDescription.c_str(), - ORBIS_NP_TROPHY_DESCR_MAX_SIZE); + details->trophy_id = trophyId; + details->trophy_grade = GetTrophyGradeFromChar(current_trophy_grade.at(0)); + details->group_id = current_trophy_groupid; + details->hidden = current_trophy_hidden; - data->trophyId = trophyId; - data->unlocked = false; - data->timestamp.tick = 0; - } - } + strncpy(details->name, current_trophy_name.data(), ORBIS_NP_TROPHY_NAME_MAX_SIZE); + strncpy(details->description, current_trophy_description.data(), + ORBIS_NP_TROPHY_DESCR_MAX_SIZE); + + data->trophy_id = trophyId; + data->unlocked = current_trophy_unlockstate; + data->timestamp.tick = current_trophy_timestamp; } } - } else - LOG_INFO(Lib_NpTrophy, "couldnt parse xml : {}", result.description()); + } return ORBIS_OK; } @@ -555,35 +502,33 @@ s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context, ORBIS_NP_TROPHY_FLAG_ZERO(flags); - const auto trophyDir = + const auto trophy_dir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles"; - auto trophy_file = trophyDir / "trophy00" / "Xml" / "TROP.XML"; + auto trophy_file = trophy_dir / "trophy00" / "Xml" / "TROP.XML"; pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str()); - int numTrophies = 0; + ASSERT_MSG(result, "Couldnt parse trophy XML : {}", result.description()); - if (result) { - auto trophyconf = doc.child("trophyconf"); - for (pugi::xml_node_iterator it = trophyconf.children().begin(); - it != trophyconf.children().end(); ++it) { + int num_trophies = 0; + auto trophyconf = doc.child("trophyconf"); - std::string currentTrophyId = it->attribute("id").value(); - std::string currentTrophyUnlockState = it->attribute("unlockstate").value(); + for (const pugi::xml_node& node : trophyconf.children()) { + std::string_view node_name = node.name(); + int current_trophy_id = node.attribute("id").as_int(ORBIS_NP_TROPHY_INVALID_TROPHY_ID); + bool current_trophy_unlockstate = node.attribute("unlockstate").as_bool(); - if (std::string(it->name()) == "trophy") { - numTrophies++; - } - - if (currentTrophyUnlockState == "unlocked") { - ORBIS_NP_TROPHY_FLAG_SET(std::stoi(currentTrophyId), flags); - } + if (node_name == "trophy") { + num_trophies++; } - } else - LOG_INFO(Lib_NpTrophy, "couldnt parse xml : {}", result.description()); - *count = numTrophies; + if (current_trophy_unlockstate) { + ORBIS_NP_TROPHY_FLAG_SET(current_trophy_id, flags); + } + } + + *count = num_trophies; return ORBIS_OK; } @@ -912,148 +857,116 @@ int PS4_SYSV_ABI sceNpTrophyUnlockTrophy(OrbisNpTrophyContext context, OrbisNpTr if (platinumId == nullptr) return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT; - const auto trophyDir = + const auto trophy_dir = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / game_serial / "TrophyFiles"; + auto trophy_file = trophy_dir / "trophy00" / "Xml" / "TROP.XML"; pugi::xml_document doc; - pugi::xml_parse_result result = - doc.load_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str()); + pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str()); + + ASSERT_MSG(result, "Couldnt parse trophy XML : {}", result.description()); *platinumId = ORBIS_NP_TROPHY_INVALID_TROPHY_ID; - int numTrophies = 0; - int numTrophiesUnlocked = 0; + int num_trophies = 0; + int num_trophies_unlocked = 0; + pugi::xml_node platinum_node; - pugi::xml_node_iterator platinumIt; - int platinumTrophyGroup = -1; + auto trophyconf = doc.child("trophyconf"); - if (result) { - auto trophyconf = doc.child("trophyconf"); - for (pugi::xml_node_iterator it = trophyconf.children().begin(); - it != trophyconf.children().end(); ++it) { + for (pugi::xml_node& node : trophyconf.children()) { + int current_trophy_id = node.attribute("id").as_int(ORBIS_NP_TROPHY_INVALID_TROPHY_ID); + bool current_trophy_unlockstate = node.attribute("unlockstate").as_bool(); + const char* current_trophy_name = node.child("name").text().as_string(); + std::string_view current_trophy_description = node.child("detail").text().as_string(); + std::string_view current_trophy_type = node.attribute("ttype").value(); - std::string currentTrophyId = it->attribute("id").value(); - std::string currentTrophyName = it->child("name").text().as_string(); - std::string currentTrophyDescription = it->child("detail").text().as_string(); - std::string currentTrophyType = it->attribute("ttype").value(); - std::string currentTrophyUnlockState = it->attribute("unlockstate").value(); + if (current_trophy_type == "P") { + platinum_node = node; + if (trophyId == current_trophy_id) { + return ORBIS_NP_TROPHY_ERROR_PLATINUM_CANNOT_UNLOCK; + } + } - if (currentTrophyType == "P") { - platinumIt = it; - - if (std::string(platinumIt->attribute("gid").value()).empty()) { - platinumTrophyGroup = -1; - } else { - platinumTrophyGroup = - std::stoi(std::string(platinumIt->attribute("gid").value())); - } - - if (trophyId == std::stoi(currentTrophyId)) { - return ORBIS_NP_TROPHY_ERROR_PLATINUM_CANNOT_UNLOCK; + if (std::string_view(node.name()) == "trophy") { + if (node.attribute("pid").as_int(-1) != ORBIS_NP_TROPHY_INVALID_TROPHY_ID) { + num_trophies++; + if (current_trophy_unlockstate) { + num_trophies_unlocked++; } } - if (std::string(it->name()) == "trophy") { - if (platinumTrophyGroup == -1) { - if (std::string(it->attribute("gid").value()).empty()) { - numTrophies++; - if (currentTrophyUnlockState == "unlocked") { - numTrophiesUnlocked++; - } - } + if (current_trophy_id == trophyId) { + if (current_trophy_unlockstate) { + LOG_INFO(Lib_NpTrophy, "Trophy already unlocked"); + return ORBIS_NP_TROPHY_ERROR_TROPHY_ALREADY_UNLOCKED; } else { - if (!std::string(it->attribute("gid").value()).empty()) { - if (std::stoi(std::string(it->attribute("gid").value())) == - platinumTrophyGroup) { - numTrophies++; - if (currentTrophyUnlockState == "unlocked") { - numTrophiesUnlocked++; - } - } - } - } - - if (std::stoi(currentTrophyId) == trophyId) { - LOG_INFO(Lib_NpTrophy, "Found trophy to unlock {} : {}", - it->child("name").text().as_string(), - it->child("detail").text().as_string()); - if (currentTrophyUnlockState == "unlocked") { - LOG_INFO(Lib_NpTrophy, "Trophy already unlocked"); - return ORBIS_NP_TROPHY_ERROR_TROPHY_ALREADY_UNLOCKED; + if (node.attribute("unlockstate").empty()) { + node.append_attribute("unlockstate") = "true"; } else { - if (std::string(it->attribute("unlockstate").value()).empty()) { - it->append_attribute("unlockstate") = "unlocked"; - } else { - it->attribute("unlockstate").set_value("unlocked"); - } - - Rtc::OrbisRtcTick trophyTimestamp; - Rtc::sceRtcGetCurrentTick(&trophyTimestamp); - - if (std::string(it->attribute("timestamp").value()).empty()) { - it->append_attribute("timestamp") = - std::to_string(trophyTimestamp.tick).c_str(); - } else { - it->attribute("timestamp") - .set_value(std::to_string(trophyTimestamp.tick).c_str()); - } - - g_trophy_ui.AddTrophyToQueue(trophyId, currentTrophyName); + node.attribute("unlockstate").set_value("true"); } + + Rtc::OrbisRtcTick trophyTimestamp; + Rtc::sceRtcGetCurrentTick(&trophyTimestamp); + + if (node.attribute("timestamp").empty()) { + node.append_attribute("timestamp") = + std::to_string(trophyTimestamp.tick).c_str(); + } else { + node.attribute("timestamp") + .set_value(std::to_string(trophyTimestamp.tick).c_str()); + } + + std::string trophy_icon_file = "TROP"; + trophy_icon_file.append(node.attribute("id").value()); + trophy_icon_file.append(".PNG"); + + std::filesystem::path current_icon_path = + trophy_dir / "trophy00" / "Icons" / trophy_icon_file; + + AddTrophyToQueue(current_icon_path, current_trophy_name); } } } + } - if (std::string(platinumIt->attribute("unlockstate").value()).empty()) { - if ((numTrophies - 2) == numTrophiesUnlocked) { - - platinumIt->append_attribute("unlockstate") = "unlocked"; - - Rtc::OrbisRtcTick trophyTimestamp; - Rtc::sceRtcGetCurrentTick(&trophyTimestamp); - - if (std::string(platinumIt->attribute("timestamp").value()).empty()) { - platinumIt->append_attribute("timestamp") = - std::to_string(trophyTimestamp.tick).c_str(); - } else { - platinumIt->attribute("timestamp") - .set_value(std::to_string(trophyTimestamp.tick).c_str()); - } - - std::string platinumTrophyId = platinumIt->attribute("id").value(); - std::string platinumTrophyName = platinumIt->child("name").text().as_string(); - - *platinumId = std::stoi(platinumTrophyId); - g_trophy_ui.AddTrophyToQueue(*platinumId, platinumTrophyName); + if (!platinum_node.attribute("unlockstate").as_bool()) { + if ((num_trophies - 1) == num_trophies_unlocked) { + if (platinum_node.attribute("unlockstate").empty()) { + platinum_node.append_attribute("unlockstate") = "true"; + } else { + platinum_node.attribute("unlockstate").set_value("true"); } - } else if (std::string(platinumIt->attribute("unlockstate").value()) == "locked") { - if ((numTrophies - 2) == numTrophiesUnlocked) { - platinumIt->attribute("unlockstate").set_value("unlocked"); + Rtc::OrbisRtcTick trophyTimestamp; + Rtc::sceRtcGetCurrentTick(&trophyTimestamp); - Rtc::OrbisRtcTick trophyTimestamp; - Rtc::sceRtcGetCurrentTick(&trophyTimestamp); - - if (std::string(platinumIt->attribute("timestamp").value()).empty()) { - platinumIt->append_attribute("timestamp") = - std::to_string(trophyTimestamp.tick).c_str(); - } else { - platinumIt->attribute("timestamp") - .set_value(std::to_string(trophyTimestamp.tick).c_str()); - } - - std::string platinumTrophyId = platinumIt->attribute("id").value(); - std::string platinumTrophyName = platinumIt->child("name").text().as_string(); - - *platinumId = std::stoi(platinumTrophyId); - g_trophy_ui.AddTrophyToQueue(*platinumId, platinumTrophyName); + if (platinum_node.attribute("timestamp").empty()) { + platinum_node.append_attribute("timestamp") = + std::to_string(trophyTimestamp.tick).c_str(); + } else { + platinum_node.attribute("timestamp") + .set_value(std::to_string(trophyTimestamp.tick).c_str()); } + + int platinum_trophy_id = + platinum_node.attribute("id").as_int(ORBIS_NP_TROPHY_INVALID_TROPHY_ID); + const char* platinum_trophy_name = platinum_node.child("name").text().as_string(); + + std::string platinum_icon_file = "TROP"; + platinum_icon_file.append(platinum_node.attribute("id").value()); + platinum_icon_file.append(".PNG"); + + std::filesystem::path platinum_icon_path = + trophy_dir / "trophy00" / "Icons" / platinum_icon_file; + + *platinumId = platinum_trophy_id; + AddTrophyToQueue(platinum_icon_path, platinum_trophy_name); } + } - doc.save_file((trophyDir.string() + "/trophy00/Xml/TROP.XML").c_str()); - - } else - LOG_INFO(Lib_NpTrophy, "couldnt parse xml : {}", result.description()); + doc.save_file((trophy_dir.string() + "/trophy00/Xml/TROP.XML").c_str()); return ORBIS_OK; } diff --git a/src/core/libraries/np_trophy/np_trophy.h b/src/core/libraries/np_trophy/np_trophy.h index ae08b2969..ac13a9ab7 100644 --- a/src/core/libraries/np_trophy/np_trophy.h +++ b/src/core/libraries/np_trophy/np_trophy.h @@ -47,7 +47,7 @@ bool ORBIS_NP_TROPHY_FLAG_ISSET(int32_t trophyId, OrbisNpTrophyFlagArray* p); struct OrbisNpTrophyData { size_t size; - OrbisNpTrophyId trophyId; + OrbisNpTrophyId trophy_id; bool unlocked; uint8_t reserved[3]; Rtc::OrbisRtcTick timestamp; @@ -66,9 +66,9 @@ constexpr int ORBIS_NP_TROPHY_INVALID_GROUP_ID = -2; struct OrbisNpTrophyDetails { size_t size; - OrbisNpTrophyId trophyId; - OrbisNpTrophyGrade trophyGrade; - OrbisNpTrophyGroupId groupId; + OrbisNpTrophyId trophy_id; + OrbisNpTrophyGrade trophy_grade; + OrbisNpTrophyGroupId group_id; bool hidden; uint8_t reserved[3]; char name[ORBIS_NP_TROPHY_NAME_MAX_SIZE]; @@ -77,46 +77,46 @@ struct OrbisNpTrophyDetails { struct OrbisNpTrophyGameData { size_t size; - uint32_t unlockedTrophies; - uint32_t unlockedPlatinum; - uint32_t unlockedGold; - uint32_t unlockedSilver; - uint32_t unlockedBronze; - uint32_t progressPercentage; + uint32_t unlocked_trophies; + uint32_t unlocked_platinum; + uint32_t unlocked_gold; + uint32_t unlocked_silver; + uint32_t unlocked_bronze; + uint32_t progress_percentage; }; struct OrbisNpTrophyGameDetails { size_t size; - uint32_t numGroups; - uint32_t numTrophies; - uint32_t numPlatinum; - uint32_t numGold; - uint32_t numSilver; - uint32_t numBronze; + uint32_t num_groups; + uint32_t num_trophies; + uint32_t num_platinum; + uint32_t num_gold; + uint32_t num_silver; + uint32_t num_bronze; char title[ORBIS_NP_TROPHY_GAME_TITLE_MAX_SIZE]; char description[ORBIS_NP_TROPHY_GAME_DESCR_MAX_SIZE]; }; struct OrbisNpTrophyGroupData { size_t size; - OrbisNpTrophyGroupId groupId; - uint32_t unlockedTrophies; - uint32_t unlockedPlatinum; - uint32_t unlockedGold; - uint32_t unlockedSilver; - uint32_t unlockedBronze; - uint32_t progressPercentage; + OrbisNpTrophyGroupId group_id; + uint32_t unlocked_trophies; + uint32_t unlocked_platinum; + uint32_t unlocked_gold; + uint32_t unlocked_silver; + uint32_t unlocked_bronze; + uint32_t progress_percentage; uint8_t reserved[4]; }; struct OrbisNpTrophyGroupDetails { size_t size; - OrbisNpTrophyGroupId groupId; - uint32_t numTrophies; - uint32_t numPlatinum; - uint32_t numGold; - uint32_t numSilver; - uint32_t numBronze; + OrbisNpTrophyGroupId group_id; + uint32_t num_trophies; + uint32_t num_platinum; + uint32_t num_gold; + uint32_t num_silver; + uint32_t num_bronze; char title[ORBIS_NP_TROPHY_GROUP_TITLE_MAX_SIZE]; char description[ORBIS_NP_TROPHY_GROUP_DESCR_MAX_SIZE]; }; diff --git a/src/core/libraries/np_trophy/trophy_ui.cpp b/src/core/libraries/np_trophy/trophy_ui.cpp index 8deaac25b..740bd3a10 100644 --- a/src/core/libraries/np_trophy/trophy_ui.cpp +++ b/src/core/libraries/np_trophy/trophy_ui.cpp @@ -2,15 +2,27 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include "common/assert.h" +#include "common/singleton.h" #include "imgui/imgui_std.h" #include "trophy_ui.h" using namespace ImGui; -using namespace Libraries::NpTrophy; +namespace Libraries::NpTrophy { -TrophyUI::TrophyUI() { +std::optional current_trophy_ui; +std::queue trophy_queue; +std::mutex queueMtx; + +TrophyUI::TrophyUI(std::filesystem::path trophyIconPath, std::string trophyName) + : trophy_name(trophyName) { + if (std::filesystem::exists(trophyIconPath)) { + trophy_icon = RefCountedTexture::DecodePngFile(trophyIconPath); + } else { + LOG_ERROR(Lib_NpTrophy, "Couldnt load trophy icon at {}", trophyIconPath.string()); + } AddLayer(this); } @@ -18,57 +30,65 @@ TrophyUI::~TrophyUI() { Finish(); } -void Libraries::NpTrophy::TrophyUI::AddTrophyToQueue(int trophyId, std::string trophyName) { - TrophyInfo newInfo; - newInfo.trophyId = trophyId; - newInfo.trophyName = trophyName; - trophyQueue.push_back(newInfo); -} - void TrophyUI::Finish() { RemoveLayer(this); } -bool displayingTrophy; -std::chrono::steady_clock::time_point trophyStartedTime; - void TrophyUI::Draw() { const auto& io = GetIO(); const ImVec2 window_size{ - std::min(io.DisplaySize.x, 200.f), - std::min(io.DisplaySize.y, 75.f), + std::min(io.DisplaySize.x, 250.f), + std::min(io.DisplaySize.y, 70.f), }; - if (trophyQueue.size() != 0) { - if (!displayingTrophy) { - displayingTrophy = true; - trophyStartedTime = std::chrono::steady_clock::now(); + SetNextWindowSize(window_size); + SetNextWindowCollapsed(false); + SetNextWindowPos(ImVec2(io.DisplaySize.x - 250, 50)); + KeepNavHighlight(); + + if (Begin("Trophy Window", nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoInputs)) { + if (trophy_icon) { + Image(trophy_icon.GetTexture().im_id, ImVec2(50, 50)); + ImGui::SameLine(); + } else { + // placeholder + const auto pos = GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(pos, pos + ImVec2{50.0f}, + GetColorU32(ImVec4{0.7f})); + ImGui::Indent(60); } + TextWrapped("Trophy earned!\n%s", trophy_name.c_str()); + } + End(); - std::chrono::steady_clock::time_point timeNow = std::chrono::steady_clock::now(); - std::chrono::seconds duration = - std::chrono::duration_cast(timeNow - trophyStartedTime); - - if (duration.count() >= 5) { - trophyQueue.erase(trophyQueue.begin()); - displayingTrophy = false; - } - - if (trophyQueue.size() != 0) { - SetNextWindowSize(window_size); - SetNextWindowCollapsed(false); - SetNextWindowPos(ImVec2(io.DisplaySize.x - 200, 50)); - KeepNavHighlight(); - - TrophyInfo currentTrophyInfo = trophyQueue[0]; - if (Begin("Trophy Window", nullptr, - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | - ImGuiWindowFlags_NoInputs)) { - Text("Trophy earned!"); - TextWrapped("%s", currentTrophyInfo.trophyName.c_str()); - } - End(); + trophy_timer -= io.DeltaTime; + if (trophy_timer <= 0) { + queueMtx.lock(); + if (!trophy_queue.empty()) { + TrophyInfo next_trophy = trophy_queue.front(); + trophy_queue.pop(); + current_trophy_ui.emplace(next_trophy.trophy_icon_path, next_trophy.trophy_name); + } else { + current_trophy_ui.reset(); } + queueMtx.unlock(); } } + +void AddTrophyToQueue(std::filesystem::path trophyIconPath, std::string trophyName) { + queueMtx.lock(); + if (current_trophy_ui.has_value()) { + TrophyInfo new_trophy; + new_trophy.trophy_icon_path = trophyIconPath; + new_trophy.trophy_name = trophyName; + trophy_queue.push(new_trophy); + } else { + current_trophy_ui.emplace(trophyIconPath, trophyName); + } + queueMtx.unlock(); +} + +} // namespace Libraries::NpTrophy \ No newline at end of file diff --git a/src/core/libraries/np_trophy/trophy_ui.h b/src/core/libraries/np_trophy/trophy_ui.h index 060d80dec..4448c2281 100644 --- a/src/core/libraries/np_trophy/trophy_ui.h +++ b/src/core/libraries/np_trophy/trophy_ui.h @@ -5,32 +5,36 @@ #include #include -#include +#include #include "common/fixed_value.h" #include "common/types.h" #include "core/libraries/np_trophy/np_trophy.h" #include "imgui/imgui_layer.h" +#include "imgui/imgui_texture.h" namespace Libraries::NpTrophy { -struct TrophyInfo { - int trophyId = -1; - std::string trophyName; -}; - class TrophyUI final : public ImGui::Layer { - std::vector trophyQueue; - public: - TrophyUI(); + TrophyUI(std::filesystem::path trophyIconPath, std::string trophyName); ~TrophyUI() override; - void AddTrophyToQueue(int trophyId, std::string trophyName); - void Finish(); void Draw() override; + +private: + std::string trophy_name; + float trophy_timer = 5.0f; + ImGui::RefCountedTexture trophy_icon; }; +struct TrophyInfo { + std::filesystem::path trophy_icon_path; + std::string trophy_name; +}; + +void AddTrophyToQueue(std::filesystem::path trophyIconPath, std::string trophyName); + }; // namespace Libraries::NpTrophy \ No newline at end of file diff --git a/src/qt_gui/trophy_viewer.cpp b/src/qt_gui/trophy_viewer.cpp index e4394c7e6..a14da1189 100644 --- a/src/qt_gui/trophy_viewer.cpp +++ b/src/qt_gui/trophy_viewer.cpp @@ -76,7 +76,7 @@ void TrophyViewer::PopulateTrophyWidget(QString title) { trpType.append(reader.attributes().value("ttype").toString()); trpPid.append(reader.attributes().value("pid").toString()); if (reader.attributes().hasAttribute("unlockstate")) { - if (reader.attributes().value("unlockstate").toString() == "unlocked") { + if (reader.attributes().value("unlockstate").toString() == "true") { trpUnlocked.append("unlocked"); } else { trpUnlocked.append("locked"); From 75adf7c8d1e273e79f3d589b02b8d6bdea48a167 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:42:20 -0700 Subject: [PATCH 33/34] vulkan: Fix some common validation errors. (#1101) * vulkan: Fix some extension support related validation errors. * vulkan: Fix validation error on zero-size buffer. * vulkan: Fix primitive list restart validation error. --- src/shader_recompiler/backend/spirv/emit_spirv.cpp | 1 + src/video_core/buffer_cache/buffer.cpp | 5 +++-- .../renderer_vulkan/vk_graphics_pipeline.cpp | 12 +++++++++--- .../renderer_vulkan/vk_graphics_pipeline.h | 10 ++++++++++ src/video_core/renderer_vulkan/vk_instance.cpp | 7 +++---- src/video_core/renderer_vulkan/vk_instance.h | 11 +++++++++++ 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 8aa292b1c..891b26084 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -233,6 +233,7 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { ctx.AddExecutionMode(main, spv::ExecutionMode::OriginUpperLeft); } if (info.has_discard) { + ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); } if (info.stores.Get(IR::Attribute::Depth)) { diff --git a/src/video_core/buffer_cache/buffer.cpp b/src/video_core/buffer_cache/buffer.cpp index f8afd6991..5a049c185 100644 --- a/src/video_core/buffer_cache/buffer.cpp +++ b/src/video_core/buffer_cache/buffer.cpp @@ -95,7 +95,8 @@ Buffer::Buffer(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, // Create buffer object. const vk::BufferCreateInfo buffer_ci = { .size = size_bytes, - .usage = flags, + // When maintenance5 is not supported, use all flags since we can't add flags to views. + .usage = instance->IsMaintenance5Supported() ? flags : AllFlags, }; VmaAllocationInfo alloc_info{}; buffer.Create(buffer_ci, usage, &alloc_info); @@ -119,7 +120,7 @@ vk::BufferView Buffer::View(u32 offset, u32 size, bool is_written, AmdGpu::DataF : vk::BufferUsageFlagBits2KHR::eUniformTexelBuffer, }; const vk::BufferViewCreateInfo view_ci = { - .pNext = &usage_flags, + .pNext = instance->IsMaintenance5Supported() ? &usage_flags : nullptr, .buffer = buffer.buffer, .format = Vulkan::LiverpoolToVK::SurfaceFormat(dfmt, nfmt), .offset = offset, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index ce79d4231..c10cac6cb 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -88,11 +88,17 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul "Rectangle List primitive type is only supported for embedded VS"); } + auto prim_restart = key.enable_primitive_restart != 0; + if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) { + LOG_WARNING(Render_Vulkan, + "Primitive restart is enabled for list topology but not supported by driver."); + prim_restart = false; + } const vk::PipelineInputAssemblyStateCreateInfo input_assembly = { .topology = LiverpoolToVK::PrimitiveType(key.prim_type), - .primitiveRestartEnable = key.enable_primitive_restart != 0, + .primitiveRestartEnable = prim_restart, }; - ASSERT_MSG(!key.enable_primitive_restart || key.primitive_restart_index == 0xFFFF || + ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF || key.primitive_restart_index == 0xFFFFFFFF, "Primitive restart index other than -1 is not supported yet"); @@ -387,7 +393,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, for (const auto& buffer : stage->buffers) { const auto vsharp = buffer.GetSharp(*stage); const bool is_storage = buffer.IsStorage(vsharp); - if (vsharp) { + if (vsharp && vsharp.GetSize() > 0) { const VAddr address = vsharp.base_address; if (texture_cache.IsMeta(address)) { LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (buffer)"); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index dda9183a5..753e2f946 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -84,6 +84,16 @@ public: return key.depth_stencil.depth_enable.Value(); } + [[nodiscard]] bool IsPrimitiveListTopology() const { + return key.prim_type == Liverpool::PrimitiveType::PointList || + key.prim_type == Liverpool::PrimitiveType::LineList || + key.prim_type == Liverpool::PrimitiveType::TriangleList || + key.prim_type == Liverpool::PrimitiveType::AdjLineList || + key.prim_type == Liverpool::PrimitiveType::AdjTriangleList || + key.prim_type == Liverpool::PrimitiveType::RectList || + key.prim_type == Liverpool::PrimitiveType::QuadList; + } + private: void BuildDescSetLayout(); diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 2aeb77ec8..022ef16c5 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -260,9 +260,8 @@ bool Instance::CreateDevice() { color_write_en &= add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); const bool calibrated_timestamps = add_extension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME); const bool robustness = add_extension(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); - const bool topology_restart = - add_extension(VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME); - const bool maintenance5 = add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); + list_restart = add_extension(VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME); + maintenance5 = add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); // These extensions are promoted by Vulkan 1.3, but for greater compatibility we use Vulkan 1.2 // with extensions. @@ -415,7 +414,7 @@ bool Instance::CreateDevice() { if (!workgroup_memory_explicit_layout) { device_chain.unlink(); } - if (!topology_restart) { + if (!list_restart) { device_chain.unlink(); } if (robustness) { diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index e6e39ab1f..e019ffba3 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -138,6 +138,15 @@ public: return null_descriptor; } + /// Returns true when VK_KHR_maintenance5 is supported. + bool IsMaintenance5Supported() const { + return maintenance5; + } + + bool IsListRestartSupported() const { + return list_restart; + } + /// Returns the vendor ID of the physical device u32 GetVendorID() const { return properties.vendorID; @@ -280,6 +289,8 @@ private: bool color_write_en{}; bool vertex_input_dynamic_state{}; bool null_descriptor{}; + bool maintenance5{}; + bool list_restart{}; u64 min_imported_host_pointer_alignment{}; u32 subgroup_size{}; bool tooling_info{}; From e68774d449ced60eb70e29c257dad0bc231e0137 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:42:37 -0700 Subject: [PATCH 34/34] shader_recompiler: Define fragment output type based on number format. (#1097) * shader_recompiler: Define fragment output type based on number format. * shader_recompiler: Fix GetAttribute SPIR-V output type. * shader_recompiler: Don't bitcast on SetAttribute unless integer target. --- .../spirv/emit_spirv_context_get_set.cpp | 64 +++++++++++++++---- .../backend/spirv/spirv_emit_context.cpp | 39 ++++++----- .../backend/spirv/spirv_emit_context.h | 7 +- .../frontend/translate/export.cpp | 2 +- src/shader_recompiler/runtime_info.h | 10 ++- .../renderer_vulkan/vk_graphics_pipeline.h | 1 + .../renderer_vulkan/vk_pipeline_cache.cpp | 12 ++-- 7 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 92279c5fb..b6bf1eed6 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -49,12 +49,13 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) { if (info.num_components == 1) { return info.id; } else { - return ctx.OpAccessChain(ctx.output_f32, info.id, ctx.ConstU32(element)); + return ctx.OpAccessChain(info.pointer_type, info.id, ctx.ConstU32(element)); } } switch (attr) { case IR::Attribute::Position0: { return ctx.OpAccessChain(ctx.output_f32, ctx.output_position, ctx.ConstU32(element)); + } case IR::Attribute::Position1: case IR::Attribute::Position2: case IR::Attribute::Position3: { @@ -70,17 +71,47 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) { case IR::Attribute::RenderTarget6: case IR::Attribute::RenderTarget7: { const u32 index = u32(attr) - u32(IR::Attribute::RenderTarget0); - if (ctx.frag_num_comp[index] > 1) { - return ctx.OpAccessChain(ctx.output_f32, ctx.frag_color[index], ctx.ConstU32(element)); + const auto& info{ctx.frag_outputs.at(index)}; + if (info.num_components > 1) { + return ctx.OpAccessChain(info.pointer_type, info.id, ctx.ConstU32(element)); } else { - return ctx.frag_color[index]; + return info.id; } } case IR::Attribute::Depth: return ctx.frag_depth; default: - throw NotImplementedException("Read attribute {}", attr); + throw NotImplementedException("Write attribute {}", attr); } +} + +std::pair OutputAttrComponentType(EmitContext& ctx, IR::Attribute attr) { + if (IR::IsParam(attr)) { + const u32 index{u32(attr) - u32(IR::Attribute::Param0)}; + const auto& info{ctx.output_params.at(index)}; + return {info.component_type, info.is_integer}; + } + switch (attr) { + case IR::Attribute::Position0: + case IR::Attribute::Position1: + case IR::Attribute::Position2: + case IR::Attribute::Position3: + case IR::Attribute::Depth: + return {ctx.F32[1], false}; + case IR::Attribute::RenderTarget0: + case IR::Attribute::RenderTarget1: + case IR::Attribute::RenderTarget2: + case IR::Attribute::RenderTarget3: + case IR::Attribute::RenderTarget4: + case IR::Attribute::RenderTarget5: + case IR::Attribute::RenderTarget6: + case IR::Attribute::RenderTarget7: { + const u32 index = u32(attr) - u32(IR::Attribute::RenderTarget0); + const auto& info{ctx.frag_outputs.at(index)}; + return {info.component_type, info.is_integer}; + } + default: + throw NotImplementedException("Write attribute {}", attr); } } } // Anonymous namespace @@ -156,17 +187,21 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, u32 comp) { // Attribute is disabled or varying component is not written return ctx.ConstF32(comp == 3 ? 1.0f : 0.0f); } - if (param.is_default) { - return ctx.OpCompositeExtract(param.component_type, param.id, comp); - } - if (param.num_components > 1) { + Id result; + if (param.is_default) { + result = ctx.OpCompositeExtract(param.component_type, param.id, comp); + } else if (param.num_components > 1) { const Id pointer{ ctx.OpAccessChain(param.pointer_type, param.id, ctx.ConstU32(comp))}; - return ctx.OpLoad(param.component_type, pointer); + result = ctx.OpLoad(param.component_type, pointer); } else { - return ctx.OpLoad(param.component_type, param.id); + result = ctx.OpLoad(param.component_type, param.id); } + if (param.is_integer) { + result = ctx.OpBitcast(ctx.F32[1], result); + } + return result; } else { const auto step_rate = EmitReadStepRate(ctx, param.id.value); const auto offset = ctx.OpIAdd( @@ -222,7 +257,12 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, u32 elemen return; } const Id pointer{OutputAttrPointer(ctx, attr, element)}; - ctx.OpStore(pointer, ctx.OpBitcast(ctx.F32[1], value)); + const auto component_type{OutputAttrComponentType(ctx, attr)}; + if (component_type.second) { + ctx.OpStore(pointer, ctx.OpBitcast(component_type.first, value)); + } else { + ctx.OpStore(pointer, value); + } } template diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index b66f09664..05b308b05 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -120,6 +120,7 @@ void EmitContext::DefineArithmeticTypes() { output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32"); output_u32 = Name(TypePointer(spv::StorageClass::Output, U32[1]), "output_u32"); + output_s32 = Name(TypePointer(spv::StorageClass::Output, S32[1]), "output_s32"); full_result_i32x2 = Name(TypeStruct(S32[1], S32[1]), "full_result_i32x2"); full_result_u32x2 = Name(TypeStruct(U32[1], U32[1]), "full_result_u32x2"); @@ -151,21 +152,21 @@ const VectorIds& GetAttributeType(EmitContext& ctx, AmdGpu::NumberFormat fmt) { UNREACHABLE_MSG("Invalid attribute type {}", fmt); } -EmitContext::SpirvAttribute EmitContext::GetAttributeInfo(AmdGpu::NumberFormat fmt, Id id) { +EmitContext::SpirvAttribute EmitContext::GetAttributeInfo(AmdGpu::NumberFormat fmt, Id id, + bool output) { switch (fmt) { case AmdGpu::NumberFormat::Float: case AmdGpu::NumberFormat::Unorm: case AmdGpu::NumberFormat::Snorm: case AmdGpu::NumberFormat::SnormNz: - return {id, input_f32, F32[1], 4}; - case AmdGpu::NumberFormat::Uint: - return {id, input_u32, U32[1], 4}; - case AmdGpu::NumberFormat::Sint: - return {id, input_s32, S32[1], 4}; case AmdGpu::NumberFormat::Sscaled: - return {id, input_f32, F32[1], 4}; case AmdGpu::NumberFormat::Uscaled: - return {id, input_f32, F32[1], 4}; + case AmdGpu::NumberFormat::Srgb: + return {id, output ? output_f32 : input_f32, F32[1], 4, false}; + case AmdGpu::NumberFormat::Uint: + return {id, output ? output_u32 : input_u32, U32[1], 4, true}; + case AmdGpu::NumberFormat::Sint: + return {id, output ? output_s32 : input_s32, S32[1], 4, true}; default: break; } @@ -236,9 +237,13 @@ void EmitContext::DefineInputs() { : 1; // Note that we pass index rather than Id input_params[input.binding] = { - rate_idx, input_u32, - U32[1], input.num_components, - false, input.instance_data_buf, + rate_idx, + input_u32, + U32[1], + input.num_components, + true, + false, + input.instance_data_buf, }; } else { Id id{DefineInput(type, input.binding)}; @@ -247,7 +252,7 @@ void EmitContext::DefineInputs() { } else { Name(id, fmt::format("vs_in_attr{}", input.binding)); } - input_params[input.binding] = GetAttributeInfo(input.fmt, id); + input_params[input.binding] = GetAttributeInfo(input.fmt, id, false); interfaces.push_back(id); } } @@ -320,10 +325,12 @@ void EmitContext::DefineOutputs() { continue; } const u32 num_components = info.stores.NumComponents(mrt); - frag_color[i] = DefineOutput(F32[num_components], i); - frag_num_comp[i] = num_components; - Name(frag_color[i], fmt::format("frag_color{}", i)); - interfaces.push_back(frag_color[i]); + const AmdGpu::NumberFormat num_format{runtime_info.fs_info.color_buffers[i].num_format}; + const Id type{GetAttributeType(*this, num_format)[num_components]}; + const Id id = DefineOutput(type, i); + Name(id, fmt::format("frag_color{}", i)); + frag_outputs[i] = GetAttributeInfo(num_format, id, true); + interfaces.push_back(id); } break; default: diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index fb7b29b3e..3dfc8bd61 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -166,6 +166,7 @@ public: Id input_s32{}; Id output_u32{}; Id output_f32{}; + Id output_s32{}; boost::container::small_vector interfaces; @@ -177,8 +178,6 @@ public: Id frag_coord{}; Id front_facing{}; Id frag_depth{}; - std::array frag_color{}; - std::array frag_num_comp{}; Id clip_distances{}; Id cull_distances{}; @@ -237,11 +236,13 @@ public: Id pointer_type; Id component_type; u32 num_components; + bool is_integer{}; bool is_default{}; s32 buffer_handle{-1}; }; std::array input_params{}; std::array output_params{}; + std::array frag_outputs{}; private: void DefineArithmeticTypes(); @@ -254,7 +255,7 @@ private: void DefineImagesAndSamplers(); void DefineSharedMemory(); - SpirvAttribute GetAttributeInfo(AmdGpu::NumberFormat fmt, Id id); + SpirvAttribute GetAttributeInfo(AmdGpu::NumberFormat fmt, Id id, bool output); }; } // namespace Shader::Backend::SPIRV diff --git a/src/shader_recompiler/frontend/translate/export.cpp b/src/shader_recompiler/frontend/translate/export.cpp index 7d901822d..f82f8fc1b 100644 --- a/src/shader_recompiler/frontend/translate/export.cpp +++ b/src/shader_recompiler/frontend/translate/export.cpp @@ -25,7 +25,7 @@ void Translator::EmitExport(const GcnInst& inst) { return comp; } const u32 index = u32(attrib) - u32(IR::Attribute::RenderTarget0); - switch (runtime_info.fs_info.mrt_swizzles[index]) { + switch (runtime_info.fs_info.color_buffers[index].mrt_swizzle) { case MrtSwizzle::Identity: return comp; case MrtSwizzle::Alt: diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 1bb065544..115bbe10d 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -80,10 +80,16 @@ struct FragmentRuntimeInfo { auto operator<=>(const PsInput&) const noexcept = default; }; boost::container::static_vector inputs; - std::array mrt_swizzles; + struct PsColorBuffer { + AmdGpu::NumberFormat num_format; + MrtSwizzle mrt_swizzle; + + auto operator<=>(const PsColorBuffer&) const noexcept = default; + }; + std::array color_buffers; bool operator==(const FragmentRuntimeInfo& other) const noexcept { - return std::ranges::equal(mrt_swizzles, other.mrt_swizzles) && + return std::ranges::equal(color_buffers, other.color_buffers) && std::ranges::equal(inputs, other.inputs); } }; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 753e2f946..ba4996742 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -26,6 +26,7 @@ using Liverpool = AmdGpu::Liverpool; struct GraphicsPipelineKey { std::array stage_hashes; std::array color_formats; + std::array color_num_formats; std::array mrt_swizzles; vk::Format depth_format; vk::Format stencil_format; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 7a66fc0a2..0ccaf3fac 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -95,10 +95,6 @@ Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Shader::Stage stage) { case Shader::Stage::Fragment: { info.num_user_data = regs.ps_program.settings.num_user_regs; info.num_allocated_vgprs = regs.ps_program.settings.num_vgprs * 4; - std::ranges::transform(graphics_key.mrt_swizzles, info.fs_info.mrt_swizzles.begin(), - [](Liverpool::ColorBuffer::SwapMode mode) { - return static_cast(mode); - }); const auto& ps_inputs = regs.ps_inputs; for (u32 i = 0; i < regs.num_interp; i++) { info.fs_info.inputs.push_back({ @@ -108,6 +104,12 @@ Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Shader::Stage stage) { .default_value = u8(ps_inputs[i].default_value), }); } + for (u32 i = 0; i < Shader::MaxColorBuffers; i++) { + info.fs_info.color_buffers[i] = { + .num_format = graphics_key.color_num_formats[i], + .mrt_swizzle = static_cast(graphics_key.mrt_swizzles[i]), + }; + } break; } case Shader::Stage::Compute: { @@ -244,6 +246,7 @@ bool PipelineCache::RefreshGraphicsKey() { // attachments. This might be not a case as HW color buffers can be bound in an arbitrary // order. We need to do some arrays compaction at this stage key.color_formats.fill(vk::Format::eUndefined); + key.color_num_formats.fill(AmdGpu::NumberFormat::Unorm); key.blend_controls.fill({}); key.write_masks.fill({}); key.mrt_swizzles.fill(Liverpool::ColorBuffer::SwapMode::Standard); @@ -261,6 +264,7 @@ bool PipelineCache::RefreshGraphicsKey() { const bool is_vo_surface = renderer->IsVideoOutSurface(col_buf); key.color_formats[remapped_cb] = LiverpoolToVK::AdjustColorBufferFormat( base_format, col_buf.info.comp_swap.Value(), false /*is_vo_surface*/); + key.color_num_formats[remapped_cb] = col_buf.NumFormat(); if (base_format == key.color_formats[remapped_cb]) { key.mrt_swizzles[remapped_cb] = col_buf.info.comp_swap.Value(); }