From 26a1d4fc371da91c11cb0a33a2a07cfdc822165b Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Wed, 26 Oct 2022 15:03:55 +0200 Subject: [PATCH] yuzu/compatdb: Rework compatibility submission system Co-Authored-By: Narr the Reg <5944268+german77@users.noreply.github.com> --- src/yuzu/compatdb.cpp | 161 ++++++++++++++-- src/yuzu/compatdb.h | 11 ++ src/yuzu/compatdb.ui | 405 ++++++++++++++++++++++++++++++----------- src/yuzu/game_list_p.h | 12 +- src/yuzu/main.cpp | 14 ++ 5 files changed, 468 insertions(+), 135 deletions(-) diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp index f46fff3406..b03e712481 100644 --- a/src/yuzu/compatdb.cpp +++ b/src/yuzu/compatdb.cpp @@ -15,12 +15,22 @@ CompatDB::CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent) : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), ui{std::make_unique()}, telemetry_session{telemetry_session_} { ui->setupUi(this); - connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Okay, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Bad, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); + + connect(ui->radioButton_GameBoot_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_GameBoot_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Gameplay_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Gameplay_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_NoFreeze_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_NoFreeze_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Complete_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Complete_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Graphical_Major, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Graphical_Minor, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Graphical_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Audio_Major, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Audio_Minor, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Audio_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); connect(&testcase_watcher, &QFutureWatcher::finished, this, &CompatDB::OnTestcaseSubmitted); @@ -30,29 +40,82 @@ CompatDB::~CompatDB() = default; enum class CompatDBPage { Intro = 0, - Selection = 1, - Final = 2, + GameBoot = 1, + GamePlay = 2, + Freeze = 3, + Completion = 4, + Graphical = 5, + Audio = 6, + Final = 7, }; void CompatDB::Submit() { - QButtonGroup* compatibility = new QButtonGroup(this); - compatibility->addButton(ui->radioButton_Perfect, 0); - compatibility->addButton(ui->radioButton_Great, 1); - compatibility->addButton(ui->radioButton_Okay, 2); - compatibility->addButton(ui->radioButton_Bad, 3); - compatibility->addButton(ui->radioButton_IntroMenu, 4); - compatibility->addButton(ui->radioButton_WontBoot, 5); + QButtonGroup* compatibility_GameBoot = new QButtonGroup(this); + compatibility_GameBoot->addButton(ui->radioButton_GameBoot_Yes, 0); + compatibility_GameBoot->addButton(ui->radioButton_GameBoot_No, 1); + + QButtonGroup* compatibility_Gameplay = new QButtonGroup(this); + compatibility_Gameplay->addButton(ui->radioButton_Gameplay_Yes, 0); + compatibility_Gameplay->addButton(ui->radioButton_Gameplay_No, 1); + + QButtonGroup* compatibility_NoFreeze = new QButtonGroup(this); + compatibility_NoFreeze->addButton(ui->radioButton_NoFreeze_Yes, 0); + compatibility_NoFreeze->addButton(ui->radioButton_NoFreeze_No, 1); + + QButtonGroup* compatibility_Complete = new QButtonGroup(this); + compatibility_Complete->addButton(ui->radioButton_Complete_Yes, 0); + compatibility_Complete->addButton(ui->radioButton_Complete_No, 1); + + QButtonGroup* compatibility_Graphical = new QButtonGroup(this); + compatibility_Graphical->addButton(ui->radioButton_Graphical_Major, 0); + compatibility_Graphical->addButton(ui->radioButton_Graphical_Minor, 1); + compatibility_Graphical->addButton(ui->radioButton_Graphical_No, 2); + + QButtonGroup* compatibility_Audio = new QButtonGroup(this); + compatibility_Audio->addButton(ui->radioButton_Audio_Major, 0); + compatibility_Graphical->addButton(ui->radioButton_Audio_Minor, 1); + compatibility_Audio->addButton(ui->radioButton_Audio_No, 2); + + const int compatiblity = static_cast(CalculateCompatibility()); + switch ((static_cast(currentId()))) { - case CompatDBPage::Selection: - if (compatibility->checkedId() == -1) { + case CompatDBPage::Intro: + break; + case CompatDBPage::GameBoot: + if (compatibility_GameBoot->checkedId() == -1) { + button(NextButton)->setEnabled(false); + } + break; + case CompatDBPage::GamePlay: + if (compatibility_Gameplay->checkedId() == -1) { + button(NextButton)->setEnabled(false); + } + break; + case CompatDBPage::Freeze: + if (compatibility_NoFreeze->checkedId() == -1) { + button(NextButton)->setEnabled(false); + } + break; + case CompatDBPage::Completion: + if (compatibility_Complete->checkedId() == -1) { + button(NextButton)->setEnabled(false); + } + break; + case CompatDBPage::Graphical: + if (compatibility_Graphical->checkedId() == -1) { + button(NextButton)->setEnabled(false); + } + break; + case CompatDBPage::Audio: + if (compatibility_Audio->checkedId() == -1) { button(NextButton)->setEnabled(false); } break; case CompatDBPage::Final: back(); - LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); + LOG_INFO(Frontend, "Compatibility Rating: {}", compatiblity); telemetry_session.AddField(Common::Telemetry::FieldType::UserFeedback, "Compatibility", - compatibility->checkedId()); + compatiblity); button(NextButton)->setEnabled(false); button(NextButton)->setText(tr("Submitting")); @@ -66,6 +129,66 @@ void CompatDB::Submit() { } } +int CompatDB::nextId() const { + switch ((static_cast(currentId()))) { + case CompatDBPage::Intro: + return static_cast(CompatDBPage::GameBoot); + case CompatDBPage::GameBoot: + if (ui->radioButton_GameBoot_No->isChecked()) { + return static_cast(CompatDBPage::Final); + } + return static_cast(CompatDBPage::GamePlay); + case CompatDBPage::GamePlay: + if (ui->radioButton_Gameplay_No->isChecked()) { + return static_cast(CompatDBPage::Final); + } + return static_cast(CompatDBPage::Freeze); + case CompatDBPage::Freeze: + if (ui->radioButton_NoFreeze_No->isChecked()) { + return static_cast(CompatDBPage::Final); + } + return static_cast(CompatDBPage::Completion); + case CompatDBPage::Completion: + if (ui->radioButton_Complete_No->isChecked()) { + return static_cast(CompatDBPage::Final); + } + return static_cast(CompatDBPage::Graphical); + case CompatDBPage::Graphical: + return static_cast(CompatDBPage::Audio); + case CompatDBPage::Audio: + return static_cast(CompatDBPage::Final); + case CompatDBPage::Final: + return -1; + default: + LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); + return static_cast(CompatDBPage::Intro); + } +} + +CompatibilityStatus CompatDB::CalculateCompatibility() const { + if (ui->radioButton_GameBoot_No->isChecked()) { + return CompatibilityStatus::WontBoot; + } + + if (ui->radioButton_Gameplay_No->isChecked()) { + return CompatibilityStatus::IntroMenu; + } + + if (ui->radioButton_NoFreeze_No->isChecked() || ui->radioButton_Complete_No->isChecked()) { + return CompatibilityStatus::Ingame; + } + + if (ui->radioButton_Graphical_Major->isChecked() || ui->radioButton_Audio_Major->isChecked()) { + return CompatibilityStatus::Ingame; + } + + if (ui->radioButton_Graphical_Minor->isChecked() || ui->radioButton_Audio_Minor->isChecked()) { + return CompatibilityStatus::Playable; + } + + return CompatibilityStatus::Perfect; +} + void CompatDB::OnTestcaseSubmitted() { if (!testcase_watcher.result()) { QMessageBox::critical(this, tr("Communication error"), diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h index 3252fc47ab..37e11278b9 100644 --- a/src/yuzu/compatdb.h +++ b/src/yuzu/compatdb.h @@ -12,12 +12,22 @@ namespace Ui { class CompatDB; } +enum class CompatibilityStatus { + Perfect = 0, + Playable = 1, + // Unused: Okay = 2, + Ingame = 3, + IntroMenu = 4, + WontBoot = 5, +}; + class CompatDB : public QWizard { Q_OBJECT public: explicit CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent = nullptr); ~CompatDB(); + int nextId() const override; private: QFutureWatcher testcase_watcher; @@ -25,6 +35,7 @@ private: std::unique_ptr ui; void Submit(); + CompatibilityStatus CalculateCompatibility() const; void OnTestcaseSubmitted(); void EnableNext(); diff --git a/src/yuzu/compatdb.ui b/src/yuzu/compatdb.ui index 3ca55eda68..d11669df26 100644 --- a/src/yuzu/compatdb.ui +++ b/src/yuzu/compatdb.ui @@ -58,128 +58,23 @@ - + Report Game Compatibility 1 - - - - - Perfect - - - - - - - <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> - - - true - - - - - - - Great - - - - - - - <html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html> - - - true - - - - - - - Okay - - - - - - - <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> - - - true - - - - - - - Bad - - - - - - - <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> - - - true - - - - - - - Intro/Menu - - - - - - - <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> - - - true - - - - - - - Won't Boot - - - true - - - false - - - - - - - <html><head/><body><p>The game crashes when attempting to startup.</p></body></html> - - - + - + 10 - <html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?</p></body></html> + <html><head/><body><p>Does the game boot?</p></body></html> true @@ -187,7 +82,295 @@ - + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + Yes The game starts to output video or audio + + + + + + + No The game doesn't get past the "Launching..." screen + + + + + + + + Report Game Compatibility + + + 2 + + + + + + Yes The game gets past the intro/menu and into gameplay + + + + + + + No The game crashes or freezes while loading or using the menu + + + + + + + + 10 + + + + <html><head/><body><p>Does the game reach gameplay?</p></body></html> + + + true + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + Report Game Compatibility + + + 3 + + + + + + Yes The game works without crashes + + + + + + + No The game crashes or freezes during gameplay + + + + + + + + 10 + + + + <html><head/><body><p>Does the game work without crashing, freezing or locking up during gameplay?</p></body></html> + + + true + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + Report Game Compatibility + + + 4 + + + + + + Yes The game can be finished without any workarounds + + + + + + + No The game can't progress past a certain area + + + + + + + + 10 + + + + <html><head/><body><p>Is the game completely playable from start to finish?</p></body></html> + + + true + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + Report Game Compatibility + + + 5 + + + + + + Major The game has major graphical errors + + + + + + + Minor The game has minor graphical errors + + + + + + + None Everything is rendered as it looks on the Nintendo Switch + + + + + + + + 10 + + + + <html><head/><body><p>Does the game have any graphical glitches?</p></body></html> + + + true + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + Report Game Compatibility + + + 6 + + + + + + Major The game has major audio errors + + + + + + + Minor The game has minor audio errors + + + + + + + None Audio is played perfectly + + + + + + + + 10 + + + + <html><head/><body><p>Does the game have any audio glitches / missing effects?</p></body></html> + + + true + + + + + Qt::Vertical @@ -206,7 +389,7 @@ Thank you for your submission! - 2 + 7 diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 6198d1e4e9..1800f090f7 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -145,12 +145,14 @@ public: const char* tooltip; }; // clang-format off + const auto ingame_status = + CompatStatus{QStringLiteral("#f2d624"), QT_TR_NOOP("Ingame"), QT_TR_NOOP("Game starts, but crashes or major glitches prevent it from being completed.")}; static const std::map status_data = { - {QStringLiteral("0"), {QStringLiteral("#5c93ed"), QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without\nany workarounds needed.")}}, - {QStringLiteral("1"), {QStringLiteral("#47d35c"), QT_TR_NOOP("Great"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish. May require some\nworkarounds.")}}, - {QStringLiteral("2"), {QStringLiteral("#94b242"), QT_TR_NOOP("Okay"), QT_TR_NOOP("Game functions with major graphical or audio glitches, but game is playable from start to finish with\nworkarounds.")}}, - {QStringLiteral("3"), {QStringLiteral("#f2d624"), QT_TR_NOOP("Bad"), QT_TR_NOOP("Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches\neven with workarounds.")}}, - {QStringLiteral("4"), {QStringLiteral("#FF0000"), QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start\nScreen.")}}, + {QStringLiteral("0"), {QStringLiteral("#5c93ed"), QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game can be played without issues.")}}, + {QStringLiteral("1"), {QStringLiteral("#47d35c"), QT_TR_NOOP("Playable"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish.")}}, + {QStringLiteral("2"), ingame_status}, + {QStringLiteral("3"), ingame_status}, // Fallback for the removed "Okay" category + {QStringLiteral("4"), {QStringLiteral("#FF0000"), QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game loads, but is unable to progress past the Start Screen.")}}, {QStringLiteral("5"), {QStringLiteral("#828282"), QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The game crashes when attempting to startup.")}}, {QStringLiteral("99"), {QStringLiteral("#000000"), QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}, }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7b16d7f7e2..ee7de910fc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2803,6 +2803,20 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex } void GMainWindow::OnMenuReportCompatibility() { + const auto& caps = Common::GetCPUCaps(); + const bool has_fma = caps.fma || caps.fma4; + const auto processor_count = std::thread::hardware_concurrency(); + const bool has_4threads = processor_count == 0 || processor_count >= 4; + const bool has_8gb_ram = Common::GetMemInfo().TotalPhysicalMemory >= 8000000000; + const bool has_broken_vulkan = UISettings::values.has_broken_vulkan; + + if (!has_fma || !has_4threads || !has_8gb_ram || has_broken_vulkan) { + QMessageBox::critical(this, tr("Hardware requirements not met"), + tr("Your system does not meet the recommended hardware requirements. " + "Compatibility reporting has been disabled.")); + return; + } + if (!Settings::values.yuzu_token.GetValue().empty() && !Settings::values.yuzu_username.GetValue().empty()) { CompatDB compatdb{system->TelemetrySession(), this};