Support QOpenGLWidget and QQuickWidget on Android

It gets somewhat complicated due to the fact that a RasterGLSurface window
(i.e. any widget window since 5.3) may behave either like an OpenGLSurface
or a RasterSurface, and the expected behavior may change on each backingstore
sync.

This does not fit designs where the platform window implementation is separated
and there is different behavior for raster and GL windows.

Therefore QAndroidPlatformOpenGLWindow is now made capable of behaving like the
raster one, based on a flag communicated from the widget stack via QWindowPrivate
(since the plugin knows nothing about widgets).

This means that widget windows that do not have renderToTexture children (QOpenGLWidget,
QQuickWidget) will go through the raster path, while the ones that have will behave
like an OpenGL window with the actual rendering happening in
QPlatformBackingStore::composeAndFlush().
The surface type is RasterGLSurface in both cases nonetheless.

Task-number: QTBUG-37907
Change-Id: I6f9261fc0fd993afcda7f30d379c5410069033d3
Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
This commit is contained in:
Laszlo Agocs 2014-08-20 11:48:02 +02:00
parent 8688656641
commit a4f50269f8
11 changed files with 77 additions and 171 deletions

View File

@ -100,6 +100,7 @@ public:
, cursor(Qt::ArrowCursor)
, hasCursor(false)
#endif
, compositing(false)
{
isWindow = true;
}
@ -175,6 +176,8 @@ public:
QCursor cursor;
bool hasCursor;
#endif
bool compositing;
};

View File

@ -47,7 +47,6 @@ SOURCES += $$PWD/androidplatformplugin.cpp \
$$PWD/qandroidplatformscreen.cpp \
$$PWD/qandroidplatformwindow.cpp \
$$PWD/qandroidplatformopenglwindow.cpp \
$$PWD/qandroidplatformrasterwindow.cpp \
$$PWD/qandroidplatformbackingstore.cpp \
$$PWD/qandroidplatformopenglcontext.cpp \
$$PWD/qandroidplatformforeignwindow.cpp \
@ -76,7 +75,6 @@ HEADERS += $$PWD/qandroidplatformintegration.h \
$$PWD/qandroidplatformscreen.h \
$$PWD/qandroidplatformwindow.h \
$$PWD/qandroidplatformopenglwindow.h \
$$PWD/qandroidplatformrasterwindow.h \
$$PWD/qandroidplatformbackingstore.h \
$$PWD/qandroidplatformopenglcontext.h \
$$PWD/qandroidplatformforeignwindow.h \

View File

