From 37cce4cadace48a22cbc5252810237341a371b10 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 19 Nov 2014 14:58:43 +0100 Subject: Add generic OpenGL compositor and backingstore bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By removing the EGL(FS) dependencies we get classes that can be used by any platform plugin that runs without a windowing system. Change-Id: If99b42de5a4da02bbef80863609b6d92c6734613 Reviewed-by: Jørgen Lind --- .../eglconvenience/eglconvenience.pri | 4 - .../eglconvenience/qeglcompositor.cpp | 185 ---------------- .../eglconvenience/qeglcompositor_p.h | 83 ------- .../eglconvenience/qeglplatformbackingstore.cpp | 241 -------------------- .../eglconvenience/qeglplatformbackingstore_p.h | 96 -------- .../eglconvenience/qeglplatformintegration.cpp | 9 +- .../eglconvenience/qeglplatformscreen.cpp | 49 +---- .../eglconvenience/qeglplatformscreen_p.h | 13 -- .../eglconvenience/qeglplatformwindow.cpp | 22 +- .../eglconvenience/qeglplatformwindow_p.h | 17 +- .../platformcompositor/platformcompositor.pri | 7 + .../platformcompositor/qopenglcompositor.cpp | 243 +++++++++++++++++++++ .../platformcompositor/qopenglcompositor_p.h | 107 +++++++++ .../qopenglcompositorbackingstore.cpp | 236 ++++++++++++++++++++ .../qopenglcompositorbackingstore_p.h | 92 ++++++++ src/platformsupport/platformsupport.pro | 1 + 16 files changed, 718 insertions(+), 687 deletions(-) delete mode 100644 src/platformsupport/eglconvenience/qeglcompositor.cpp delete mode 100644 src/platformsupport/eglconvenience/qeglcompositor_p.h delete mode 100644 src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp delete mode 100644 src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h create mode 100644 src/platformsupport/platformcompositor/platformcompositor.pri create mode 100644 src/platformsupport/platformcompositor/qopenglcompositor.cpp create mode 100644 src/platformsupport/platformcompositor/qopenglcompositor_p.h create mode 100644 src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp create mode 100644 src/platformsupport/platformcompositor/qopenglcompositorbackingstore_p.h (limited to 'src/platformsupport') diff --git a/src/platformsupport/eglconvenience/eglconvenience.pri b/src/platformsupport/eglconvenience/eglconvenience.pri index 8ada53d2c1..d102203d5e 100644 --- a/src/platformsupport/eglconvenience/eglconvenience.pri +++ b/src/platformsupport/eglconvenience/eglconvenience.pri @@ -16,16 +16,12 @@ contains(QT_CONFIG,egl) { $$PWD/qeglplatformcursor_p.h \ $$PWD/qeglplatformwindow_p.h \ $$PWD/qeglplatformscreen_p.h \ - $$PWD/qeglcompositor_p.h \ - $$PWD/qeglplatformbackingstore_p.h \ $$PWD/qeglplatformintegration_p.h SOURCES += \ $$PWD/qeglplatformcursor.cpp \ $$PWD/qeglplatformwindow.cpp \ $$PWD/qeglplatformscreen.cpp \ - $$PWD/qeglcompositor.cpp \ - $$PWD/qeglplatformbackingstore.cpp \ $$PWD/qeglplatformintegration.cpp } } diff --git a/src/platformsupport/eglconvenience/qeglcompositor.cpp b/src/platformsupport/eglconvenience/qeglcompositor.cpp deleted file mode 100644 index 5866edc48d..0000000000 --- a/src/platformsupport/eglconvenience/qeglcompositor.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include - -#include "qeglcompositor_p.h" -#include "qeglplatformwindow_p.h" -#include "qeglplatformscreen_p.h" - -QT_BEGIN_NAMESPACE - -static QEGLCompositor *compositor = 0; - -QEGLCompositor::QEGLCompositor() - : m_context(0), - m_window(0), - m_blitter(0) -{ - Q_ASSERT(!compositor); - m_updateTimer.setSingleShot(true); - m_updateTimer.setInterval(0); - connect(&m_updateTimer, SIGNAL(timeout()), SLOT(renderAll())); -} - -QEGLCompositor::~QEGLCompositor() -{ - Q_ASSERT(compositor == this); - if (m_blitter) { - m_blitter->destroy(); - delete m_blitter; - } - compositor = 0; -} - -void QEGLCompositor::schedule(QOpenGLContext *context, QEGLPlatformWindow *window) -{ - m_context = context; - m_window = window; - if (!m_updateTimer.isActive()) - m_updateTimer.start(); -} - -void QEGLCompositor::renderAll() -{ - Q_ASSERT(m_context && m_window); - m_context->makeCurrent(m_window->window()); - - if (!m_blitter) { - m_blitter = new QOpenGLTextureBlitter; - m_blitter->create(); - } - m_blitter->bind(); - - QEGLPlatformScreen *screen = static_cast(m_window->screen()); - QList windows = screen->windows(); - for (int i = 0; i < windows.size(); ++i) - render(windows.at(i)); - - m_blitter->release(); - m_context->swapBuffers(m_window->window()); - - for (int i = 0; i < windows.size(); ++i) - windows.at(i)->composited(); -} - -struct BlendStateBinder -{ - BlendStateBinder() : m_blend(false) { - glDisable(GL_BLEND); - } - void set(bool blend) { - if (blend != m_blend) { - if (blend) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } - m_blend = blend; - } - } - ~BlendStateBinder() { - if (m_blend) - glDisable(GL_BLEND); - } - bool m_blend; -}; - -void QEGLCompositor::render(QEGLPlatformWindow *window) -{ - const QPlatformTextureList *textures = window->textures(); - if (!textures) - return; - - const QRect targetWindowRect(QPoint(0, 0), window->screen()->geometry().size()); - glViewport(0, 0, targetWindowRect.width(), targetWindowRect.height()); - - float currentOpacity = 1.0f; - BlendStateBinder blend; - - for (int i = 0; i < textures->count(); ++i) { - uint textureId = textures->textureId(i); - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), - targetWindowRect); - const float opacity = window->window()->opacity(); - if (opacity != currentOpacity) { - currentOpacity = opacity; - m_blitter->setOpacity(currentOpacity); - } - - if (textures->count() > 1 && i == textures->count() - 1) { - // Backingstore for a widget with QOpenGLWidget subwidgets - blend.set(true); - m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); - } else if (textures->count() == 1) { - // A regular QWidget window - const bool translucent = window->window()->requestedFormat().alphaBufferSize() > 0; - blend.set(translucent); - m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); - } else if (!textures->stacksOnTop(i)) { - // Texture from an FBO belonging to a QOpenGLWidget - blend.set(false); - m_blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); - } - } - - for (int i = 0; i < textures->count(); ++i) { - if (textures->stacksOnTop(i)) { - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); - blend.set(true); - m_blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); - } - } - - m_blitter->setOpacity(1.0f); -} - -QEGLCompositor *QEGLCompositor::instance() -{ - if (!compositor) - compositor = new QEGLCompositor; - return compositor; -} - -void QEGLCompositor::destroy() -{ - delete compositor; - compositor = 0; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglcompositor_p.h b/src/platformsupport/eglconvenience/qeglcompositor_p.h deleted file mode 100644 index 1401fbdd55..0000000000 --- a/src/platformsupport/eglconvenience/qeglcompositor_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGLCOMPOSITOR_H -#define QEGLCOMPOSITOR_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -QT_BEGIN_NAMESPACE - -class QOpenGLContext; -class QOpenGLTextureBlitter; -class QEGLPlatformWindow; - -class QEGLCompositor : public QObject -{ - Q_OBJECT - -public: - void schedule(QOpenGLContext *context, QEGLPlatformWindow *window); - - static QEGLCompositor *instance(); - static void destroy(); - -private slots: - void renderAll(); - -private: - QEGLCompositor(); - ~QEGLCompositor(); - - void render(QEGLPlatformWindow *window); - - QOpenGLContext *m_context; - QEGLPlatformWindow *m_window; - QTimer m_updateTimer; - QOpenGLTextureBlitter *m_blitter; -}; - -QT_END_NAMESPACE - -#endif // QEGLCOMPOSITOR_H diff --git a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp b/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp deleted file mode 100644 index 43c18573f2..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformbackingstore.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include - -#include "qeglplatformbackingstore_p.h" -#include "qeglcompositor_p.h" -#include "qeglplatformwindow_p.h" -#include "qeglplatformscreen_p.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QEGLPlatformBackingStore - \brief A backing store implementation for EGL and GLES. - \since 5.2 - \internal - \ingroup qpa - - This implementation uploads raster-rendered widget windows into - textures and composites them onto a single native window using - QEGLCompositor. This means that multiple top-level widgets are - supported without creating actual native windows for each of them. - - The class is ready to be used as-is, the default - QEGLPlatformIntegration::createPlatformBackingStore() - implementation creates an instance which is ready to be used - without further customization. - - If QEGLCompositor is not suitable, this backing store - implementation can also be used without it. In this case a - subclass must reimplement composite() and schedule an update in - its custom compositor when this function is called. The textures - are accessible via QEGLPlatformWindow::texture(). -*/ - -QEGLPlatformBackingStore::QEGLPlatformBackingStore(QWindow *window) - : QPlatformBackingStore(window), - m_window(static_cast(window->handle())), - m_bsTexture(0), - m_textures(new QPlatformTextureList), - m_lockedWidgetTextures(0) -{ - m_window->setBackingStore(this); -} - -QEGLPlatformBackingStore::~QEGLPlatformBackingStore() -{ - delete m_textures; -} - -QPaintDevice *QEGLPlatformBackingStore::paintDevice() -{ - return &m_image; -} - -void QEGLPlatformBackingStore::updateTexture() -{ - if (!m_bsTexture) { - glGenTextures(1, &m_bsTexture); - glBindTexture(GL_TEXTURE_2D, m_bsTexture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_image.width(), m_image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - } else { - glBindTexture(GL_TEXTURE_2D, m_bsTexture); - } - - if (!m_dirty.isNull()) { - QRegion fixed; - QRect imageRect = m_image.rect(); - - foreach (const QRect &rect, m_dirty.rects()) { - // intersect with image rect to be sure - QRect r = imageRect & rect; - - // if the rect is wide enough it's cheaper to just - // extend it instead of doing an image copy - if (r.width() >= imageRect.width() / 2) { - r.setX(0); - r.setWidth(imageRect.width()); - } - - fixed |= r; - } - - foreach (const QRect &rect, fixed.rects()) { - // if the sub-rect is full-width we can pass the image data directly to - // OpenGL instead of copying, since there's no gap between scanlines - if (rect.width() == imageRect.width()) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - m_image.constScanLine(rect.y())); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - m_image.copy(rect).constBits()); - } - } - - m_dirty = QRegion(); - } -} - -void QEGLPlatformBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - // Called for ordinary raster windows. This is rare since RasterGLSurface - // support is claimed which leads to having all QWidget windows marked as - // RasterGLSurface instead of just Raster. These go through - // compositeAndFlush() instead of this function. - - Q_UNUSED(region); - Q_UNUSED(offset); - - QEGLPlatformScreen *screen = static_cast(m_window->screen()); - QEGLPlatformWindow *dstWin = screen->compositingWindow(); - if (!dstWin || !dstWin->isRaster()) - return; - - screen->compositingContext()->makeCurrent(dstWin->window()); - updateTexture(); - m_textures->clear(); - m_textures->appendTexture(m_bsTexture, window->geometry()); - composite(screen->compositingContext(), dstWin); -} - -void QEGLPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, - QPlatformTextureList *textures, QOpenGLContext *context, - bool translucentBackground) -{ - // QOpenGLWidget content provided as textures. The raster content should go on top. - - Q_UNUSED(region); - Q_UNUSED(offset); - Q_UNUSED(context); - Q_UNUSED(translucentBackground); - - QEGLPlatformScreen *screen = static_cast(m_window->screen()); - QEGLPlatformWindow *dstWin = screen->compositingWindow(); - if (!dstWin || !dstWin->isRaster()) - return; - - screen->compositingContext()->makeCurrent(dstWin->window()); - - m_textures->clear(); - for (int i = 0; i < textures->count(); ++i) - m_textures->appendTexture(textures->textureId(i), textures->geometry(i), textures->stacksOnTop(i)); - - updateTexture(); - m_textures->appendTexture(m_bsTexture, window->geometry()); - - textures->lock(true); - m_lockedWidgetTextures = textures; - - composite(screen->compositingContext(), dstWin); -} - -void QEGLPlatformBackingStore::composite(QOpenGLContext *context, QEGLPlatformWindow *window) -{ - QEGLCompositor::instance()->schedule(context, window); -} - -void QEGLPlatformBackingStore::composited() -{ - if (m_lockedWidgetTextures) { - QPlatformTextureList *textureList = m_lockedWidgetTextures; - m_lockedWidgetTextures = 0; // may reenter so null before unlocking - textureList->lock(false); - } -} - -void QEGLPlatformBackingStore::beginPaint(const QRegion ®ion) -{ - m_dirty |= region; - - if (m_image.hasAlphaChannel()) { - QPainter p(&m_image); - p.setCompositionMode(QPainter::CompositionMode_Source); - foreach (const QRect &r, region.rects()) - p.fillRect(r, Qt::transparent); - } -} - -void QEGLPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents) -{ - Q_UNUSED(staticContents); - - QEGLPlatformScreen *screen = static_cast(m_window->screen()); - QEGLPlatformWindow *dstWin = screen->compositingWindow(); - if (!dstWin || (!dstWin->isRaster() && dstWin->window()->surfaceType() != QSurface::RasterGLSurface)) - return; - - m_image = QImage(size, QImage::Format_RGBA8888); - - m_window->create(); - - screen->compositingContext()->makeCurrent(dstWin->window()); - if (m_bsTexture) { - glDeleteTextures(1, &m_bsTexture); - m_bsTexture = 0; - } -} - -QImage QEGLPlatformBackingStore::toImage() const -{ - return m_image; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h b/src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h deleted file mode 100644 index 502ca5a639..0000000000 --- a/src/platformsupport/eglconvenience/qeglplatformbackingstore_p.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGLPLATFORMBACKINGSTORE_H -#define QEGLPLATFORMBACKINGSTORE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QOpenGLContext; -class QPlatformTextureList; -class QEGLPlatformWindow; - -class QEGLPlatformBackingStore : public QPlatformBackingStore -{ -public: - QEGLPlatformBackingStore(QWindow *window); - ~QEGLPlatformBackingStore(); - - QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - - void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; - - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; - void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; - - QImage toImage() const Q_DECL_OVERRIDE; - void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, - QPlatformTextureList *textures, QOpenGLContext *context, - bool translucentBackground) Q_DECL_OVERRIDE; - - const QPlatformTextureList *textures() const { return m_textures; } - - virtual void composite(QOpenGLContext *context, QEGLPlatformWindow *window); - - void composited(); - -private: - void updateTexture(); - - QEGLPlatformWindow *m_window; - QImage m_image; - QRegion m_dirty; - uint m_bsTexture; - QPlatformTextureList *m_textures; - QPlatformTextureList *m_lockedWidgetTextures; -}; - -QT_END_NAMESPACE - -#endif // QEGLPLATFORMBACKINGSTORE_H diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp index fea2ae2369..09011e6e58 100644 --- a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) #include @@ -59,7 +60,6 @@ #include "qeglplatformintegration_p.h" #include "qeglplatformcontext_p.h" #include "qeglplatformwindow_p.h" -#include "qeglplatformbackingstore_p.h" #include "qeglplatformscreen_p.h" #include "qeglplatformcursor_p.h" @@ -141,7 +141,9 @@ QPlatformFontDatabase *QEGLPlatformIntegration::fontDatabase() const QPlatformBackingStore *QEGLPlatformIntegration::createPlatformBackingStore(QWindow *window) const { - return new QEGLPlatformBackingStore(window); + QOpenGLCompositorBackingStore *bs = new QOpenGLCompositorBackingStore(window); + static_cast(window->handle())->setBackingStore(bs); + return bs; } QPlatformWindow *QEGLPlatformIntegration::createPlatformWindow(QWindow *window) const @@ -156,10 +158,9 @@ QPlatformWindow *QEGLPlatformIntegration::createPlatformWindow(QWindow *window) QPlatformOpenGLContext *QEGLPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - QEGLPlatformScreen *screen = static_cast(context->screen()->handle()); // If there is a "root" window into which raster and QOpenGLWidget content is // composited, all other contexts must share with its context. - QOpenGLContext *compositingContext = screen ? screen->compositingContext() : 0; + QOpenGLContext *compositingContext = QOpenGLCompositor::instance()->context(); QPlatformOpenGLContext *share = compositingContext ? compositingContext->handle() : context->shareHandle(); QVariant nativeHandle = context->nativeHandle(); QPlatformOpenGLContext *platformContext = createContext(context->format(), diff --git a/src/platformsupport/eglconvenience/qeglplatformscreen.cpp b/src/platformsupport/eglconvenience/qeglplatformscreen.cpp index fd577a48d7..fd9befb575 100644 --- a/src/platformsupport/eglconvenience/qeglplatformscreen.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformscreen.cpp @@ -31,8 +31,8 @@ ** ****************************************************************************/ -#include "qeglcompositor_p.h" #include "qeglplatformscreen_p.h" +#include QT_BEGIN_NAMESPACE @@ -42,19 +42,6 @@ QT_BEGIN_NAMESPACE \since 5.2 \internal \ingroup qpa - - This class provides a lightweight base for QPlatformScreen - implementations. It covers basic window stack management which is - necessary when compositing multiple raster (widget-based) windows - together into one single native surface. - - Reimplementing the virtuals are essential when using - QEGLPlatformBackingStore. The context and the window returned from - these are the ones that are used when compositing the textures - generated from the raster (widget) based windows. - - \note It is up to the QEGLPlatformWindow subclasses to use the - functions, like addWindow(), removeWindow(), etc., provided here. */ QEGLPlatformScreen::QEGLPlatformScreen(EGLDisplay dpy) @@ -64,39 +51,7 @@ QEGLPlatformScreen::QEGLPlatformScreen(EGLDisplay dpy) QEGLPlatformScreen::~QEGLPlatformScreen() { - QEGLCompositor::destroy(); -} - -void QEGLPlatformScreen::addWindow(QEGLPlatformWindow *window) -{ - if (!m_windows.contains(window)) { - m_windows.append(window); - topWindowChanged(window); - } -} - -void QEGLPlatformScreen::removeWindow(QEGLPlatformWindow *window) -{ - m_windows.removeOne(window); - if (!m_windows.isEmpty()) - topWindowChanged(m_windows.last()); -} - -void QEGLPlatformScreen::moveToTop(QEGLPlatformWindow *window) -{ - m_windows.removeOne(window); - m_windows.append(window); - topWindowChanged(window); -} - -void QEGLPlatformScreen::changeWindowIndex(QEGLPlatformWindow *window, int newIdx) -{ - int idx = m_windows.indexOf(window); - if (idx != -1 && idx != newIdx) { - m_windows.move(idx, newIdx); - if (newIdx == m_windows.size() - 1) - topWindowChanged(m_windows.last()); - } + QOpenGLCompositor::destroy(); } QT_END_NAMESPACE diff --git a/src/platformsupport/eglconvenience/qeglplatformscreen_p.h b/src/platformsupport/eglconvenience/qeglplatformscreen_p.h index bb1d26d7d2..e9d3363a66 100644 --- a/src/platformsupport/eglconvenience/qeglplatformscreen_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformscreen_p.h @@ -60,22 +60,9 @@ public: QEGLPlatformScreen(EGLDisplay dpy); ~QEGLPlatformScreen(); - QList windows() const { return m_windows; } - - void addWindow(QEGLPlatformWindow *window); - void removeWindow(QEGLPlatformWindow *window); - void moveToTop(QEGLPlatformWindow *window); - void changeWindowIndex(QEGLPlatformWindow *window, int newIdx); - - virtual void topWindowChanged(QEGLPlatformWindow *window) { Q_UNUSED(window); } - EGLDisplay display() const { return m_dpy; } - virtual QEGLPlatformWindow *compositingWindow() = 0; - virtual QOpenGLContext *compositingContext() = 0; - private: - QList m_windows; EGLDisplay m_dpy; }; diff --git a/src/platformsupport/eglconvenience/qeglplatformwindow.cpp b/src/platformsupport/eglconvenience/qeglplatformwindow.cpp index af4c907e85..5e5c879a22 100644 --- a/src/platformsupport/eglconvenience/qeglplatformwindow.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformwindow.cpp @@ -32,9 +32,10 @@ ****************************************************************************/ #include +#include +#include #include "qeglplatformwindow_p.h" -#include "qeglplatformbackingstore_p.h" #include "qeglplatformscreen_p.h" QT_BEGIN_NAMESPACE @@ -47,7 +48,7 @@ QT_BEGIN_NAMESPACE \ingroup qpa Lightweight class providing some basic platform window operations - and interfacing with QEGLPlatformBackingStore. + and interfacing with QOpenGLCompositorBackingStore. Almost no QPlatformWindow functions are implemented here. This is intentional because different platform plugins may use different @@ -57,13 +58,15 @@ QT_BEGIN_NAMESPACE enforce anything for these functions. \note Subclasses are responsible for invoking this class' - implementation of create(). When using QEGLPlatformScreen, the - subclasses of this class are expected to utilize the window stack - management functions (addWindow() etc.) provided there. + implementation of create() and are expected to utilize the window + stack management functions (addWindow() etc.) in + QOpenGLCompositor. */ QEGLPlatformWindow::QEGLPlatformWindow(QWindow *w) : QPlatformWindow(w), + m_backingStore(0), + m_raster(false), m_winId(0) { } @@ -100,6 +103,11 @@ bool QEGLPlatformWindow::isRaster() const return m_raster || window()->surfaceType() == QSurface::RasterGLSurface; } +QWindow *QEGLPlatformWindow::sourceWindow() const +{ + return window(); +} + const QPlatformTextureList *QEGLPlatformWindow::textures() const { if (m_backingStore) @@ -108,10 +116,10 @@ const QPlatformTextureList *QEGLPlatformWindow::textures() const return 0; } -void QEGLPlatformWindow::composited() +void QEGLPlatformWindow::endCompositing() { if (m_backingStore) - m_backingStore->composited(); + m_backingStore->notifyComposited(); } WId QEGLPlatformWindow::winId() const diff --git a/src/platformsupport/eglconvenience/qeglplatformwindow_p.h b/src/platformsupport/eglconvenience/qeglplatformwindow_p.h index 3a19301e5d..947f02aeb5 100644 --- a/src/platformsupport/eglconvenience/qeglplatformwindow_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformwindow_p.h @@ -46,33 +46,36 @@ // #include +#include #include QT_BEGIN_NAMESPACE -class QEGLPlatformBackingStore; +class QOpenGLCompositorBackingStore; class QPlatformTextureList; -class QEGLPlatformWindow : public QPlatformWindow +class QEGLPlatformWindow : public QPlatformWindow, public QOpenGLCompositorWindow { public: QEGLPlatformWindow(QWindow *w); virtual void create(); - QEGLPlatformBackingStore *backingStore() { return m_backingStore; } - void setBackingStore(QEGLPlatformBackingStore *backingStore) { m_backingStore = backingStore; } - const QPlatformTextureList *textures() const; - void composited(); + QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; } + void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; } bool isRaster() const; + QWindow *sourceWindow() const Q_DECL_OVERRIDE; + const QPlatformTextureList *textures() const Q_DECL_OVERRIDE; + void endCompositing() Q_DECL_OVERRIDE; + WId winId() const Q_DECL_OVERRIDE; void setOpacity(qreal opacity) Q_DECL_OVERRIDE; virtual EGLNativeWindowType eglWindow() const = 0; private: - QEGLPlatformBackingStore *m_backingStore; + QOpenGLCompositorBackingStore *m_backingStore; bool m_raster; WId m_winId; }; diff --git a/src/platformsupport/platformcompositor/platformcompositor.pri b/src/platformsupport/platformcompositor/platformcompositor.pri new file mode 100644 index 0000000000..923d7225da --- /dev/null +++ b/src/platformsupport/platformcompositor/platformcompositor.pri @@ -0,0 +1,7 @@ +contains(QT_CONFIG, opengl) { + SOURCES += $$PWD/qopenglcompositor.cpp \ + $$PWD/qopenglcompositorbackingstore.cpp + + HEADERS += $$PWD/qopenglcompositor_p.h \ + $$PWD/qopenglcompositorbackingstore_p.h +} diff --git a/src/platformsupport/platformcompositor/qopenglcompositor.cpp b/src/platformsupport/platformcompositor/qopenglcompositor.cpp new file mode 100644 index 0000000000..3fefdc4935 --- /dev/null +++ b/src/platformsupport/platformcompositor/qopenglcompositor.cpp @@ -0,0 +1,243 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qopenglcompositor_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QOpenGLCompositor + \brief A generic OpenGL-based compositor + \since 5.4 + \internal + \ingroup qpa + + This class provides a lightweight compositor that maintains the + basic stacking order of windows and composites them by drawing + textured quads via OpenGL. + + It it meant to be used by platform plugins that run without a + windowing system. + + It is up to the platform plugin to manage the lifetime of the + compositor (instance(), destroy()), set the correct destination + context and window as early as possible (setTargetWindow()), + register the composited windows as they are shown, activated, + raised and lowered (addWindow(), moveToTop(), etc.), and to + schedule repaints (update()). + + \note To get support for QWidget-based windows, just use + QOpenGLCompositorBackingStore. It will automatically create + textures from the raster-rendered content and trigger the + necessary repaints. + */ + +static QOpenGLCompositor *compositor = 0; + +QOpenGLCompositor::QOpenGLCompositor() + : m_context(0), + m_targetWindow(0) +{ + Q_ASSERT(!compositor); + m_updateTimer.setSingleShot(true); + m_updateTimer.setInterval(0); + connect(&m_updateTimer, SIGNAL(timeout()), SLOT(renderAll())); +} + +QOpenGLCompositor::~QOpenGLCompositor() +{ + Q_ASSERT(compositor == this); + m_blitter.destroy(); + compositor = 0; +} + +void QOpenGLCompositor::setTarget(QOpenGLContext *context, QWindow *targetWindow) +{ + m_context = context; + m_targetWindow = targetWindow; +} + +void QOpenGLCompositor::update() +{ + if (!m_updateTimer.isActive()) + m_updateTimer.start(); +} + +void QOpenGLCompositor::renderAll() +{ + Q_ASSERT(m_context && m_targetWindow); + m_context->makeCurrent(m_targetWindow); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size()); + glViewport(0, 0, targetWindowRect.width(), targetWindowRect.height()); + + if (!m_blitter.isCreated()) + m_blitter.create(); + + m_blitter.bind(); + + for (int i = 0; i < m_windows.size(); ++i) + m_windows.at(i)->beginCompositing(); + + for (int i = 0; i < m_windows.size(); ++i) + render(m_windows.at(i)); + + m_blitter.release(); + m_context->swapBuffers(m_targetWindow); + + for (int i = 0; i < m_windows.size(); ++i) + m_windows.at(i)->endCompositing(); +} + +struct BlendStateBinder +{ + BlendStateBinder() : m_blend(false) { + glDisable(GL_BLEND); + } + void set(bool blend) { + if (blend != m_blend) { + if (blend) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } + m_blend = blend; + } + } + ~BlendStateBinder() { + if (m_blend) + glDisable(GL_BLEND); + } + bool m_blend; +}; + +void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) +{ + const QPlatformTextureList *textures = window->textures(); + if (!textures) + return; + + const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size()); + float currentOpacity = 1.0f; + BlendStateBinder blend; + + for (int i = 0; i < textures->count(); ++i) { + uint textureId = textures->textureId(i); + QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); + const float opacity = window->sourceWindow()->opacity(); + if (opacity != currentOpacity) { + currentOpacity = opacity; + m_blitter.setOpacity(currentOpacity); + } + + if (textures->count() > 1 && i == textures->count() - 1) { + // Backingstore for a widget with QOpenGLWidget subwidgets + blend.set(true); + m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); + } else if (textures->count() == 1) { + // A regular QWidget window + const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0; + blend.set(translucent); + m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); + } else if (!textures->stacksOnTop(i)) { + // Texture from an FBO belonging to a QOpenGLWidget + blend.set(false); + m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); + } + } + + for (int i = 0; i < textures->count(); ++i) { + if (textures->stacksOnTop(i)) { + QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); + blend.set(true); + m_blitter.blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); + } + } + + m_blitter.setOpacity(1.0f); +} + +QOpenGLCompositor *QOpenGLCompositor::instance() +{ + if (!compositor) + compositor = new QOpenGLCompositor; + return compositor; +} + +void QOpenGLCompositor::destroy() +{ + delete compositor; + compositor = 0; +} + +void QOpenGLCompositor::addWindow(QOpenGLCompositorWindow *window) +{ + if (!m_windows.contains(window)) { + m_windows.append(window); + emit topWindowChanged(window); + } +} + +void QOpenGLCompositor::removeWindow(QOpenGLCompositorWindow *window) +{ + m_windows.removeOne(window); + if (!m_windows.isEmpty()) + emit topWindowChanged(m_windows.last()); +} + +void QOpenGLCompositor::moveToTop(QOpenGLCompositorWindow *window) +{ + m_windows.removeOne(window); + m_windows.append(window); + emit topWindowChanged(window); +} + +void QOpenGLCompositor::changeWindowIndex(QOpenGLCompositorWindow *window, int newIdx) +{ + int idx = m_windows.indexOf(window); + if (idx != -1 && idx != newIdx) { + m_windows.move(idx, newIdx); + if (newIdx == m_windows.size() - 1) + emit topWindowChanged(m_windows.last()); + } +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/platformcompositor/qopenglcompositor_p.h b/src/platformsupport/platformcompositor/qopenglcompositor_p.h new file mode 100644 index 0000000000..9c876f5af1 --- /dev/null +++ b/src/platformsupport/platformcompositor/qopenglcompositor_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLCOMPOSITOR_H +#define QOPENGLCOMPOSITOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenGLContext; +class QWindow; +class QPlatformTextureList; + +class QOpenGLCompositorWindow +{ +public: + virtual QWindow *sourceWindow() const = 0; + virtual const QPlatformTextureList *textures() const = 0; + virtual void beginCompositing() { } + virtual void endCompositing() { } +}; + +class QOpenGLCompositor : public QObject +{ + Q_OBJECT + +public: + static QOpenGLCompositor *instance(); + static void destroy(); + + void setTarget(QOpenGLContext *context, QWindow *window); + QOpenGLContext *context() const { return m_context; } + QWindow *targetWindow() const { return m_targetWindow; } + + void update(); + + QList windows() const { return m_windows; } + void addWindow(QOpenGLCompositorWindow *window); + void removeWindow(QOpenGLCompositorWindow *window); + void moveToTop(QOpenGLCompositorWindow *window); + void changeWindowIndex(QOpenGLCompositorWindow *window, int newIdx); + +signals: + void topWindowChanged(QOpenGLCompositorWindow *window); + +private slots: + void renderAll(); + +private: + QOpenGLCompositor(); + ~QOpenGLCompositor(); + + void render(QOpenGLCompositorWindow *window); + + QOpenGLContext *m_context; + QWindow *m_targetWindow; + QTimer m_updateTimer; + QOpenGLTextureBlitter m_blitter; + QList m_windows; +}; + +QT_END_NAMESPACE + +#endif // QOPENGLCOMPOSITOR_H diff --git a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp new file mode 100644 index 0000000000..9c254bead3 --- /dev/null +++ b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qopenglcompositorbackingstore_p.h" +#include "qopenglcompositor_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QOpenGLCompositorBackingStore + \brief A backing store implementation for OpenGL + \since 5.4 + \internal + \ingroup qpa + + This implementation uploads raster-rendered widget windows into + textures. It is meant to be used with QOpenGLCompositor that + composites the textures onto a single native window using OpenGL. + This means that multiple top-level widgets are supported without + creating actual native windows for each of them. + + \note It is important to call notifyComposited() from the + corresponding platform window's endCompositing() callback + (inherited from QOpenGLCompositorWindow). + + \note When implementing QOpenGLCompositorWindow::textures() for + windows of type RasterSurface or RasterGLSurface, simply return + the list provided by this class' textures(). +*/ + +QOpenGLCompositorBackingStore::QOpenGLCompositorBackingStore(QWindow *window) + : QPlatformBackingStore(window), + m_window(window), + m_bsTexture(0), + m_textures(new QPlatformTextureList), + m_lockedWidgetTextures(0) +{ +} + +QOpenGLCompositorBackingStore::~QOpenGLCompositorBackingStore() +{ + delete m_textures; +} + +QPaintDevice *QOpenGLCompositorBackingStore::paintDevice() +{ + return &m_image; +} + +void QOpenGLCompositorBackingStore::updateTexture() +{ + if (!m_bsTexture) { + glGenTextures(1, &m_bsTexture); + glBindTexture(GL_TEXTURE_2D, m_bsTexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_image.width(), m_image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + } else { + glBindTexture(GL_TEXTURE_2D, m_bsTexture); + } + + if (!m_dirty.isNull()) { + QRegion fixed; + QRect imageRect = m_image.rect(); + + foreach (const QRect &rect, m_dirty.rects()) { + // intersect with image rect to be sure + QRect r = imageRect & rect; + + // if the rect is wide enough it's cheaper to just + // extend it instead of doing an image copy + if (r.width() >= imageRect.width() / 2) { + r.setX(0); + r.setWidth(imageRect.width()); + } + + fixed |= r; + } + + foreach (const QRect &rect, fixed.rects()) { + // if the sub-rect is full-width we can pass the image data directly to + // OpenGL instead of copying, since there's no gap between scanlines + if (rect.width() == imageRect.width()) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + m_image.constScanLine(rect.y())); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + m_image.copy(rect).constBits()); + } + } + + m_dirty = QRegion(); + } +} + +void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + // Called for ordinary raster windows. This is rare since RasterGLSurface + // support is claimed which leads to having all QWidget windows marked as + // RasterGLSurface instead of just Raster. These go through + // compositeAndFlush() instead of this function. + + Q_UNUSED(region); + Q_UNUSED(offset); + + QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); + QOpenGLContext *dstCtx = compositor->context(); + QWindow *dstWin = compositor->targetWindow(); + if (!dstWin) + return; + + dstCtx->makeCurrent(dstWin); + updateTexture(); + m_textures->clear(); + m_textures->appendTexture(m_bsTexture, window->geometry()); + + compositor->update(); +} + +void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, + QPlatformTextureList *textures, QOpenGLContext *context, + bool translucentBackground) +{ + // QOpenGLWidget/QQuickWidget content provided as textures. The raster content should go on top. + + Q_UNUSED(region); + Q_UNUSED(offset); + Q_UNUSED(context); + Q_UNUSED(translucentBackground); + + QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); + QOpenGLContext *dstCtx = compositor->context(); + QWindow *dstWin = compositor->targetWindow(); + if (!dstWin) + return; + + dstCtx->makeCurrent(dstWin); + + m_textures->clear(); + for (int i = 0; i < textures->count(); ++i) + m_textures->appendTexture(textures->textureId(i), textures->geometry(i), textures->stacksOnTop(i)); + + updateTexture(); + m_textures->appendTexture(m_bsTexture, window->geometry()); + + textures->lock(true); + m_lockedWidgetTextures = textures; + + compositor->update(); +} + +void QOpenGLCompositorBackingStore::notifyComposited() +{ + if (m_lockedWidgetTextures) { + QPlatformTextureList *textureList = m_lockedWidgetTextures; + m_lockedWidgetTextures = 0; // may reenter so null before unlocking + textureList->lock(false); + } +} + +void QOpenGLCompositorBackingStore::beginPaint(const QRegion ®ion) +{ + m_dirty |= region; + + if (m_image.hasAlphaChannel()) { + QPainter p(&m_image); + p.setCompositionMode(QPainter::CompositionMode_Source); + foreach (const QRect &r, region.rects()) + p.fillRect(r, Qt::transparent); + } +} + +void QOpenGLCompositorBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents); + + QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); + QOpenGLContext *dstCtx = compositor->context(); + QWindow *dstWin = compositor->targetWindow(); + if (!dstWin) + return; + + m_image = QImage(size, QImage::Format_RGBA8888); + + m_window->create(); + + dstCtx->makeCurrent(dstWin); + if (m_bsTexture) { + glDeleteTextures(1, &m_bsTexture); + m_bsTexture = 0; + } +} + +QImage QOpenGLCompositorBackingStore::toImage() const +{ + return m_image; +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore_p.h b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore_p.h new file mode 100644 index 0000000000..0501cd868c --- /dev/null +++ b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLCOMPOSITORBACKINGSTORE_H +#define QOPENGLCOMPOSITORBACKINGSTORE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenGLContext; +class QPlatformTextureList; + +class QOpenGLCompositorBackingStore : public QPlatformBackingStore +{ +public: + QOpenGLCompositorBackingStore(QWindow *window); + ~QOpenGLCompositorBackingStore(); + + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + + void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; + + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; + + QImage toImage() const Q_DECL_OVERRIDE; + void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, + QPlatformTextureList *textures, QOpenGLContext *context, + bool translucentBackground) Q_DECL_OVERRIDE; + + const QPlatformTextureList *textures() const { return m_textures; } + + void notifyComposited(); + +private: + void updateTexture(); + + QWindow *m_window; + QImage m_image; + QRegion m_dirty; + uint m_bsTexture; + QPlatformTextureList *m_textures; + QPlatformTextureList *m_lockedWidgetTextures; +}; + +QT_END_NAMESPACE + +#endif // QOPENGLCOMPOSITORBACKINGSTORE_H diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 32ce2e3887..39cbd9d181 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -21,5 +21,6 @@ include(themes/themes.pri) include(accessibility/accessibility.pri) include(linuxaccessibility/linuxaccessibility.pri) include(clipboard/clipboard.pri) +include(platformcompositor/platformcompositor.pri) load(qt_module) -- cgit v1.2.3