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