@ -42,7 +42,7 @@
#include "qandroidplatformbackingstore.h"
#include "qandroidplatformscreen.h"
#include "qandroidplatformrasterwindow.h"
#include "qandroidplatformwindow.h"
#include <qpa/qplatformscreen.h>
QT_BEGIN_NAMESPACE
@ -66,7 +66,7 @@ void QAndroidPlatformBackingStore::flush(QWindow *window, const QRegion &region,
if (!m_backingStoreSet)
setBackingStore(window);
(static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->repaint(region);
(static_cast<QAndroidPlatformWindow *>(window->handle()))->repaint(region);
}
void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents)
@ -79,11 +79,11 @@ void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &stat
void QAndroidPlatformBackingStore::setBackingStore(QWindow *window)
{
if (window->surfaceType() == QSurface::RasterSurface) {
(static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->setBackingStore(this);
if (window->surfaceType() == QSurface::RasterSurface || window->surfaceType() == QSurface::RasterGLSurface) {
(static_cast<QAndroidPlatformWindow *>(window->handle()))->setBackingStore(this);
m_backingStoreSet = true;
} else {
qWarning("QAndroidPlatformBackingStore does not support GL windows.");
qWarning("QAndroidPlatformBackingStore does not support OpenGL-only windows.");
}
}

View File

@ -62,7 +62,6 @@
#include "qandroidplatformfontdatabase.h"
#include "qandroidplatformopenglcontext.h"
#include "qandroidplatformopenglwindow.h"
#include "qandroidplatformrasterwindow.h"
#include "qandroidplatformscreen.h"
#include "qandroidplatformservices.h"
#include "qandroidplatformtheme.h"
@ -192,6 +191,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
return false;
else
return true;
case RasterGLSurface: return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
@ -227,8 +227,6 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind
{
if (window->type() == Qt::ForeignWindow)
return new QAndroidPlatformForeignWindow(window);
else if (window->surfaceType() == QSurface::RasterSurface)
return new QAndroidPlatformRasterWindow(window);
else
return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
}

View File

@ -42,9 +42,11 @@
#include "qandroidplatformopenglwindow.h"
#include "qandroidplatformscreen.h"
#include "androidjnimain.h"
#include <QSurfaceFormat>
#include <QtGui/private/qwindow_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
@ -69,25 +71,52 @@ QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
unlockSurface();
}
void QAndroidPlatformOpenGLWindow::repaint(const QRegion &region)
{
// This is only for real raster top-level windows. Stop in all other cases.
if ((window()->surfaceType() == QSurface::RasterGLSurface && qt_window_private(window())->compositing)
|| window()->surfaceType() == QSurface::OpenGLSurface
|| QAndroidPlatformWindow::parent())
return;
QRect currentGeometry = geometry();
QRect dirtyClient = region.boundingRect();
QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
currentGeometry.top() + dirtyClient.top(),
dirtyClient.width(),
dirtyClient.height());
QRect mOldGeometryLocal = m_oldGeometry;
m_oldGeometry = currentGeometry;
// If this is a move, redraw the previous location
if (mOldGeometryLocal != currentGeometry)
platformScreen()->setDirty(mOldGeometryLocal);
platformScreen()->setDirty(dirtyRegion);
}
void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
{
if (rect == geometry())
return;
QRect oldGeometry = geometry();
m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
if (m_nativeSurfaceId != -1)
QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
QRect availableGeometry = screen()->availableGeometry();
if (oldGeometry.width() == 0
&& oldGeometry.height() == 0
if (m_oldGeometry.width() == 0
&& m_oldGeometry.height() == 0
&& rect.width() > 0
&& rect.height() > 0
&& availableGeometry.width() > 0
&& availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
}
if (rect.topLeft() != m_oldGeometry.topLeft())
repaint(QRegion(rect));
}
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
@ -162,8 +191,8 @@ QSurfaceFormat QAndroidPlatformOpenGLWindow::format() const
void QAndroidPlatformOpenGLWindow::clearEgl()
{
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_eglSurface != EGL_NO_SURFACE) {
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(m_eglDisplay, m_eglSurface);
m_eglSurface = EGL_NO_SURFACE;
}

View File

@ -66,6 +66,8 @@ public:
void applicationStateChanged(Qt::ApplicationState);
void repaint(const QRegion &region) Q_DECL_OVERRIDE;
protected:
virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h);
void createEgl(EGLConfig config);
@ -80,6 +82,7 @@ private:
QJNIObjectPrivate m_androidSurfaceObject;
QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
QRect m_oldGeometry;
};
QT_END_NAMESPACE

View File

@ -1,83 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
** Copyright (C) 2013 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: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 "qandroidplatformrasterwindow.h"
#include "qandroidplatformscreen.h"
QT_BEGIN_NAMESPACE
QAndroidPlatformRasterWindow::QAndroidPlatformRasterWindow(QWindow *window)
:QAndroidPlatformWindow(window)
{
}
void QAndroidPlatformRasterWindow::repaint(const QRegion &region)
{
if (QAndroidPlatformWindow::parent())
return;
QRect currentGeometry = geometry();
QRect dirtyClient = region.boundingRect();
QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
currentGeometry.top() + dirtyClient.top(),
dirtyClient.width(),
dirtyClient.height());
QRect mOldGeometryLocal = m_oldGeometry;
m_oldGeometry = currentGeometry;
// If this is a move, redraw the previous location
if (mOldGeometryLocal != currentGeometry)
platformScreen()->setDirty(mOldGeometryLocal);
platformScreen()->setDirty(dirtyRegion);
}
void QAndroidPlatformRasterWindow::setGeometry(const QRect &rect)
{
m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
if (rect.topLeft() != m_oldGeometry.topLeft())
repaint(QRegion(rect));
}
QT_END_NAMESPACE

View File

