diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..09a1b0141e --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,76 @@ +{ + "version": 4, + "configurePresets": [ + { + "name": "VS", + "displayName": "Visual Studio 17 2022", + "generator": "Visual Studio 17 2022", + "binaryDir": "${sourceDir}/build_cmake/build/${presetName}", + "hidden": true + }, + { + "name": "NINJA", + "displayName": "Ninja", + "generator": "Ninja Multi-Config", + "binaryDir": "${sourceDir}/build_cmake/build/${presetName}", + "hidden": true + }, + { + "name": "DEBUGGER", + "cacheVariables": { + "DEBUGGER_INCLUDED": { + "type": "BOOL", + "value": "ON" + } + }, + "hidden": true + }, + { + "name": "WIN32", + "architecture": { + "value": "x64", + "strategy": "set" + }, + "cacheVariables": { + "USE_QT": { + "type": "BOOL", + "value": "ON" + } + }, + "hidden": true + }, + { + "name": "win32-vs", + "inherits": [ + "WIN32", + "VS" + ] + }, + { + "name": "win32-vs-debugger", + "inherits": [ + "WIN32", + "VS", + "DEBUGGER" + ] + } + ], + "buildPresets": [ + { + "name": "win32-vs", + "configurePreset": "win32-vs", + "configuration": "RelWithDebInfo", + "targets": [ + "Play", + "CodeGenTestSuite" + ] + }, + { + "name": "win32-vs-debugger", + "configurePreset": "win32-vs-debugger", + "targets": [ + "Play" + ] + } + ] +} \ No newline at end of file diff --git a/Source/ui_android/BootablesInterop.cpp b/Source/ui_android/BootablesInterop.cpp index 6fba672d7b..310d4c9ec5 100644 --- a/Source/ui_android/BootablesInterop.cpp +++ b/Source/ui_android/BootablesInterop.cpp @@ -1,5 +1,6 @@ #include "../ui_shared/BootablesProcesses.h" #include "../ui_shared/BootablesDbClient.h" +#include "ui_shared/BootableUtils.h" #include "com_virtualapplications_play_Bootable.h" #include "NativeShared.h" @@ -108,7 +109,7 @@ extern "C" JNIEXPORT void Java_com_virtualapplications_play_BootablesInterop_set extern "C" JNIEXPORT jboolean Java_com_virtualapplications_play_BootablesInterop_IsBootableExecutablePath(JNIEnv* env, jclass clazz, jstring bootablePathString) { auto bootablePath = fs::path(GetStringFromJstring(env, bootablePathString)); - return IsBootableExecutablePath(bootablePath); + return BootableUtils::IsBootableExecutablePath(bootablePath); } extern "C" JNIEXPORT jboolean Java_com_virtualapplications_play_BootablesInterop_DoesBootableExist(JNIEnv* env, jclass clazz, jstring bootablePathString) diff --git a/Source/ui_android/java/com/virtualapplications/play/BootablesInterop.java b/Source/ui_android/java/com/virtualapplications/play/BootablesInterop.java index 1f05fbff75..0e5a028311 100644 --- a/Source/ui_android/java/com/virtualapplications/play/BootablesInterop.java +++ b/Source/ui_android/java/com/virtualapplications/play/BootablesInterop.java @@ -8,8 +8,8 @@ public class BootablesInterop } public static final int SORT_RECENT = 0; - public static final int SORT_HOMEBREW = 1; - public static final int SORT_NONE = 2; + public static final int SORT_NONE = 1; + public static final int SORT_HOMEBREW = 2; public static native void scanBootables(String[] rootDirectories); public static native void fullScanBootables(String[] rootDirectories); diff --git a/Source/ui_android/java/com/virtualapplications/play/MainActivity.java b/Source/ui_android/java/com/virtualapplications/play/MainActivity.java index 017315c299..f469148778 100644 --- a/Source/ui_android/java/com/virtualapplications/play/MainActivity.java +++ b/Source/ui_android/java/com/virtualapplications/play/MainActivity.java @@ -139,7 +139,7 @@ private void Startup() gameInfo = new GameInfo(MainActivity.this); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - sortMethod = sp.getInt("sortMethod", SORT_NONE); + sortMethod = sp.getInt("sortMethod.v2", SORT_NONE); onNavigationDrawerItemSelected(sortMethod); sp.registerOnSharedPreferenceChangeListener(this); @@ -339,7 +339,7 @@ public void onNavigationDrawerItemSelected(int position) prepareFileListView(false); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - sp.edit().putInt("sortMethod", sortMethod).apply(); + sp.edit().putInt("sortMethod.v2", sortMethod).apply(); } @Override diff --git a/Source/ui_ios/EmulatorViewController.mm b/Source/ui_ios/EmulatorViewController.mm index 4056b7b635..5cd1498d4f 100644 --- a/Source/ui_ios/EmulatorViewController.mm +++ b/Source/ui_ios/EmulatorViewController.mm @@ -11,7 +11,7 @@ #ifdef HAS_GSH_VULKAN #include "GSH_VulkaniOS.h" #endif -#include "../ui_shared/BootablesProcesses.h" +#include "../ui_shared/BootableUtils.h" #include "PH_Generic.h" #include "../../tools/PsfPlayer/Source/SH_OpenAL.h" #include "../ui_shared/StatsManager.h" @@ -127,7 +127,7 @@ - (void)viewDidAppear:(BOOL)animated g_virtualMachine->Reset(); auto bootablePath = fs::path([self.bootablePath fileSystemRepresentation]); - if(IsBootableExecutablePath(bootablePath)) + if(BootableUtils::IsBootableExecutablePath(bootablePath)) { g_virtualMachine->m_ee->m_os->BootFromFile(bootablePath); } diff --git a/Source/ui_libretro/CMakeLists.txt b/Source/ui_libretro/CMakeLists.txt index b84b0c402d..cc195c1aa3 100644 --- a/Source/ui_libretro/CMakeLists.txt +++ b/Source/ui_libretro/CMakeLists.txt @@ -10,6 +10,14 @@ project(Play_Libretro_Core) add_definitions(-DPLAY_VERSION="${PROJECT_Version}") +if(NOT TARGET ui_shared) + add_subdirectory( + ${CMAKE_CURRENT_SOURCE_DIR}/../ui_shared + ${CMAKE_CURRENT_BINARY_DIR}/ui_shared + ) +endif() +list(APPEND PROJECT_LIBS ui_shared) + if(NOT TARGET PlayCore) add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/../ diff --git a/Source/ui_libretro/main_libretro.cpp b/Source/ui_libretro/main_libretro.cpp index d38d052ee3..fc01f37997 100644 --- a/Source/ui_libretro/main_libretro.cpp +++ b/Source/ui_libretro/main_libretro.cpp @@ -3,7 +3,7 @@ #include "Log.h" #include "AppConfig.h" #include "PS2VM.h" -#include "DiskUtils.h" +#include "ui_shared/BootableUtils.h" #include "PS2VM_Preferences.h" #include "GSH_OpenGL_Libretro.h" @@ -473,22 +473,6 @@ void retro_reset(void) first_run = false; } -bool IsBootableExecutablePath(const fs::path& filePath) -{ - auto extension = filePath.extension().string(); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - return (extension == ".elf"); -} - -bool IsBootableDiscImagePath(const fs::path& filePath) -{ - const auto& supportedExtensions = DiskUtils::GetSupportedExtensions(); - auto extension = filePath.extension().string(); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - auto extensionIterator = supportedExtensions.find(extension); - return extensionIterator != std::end(supportedExtensions); -} - bool retro_load_game(const retro_game_info* info) { CLog::GetInstance().Print(LOG_NAME, "%s\n", __FUNCTION__); @@ -507,11 +491,11 @@ bool retro_load_game(const retro_game_info* info) #endif fs::path filePath = info->path; - if(IsBootableExecutablePath(filePath)) + if(BootableUtils::IsBootableExecutablePath(filePath)) { m_bootCommand = LastOpenCommand(BootType::ELF, filePath); } - else if(IsBootableDiscImagePath(filePath)) + else if(BootableUtils::IsBootableDiscImagePath(filePath)) { m_bootCommand = LastOpenCommand(BootType::CD, filePath); CAppConfig::GetInstance().SetPreferencePath(PREF_PS2_CDROM0_PATH, filePath); diff --git a/Source/ui_qt/BootableModel.cpp b/Source/ui_qt/BootableModel.cpp index 008a5ccf1e..1f8cea65ef 100644 --- a/Source/ui_qt/BootableModel.cpp +++ b/Source/ui_qt/BootableModel.cpp @@ -31,7 +31,7 @@ QVariant BootableModel::data(const QModelIndex& index, int role) const { int pos = index.row() + index.column(); auto bootable = m_bootables.at(static_cast(pos)); - return QVariant::fromValue(BootableCoverQVariant(bootable.discId, bootable.title, bootable.path, bootable.states)); + return QVariant::fromValue(BootableCoverQVariant(bootable.discId, bootable.title, bootable.path, bootable.states, bootable.bootableType)); } return QVariant(); } @@ -69,11 +69,12 @@ void BootableModel::SetWidth(int width) } /* start of BootImageItemDelegate */ -BootableCoverQVariant::BootableCoverQVariant(std::string key, std::string title, fs::path path, BootablesDb::BootableStateList states) +BootableCoverQVariant::BootableCoverQVariant(std::string key, std::string title, fs::path path, BootablesDb::BootableStateList states, BootableUtils::BOOTABLE_TYPE bootableType) : m_key(key) , m_title(title) , m_path(path) , m_states(states) + , m_bootableType(bootableType) { for(auto state : states) { @@ -171,6 +172,11 @@ fs::path BootableCoverQVariant::GetPath() const return m_path; } +int BootableCoverQVariant::GetBootableType() const +{ + return m_bootableType; +} + bool BootableCoverQVariant::HasState(std::string state) { auto itr = std::find_if(std::begin(m_states), std::end(m_states), [state](BootablesDb::BootableState bootState) { diff --git a/Source/ui_qt/BootableModel.h b/Source/ui_qt/BootableModel.h index 793af72f5a..7e0601edfb 100644 --- a/Source/ui_qt/BootableModel.h +++ b/Source/ui_qt/BootableModel.h @@ -6,6 +6,7 @@ #include #include #include "ui_shared/BootablesDbClient.h" +#include "ui_shared/BootableUtils.h" class BootableModel : public QAbstractTableModel { @@ -31,7 +32,7 @@ class BootableCoverQVariant { public: - explicit BootableCoverQVariant(std::string = "PH", std::string = "", fs::path = "", BootablesDb::BootableStateList = {}); + explicit BootableCoverQVariant(std::string = "PH", std::string = "", fs::path = "", BootablesDb::BootableStateList = {}, BootableUtils::BOOTABLE_TYPE = BootableUtils::UNKNOWN); ~BootableCoverQVariant() = default; void paint(QPainter* painter, const QRect& rect, const QPalette& palette, int mode) const; @@ -41,6 +42,7 @@ class BootableCoverQVariant std::string GetTitle() const; fs::path GetPath() const; bool HasState(std::string); + int GetBootableType() const; private: int GetPadding() const; @@ -49,6 +51,7 @@ class BootableCoverQVariant fs::path m_path; std::string m_statusColor; BootablesDb::BootableStateList m_states; + BootableUtils::BOOTABLE_TYPE m_bootableType; }; Q_DECLARE_METATYPE(BootableCoverQVariant) diff --git a/Source/ui_qt/BootableModelProxy.cpp b/Source/ui_qt/BootableModelProxy.cpp index 1b7da530bf..407a16a27f 100644 --- a/Source/ui_qt/BootableModelProxy.cpp +++ b/Source/ui_qt/BootableModelProxy.cpp @@ -21,6 +21,21 @@ void BootableModelProxy::setFilterState(const QString& state) invalidateFilter(); } +void BootableModelProxy::setBootableTypeFilterState(int bitIndex, bool value) +{ + if(value) + m_bootableType |= bitIndex; + else + m_bootableType &= ~bitIndex; + + invalidateFilter(); +} + +int BootableModelProxy::getBootableTypeFilterState() +{ + return m_bootableType; +} + bool BootableModelProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); @@ -32,6 +47,7 @@ bool BootableModelProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sour QString key = QString::fromStdString(bootablecover.GetKey()); QString title = QString::fromStdString(bootablecover.GetTitle()); QString path = PathToQString(bootablecover.GetPath()); + auto bootableType = bootablecover.GetBootableType(); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QRegularExpression regex = filterRegularExpression(); regex.setPatternOptions(QRegularExpression::CaseInsensitiveOption); @@ -47,6 +63,11 @@ bool BootableModelProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sour { res &= bootablecover.HasState(m_state); } + + if(m_bootableType != 0) + { + res &= (bootableType & m_bootableType) != 0; + } return res; } return false; diff --git a/Source/ui_qt/BootableModelProxy.h b/Source/ui_qt/BootableModelProxy.h index 497768e2ce..68039a29b9 100644 --- a/Source/ui_qt/BootableModelProxy.h +++ b/Source/ui_qt/BootableModelProxy.h @@ -8,10 +8,13 @@ class BootableModelProxy : public QSortFilterProxyModel BootableModelProxy(QObject* parent); void setFilterState(const QString&); + void setBootableTypeFilterState(int, bool); + int getBootableTypeFilterState(); protected: bool filterAcceptsRow(int, const QModelIndex&) const override; private: - std::string m_state; + std::string m_state = ""; + int m_bootableType = 0; }; diff --git a/Source/ui_qt/QBootablesView.cpp b/Source/ui_qt/QBootablesView.cpp index 4f8ac54fe3..e6c814dcbb 100644 --- a/Source/ui_qt/QBootablesView.cpp +++ b/Source/ui_qt/QBootablesView.cpp @@ -31,10 +31,37 @@ QBootablesView::QBootablesView(QWidget* parent) m_proxyModel = new BootableModelProxy(this); ui->listView->setModel(m_proxyModel); - CAppConfig::GetInstance().RegisterPreferenceInteger("ui.sortmethod", BootablesDb::CClient::SORT_METHOD_NONE); - m_sortingMethod = CAppConfig::GetInstance().GetPreferenceInteger("ui.sortmethod"); + CAppConfig::GetInstance().RegisterPreferenceInteger("ui.sortmethod.v2", BootablesDb::CClient::SORT_METHOD_NONE); + m_sortingMethod = CAppConfig::GetInstance().GetPreferenceInteger("ui.sortmethod.v2") & BootablesDb::CClient::SORT_METHOD_NONE; ui->comboBox->setCurrentIndex(m_sortingMethod); + CAppConfig::GetInstance().RegisterPreferenceInteger("ui.filterbootabletype", BootableUtils::PS2_DISC | BootableUtils::PS2_ARCADE | BootableUtils::PS2_ELF); + auto filter = CAppConfig::GetInstance().GetPreferenceInteger("ui.filterbootabletype"); + ui->checkBox_ps2->setChecked(filter & BootableUtils::PS2_DISC); + ui->checkBox_ps2_arcade->setChecked(filter & BootableUtils::PS2_ARCADE); + ui->checkBox_ps2_elf->setChecked(filter & BootableUtils::PS2_ELF); + + m_proxyModel->setBootableTypeFilterState(filter, 1); + + auto updateFilterPref = [](auto proxyModel) { + CAppConfig::GetInstance().SetPreferenceInteger("ui.filterbootabletype", proxyModel->getBootableTypeFilterState()); + }; + + connect(ui->checkBox_ps2, &QCheckBox::stateChanged, [this, updateFilterPref](int state) { + m_proxyModel->setBootableTypeFilterState(BootableUtils::PS2_DISC, state); + updateFilterPref(m_proxyModel); + }); + + connect(ui->checkBox_ps2_arcade, &QCheckBox::stateChanged, [this, updateFilterPref](int state) { + m_proxyModel->setBootableTypeFilterState(BootableUtils::PS2_ARCADE, state); + updateFilterPref(m_proxyModel); + }); + + connect(ui->checkBox_ps2_elf, &QCheckBox::stateChanged, [this, updateFilterPref](int state) { + m_proxyModel->setBootableTypeFilterState(BootableUtils::PS2_ELF, state); + updateFilterPref(m_proxyModel); + }); + connect(ui->filterLineEdit, &QLineEdit::textChanged, m_proxyModel, &QSortFilterProxyModel::setFilterFixedString); connect(ui->stateFilterComboBox, &QComboBox::currentTextChanged, m_proxyModel, &BootableModelProxy::setFilterState); connect(ui->listView->selectionModel(), &QItemSelectionModel::currentChanged, this, &QBootablesView::SelectionChange); @@ -178,7 +205,7 @@ void QBootablesView::BootBootables(const QModelIndex& index) auto src_index = m_proxyModel->mapToSource(index); assert(src_index.isValid()); auto bootable = static_cast(m_proxyModel->sourceModel())->GetBootable(src_index); - m_bootCallback(bootable.path); + m_bootCallback(bootable); } void QBootablesView::on_listView_doubleClicked(const QModelIndex& index) @@ -222,7 +249,7 @@ void QBootablesView::on_refresh_button_clicked() void QBootablesView::on_comboBox_currentIndexChanged(int index) { - CAppConfig::GetInstance().SetPreferenceInteger("ui.sortmethod", index); + CAppConfig::GetInstance().SetPreferenceInteger("ui.sortmethod.v2", index); m_sortingMethod = index; resetModel(); } @@ -315,6 +342,10 @@ void QBootablesView::on_reset_filter_button_clicked() { ui->filterLineEdit->clear(); ui->stateFilterComboBox->setCurrentIndex(0); + + ui->checkBox_ps2->setChecked(true); + ui->checkBox_ps2_arcade->setChecked(true); + ui->checkBox_ps2_elf->setChecked(true); } bool QBootablesView::IsProcessing() diff --git a/Source/ui_qt/QBootablesView.h b/Source/ui_qt/QBootablesView.h index a70ef81997..bf9e7bca53 100644 --- a/Source/ui_qt/QBootablesView.h +++ b/Source/ui_qt/QBootablesView.h @@ -22,7 +22,7 @@ class QBootablesView : public QWidget public: explicit QBootablesView(QWidget* parent = 0); - using BootCallback = std::function; + using BootCallback = std::function; void SetupActions(BootCallback); void AddMsgLabel(ElidedLabel*); diff --git a/Source/ui_qt/Qt_ui/bootableview.ui b/Source/ui_qt/Qt_ui/bootableview.ui index 9d8377ce72..e0436b23d4 100644 --- a/Source/ui_qt/Qt_ui/bootableview.ui +++ b/Source/ui_qt/Qt_ui/bootableview.ui @@ -70,6 +70,59 @@ + + + + 9 + + + 9 + + + + + + 0 + 0 + + + + Filter: + + + + + + + Disc + + + true + + + + + + + Arcade + + + true + + + + + + + Homebrew + + + true + + + + + @@ -79,13 +132,13 @@ - QListView::Free + QListView::Movement::Free - QListView::Adjust + QListView::ResizeMode::Adjust - QListView::IconMode + QListView::ViewMode::IconMode true @@ -206,21 +259,11 @@ Recently Played - - - Homebrew - - Unsorted - - - Arcade Machines - - diff --git a/Source/ui_qt/mainwindow.cpp b/Source/ui_qt/mainwindow.cpp index ad21a0a0d2..95a8f9849f 100644 --- a/Source/ui_qt/mainwindow.cpp +++ b/Source/ui_qt/mainwindow.cpp @@ -46,7 +46,7 @@ #include "ui_debugmenu.h" #endif #include "input/PH_GenericInput.h" -#include "DiskUtils.h" +#include "ui_shared/BootableUtils.h" #include "PathUtils.h" #include @@ -494,6 +494,54 @@ void MainWindow::CreateStatusBar() m_fpsLabel = new QLabel(""); m_fpsLabel->setAlignment(Qt::AlignHCenter); m_fpsLabel->setMinimumSize(m_fpsLabel->sizeHint()); + m_fpsLabel->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(m_fpsLabel, &QLabel::customContextMenuRequested, [&]() { + auto value = CAppConfig::GetInstance().GetPreferenceBoolean(PREF_PS2_LIMIT_FRAMERATE); + CAppConfig::GetInstance().SetPreferenceBoolean(PREF_PS2_LIMIT_FRAMERATE, !value); + if(m_virtualMachine) + { + m_virtualMachine->ReloadFrameRateLimit(); + } + }); + + int factor = CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSH_OPENGL_RESOLUTION_FACTOR); + m_scaleFactorLabel = new QLabel(); + m_scaleFactorLabel->setAlignment(Qt::AlignHCenter); + m_scaleFactorLabel->setMinimumSize(m_scaleFactorLabel->sizeHint()); + m_scaleFactorLabel->setText(QString("%1x").arg(factor)); + m_scaleFactorLabel->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(m_scaleFactorLabel, &QLabel::customContextMenuRequested, [&](const QPoint& pos) { + QMenu contextMenu(this); + + int factor = CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSH_OPENGL_RESOLUTION_FACTOR); + for(int index = 0; index < 5; ++index) + { + int value = 1 << index; + QAction* action = contextMenu.addAction(QString("%1x").arg(value)); + action->setCheckable(true); + action->setChecked(factor == value); + + connect(action, &QAction::triggered, [this, index, value, factor]() mutable { + CAppConfig::GetInstance().SetPreferenceInteger(PREF_CGSH_OPENGL_RESOLUTION_FACTOR, value); + m_scaleFactorLabel->setText(QString("%1x").arg(value)); + + if(m_virtualMachine && factor != value) + { + outputWindow_resized(); + auto gsHandler = m_virtualMachine->GetGSHandler(); + if(gsHandler) + { + gsHandler->NotifyPreferencesChanged(); + } + } + factor = value; + }); + } + + contextMenu.exec(m_scaleFactorLabel->mapToGlobal(pos)); + }); m_cpuUsageLabel = new QLabel(""); m_cpuUsageLabel->setAlignment(Qt::AlignHCenter); @@ -508,12 +556,12 @@ void MainWindow::CreateStatusBar() statusBar()->addWidget(m_msgLabel, 1); statusBar()->addWidget(m_fpsLabel); statusBar()->addWidget(m_cpuUsageLabel); + statusBar()->addWidget(m_scaleFactorLabel); #ifdef HAS_GSH_VULKAN if(GSH_Vulkan::CDeviceInfo::GetInstance().HasAvailableDevices()) { m_gsLabel = new QLabel(""); - auto gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER); - UpdateGSHandlerLabel(gs_index); + UpdateGSHandlerLabel(); m_gsLabel->setAlignment(Qt::AlignHCenter); m_gsLabel->setMinimumSize(m_gsLabel->sizeHint()); @@ -523,8 +571,11 @@ void MainWindow::CreateStatusBar() auto gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER); gs_index = (gs_index + 1) % SettingsDialog::GS_HANDLERS::MAX_HANDLER; CAppConfig::GetInstance().SetPreferenceInteger(PREF_VIDEO_GS_HANDLER, gs_index); - SetupGsHandler(); - UpdateGSHandlerLabel(gs_index); + if(m_virtualMachine) + { + SetupGsHandler(); + } + UpdateGSHandlerLabel(); }); statusBar()->addWidget(m_gsLabel); } @@ -540,6 +591,7 @@ void MainWindow::CreateStatusBar() void MainWindow::updateStats() { + auto unlockedFps = !CAppConfig::GetInstance().GetPreferenceBoolean(PREF_PS2_LIMIT_FRAMERATE); uint32 frames = CStatsManager::GetInstance().GetFrames(); uint32 drawCalls = CStatsManager::GetInstance().GetDrawCalls(); auto cpuUtilisation = CStatsManager::GetInstance().GetCpuUtilisationInfo(); @@ -547,7 +599,7 @@ void MainWindow::updateStats() #ifdef PROFILE m_profileStatsLabel->setText(QString::fromStdString(CStatsManager::GetInstance().GetProfilingInfo())); #endif - m_fpsLabel->setText(QString("%1 f/s, %2 dc/f").arg(frames).arg(dcpf)); + m_fpsLabel->setText(QString("%1%2 f/s, %3 dc/f").arg(frames).arg(unlockedFps ? " (U)" : "").arg(dcpf)); auto eeUsageRatio = CStatsManager::ComputeCpuUsageRatio(cpuUtilisation.eeIdleTicks, cpuUtilisation.eeTotalTicks); m_cpuUsageLabel->setText(QString("EE CPU: %1%").arg(static_cast(eeUsageRatio))); @@ -569,7 +621,6 @@ void MainWindow::on_actionSettings_triggered() auto new_gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER); if(gs_index != new_gs_index) { - UpdateGSHandlerLabel(new_gs_index); SetupGsHandler(); } else @@ -582,6 +633,10 @@ void MainWindow::on_actionSettings_triggered() } } } + else + { + UpdateGSHandlerLabel(); + } } void MainWindow::SetupSaveLoadStateSlots() @@ -1102,9 +1157,10 @@ void MainWindow::on_actionList_Bootables_triggered() ui->stackedWidget->setCurrentIndex(1 - ui->stackedWidget->currentIndex()); } -void MainWindow::UpdateGSHandlerLabel(int gs_index) +void MainWindow::UpdateGSHandlerLabel() { #if HAS_GSH_VULKAN + auto gs_index = CAppConfig::GetInstance().GetPreferenceInteger(PREF_VIDEO_GS_HANDLER); switch(gs_index) { default: @@ -1116,6 +1172,9 @@ void MainWindow::UpdateGSHandlerLabel(int gs_index) break; } #endif + + int factor = CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSH_OPENGL_RESOLUTION_FACTOR); + m_scaleFactorLabel->setText(QString("%1x").arg(factor)); } void MainWindow::SetupBootableView() @@ -1125,28 +1184,27 @@ void MainWindow::SetupBootableView() bootablesView->AddMsgLabel(m_msgLabel); - QBootablesView::BootCallback bootGameCallback = [&, showEmu](fs::path filePath) { + QBootablesView::BootCallback bootGameCallback = [&, showEmu](const BootablesDb::Bootable& bootable) { try { - if(IsBootableDiscImagePath(filePath)) + switch(bootable.bootableType) { - LoadCDROM(filePath); + case BootableUtils::PS2_DISC: + LoadCDROM(bootable.path); BootCDROM(); - } - else if(IsBootableExecutablePath(filePath)) - { - BootElf(filePath); - } - else if(IsBootableArcadeDefPath(filePath)) - { - BootArcadeMachine(filePath); - } - else - { + break; + case BootableUtils::PS2_ELF: + BootElf(bootable.path); + break; + case BootableUtils::PS2_ARCADE: + BootArcadeMachine(bootable.path); + break; + default: QMessageBox messageBox; QString invalid("Invalid File Format."); messageBox.critical(this, this->windowTitle(), invalid); messageBox.show(); + break; } showEmu(); } diff --git a/Source/ui_qt/mainwindow.h b/Source/ui_qt/mainwindow.h index 594cd14a20..a2710e6d43 100644 --- a/Source/ui_qt/mainwindow.h +++ b/Source/ui_qt/mainwindow.h @@ -91,7 +91,7 @@ class MainWindow : public QMainWindow void saveState(int); void buildResizeWindowMenu(); void resizeWindow(unsigned int, unsigned int); - void UpdateGSHandlerLabel(int); + void UpdateGSHandlerLabel(); void SetupBootableView(); void SetupDebugger(); @@ -99,6 +99,7 @@ class MainWindow : public QMainWindow OutputWindow* m_outputwindow = nullptr; QLabel* m_fpsLabel = nullptr; + QLabel* m_scaleFactorLabel = nullptr; QLabel* m_cpuUsageLabel = nullptr; QLabel* m_gsLabel = nullptr; #ifdef PROFILE diff --git a/Source/ui_qt/win32/InputProviderDirectInput.cpp b/Source/ui_qt/win32/InputProviderDirectInput.cpp index 710ac8afc3..c5dca6bbe6 100644 --- a/Source/ui_qt/win32/InputProviderDirectInput.cpp +++ b/Source/ui_qt/win32/InputProviderDirectInput.cpp @@ -46,13 +46,13 @@ std::string CInputProviderDirectInput::GetTargetDescription(const BINDINGTARGET& DIDEVICEINSTANCE deviceInstance = {}; if(m_diManager->GetDeviceInfo(deviceId, &deviceInstance)) { - deviceName = string_cast(deviceInstance.tszInstanceName); + deviceName = string_cast(deviceInstance.tszInstanceName); } DIDEVICEOBJECTINSTANCE objectInstance = {}; if(m_diManager->GetDeviceObjectInfo(deviceId, target.keyId, &objectInstance)) { - deviceKeyName = string_cast(objectInstance.tszName); + deviceKeyName = string_cast(objectInstance.tszName); } return string_format("%s: %s", deviceName.c_str(), deviceKeyName.c_str()); @@ -67,7 +67,7 @@ std::vector CInputProviderDirectInput::GetDevices() const DIDEVICEINSTANCE deviceInstance = {}; if(m_diManager->GetDeviceInfo(deviceGuid, &deviceInstance)) { - deviceName = string_cast(deviceInstance.tszInstanceName); + deviceName = string_cast(deviceInstance.tszInstanceName); } auto deviceId = GuidToDeviceId(deviceGuid); devices.push_back({GetId(), deviceId, string_format("%s : 0x%X", deviceName.c_str(), deviceId)}); diff --git a/Source/ui_shared/ArcadeUtils.cpp b/Source/ui_shared/ArcadeUtils.cpp index b31a428086..1f5c07cdab 100644 --- a/Source/ui_shared/ArcadeUtils.cpp +++ b/Source/ui_shared/ArcadeUtils.cpp @@ -267,7 +267,7 @@ void ArcadeUtils::RegisterArcadeMachines() try { auto def = ReadArcadeMachineDefinition(arcadeDefsPath / arcadeDefFilename); - BootablesDb::CClient::GetInstance().RegisterBootable(arcadeDefFilename, "", ""); + BootablesDb::CClient::GetInstance().RegisterBootable(arcadeDefFilename, "", "", BootableUtils::PS2_ARCADE); BootablesDb::CClient::GetInstance().SetTitle(arcadeDefFilename, def.name.c_str()); } catch(const std::exception& exception) diff --git a/Source/ui_shared/BootableUtils.cpp b/Source/ui_shared/BootableUtils.cpp new file mode 100644 index 0000000000..e30ba2912a --- /dev/null +++ b/Source/ui_shared/BootableUtils.cpp @@ -0,0 +1,60 @@ +#include +#include +#include "BootableUtils.h" +#include "DiskUtils.h" + +bool BootableUtils::IsBootableExecutablePath(const fs::path& filePath) +{ + auto extension = filePath.extension().string(); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + return (extension == ".elf"); +} + +bool BootableUtils::IsBootableDiscImagePath(const fs::path& filePath) +{ + const auto& supportedExtensions = DiskUtils::GetSupportedExtensions(); + auto extension = filePath.extension().string(); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + auto extensionIterator = supportedExtensions.find(extension); + return extensionIterator != std::end(supportedExtensions); +} + +bool BootableUtils::IsBootableArcadeDefPath(const fs::path& filePath) +{ + auto extension = filePath.extension().string(); + return (extension == ".arcadedef"); +} + +BootableUtils::BOOTABLE_TYPE BootableUtils::GetBootableType(const fs::path& filePath) +{ + auto extension = filePath.extension().string(); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + + if(extension == ".elf") + return BootableUtils::BOOTABLE_TYPE::PS2_ELF; + if(extension == ".arcadedef") + return BootableUtils::BOOTABLE_TYPE::PS2_ARCADE; + + if(BootableUtils::IsBootableDiscImagePath(filePath)) + { + try + { + auto opticalMedia = DiskUtils::CreateOpticalMediaFromPath(filePath, COpticalMedia::CREATE_AUTO_DISABLE_DL_DETECT); + auto fileSystem = opticalMedia->GetFileSystem(); + auto systemConfigFile = std::unique_ptr(fileSystem->Open("SYSTEM.CNF;1")); + if(!systemConfigFile) return BootableUtils::BOOTABLE_TYPE::UNKNOWN; + + auto systemConfig = DiskUtils::ParseSystemConfigFile(systemConfigFile.get()); + + auto bootItemIterator = systemConfig.find("BOOT2"); + if(bootItemIterator != std::end(systemConfig)) + { + return BootableUtils::BOOTABLE_TYPE::PS2_DISC; + } + } + catch(const std::exception&) + { + } + } + return BootableUtils::BOOTABLE_TYPE::UNKNOWN; +} diff --git a/Source/ui_shared/BootableUtils.h b/Source/ui_shared/BootableUtils.h new file mode 100644 index 0000000000..2dca440e21 --- /dev/null +++ b/Source/ui_shared/BootableUtils.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "filesystem_def.h" + +namespace BootableUtils +{ + enum BOOTABLE_TYPE + { + UNKNOWN = 0, + PS2_DISC = 1 << 0, + PS2_ARCADE = 1 << 1, + PS2_ELF = 1 << 2, + }; + + bool TryGetDiskId(const fs::path&, std::string*); + + bool IsBootableExecutablePath(const fs::path&); + bool IsBootableDiscImagePath(const fs::path&); + bool IsBootableArcadeDefPath(const fs::path&); + + BOOTABLE_TYPE GetBootableType(const fs::path&); +} diff --git a/Source/ui_shared/BootablesDbClient.cpp b/Source/ui_shared/BootablesDbClient.cpp index c60a13f4a3..bc2dd8c12a 100644 --- a/Source/ui_shared/BootablesDbClient.cpp +++ b/Source/ui_shared/BootablesDbClient.cpp @@ -7,7 +7,7 @@ using namespace BootablesDb; -#define DATABASE_VERSION 2 +#define DATABASE_VERSION 3 static const char* g_dbFileName = "bootables.db"; @@ -19,14 +19,15 @@ static const char* g_bootablesTableCreateStatement = " title TEXT DEFAULT ''," " coverUrl TEXT DEFAULT ''," " lastBootedTime INTEGER DEFAULT 0," - " overview TEXT DEFAULT ''" + " overview TEXT DEFAULT ''," + " bootableType INTEGER DEFAULT 0" ")"; CClient::CClient() { m_dbPath = CAppConfig::GetInstance().GetBasePath() / g_dbFileName; - CheckDbVersion(); + UpgradeDb(); m_db = Framework::CSqliteDb(Framework::PathUtils::GetNativeStringFromPath(m_dbPath).c_str(), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); @@ -100,12 +101,13 @@ std::vector CClient::GetBootables(int32_t sortMethod) return bootables; } -void CClient::RegisterBootable(const fs::path& path, const char* title, const char* discId) +void CClient::RegisterBootable(const fs::path& path, const char* title, const char* discId, BootableUtils::BOOTABLE_TYPE bootableType) { - Framework::CSqliteStatement statement(m_db, "INSERT OR IGNORE INTO bootables (path, title, discId) VALUES (?,?,?)"); + Framework::CSqliteStatement statement(m_db, "INSERT OR IGNORE INTO bootables (path, title, discId, bootableType) VALUES (?,?,?,?)"); statement.BindText(1, Framework::PathUtils::GetNativeStringFromPath(path).c_str()); statement.BindText(2, title, true); statement.BindText(3, discId, true); + statement.BindInteger(4, bootableType); statement.StepNoResult(); } @@ -207,30 +209,58 @@ Bootable CClient::ReadBootable(Framework::CSqliteStatement& statement) bootable.overview = reinterpret_cast(sqlite3_column_text(statement, 5)); bootable.lastBootedTime = sqlite3_column_int(statement, 4); bootable.states = GetGameStates(bootable.discId); + bootable.bootableType = static_cast(sqlite3_column_int(statement, 6)); return bootable; } -void CClient::CheckDbVersion() +void CClient::UpgradeDb() { - bool dbExistsAndMatchesVersion = - [&]() { - try - { - auto db = Framework::CSqliteDb(Framework::PathUtils::GetNativeStringFromPath(m_dbPath).c_str(), - SQLITE_OPEN_READONLY); - - Framework::CSqliteStatement statement(db, "PRAGMA user_version"); - statement.StepWithResult(); - int version = sqlite3_column_int(statement, 0); - return (version == DATABASE_VERSION); - } - catch(...) - { - return false; - } - }(); - - if(!dbExistsAndMatchesVersion) + try + { + auto db = Framework::CSqliteDb(Framework::PathUtils::GetNativeStringFromPath(m_dbPath).c_str(), SQLITE_OPEN_READWRITE); + + Framework::CSqliteStatement statement(db, "PRAGMA user_version"); + statement.StepWithResult(); + + auto currentVersion = sqlite3_column_int(statement, 0); + while(currentVersion < DATABASE_VERSION) + { + switch(currentVersion) + { + case 2: + { + Framework::CSqliteStatement statement(db, "ALTER TABLE bootables ADD COLUMN bootableType INTEGER DEFAULT 0"); + statement.StepNoResult(); + + { + Framework::CSqliteStatement statement(db, "UPDATE bootables SET bootableType = ? WHERE path LIKE '%.arcade%';"); + statement.BindInteger(1, BootableUtils::PS2_ARCADE); + statement.StepNoResult(); + } + { + Framework::CSqliteStatement statement(db, "UPDATE bootables SET bootableType = ? WHERE path LIKE '%.elf%';"); + statement.BindInteger(1, BootableUtils::PS2_ELF); + statement.StepNoResult(); + } + { + Framework::CSqliteStatement statement(db, "UPDATE bootables SET bootableType = ? WHERE bootableType = 0;"); + statement.BindInteger(1, BootableUtils::PS2_DISC); + statement.StepNoResult(); + } + + currentVersion = 3; + } + break; + default: + fs::remove(m_dbPath); + return; + } + } + auto query = string_format("PRAGMA user_version = %d", currentVersion); + Framework::CSqliteStatement versionStatement(db, query.c_str()); + versionStatement.StepNoResult(); + } + catch(...) { fs::remove(m_dbPath); } diff --git a/Source/ui_shared/BootablesDbClient.h b/Source/ui_shared/BootablesDbClient.h index 6fea66fdb9..1e568fd424 100644 --- a/Source/ui_shared/BootablesDbClient.h +++ b/Source/ui_shared/BootablesDbClient.h @@ -7,6 +7,7 @@ #include "Singleton.h" #include "sqlite/SqliteDb.h" #include "sqlite/SqliteStatement.h" +#include "BootableUtils.h" namespace BootablesDb { @@ -26,6 +27,7 @@ namespace BootablesDb std::string overview; time_t lastBootedTime = 0; BootableStateList states; + BootableUtils::BOOTABLE_TYPE bootableType = BootableUtils::UNKNOWN; }; class CClient : public CSingleton @@ -35,8 +37,8 @@ namespace BootablesDb enum SORT_METHOD { SORT_METHOD_RECENT, - SORT_METHOD_HOMEBREW, SORT_METHOD_NONE, + SORT_METHOD_HOMEBREW, SORT_METHOD_ARCADE, }; @@ -48,7 +50,7 @@ namespace BootablesDb std::vector GetBootables(int32_t = SORT_METHOD_NONE); BootableStateList GetStates(); - void RegisterBootable(const fs::path&, const char*, const char*); + void RegisterBootable(const fs::path&, const char*, const char*, BootableUtils::BOOTABLE_TYPE); void UnregisterBootable(const fs::path&); void SetDiscId(const fs::path&, const char*); @@ -61,7 +63,7 @@ namespace BootablesDb Bootable ReadBootable(Framework::CSqliteStatement&); BootableStateList GetGameStates(std::string); - void CheckDbVersion(); + void UpgradeDb(); fs::path m_dbPath; Framework::CSqliteDb m_db; diff --git a/Source/ui_shared/BootablesProcesses.cpp b/Source/ui_shared/BootablesProcesses.cpp index bf3afb13e0..d7003b639c 100644 --- a/Source/ui_shared/BootablesProcesses.cpp +++ b/Source/ui_shared/BootablesProcesses.cpp @@ -3,6 +3,7 @@ #include "BootablesProcesses.h" #include "BootablesDbClient.h" #include "TheGamesDbClient.h" +#include "BootableUtils.h" #include "DiskUtils.h" #include "PathUtils.h" #include "StringUtils.h" @@ -38,26 +39,6 @@ static void BootableLog(const char* format, ...) #endif } -bool IsBootableExecutablePath(const fs::path& filePath) -{ - auto extension = StringUtils::ToLower(filePath.extension().string()); - return (extension == ".elf"); -} - -bool IsBootableDiscImagePath(const fs::path& filePath) -{ - const auto& supportedExtensions = DiskUtils::GetSupportedExtensions(); - auto extension = StringUtils::ToLower(filePath.extension().string()); - auto extensionIterator = supportedExtensions.find(extension); - return extensionIterator != std::end(supportedExtensions); -} - -bool IsBootableArcadeDefPath(const fs::path& filePath) -{ - auto extension = filePath.extension().string(); - return (extension == ".arcadedef"); -} - bool DoesBootableExist(const fs::path& filePath) { //TODO: Properly support S3 paths. Also, beware when implementing this because Android @@ -77,16 +58,21 @@ bool TryRegisterBootable(const fs::path& path) { try { - std::string serial; - if( - !BootablesDb::CClient::GetInstance().BootableExists(path) && - !IsBootableExecutablePath(path) && - !(IsBootableDiscImagePath(path) && DiskUtils::TryGetDiskId(path, &serial)) && - !IsBootableArcadeDefPath(path)) + if(BootablesDb::CClient::GetInstance().BootableExists(path)) { return false; } - BootablesDb::CClient::GetInstance().RegisterBootable(path, path.filename().string().c_str(), serial.c_str()); + + BootableUtils::BOOTABLE_TYPE bootableType = BootableUtils::GetBootableType(path); + if(bootableType == BootableUtils::UNKNOWN) + return false; + + std::string serial; + if(bootableType == BootableUtils::PS2_DISC) + if(!DiskUtils::TryGetDiskId(path, &serial)) + return false; + + BootablesDb::CClient::GetInstance().RegisterBootable(path, path.filename().string().c_str(), serial.c_str(), bootableType); return true; } catch(...) diff --git a/Source/ui_shared/BootablesProcesses.h b/Source/ui_shared/BootablesProcesses.h index b70e251ae3..d322f67b2c 100644 --- a/Source/ui_shared/BootablesProcesses.h +++ b/Source/ui_shared/BootablesProcesses.h @@ -3,8 +3,6 @@ #include "filesystem_def.h" #include -bool IsBootableExecutablePath(const fs::path&); -bool IsBootableDiscImagePath(const fs::path&); bool IsBootableArcadeDefPath(const fs::path&); bool DoesBootableExist(const fs::path&); bool TryRegisterBootable(const fs::path&); diff --git a/Source/ui_shared/CMakeLists.txt b/Source/ui_shared/CMakeLists.txt index 4cf00732b9..be101de70d 100644 --- a/Source/ui_shared/CMakeLists.txt +++ b/Source/ui_shared/CMakeLists.txt @@ -60,6 +60,8 @@ set(SHARED_UI_SRC_FILES BootablesDbClient.h BootablesProcesses.cpp BootablesProcesses.h + BootableUtils.cpp + BootableUtils.h TheGamesDbClient.cpp TheGamesDbClient.h StatsManager.cpp