diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 1e740adeef..1c0ad56a8b 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1390,12 +1390,12 @@ void ppu_load_exec(const ppu_exec_object& elf) // Module list to load at startup std::set load_libs; - if ((g_cfg.core.lib_loading != lib_loading_type::hybrid && g_cfg.core.lib_loading != lib_loading_type::manual) || g_cfg.core.load_libraries.get_set().count("liblv2.sprx")) + if (g_cfg.core.libraries_control.get_set().count("liblv2.sprx:lle") || !g_cfg.core.libraries_control.get_set().count("liblv2.sprx:hle")) { // Will load libsysmodule.sprx internally load_libs.emplace("liblv2.sprx"); } - else if (g_cfg.core.lib_loading == lib_loading_type::hybrid) + else if (g_cfg.core.libraries_control.get_set().count("libsysmodule.sprx:lle") || !g_cfg.core.libraries_control.get_set().count("libsysmodule.sprx:hle")) { // Load only libsysmodule.sprx load_libs.emplace("libsysmodule.sprx"); diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 5ee28edbdf..8f87f85f6a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -21,7 +21,7 @@ extern void ppu_initialize(const ppu_module&); LOG_CHANNEL(sys_prx); -extern const std::unordered_map g_prx_list +extern const std::map g_prx_list { { "libaacenc.sprx", 0 }, { "libaacenc_spurs.sprx", 0 }, @@ -205,17 +205,20 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr set; + + extern const std::map g_prx_list; + + for (const auto& lib : g_prx_list) + { + set.emplace(std::string(lib.first) + ":lle"); + } + + return set; + }()); // Fake arg (workaround) argv.resize(1); @@ -1361,10 +1371,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool const std::string game_path = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size(), 9); - sys_log.notice("Forcing manual lib loading mode"); - g_cfg.core.lib_loading.from_string(fmt::format("%s", lib_loading_type::manual)); - g_cfg.core.load_libraries.from_list({}); - argv.resize(9); argv[0] = "/dev_flash/ps1emu/ps1_newemu.self"; argv[1] = m_title_id + "_mc1.VM1"; // virtual mc 1 /dev_hdd0/savedata/vmc/%argv[1]% diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 518d89529b..ebaa48d60b 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -60,9 +60,8 @@ struct cfg_root : cfg::node cfg::_int<-64, 64> stub_ppu_traps{ this, "Stub PPU Traps", 0, true }; // Hack, skip PPU traps for rare cases where the trap is continueable (specify relative instructions to skip) cfg::_bool debug_console_mode{ this, "Debug Console Mode", false }; // Debug console emulation, not recommended - cfg::_enum lib_loading{ this, "Lib Loader", lib_loading_type::liblv2only }; cfg::_bool hook_functions{ this, "Hook static functions" }; - cfg::set_entry load_libraries{ this, "Load libraries" }; + cfg::set_entry libraries_control{ this, "Libraries Control" }; // Override HLE/LLE behaviour of selected libs cfg::_bool hle_lwmutex{ this, "HLE lwmutex" }; // Force alternative lwmutex/lwcond implementation cfg::uint64 spu_llvm_lower_bound{ this, "SPU LLVM Lower Bound" }; cfg::uint64 spu_llvm_upper_bound{ this, "SPU LLVM Upper Bound", 0xffffffffffffffff }; diff --git a/rpcs3/Emu/system_config_types.cpp b/rpcs3/Emu/system_config_types.cpp index 813b725d4f..a3fe64a51b 100644 --- a/rpcs3/Emu/system_config_types.cpp +++ b/rpcs3/Emu/system_config_types.cpp @@ -355,24 +355,6 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](lib_loading_type value) - { - switch (value) - { - case lib_loading_type::manual: return "Manually load selected libraries"; - case lib_loading_type::hybrid: return "Load automatic and manual selection"; - case lib_loading_type::liblv2only: return "Load liblv2.sprx only"; - case lib_loading_type::liblv2both: return "Load liblv2.sprx and manual selection"; - case lib_loading_type::liblv2list: return "Load liblv2.sprx and strict selection"; - } - - return unknown; - }); -} - template <> void fmt_class_string::format(std::string& out, u64 arg) { diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index 0edee8dcc7..65e315bf9d 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -22,15 +22,6 @@ enum class spu_block_size_type giga, }; -enum class lib_loading_type -{ - manual, - hybrid, - liblv2only, - liblv2both, - liblv2list, -}; - enum class sleep_timers_accuracy_level { _as_host, diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index 29e59967c8..fde0372033 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -603,6 +603,7 @@ void emu_settings::EnhanceRadioButton(QButtonGroup* button_group, emu_settings_t } const QString selected = qstr(GetSetting(type)); + const QString def = qstr(GetSettingDefault(type)); const QStringList options = GetSettingOptions(type); if (button_group->buttons().count() < options.size()) @@ -611,32 +612,51 @@ void emu_settings::EnhanceRadioButton(QButtonGroup* button_group, emu_settings_t return; } + bool found = false; + int def_pos = -1; + for (int i = 0; i < options.count(); i++) { const QString localized_setting = GetLocalizedSetting(options[i], type, i); button_group->button(i)->setText(localized_setting); - if (options[i] == selected) + if (!found && options[i] == selected) { + found = true; button_group->button(i)->setChecked(true); } + else if (def_pos == -1 && options[i] == def) + { + def_pos = i; + } connect(button_group->button(i), &QAbstractButton::clicked, [=, this]() { SetSetting(type, sstr(options[i])); }); } + + if (!found) + { + ensure(def_pos >= 0); + + cfg_log.error("EnhanceRadioButton '%s' tried to set an invalid value: %s. Setting to default: %s.", cfg_adapter::get_setting_name(type), sstr(selected), sstr(def)); + m_broken_types.insert(type); + + // Select the default option on invalid setting string + button_group->button(def_pos)->setChecked(true); + } } -std::vector emu_settings::GetLoadedLibraries() +std::vector emu_settings::GetLibrariesControl() { - return m_currentSettings["Core"]["Load libraries"].as, std::initializer_list>({}); + return m_currentSettings["Core"]["Libraries Control"].as, std::initializer_list>({}); } void emu_settings::SaveSelectedLibraries(const std::vector& libs) { - m_currentSettings["Core"]["Load libraries"] = libs; + m_currentSettings["Core"]["Libraries Control"] = libs; } QStringList emu_settings::GetSettingOptions(emu_settings_type type) const @@ -860,16 +880,6 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ case screen_quadrant::bottom_right: return tr("Bottom Right", "Performance overlay position"); } break; - case emu_settings_type::LibLoadOptions: - switch (static_cast(index)) - { - case lib_loading_type::manual: return tr("Manually load selected libraries", "Libraries"); - case lib_loading_type::hybrid: return tr("Load automatic and manual selection", "Libraries"); - case lib_loading_type::liblv2only: return tr("Load liblv2.sprx only", "Libraries"); - case lib_loading_type::liblv2both: return tr("Load liblv2.sprx and manual selection", "Libraries"); - case lib_loading_type::liblv2list: return tr("Load liblv2.sprx and strict selection", "Libraries"); - } - break; case emu_settings_type::PPUDecoder: switch (static_cast(index)) { diff --git a/rpcs3/rpcs3qt/emu_settings.h b/rpcs3/rpcs3qt/emu_settings.h index 745b99c9ae..dfcc7d6fe7 100644 --- a/rpcs3/rpcs3qt/emu_settings.h +++ b/rpcs3/rpcs3qt/emu_settings.h @@ -56,7 +56,7 @@ public: /** Connects a button group with the target settings type*/ void EnhanceRadioButton(QButtonGroup* button_group, emu_settings_type type); - std::vector GetLoadedLibraries(); + std::vector GetLibrariesControl(); void SaveSelectedLibraries(const std::vector& libs); /** Returns the valid options for a given setting.*/ diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index b4e36a80de..9aaefb972a 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -10,7 +10,6 @@ enum class emu_settings_type // Core PPUDecoder, SPUDecoder, - LibLoadOptions, HookStaticFuncs, EnableThreadScheduler, LowerSPUThreadPrio, @@ -156,7 +155,6 @@ static const QMap settings_location = // Core Tab { emu_settings_type::PPUDecoder, { "Core", "PPU Decoder"}}, { emu_settings_type::SPUDecoder, { "Core", "SPU Decoder"}}, - { emu_settings_type::LibLoadOptions, { "Core", "Lib Loader"}}, { emu_settings_type::HookStaticFuncs, { "Core", "Hook static functions"}}, { emu_settings_type::EnableThreadScheduler, { "Core", "Enable thread scheduler"}}, { emu_settings_type::LowerSPUThreadPrio, { "Core", "Lower SPU thread priority"}}, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 3bc76f41e8..e27a6738cc 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -44,6 +44,8 @@ inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QVariant& _in) { return sstr(_in.toString()); } inline QString qsv(std::string_view sv) { return QString(sv.data()); } +extern const std::map g_prx_list; + settings_dialog::settings_dialog(std::shared_ptr gui_settings, std::shared_ptr emu_settings, const int& tab_index, QWidget *parent, const GameInfo* game) : QDialog(parent) , m_tab_index(tab_index) @@ -104,16 +106,28 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std const auto apply_configs = [this, use_discord_old = m_use_discord, discord_state_old = m_discord_state](bool do_exit) { - std::set selectedlle; + std::set selected; for (int i = 0; i < ui->lleList->count(); ++i) { const auto& item = ui->lleList->item(i); if (item->checkState() != Qt::CheckState::Unchecked) { - selectedlle.emplace(sstr(item->text())); + // suffix indicates forced HLE mode + selected.emplace(sstr(item->text()) + ":hle"); } } - std::vector selected_ls = std::vector(selectedlle.begin(), selectedlle.end()); + + for (int i = 0; i < ui->hleList->count(); ++i) + { + const auto& item = ui->hleList->item(i); + if (item->checkState() != Qt::CheckState::Unchecked) + { + // suffix indicates forced LLE mode + selected.emplace(sstr(item->text()) + ":lle"); + } + } + + std::vector selected_ls(selected.begin(), selected.end()); m_emu_settings->SaveSelectedLibraries(selected_ls); m_emu_settings->SaveSettings(); @@ -1012,78 +1026,60 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std SubscribeTooltip(ui->gb_wakeupDelay, tooltips.settings.wake_up_delay); } - // lib options tool tips - SubscribeTooltip(ui->lib_manu, tooltips.settings.libraries_manual); - SubscribeTooltip(ui->lib_both, tooltips.settings.libraries_both); - SubscribeTooltip(ui->lib_lv2, tooltips.settings.libraries_liblv2); - SubscribeTooltip(ui->lib_lv2b, tooltips.settings.libraries_liblv2both); - SubscribeTooltip(ui->lib_lv2l, tooltips.settings.libraries_liblv2list); - - // creating this in ui file keeps scrambling the order... - QButtonGroup *lib_mode_bg = new QButtonGroup(this); - lib_mode_bg->addButton(ui->lib_manu, static_cast(lib_loading_type::manual)); - lib_mode_bg->addButton(ui->lib_both, static_cast(lib_loading_type::hybrid)); - lib_mode_bg->addButton(ui->lib_lv2, static_cast(lib_loading_type::liblv2only)); - lib_mode_bg->addButton(ui->lib_lv2b, static_cast(lib_loading_type::liblv2both)); - lib_mode_bg->addButton(ui->lib_lv2l, static_cast(lib_loading_type::liblv2list)); - - m_emu_settings->EnhanceRadioButton(lib_mode_bg, emu_settings_type::LibLoadOptions); - - std::vector loadedLibs = m_emu_settings->GetLoadedLibraries(); + std::vector loadedLibs = m_emu_settings->GetLibrariesControl(); std::set set(loadedLibs.begin(), loadedLibs.end()); - for (const auto& lib : set) - { - QListWidgetItem* item = new QListWidgetItem(qsv(lib), ui->lleList); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag - item->setCheckState(Qt::Checked); // AND initialize check state - ui->lleList->addItem(item); - } - - extern const std::unordered_map g_prx_list; - for (const auto& lib : g_prx_list) { - if (set.count(lib.first)) - { - continue; - } + // -1: Override LLE + // 1: Override HLE + // 0: No override + const int res = static_cast(set.count(std::string(lib.first) + ":hle") - set.count(std::string(lib.first) + ":lle")); - QListWidgetItem* item = new QListWidgetItem(qsv(lib.first), ui->lleList); + const auto list = (lib.second ? ui->hleList : ui->lleList); + + QListWidgetItem* item = new QListWidgetItem(qsv(lib.first), list); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag - item->setCheckState(Qt::Unchecked); // AND initialize check state - ui->lleList->addItem(item); + + // If no override selected (res=0), checkbox is unchecked + // Otherwise if the override does not match the default behaviour, checkbox is checked + item->setCheckState(res && res != (lib.second * 2 - 1) ? Qt::Checked : Qt::Unchecked); // AND initialize check state + + item->setToolTip(!lib.second ? tooltips.settings.lib_default_lle : + (lib.first.starts_with("libsysutil") ? tr("Do not touch libsysutil libs, development purposes only, will cause game crashes.") : tooltips.settings.lib_default_hle)); + + list->addItem(item); } + SubscribeTooltip(ui->lleList, tooltips.settings.lle_list); + SubscribeTooltip(ui->hleList, tooltips.settings.hle_list); ui->searchBox->setPlaceholderText(tr("Search libraries", "Library search box")); - auto on_lib_button_clicked = [this](int id) - { - const bool enableLibs = id != static_cast(lib_loading_type::liblv2only); - ui->searchBox->setEnabled(enableLibs); - ui->lleList->setEnabled(enableLibs); - }; - - auto on_search_box_text_changed = [this](QString text) + auto on_lib_state_changed = [this](QString text) { const QString search_term = text.toLower(); - std::vector items; + std::vector items, items2; - // duplicate current items, we need clones to preserve checkstates - for (int i = 0; i < ui->lleList->count(); i++) + // Take current items + while (ui->lleList->count()) { - items.push_back(ui->lleList->item(i)->clone()); + items.push_back(ui->lleList->takeItem(0)); + } + + while (ui->hleList->count()) + { + items2.push_back(ui->hleList->takeItem(0)); } // sort items: checked items first then alphabetical order - std::sort(items.begin(), items.end(), [](QListWidgetItem *i1, QListWidgetItem *i2) + const auto func = [](QListWidgetItem *i1, QListWidgetItem *i2) { return (i1->checkState() != i2->checkState()) ? (i1->checkState() > i2->checkState()) : (i1->text() < i2->text()); - }); - - // refill library list - ui->lleList->clear(); + }; + + std::sort(items.begin(), items.end(), func); + std::sort(items2.begin(), items2.end(), func); for (uint i = 0; i < items.size(); i++) { @@ -1092,11 +1088,35 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std // only show items filtered for search text ui->lleList->setRowHidden(i, !items[i]->text().contains(search_term)); } + + for (uint i = 0; i < items2.size(); i++) + { + ui->hleList->addItem(items2[i]); + + // only show items filtered for search text + ui->hleList->setRowHidden(i, !items2[i]->text().contains(search_term)); + } }; + // Sort libs + on_lib_state_changed({}); + // Events - connect(lib_mode_bg, &QButtonGroup::idClicked, on_lib_button_clicked); - connect(ui->searchBox, &QLineEdit::textChanged, on_search_box_text_changed); + connect(ui->searchBox, &QLineEdit::textChanged, on_lib_state_changed); + connect(ui->resetLleList, &QAbstractButton::clicked, [this, on_lib_state_changed]() + { + for (int i = 0; i < ui->lleList->count(); i++) + { + ui->lleList->item(i)->setCheckState(Qt::Unchecked); + } + + for (int i = 0; i < ui->hleList->count(); i++) + { + ui->hleList->item(i)->setCheckState(Qt::Unchecked); + } + + on_lib_state_changed(ui->searchBox->text()); + }); // enable multiselection (there must be a better way) connect(ui->lleList, &QListWidget::itemChanged, [this](QListWidgetItem* item) @@ -1107,10 +1127,13 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std } }); - if (const int lib_mode_button_id = lib_mode_bg->checkedId(); lib_mode_button_id >= 0) + connect(ui->hleList, &QListWidget::itemChanged, [this](QListWidgetItem* item) { - on_lib_button_clicked(lib_mode_button_id); - } + for (auto cb : ui->hleList->selectedItems()) + { + cb->setCheckState(item->checkState()); + } + }); // ______ _ _ _______ _ // | ____| | | | | |__ __| | | diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 7f9d6ae008..4fdbc604e7 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -1904,86 +1904,6 @@ - - - - - 0 - 0 - - - - Firmware Settings - - - - - - - 0 - 0 - - - - Manually load selected libraries - - - - - - - - 0 - 0 - - - - Load automatic and manual selection - - - - - - - - 0 - 0 - - - - Load liblv2.sprx only - - - - - - - - 0 - 0 - - - - Load liblv2.sprx and manual selection - - - - - - - - 0 - 0 - - - - Load liblv2.sprx and strict selection - - - - - - @@ -2013,6 +1933,22 @@ Firmware Libraries + + + + + 0 + 0 + + + + QAbstractItemView::ExtendedSelection + + + QListView::ListMode + + + @@ -2030,14 +1966,25 @@ - - - - 0 - 0 - + + + 6 - + + QLayout::SetNoConstraint + + + + + + + + + Reset + + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 8d6336d357..bad109b71e 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -19,11 +19,10 @@ public: { // advanced - const QString libraries_manual = tr("Allows the user to manually choose the LLE libraries to load.\nIf unsure, don't use this option. Nothing will work if you use this."); - const QString libraries_both = tr("Load libsysmodule.sprx and chosen list of libraries. Option for backward compatibility.\nIf unsure, don't use this option."); - const QString libraries_liblv2both = tr("Loads liblv2.sprx and chosen list of libraries.\nIf unsure, don't use this option."); - const QString libraries_liblv2list = tr("Loads liblv2.sprx and nothing but selected libraries.\nDon't use this option."); - const QString libraries_liblv2 = tr("This closely emulates how games can load and unload system module files on a real PlayStation 3.\nSome games require this.\nThis is the preferred option."); + const QString lle_list = tr("This libraries group are LLEd by default (lower list), selection will switch to HLE.\nLLE - \"Low Level Emulated\", function code inside the selected SPRX file will be used for exported firmware functions.\nHLE - \"High Level Emulated\", alternative emulator code will be used instead for exported firmware functions.\nIf choosen wrongly, games will not work! If unsure, leave both lists' selection empty."); + const QString hle_list = tr("This libraries group are HLEd by default (upper list), selection will switch to LLE.\nLLE - \"Low Level Emulated\", function code inside the selected SPRX file will be used for exported firmware functions.\nHLE - \"High Level Emulated\", alternative emulator code will be used instead for exported firmware functions.\nIf choosen wrongly, games will not work! If unsure, leave both lists' selection empty."); + const QString lib_default_hle = tr("Select to LLE. (HLE by default)"); + const QString lib_default_lle = tr("Select to HLE. (LLE by default)"); const QString debug_console_mode = tr("Increases the amount of usable system memory to match a DECR console and more.\nCauses some software to behave differently than on retail hardware."); const QString silence_all_logs = tr("Stop writing any logs after game startup. Don't use unless you believe it's necessary.");