[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.
This commit is contained in:
parent
f78ff8eaa5
commit
ca27bc09c5
2 changed files with 101 additions and 0 deletions
|
@ -34,14 +34,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QDirIterator>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QPainter>
|
||||
#include <QQuickItem>
|
||||
|
||||
#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 <QQuickRenderControl>
|
||||
#endif
|
||||
#include <QQuickWindow>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QStandardPaths>
|
||||
#include <QTimer>
|
||||
|
||||
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<QQuickItem*>());
|
||||
visualParent.value<QQuickItem*>()->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 &&
|
||||
|
|
|
@ -22,10 +22,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QVariant>
|
||||
#include <QMutex>
|
||||
|
||||
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<QTimer> m_updateTimer;
|
||||
QScopedPointer<QOpenGLContext> m_context;
|
||||
QScopedPointer<QOffscreenSurface> m_offscreenSurface;
|
||||
};
|
||||
|
||||
class ThemeFinder : public QObject
|
||||
|
|
Loading…
Reference in a new issue