summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar James Rowe2019-01-19 21:03:26 -0700
committerGravatar James Rowe2019-01-20 14:47:35 -0700
commite8bd6b1fcc5abd4813cda08b4921c94ada89509d (patch)
tree1db492eb96d27f4e2ded0aee295d3be579352535 /src
parentMerge pull request #2034 from jroweboy/loading-widget (diff)
downloadyuzu-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.h9
-rw-r--r--src/yuzu/loading_screen.cpp108
-rw-r--r--src/yuzu/loading_screen.h26
-rw-r--r--src/yuzu/loading_screen.ui69
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
12namespace VideoCore { 13namespace VideoCore {
13 14
15enum class LoadCallbackStage {
16 Prepare,
17 Raw,
18 Binary,
19 Complete,
20};
21using DiskResourceLoadCallback = std::function<void(LoadCallbackStage, std::size_t, std::size_t)>;
22
14class RasterizerInterface { 23class RasterizerInterface {
15public: 24public:
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
28LoadingScreen::LoadingScreen(QWidget* parent) 31LoadingScreen::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"(
49QProgressBar {
50 background-color: black;
51}
52QProgressBar::chunk {
53 background-color: white;
54})"},
55 {VideoCore::LoadCallbackStage::Raw,
56 R"(
57QProgressBar {
58 background-color: black;
59 border: 2px solid white;
60 border-radius: 4px;
61 padding: 2px;
62}
63QProgressBar::chunk {
64 background-color: #0ab9e6;
65})"},
66 {VideoCore::LoadCallbackStage::Binary,
67 R"(
68QProgressBar {
69 background-color: black;
70 border: 2px solid white;
71 border-radius: 4px;
72 padding: 2px;
73}
74QProgressBar::chunk {
75 background-color: #ff3c28;
76})"},
77 {VideoCore::LoadCallbackStage::Complete,
78 R"(
79QProgressBar {
80 background-color: black;
81 border: 2px solid white;
82 border-radius: 4px;
83 padding: 2px;
84}
85QProgressBar::chunk {
86 background-color: #ff3c28;
87})"},
88 };
33} 89}
34 90
35LoadingScreen::~LoadingScreen() = default; 91LoadingScreen::~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
62void LoadingScreen::OnLoadProgress(std::size_t value, std::size_t total) { 120void 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
70void LoadingScreen::paintEvent(QPaintEvent* event) { 166void 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 {
19class LoadingScreen; 21class LoadingScreen;
20} 22}
21 23
24namespace VideoCore {
25enum class LoadCallbackStage;
26}
27
22class QBuffer; 28class QBuffer;
23class QByteArray; 29class QByteArray;
24class QMovie; 30class 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); 54signals:
55 void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total);
47 56
48private: 57private:
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
80Q_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;
63font: 75 20pt &quot;Arial&quot;;</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 {
86color: white;
87border: 2px solid white;
88outline-color: black;
89border-radius: 20px;
90}
91QProgressBar::chunk {
92background-color: white;
93border-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;
114font: 75 15pt &quot;Arial&quot;;</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">