diff options
Diffstat (limited to 'src/yuzu')
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 91 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 10 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 3 | 
3 files changed, 83 insertions, 21 deletions
| diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index f74cb693a..087ee8f93 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -1,6 +1,13 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. +  #include <QApplication>  #include <QHBoxLayout>  #include <QKeyEvent> +#include <QOffscreenSurface> +#include <QOpenGLWindow> +#include <QPainter>  #include <QScreen>  #include <QWindow>  #include <fmt/format.h> @@ -73,13 +80,36 @@ void EmuThread::run() {      render_window->moveContext();  } +class GGLContext : public Core::Frontend::GraphicsContext { +public: +    explicit GGLContext(QOpenGLContext* shared_context) : surface() { +        context = std::make_unique<QOpenGLContext>(shared_context); +        surface.setFormat(shared_context->format()); +        surface.create(); +    } + +    void MakeCurrent() override { +        context->makeCurrent(&surface); +    } + +    void DoneCurrent() override { +        context->doneCurrent(); +    } + +    void SwapBuffers() override {} + +private: +    std::unique_ptr<QOpenGLContext> context; +    QOffscreenSurface surface; +}; +  // 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 : public QGLWidget { +class GGLWidgetInternal : public QOpenGLWindow {  public: -    GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) -        : QGLWidget(fmt, parent), parent(parent) {} +    GGLWidgetInternal(GRenderWindow* parent, QOpenGLContext* shared_context) +        : QOpenGLWindow(shared_context), parent(parent) {}      void paintEvent(QPaintEvent* ev) override {          if (do_painting) { @@ -105,7 +135,7 @@ private:  };  GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) -    : QWidget(parent), child(nullptr), emu_thread(emu_thread) { +    : QWidget(parent), child(nullptr), context(nullptr), emu_thread(emu_thread) {      setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")                         .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); @@ -129,19 +159,19 @@ void GRenderWindow::moveContext() {      auto thread = (QThread::currentThread() == qApp->thread() && emu_thread != nullptr)                        ? emu_thread                        : qApp->thread(); -    child->context()->moveToThread(thread); +    context->moveToThread(thread);  }  void GRenderWindow::SwapBuffers() { -    // In our multi-threaded QGLWidget use case we shouldn't need to call `makeCurrent`, +    // In our multi-threaded QWidget use case we shouldn't need to call `makeCurrent`,      // since we never call `doneCurrent` in this thread.      // However:      // - The Qt debug runtime prints a bogus warning on the console if `makeCurrent` wasn't called      // since the last time `swapBuffers` was executed;      // - On macOS, if `makeCurrent` isn't called explicitely, resizing the buffer breaks. -    child->makeCurrent(); +    context->makeCurrent(child); -    child->swapBuffers(); +    context->swapBuffers(child);      if (!first_frame) {          emit FirstFrameDisplayed();          first_frame = true; @@ -149,11 +179,11 @@ void GRenderWindow::SwapBuffers() {  }  void GRenderWindow::MakeCurrent() { -    child->makeCurrent(); +    context->makeCurrent(child);  }  void GRenderWindow::DoneCurrent() { -    child->doneCurrent(); +    context->doneCurrent();  }  void GRenderWindow::PollEvents() {} @@ -173,7 +203,7 @@ void GRenderWindow::OnFramebufferSizeChanged() {  }  void GRenderWindow::BackupGeometry() { -    geometry = ((QGLWidget*)this)->saveGeometry(); +    geometry = ((QWidget*)this)->saveGeometry();  }  void GRenderWindow::RestoreGeometry() { @@ -191,7 +221,7 @@ QByteArray GRenderWindow::saveGeometry() {      // If we are a top-level widget, store the current geometry      // otherwise, store the last backup      if (parent() == nullptr) -        return ((QGLWidget*)this)->saveGeometry(); +        return ((QWidget*)this)->saveGeometry();      else          return geometry;  } @@ -305,7 +335,19 @@ void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) {      NotifyClientAreaSizeChanged(std::make_pair(width, height));  } +std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { +    return std::make_unique<GGLContext>(shared_context.get()); +} +  void GRenderWindow::InitRenderTarget() { +    if (shared_context) { +        shared_context.reset(); +    } + +    if (context) { +        context.reset(); +    } +      if (child) {          delete child;      } @@ -318,19 +360,28 @@ void GRenderWindow::InitRenderTarget() {      // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,      // WA_DontShowOnScreen, WA_DeleteOnClose -    QGLFormat fmt; +    QSurfaceFormat fmt;      fmt.setVersion(4, 3); -    fmt.setProfile(QGLFormat::CoreProfile); +    fmt.setProfile(QSurfaceFormat::CoreProfile); +    // 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); -    // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X -    fmt.setOption(QGL::NoDeprecatedFunctions); - -    child = new GGLWidgetInternal(fmt, this); +    child = new GGLWidgetInternal(this, shared_context.get()); +    QWidget* container = QWidget::createWindowContainer(child, this);      QBoxLayout* layout = new QHBoxLayout(this);      resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); -    layout->addWidget(child); +    child->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); +    container->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); +    layout->addWidget(container);      layout->setMargin(0);      setLayout(layout); @@ -340,6 +391,8 @@ void GRenderWindow::InitRenderTarget() {      NotifyClientAreaSizeChanged(std::pair<unsigned, unsigned>(child->width(), child->height()));      BackupGeometry(); +    // show causes the window to actually be created and the gl context as well +    show();  }  void GRenderWindow::CaptureScreenshot(u16 res_scale, const QString& screenshot_path) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index d1f37e503..d2a440d0d 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -7,9 +7,9 @@  #include <atomic>  #include <condition_variable>  #include <mutex> -#include <QGLWidget>  #include <QImage>  #include <QThread> +#include <QWidget>  #include "common/thread.h"  #include "core/core.h"  #include "core/frontend/emu_window.h" @@ -21,6 +21,8 @@ class QTouchEvent;  class GGLWidgetInternal;  class GMainWindow;  class GRenderWindow; +class QSurface; +class QOpenGLContext;  class EmuThread : public QThread {      Q_OBJECT @@ -115,6 +117,7 @@ public:      void MakeCurrent() override;      void DoneCurrent() override;      void PollEvents() override; +    std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;      void BackupGeometry();      void RestoreGeometry(); @@ -168,6 +171,11 @@ private:      QByteArray geometry;      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;      /// Temporary storage of the screenshot taken      QImage screenshot_image; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2c3e27c2e..c8db7b907 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2032,7 +2032,8 @@ int main(int argc, char* argv[]) {      QCoreApplication::setOrganizationName("yuzu team");      QCoreApplication::setApplicationName("yuzu"); -    QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); +    // Enables the core to make the qt created contexts current on std::threads +    QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);      QApplication app(argc, argv);      // Qt changes the locale and causes issues in float conversion using std::to_string() when | 
