From ca27bc09c5a413f00f01521f26f60a0b50e331fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 3 Dec 2014 16:22:15 +0100 Subject: [PATCH] [aurorae] Use QQuickRenderControl if compiled against Qt 5.4 QQuickRenderControl brings a few advantages for the usage in Aurorae: * can create an offscreen window * eliminate the need for mutex as we control the rendering * control the tear down of the QML scene (no more crashes in Qt) In future we can further improve this, by sharing the context, so that we can use the FBO texture directly. But this first needs some more work in KWin core. As we don't hard depend on Qt 5.4 yet it's using ifdefs. Once we have Qt 5.4 the old code will be removed. --- clients/aurorae/src/aurorae.cpp | 94 +++++++++++++++++++++++++++++++++ clients/aurorae/src/aurorae.h | 7 +++ 2 files changed, 101 insertions(+) diff --git a/clients/aurorae/src/aurorae.cpp b/clients/aurorae/src/aurorae.cpp index 47376a2e5e..23a6071f26 100644 --- a/clients/aurorae/src/aurorae.cpp +++ b/clients/aurorae/src/aurorae.cpp @@ -34,14 +34,27 @@ along with this program. If not, see . // Qt #include #include +#include +#include #include #include #include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) +#define HAVE_RENDER_CONTROL 1 +#else +#define HAVE_RENDER_CONTROL 0 +#endif + +#if HAVE_RENDER_CONTROL +#include +#endif #include #include #include #include #include +#include K_PLUGIN_FACTORY_WITH_JSON(AuroraeDecoFactory, "aurorae.json", @@ -234,6 +247,18 @@ Decoration::Decoration(QObject *parent, const QVariantList &args) Decoration::~Decoration() { Helper::instance().unref(); +#if HAVE_RENDER_CONTROL + if (m_context) { + m_context->makeCurrent(m_offscreenSurface.data()); + + delete m_renderControl; + delete m_view.data(); + m_fbo.reset(); + delete m_item; + + m_context->doneCurrent(); + } +#endif } void Decoration::init() @@ -241,6 +266,7 @@ void Decoration::init() KDecoration2::Decoration::init(); auto s = settings(); // recreate scene when compositing gets disabled, TODO: remove with rendercontrol +#if !HAVE_RENDER_CONTROL if (!m_recreateNonCompositedConnection) { m_recreateNonCompositedConnection = connect(s.data(), &KDecoration2::DecorationSettings::alphaChannelSupportedChanged, this, [this](bool alpha) { @@ -251,6 +277,7 @@ void Decoration::init() } }); } +#endif QQmlContext *context = new QQmlContext(Helper::instance().rootContext(), this); context->setContextProperty(QStringLiteral("decoration"), this); @@ -282,6 +309,66 @@ void Decoration::init() m_item->setParentItem(visualParent.value()); visualParent.value()->setProperty("drawBackground", false); } else { +#if HAVE_RENDER_CONTROL + // first create the context + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + m_context.reset(new QOpenGLContext); + m_context->setFormat(format); + m_context->create(); + // and the offscreen surface + m_offscreenSurface.reset(new QOffscreenSurface); + m_offscreenSurface->setFormat(m_context->format()); + m_offscreenSurface->create(); + + m_renderControl = new QQuickRenderControl(this); + m_view = new QQuickWindow(m_renderControl); + m_view->setColor(Qt::transparent); + + // delay rendering a little bit for better performance + m_updateTimer.reset(new QTimer); + m_updateTimer->setSingleShot(true); + m_updateTimer->setInterval(5); + connect(m_updateTimer.data(), &QTimer::timeout, this, + [this] { + if (!m_context->makeCurrent(m_offscreenSurface.data())) { + return; + } + if (m_fbo.isNull() || m_fbo->size() != m_view->size()) { + m_fbo.reset(new QOpenGLFramebufferObject(m_view->size(), QOpenGLFramebufferObject::CombinedDepthStencil)); + if (!m_fbo->isValid()) { + qCWarning(AURORAE) << "Creating FBO as render target failed"; + m_fbo.reset(); + return; + } + } + m_view->setRenderTarget(m_fbo.data()); + m_renderControl->polishItems(); + m_renderControl->sync(); + m_renderControl->render(); + + m_view->resetOpenGLState(); + m_buffer = m_fbo->toImage(); + QOpenGLFramebufferObject::bindDefault(); + update(); + } + ); + auto requestUpdate = [this] { + if (m_updateTimer->isActive()) { + return; + } + m_updateTimer->start(); + }; + connect(m_renderControl, &QQuickRenderControl::renderRequested, this, requestUpdate); + connect(m_renderControl, &QQuickRenderControl::sceneChanged, this, requestUpdate); + + m_item->setParentItem(m_view->contentItem()); + + m_context->makeCurrent(m_offscreenSurface.data()); + m_renderControl->initialize(m_context.data()); + m_context->doneCurrent(); +#else // we need a QQuickWindow till we depend on Qt 5.4 m_decorationWindow.reset(QWindow::fromWinId(client().data()->decorationId())); m_view = new QQuickWindow(m_decorationWindow.data()); @@ -314,6 +401,7 @@ void Decoration::init() m_view.data(), &QQuickWindow::update); connect(m_view.data(), &QQuickWindow::afterRendering, this, [this] { update(); }, Qt::QueuedConnection); m_item->setParentItem(m_view->contentItem()); +#endif } setupBorders(m_item); if (m_extendedBorders) { @@ -329,15 +417,19 @@ void Decoration::init() connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateBorders, Qt::QueuedConnection); updateBorders(); if (!m_view.isNull()) { +#if !HAVE_RENDER_CONTROL m_view->setVisible(true); +#endif auto resizeWindow = [this] { QRect rect(QPoint(0, 0), size()); if (m_padding && !client().data()->isMaximized()) { rect = rect.adjusted(-m_padding->left(), -m_padding->top(), m_padding->right(), m_padding->bottom()); } m_view->setGeometry(rect); +#if !HAVE_RENDER_CONTROL m_view->lower(); m_view->update(); +#endif }; connect(this, &Decoration::bordersChanged, this, resizeWindow); connect(client().data(), &KDecoration2::DecoratedClient::widthChanged, this, resizeWindow); @@ -384,10 +476,12 @@ void Decoration::updateBorders() void Decoration::paint(QPainter *painter, const QRect &repaintRegion) { Q_UNUSED(repaintRegion) +#if !HAVE_RENDER_CONTROL if (!settings()->isAlphaChannelSupported()) { return; } QMutexLocker locker(&m_mutex); +#endif painter->fillRect(rect(), Qt::transparent); QRectF r(QPointF(0, 0), m_buffer.size()); if (m_padding && diff --git a/clients/aurorae/src/aurorae.h b/clients/aurorae/src/aurorae.h index 4dfdc56e46..aa49d86b6d 100644 --- a/clients/aurorae/src/aurorae.h +++ b/clients/aurorae/src/aurorae.h @@ -22,10 +22,13 @@ along with this program. If not, see . #include #include +class QOffscreenSurface; +class QOpenGLContext; class QOpenGLFramebufferObject; class QQmlComponent; class QQmlEngine; class QQuickItem; +class QQuickRenderControl; class QQuickWindow; class QWindow; @@ -79,6 +82,10 @@ private: QString m_themeName; QMutex m_mutex; QMetaObject::Connection m_recreateNonCompositedConnection; + QQuickRenderControl *m_renderControl = nullptr; + QScopedPointer m_updateTimer; + QScopedPointer m_context; + QScopedPointer m_offscreenSurface; }; class ThemeFinder : public QObject