diff options
Diffstat (limited to 'src/yuzu')
-rw-r--r-- | src/yuzu/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/yuzu/bootmanager.cpp | 420 | ||||
-rw-r--r-- | src/yuzu/bootmanager.h | 67 | ||||
-rw-r--r-- | src/yuzu/configuration/config.cpp | 13 | ||||
-rw-r--r-- | src/yuzu/configuration/configure.ui | 11 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_dialog.cpp | 4 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics.cpp | 5 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics.ui | 14 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.cpp | 48 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.h | 30 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.ui | 111 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_system.cpp | 4 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_system.h | 1 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_system.ui | 62 | ||||
-rw-r--r-- | src/yuzu/debugger/wait_tree.cpp | 4 | ||||
-rw-r--r-- | src/yuzu/loading_screen.cpp | 17 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 49 | ||||
-rw-r--r-- | src/yuzu/main.h | 7 |
18 files changed, 579 insertions, 291 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index b841e63fa..d34b47b3f 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -42,6 +42,9 @@ add_executable(yuzu configuration/configure_graphics.cpp configuration/configure_graphics.h configuration/configure_graphics.ui + configuration/configure_graphics_advanced.cpp + configuration/configure_graphics_advanced.h + configuration/configure_graphics_advanced.ui configuration/configure_hotkeys.cpp configuration/configure_hotkeys.h configuration/configure_hotkeys.ui diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 55a37fffa..c3dbb1a88 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -9,6 +9,9 @@ #include <QKeyEvent> #include <QMessageBox> #include <QOffscreenSurface> +#include <QOpenGLContext> +#include <QOpenGLFunctions> +#include <QOpenGLFunctions_4_3_Core> #include <QOpenGLWindow> #include <QPainter> #include <QScreen> @@ -23,9 +26,10 @@ #include "common/assert.h" #include "common/microprofile.h" #include "common/scm_rev.h" +#include "common/scope_exit.h" #include "core/core.h" #include "core/frontend/framebuffer_layout.h" -#include "core/frontend/scope_acquire_window_context.h" +#include "core/frontend/scope_acquire_context.h" #include "core/settings.h" #include "input_common/keyboard.h" #include "input_common/main.h" @@ -35,15 +39,27 @@ #include "yuzu/bootmanager.h" #include "yuzu/main.h" -EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {} +EmuThread::EmuThread(GRenderWindow& window) + : shared_context{window.CreateSharedContext()}, + context{(Settings::values.use_asynchronous_gpu_emulation && shared_context) ? *shared_context + : window} {} EmuThread::~EmuThread() = default; -void EmuThread::run() { - render_window->MakeCurrent(); +static GMainWindow* GetMainWindow() { + for (QWidget* w : qApp->topLevelWidgets()) { + if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) { + return main; + } + } + return nullptr; +} +void EmuThread::run() { MicroProfileOnThreadCreate("EmuThread"); + Core::Frontend::ScopeAcquireContext acquire_context{context}; + emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( @@ -53,11 +69,6 @@ void EmuThread::run() { emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); - if (Settings::values.use_asynchronous_gpu_emulation) { - // Release OpenGL context for the GPU thread - render_window->DoneCurrent(); - } - // Holds whether the cpu was running during the last iteration, // so that the DebugModeLeft signal can be emitted before the // next execution step @@ -98,190 +109,202 @@ void EmuThread::run() { #if MICROPROFILE_ENABLED MicroProfileOnThreadExit(); #endif - - render_window->moveContext(); } class GGLContext : public Core::Frontend::GraphicsContext { public: - explicit GGLContext(QOpenGLContext* shared_context) : shared_context{shared_context} { - context.setFormat(shared_context->format()); - context.setShareContext(shared_context); - context.create(); + explicit GGLContext(QOpenGLContext* shared_context) + : context(new QOpenGLContext(shared_context->parent())), + surface(new QOffscreenSurface(nullptr)) { + + // disable vsync for any shared contexts + auto format = shared_context->format(); + format.setSwapInterval(0); + + context->setShareContext(shared_context); + context->setFormat(format); + context->create(); + surface->setParent(shared_context->parent()); + surface->setFormat(format); + surface->create(); } void MakeCurrent() override { - context.makeCurrent(shared_context->surface()); + context->makeCurrent(surface); } void DoneCurrent() override { - context.doneCurrent(); + context->doneCurrent(); } - void SwapBuffers() override {} - private: - QOpenGLContext* shared_context; - QOpenGLContext context; + QOpenGLContext* context; + QOffscreenSurface* surface; }; -class GWidgetInternal : public QWindow { +class ChildRenderWindow : public QWindow { public: - GWidgetInternal(GRenderWindow* parent) : parent(parent) {} - virtual ~GWidgetInternal() = default; + ChildRenderWindow(QWindow* parent, QWidget* event_handler) + : QWindow{parent}, event_handler{event_handler} {} - void resizeEvent(QResizeEvent* ev) override { - parent->OnClientAreaResized(ev->size().width(), ev->size().height()); - parent->OnFramebufferSizeChanged(); - } + virtual ~ChildRenderWindow() = default; - void keyPressEvent(QKeyEvent* event) override { - InputCommon::GetKeyboard()->PressKey(event->key()); - } + virtual void Present() = 0; - void keyReleaseEvent(QKeyEvent* event) override { - InputCommon::GetKeyboard()->ReleaseKey(event->key()); +protected: + bool event(QEvent* event) override { + switch (event->type()) { + case QEvent::UpdateRequest: + Present(); + return true; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::FocusAboutToChange: + case QEvent::Enter: + case QEvent::Leave: + case QEvent::Wheel: + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::InputMethodQuery: + case QEvent::TouchCancel: + return QCoreApplication::sendEvent(event_handler, event); + case QEvent::Drop: + GetMainWindow()->DropAction(static_cast<QDropEvent*>(event)); + return true; + case QEvent::DragResponse: + case QEvent::DragEnter: + case QEvent::DragLeave: + case QEvent::DragMove: + GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event)); + return true; + default: + return QWindow::event(event); + } } - void mousePressEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchBeginEvent - - const auto pos{event->pos()}; - if (event->button() == Qt::LeftButton) { - const auto [x, y] = parent->ScaleTouch(pos); - parent->TouchPressed(x, y); - } else if (event->button() == Qt::RightButton) { - InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); - } + void exposeEvent(QExposeEvent* event) override { + QWindow::requestUpdate(); + QWindow::exposeEvent(event); } - void mouseMoveEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchUpdateEvent +private: + QWidget* event_handler{}; +}; - const auto pos{event->pos()}; - const auto [x, y] = parent->ScaleTouch(pos); - parent->TouchMoved(x, y); - InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); - } +class OpenGLWindow final : public ChildRenderWindow { +public: + OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context) + : ChildRenderWindow{parent, event_handler}, + context(new QOpenGLContext(shared_context->parent())) { - void mouseReleaseEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchEndEvent + // disable vsync for any shared contexts + auto format = shared_context->format(); + format.setSwapInterval(Settings::values.use_vsync ? 1 : 0); + this->setFormat(format); - if (event->button() == Qt::LeftButton) - parent->TouchReleased(); - else if (event->button() == Qt::RightButton) - InputCommon::GetMotionEmu()->EndTilt(); - } + context->setShareContext(shared_context); + context->setScreen(this->screen()); + context->setFormat(format); + context->create(); - void DisablePainting() { - do_painting = false; - } + setSurfaceType(QWindow::OpenGLSurface); - void EnablePainting() { - do_painting = true; + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, + // WA_DontShowOnScreen, WA_DeleteOnClose } - std::pair<unsigned, unsigned> GetSize() const { - return std::make_pair(width(), height()); + ~OpenGLWindow() override { + context->doneCurrent(); } -protected: - bool IsPaintingEnabled() const { - return do_painting; + void Present() override { + if (!isExposed()) { + return; + } + + context->makeCurrent(this); + Core::System::GetInstance().Renderer().TryPresent(100); + context->swapBuffers(this); + auto f = context->versionFunctions<QOpenGLFunctions_4_3_Core>(); + f->glFinish(); + QWindow::requestUpdate(); } private: - GRenderWindow* parent; - bool do_painting = false; -}; - -// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL -// context. -// The corresponding functionality is handled in EmuThread instead -class GGLWidgetInternal final : public GWidgetInternal, public QOpenGLWindow { -public: - GGLWidgetInternal(GRenderWindow* parent, QOpenGLContext* shared_context) - : GWidgetInternal(parent), QOpenGLWindow(shared_context) {} - ~GGLWidgetInternal() override = default; - - void paintEvent(QPaintEvent* ev) override { - if (IsPaintingEnabled()) { - QPainter painter(this); - } - } + QOpenGLContext* context{}; }; #ifdef HAS_VULKAN -class GVKWidgetInternal final : public GWidgetInternal { +class VulkanWindow final : public ChildRenderWindow { public: - GVKWidgetInternal(GRenderWindow* parent, QVulkanInstance* instance) : GWidgetInternal(parent) { + VulkanWindow(QWindow* parent, QWidget* event_handler, QVulkanInstance* instance) + : ChildRenderWindow{parent, event_handler} { setSurfaceType(QSurface::SurfaceType::VulkanSurface); setVulkanInstance(instance); } - ~GVKWidgetInternal() override = default; + + ~VulkanWindow() override = default; + + void Present() override { + // TODO(bunnei): ImplementMe + } + +private: + QWidget* event_handler{}; }; #endif -GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread) - : QWidget(parent), emu_thread(emu_thread) { +GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread) + : QWidget(parent_), emu_thread(emu_thread) { setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") .arg(QString::fromUtf8(Common::g_build_name), QString::fromUtf8(Common::g_scm_branch), QString::fromUtf8(Common::g_scm_desc))); setAttribute(Qt::WA_AcceptTouchEvents); - + auto layout = new QHBoxLayout(this); + layout->setMargin(0); + setLayout(layout); InputCommon::Init(); + + GMainWindow* parent = GetMainWindow(); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); } GRenderWindow::~GRenderWindow() { InputCommon::Shutdown(); - - // Avoid an unordered destruction that generates a segfault - delete child; } -void GRenderWindow::moveContext() { - if (!context) { - return; +void GRenderWindow::MakeCurrent() { + if (core_context) { + core_context->MakeCurrent(); } - DoneCurrent(); - - // If the thread started running, move the GL Context to the new thread. Otherwise, move it - // back. - auto thread = (QThread::currentThread() == qApp->thread() && emu_thread != nullptr) - ? emu_thread - : qApp->thread(); - context->moveToThread(thread); } -void GRenderWindow::SwapBuffers() { - if (context) { - context->swapBuffers(child); +void GRenderWindow::DoneCurrent() { + if (core_context) { + core_context->DoneCurrent(); } +} + +void GRenderWindow::PollEvents() { if (!first_frame) { first_frame = true; emit FirstFrameDisplayed(); } } -void GRenderWindow::MakeCurrent() { - if (context) { - context->makeCurrent(child); - } -} - -void GRenderWindow::DoneCurrent() { - if (context) { - context->doneCurrent(); - } -} - -void GRenderWindow::PollEvents() {} - bool GRenderWindow::IsShown() const { return !isMinimized(); } @@ -291,7 +314,7 @@ void GRenderWindow::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* i #ifdef HAS_VULKAN const auto instance_proc_addr = vk_instance->getInstanceProcAddr("vkGetInstanceProcAddr"); const VkInstance instance_copy = vk_instance->vkInstance(); - const VkSurfaceKHR surface_copy = vk_instance->surfaceForWindow(child); + const VkSurfaceKHR surface_copy = vk_instance->surfaceForWindow(child_window); std::memcpy(get_instance_proc_addr, &instance_proc_addr, sizeof(instance_proc_addr)); std::memcpy(instance, &instance_copy, sizeof(instance_copy)); @@ -309,21 +332,10 @@ void GRenderWindow::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* i void GRenderWindow::OnFramebufferSizeChanged() { // Screen changes potentially incur a change in screen DPI, hence we should update the // framebuffer size - const qreal pixelRatio{GetWindowPixelRatio()}; - const auto size{child->GetSize()}; - UpdateCurrentFramebufferLayout(size.first * pixelRatio, size.second * pixelRatio); -} - -void GRenderWindow::ForwardKeyPressEvent(QKeyEvent* event) { - if (child) { - child->keyPressEvent(event); - } -} - -void GRenderWindow::ForwardKeyReleaseEvent(QKeyEvent* event) { - if (child) { - child->keyReleaseEvent(event); - } + const qreal pixel_ratio = windowPixelRatio(); + const u32 width = this->width() * pixel_ratio; + const u32 height = this->height() * pixel_ratio; + UpdateCurrentFramebufferLayout(width, height); } void GRenderWindow::BackupGeometry() { @@ -351,13 +363,12 @@ QByteArray GRenderWindow::saveGeometry() { return geometry; } -qreal GRenderWindow::GetWindowPixelRatio() const { - // windowHandle() might not be accessible until the window is displayed to screen. - return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f; +qreal GRenderWindow::windowPixelRatio() const { + return devicePixelRatio(); } std::pair<u32, u32> GRenderWindow::ScaleTouch(const QPointF pos) const { - const qreal pixel_ratio{GetWindowPixelRatio()}; + const qreal pixel_ratio = windowPixelRatio(); return {static_cast<u32>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})), static_cast<u32>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))}; } @@ -367,6 +378,47 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { QWidget::closeEvent(event); } +void GRenderWindow::keyPressEvent(QKeyEvent* event) { + InputCommon::GetKeyboard()->PressKey(event->key()); +} + +void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { + InputCommon::GetKeyboard()->ReleaseKey(event->key()); +} + +void GRenderWindow::mousePressEvent(QMouseEvent* event) { + if (event->source() == Qt::MouseEventSynthesizedBySystem) + return; // touch input is handled in TouchBeginEvent + + auto pos = event->pos(); + if (event->button() == Qt::LeftButton) { + const auto [x, y] = ScaleTouch(pos); + this->TouchPressed(x, y); + } else if (event->button() == Qt::RightButton) { + InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); + } +} + +void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { + if (event->source() == Qt::MouseEventSynthesizedBySystem) + return; // touch input is handled in TouchUpdateEvent + + auto pos = event->pos(); + const auto [x, y] = ScaleTouch(pos); + this->TouchMoved(x, y); + InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); +} + +void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { + if (event->source() == Qt::MouseEventSynthesizedBySystem) + return; // touch input is handled in TouchEndEvent + + if (event->button() == Qt::LeftButton) + this->TouchReleased(); + else if (event->button() == Qt::RightButton) + InputCommon::GetMotionEmu()->EndTilt(); +} + void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { // TouchBegin always has exactly one touch point, so take the .first() const auto [x, y] = ScaleTouch(event->touchPoints().first().pos()); @@ -415,26 +467,20 @@ void GRenderWindow::focusOutEvent(QFocusEvent* event) { InputCommon::GetKeyboard()->ReleaseAllKeys(); } -void GRenderWindow::OnClientAreaResized(u32 width, u32 height) { - NotifyClientAreaSizeChanged(std::make_pair(width, height)); +void GRenderWindow::resizeEvent(QResizeEvent* event) { + QWidget::resizeEvent(event); + OnFramebufferSizeChanged(); } std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { - return std::make_unique<GGLContext>(context.get()); + if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) { + return std::make_unique<GGLContext>(QOpenGLContext::globalShareContext()); + } + return {}; } bool GRenderWindow::InitRenderTarget() { - shared_context.reset(); - context.reset(); - if (child) { - delete child; - } - if (container) { - delete container; - } - if (layout()) { - delete layout(); - } + ReleaseRenderTarget(); first_frame = false; @@ -451,13 +497,6 @@ bool GRenderWindow::InitRenderTarget() { break; } - container = QWidget::createWindowContainer(child, this); - QBoxLayout* layout = new QHBoxLayout(this); - - layout->addWidget(container); - layout->setMargin(0); - setLayout(layout); - // Reset minimum required size to avoid resizing issues on the main window after restarting. setMinimumSize(1, 1); @@ -467,14 +506,9 @@ bool GRenderWindow::InitRenderTarget() { hide(); resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); - child->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); - container->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); - OnFramebufferSizeChanged(); - NotifyClientAreaSizeChanged(child->GetSize()); - BackupGeometry(); if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) { @@ -486,6 +520,14 @@ bool GRenderWindow::InitRenderTarget() { return true; } +void GRenderWindow::ReleaseRenderTarget() { + if (child_widget) { + layout()->removeWidget(child_widget); + delete child_widget; + child_widget = nullptr; + } +} + void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) { auto& renderer = Core::System::GetInstance().Renderer(); @@ -521,16 +563,19 @@ bool GRenderWindow::InitializeOpenGL() { fmt.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); // TODO: expose a setting for buffer value (ie default/single/double/triple) fmt.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); - shared_context = std::make_unique<QOpenGLContext>(); - shared_context->setFormat(fmt); - shared_context->create(); - context = std::make_unique<QOpenGLContext>(); - context->setShareContext(shared_context.get()); - context->setFormat(fmt); - context->create(); - fmt.setSwapInterval(false); - - child = new GGLWidgetInternal(this, shared_context.get()); + fmt.setSwapInterval(0); + QSurfaceFormat::setDefaultFormat(fmt); + + GMainWindow* parent = GetMainWindow(); + QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr; + child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext()); + child_window->create(); + child_widget = createWindowContainer(child_window, this); + child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); + layout()->addWidget(child_widget); + + core_context = CreateSharedContext(); + return true; } @@ -559,7 +604,14 @@ bool GRenderWindow::InitializeVulkan() { return false; } - child = new GVKWidgetInternal(this, vk_instance.get()); + GMainWindow* parent = GetMainWindow(); + QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr; + child_window = new VulkanWindow(parent_win_handle, this, vk_instance.get()); + child_window->create(); + child_widget = createWindowContainer(child_window, this); + child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); + layout()->addWidget(child_widget); + return true; #else QMessageBox::critical(this, tr("Vulkan not available!"), @@ -569,7 +621,7 @@ bool GRenderWindow::InitializeVulkan() { } bool GRenderWindow::LoadOpenGL() { - Core::Frontend::ScopeAcquireWindowContext acquire_context{*this}; + Core::Frontend::ScopeAcquireContext acquire_context{*this}; if (!gladLoadGL()) { QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3!"), tr("Your GPU may not support OpenGL 4.3, or you do not have the " @@ -621,12 +673,10 @@ QStringList GRenderWindow::GetUnsupportedGLExtensions() const { void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) { this->emu_thread = emu_thread; - child->DisablePainting(); } void GRenderWindow::OnEmulationStopping() { emu_thread = nullptr; - child->EnablePainting(); } void GRenderWindow::showEvent(QShowEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 71a2fa321..79b030304 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -11,11 +11,13 @@ #include <QImage> #include <QThread> #include <QWidget> +#include <QWindow> #include "common/thread.h" #include "core/core.h" #include "core/frontend/emu_window.h" +class GRenderWindow; class QKeyEvent; class QScreen; class QTouchEvent; @@ -26,14 +28,6 @@ class QOpenGLContext; class QVulkanInstance; #endif -class GWidgetInternal; -class GGLWidgetInternal; -class GVKWidgetInternal; -class GMainWindow; -class GRenderWindow; -class QSurface; -class QOpenGLContext; - namespace VideoCore { enum class LoadCallbackStage; } @@ -42,7 +36,7 @@ class EmuThread final : public QThread { Q_OBJECT public: - explicit EmuThread(GRenderWindow* render_window); + explicit EmuThread(GRenderWindow& window); ~EmuThread() override; /** @@ -96,7 +90,11 @@ private: std::mutex running_mutex; std::condition_variable running_cv; - GRenderWindow* render_window; + /// Only used in asynchronous GPU mode + std::unique_ptr<Core::Frontend::GraphicsContext> shared_context; + + /// This is shared_context in asynchronous GPU mode, core_context in synchronous GPU mode + Core::Frontend::GraphicsContext& context; signals: /** @@ -126,11 +124,10 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow { Q_OBJECT public: - GRenderWindow(GMainWindow* parent, EmuThread* emu_thread); + GRenderWindow(QWidget* parent, EmuThread* emu_thread); ~GRenderWindow() override; - // EmuWindow implementation - void SwapBuffers() override; + // EmuWindow implementation. void MakeCurrent() override; void DoneCurrent() override; void PollEvents() override; @@ -139,30 +136,36 @@ public: void* surface) const override; std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; - void ForwardKeyPressEvent(QKeyEvent* event); - void ForwardKeyReleaseEvent(QKeyEvent* event); - void BackupGeometry(); void RestoreGeometry(); void restoreGeometry(const QByteArray& geometry); // overridden QByteArray saveGeometry(); // overridden - qreal GetWindowPixelRatio() const; - std::pair<u32, u32> ScaleTouch(QPointF pos) const; + qreal windowPixelRatio() const; void closeEvent(QCloseEvent* event) override; + + void resizeEvent(QResizeEvent* event) override; + + void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; + + void mousePressEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; + void mouseReleaseEvent(QMouseEvent* event) override; + bool event(QEvent* event) override; - void focusOutEvent(QFocusEvent* event) override; - void OnClientAreaResized(u32 width, u32 height); + void focusOutEvent(QFocusEvent* event) override; bool InitRenderTarget(); + /// Destroy the previous run's child_widget which should also destroy the child_window + void ReleaseRenderTarget(); + void CaptureScreenshot(u32 res_scale, const QString& screenshot_path); public slots: - void moveContext(); // overridden - void OnEmulationStarting(EmuThread* emu_thread); void OnEmulationStopping(); void OnFramebufferSizeChanged(); @@ -173,6 +176,7 @@ signals: void FirstFrameDisplayed(); private: + std::pair<u32, u32> ScaleTouch(QPointF pos) const; void TouchBeginEvent(const QTouchEvent* event); void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); @@ -184,15 +188,9 @@ private: bool LoadOpenGL(); QStringList GetUnsupportedGLExtensions() const; - QWidget* container = nullptr; - GWidgetInternal* child = nullptr; - EmuThread* emu_thread; - // Context that backs the GGLWidgetInternal (and will be used by core to render) - std::unique_ptr<QOpenGLContext> context; - // Context that will be shared between all newly created contexts. This should never be made - // current - std::unique_ptr<QOpenGLContext> shared_context; + + std::unique_ptr<GraphicsContext> core_context; #ifdef HAS_VULKAN std::unique_ptr<QVulkanInstance> vk_instance; @@ -202,6 +200,15 @@ private: QImage screenshot_image; QByteArray geometry; + + /// Native window handle that backs this presentation widget + QWindow* child_window = nullptr; + + /// In order to embed the window into GRenderWindow, you need to use createWindowContainer to + /// put the child_window into a widget then add it to the layout. This child_widget can be + /// parented to GRenderWindow and use Qt's lifetime system + QWidget* child_widget = nullptr; + bool first_frame = false; protected: diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 6209fff75..3b9ab38dd 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -539,7 +539,7 @@ void Config::ReadDebuggingValues() { void Config::ReadServiceValues() { qt_config->beginGroup(QStringLiteral("Services")); Settings::values.bcat_backend = - ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("boxcat")) + ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("null")) .toString() .toStdString(); Settings::values.bcat_boxcat_local = @@ -631,6 +631,7 @@ void Config::ReadRendererValues() { Settings::values.resolution_factor = ReadSetting(QStringLiteral("resolution_factor"), 1.0).toFloat(); Settings::values.aspect_ratio = ReadSetting(QStringLiteral("aspect_ratio"), 0).toInt(); + Settings::values.max_anisotropy = ReadSetting(QStringLiteral("max_anisotropy"), 0).toInt(); Settings::values.use_frame_limit = ReadSetting(QStringLiteral("use_frame_limit"), true).toBool(); Settings::values.frame_limit = ReadSetting(QStringLiteral("frame_limit"), 100).toInt(); @@ -640,6 +641,7 @@ void Config::ReadRendererValues() { ReadSetting(QStringLiteral("use_accurate_gpu_emulation"), false).toBool(); Settings::values.use_asynchronous_gpu_emulation = ReadSetting(QStringLiteral("use_asynchronous_gpu_emulation"), false).toBool(); + Settings::values.use_vsync = ReadSetting(QStringLiteral("use_vsync"), true).toBool(); Settings::values.force_30fps_mode = ReadSetting(QStringLiteral("force_30fps_mode"), false).toBool(); @@ -680,6 +682,8 @@ void Config::ReadSystemValues() { Settings::values.language_index = ReadSetting(QStringLiteral("language_index"), 1).toInt(); + Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt(); + const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool(); if (rng_seed_enabled) { Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong(); @@ -696,6 +700,8 @@ void Config::ReadSystemValues() { Settings::values.custom_rtc = std::nullopt; } + Settings::values.sound_index = ReadSetting(QStringLiteral("sound_index"), 1).toInt(); + qt_config->endGroup(); } @@ -1066,6 +1072,7 @@ void Config::SaveRendererValues() { WriteSetting(QStringLiteral("resolution_factor"), static_cast<double>(Settings::values.resolution_factor), 1.0); WriteSetting(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0); + WriteSetting(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0); WriteSetting(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true); WriteSetting(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100); WriteSetting(QStringLiteral("use_disk_shader_cache"), Settings::values.use_disk_shader_cache, @@ -1074,6 +1081,7 @@ void Config::SaveRendererValues() { Settings::values.use_accurate_gpu_emulation, false); WriteSetting(QStringLiteral("use_asynchronous_gpu_emulation"), Settings::values.use_asynchronous_gpu_emulation, false); + WriteSetting(QStringLiteral("use_vsync"), Settings::values.use_vsync, true); WriteSetting(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode, false); // Cast to double because Qt's written float values are not human-readable @@ -1110,6 +1118,7 @@ void Config::SaveSystemValues() { WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false); WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0); WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1); + WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1); WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false); WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0); @@ -1121,6 +1130,8 @@ void Config::SaveSystemValues() { Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()), 0); + WriteSetting(QStringLiteral("sound_index"), Settings::values.sound_index, 1); + qt_config->endGroup(); } diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 67b990f1a..9aec1bd09 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -83,6 +83,11 @@ <string>Graphics</string> </attribute> </widget> + <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab"> + <attribute name="title"> + <string>GraphicsAdvanced</string> + </attribute> + </widget> <widget class="ConfigureAudio" name="audioTab"> <attribute name="title"> <string>Audio</string> @@ -160,6 +165,12 @@ <container>1</container> </customwidget> <customwidget> + <class>ConfigureGraphicsAdvanced</class> + <extends>QWidget</extends> + <header>configuration/configure_graphics_advanced.h</header> + <container>1</container> + </customwidget> + <customwidget> <class>ConfigureWeb</class> <extends>QWidget</extends> <header>configuration/configure_web.h</header> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index db3b19352..df4473b46 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -41,6 +41,7 @@ void ConfigureDialog::ApplyConfiguration() { ui->inputTab->ApplyConfiguration(); ui->hotkeysTab->ApplyConfiguration(registry); ui->graphicsTab->ApplyConfiguration(); + ui->graphicsAdvancedTab->ApplyConfiguration(); ui->audioTab->ApplyConfiguration(); ui->debugTab->ApplyConfiguration(); ui->webTab->ApplyConfiguration(); @@ -76,7 +77,7 @@ void ConfigureDialog::PopulateSelectionList() { const std::array<std::pair<QString, QList<QWidget*>>, 5> items{ {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, - {tr("Graphics"), {ui->graphicsTab}}, + {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, {tr("Audio"), {ui->audioTab}}, {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, }; @@ -105,6 +106,7 @@ void ConfigureDialog::UpdateVisibleTabs() { {ui->inputTab, tr("Input")}, {ui->hotkeysTab, tr("Hotkeys")}, {ui->graphicsTab, tr("Graphics")}, + {ui->graphicsAdvancedTab, tr("Advanced")}, {ui->audioTab, tr("Audio")}, {ui->debugTab, tr("Debug")}, {ui->webTab, tr("Web")}, diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index ea899c080..a821c7b3c 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -100,11 +100,8 @@ void ConfigureGraphics::SetConfiguration() { ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio); ui->use_disk_shader_cache->setEnabled(runtime_lock); ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache); - ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation); ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock); ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation); - ui->force_30fps_mode->setEnabled(runtime_lock); - ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode); UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue)); UpdateDeviceComboBox(); @@ -117,10 +114,8 @@ void ConfigureGraphics::ApplyConfiguration() { ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex())); Settings::values.aspect_ratio = ui->aspect_ratio_combobox->currentIndex(); Settings::values.use_disk_shader_cache = ui->use_disk_shader_cache->isChecked(); - Settings::values.use_accurate_gpu_emulation = ui->use_accurate_gpu_emulation->isChecked(); Settings::values.use_asynchronous_gpu_emulation = ui->use_asynchronous_gpu_emulation->isChecked(); - Settings::values.force_30fps_mode = ui->force_30fps_mode->isChecked(); Settings::values.bg_red = static_cast<float>(bg_color.redF()); Settings::values.bg_green = static_cast<float>(bg_color.greenF()); Settings::values.bg_blue = static_cast<float>(bg_color.blueF()); diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index db60426ab..c816d6108 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -85,20 +85,6 @@ </widget> </item> <item> - <widget class="QCheckBox" name="use_accurate_gpu_emulation"> - <property name="text"> - <string>Use accurate GPU emulation (slow)</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="force_30fps_mode"> - <property name="text"> - <string>Force 30 FPS mode</string> - </property> - </widget> - </item> - <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QLabel" name="label"> diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp new file mode 100644 index 000000000..b9f429f84 --- /dev/null +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -0,0 +1,48 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/settings.h" +#include "ui_configure_graphics_advanced.h" +#include "yuzu/configuration/configure_graphics_advanced.h" + +ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent) + : QWidget(parent), ui(new Ui::ConfigureGraphicsAdvanced) { + + ui->setupUi(this); + + SetConfiguration(); +} + +ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; + +void ConfigureGraphicsAdvanced::SetConfiguration() { + const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); + ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation); + ui->use_vsync->setEnabled(runtime_lock); + ui->use_vsync->setChecked(Settings::values.use_vsync); + ui->force_30fps_mode->setEnabled(runtime_lock); + ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode); + ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); + ui->anisotropic_filtering_combobox->setCurrentIndex(Settings::values.max_anisotropy); +} + +void ConfigureGraphicsAdvanced::ApplyConfiguration() { + Settings::values.use_accurate_gpu_emulation = ui->use_accurate_gpu_emulation->isChecked(); + Settings::values.use_vsync = ui->use_vsync->isChecked(); + Settings::values.force_30fps_mode = ui->force_30fps_mode->isChecked(); + Settings::values.max_anisotropy = ui->anisotropic_filtering_combobox->currentIndex(); +} + +void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QWidget::changeEvent(event); +} + +void ConfigureGraphicsAdvanced::RetranslateUI() { + ui->retranslateUi(this); +} diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h new file mode 100644 index 000000000..bbc9d4355 --- /dev/null +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -0,0 +1,30 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <QWidget> + +namespace Ui { +class ConfigureGraphicsAdvanced; +} + +class ConfigureGraphicsAdvanced : public QWidget { + Q_OBJECT + +public: + explicit ConfigureGraphicsAdvanced(QWidget* parent = nullptr); + ~ConfigureGraphicsAdvanced() override; + + void ApplyConfiguration(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + void SetConfiguration(); + + std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; +}; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui new file mode 100644 index 000000000..42eec278e --- /dev/null +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureGraphicsAdvanced</class> + <widget class="QWidget" name="ConfigureGraphicsAdvanced"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>321</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_1"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QGroupBox" name="groupBox_1"> + <property name="title"> + <string>Advanced Graphics Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QCheckBox" name="use_accurate_gpu_emulation"> + <property name="text"> + <string>Use accurate GPU emulation (slow)</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="use_vsync"> + <property name="toolTip"> + <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> + </property> + <property name="text"> + <string>Use VSync (OpenGL only)</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="force_30fps_mode"> + <property name="text"> + <string>Force 30 FPS mode</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_1"> + <item> + <widget class="QLabel" name="af_label"> + <property name="text"> + <string>Anisotropic Filtering:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="anisotropic_filtering_combobox"> + <item> + <property name="text"> + <string>Default</string> + </property> + </item> + <item> + <property name="text"> + <string>2x</string> + </property> + </item> + <item> + <property name="text"> + <string>4x</string> + </property> + </item> + <item> + <property name="text"> + <string>8x</string> + </property> + </item> + <item> + <property name="text"> + <string>16x</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index e1b52f8d9..f49cd4c8f 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -56,6 +56,8 @@ void ConfigureSystem::SetConfiguration() { enabled = !Core::System::GetInstance().IsPoweredOn(); ui->combo_language->setCurrentIndex(Settings::values.language_index); + ui->combo_region->setCurrentIndex(Settings::values.region_index); + ui->combo_sound->setCurrentIndex(Settings::values.sound_index); ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value()); ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value()); @@ -81,6 +83,8 @@ void ConfigureSystem::ApplyConfiguration() { } Settings::values.language_index = ui->combo_language->currentIndex(); + Settings::values.region_index = ui->combo_region->currentIndex(); + Settings::values.sound_index = ui->combo_sound->currentIndex(); if (ui->rng_seed_checkbox->isChecked()) { Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16); diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index 1eab3781d..d8fa2d2cc 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h @@ -36,5 +36,6 @@ private: bool enabled = false; int language_index = 0; + int region_index = 0; int sound_index = 0; }; diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 65745a2f8..4e2c7e76e 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui @@ -22,14 +22,14 @@ <string>System Settings</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QLabel" name="label_sound"> <property name="text"> <string>Sound output mode</string> </property> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="label_console_id"> <property name="text"> <string>Console ID:</string> @@ -128,14 +128,60 @@ </item> </widget> </item> - <item row="4" column="0"> + <item row="1" column="0"> + <widget class="QLabel" name="label_region"> + <property name="text"> + <string>Region:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="combo_region"> + <item> + <property name="text"> + <string>Japan</string> + </property> + </item> + <item> + <property name="text"> + <string>USA</string> + </property> + </item> + <item> + <property name="text"> + <string>Europe</string> + </property> + </item> + <item> + <property name="text"> + <string>Australia</string> + </property> + </item> + <item> + <property name="text"> + <string>China</string> + </property> + </item> + <item> + <property name="text"> + <string>Korea</string> + </property> + </item> + <item> + <property name="text"> + <string>Taiwan</string> + </property> + </item> + </widget> + </item> + <item row="5" column="0"> <widget class="QCheckBox" name="rng_seed_checkbox"> <property name="text"> <string>RNG Seed</string> </property> </widget> </item> - <item row="1" column="1"> + <item row="2" column="1"> <widget class="QComboBox" name="combo_sound"> <item> <property name="text"> @@ -161,7 +207,7 @@ </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QPushButton" name="button_regenerate_console_id"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> @@ -177,14 +223,14 @@ </property> </widget> </item> - <item row="3" column="0"> + <item row="4" column="0"> <widget class="QCheckBox" name="custom_rtc_checkbox"> <property name="text"> <string>Custom RTC</string> </property> </widget> </item> - <item row="3" column="1"> + <item row="4" column="1"> <widget class="QDateTimeEdit" name="custom_rtc_edit"> <property name="minimumDate"> <date> @@ -198,7 +244,7 @@ </property> </widget> </item> - <item row="4" column="1"> + <item row="5" column="1"> <widget class="QLineEdit" name="rng_seed_edit"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 3f1a94627..c1ea25fb8 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -116,7 +116,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons constexpr std::size_t BaseRegister = 29; auto& memory = Core::System::GetInstance().Memory(); - u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister]; + u64 base_pointer = thread.GetContext64().cpu_registers[BaseRegister]; while (base_pointer != 0) { const u64 lr = memory.Read64(base_pointer + sizeof(u64)); @@ -240,7 +240,7 @@ QString WaitTreeThread::GetText() const { break; } - const auto& context = thread.GetContext(); + const auto& context = thread.GetContext64(); const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") .arg(context.pc, 8, 16, QLatin1Char{'0'}) .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp index 4f2bfab48..2a6483370 100644 --- a/src/yuzu/loading_screen.cpp +++ b/src/yuzu/loading_screen.cpp @@ -34,18 +34,6 @@ constexpr char PROGRESSBAR_STYLE_PREPARE[] = R"( QProgressBar {} QProgressBar::chunk {})"; -constexpr char PROGRESSBAR_STYLE_DECOMPILE[] = R"( -QProgressBar { - background-color: black; - border: 2px solid white; - border-radius: 4px; - padding: 2px; -} -QProgressBar::chunk { - background-color: #0ab9e6; - width: 1px; -})"; - constexpr char PROGRESSBAR_STYLE_BUILD[] = R"( QProgressBar { background-color: black; @@ -100,13 +88,11 @@ LoadingScreen::LoadingScreen(QWidget* parent) 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}, }; @@ -192,8 +178,7 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size } // update labels and progress bar - if (stage == VideoCore::LoadCallbackStage::Decompile || - stage == VideoCore::LoadCallbackStage::Build) { + if (stage == VideoCore::LoadCallbackStage::Build) { ui->stage->setText(stage_translations[stage].arg(value).arg(total)); } else { ui->stage->setText(stage_translations[stage]); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 1be61bd48..4769a612e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -20,7 +20,6 @@ #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" #include "core/frontend/applets/general_frontend.h" -#include "core/frontend/scope_acquire_window_context.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" @@ -985,11 +984,8 @@ void GMainWindow::BootGame(const QString& filename) { return; // Create and start the emulation thread - emu_thread = std::make_unique<EmuThread>(render_window); + emu_thread = std::make_unique<EmuThread>(*render_window); emit EmulationStarting(emu_thread.get()); - if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) { - render_window->moveContext(); - } emu_thread->start(); connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); @@ -1087,6 +1083,9 @@ void GMainWindow::ShutdownGame() { emulation_running = false; game_path.clear(); + + // When closing the game, destroy the GLWindow to clear the context after the game is closed + render_window->ReleaseRenderTarget(); } void GMainWindow::StoreRecentFile(const QString& filename) { @@ -2210,48 +2209,47 @@ void GMainWindow::closeEvent(QCloseEvent* event) { QWidget::closeEvent(event); } -void GMainWindow::keyPressEvent(QKeyEvent* event) { - if (render_window) { - render_window->ForwardKeyPressEvent(event); - } +static bool IsSingleFileDropEvent(const QMimeData* mime) { + return mime->hasUrls() && mime->urls().length() == 1; } -void GMainWindow::keyReleaseEvent(QKeyEvent* event) { - if (render_window) { - render_window->ForwardKeyReleaseEvent(event); +void GMainWindow::AcceptDropEvent(QDropEvent* event) { + if (IsSingleFileDropEvent(event->mimeData())) { + event->setDropAction(Qt::DropAction::LinkAction); + event->accept(); } } -static bool IsSingleFileDropEvent(QDropEvent* event) { - const QMimeData* mimeData = event->mimeData(); - return mimeData->hasUrls() && mimeData->urls().length() == 1; -} - -void GMainWindow::dropEvent(QDropEvent* event) { - if (!IsSingleFileDropEvent(event)) { - return; +bool GMainWindow::DropAction(QDropEvent* event) { + if (!IsSingleFileDropEvent(event->mimeData())) { + return false; } const QMimeData* mime_data = event->mimeData(); - const QString filename = mime_data->urls().at(0).toLocalFile(); + const QString& filename = mime_data->urls().at(0).toLocalFile(); if (emulation_running && QFileInfo(filename).suffix() == QStringLiteral("bin")) { + // Amiibo LoadAmiibo(filename); } else { + // Game if (ConfirmChangeGame()) { BootGame(filename); } } + return true; +} + +void GMainWindow::dropEvent(QDropEvent* event) { + DropAction(event); } void GMainWindow::dragEnterEvent(QDragEnterEvent* event) { - if (IsSingleFileDropEvent(event)) { - event->acceptProposedAction(); - } + AcceptDropEvent(event); } void GMainWindow::dragMoveEvent(QDragMoveEvent* event) { - event->acceptProposedAction(); + AcceptDropEvent(event); } bool GMainWindow::ConfirmChangeGame() { @@ -2372,6 +2370,7 @@ int main(int argc, char* argv[]) { // Enables the core to make the qt created contexts current on std::threads QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); QApplication app(argc, argv); // Qt changes the locale and causes issues in float conversion using std::to_string() when diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8eba2172c..a67125567 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -78,6 +78,9 @@ public: std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc; + bool DropAction(QDropEvent* event); + void AcceptDropEvent(QDropEvent* event); + signals: /** @@ -264,8 +267,4 @@ protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override; - - // Overrides used to forward signals to the render window when the focus moves out. - void keyPressEvent(QKeyEvent* event) override; - void keyReleaseEvent(QKeyEvent* event) override; }; |