diff options
Diffstat (limited to 'src/yuzu')
-rw-r--r-- | src/yuzu/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/yuzu/applets/web_browser.cpp | 6 | ||||
-rw-r--r-- | src/yuzu/applets/web_browser.h | 9 | ||||
-rw-r--r-- | src/yuzu/bootmanager.cpp | 11 | ||||
-rw-r--r-- | src/yuzu/bootmanager.h | 3 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_debug.cpp | 1 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_dialog.cpp | 1 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 1 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_input_player.h | 8 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_per_general.cpp | 1 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_per_general.h | 6 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_system.cpp | 12 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_touchscreen_advanced.h | 2 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_web.cpp | 11 | ||||
-rw-r--r-- | src/yuzu/loading_screen.cpp | 213 | ||||
-rw-r--r-- | src/yuzu/loading_screen.h | 92 | ||||
-rw-r--r-- | src/yuzu/loading_screen.ui | 161 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 49 | ||||
-rw-r--r-- | src/yuzu/main.h | 4 |
19 files changed, 547 insertions, 49 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 game_list_p.h game_list_worker.cpp game_list_worker.h + loading_screen.cpp + loading_screen.h hotkeys.cpp hotkeys.h main.cpp @@ -102,9 +104,10 @@ set(UIS configuration/configure_system.ui configuration/configure_touchscreen_advanced.ui configuration/configure_web.ui + compatdb.ui hotkeys.ui + loading_screen.ui main.ui - compatdb.ui ) file(GLOB COMPAT_LIST diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp index c59b7ade1..6a9138d53 100644 --- a/src/yuzu/applets/web_browser.cpp +++ b/src/yuzu/applets/web_browser.cpp @@ -86,9 +86,9 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { QtWebBrowser::~QtWebBrowser() = default; void QtWebBrowser::OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, - std::function<void()> finished_callback) const { - this->unpack_romfs_callback = unpack_romfs_callback; - this->finished_callback = finished_callback; + std::function<void()> finished_callback) { + this->unpack_romfs_callback = std::move(unpack_romfs_callback); + this->finished_callback = std::move(finished_callback); const auto index = url.find('?'); if (index == std::string::npos) { diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h index bba273767..1a3d67353 100644 --- a/src/yuzu/applets/web_browser.h +++ b/src/yuzu/applets/web_browser.h @@ -38,16 +38,15 @@ public: ~QtWebBrowser() override; void OpenPage(std::string_view url, std::function<void()> unpack_romfs_callback, - std::function<void()> finished_callback) const override; + std::function<void()> finished_callback) override; signals: void MainWindowOpenPage(std::string_view filename, std::string_view additional_args) const; -public slots: +private: void MainWindowUnpackRomFS(); void MainWindowFinishedBrowsing(); -private: - mutable std::function<void()> unpack_romfs_callback; - mutable std::function<void()> finished_callback; + std::function<void()> unpack_romfs_callback; + std::function<void()> finished_callback; }; 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 @@ #include <QKeyEvent> #include <QScreen> #include <QWindow> - #include <fmt/format.h> - #include "common/microprofile.h" #include "common/scm_rev.h" #include "core/core.h" @@ -17,6 +15,7 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" #include "yuzu/bootmanager.h" +#include "yuzu/main.h" EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {} @@ -114,6 +113,8 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) InputCommon::Init(); InputCommon::StartJoystickEventHandler(); + connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent), + &GMainWindow::OnLoadComplete); } GRenderWindow::~GRenderWindow() { @@ -141,6 +142,10 @@ void GRenderWindow::SwapBuffers() { child->makeCurrent(); child->swapBuffers(); + if (!first_frame) { + emit FirstFrameDisplayed(); + first_frame = true; + } } void GRenderWindow::MakeCurrent() { @@ -309,6 +314,8 @@ void GRenderWindow::InitRenderTarget() { delete layout(); } + first_frame = false; + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, // WA_DontShowOnScreen, WA_DeleteOnClose 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: signals: /// Emitted when the window is closed void Closed(); + void FirstFrameDisplayed(); private: std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const; @@ -171,6 +172,8 @@ private: /// Temporary storage of the screenshot taken QImage screenshot_image; + bool first_frame = false; + protected: void showEvent(QShowEvent* event) override; }; diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index aa7de7b54..550cf9dca 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -7,7 +7,6 @@ #include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/filter.h" -#include "common/logging/log.h" #include "core/core.h" #include "core/settings.h" #include "ui_configure_debug.h" diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index d802443d0..777050405 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -39,6 +39,7 @@ void ConfigureDialog::applyConfiguration() { ui->debugTab->applyConfiguration(); ui->webTab->applyConfiguration(); Settings::Apply(); + Settings::LogSettings(); } void ConfigureDialog::PopulateSelectionList() { diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index ba2b32c4f..c5a245ebe 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -7,6 +7,7 @@ #include <utility> #include <QColorDialog> #include <QGridLayout> +#include <QKeyEvent> #include <QMenu> #include <QMessageBox> #include <QTimer> diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 7a53f6715..ade8d4435 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -11,17 +11,21 @@ #include <string> #include <QDialog> -#include <QKeyEvent> #include "common/param_package.h" #include "core/settings.h" -#include "input_common/main.h" #include "ui_configure_input.h" +class QKeyEvent; class QPushButton; class QString; class QTimer; +namespace InputCommon::Polling { +class DevicePoller; +enum class DeviceType; +} // namespace InputCommon::Polling + namespace Ui { class ConfigureInputPlayer; } diff --git a/src/yuzu/configuration/configure_per_general.cpp b/src/yuzu/configuration/configure_per_general.cpp index e13d2eac8..022b94609 100644 --- a/src/yuzu/configuration/configure_per_general.cpp +++ b/src/yuzu/configuration/configure_per_general.cpp @@ -8,7 +8,6 @@ #include <QHeaderView> #include <QMenu> -#include <QMessageBox> #include <QStandardItemModel> #include <QString> #include <QTimer> diff --git a/src/yuzu/configuration/configure_per_general.h b/src/yuzu/configuration/configure_per_general.h index a4494446c..f8a7d5326 100644 --- a/src/yuzu/configuration/configure_per_general.h +++ b/src/yuzu/configuration/configure_per_general.h @@ -7,16 +7,16 @@ #include <memory> #include <vector> -#include <QKeyEvent> +#include <QDialog> #include <QList> -#include <QWidget> #include "core/file_sys/vfs_types.h" -class QTreeView; class QGraphicsScene; class QStandardItem; class QStandardItemModel; +class QTreeView; +class QVBoxLayout; namespace Ui { class ConfigurePerGameGeneral; diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 94e27349d..10645a2b3 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -2,23 +2,19 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <algorithm> +#include <array> +#include <chrono> +#include <optional> + #include <QFileDialog> #include <QGraphicsItem> -#include <QGraphicsScene> -#include <QHeaderView> #include <QMessageBox> -#include <QStandardItemModel> -#include <QTreeView> -#include <QVBoxLayout> #include "common/assert.h" #include "common/file_util.h" -#include "common/string_util.h" #include "core/core.h" #include "core/settings.h" #include "ui_configure_system.h" #include "yuzu/configuration/configure_system.h" -#include "yuzu/util/limitable_input_dialog.h" namespace { constexpr std::array<int, 12> days_in_month = {{ diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.h b/src/yuzu/configuration/configure_touchscreen_advanced.h index 41cd255fb..3d0772c87 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.h +++ b/src/yuzu/configuration/configure_touchscreen_advanced.h @@ -6,8 +6,6 @@ #include <memory> #include <QDialog> -#include <QWidget> -#include "yuzu/configuration/config.h" namespace Ui { class ConfigureTouchscreenAdvanced; diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index 3c2ccb76f..18566d028 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -89,12 +89,11 @@ void ConfigureWeb::OnLoginChanged() { void ConfigureWeb::VerifyLogin() { ui->button_verify_login->setDisabled(true); - ui->button_verify_login->setText(tr("Verifying")); - verify_watcher.setFuture( - QtConcurrent::run([this, username = ui->edit_username->text().toStdString(), - token = ui->edit_token->text().toStdString()]() { - return Core::VerifyLogin(username, token); - })); + ui->button_verify_login->setText(tr("Verifying...")); + verify_watcher.setFuture(QtConcurrent::run([username = ui->edit_username->text().toStdString(), + token = ui->edit_token->text().toStdString()] { + return Core::VerifyLogin(username, token); + })); } void ConfigureWeb::OnLoginVerified() { diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp new file mode 100644 index 000000000..907aac4f1 --- /dev/null +++ b/src/yuzu/loading_screen.cpp @@ -0,0 +1,213 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <unordered_map> +#include <QBuffer> +#include <QByteArray> +#include <QGraphicsOpacityEffect> +#include <QHBoxLayout> +#include <QIODevice> +#include <QImage> +#include <QLabel> +#include <QPainter> +#include <QPalette> +#include <QPixmap> +#include <QProgressBar> +#include <QPropertyAnimation> +#include <QStyleOption> +#include <QTime> +#include <QtConcurrent/QtConcurrentRun> +#include "common/logging/log.h" +#include "core/loader/loader.h" +#include "ui_loading_screen.h" +#include "video_core/rasterizer_interface.h" +#include "yuzu/loading_screen.h" + +// Mingw seems to not have QMovie at all. If QMovie is missing then use a single frame instead of an +// showing the full animation +#if !YUZU_QT_MOVIE_MISSING +#include <QMovie> +#endif + +constexpr const char PROGRESSBAR_STYLE_PREPARE[] = R"( +QProgressBar {} +QProgressBar::chunk {})"; + +constexpr const char PROGRESSBAR_STYLE_DECOMPILE[] = R"( +QProgressBar { + background-color: black; + border: 2px solid white; + border-radius: 4px; + padding: 2px; +} +QProgressBar::chunk { + background-color: #0ab9e6; +})"; + +constexpr const char PROGRESSBAR_STYLE_BUILD[] = R"( +QProgressBar { + background-color: black; + border: 2px solid white; + border-radius: 4px; + padding: 2px; +} +QProgressBar::chunk { + background-color: #ff3c28; +})"; + +constexpr const char PROGRESSBAR_STYLE_COMPLETE[] = R"( +QProgressBar { + background-color: #0ab9e6; + border: 2px solid white; + border-radius: 4px; + padding: 2px; +} +QProgressBar::chunk { + background-color: #ff3c28; +})"; + +LoadingScreen::LoadingScreen(QWidget* parent) + : QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()), + previous_stage(VideoCore::LoadCallbackStage::Complete) { + ui->setupUi(this); + setMinimumSize(1280, 720); + + // Create a fade out effect to hide this loading screen widget. + // When fading opacity, it will fade to the parent widgets background color, which is why we + // create an internal widget named fade_widget that we use the effect on, while keeping the + // loading screen widget's background color black. This way we can create a fade to black effect + opacity_effect = new QGraphicsOpacityEffect(this); + opacity_effect->setOpacity(1); + ui->fade_parent->setGraphicsEffect(opacity_effect); + fadeout_animation = std::make_unique<QPropertyAnimation>(opacity_effect, "opacity"); + fadeout_animation->setDuration(500); + fadeout_animation->setStartValue(1); + fadeout_animation->setEndValue(0); + fadeout_animation->setEasingCurve(QEasingCurve::OutBack); + + // After the fade completes, hide the widget and reset the opacity + connect(fadeout_animation.get(), &QPropertyAnimation::finished, [this] { + hide(); + opacity_effect->setOpacity(1); + emit Hidden(); + }); + connect(this, &LoadingScreen::LoadProgress, this, &LoadingScreen::OnLoadProgress, + Qt::QueuedConnection); + qRegisterMetaType<VideoCore::LoadCallbackStage>(); + + stage_translations = { + {VideoCore::LoadCallbackStage::Prepare, tr("Loading...")}, + {VideoCore::LoadCallbackStage::Decompile, tr("Preparing Shaders %1 / %2")}, + {VideoCore::LoadCallbackStage::Build, tr("Loading Shaders %1 / %2")}, + {VideoCore::LoadCallbackStage::Complete, tr("Launching...")}, + }; + progressbar_style = { + {VideoCore::LoadCallbackStage::Prepare, PROGRESSBAR_STYLE_PREPARE}, + {VideoCore::LoadCallbackStage::Decompile, PROGRESSBAR_STYLE_DECOMPILE}, + {VideoCore::LoadCallbackStage::Build, PROGRESSBAR_STYLE_BUILD}, + {VideoCore::LoadCallbackStage::Complete, PROGRESSBAR_STYLE_COMPLETE}, + }; +} + +LoadingScreen::~LoadingScreen() = default; + +void LoadingScreen::Prepare(Loader::AppLoader& loader) { + std::vector<u8> buffer; + if (loader.ReadBanner(buffer) == Loader::ResultStatus::Success) { +#ifdef YUZU_QT_MOVIE_MISSING + QPixmap map; + map.loadFromData(buffer.data(), buffer.size()); + ui->banner->setPixmap(map); +#else + backing_mem = std::make_unique<QByteArray>(reinterpret_cast<char*>(buffer.data()), + static_cast<int>(buffer.size())); + backing_buf = std::make_unique<QBuffer>(backing_mem.get()); + backing_buf->open(QIODevice::ReadOnly); + animation = std::make_unique<QMovie>(backing_buf.get(), QByteArray()); + animation->start(); + ui->banner->setMovie(animation.get()); +#endif + buffer.clear(); + } + if (loader.ReadLogo(buffer) == Loader::ResultStatus::Success) { + QPixmap map; + map.loadFromData(buffer.data(), static_cast<uint>(buffer.size())); + ui->logo->setPixmap(map); + } + + slow_shader_compile_start = false; + OnLoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); +} + +void LoadingScreen::OnLoadComplete() { + fadeout_animation->start(QPropertyAnimation::KeepWhenStopped); +} + +void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, + std::size_t total) { + using namespace std::chrono; + auto now = high_resolution_clock::now(); + // reset the timer if the stage changes + if (stage != previous_stage) { + ui->progress_bar->setStyleSheet(progressbar_style[stage]); + // Hide the progress bar during the prepare stage + if (stage == VideoCore::LoadCallbackStage::Prepare) { + ui->progress_bar->hide(); + } else { + ui->progress_bar->show(); + } + previous_stage = stage; + // reset back to fast shader compiling since the stage changed + slow_shader_compile_start = false; + } + // update the max of the progress bar if the number of shaders change + if (total != previous_total) { + ui->progress_bar->setMaximum(static_cast<int>(total)); + previous_total = total; + } + + QString estimate; + // If theres a drastic slowdown in the rate, then display an estimate + if (now - previous_time > milliseconds{50} || slow_shader_compile_start) { + if (!slow_shader_compile_start) { + slow_shader_start = high_resolution_clock::now(); + slow_shader_compile_start = true; + slow_shader_first_value = value; + } + // only calculate an estimate time after a second has passed since stage change + auto diff = duration_cast<milliseconds>(now - slow_shader_start); + if (diff > seconds{1}) { + auto eta_mseconds = + static_cast<long>(static_cast<double>(total - slow_shader_first_value) / + (value - slow_shader_first_value) * diff.count()); + estimate = + tr("Estimated Time %1") + .arg(QTime(0, 0, 0, 0) + .addMSecs(std::max<long>(eta_mseconds - diff.count() + 1000, 1000)) + .toString("mm:ss")); + } + } + + // update labels and progress bar + ui->stage->setText(stage_translations[stage].arg(value).arg(total)); + ui->value->setText(estimate); + ui->progress_bar->setValue(static_cast<int>(value)); + previous_time = now; +} + +void LoadingScreen::paintEvent(QPaintEvent* event) { + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + QWidget::paintEvent(event); +} + +void LoadingScreen::Clear() { +#ifndef YUZU_QT_MOVIE_MISSING + animation.reset(); + backing_buf.reset(); + backing_mem.reset(); +#endif +} diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h new file mode 100644 index 000000000..801d08e1a --- /dev/null +++ b/src/yuzu/loading_screen.h @@ -0,0 +1,92 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <chrono> +#include <memory> +#include <QString> +#include <QWidget> + +#if !QT_CONFIG(movie) +#define YUZU_QT_MOVIE_MISSING 1 +#endif + +namespace Loader { +class AppLoader; +} + +namespace Ui { +class LoadingScreen; +} + +namespace VideoCore { +enum class LoadCallbackStage; +} + +class QBuffer; +class QByteArray; +class QGraphicsOpacityEffect; +class QMovie; +class QPropertyAnimation; + +class LoadingScreen : public QWidget { + Q_OBJECT + +public: + explicit LoadingScreen(QWidget* parent = nullptr); + + ~LoadingScreen(); + + /// Call before showing the loading screen to load the widgets with the logo and banner for the + /// currently loaded application. + void Prepare(Loader::AppLoader& loader); + + /// After the loading screen is hidden, the owner of this class can call this to clean up any + /// used resources such as the logo and banner. + void Clear(); + + /// Slot used to update the status of the progress bar + void OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); + + /// Hides the LoadingScreen with a fade out effect + void OnLoadComplete(); + + // In order to use a custom widget with a stylesheet, you need to override the paintEvent + // See https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget + void paintEvent(QPaintEvent* event) override; + +signals: + void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); + /// Signals that this widget is completely hidden now and should be replaced with the other + /// widget + void Hidden(); + +private: +#ifndef YUZU_QT_MOVIE_MISSING + std::unique_ptr<QMovie> animation; + std::unique_ptr<QBuffer> backing_buf; + std::unique_ptr<QByteArray> backing_mem; +#endif + std::unique_ptr<Ui::LoadingScreen> ui; + std::size_t previous_total = 0; + VideoCore::LoadCallbackStage previous_stage; + + QGraphicsOpacityEffect* opacity_effect = nullptr; + std::unique_ptr<QPropertyAnimation> fadeout_animation; + + // Definitions for the differences in text and styling for each stage + std::unordered_map<VideoCore::LoadCallbackStage, const char*> progressbar_style; + std::unordered_map<VideoCore::LoadCallbackStage, QString> stage_translations; + + // newly generated shaders are added to the end of the file, so when loading and compiling + // shaders, it will start quickly but end slow if new shaders were added since previous launch. + // These variables are used to detect the change in speed so we can generate an ETA + bool slow_shader_compile_start = false; + std::chrono::high_resolution_clock::time_point slow_shader_start; + std::chrono::high_resolution_clock::time_point previous_time; + std::size_t slow_shader_first_value = 0; +}; + +Q_DECLARE_METATYPE(VideoCore::LoadCallbackStage); diff --git a/src/yuzu/loading_screen.ui b/src/yuzu/loading_screen.ui new file mode 100644 index 000000000..a67d273fd --- /dev/null +++ b/src/yuzu/loading_screen.ui @@ -0,0 +1,161 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LoadingScreen</class> + <widget class="QWidget" name="LoadingScreen"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>746</width> + <height>495</height> + </rect> + </property> + <property name="styleSheet"> + <string notr="true">background-color: rgb(0, 0, 0);</string> + </property> + <layout class="QVBoxLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWidget" name="fade_parent" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item alignment="Qt::AlignLeft|Qt::AlignTop"> + <widget class="QLabel" name="logo"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="margin"> + <number>30</number> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout" stretch="1,0,1"> + <property name="spacing"> + <number>15</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetNoConstraint</enum> + </property> + <item alignment="Qt::AlignHCenter|Qt::AlignBottom"> + <widget class="QLabel" name="stage"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">background-color: black; color: white; +font: 75 20pt "Arial";</string> + </property> + <property name="text"> + <string>Loading Shaders 387 / 1628</string> + </property> + </widget> + </item> + <item alignment="Qt::AlignHCenter|Qt::AlignTop"> + <widget class="QProgressBar" name="progress_bar"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>40</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">QProgressBar { +color: white; +border: 2px solid white; +outline-color: black; +border-radius: 20px; +} +QProgressBar::chunk { +background-color: white; +border-radius: 15px; +}</string> + </property> + <property name="value"> + <number>50</number> + </property> + <property name="textVisible"> + <bool>false</bool> + </property> + <property name="format"> + <string>Loading Shaders %v out of %m</string> + </property> + </widget> + </item> + <item alignment="Qt::AlignHCenter|Qt::AlignTop"> + <widget class="QLabel" name="value"> + <property name="toolTip"> + <string notr="true"/> + </property> + <property name="styleSheet"> + <string notr="true">background-color: black; color: white; +font: 75 15pt "Arial";</string> + </property> + <property name="text"> + <string>Stage 1 of 2. Estimate Time 5m 4s</string> + </property> + </widget> + </item> + </layout> + </item> + <item alignment="Qt::AlignRight|Qt::AlignBottom"> + <widget class="QLabel" name="banner"> + <property name="styleSheet"> + <string notr="true">background-color: black;</string> + </property> + <property name="text"> + <string/> + </property> + <property name="margin"> + <number>30</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f564de994..ab403b3ac 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -14,6 +14,7 @@ #include "configuration/configure_per_general.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" +#include "core/frontend/scope_acquire_window_context.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/hid/controllers/npad.h" @@ -92,6 +93,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/hotkeys.h" +#include "yuzu/loading_screen.h" #include "yuzu/main.h" #include "yuzu/ui_settings.h" @@ -411,6 +413,17 @@ void GMainWindow::InitializeWidgets() { game_list = new GameList(vfs, this); ui.horizontalLayout->addWidget(game_list); + loading_screen = new LoadingScreen(this); + loading_screen->hide(); + ui.horizontalLayout->addWidget(loading_screen); + connect(loading_screen, &LoadingScreen::Hidden, [&] { + loading_screen->Clear(); + if (emulation_running) { + render_window->show(); + render_window->setFocus(); + } + }); + // Create status bar message_label = new QLabel(); // Configured separately for left alignment @@ -735,13 +748,15 @@ bool GMainWindow::LoadROM(const QString& filename) { ShutdownGame(); render_window->InitRenderTarget(); - render_window->MakeCurrent(); - if (!gladLoadGL()) { - QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3 Core!"), - tr("Your GPU may not support OpenGL 4.3, or you do not " - "have the latest graphics driver.")); - return false; + { + Core::Frontend::ScopeAcquireWindowContext acquire_context{*render_window}; + if (!gladLoadGL()) { + QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3 Core!"), + tr("Your GPU may not support OpenGL 4.3, or you do not " + "have the latest graphics driver.")); + return false; + } } QStringList unsupported_gl_extensions = GetUnsupportedGLExtensions(); @@ -782,8 +797,6 @@ bool GMainWindow::LoadROM(const QString& filename) { "wiki</a>. This message will not be shown again.")); } - render_window->DoneCurrent(); - if (result != Core::System::ResultStatus::Success) { switch (result) { case Core::System::ResultStatus::ErrorGetLoader: @@ -897,8 +910,8 @@ void GMainWindow::BootGame(const QString& filename) { .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, QString::fromStdString(title_name))); - render_window->show(); - render_window->setFocus(); + loading_screen->Prepare(Core::System::GetInstance().GetAppLoader()); + loading_screen->show(); emulation_running = true; if (ui.action_Fullscreen->isChecked()) { @@ -932,6 +945,8 @@ void GMainWindow::ShutdownGame() { ui.action_Load_Amiibo->setEnabled(false); ui.action_Capture_Screenshot->setEnabled(false); render_window->hide(); + loading_screen->hide(); + loading_screen->Clear(); game_list->show(); game_list->setFilterFocus(); setWindowTitle(QString("yuzu %1| %2-%3") @@ -1505,6 +1520,10 @@ void GMainWindow::OnStopGame() { ShutdownGame(); } +void GMainWindow::OnLoadComplete() { + loading_screen->OnLoadComplete(); +} + void GMainWindow::OnMenuReportCompatibility() { if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { CompatDB compatdb{this}; @@ -1771,9 +1790,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { this, tr("Confirm Key Rederivation"), tr("You are about to force rederive all of your keys. \nIf you do not know what this " "means or what you are doing, \nthis is a potentially destructive action. \nPlease " - "make " - "sure this is what you want \nand optionally make backups.\n\nThis will delete your " - "autogenerated key files and re-run the key derivation module."), + "make sure this is what you want \nand optionally make backups.\n\nThis will delete " + "your autogenerated key files and re-run the key derivation module."), QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel}); if (res == QMessageBox::Cancel) @@ -1818,7 +1836,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { errors + tr("<br><br>You can get all of these and dump all of your games easily by " "following <a href='https://yuzu-emu.org/help/quickstart/'>the " - "quickstart guide</a>. Alternatively, you can use another method of dumping " + "quickstart guide</a>. Alternatively, you can use another method of dumping" "to obtain all of your keys.")); } @@ -2025,6 +2043,9 @@ int main(int argc, char* argv[]) { GMainWindow main_window; // After settings have been loaded by GMainWindow, apply the filter main_window.show(); + + Settings::LogSettings(); + int result = app.exec(); detached_tasks.WaitForAllTasks(); return result; 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; class GraphicsBreakPointsWidget; class GraphicsSurfaceWidget; class GRenderWindow; +class LoadingScreen; class MicroProfileDialog; class ProfilerWidget; class QLabel; @@ -109,10 +110,10 @@ signals: void WebBrowserFinishedBrowsing(); public slots: + void OnLoadComplete(); void ProfileSelectorSelectProfile(); void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); - void WebBrowserOpenPage(std::string_view filename, std::string_view arguments); private: @@ -212,6 +213,7 @@ private: GRenderWindow* render_window; GameList* game_list; + LoadingScreen* loading_screen; // Status bar elements QLabel* message_label = nullptr; |