summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar James Rowe2019-01-17 00:01:00 -0700
committerGravatar James Rowe2019-01-19 23:34:03 -0700
commit08fcf41b0a3d4e6066cb72f47c3e1d94bb7fc408 (patch)
tree5de343927c3ac46b141ff2675bed7d9c720debc7 /src
parentMerge pull request #2031 from lioncash/priv (diff)
downloadyuzu-08fcf41b0a3d4e6066cb72f47c3e1d94bb7fc408.tar.gz
yuzu-08fcf41b0a3d4e6066cb72f47c3e1d94bb7fc408.tar.xz
yuzu-08fcf41b0a3d4e6066cb72f47c3e1d94bb7fc408.zip
QT Frontend: Add a Loading screen with progressbar
With shader caches on the horizon, one requirement is to provide visible feedback for the progress. The shader cache reportedly takes several minutes to load for large caches that were invalidated, and as such we should provide a loading screen with progress. Adds a loading screen widget that will be shown until the first frame of the game is swapped. This was chosen in case shader caches are not being used, several games still take more than a few seconds to launch and could benefit from a loading screen.
Diffstat (limited to 'src')
-rw-r--r--src/yuzu/CMakeLists.txt5
-rw-r--r--src/yuzu/bootmanager.cpp11
-rw-r--r--src/yuzu/bootmanager.h3
-rw-r--r--src/yuzu/loading_screen.cpp71
-rw-r--r--src/yuzu/loading_screen.h50
-rw-r--r--src/yuzu/loading_screen.ui79
-rw-r--r--src/yuzu/main.cpp26
-rw-r--r--src/yuzu/main.h4
8 files changed, 239 insertions, 10 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 1f852df4b..4cab599b4 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -68,6 +68,8 @@ add_executable(yuzu
68 game_list_p.h 68 game_list_p.h
69 game_list_worker.cpp 69 game_list_worker.cpp
70 game_list_worker.h 70 game_list_worker.h
71 loading_screen.cpp
72 loading_screen.h
71 hotkeys.cpp 73 hotkeys.cpp
72 hotkeys.h 74 hotkeys.h
73 main.cpp 75 main.cpp
@@ -102,9 +104,10 @@ set(UIS
102 configuration/configure_system.ui 104 configuration/configure_system.ui
103 configuration/configure_touchscreen_advanced.ui 105 configuration/configure_touchscreen_advanced.ui
104 configuration/configure_web.ui 106 configuration/configure_web.ui
107 compatdb.ui
105 hotkeys.ui 108 hotkeys.ui
109 loading_screen.ui
106 main.ui 110 main.ui
107 compatdb.ui
108) 111)
109 112
110file(GLOB COMPAT_LIST 113file(GLOB COMPAT_LIST
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 40db7a5e9..f74cb693a 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -3,9 +3,7 @@
3#include <QKeyEvent> 3#include <QKeyEvent>
4#include <QScreen> 4#include <QScreen>
5#include <QWindow> 5#include <QWindow>
6
7#include <fmt/format.h> 6#include <fmt/format.h>
8
9#include "common/microprofile.h" 7#include "common/microprofile.h"
10#include "common/scm_rev.h" 8#include "common/scm_rev.h"
11#include "core/core.h" 9#include "core/core.h"
@@ -17,6 +15,7 @@
17#include "video_core/renderer_base.h" 15#include "video_core/renderer_base.h"
18#include "video_core/video_core.h" 16#include "video_core/video_core.h"
19#include "yuzu/bootmanager.h" 17#include "yuzu/bootmanager.h"
18#include "yuzu/main.h"
20 19
21EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {} 20EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {}
22 21
@@ -114,6 +113,8 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
114 113
115 InputCommon::Init(); 114 InputCommon::Init();
116 InputCommon::StartJoystickEventHandler(); 115 InputCommon::StartJoystickEventHandler();
116 connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent),
117 &GMainWindow::OnLoadComplete);
117} 118}
118 119
119GRenderWindow::~GRenderWindow() { 120GRenderWindow::~GRenderWindow() {
@@ -141,6 +142,10 @@ void GRenderWindow::SwapBuffers() {
141 child->makeCurrent(); 142 child->makeCurrent();
142 143
143 child->swapBuffers(); 144 child->swapBuffers();
145 if (!first_frame) {
146 emit FirstFrameDisplayed();
147 first_frame = true;
148 }
144} 149}
145 150
146void GRenderWindow::MakeCurrent() { 151void GRenderWindow::MakeCurrent() {
@@ -309,6 +314,8 @@ void GRenderWindow::InitRenderTarget() {
309 delete layout(); 314 delete layout();
310 } 315 }
311 316
317 first_frame = false;
318
312 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, 319 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
313 // WA_DontShowOnScreen, WA_DeleteOnClose 320 // WA_DontShowOnScreen, WA_DeleteOnClose
314 QGLFormat fmt; 321 QGLFormat fmt;
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index 4e3028215..d1f37e503 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -152,6 +152,7 @@ public slots:
152signals: 152signals:
153 /// Emitted when the window is closed 153 /// Emitted when the window is closed
154 void Closed(); 154 void Closed();
155 void FirstFrameDisplayed();
155 156
156private: 157private:
157 std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const; 158 std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const;
@@ -171,6 +172,8 @@ private:
171 /// Temporary storage of the screenshot taken 172 /// Temporary storage of the screenshot taken
172 QImage screenshot_image; 173 QImage screenshot_image;
173 174
175 bool first_frame = false;
176
174protected: 177protected:
175 void showEvent(QShowEvent* event) override; 178 void showEvent(QShowEvent* event) override;
176}; 179};
diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp
new file mode 100644
index 000000000..f2d3214f6
--- /dev/null
+++ b/src/yuzu/loading_screen.cpp
@@ -0,0 +1,71 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QBuffer>
6#include <QByteArray>
7#include <QHBoxLayout>
8#include <QIODevice>
9#include <QImage>
10#include <QLabel>
11#include <QMovie>
12#include <QPainter>
13#include <QPalette>
14#include <QPixmap>
15#include <QProgressBar>
16#include <QStyleOption>
17#include <QWindow>
18#include "common/logging/log.h"
19#include "core/loader/loader.h"
20#include "ui_loading_screen.h"
21#include "yuzu/loading_screen.h"
22
23LoadingScreen::LoadingScreen(QWidget* parent)
24 : QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()) {
25 ui->setupUi(this);
26 // Progress bar is hidden until we have a use for it.
27 ui->progress_bar->hide();
28}
29
30LoadingScreen::~LoadingScreen() = default;
31
32void LoadingScreen::Prepare(Loader::AppLoader& loader) {
33 std::vector<u8> buffer;
34 if (loader.ReadBanner(buffer) == Loader::ResultStatus::Success) {
35 backing_mem =
36 std::make_unique<QByteArray>(reinterpret_cast<char*>(buffer.data()), buffer.size());
37 backing_buf = std::make_unique<QBuffer>(backing_mem.get());
38 backing_buf->open(QIODevice::ReadOnly);
39 animation = std::make_unique<QMovie>(backing_buf.get(), QByteArray("GIF"));
40 animation->start();
41 ui->banner->setMovie(animation.get());
42 buffer.clear();
43 }
44 if (loader.ReadLogo(buffer) == Loader::ResultStatus::Success) {
45 QPixmap map;
46 map.loadFromData(buffer.data(), buffer.size());
47 ui->logo->setPixmap(map);
48 }
49}
50
51void LoadingScreen::OnLoadProgress(std::size_t value, std::size_t total) {
52 if (total != previous_total) {
53 ui->progress_bar->setMaximum(total);
54 previous_total = total;
55 }
56 ui->progress_bar->setValue(value);
57}
58
59void LoadingScreen::paintEvent(QPaintEvent* event) {
60 QStyleOption opt;
61 opt.init(this);
62 QPainter p(this);
63 style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
64 QWidget::paintEvent(event);
65}
66
67void LoadingScreen::Clear() {
68 animation.reset();
69 backing_buf.reset();
70 backing_mem.reset();
71}
diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h
new file mode 100644
index 000000000..ffcaa260d
--- /dev/null
+++ b/src/yuzu/loading_screen.h
@@ -0,0 +1,50 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QWidget>
9
10namespace Loader {
11class AppLoader;
12}
13
14namespace Ui {
15class LoadingScreen;
16}
17
18class QBuffer;
19class QByteArray;
20class QMovie;
21
22class LoadingScreen : public QWidget {
23 Q_OBJECT
24
25public:
26 explicit LoadingScreen(QWidget* parent = nullptr);
27
28 ~LoadingScreen();
29
30 /// Call before showing the loading screen to load the widgets with the logo and banner for the
31 /// currently loaded application.
32 void Prepare(Loader::AppLoader& loader);
33
34 /// After the loading screen is hidden, the owner of this class can call this to clean up any
35 /// used resources such as the logo and banner.
36 void Clear();
37
38 // In order to use a custom widget with a stylesheet, you need to override the paintEvent
39 // See https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget
40 void paintEvent(QPaintEvent* event) override;
41
42 void OnLoadProgress(std::size_t value, std::size_t total);
43
44private:
45 std::unique_ptr<QMovie> animation;
46 std::unique_ptr<QBuffer> backing_buf;
47 std::unique_ptr<QByteArray> backing_mem;
48 std::unique_ptr<Ui::LoadingScreen> ui;
49 std::size_t previous_total = 0;
50};
diff --git a/src/yuzu/loading_screen.ui b/src/yuzu/loading_screen.ui
new file mode 100644
index 000000000..00579b670
--- /dev/null
+++ b/src/yuzu/loading_screen.ui
@@ -0,0 +1,79 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>LoadingScreen</class>
4 <widget class="QWidget" name="LoadingScreen">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>746</width>
10 <height>495</height>
11 </rect>
12 </property>
13 <property name="styleSheet">
14 <string notr="true">background-color: rgb(0, 0, 0);</string>
15 </property>
16 <layout class="QVBoxLayout">
17 <property name="spacing">
18 <number>0</number>
19 </property>
20 <property name="leftMargin">
21 <number>0</number>
22 </property>
23 <property name="topMargin">
24 <number>0</number>
25 </property>
26 <property name="rightMargin">
27 <number>0</number>
28 </property>
29 <property name="bottomMargin">
30 <number>0</number>
31 </property>
32 <item>
33 <widget class="QLabel" name="logo">
34 <property name="text">
35 <string/>
36 </property>
37 <property name="alignment">
38 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
39 </property>
40 <property name="margin">
41 <number>30</number>
42 </property>
43 </widget>
44 </item>
45 <item>
46 <layout class="QHBoxLayout" name="horizontalLayout">
47 <item>
48 <widget class="QProgressBar" name="progress_bar">
49 <property name="styleSheet">
50 <string notr="true">font-size: 26px;</string>
51 </property>
52 <property name="value">
53 <number>0</number>
54 </property>
55 <property name="format">
56 <string>Loading Shaders %v out of %m</string>
57 </property>
58 </widget>
59 </item>
60 </layout>
61 </item>
62 <item alignment="Qt::AlignRight|Qt::AlignBottom">
63 <widget class="QLabel" name="banner">
64 <property name="styleSheet">
65 <string notr="true">background-color: black;</string>
66 </property>
67 <property name="text">
68 <string/>
69 </property>
70 <property name="margin">
71 <number>30</number>
72 </property>
73 </widget>
74 </item>
75 </layout>
76 </widget>
77 <resources/>
78 <connections/>
79</ui>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f564de994..68bfa23ab 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -92,6 +92,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
92#include "yuzu/game_list.h" 92#include "yuzu/game_list.h"
93#include "yuzu/game_list_p.h" 93#include "yuzu/game_list_p.h"
94#include "yuzu/hotkeys.h" 94#include "yuzu/hotkeys.h"
95#include "yuzu/loading_screen.h"
95#include "yuzu/main.h" 96#include "yuzu/main.h"
96#include "yuzu/ui_settings.h" 97#include "yuzu/ui_settings.h"
97 98
@@ -411,6 +412,10 @@ void GMainWindow::InitializeWidgets() {
411 game_list = new GameList(vfs, this); 412 game_list = new GameList(vfs, this);
412 ui.horizontalLayout->addWidget(game_list); 413 ui.horizontalLayout->addWidget(game_list);
413 414
415 loading_screen = new LoadingScreen(this);
416 loading_screen->hide();
417 ui.horizontalLayout->addWidget(loading_screen);
418
414 // Create status bar 419 // Create status bar
415 message_label = new QLabel(); 420 message_label = new QLabel();
416 // Configured separately for left alignment 421 // Configured separately for left alignment
@@ -897,8 +902,9 @@ void GMainWindow::BootGame(const QString& filename) {
897 .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, 902 .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc,
898 QString::fromStdString(title_name))); 903 QString::fromStdString(title_name)));
899 904
900 render_window->show(); 905 loading_screen->Prepare(Core::System::GetInstance().GetAppLoader());
901 render_window->setFocus(); 906 loading_screen->show();
907 loading_screen->setFocus();
902 908
903 emulation_running = true; 909 emulation_running = true;
904 if (ui.action_Fullscreen->isChecked()) { 910 if (ui.action_Fullscreen->isChecked()) {
@@ -932,6 +938,8 @@ void GMainWindow::ShutdownGame() {
932 ui.action_Load_Amiibo->setEnabled(false); 938 ui.action_Load_Amiibo->setEnabled(false);
933 ui.action_Capture_Screenshot->setEnabled(false); 939 ui.action_Capture_Screenshot->setEnabled(false);
934 render_window->hide(); 940 render_window->hide();
941 loading_screen->hide();
942 loading_screen->Clear();
935 game_list->show(); 943 game_list->show();
936 game_list->setFilterFocus(); 944 game_list->setFilterFocus();
937 setWindowTitle(QString("yuzu %1| %2-%3") 945 setWindowTitle(QString("yuzu %1| %2-%3")
@@ -1505,6 +1513,13 @@ void GMainWindow::OnStopGame() {
1505 ShutdownGame(); 1513 ShutdownGame();
1506} 1514}
1507 1515
1516void GMainWindow::OnLoadComplete() {
1517 loading_screen->hide();
1518 loading_screen->Clear();
1519 render_window->show();
1520 render_window->setFocus();
1521}
1522
1508void GMainWindow::OnMenuReportCompatibility() { 1523void GMainWindow::OnMenuReportCompatibility() {
1509 if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { 1524 if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) {
1510 CompatDB compatdb{this}; 1525 CompatDB compatdb{this};
@@ -1771,9 +1786,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
1771 this, tr("Confirm Key Rederivation"), 1786 this, tr("Confirm Key Rederivation"),
1772 tr("You are about to force rederive all of your keys. \nIf you do not know what this " 1787 tr("You are about to force rederive all of your keys. \nIf you do not know what this "
1773 "means or what you are doing, \nthis is a potentially destructive action. \nPlease " 1788 "means or what you are doing, \nthis is a potentially destructive action. \nPlease "
1774 "make " 1789 "make sure this is what you want \nand optionally make backups.\n\nThis will delete "
1775 "sure this is what you want \nand optionally make backups.\n\nThis will delete your " 1790 "your autogenerated key files and re-run the key derivation module."),
1776 "autogenerated key files and re-run the key derivation module."),
1777 QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel}); 1791 QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel});
1778 1792
1779 if (res == QMessageBox::Cancel) 1793 if (res == QMessageBox::Cancel)
@@ -1818,7 +1832,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
1818 errors + 1832 errors +
1819 tr("<br><br>You can get all of these and dump all of your games easily by " 1833 tr("<br><br>You can get all of these and dump all of your games easily by "
1820 "following <a href='https://yuzu-emu.org/help/quickstart/'>the " 1834 "following <a href='https://yuzu-emu.org/help/quickstart/'>the "
1821 "quickstart guide</a>. Alternatively, you can use another method of dumping " 1835 "quickstart guide</a>. Alternatively, you can use another method of dumping"
1822 "to obtain all of your keys.")); 1836 "to obtain all of your keys."));
1823 } 1837 }
1824 1838
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 2d705ad54..e07c892cf 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -25,6 +25,7 @@ class GImageInfo;
25class GraphicsBreakPointsWidget; 25class GraphicsBreakPointsWidget;
26class GraphicsSurfaceWidget; 26class GraphicsSurfaceWidget;
27class GRenderWindow; 27class GRenderWindow;
28class LoadingScreen;
28class MicroProfileDialog; 29class MicroProfileDialog;
29class ProfilerWidget; 30class ProfilerWidget;
30class QLabel; 31class QLabel;
@@ -109,10 +110,10 @@ signals:
109 void WebBrowserFinishedBrowsing(); 110 void WebBrowserFinishedBrowsing();
110 111
111public slots: 112public slots:
113 void OnLoadComplete();
112 void ProfileSelectorSelectProfile(); 114 void ProfileSelectorSelectProfile();
113 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); 115 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
114 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); 116 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
115
116 void WebBrowserOpenPage(std::string_view filename, std::string_view arguments); 117 void WebBrowserOpenPage(std::string_view filename, std::string_view arguments);
117 118
118private: 119private:
@@ -212,6 +213,7 @@ private:
212 213
213 GRenderWindow* render_window; 214 GRenderWindow* render_window;
214 GameList* game_list; 215 GameList* game_list;
216 LoadingScreen* loading_screen;
215 217
216 // Status bar elements 218 // Status bar elements
217 QLabel* message_label = nullptr; 219 QLabel* message_label = nullptr;