diff options
| author | 2019-01-19 21:03:26 -0700 | |
|---|---|---|
| committer | 2019-01-20 14:47:35 -0700 | |
| commit | e8bd6b1fcc5abd4813cda08b4921c94ada89509d (patch) | |
| tree | 1db492eb96d27f4e2ded0aee295d3be579352535 /src | |
| parent | Merge pull request #2034 from jroweboy/loading-widget (diff) | |
| download | yuzu-e8bd6b1fcc5abd4813cda08b4921c94ada89509d.tar.gz yuzu-e8bd6b1fcc5abd4813cda08b4921c94ada89509d.tar.xz yuzu-e8bd6b1fcc5abd4813cda08b4921c94ada89509d.zip | |
QT: Upgrade the Loading Bar to look much better
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/rasterizer_interface.h | 9 | ||||
| -rw-r--r-- | src/yuzu/loading_screen.cpp | 108 | ||||
| -rw-r--r-- | src/yuzu/loading_screen.h | 26 | ||||
| -rw-r--r-- | src/yuzu/loading_screen.ui | 69 |
4 files changed, 201 insertions, 11 deletions
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 06fc59dbe..b2c74afde 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <functional> | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "video_core/engines/fermi_2d.h" | 9 | #include "video_core/engines/fermi_2d.h" |
| 9 | #include "video_core/gpu.h" | 10 | #include "video_core/gpu.h" |
| @@ -11,6 +12,14 @@ | |||
| 11 | 12 | ||
| 12 | namespace VideoCore { | 13 | namespace VideoCore { |
| 13 | 14 | ||
| 15 | enum class LoadCallbackStage { | ||
| 16 | Prepare, | ||
| 17 | Raw, | ||
| 18 | Binary, | ||
| 19 | Complete, | ||
| 20 | }; | ||
| 21 | using DiskResourceLoadCallback = std::function<void(LoadCallbackStage, std::size_t, std::size_t)>; | ||
| 22 | |||
| 14 | class RasterizerInterface { | 23 | class RasterizerInterface { |
| 15 | public: | 24 | public: |
| 16 | virtual ~RasterizerInterface() {} | 25 | virtual ~RasterizerInterface() {} |
diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp index 0f3c4bb6c..617b8c858 100644 --- a/src/yuzu/loading_screen.cpp +++ b/src/yuzu/loading_screen.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <unordered_map> | ||
| 5 | #include <QBuffer> | 6 | #include <QBuffer> |
| 6 | #include <QByteArray> | 7 | #include <QByteArray> |
| 7 | #include <QHBoxLayout> | 8 | #include <QHBoxLayout> |
| @@ -13,10 +14,12 @@ | |||
| 13 | #include <QPixmap> | 14 | #include <QPixmap> |
| 14 | #include <QProgressBar> | 15 | #include <QProgressBar> |
| 15 | #include <QStyleOption> | 16 | #include <QStyleOption> |
| 16 | #include <QWindow> | 17 | #include <QTime> |
| 18 | #include <QtConcurrent/QtConcurrentRun> | ||
| 17 | #include "common/logging/log.h" | 19 | #include "common/logging/log.h" |
| 18 | #include "core/loader/loader.h" | 20 | #include "core/loader/loader.h" |
| 19 | #include "ui_loading_screen.h" | 21 | #include "ui_loading_screen.h" |
| 22 | #include "video_core/rasterizer_interface.h" | ||
| 20 | #include "yuzu/loading_screen.h" | 23 | #include "yuzu/loading_screen.h" |
| 21 | 24 | ||
| 22 | // Mingw seems to not have QMovie at all. If QMovie is missing then use a single frame instead of an | 25 | // Mingw seems to not have QMovie at all. If QMovie is missing then use a single frame instead of an |
| @@ -26,10 +29,63 @@ | |||
| 26 | #endif | 29 | #endif |
| 27 | 30 | ||
| 28 | LoadingScreen::LoadingScreen(QWidget* parent) | 31 | LoadingScreen::LoadingScreen(QWidget* parent) |
| 29 | : QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()) { | 32 | : QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()), |
| 33 | previous_stage(VideoCore::LoadCallbackStage::Complete) { | ||
| 30 | ui->setupUi(this); | 34 | ui->setupUi(this); |
| 31 | // Progress bar is hidden until we have a use for it. | 35 | |
| 32 | ui->progress_bar->hide(); | 36 | connect(this, &LoadingScreen::LoadProgress, this, &LoadingScreen::OnLoadProgress, |
| 37 | Qt::QueuedConnection); | ||
| 38 | qRegisterMetaType<VideoCore::LoadCallbackStage>(); | ||
| 39 | |||
| 40 | stage_translations = { | ||
| 41 | {VideoCore::LoadCallbackStage::Prepare, tr("Loading...")}, | ||
| 42 | {VideoCore::LoadCallbackStage::Raw, tr("Preparing Shaders %1 / %2")}, | ||
| 43 | {VideoCore::LoadCallbackStage::Binary, tr("Loading Shaders %1 / %2")}, | ||
| 44 | {VideoCore::LoadCallbackStage::Complete, tr("Launching...")}, | ||
| 45 | }; | ||
| 46 | progressbar_style = { | ||
| 47 | {VideoCore::LoadCallbackStage::Prepare, | ||
| 48 | R"( | ||
| 49 | QProgressBar { | ||
| 50 | background-color: black; | ||
| 51 | } | ||
| 52 | QProgressBar::chunk { | ||
| 53 | background-color: white; | ||
| 54 | })"}, | ||
| 55 | {VideoCore::LoadCallbackStage::Raw, | ||
| 56 | R"( | ||
| 57 | QProgressBar { | ||
| 58 | background-color: black; | ||
| 59 | border: 2px solid white; | ||
| 60 | border-radius: 4px; | ||
| 61 | padding: 2px; | ||
| 62 | } | ||
| 63 | QProgressBar::chunk { | ||
| 64 | background-color: #0ab9e6; | ||
| 65 | })"}, | ||
| 66 | {VideoCore::LoadCallbackStage::Binary, | ||
| 67 | R"( | ||
| 68 | QProgressBar { | ||
| 69 | background-color: black; | ||
| 70 | border: 2px solid white; | ||
| 71 | border-radius: 4px; | ||
| 72 | padding: 2px; | ||
| 73 | } | ||
| 74 | QProgressBar::chunk { | ||
| 75 | background-color: #ff3c28; | ||
| 76 | })"}, | ||
| 77 | {VideoCore::LoadCallbackStage::Complete, | ||
| 78 | R"( | ||
| 79 | QProgressBar { | ||
| 80 | background-color: black; | ||
| 81 | border: 2px solid white; | ||
| 82 | border-radius: 4px; | ||
| 83 | padding: 2px; | ||
| 84 | } | ||
| 85 | QProgressBar::chunk { | ||
| 86 | background-color: #ff3c28; | ||
| 87 | })"}, | ||
| 88 | }; | ||
| 33 | } | 89 | } |
| 34 | 90 | ||
| 35 | LoadingScreen::~LoadingScreen() = default; | 91 | LoadingScreen::~LoadingScreen() = default; |
| @@ -46,7 +102,7 @@ void LoadingScreen::Prepare(Loader::AppLoader& loader) { | |||
| 46 | std::make_unique<QByteArray>(reinterpret_cast<char*>(buffer.data()), buffer.size()); | 102 | std::make_unique<QByteArray>(reinterpret_cast<char*>(buffer.data()), buffer.size()); |
| 47 | backing_buf = std::make_unique<QBuffer>(backing_mem.get()); | 103 | backing_buf = std::make_unique<QBuffer>(backing_mem.get()); |
| 48 | backing_buf->open(QIODevice::ReadOnly); | 104 | backing_buf->open(QIODevice::ReadOnly); |
| 49 | animation = std::make_unique<QMovie>(backing_buf.get(), QByteArray("GIF")); | 105 | animation = std::make_unique<QMovie>(backing_buf.get(), QByteArray()); |
| 50 | animation->start(); | 106 | animation->start(); |
| 51 | ui->banner->setMovie(animation.get()); | 107 | ui->banner->setMovie(animation.get()); |
| 52 | #endif | 108 | #endif |
| @@ -57,14 +113,54 @@ void LoadingScreen::Prepare(Loader::AppLoader& loader) { | |||
| 57 | map.loadFromData(buffer.data(), buffer.size()); | 113 | map.loadFromData(buffer.data(), buffer.size()); |
| 58 | ui->logo->setPixmap(map); | 114 | ui->logo->setPixmap(map); |
| 59 | } | 115 | } |
| 116 | |||
| 117 | OnLoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 100); | ||
| 60 | } | 118 | } |
| 61 | 119 | ||
| 62 | void LoadingScreen::OnLoadProgress(std::size_t value, std::size_t total) { | 120 | void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, |
| 121 | std::size_t total) { | ||
| 122 | using namespace std::chrono; | ||
| 123 | auto now = high_resolution_clock::now(); | ||
| 124 | // reset the timer if the stage changes | ||
| 125 | if (stage != previous_stage) { | ||
| 126 | ui->progress_bar->setStyleSheet(progressbar_style[stage]); | ||
| 127 | previous_stage = stage; | ||
| 128 | // reset back to fast shader compiling since the stage changed | ||
| 129 | slow_shader_compile_start = false; | ||
| 130 | } | ||
| 131 | // update the max of the progress bar if the number of shaders change | ||
| 63 | if (total != previous_total) { | 132 | if (total != previous_total) { |
| 64 | ui->progress_bar->setMaximum(total); | 133 | ui->progress_bar->setMaximum(total); |
| 65 | previous_total = total; | 134 | previous_total = total; |
| 66 | } | 135 | } |
| 136 | |||
| 137 | QString estimate; | ||
| 138 | // If theres a drastic slowdown in the rate, then display an estimate | ||
| 139 | if (now - previous_time > milliseconds{20}) { | ||
| 140 | if (!slow_shader_compile_start) { | ||
| 141 | slow_shader_start = high_resolution_clock::now(); | ||
| 142 | slow_shader_compile_start = true; | ||
| 143 | slow_shader_first_value = value; | ||
| 144 | } | ||
| 145 | // only calculate an estimate time after a second has passed since stage change | ||
| 146 | auto diff = duration_cast<milliseconds>(now - slow_shader_start); | ||
| 147 | if (diff > seconds{1}) { | ||
| 148 | auto eta_mseconds = | ||
| 149 | static_cast<long>(static_cast<double>(total - slow_shader_first_value) / | ||
| 150 | (value - slow_shader_first_value) * diff.count()); | ||
| 151 | estimate = | ||
| 152 | tr("Estimated Time %1") | ||
| 153 | .arg(QTime(0, 0, 0, 0) | ||
| 154 | .addMSecs(std::max<long>(eta_mseconds - diff.count() + 1000, 1000)) | ||
| 155 | .toString("mm:ss")); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | // update labels and progress bar | ||
| 160 | ui->stage->setText(stage_translations[stage].arg(value).arg(total)); | ||
| 161 | ui->value->setText(estimate); | ||
| 67 | ui->progress_bar->setValue(value); | 162 | ui->progress_bar->setValue(value); |
| 163 | previous_time = now; | ||
| 68 | } | 164 | } |
| 69 | 165 | ||
| 70 | void LoadingScreen::paintEvent(QPaintEvent* event) { | 166 | void LoadingScreen::paintEvent(QPaintEvent* event) { |
diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h index 2a6cf1142..9370ede69 100644 --- a/src/yuzu/loading_screen.h +++ b/src/yuzu/loading_screen.h | |||
| @@ -4,7 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <chrono> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 9 | #include <QString> | ||
| 8 | #include <QWidget> | 10 | #include <QWidget> |
| 9 | 11 | ||
| 10 | #if !QT_CONFIG(movie) | 12 | #if !QT_CONFIG(movie) |
| @@ -19,6 +21,10 @@ namespace Ui { | |||
| 19 | class LoadingScreen; | 21 | class LoadingScreen; |
| 20 | } | 22 | } |
| 21 | 23 | ||
| 24 | namespace VideoCore { | ||
| 25 | enum class LoadCallbackStage; | ||
| 26 | } | ||
| 27 | |||
| 22 | class QBuffer; | 28 | class QBuffer; |
| 23 | class QByteArray; | 29 | class QByteArray; |
| 24 | class QMovie; | 30 | class QMovie; |
| @@ -39,11 +45,14 @@ public: | |||
| 39 | /// used resources such as the logo and banner. | 45 | /// used resources such as the logo and banner. |
| 40 | void Clear(); | 46 | void Clear(); |
| 41 | 47 | ||
| 48 | void OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); | ||
| 49 | |||
| 42 | // In order to use a custom widget with a stylesheet, you need to override the paintEvent | 50 | // In order to use a custom widget with a stylesheet, you need to override the paintEvent |
| 43 | // See https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget | 51 | // See https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget |
| 44 | void paintEvent(QPaintEvent* event) override; | 52 | void paintEvent(QPaintEvent* event) override; |
| 45 | 53 | ||
| 46 | void OnLoadProgress(std::size_t value, std::size_t total); | 54 | signals: |
| 55 | void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); | ||
| 47 | 56 | ||
| 48 | private: | 57 | private: |
| 49 | #ifndef YUZU_QT_MOVIE_MISSING | 58 | #ifndef YUZU_QT_MOVIE_MISSING |
| @@ -53,4 +62,19 @@ private: | |||
| 53 | #endif | 62 | #endif |
| 54 | std::unique_ptr<Ui::LoadingScreen> ui; | 63 | std::unique_ptr<Ui::LoadingScreen> ui; |
| 55 | std::size_t previous_total = 0; | 64 | std::size_t previous_total = 0; |
| 65 | VideoCore::LoadCallbackStage previous_stage; | ||
| 66 | |||
| 67 | // Definitions for the differences in text and styling for each stage | ||
| 68 | std::unordered_map<VideoCore::LoadCallbackStage, const char*> progressbar_style; | ||
| 69 | std::unordered_map<VideoCore::LoadCallbackStage, QString> stage_translations; | ||
| 70 | |||
| 71 | // newly generated shaders are added to the end of the file, so when loading and compiling | ||
| 72 | // shaders, it will start quickly but end slow if new shaders were added since previous launch. | ||
| 73 | // These variables are used to detect the change in speed so we can generate an ETA | ||
| 74 | bool slow_shader_compile_start = false; | ||
| 75 | std::chrono::high_resolution_clock::time_point slow_shader_start; | ||
| 76 | std::chrono::high_resolution_clock::time_point previous_time; | ||
| 77 | std::size_t slow_shader_first_value = 0; | ||
| 56 | }; | 78 | }; |
| 79 | |||
| 80 | Q_DECLARE_METATYPE(VideoCore::LoadCallbackStage); | ||
diff --git a/src/yuzu/loading_screen.ui b/src/yuzu/loading_screen.ui index 00579b670..35d50741e 100644 --- a/src/yuzu/loading_screen.ui +++ b/src/yuzu/loading_screen.ui | |||
| @@ -43,20 +43,81 @@ | |||
| 43 | </widget> | 43 | </widget> |
| 44 | </item> | 44 | </item> |
| 45 | <item> | 45 | <item> |
| 46 | <layout class="QHBoxLayout" name="horizontalLayout"> | 46 | <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,1"> |
| 47 | <item> | 47 | <property name="spacing"> |
| 48 | <number>15</number> | ||
| 49 | </property> | ||
| 50 | <property name="sizeConstraint"> | ||
| 51 | <enum>QLayout::SetNoConstraint</enum> | ||
| 52 | </property> | ||
| 53 | <item alignment="Qt::AlignHCenter|Qt::AlignBottom"> | ||
| 54 | <widget class="QLabel" name="stage"> | ||
| 55 | <property name="sizePolicy"> | ||
| 56 | <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> | ||
| 57 | <horstretch>0</horstretch> | ||
| 58 | <verstretch>0</verstretch> | ||
| 59 | </sizepolicy> | ||
| 60 | </property> | ||
| 61 | <property name="styleSheet"> | ||
| 62 | <string notr="true">background-color: black; color: white; | ||
| 63 | font: 75 20pt "Arial";</string> | ||
| 64 | </property> | ||
| 65 | <property name="text"> | ||
| 66 | <string>Loading Shaders 387 / 1628</string> | ||
| 67 | </property> | ||
| 68 | </widget> | ||
| 69 | </item> | ||
| 70 | <item alignment="Qt::AlignHCenter|Qt::AlignTop"> | ||
| 48 | <widget class="QProgressBar" name="progress_bar"> | 71 | <widget class="QProgressBar" name="progress_bar"> |
| 72 | <property name="sizePolicy"> | ||
| 73 | <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> | ||
| 74 | <horstretch>0</horstretch> | ||
| 75 | <verstretch>0</verstretch> | ||
| 76 | </sizepolicy> | ||
| 77 | </property> | ||
| 78 | <property name="minimumSize"> | ||
| 79 | <size> | ||
| 80 | <width>500</width> | ||
| 81 | <height>40</height> | ||
| 82 | </size> | ||
| 83 | </property> | ||
| 49 | <property name="styleSheet"> | 84 | <property name="styleSheet"> |
| 50 | <string notr="true">font-size: 26px;</string> | 85 | <string notr="true">QProgressBar { |
| 86 | color: white; | ||
| 87 | border: 2px solid white; | ||
| 88 | outline-color: black; | ||
| 89 | border-radius: 20px; | ||
| 90 | } | ||
| 91 | QProgressBar::chunk { | ||
| 92 | background-color: white; | ||
| 93 | border-radius: 15px; | ||
| 94 | }</string> | ||
| 51 | </property> | 95 | </property> |
| 52 | <property name="value"> | 96 | <property name="value"> |
| 53 | <number>0</number> | 97 | <number>50</number> |
| 98 | </property> | ||
| 99 | <property name="textVisible"> | ||
| 100 | <bool>false</bool> | ||
| 54 | </property> | 101 | </property> |
| 55 | <property name="format"> | 102 | <property name="format"> |
| 56 | <string>Loading Shaders %v out of %m</string> | 103 | <string>Loading Shaders %v out of %m</string> |
| 57 | </property> | 104 | </property> |
| 58 | </widget> | 105 | </widget> |
| 59 | </item> | 106 | </item> |
| 107 | <item alignment="Qt::AlignHCenter|Qt::AlignTop"> | ||
| 108 | <widget class="QLabel" name="value"> | ||
| 109 | <property name="toolTip"> | ||
| 110 | <string notr="true"/> | ||
| 111 | </property> | ||
| 112 | <property name="styleSheet"> | ||
| 113 | <string notr="true">background-color: black; color: white; | ||
| 114 | font: 75 15pt "Arial";</string> | ||
| 115 | </property> | ||
| 116 | <property name="text"> | ||
| 117 | <string>Stage 1 of 2. Estimate Time 5m 4s</string> | ||
| 118 | </property> | ||
| 119 | </widget> | ||
| 120 | </item> | ||
| 60 | </layout> | 121 | </layout> |
| 61 | </item> | 122 | </item> |
| 62 | <item alignment="Qt::AlignRight|Qt::AlignBottom"> | 123 | <item alignment="Qt::AlignRight|Qt::AlignBottom"> |