diff options
author | Giulio Camuffo <giulio.camuffo@jollamobile.com> | 2014-03-25 14:19:55 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-29 10:09:31 +0200 |
commit | fc439e40e37f9c0b3108225f951fb19bb3abee80 (patch) | |
tree | 851bf52ee2004b3b201b5e86df7a4d4db7f79a2c /src/compositor/compositor_api/qwaylandquicksurface.cpp | |
parent | c551e6df6c77f65a0db62b3ad4db539e86b75a30 (diff) |
Rework the way buffers are used and rendered
The current way buffers are handled is sub-optimal. They are hidden
inside QtWayland::Surface and the actual renderer, be it QtQuick or
anything else, cannot get a direct hold of them, nor it can directly
control when the underlying textures are created or deleted.
The main additions in this commit are the splitting of the QtQuick
code path and the new QWaylandBufferRef and QWaylandBufferAttacher
classes.
QWaylandBufferRef allows a renderer to retain a reference
to a wl_buffer even after the underlying Surface discarded it.
That allows the renderer to directly decide when to destroy the texture
of the buffer.
QWaylandBufferAttacher is a pure virtual class which must be implemented
by the renderer. Instances of it will be assigned to the QWaylandSurfaces,
created. Its attach() virtual method will then be called when a new buffer
is committed to the surface. The renderer can then choose to immediately
create a texture or wait for some later time. It is its responsibility to
create and destroy the GL texture, it will not happen automatically.
This functionality is implemented for QtQuick in the new QWaylandQuickCompositor
and QWaylandQuickSurface classes.
Change-Id: I674b4e5fb8c65c3b1c582e33ff3a0b0e45f2acc9
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Diffstat (limited to 'src/compositor/compositor_api/qwaylandquicksurface.cpp')
-rw-r--r-- | src/compositor/compositor_api/qwaylandquicksurface.cpp | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/src/compositor/compositor_api/qwaylandquicksurface.cpp b/src/compositor/compositor_api/qwaylandquicksurface.cpp new file mode 100644 index 000000000..e4a5f7732 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandquicksurface.cpp @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QSGTexture> +#include <QOpenGLTexture> +#include <QQuickWindow> +#include <QDebug> +#include <QQmlPropertyMap> + +#include "qwaylandquicksurface.h" +#include "qwaylandquickcompositor.h" +#include "qwaylandsurfaceitem.h" +#include <QtCompositor/qwaylandbufferref.h> +#include <QtCompositor/private/qwaylandsurface_p.h> + +QT_BEGIN_NAMESPACE + +class BufferAttacher : public QWaylandBufferAttacher +{ +public: + BufferAttacher() + : surface(0) + , texture(0) + , update(false) + { + + } + + ~BufferAttacher() + { + if (texture) + texture->deleteLater(); + bufferRef = QWaylandBufferRef(); + nextBuffer = QWaylandBufferRef(); + } + + void attach(const QWaylandBufferRef &ref) Q_DECL_OVERRIDE + { + nextBuffer = ref; + update = true; + } + + void createTexture() + { + if (bufferRef) + bufferRef.destroyTexture(); + bufferRef = nextBuffer; + + QQuickWindow *window = static_cast<QQuickWindow *>(surface->compositor()->window()); + // If the next buffer is NULL do not delete the current texture. If the client called + // attach(0) the surface is going to be unmapped anyway, if instead the client attached + // a valid buffer but died before we got here we want to keep the old buffer around + // in case some destroy animation is run. + if (bufferRef) { + delete texture; + + if (bufferRef.isShm()) { + texture = window->createTextureFromImage(bufferRef.image()); + } else { + QQuickWindow::CreateTextureOptions opt = 0; + if (surface->useTextureAlpha()) { + opt |= QQuickWindow::TextureHasAlphaChannel; + } + texture = window->createTextureFromId(bufferRef.createTexture(), surface->size(), opt); + } + texture->bind(); + } + + update = false; + } + + void invalidateTexture() + { + delete texture; + texture = 0; + } + + QWaylandQuickSurface *surface; + QWaylandBufferRef bufferRef; + QWaylandBufferRef nextBuffer; + QSGTexture *texture; + bool update; +}; + + +class QWaylandQuickSurfacePrivate : public QWaylandSurfacePrivate +{ +public: + QWaylandQuickSurfacePrivate(wl_client *client, quint32 id, QWaylandQuickCompositor *c, QWaylandQuickSurface *surf) + : QWaylandSurfacePrivate(client, id, c, surf) + , buffer(new BufferAttacher) + , compositor(c) + , useTextureAlpha(true) + , windowPropertyMap(new QQmlPropertyMap) + , clientRenderingEnabled(true) + { + + } + + ~QWaylandQuickSurfacePrivate() + { + windowPropertyMap->deleteLater(); + // buffer is deleted automatically by ~Surface(), since it is the assigned attacher + } + + void surface_commit(Resource *resource) Q_DECL_OVERRIDE + { + if (m_pending.newlyAttached) { + buffer->update = true; + } + QWaylandSurfacePrivate::surface_commit(resource); + + compositor->update(); + } + + BufferAttacher *buffer; + QWaylandQuickCompositor *compositor; + bool useTextureAlpha; + QQmlPropertyMap *windowPropertyMap; + bool clientRenderingEnabled; +}; + +QWaylandQuickSurface::QWaylandQuickSurface(wl_client *client, quint32 id, QWaylandQuickCompositor *compositor) + : QWaylandSurface(new QWaylandQuickSurfacePrivate(client, id, compositor, this)) +{ + Q_D(QWaylandQuickSurface); + d->buffer->surface = this; + setBufferAttacher(d->buffer); + + QQuickWindow *window = static_cast<QQuickWindow *>(compositor->window()); + connect(window, &QQuickWindow::beforeSynchronizing, this, &QWaylandQuickSurface::updateTexture, Qt::DirectConnection); + connect(window, &QQuickWindow::sceneGraphInvalidated, this, &QWaylandQuickSurface::invalidateTexture, Qt::DirectConnection); + connect(this, &QWaylandSurface::windowPropertyChanged, d->windowPropertyMap, &QQmlPropertyMap::insert); + connect(d->windowPropertyMap, &QQmlPropertyMap::valueChanged, this, &QWaylandSurface::setWindowProperty); + +} + +QWaylandQuickSurface::~QWaylandQuickSurface() +{ + +} + +QSGTexture *QWaylandQuickSurface::texture() const +{ + Q_D(const QWaylandQuickSurface); + return d->buffer->texture; +} + +bool QWaylandQuickSurface::useTextureAlpha() const +{ + Q_D(const QWaylandQuickSurface); + return d->useTextureAlpha; +} + +void QWaylandQuickSurface::setUseTextureAlpha(bool useTextureAlpha) +{ + Q_D(QWaylandQuickSurface); + if (d->useTextureAlpha != useTextureAlpha) { + d->useTextureAlpha = useTextureAlpha; + emit useTextureAlphaChanged(); + emit configure(); + } +} + +QObject *QWaylandQuickSurface::windowPropertyMap() const +{ + Q_D(const QWaylandQuickSurface); + return d->windowPropertyMap; +} + + +void QWaylandQuickSurface::updateTexture() +{ + Q_D(QWaylandQuickSurface); + if (d->buffer->update) + d->buffer->createTexture(); +} + +void QWaylandQuickSurface::invalidateTexture() +{ + Q_D(QWaylandQuickSurface); + d->buffer->invalidateTexture(); +} + +bool QWaylandQuickSurface::clientRenderingEnabled() const +{ + Q_D(const QWaylandQuickSurface); + return d->clientRenderingEnabled; +} + +void QWaylandQuickSurface::setClientRenderingEnabled(bool enabled) +{ + Q_D(QWaylandQuickSurface); + if (d->clientRenderingEnabled != enabled) { + d->clientRenderingEnabled = enabled; + + sendOnScreenVisibilityChange(enabled); + + emit clientRenderingEnabledChanged(); + } +} + +QT_END_NAMESPACE |