@ -1,70 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
** Copyright (C) 2013 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: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$
**
****************************************************************************/
#ifndef QANDROIDPLATFORMRASTERWINDOW_H
#define QANDROIDPLATFORMRASTERWINDOW_H
#include "qandroidplatformwindow.h"
QT_BEGIN_NAMESPACE
class QAndroidPlatformBackingStore;
class QAndroidPlatformRasterWindow : public QObject, public QAndroidPlatformWindow
{
Q_OBJECT
public:
QAndroidPlatformRasterWindow(QWindow *window);
void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; }
QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; }
void repaint(const QRegion&region);
public slots:
void setGeometry(const QRect &rect);
private:
QAndroidPlatformBackingStore *m_backingStore = nullptr;
QRect m_oldGeometry;
};
QT_END_NAMESPACE
#endif // QANDROIDPLATFORMRASTERWINDOW_H

View File

@ -48,9 +48,9 @@
#include "qandroidplatformscreen.h"
#include "qandroidplatformbackingstore.h"
#include "qandroidplatformintegration.h"
#include "qandroidplatformwindow.h"
#include "androidjnimain.h"
#include "androidjnimenu.h"
#include "qandroidplatformrasterwindow.h"
#include <android/bitmap.h>
#include <android/native_window_jni.h>
@ -58,6 +58,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtGui/private/qwindow_p.h>
QT_BEGIN_NAMESPACE
@ -291,6 +292,19 @@ void QAndroidPlatformScreen::doRedraw()
if (m_dirtyRect.isEmpty())
return;
// Stop if there no visible raster windows. This is important because if we only have
// RasterGLSurface windows that have renderToTexture children (i.e. they need the
// OpenGL path) then we must bail out right now.
bool hasVisibleRasterWindows = false;
foreach (QAndroidPlatformWindow *window, m_windowStack) {
if (window->window()->isVisible() && window->isRaster() && !qt_window_private(window->window())->compositing) {
hasVisibleRasterWindows = true;
break;
}
}
if (!hasVisibleRasterWindows)
return;
QMutexLocker lock(&m_surfaceMutex);
if (m_id == -1 && m_rasterSurfaces) {
m_id = QtAndroid::createSurface(this, m_availableGeometry, true, m_depth);
@ -343,7 +357,7 @@ void QAndroidPlatformScreen::doRedraw()
visibleRegion -= targetRect;
QRect windowRect = targetRect.translated(-window->geometry().topLeft());
QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformRasterWindow *>(window)->backingStore();
QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformWindow *>(window)->backingStore();
if (backingStore)
compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect);
}

View File

@ -49,6 +49,7 @@
QT_BEGIN_NAMESPACE
class QAndroidPlatformScreen;
class QAndroidPlatformBackingStore;
class QAndroidPlatformWindow: public QPlatformWindow
{
@ -71,10 +72,19 @@ public:
void propagateSizeHints();
void requestActivateWindow();
void updateStatusBarVisibility();
inline bool isRaster() const { return window()->surfaceType() == QSurface::RasterSurface; }
inline bool isRaster() const {
return window()->surfaceType() == QSurface::RasterSurface
|| window()->surfaceType() == QSurface::RasterGLSurface;
}
bool isExposed() const;
virtual void applicationStateChanged(Qt::ApplicationState);
void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; }
QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; }
virtual void repaint(const QRegion &) { }
protected:
void setGeometry(const QRect &rect);
@ -83,6 +93,8 @@ protected:
Qt::WindowState m_windowState;
WId m_windowId;
QAndroidPlatformBackingStore *m_backingStore = nullptr;
};
QT_END_NAMESPACE

View File

@ -56,6 +56,7 @@
#include <private/qapplication_p.h>
#include <private/qpaintengine_raster_p.h>
#include <private/qgraphicseffect_p.h>
#include <QtGui/private/qwindow_p.h>
#include <qpa/qplatformbackingstore.h>
@ -1132,6 +1133,7 @@ void QWidgetBackingStore::doSync()
widgetTextures = new QPlatformTextureList;
findTextureWidgetsRecursively(tlw, tlw, widgetTextures);
}
qt_window_private(tlw->windowHandle())->compositing = widgetTextures && !widgetTextures->isEmpty();
fullUpdatePending = false;
#endif