diff --git a/.github/ISSUE_TEMPLATE/game-bug-report.yaml b/.github/ISSUE_TEMPLATE/game-bug-report.yaml index d9ebd8347..848877037 100644 --- a/.github/ISSUE_TEMPLATE/game-bug-report.yaml +++ b/.github/ISSUE_TEMPLATE/game-bug-report.yaml @@ -17,7 +17,7 @@ body: This repository does not provide support for game patches. If you are having issues with patches please refer to [Cheats and Patches Repository](https://github.com/shadps4-emu/ps4_cheats). - Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-emu/shadps4-game-compatibility) for the information about the status of the game. + Before submitting an issue please check [Game Compatibility Repository](https://github.com/shadps4-compatibility/shadps4-game-compatibility) for the information about the status of the game. Please make an effort to make sure your issue isn't already reported. diff --git a/CMakeLists.txt b/CMakeLists.txt index adff454b8..24a81243f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,7 +126,7 @@ execute_process( # If there's no upstream set or the command failed, check remote.pushDefault if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") - message("check default push") + message(STATUS "check default push") execute_process( COMMAND git config --get remote.pushDefault OUTPUT_VARIABLE GIT_REMOTE_NAME @@ -134,30 +134,30 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) - message("got remote: ${GIT_REMOTE_NAME}") + message(STATUS "got remote: ${GIT_REMOTE_NAME}") endif() # If running in GitHub Actions and the above fails if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") - message("check github") + message(STATUS "check github") set(GIT_REMOTE_NAME "origin") # Retrieve environment variables if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "") - message("github head ref: $ENV{GITHUB_HEAD_REF}") + message(STATUS "github head ref: $ENV{GITHUB_HEAD_REF}") set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}") else() set(GITHUB_HEAD_REF "") endif() if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "") - message("github ref: $ENV{GITHUB_REF}") + message(STATUS "github ref: $ENV{GITHUB_REF}") string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}") string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}") if (MATCHED_REF) set(PR_NUMBER "${CMAKE_MATCH_1}") set(GITHUB_BRANCH "") - message("PR number: ${PR_NUMBER}") + message(STATUS "PR number: ${PR_NUMBER}") else() set(PR_NUMBER "") endif() @@ -179,7 +179,7 @@ if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "") elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "") set(GIT_BRANCH "${GITHUB_REF}") elseif("${GIT_BRANCH}" STREQUAL "") - message("couldn't find branch") + message(STATUS "couldn't find branch") set(GIT_BRANCH "detached-head") endif() else() @@ -188,13 +188,13 @@ else() if (INDEX GREATER -1) string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME) elseif("${GIT_REMOTE_NAME}" STREQUAL "") - message("reset to origin") + message(STATUS "reset to origin") set(GIT_REMOTE_NAME "origin") endif() endif() # Get remote link -message("getting remote link") +message(STATUS "getting remote link") execute_process( COMMAND git config --get remote.${GIT_REMOTE_NAME}.url OUTPUT_VARIABLE GIT_REMOTE_URL @@ -212,7 +212,12 @@ set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_ set(APP_IS_RELEASE false) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY) -message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}") +message("-- end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}, link: ${GIT_REMOTE_URL}") + +if(NOT GIT_REMOTE_URL MATCHES "shadps4-emu/shadPS4" OR NOT GIT_BRANCH STREQUAL "main") + message(STATUS "not main, disabling auto update") + set(ENABLE_UPDATER OFF) +endif() if(WIN32 AND ENABLE_QT_GUI AND NOT CMAKE_PREFIX_PATH) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/DetectQtInstallation.cmake") diff --git a/README.md b/README.md index 22fc27a33..06da2d471 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ SPDX-License-Identifier: GPL-2.0-or-later **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/wiki/I.-Quick-start-%5BUsers%5D).\ -To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility).\ +To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-compatibility/shadps4-game-compatibility).\ To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\ 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)! diff --git a/documents/Debugging/Debugging.md b/documents/Debugging/Debugging.md index ef9aab879..d2eda61b7 100644 --- a/documents/Debugging/Debugging.md +++ b/documents/Debugging/Debugging.md @@ -147,7 +147,7 @@ Accurately identifying games will help other developers that own that game recog - If your issue is small or you aren't sure whether you have properly identified something, [join the Discord server](https://discord.gg/MyZRaBngxA) and use the #development channel to concisely explain the issue, as well as any findings you currently have. -- It is recommended that you check the [game compatibility issue tracker](https://github.com/shadps4-emu/shadps4-game-compatibility/issues) and post very short summaries of progress changes there, +- It is recommended that you check the [game compatibility issue tracker](https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues) and post very short summaries of progress changes there, (such as the game now booting into the menu or getting in-game) for organizational and status update purposes. - ⚠ **Do not post theoretical, unproven game-specific issues in the emulator issue tracker that you cannot verify and locate in the emulator source code as being a bug.**\ diff --git a/src/common/config.cpp b/src/common/config.cpp index 6f8563377..a1b12ee5d 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -32,6 +32,7 @@ std::filesystem::path find_fs_path_or(const basic_value& v, const K& ky, namespace Config { // General +static int volumeSlider = 100; static bool isNeo = false; static bool isDevKit = false; static bool isPSNSignedIn = false; @@ -108,6 +109,9 @@ static std::string trophyKey = ""; // Expected number of items in the config file static constexpr u64 total_entries = 54; +int getVolumeSlider() { + return volumeSlider; +} bool allowHDR() { return isHDRAllowed; } @@ -157,6 +161,10 @@ std::filesystem::path GetSaveDataPath() { return save_data_path; } +void setVolumeSlider(int volumeValue) { + volumeSlider = volumeValue; +} + void setLoadGameSizeEnabled(bool enable) { load_game_size = enable; } @@ -611,6 +619,7 @@ void load(const std::filesystem::path& path) { if (data.contains("General")) { const toml::value& general = data.at("General"); + volumeSlider = toml::find_or(general, "volumeSlider", volumeSlider); isNeo = toml::find_or(general, "isPS4Pro", isNeo); isDevKit = toml::find_or(general, "isDevKit", isDevKit); isPSNSignedIn = toml::find_or(general, "isPSNSignedIn", isPSNSignedIn); @@ -806,6 +815,7 @@ void save(const std::filesystem::path& path) { fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string())); } + data["General"]["volumeSlider"] = volumeSlider; data["General"]["isPS4Pro"] = isNeo; data["General"]["isDevKit"] = isDevKit; data["General"]["isPSNSignedIn"] = isPSNSignedIn; @@ -901,6 +911,7 @@ void save(const std::filesystem::path& path) { void setDefaultValues() { // General + volumeSlider = 100; isNeo = false; isDevKit = false; isPSNSignedIn = false; diff --git a/src/common/config.h b/src/common/config.h index e54425676..4ace4d316 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -19,6 +19,8 @@ enum HideCursorState : int { Never, Idle, Always }; void load(const std::filesystem::path& path); void save(const std::filesystem::path& path); +int getVolumeSlider(); +void setVolumeSlider(int volumeValue); std::string getTrophyKey(); void setTrophyKey(std::string key); bool getIsFullscreen(); diff --git a/src/core/libraries/audio/audioout.cpp b/src/core/libraries/audio/audioout.cpp index 421289a9d..2ec44e80f 100644 --- a/src/core/libraries/audio/audioout.cpp +++ b/src/core/libraries/audio/audioout.cpp @@ -523,9 +523,24 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) { } port.impl->SetVolume(port.volume); } + AdjustVol(); return ORBIS_OK; } +void AdjustVol() { + if (audio == nullptr) { + return; + } + + for (int i = 0; i < ports_out.size(); i++) { + std::unique_lock lock{ports_out[i].mutex}; + if (!ports_out[i].IsOpen()) { + continue; + } + ports_out[i].impl->SetVolume(ports_out[i].volume); + } +} + int PS4_SYSV_ABI sceAudioOutSetVolumeDown() { LOG_ERROR(Lib_AudioOut, "(STUBBED) called"); return ORBIS_OK; diff --git a/src/core/libraries/audio/audioout.h b/src/core/libraries/audio/audioout.h index 4f799665e..5247561ee 100644 --- a/src/core/libraries/audio/audioout.h +++ b/src/core/libraries/audio/audioout.h @@ -181,5 +181,6 @@ int PS4_SYSV_ABI sceAudioOutSystemControlSet(); int PS4_SYSV_ABI sceAudioOutSparkControlSetEqCoef(); int PS4_SYSV_ABI sceAudioOutSetSystemDebugState(); +void AdjustVol(); void RegisterLib(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::AudioOut diff --git a/src/core/libraries/audio/sdl_audio.cpp b/src/core/libraries/audio/sdl_audio.cpp index 9aee2b447..94d624b0c 100644 --- a/src/core/libraries/audio/sdl_audio.cpp +++ b/src/core/libraries/audio/sdl_audio.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "common/logging/log.h" #include "core/libraries/audio/audioout.h" @@ -41,6 +42,7 @@ public: stream = nullptr; return; } + SDL_SetAudioStreamGain(stream, Config::getVolumeSlider() / 100.0f); } ~SDLPortBackend() override { @@ -77,7 +79,8 @@ public: } // SDL does not have per-channel volumes, for now just take the maximum of the channels. const auto vol = *std::ranges::max_element(ch_volumes); - if (!SDL_SetAudioStreamGain(stream, static_cast(vol) / SCE_AUDIO_OUT_VOLUME_0DB)) { + if (!SDL_SetAudioStreamGain(stream, static_cast(vol) / SCE_AUDIO_OUT_VOLUME_0DB * + Config::getVolumeSlider() / 100.0f)) { LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}", SDL_GetError()); } diff --git a/src/core/libraries/ime/ime.cpp b/src/core/libraries/ime/ime.cpp index 2c494f59a..ea723bb7d 100644 --- a/src/core/libraries/ime/ime.cpp +++ b/src/core/libraries/ime/ime.cpp @@ -230,7 +230,7 @@ int PS4_SYSV_ABI sceImeGetPanelPositionAndForm() { } Error PS4_SYSV_ABI sceImeGetPanelSize(const OrbisImeParam* param, u32* width, u32* height) { - LOG_INFO(Lib_Ime, "called"); + LOG_INFO(Lib_Ime, "sceImeGetPanelSize called"); if (!param) { LOG_ERROR(Lib_Ime, "param is NULL"); @@ -311,7 +311,6 @@ int PS4_SYSV_ABI sceImeKeyboardGetResourceId() { Error PS4_SYSV_ABI sceImeKeyboardOpen(Libraries::UserService::OrbisUserServiceUserId userId, const OrbisImeKeyboardParam* param) { LOG_INFO(Lib_Ime, "called"); - LOG_INFO(Lib_Ime, "kValidImeDialogExtOptionMask={:032b}", kValidImeDialogExtOptionMask); if (!param) { @@ -453,7 +452,7 @@ Error PS4_SYSV_ABI sceImeOpen(const OrbisImeParam* param, const OrbisImeParamExt } if (static_cast(param->option) & ~kValidImeOptionMask) { - LOG_ERROR(Lib_Ime, "option has invalid bits set (0x{:X}), mask=(0x{:X})", + LOG_ERROR(Lib_Ime, "option has invalid bits set (0x{:X}), mask=({:032b})", static_cast(param->option), kValidImeOptionMask); return Error::INVALID_OPTION; } @@ -533,7 +532,7 @@ int PS4_SYSV_ABI sceImeOpenInternal() { } void PS4_SYSV_ABI sceImeParamInit(OrbisImeParam* param) { - LOG_INFO(Lib_Ime, "called"); + LOG_INFO(Lib_Ime, "sceImeParamInit called"); if (!param) { return; diff --git a/src/qt_gui/compatibility_info.cpp b/src/qt_gui/compatibility_info.cpp index da32f24ae..eecd1bd47 100644 --- a/src/qt_gui/compatibility_info.cpp +++ b/src/qt_gui/compatibility_info.cpp @@ -22,8 +22,8 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent, bool f if (!forced && LoadCompatibilityFile()) return; - QUrl url("https://github.com/shadps4-emu/shadps4-game-compatibility/releases/latest/download/" - "compatibility_data.json"); + QUrl url("https://github.com/shadps4-compatibility/shadps4-game-compatibility/releases/latest/" + "download/compatibility_data.json"); QNetworkRequest request(url); QNetworkReply* reply = m_network_manager->get(request); diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp index e4c40b4f9..e0995d3ef 100644 --- a/src/qt_gui/game_list_frame.cpp +++ b/src/qt_gui/game_list_frame.cpp @@ -91,7 +91,8 @@ GameListFrame::GameListFrame(std::shared_ptr gui_settings, connect(this, &QTableWidget::cellClicked, this, [=, this](int row, int column) { if (column == 2 && m_game_info->m_games[row].compatibility.issue_number != "") { - auto url_issues = "https://github.com/shadps4-emu/shadps4-game-compatibility/issues/"; + auto url_issues = + "https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues/"; QDesktopServices::openUrl( QUrl(url_issues + m_game_info->m_games[row].compatibility.issue_number)); } else if (column == 10) { diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 6c384c4bc..110421002 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -581,7 +581,7 @@ public: if (selected == viewCompatibilityReport) { if (m_games[itemID].compatibility.issue_number != "") { auto url_issues = - "https://github.com/shadps4-emu/shadps4-game-compatibility/issues/"; + "https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues/"; QDesktopServices::openUrl( QUrl(url_issues + m_games[itemID].compatibility.issue_number)); } @@ -589,8 +589,8 @@ public: if (selected == submitCompatibilityReport) { if (m_games[itemID].compatibility.issue_number == "") { - QUrl url = - QUrl("https://github.com/shadps4-emu/shadps4-game-compatibility/issues/new"); + QUrl url = QUrl("https://github.com/shadps4-compatibility/" + "shadps4-game-compatibility/issues/new"); QUrlQuery query; query.addQueryItem("template", QString("game_compatibility.yml")); query.addQueryItem( @@ -605,7 +605,7 @@ public: QDesktopServices::openUrl(url); } else { auto url_issues = - "https://github.com/shadps4-emu/shadps4-game-compatibility/issues/"; + "https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues/"; QDesktopServices::openUrl( QUrl(url_issues + m_games[itemID].compatibility.issue_number)); } diff --git a/src/qt_gui/gui_settings.h b/src/qt_gui/gui_settings.h index 4c1eafc95..4d2a1b7f7 100644 --- a/src/qt_gui/gui_settings.h +++ b/src/qt_gui/gui_settings.h @@ -37,6 +37,7 @@ const gui_value gl_showBackgroundImage = gui_value(game_list, "showBackgroundIma const gui_value gl_backgroundImageOpacity = gui_value(game_list, "backgroundImageOpacity", 50); const gui_value gl_playBackgroundMusic = gui_value(game_list, "playBackgroundMusic", true); const gui_value gl_backgroundMusicVolume = gui_value(game_list, "backgroundMusicVolume", 50); +const gui_value gl_VolumeSlider = gui_value(game_list, "volumeSlider", 100); // game grid settings const gui_value gg_icon_size = gui_value(game_grid, "icon_size", 69); diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index f903562f9..b08bb5aee 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -11,6 +11,7 @@ #include "common/config.h" #include "common/scm_rev.h" +#include "core/libraries/audio/audioout.h" #include "qt_gui/compatibility_info.h" #ifdef ENABLE_DISCORD_RPC #include "common/discord_rpc_handler.h" @@ -68,6 +69,7 @@ QMap chooseHomeTabMap; int backgroundImageOpacitySlider_backup; int bgm_volume_backup; +int volume_slider_backup; static std::vector m_physical_devices; @@ -149,9 +151,11 @@ SettingsDialog::SettingsDialog(std::shared_ptr gui_settings, } else if (button == ui->buttonBox->button(QDialogButtonBox::Close)) { ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup); emit BackgroundOpacityChanged(backgroundImageOpacitySlider_backup); + ui->horizontalVolumeSlider->setValue(volume_slider_backup); + Config::setVolumeSlider(volume_slider_backup); ui->BGMVolumeSlider->setValue(bgm_volume_backup); BackgroundMusicPlayer::getInstance().setVolume(bgm_volume_backup); - ResetInstallFolders(); + SyncRealTimeWidgetstoConfig(); } if (Common::Log::IsActive()) { Common::Log::Filter filter; @@ -170,6 +174,12 @@ SettingsDialog::SettingsDialog(std::shared_ptr gui_settings, // GENERAL TAB { + connect(ui->horizontalVolumeSlider, &QSlider::valueChanged, this, [this](int value) { + VolumeSliderChange(value); + Config::setVolumeSlider(value); + Libraries::AudioOut::AdjustVol(); + }); + #ifdef ENABLE_UPDATER #if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0)) connect(ui->updateCheckBox, &QCheckBox::stateChanged, this, [this](int state) { @@ -398,6 +408,8 @@ void SettingsDialog::closeEvent(QCloseEvent* event) { if (!is_saving) { ui->backgroundImageOpacitySlider->setValue(backgroundImageOpacitySlider_backup); emit BackgroundOpacityChanged(backgroundImageOpacitySlider_backup); + ui->horizontalVolumeSlider->setValue(volume_slider_backup); + Config::setVolumeSlider(volume_slider_backup); ui->BGMVolumeSlider->setValue(bgm_volume_backup); BackgroundMusicPlayer::getInstance().setVolume(bgm_volume_backup); } @@ -463,6 +475,8 @@ void SettingsDialog::LoadValuesFromConfig() { ui->radioButton_Bottom->setChecked(side == "bottom"); ui->BGMVolumeSlider->setValue(m_gui_settings->GetValue(gui::gl_backgroundMusicVolume).toInt()); + ui->horizontalVolumeSlider->setValue(m_gui_settings->GetValue(gui::gl_VolumeSlider).toInt()); + ui->volumeText->setText(QString::number(ui->horizontalVolumeSlider->sliderPosition()) + "%"); ui->discordRPCCheckbox->setChecked( toml::find_or(data, "General", "enableDiscordRPC", true)); QString translatedText_FullscreenMode = @@ -532,7 +546,7 @@ void SettingsDialog::LoadValuesFromConfig() { toml::find_or(data, "Input", "isMotionControlsEnabled", true)); ui->removeFolderButton->setEnabled(!ui->gameFoldersListWidget->selectedItems().isEmpty()); - ResetInstallFolders(); + SyncRealTimeWidgetstoConfig(); ui->backgroundImageOpacitySlider->setValue( m_gui_settings->GetValue(gui::gl_backgroundImageOpacity).toInt()); ui->showBackgroundImageCheckBox->setChecked( @@ -541,6 +555,7 @@ void SettingsDialog::LoadValuesFromConfig() { backgroundImageOpacitySlider_backup = m_gui_settings->GetValue(gui::gl_backgroundImageOpacity).toInt(); bgm_volume_backup = m_gui_settings->GetValue(gui::gl_backgroundMusicVolume).toInt(); + volume_slider_backup = m_gui_settings->GetValue(gui::gl_VolumeSlider).toInt(); } void SettingsDialog::InitializeEmulatorLanguages() { @@ -599,6 +614,10 @@ void SettingsDialog::OnCursorStateChanged(s16 index) { } } +void SettingsDialog::VolumeSliderChange(int value) { + ui->volumeText->setText(QString::number(ui->horizontalVolumeSlider->sliderPosition()) + "%"); +} + int SettingsDialog::exec() { return QDialog::exec(); } @@ -719,7 +738,6 @@ bool SettingsDialog::eventFilter(QObject* obj, QEvent* event) { if (qobject_cast(obj)) { bool hovered = (event->type() == QEvent::Enter); QString elementName = obj->objectName(); - if (hovered) { updateNoteTextEdit(elementName); } else { @@ -759,6 +777,7 @@ void SettingsDialog::UpdateSettings() { Config::setCursorState(ui->hideCursorComboBox->currentIndex()); Config::setCursorHideTimeout(ui->idleTimeoutSpinBox->value()); Config::setGpuId(ui->graphicsAdapterBox->currentIndex() - 1); + m_gui_settings->SetValue(gui::gl_VolumeSlider, ui->horizontalVolumeSlider->value()); m_gui_settings->SetValue(gui::gl_backgroundMusicVolume, ui->BGMVolumeSlider->value()); Config::setLanguage(languageIndexes[ui->consoleLanguageComboBox->currentIndex()]); Config::setEnableDiscordRPC(ui->discordRPCCheckbox->isChecked()); @@ -815,9 +834,10 @@ void SettingsDialog::UpdateSettings() { #endif BackgroundMusicPlayer::getInstance().setVolume(ui->BGMVolumeSlider->value()); + Config::setVolumeSlider(ui->horizontalVolumeSlider->value()); } -void SettingsDialog::ResetInstallFolders() { +void SettingsDialog::SyncRealTimeWidgetstoConfig() { ui->gameFoldersListWidget->clear(); std::filesystem::path userdir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); @@ -865,6 +885,7 @@ void SettingsDialog::setDefaultValues() { m_gui_settings->SetValue(gui::gl_backgroundImageOpacity, 50); m_gui_settings->SetValue(gui::gl_playBackgroundMusic, false); m_gui_settings->SetValue(gui::gl_backgroundMusicVolume, 50); + m_gui_settings->SetValue(gui::gl_VolumeSlider, 100); m_gui_settings->SetValue(gui::gen_checkForUpdates, false); m_gui_settings->SetValue(gui::gen_showChangeLog, false); if (Common::g_is_release) { @@ -873,4 +894,4 @@ void SettingsDialog::setDefaultValues() { m_gui_settings->SetValue(gui::gen_updateChannel, "Nightly"); } m_gui_settings->SetValue(gui::gen_guiLanguage, "en_US"); -} \ No newline at end of file +} diff --git a/src/qt_gui/settings_dialog.h b/src/qt_gui/settings_dialog.h index d9fbcb214..13fab36a2 100644 --- a/src/qt_gui/settings_dialog.h +++ b/src/qt_gui/settings_dialog.h @@ -39,12 +39,13 @@ signals: private: void LoadValuesFromConfig(); void UpdateSettings(); - void ResetInstallFolders(); + void SyncRealTimeWidgetstoConfig(); void InitializeEmulatorLanguages(); void OnLanguageChanged(int index); void OnCursorStateChanged(s16 index); void closeEvent(QCloseEvent* event) override; void setDefaultValues(); + void VolumeSliderChange(int value); std::unique_ptr ui; diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui index 8d239b58c..9ebb1cbc1 100644 --- a/src/qt_gui/settings_dialog.ui +++ b/src/qt_gui/settings_dialog.ui @@ -59,7 +59,7 @@ - 5 + 0 @@ -73,8 +73,8 @@ 0 0 - 946 - 536 + 944 + 537 @@ -86,148 +86,7 @@ 6 - - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Emulator - - - false - - - false - - - - 6 - - - 9 - - - 9 - - - 9 - - - 9 - - - - - 10 - - - - - Show Splash - - - - - - - Enable Discord Rich Presence - - - - - - - - - - - - - - 6 - - - 0 - - - - - - 0 - 0 - - - - - 0 - 0 - - - - System - - - - 70 - - - - - Console Language - - - - - - - - - - - - Emulator Language - - - - - - - - - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - + Qt::Orientation::Vertical @@ -240,8 +99,8 @@ - - + + Qt::Orientation::Vertical @@ -253,7 +112,7 @@ - + 6 @@ -427,6 +286,228 @@ + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + System + + + + 70 + + + + + Console Language + + + + + + + + + + + + Emulator Language + + + + + + + + + + + + + + + + + Volume + + + + + + + 0 + 0 + + + + + + + true + + + + + 0 + 0 + 414 + 69 + + + + + + + + 0 + 0 + + + + + 60 + 16777215 + + + + 100% + + + Qt::AlignmentFlag::AlignCenter + + + true + + + + + + + Qt::FocusPolicy::StrongFocus + + + 500 + + + 100 + + + 100 + + + Qt::Orientation::Horizontal + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Emulator + + + false + + + false + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + 10 + + + + + Show Splash + + + + + + + Enable Discord Rich Presence + + + + + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + @@ -444,8 +525,8 @@ 0 0 - 946 - 536 + 944 + 537 @@ -700,7 +781,7 @@ - + 0 0 @@ -893,8 +974,8 @@ 0 0 - 946 - 536 + 944 + 537 @@ -1188,8 +1269,8 @@ 0 0 - 946 - 536 + 944 + 537 @@ -1430,8 +1511,8 @@ 0 0 - 946 - 536 + 944 + 537 @@ -1684,8 +1765,8 @@ 0 0 - 946 - 536 + 944 + 537 @@ -1826,8 +1907,8 @@ 0 0 - 946 - 536 + 944 + 537 diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index 80c8b836b..fe2d64d2f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp @@ -268,6 +268,7 @@ Id EmitBufferAtomicFMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre const auto sign_bit_set = ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u)); + // FIXME this needs control flow because it currently executes both atomics const auto result = ctx.OpSelect( ctx.F32[1], sign_bit_set, EmitBitCastF32U32(ctx, EmitBufferAtomicUMax32(ctx, inst, handle, address, u32_value)), @@ -302,6 +303,7 @@ Id EmitBufferAtomicFMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre const auto sign_bit_set = ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u)); + // FIXME this needs control flow because it currently executes both atomics const auto result = ctx.OpSelect( ctx.F32[1], sign_bit_set, EmitBitCastF32U32(ctx, EmitBufferAtomicUMin32(ctx, inst, handle, address, u32_value)), diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp index c75f43393..2f4984f57 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp @@ -7,60 +7,32 @@ namespace Shader::Backend::SPIRV { namespace { Id ExtractU16(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpUConvert(ctx.U16, value); - } else { - return ctx.OpBitFieldUExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(16u)); - } + return ctx.OpUConvert(ctx.U16, value); } Id ExtractS16(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpSConvert(ctx.S16, value); - } else { - return ctx.OpBitFieldSExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(16u)); - } + return ctx.OpSConvert(ctx.S16, value); } Id ExtractU8(EmitContext& ctx, Id value) { - if (ctx.profile.support_int8) { - return ctx.OpUConvert(ctx.U8, value); - } else { - return ctx.OpBitFieldUExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(8u)); - } + return ctx.OpUConvert(ctx.U8, value); } Id ExtractS8(EmitContext& ctx, Id value) { - if (ctx.profile.support_int8) { - return ctx.OpSConvert(ctx.S8, value); - } else { - return ctx.OpBitFieldSExtract(ctx.U32[1], value, ctx.u32_zero_value, ctx.ConstU32(8u)); - } + return ctx.OpSConvert(ctx.S8, value); } } // Anonymous namespace Id EmitConvertS16F16(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); - } else { - return ExtractS16(ctx, ctx.OpConvertFToS(ctx.U32[1], value)); - } + return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); } Id EmitConvertS16F32(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); - } else { - return ExtractS16(ctx, ctx.OpConvertFToS(ctx.U32[1], value)); - } + return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); } Id EmitConvertS16F64(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); - } else { - return ExtractS16(ctx, ctx.OpConvertFToS(ctx.U32[1], value)); - } + return ctx.OpSConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value)); } Id EmitConvertS32F16(EmitContext& ctx, Id value) { @@ -88,27 +60,15 @@ Id EmitConvertS64F64(EmitContext& ctx, Id value) { } Id EmitConvertU16F16(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); - } else { - return ExtractU16(ctx, ctx.OpConvertFToU(ctx.U32[1], value)); - } + return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); } Id EmitConvertU16F32(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); - } else { - return ExtractU16(ctx, ctx.OpConvertFToU(ctx.U32[1], value)); - } + return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); } Id EmitConvertU16F64(EmitContext& ctx, Id value) { - if (ctx.profile.support_int16) { - return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); - } else { - return ExtractU16(ctx, ctx.OpConvertFToU(ctx.U32[1], value)); - } + return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value)); } Id EmitConvertU32F16(EmitContext& ctx, Id value) { @@ -271,4 +231,12 @@ Id EmitConvertU32U8(EmitContext& ctx, Id value) { return ctx.OpUConvert(ctx.U32[1], value); } +Id EmitConvertS32S8(EmitContext& ctx, Id value) { + return ctx.OpSConvert(ctx.U32[1], value); +} + +Id EmitConvertS32S16(EmitContext& ctx, Id value) { + return ctx.OpSConvert(ctx.U32[1], value); +} + } // namespace Shader::Backend::SPIRV diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 37d5d84c9..a8c58bdba 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -488,6 +488,8 @@ Id EmitConvertU16U32(EmitContext& ctx, Id value); Id EmitConvertU32U16(EmitContext& ctx, Id value); Id EmitConvertU8U32(EmitContext& ctx, Id value); Id EmitConvertU32U8(EmitContext& ctx, Id value); +Id EmitConvertS32S8(EmitContext& ctx, Id value); +Id EmitConvertS32S16(EmitContext& ctx, Id value); Id EmitImageSampleRaw(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address1, Id address2, Id address3, Id address4); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index f373808d9..a8ffe6ae5 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -117,7 +117,9 @@ void EmitContext::DefineArithmeticTypes() { void_id = Name(TypeVoid(), "void_id"); U1[1] = Name(TypeBool(), "bool_id"); U8 = Name(TypeUInt(8), "u8_id"); + S8 = Name(TypeSInt(8), "i8_id"); U16 = Name(TypeUInt(16), "u16_id"); + S16 = Name(TypeSInt(16), "i16_id"); if (info.uses_fp16) { F16[1] = Name(TypeFloat(16), "f16_id"); U16 = Name(TypeUInt(16), "u16_id"); diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index a29bdc993..ae904b822 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -281,9 +281,10 @@ public: // Buffer Memory // MUBUF / MTBUF - void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst); - void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, - const GcnInst& inst); + void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst, + u32 scalar_width = 32, bool is_signed = false); + void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst, + u32 scalar_width = 32); template void BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst); diff --git a/src/shader_recompiler/frontend/translate/vector_memory.cpp b/src/shader_recompiler/frontend/translate/vector_memory.cpp index df20f7f73..ec9bc200d 100644 --- a/src/shader_recompiler/frontend/translate/vector_memory.cpp +++ b/src/shader_recompiler/frontend/translate/vector_memory.cpp @@ -28,6 +28,15 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { case Opcode::BUFFER_LOAD_FORMAT_XYZW: return BUFFER_LOAD(4, false, true, inst); + case Opcode::BUFFER_LOAD_UBYTE: + return BUFFER_LOAD(1, false, false, inst, 8, false); + case Opcode::BUFFER_LOAD_SBYTE: + return BUFFER_LOAD(1, false, false, inst, 8, true); + case Opcode::BUFFER_LOAD_USHORT: + return BUFFER_LOAD(1, false, false, inst, 16, false); + case Opcode::BUFFER_LOAD_SSHORT: + return BUFFER_LOAD(1, false, false, inst, 16, true); + case Opcode::BUFFER_LOAD_DWORD: return BUFFER_LOAD(1, false, false, inst); case Opcode::BUFFER_LOAD_DWORDX2: @@ -56,6 +65,11 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { case Opcode::TBUFFER_STORE_FORMAT_XYZW: return BUFFER_STORE(4, true, false, inst); + case Opcode::BUFFER_STORE_BYTE: + return BUFFER_STORE(1, false, false, inst, 8); + case Opcode::BUFFER_STORE_SHORT: + return BUFFER_STORE(1, false, false, inst, 16); + case Opcode::BUFFER_STORE_DWORD: return BUFFER_STORE(1, false, false, inst); case Opcode::BUFFER_STORE_DWORDX2: @@ -186,7 +200,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { } void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, - const GcnInst& inst) { + const GcnInst& inst, u32 scalar_width, bool is_signed) { const auto& mubuf = inst.control.mubuf; const bool is_ring = mubuf.glc && mubuf.slc; const IR::VectorReg vaddr{inst.src[0].code}; @@ -242,7 +256,26 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_ ir.SetVectorReg(dst_reg + i, IR::F32{ir.CompositeExtract(value, i)}); } } else { - const IR::Value value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info); + IR::Value value; + switch (scalar_width) { + case 8: { + IR::U8 byte_val = ir.LoadBufferU8(handle, address, buffer_info); + value = is_signed ? ir.SConvert(32, byte_val) : ir.UConvert(32, byte_val); + break; + } + case 16: { + IR::U16 short_val = ir.LoadBufferU16(handle, address, buffer_info); + value = is_signed ? ir.SConvert(32, short_val) : ir.UConvert(32, short_val); + break; + } + case 32: + value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info); + break; + + default: + UNREACHABLE(); + } + if (num_dwords == 1) { ir.SetVectorReg(dst_reg, IR::U32{value}); return; @@ -254,7 +287,7 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_ } void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, - const GcnInst& inst) { + const GcnInst& inst, u32 scalar_width) { const auto& mubuf = inst.control.mubuf; const bool is_ring = mubuf.glc && mubuf.slc; const IR::VectorReg vaddr{inst.src[0].code}; @@ -314,8 +347,23 @@ void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer } ir.StoreBufferFormat(handle, address, ir.CompositeConstruct(comps), buffer_info); } else { - const auto value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps); - ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info); + IR::Value value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps); + if (scalar_width != 32) { + value = ir.UConvert(scalar_width, IR::U32{value}); + } + switch (scalar_width) { + case 8: + ir.StoreBufferU8(handle, address, IR::U8{value}, buffer_info); + break; + case 16: + ir.StoreBufferU16(handle, address, IR::U16{value}, buffer_info); + break; + case 32: + ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info); + break; + default: + UNREACHABLE(); + } } } diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 6ca86b2c0..a6d43d102 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -1979,6 +1979,24 @@ U8U16U32U64 IREmitter::UConvert(size_t result_bitsize, const U8U16U32U64& value) throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize); } +U8U16U32U64 IR::IREmitter::SConvert(size_t result_bitsize, const U8U16U32U64& value) { + switch (result_bitsize) { + case 32: + switch (value.Type()) { + case Type::U8: + return Inst(Opcode::ConvertS32S8, value); + case Type::U16: + return Inst(Opcode::ConvertS32S16, value); + default: + break; + } + default: + break; + } + throw NotImplementedException("Signed Conversion from {} to {} bits", value.Type(), + result_bitsize); +} + F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) { switch (result_bitsize) { case 16: diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index a105b042d..e4afb8739 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -325,6 +325,7 @@ public: const Value& value); [[nodiscard]] U8U16U32U64 UConvert(size_t result_bitsize, const U8U16U32U64& value); + [[nodiscard]] U8U16U32U64 SConvert(size_t result_bitsize, const U8U16U32U64& value); [[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value); [[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords, diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 747a27e35..280cd47ec 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -432,6 +432,8 @@ OPCODE(ConvertU16U32, U16, U32, OPCODE(ConvertU32U16, U32, U16, ) OPCODE(ConvertU8U32, U8, U32, ) OPCODE(ConvertU32U8, U32, U8, ) +OPCODE(ConvertS32S8, U32, U8, ) +OPCODE(ConvertS32S16, U32, U16, ) // Image operations OPCODE(ImageSampleRaw, F32x4, Opaque, F32x4, F32x4, F32x4, F32, Opaque, ) diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 6cede44a8..61954bec2 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -171,6 +171,7 @@ enum class MrtSwizzle : u8 { static constexpr u32 MaxColorBuffers = 8; struct PsColorBuffer { + AmdGpu::DataFormat data_format : 6; AmdGpu::NumberFormat num_format : 4; AmdGpu::NumberConversion num_conversion : 3; AmdGpu::Liverpool::ShaderExportFormat export_format : 4; diff --git a/src/video_core/amdgpu/pixel_format.h b/src/video_core/amdgpu/pixel_format.h index bd0f778f4..45c688e57 100644 --- a/src/video_core/amdgpu/pixel_format.h +++ b/src/video_core/amdgpu/pixel_format.h @@ -248,6 +248,15 @@ constexpr CompMapping RemapSwizzle(const DataFormat format, const CompMapping sw result.a = swizzle.r; return result; } + case DataFormat::Format5_6_5: { + // Remap to a more supported component order. + CompMapping result; + result.r = swizzle.b; + result.g = swizzle.g; + result.b = swizzle.r; + result.a = swizzle.a; + return result; + } default: return swizzle; } diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index 42e3c61a5..c5e5d18f8 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -961,15 +961,15 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr, const u32 height = std::max(image.info.size.height >> m, 1u); const u32 depth = image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u; - const auto& [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m]; + const auto [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m]; offset += mip_ofs; if (offset + mip_size > max_offset) { break; } copies.push_back({ .bufferOffset = offset, - .bufferRowLength = static_cast(mip_pitch), - .bufferImageHeight = static_cast(mip_height), + .bufferRowLength = mip_pitch, + .bufferImageHeight = mip_height, .imageSubresource{ .aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .mipLevel = m, diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp index cd597e16c..51411be7f 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp @@ -671,7 +671,7 @@ std::span SurfaceFormats() { vk::Format::eR32G32B32A32Sfloat), // 5_6_5 CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format5_6_5, AmdGpu::NumberFormat::Unorm, - vk::Format::eB5G6R5UnormPack16), + vk::Format::eR5G6B5UnormPack16), // 1_5_5_5 CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format1_5_5_5, AmdGpu::NumberFormat::Unorm, vk::Format::eA1R5G5B5UnormPack16), diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 4d89c83b2..8094bc260 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -244,9 +244,24 @@ GraphicsPipeline::GraphicsPipeline( const auto depth_format = instance.GetSupportedFormat(LiverpoolToVK::DepthFormat(key.z_format, key.stencil_format), vk::FormatFeatureFlagBits2::eDepthStencilAttachment); + std::array color_formats; + for (s32 i = 0; i < key.num_color_attachments; ++i) { + const auto& col_buf = key.color_buffers[i]; + const auto format = LiverpoolToVK::SurfaceFormat(col_buf.data_format, col_buf.num_format); + const auto color_format = + instance.GetSupportedFormat(format, vk::FormatFeatureFlagBits2::eColorAttachment); + if (!instance.IsFormatSupported(color_format, + vk::FormatFeatureFlagBits2::eColorAttachment)) { + LOG_WARNING(Render_Vulkan, + "color buffer format {} does not support COLOR_ATTACHMENT_BIT", + vk::to_string(color_format)); + } + color_formats[i] = color_format; + } + const vk::PipelineRenderingCreateInfo pipeline_rendering_ci = { .colorAttachmentCount = key.num_color_attachments, - .pColorAttachmentFormats = key.color_formats.data(), + .pColorAttachmentFormats = color_formats.data(), .depthAttachmentFormat = key.z_format != Liverpool::DepthBuffer::ZFormat::Invalid ? depth_format : vk::Format::eUndefined, diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 75b8c8c73..aaf47ba7d 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -36,7 +36,6 @@ struct GraphicsPipelineKey { std::array vertex_buffer_formats; u32 patch_control_points; u32 num_color_attachments; - std::array color_formats; std::array color_buffers; std::array blend_controls; std::array write_masks; diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 119c0a367..6e5351ddd 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -669,6 +669,12 @@ vk::Format Instance::GetSupportedFormat(const vk::Format format, if (IsFormatSupported(vk::Format::eD32SfloatS8Uint, flags)) { return vk::Format::eD32SfloatS8Uint; } + break; + case vk::Format::eR8Srgb: + if (IsFormatSupported(vk::Format::eR8Unorm, flags)) { + return vk::Format::eR8Unorm; + } + break; default: break; } diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 9be2d9520..b21e00a71 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -94,6 +94,21 @@ public: return features.shaderFloat64; } + /// Returns true if 64-bit ints are supported in shaders + bool IsShaderInt64Supported() const { + return features.shaderInt64; + } + + /// Returns true if 16-bit ints are supported in shaders + bool IsShaderInt16Supported() const { + return features.shaderInt16; + } + + /// Returns true if 8-bit ints are supported in shaders + bool IsShaderInt8Supported() const { + return vk12_features.shaderInt8; + } + /// Returns true when VK_EXT_custom_border_color is supported bool IsCustomBorderColorSupported() const { return custom_border_color; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 4de8fd73b..bce16cbff 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -203,6 +203,9 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, profile = Shader::Profile{ .supported_spirv = SpirvVersion1_6, .subgroup_size = instance.SubgroupSize(), + .support_int8 = instance.IsShaderInt8Supported(), + .support_int16 = instance.IsShaderInt16Supported(), + .support_int64 = instance.IsShaderInt64Supported(), .support_float64 = instance.IsShaderFloat64Supported(), .support_fp32_denorm_preserve = bool(vk12_props.shaderDenormPreserveFloat32), .support_fp32_denorm_flush = bool(vk12_props.shaderDenormFlushToZeroFloat32), @@ -312,7 +315,6 @@ 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.num_color_attachments = 0; - key.color_formats.fill(vk::Format::eUndefined); key.color_buffers.fill({}); key.blend_controls.fill({}); key.write_masks.fill({}); @@ -348,16 +350,8 @@ bool PipelineCache::RefreshGraphicsKey() { col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8 || col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8_8_8); - const auto format = - LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt()); - key.color_formats[remapped_cb] = format; - if (!instance.IsFormatSupported(format, vk::FormatFeatureFlagBits2::eColorAttachment)) { - LOG_WARNING(Render_Vulkan, - "color buffer format {} does not support COLOR_ATTACHMENT_BIT", - vk::to_string(format)); - } - key.color_buffers[remapped_cb] = Shader::PsColorBuffer{ + .data_format = col_buf.GetDataFmt(), .num_format = col_buf.GetNumberFmt(), .num_conversion = col_buf.GetNumberConversion(), .export_format = regs.color_export_format.GetFormat(cb), @@ -476,9 +470,7 @@ bool PipelineCache::RefreshGraphicsKey() { // Attachment is masked out by either color_target_mask or shader mrt_mask. In the case // of the latter we need to change format to undefined, and either way we need to // increment the index for the null attachment binding. - key.color_formats[remapped_cb] = vk::Format::eUndefined; - key.color_buffers[remapped_cb] = {}; - ++remapped_cb; + key.color_buffers[remapped_cb++] = {}; continue; } diff --git a/src/video_core/texture_cache/blit_helper.cpp b/src/video_core/texture_cache/blit_helper.cpp index 1ad41be00..4f1d17547 100644 --- a/src/video_core/texture_cache/blit_helper.cpp +++ b/src/video_core/texture_cache/blit_helper.cpp @@ -126,13 +126,13 @@ void BlitHelper::BlitColorToMsDepth(Image& source, Image& dest) { .minDepth = 0.f, .maxDepth = 1.f, }; - cmdbuf.setViewport(0, viewport); + cmdbuf.setViewportWithCount(viewport); const vk::Rect2D scissor = { .offset = {0, 0}, .extent = {state.width, state.height}, }; - cmdbuf.setScissor(0, scissor); + cmdbuf.setScissorWithCount(scissor); cmdbuf.draw(3, 1, 0, 0); diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index 7b8ff4403..4ab2e991c 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -21,7 +21,7 @@ static vk::ImageUsageFlags ImageUsageFlags(const ImageInfo& info) { if (info.IsDepthStencil()) { usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; } else { - if (!info.IsBlockCoded() && !info.IsPacked()) { + if (!info.IsBlockCoded()) { usage |= vk::ImageUsageFlagBits::eColorAttachment; } // In cases where an image is created as a render/depth target and cleared with compute, diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index 769c4211f..ed10a20bf 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp @@ -176,17 +176,6 @@ bool ImageInfo::IsBlockCoded() const { } } -bool ImageInfo::IsPacked() const { - switch (pixel_format) { - case vk::Format::eB5G5R5A1UnormPack16: - [[fallthrough]]; - case vk::Format::eB5G6R5UnormPack16: - return true; - default: - return false; - } -} - bool ImageInfo::IsDepthStencil() const { switch (pixel_format) { case vk::Format::eD16Unorm: diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h index dbd7f7cbb..9fa3b6c3d 100644 --- a/src/video_core/texture_cache/image_info.h +++ b/src/video_core/texture_cache/image_info.h @@ -31,7 +31,6 @@ struct ImageInfo { } bool IsBlockCoded() const; - bool IsPacked() const; bool IsDepthStencil() const; bool HasStencil() const; diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index a6657d8d9..fa24728ad 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -605,28 +605,27 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule const u32 height = std::max(image.info.size.height >> m, 1u); const u32 depth = image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u; - const auto& mip = image.info.mips_layout[m]; + const auto [mip_size, mip_pitch, mip_height, mip_offset] = image.info.mips_layout[m]; // Protect GPU modified resources from accidental CPU reuploads. if (is_gpu_modified && !is_gpu_dirty) { const u8* addr = std::bit_cast(image.info.guest_address); - const u64 hash = XXH3_64bits(addr + mip.offset, mip.size); + const u64 hash = XXH3_64bits(addr + mip_offset, mip_size); if (image.mip_hashes[m] == hash) { continue; } image.mip_hashes[m] = hash; } - auto mip_pitch = static_cast(mip.pitch); - auto mip_height = static_cast(mip.height); - - auto image_extent_width = mip_pitch ? std::min(mip_pitch, width) : width; - auto image_extent_height = mip_height ? std::min(mip_height, height) : height; + const u32 extent_width = mip_pitch ? std::min(mip_pitch, width) : width; + const u32 extent_height = mip_height ? std::min(mip_height, height) : height; + const u32 height_aligned = + mip_height && image.info.IsTiled() ? std::max(mip_height, 8U) : mip_height; image_copy.push_back({ - .bufferOffset = mip.offset, + .bufferOffset = mip_offset, .bufferRowLength = mip_pitch, - .bufferImageHeight = mip_height, + .bufferImageHeight = height_aligned, .imageSubresource{ .aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .mipLevel = m, @@ -634,7 +633,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule .layerCount = num_layers, }, .imageOffset = {0, 0, 0}, - .imageExtent = {image_extent_width, image_extent_height, depth}, + .imageExtent = {extent_width, extent_height, depth}, }); }