Android: Give raster windows their own surface, and flush via RHI

Refactored platform windows on Android so that all window
types, including raster windows, have their own surface to
draw on.

Raster windows now flush the backing-store via RHI/OpenGL.

As a drive by, update to newer JNI syntax where appropriate.

Task-number: QTBUG-116187
Change-Id: I3b764b7126abf53556750b0ccbb7d27efe007bc1
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Tinja Paavoseppä 2023-11-06 13:02:10 +02:00
parent 76b58be4b8
commit 2020ce5fd2
19 changed files with 108 additions and 531 deletions

View File

@ -377,7 +377,7 @@ class QtNative
// application methods // application methods
// surface methods // surface methods
public static native void setSurface(int id, Object surface, int w, int h); public static native void setSurface(int id, Object surface);
// surface methods // surface methods
// window methods // window methods

View File

@ -50,13 +50,13 @@ class QtSurface extends SurfaceView implements SurfaceHolder.Callback
if (width < 1 || height < 1) if (width < 1 || height < 1)
return; return;
QtNative.setSurface(getId(), holder.getSurface(), width, height); QtNative.setSurface(getId(), holder.getSurface());
} }
@Override @Override
public void surfaceDestroyed(SurfaceHolder holder) public void surfaceDestroyed(SurfaceHolder holder)
{ {
QtNative.setSurface(getId(), null, 0, 0); QtNative.setSurface(getId(), null);
} }
@Override @Override

View File

@ -641,6 +641,8 @@ endif()
qt_internal_extend_target(Gui CONDITION ANDROID qt_internal_extend_target(Gui CONDITION ANDROID
SOURCES SOURCES
platform/android/qandroidnativeinterface.cpp platform/android/qandroidnativeinterface.cpp
painting/qrasterbackingstore.cpp painting/qrasterbackingstore_p.h
painting/qrhibackingstore.cpp painting/qrhibackingstore_p.h
) )
qt_internal_extend_target(Gui CONDITION ANDROID AND (TEST_architecture_arch STREQUAL arm64 OR TEST_architecture_arch STREQUAL arm) qt_internal_extend_target(Gui CONDITION ANDROID AND (TEST_architecture_arch STREQUAL arm64 OR TEST_architecture_arch STREQUAL arm)

View File

@ -17,13 +17,11 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin
androidjniinput.cpp androidjniinput.h androidjniinput.cpp androidjniinput.h
androidjnimain.cpp androidjnimain.h androidjnimain.cpp androidjnimain.h
androidjnimenu.cpp androidjnimenu.h androidjnimenu.cpp androidjnimenu.h
androidsurfaceclient.h
main.cpp main.cpp
qandroidassetsfileenginehandler.cpp qandroidassetsfileenginehandler.h qandroidassetsfileenginehandler.cpp qandroidassetsfileenginehandler.h
qandroideventdispatcher.cpp qandroideventdispatcher.h qandroideventdispatcher.cpp qandroideventdispatcher.h
qandroidinputcontext.cpp qandroidinputcontext.h qandroidinputcontext.cpp qandroidinputcontext.h
qandroidplatformaccessibility.cpp qandroidplatformaccessibility.h qandroidplatformaccessibility.cpp qandroidplatformaccessibility.h
qandroidplatformbackingstore.cpp qandroidplatformbackingstore.h
qandroidplatformclipboard.cpp qandroidplatformclipboard.h qandroidplatformclipboard.cpp qandroidplatformclipboard.h
qandroidplatformdialoghelpers.cpp qandroidplatformdialoghelpers.h qandroidplatformdialoghelpers.cpp qandroidplatformdialoghelpers.h
qandroidplatformfiledialoghelper.cpp qandroidplatformfiledialoghelper.h qandroidplatformfiledialoghelper.cpp qandroidplatformfiledialoghelper.h

View File

@ -18,6 +18,7 @@
#include "qandroidplatformdialoghelpers.h" #include "qandroidplatformdialoghelpers.h"
#include "qandroidplatformintegration.h" #include "qandroidplatformintegration.h"
#include "qandroidplatformclipboard.h" #include "qandroidplatformclipboard.h"
#include "qandroidplatformwindow.h"
#include <android/api-level.h> #include <android/api-level.h>
#include <android/asset_manager_jni.h> #include <android/asset_manager_jni.h>
@ -69,7 +70,7 @@ static void *m_mainLibraryHnd = nullptr;
static QList<QByteArray> m_applicationParams; static QList<QByteArray> m_applicationParams;
static sem_t m_exitSemaphore, m_terminateSemaphore; static sem_t m_exitSemaphore, m_terminateSemaphore;
QHash<int, AndroidSurfaceClient *> m_surfaces; QHash<int, QAndroidPlatformWindow *> m_surfaces;
Q_CONSTINIT static QBasicMutex m_surfacesMutex; Q_CONSTINIT static QBasicMutex m_surfacesMutex;
@ -323,7 +324,7 @@ namespace QtAndroid
return QJniObject::callStaticMethod<jint>("android/view/View", "generateViewId", "()I"); return QJniObject::callStaticMethod<jint>("android/view/View", "generateViewId", "()I");
} }
int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop, int imageDepth) int createSurface(QAndroidPlatformWindow *window, const QRect &geometry, bool onTop, int imageDepth)
{ {
QJniEnvironment env; QJniEnvironment env;
if (!env.jniEnv()) if (!env.jniEnv())
@ -331,7 +332,7 @@ namespace QtAndroid
m_surfacesMutex.lock(); m_surfacesMutex.lock();
jint surfaceId = generateViewId(); jint surfaceId = generateViewId();
m_surfaces[surfaceId] = client; m_surfaces[surfaceId] = window;
m_surfacesMutex.unlock(); m_surfacesMutex.unlock();
jint x = 0, y = 0, w = -1, h = -1; jint x = 0, y = 0, w = -1, h = -1;
@ -594,8 +595,11 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
sem_post(&m_exitSemaphore); sem_post(&m_exitSemaphore);
} }
static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h) static void setSurface(JNIEnv *env, jobject thiz, jint id, jobject jSurface)
{ {
Q_UNUSED(env);
Q_UNUSED(thiz);
QMutexLocker lock(&m_surfacesMutex); QMutexLocker lock(&m_surfacesMutex);
const auto &it = m_surfaces.find(id); const auto &it = m_surfaces.find(id);
if (it == m_surfaces.end()) if (it == m_surfaces.end())
@ -603,7 +607,7 @@ static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface,
auto surfaceClient = it.value(); auto surfaceClient = it.value();
if (surfaceClient) if (surfaceClient)
surfaceClient->surfaceChanged(env, jSurface, w, h); surfaceClient->onSurfaceChanged(jSurface);
} }
static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWidthPixels, static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWidthPixels,
@ -658,10 +662,6 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
QWindowSystemInterface::handleExposeEvent(w, QRegion(QRect(QPoint(), w->geometry().size()))); QWindowSystemInterface::handleExposeEvent(w, QRegion(QRect(QPoint(), w->geometry().size())));
} }
} }
QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());
if (screen->rasterSurfaces())
QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
} }
static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state) static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
@ -802,7 +802,7 @@ static JNINativeMethod methods[] = {
{ "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication }, { "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication },
{ "terminateQt", "()V", (void *)terminateQt }, { "terminateQt", "()V", (void *)terminateQt },
{ "waitForServiceSetup", "()V", (void *)waitForServiceSetup }, { "waitForServiceSetup", "()V", (void *)waitForServiceSetup },
{ "setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface }, { "setSurface", "(ILjava/lang/Object;)V", (void *)setSurface },
{ "updateWindow", "()V", (void *)updateWindow }, { "updateWindow", "()V", (void *)updateWindow },
{ "updateApplicationState", "(I)V", (void *)updateApplicationState }, { "updateApplicationState", "(I)V", (void *)updateApplicationState },
{ "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult }, { "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },

View File

@ -23,7 +23,7 @@ class QAndroidPlatformIntegration;
class QWidget; class QWidget;
class QString; class QString;
class QWindow; class QWindow;
class AndroidSurfaceClient; class QAndroidPlatformWindow;
class QBasicMutex; class QBasicMutex;
Q_DECLARE_JNI_CLASS(QtActivityDelegate, "org/qtproject/qt/android/QtActivityDelegate") Q_DECLARE_JNI_CLASS(QtActivityDelegate, "org/qtproject/qt/android/QtActivityDelegate")
@ -37,7 +37,7 @@ namespace QtAndroid
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration); void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
void setQtThread(QThread *thread); void setQtThread(QThread *thread);
int createSurface(AndroidSurfaceClient * client, const QRect &geometry, bool onTop, int imageDepth); int createSurface(QAndroidPlatformWindow *window, const QRect &geometry, bool onTop, int imageDepth);
int insertNativeView(QtJniTypes::View view, const QRect &geometry); int insertNativeView(QtJniTypes::View view, const QRect &geometry);
void setViewVisibility(jobject view, bool visible); void setViewVisibility(jobject view, bool visible);
void setSurfaceGeometry(int surfaceId, const QRect &geometry); void setSurfaceGeometry(int surfaceId, const QRect &geometry);

View File

@ -1,24 +0,0 @@
// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDSURFACECLIENT_H
#define ANDROIDSURFACECLIENT_H
#include <QMutex>
#include <jni.h>
QT_BEGIN_NAMESPACE
class AndroidSurfaceClient
{
public:
virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) = 0;
void lockSurface() { m_surfaceMutex.lock(); }
void unlockSurface() { m_surfaceMutex.unlock(); }
protected:
QMutex m_surfaceMutex;
};
QT_END_NAMESPACE
#endif // ANDROIDSURFACECLIENT_H

View File

@ -1,48 +0,0 @@
// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformbackingstore.h"
#include "qandroidplatformscreen.h"
#include "qandroidplatformwindow.h"
#include <qpa/qplatformscreen.h>
QT_BEGIN_NAMESPACE
QAndroidPlatformBackingStore::QAndroidPlatformBackingStore(QWindow *window)
: QPlatformBackingStore(window)
{
if (window->handle())
setBackingStore(window);
}
QPaintDevice *QAndroidPlatformBackingStore::paintDevice()
{
return &m_image;
}
void QAndroidPlatformBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
Q_UNUSED(offset);
auto *platformWindow = static_cast<QAndroidPlatformWindow *>(window->handle());
if (!platformWindow->backingStore())
setBackingStore(window);
platformWindow->repaint(region);
}
void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents)
{
Q_UNUSED(staticContents);
if (m_image.size() != size)
m_image = QImage(size, window()->screen()->handle()->format());
}
void QAndroidPlatformBackingStore::setBackingStore(QWindow *window)
{
(static_cast<QAndroidPlatformWindow *>(window->handle()))->setBackingStore(this);
}
QT_END_NAMESPACE

View File

@ -1,28 +0,0 @@
// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANDROIDPLATFORMBACKINGSTORE_H
#define QANDROIDPLATFORMBACKINGSTORE_H
#include <qpa/qplatformbackingstore.h>
#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
class QAndroidPlatformBackingStore : public QPlatformBackingStore
{
public:
explicit QAndroidPlatformBackingStore(QWindow *window);
QPaintDevice *paintDevice() override;
void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
void resize(const QSize &size, const QRegion &staticContents) override;
QImage toImage() const override { return m_image; }
void setBackingStore(QWindow *window);
protected:
QImage m_image;
};
QT_END_NAMESPACE
#endif // QANDROIDPLATFORMBACKINGSTORE_H

View File

@ -4,7 +4,6 @@
#ifndef QANDROIDPLATFORMFOREIGNWINDOW_H #ifndef QANDROIDPLATFORMFOREIGNWINDOW_H
#define QANDROIDPLATFORMFOREIGNWINDOW_H #define QANDROIDPLATFORMFOREIGNWINDOW_H
#include "androidsurfaceclient.h"
#include "qandroidplatformwindow.h" #include "qandroidplatformwindow.h"
#include <QtCore/QJniObject> #include <QtCore/QJniObject>

View File

@ -9,7 +9,6 @@
#include "qabstracteventdispatcher.h" #include "qabstracteventdispatcher.h"
#include "qandroideventdispatcher.h" #include "qandroideventdispatcher.h"
#include "qandroidplatformaccessibility.h" #include "qandroidplatformaccessibility.h"
#include "qandroidplatformbackingstore.h"
#include "qandroidplatformclipboard.h" #include "qandroidplatformclipboard.h"
#include "qandroidplatformfontdatabase.h" #include "qandroidplatformfontdatabase.h"
#include "qandroidplatformforeignwindow.h" #include "qandroidplatformforeignwindow.h"
@ -29,6 +28,7 @@
#include <QtGui/private/qeglpbuffer_p.h> #include <QtGui/private/qeglpbuffer_p.h>
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qoffscreensurface_p.h> #include <QtGui/private/qoffscreensurface_p.h>
#include <QtGui/private/qrhibackingstore_p.h>
#include <qpa/qplatformoffscreensurface.h> #include <qpa/qplatformoffscreensurface.h>
#include <qpa/qplatformwindow.h> #include <qpa/qplatformwindow.h>
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
@ -323,6 +323,9 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
case RasterGLSurface: return QtAndroidPrivate::activity().isValid(); case RasterGLSurface: return QtAndroidPrivate::activity().isValid();
case TopStackedNativeChildWindows: return false; case TopStackedNativeChildWindows: return false;
case MaximizeUsingFullscreenGeometry: return true; case MaximizeUsingFullscreenGeometry: return true;
// FIXME QTBUG-118849 - we do not implement grabWindow() anymore, calling it will return
// a null QPixmap also for raster windows - for OpenGL windows this was always true
case ScreenWindowGrabbing: return false;
default: default:
return QPlatformIntegration::hasCapability(cap); return QPlatformIntegration::hasCapability(cap);
} }
@ -333,7 +336,7 @@ QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(Q
if (!QtAndroidPrivate::activity().isValid()) if (!QtAndroidPrivate::activity().isValid())
return nullptr; return nullptr;
return new QAndroidPlatformBackingStore(window); return new QRhiBackingStore(window);
} }
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const

View File

@ -24,41 +24,19 @@ QT_BEGIN_NAMESPACE
QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display) QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display)
:QAndroidPlatformWindow(window), m_eglDisplay(display) :QAndroidPlatformWindow(window), m_eglDisplay(display)
{ {
if (window->surfaceType() == QSurface::RasterSurface)
window->setSurfaceType(QSurface::OpenGLSurface);
} }
QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow() QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
{ {
m_surfaceWaitCondition.wakeOne(); m_surfaceWaitCondition.wakeOne();
lockSurface(); lockSurface();
if (m_nativeSurfaceId != -1) destroySurface();
QtAndroid::destroySurface(m_nativeSurfaceId);
clearEgl(); clearEgl();
unlockSurface(); 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) void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
{ {
if (rect == geometry()) if (rect == geometry())
@ -67,8 +45,7 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
m_oldGeometry = geometry(); m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect); QAndroidPlatformWindow::setGeometry(rect);
if (m_nativeSurfaceId != -1) setSurfaceGeometry(rect);
QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
QRect availableGeometry = screen()->availableGeometry(); QRect availableGeometry = screen()->availableGeometry();
if (rect.width() > 0 if (rect.width() > 0
@ -77,9 +54,6 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
&& availableGeometry.height() > 0) { && availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
} }
if (rect.topLeft() != m_oldGeometry.topLeft())
repaint(QRegion(rect));
} }
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
@ -94,8 +68,7 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
if (!protector.acquire()) if (!protector.acquire())
return m_eglSurface; return m_eglSurface;
const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); createSurface();
m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
m_surfaceWaitCondition.wait(&m_surfaceMutex); m_surfaceWaitCondition.wait(&m_surfaceMutex);
} }
@ -127,10 +100,7 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState
QAndroidPlatformWindow::applicationStateChanged(state); QAndroidPlatformWindow::applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) { if (state <= Qt::ApplicationHidden) {
lockSurface(); lockSurface();
if (m_nativeSurfaceId != -1) { destroySurface();
QtAndroid::destroySurface(m_nativeSurfaceId);
m_nativeSurfaceId = -1;
}
clearEgl(); clearEgl();
unlockSurface(); unlockSurface();
} }
@ -173,24 +143,4 @@ void QAndroidPlatformOpenGLWindow::clearEgl()
} }
} }
void QAndroidPlatformOpenGLWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h)
{
Q_UNUSED(jniEnv);
Q_UNUSED(w);
Q_UNUSED(h);
lockSurface();
m_androidSurfaceObject = surface;
if (surface) // wait until we have a valid surface to draw into
m_surfaceWaitCondition.wakeOne();
unlockSurface();
if (surface) {
// repaint the window, when we have a valid surface
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size())));
}
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -5,7 +5,6 @@
#ifndef QANDROIDPLATFORMOPENGLWINDOW_H #ifndef QANDROIDPLATFORMOPENGLWINDOW_H
#define QANDROIDPLATFORMOPENGLWINDOW_H #define QANDROIDPLATFORMOPENGLWINDOW_H
#include "androidsurfaceclient.h"
#include "qandroidplatformwindow.h" #include "qandroidplatformwindow.h"
#include <QWaitCondition> #include <QWaitCondition>
@ -16,7 +15,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow
{ {
public: public:
explicit QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display); explicit QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display);
@ -30,10 +29,7 @@ public:
void applicationStateChanged(Qt::ApplicationState) override; void applicationStateChanged(Qt::ApplicationState) override;
void repaint(const QRegion &region) override;
protected: protected:
void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
void createEgl(EGLConfig config); void createEgl(EGLConfig config);
void clearEgl(); void clearEgl();
@ -42,9 +38,6 @@ private:
EGLSurface m_eglSurface = EGL_NO_SURFACE; EGLSurface m_eglSurface = EGL_NO_SURFACE;
EGLNativeWindowType m_nativeWindow = nullptr; EGLNativeWindowType m_nativeWindow = nullptr;
int m_nativeSurfaceId = -1;
QJniObject m_androidSurfaceObject;
QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format; QSurfaceFormat m_format;
QRect m_oldGeometry; QRect m_oldGeometry;
}; };

View File

@ -8,7 +8,6 @@
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
#include "qandroidplatformscreen.h" #include "qandroidplatformscreen.h"
#include "qandroidplatformbackingstore.h"
#include "qandroidplatformintegration.h" #include "qandroidplatformintegration.h"
#include "qandroidplatformwindow.h" #include "qandroidplatformwindow.h"
#include "androidjnimain.h" #include "androidjnimain.h"
@ -131,11 +130,6 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
QAndroidPlatformScreen::~QAndroidPlatformScreen() QAndroidPlatformScreen::~QAndroidPlatformScreen()
{ {
if (m_surfaceId != -1) {
QtAndroid::destroySurface(m_surfaceId);
m_surfaceWaitCondition.wakeOne();
releaseSurface();
}
} }
QWindow *QAndroidPlatformScreen::topWindow() const QWindow *QAndroidPlatformScreen::topWindow() const
@ -159,16 +153,6 @@ QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
return 0; return 0;
} }
bool QAndroidPlatformScreen::event(QEvent *event)
{
if (event->type() == QEvent::UpdateRequest) {
doRedraw();
m_updatePending = false;
return true;
}
return QObject::event(event);
}
void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
{ {
if (window->parent() && window->isRaster()) if (window->parent() && window->isRaster())
@ -178,10 +162,6 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
return; return;
m_windowStack.prepend(window); m_windowStack.prepend(window);
if (window->isRaster()) {
m_rasterSurfaces.ref();
setDirty(window->geometry());
}
QWindow *w = topWindow(); QWindow *w = topWindow();
QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
@ -198,11 +178,6 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
if (m_windowStack.contains(window)) if (m_windowStack.contains(window))
qWarning() << "Failed to remove window"; qWarning() << "Failed to remove window";
if (window->isRaster()) {
m_rasterSurfaces.deref();
setDirty(window->geometry());
}
QWindow *w = topWindow(); QWindow *w = topWindow();
QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
topWindowChanged(w); topWindowChanged(w);
@ -210,16 +185,11 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
{ {
if (window->parent() && window->isRaster())
return;
int index = m_windowStack.indexOf(window); int index = m_windowStack.indexOf(window);
if (index <= 0) if (index <= 0)
return; return;
m_windowStack.move(index, 0); m_windowStack.move(index, 0);
if (window->isRaster()) {
setDirty(window->geometry());
}
QWindow *w = topWindow(); QWindow *w = topWindow();
QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
topWindowChanged(w); topWindowChanged(w);
@ -227,36 +197,16 @@ void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window)
{ {
if (window->parent() && window->isRaster())
return;
int index = m_windowStack.indexOf(window); int index = m_windowStack.indexOf(window);
if (index == -1 || index == (m_windowStack.size() - 1)) if (index == -1 || index == (m_windowStack.size() - 1))
return; return;
m_windowStack.move(index, m_windowStack.size() - 1); m_windowStack.move(index, m_windowStack.size() - 1);
if (window->isRaster()) {
setDirty(window->geometry());
}
QWindow *w = topWindow(); QWindow *w = topWindow();
QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
topWindowChanged(w); topWindowChanged(w);
} }
void QAndroidPlatformScreen::scheduleUpdate()
{
if (!m_updatePending) {
m_updatePending = true;
QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
}
}
void QAndroidPlatformScreen::setDirty(const QRect &rect)
{
QRect intersection = rect.intersected(m_availableGeometry);
m_dirtyRect |= intersection;
scheduleUpdate();
}
void QAndroidPlatformScreen::setPhysicalSize(const QSize &size) void QAndroidPlatformScreen::setPhysicalSize(const QSize &size)
{ {
m_physicalSize = size; m_physicalSize = size;
@ -306,7 +256,6 @@ void QAndroidPlatformScreen::setOrientation(Qt::ScreenOrientation orientation)
void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect) void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
{ {
QMutexLocker lock(&m_surfaceMutex);
if (m_availableGeometry == rect) if (m_availableGeometry == rect)
return; return;
@ -327,25 +276,12 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
} }
} }
} }
if (m_surfaceId != -1) {
releaseSurface();
QtAndroid::setSurfaceGeometry(m_surfaceId, rect);
}
} }
void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state) void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state)
{ {
for (QAndroidPlatformWindow *w : std::as_const(m_windowStack)) for (QAndroidPlatformWindow *w : std::as_const(m_windowStack))
w->applicationStateChanged(state); w->applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) {
lockSurface();
QtAndroid::destroySurface(m_surfaceId);
m_surfaceId = -1;
releaseSurface();
unlockSurface();
}
} }
void QAndroidPlatformScreen::topWindowChanged(QWindow *w) void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
@ -359,133 +295,6 @@ void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
} }
} }
int QAndroidPlatformScreen::rasterSurfaces()
{
return m_rasterSurfaces;
}
void QAndroidPlatformScreen::doRedraw(QImage* screenGrabImage)
{
PROFILE_SCOPE;
if (!QtAndroidPrivate::activity().isValid())
return;
if (m_dirtyRect.isEmpty())
return;
// Stop if there are no visible raster windows. If we only have RasterGLSurface
// windows that have renderToTexture children (i.e. they need the OpenGL path) then
// we do not need an overlay surface.
bool hasVisibleRasterWindows = false;
for (QAndroidPlatformWindow *window : std::as_const(m_windowStack)) {
if (window->window()->isVisible() && window->isRaster() && !qt_window_private(window->window())->compositing) {
hasVisibleRasterWindows = true;
break;
}
}
if (!hasVisibleRasterWindows) {
lockSurface();
if (m_surfaceId != -1) {
QtAndroid::destroySurface(m_surfaceId);
releaseSurface();
m_surfaceId = -1;
}
unlockSurface();
return;
}
QMutexLocker lock(&m_surfaceMutex);
if (m_surfaceId == -1 && m_rasterSurfaces) {
m_surfaceId = QtAndroid::createSurface(this, geometry(), true, m_depth);
AndroidDeadlockProtector protector;
if (!protector.acquire())
return;
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
if (!m_nativeSurface)
return;
ANativeWindow_Buffer nativeWindowBuffer;
ARect nativeWindowRect;
nativeWindowRect.top = m_dirtyRect.top();
nativeWindowRect.left = m_dirtyRect.left();
nativeWindowRect.bottom = m_dirtyRect.bottom() + 1; // for some reason that I don't understand the QRect bottom needs to +1 to be the same with ARect bottom
nativeWindowRect.right = m_dirtyRect.right() + 1; // same for the right
int ret;
if ((ret = ANativeWindow_lock(m_nativeSurface, &nativeWindowBuffer, &nativeWindowRect)) < 0) {
qWarning() << "ANativeWindow_lock() failed! error=" << ret;
return;
}
int bpp = 4;
if (nativeWindowBuffer.format == WINDOW_FORMAT_RGB_565) {
bpp = 2;
m_pixelFormat = QImage::Format_RGB16;
}
QImage screenImage(reinterpret_cast<uchar *>(nativeWindowBuffer.bits)
, nativeWindowBuffer.width, nativeWindowBuffer.height
, nativeWindowBuffer.stride * bpp , m_pixelFormat);
QPainter compositePainter(&screenImage);
compositePainter.setCompositionMode(QPainter::CompositionMode_Source);
QRegion visibleRegion(m_dirtyRect);
for (QAndroidPlatformWindow *window : std::as_const(m_windowStack)) {
if (!window->window()->isVisible()
|| qt_window_private(window->window())->compositing
|| !window->isRaster())
continue;
for (const QRect &rect : std::vector<QRect>(visibleRegion.begin(), visibleRegion.end())) {
QRect targetRect = window->geometry();
targetRect &= rect;
if (targetRect.isNull())
continue;
visibleRegion -= targetRect;
QRect windowRect = targetRect.translated(-window->geometry().topLeft());
QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformWindow *>(window)->backingStore();
if (backingStore)
compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect);
}
}
for (const QRect &rect : visibleRegion)
compositePainter.fillRect(rect, QColor(Qt::transparent));
ret = ANativeWindow_unlockAndPost(m_nativeSurface);
if (ret >= 0)
m_dirtyRect = QRect();
if (screenGrabImage) {
if (screenGrabImage->size() != screenImage.size()) {
uchar* bytes = static_cast<uchar*>(malloc(screenImage.height() * screenImage.bytesPerLine()));
*screenGrabImage = QImage(bytes, screenImage.width(), screenImage.height(),
screenImage.bytesPerLine(), m_pixelFormat,
[](void* ptr){ if (ptr) free (ptr);});
}
memcpy(screenGrabImage->bits(),
screenImage.bits(),
screenImage.bytesPerLine() * screenImage.height());
}
m_repaintOccurred = true;
}
QPixmap QAndroidPlatformScreen::doScreenShot(QRect grabRect)
{
if (!m_repaintOccurred)
return QPixmap::fromImage(m_lastScreenshot.copy(grabRect));
QRect tmp = m_dirtyRect;
m_dirtyRect = geometry();
doRedraw(&m_lastScreenshot);
m_dirtyRect = tmp;
m_repaintOccurred = false;
return QPixmap::fromImage(m_lastScreenshot.copy(grabRect));
}
static const int androidLogicalDpi = 72; static const int androidLogicalDpi = 72;
QDpi QAndroidPlatformScreen::logicalDpi() const QDpi QAndroidPlatformScreen::logicalDpi() const
@ -508,67 +317,4 @@ Qt::ScreenOrientation QAndroidPlatformScreen::nativeOrientation() const
{ {
return QAndroidPlatformIntegration::m_nativeOrientation; return QAndroidPlatformIntegration::m_nativeOrientation;
} }
void QAndroidPlatformScreen::surfaceChanged(JNIEnv *env, jobject surface, int w, int h)
{
lockSurface();
if (surface && w > 0 && h > 0) {
releaseSurface();
m_nativeSurface = ANativeWindow_fromSurface(env, surface);
QMetaObject::invokeMethod(this, "setDirty", Qt::QueuedConnection, Q_ARG(QRect, QRect(0, 0, w, h)));
} else {
releaseSurface();
}
unlockSurface();
m_surfaceWaitCondition.wakeOne();
}
void QAndroidPlatformScreen::releaseSurface()
{
if (m_nativeSurface) {
ANativeWindow_release(m_nativeSurface);
m_nativeSurface = 0;
}
}
/*!
This function is called when Qt needs to be able to grab the content of a window.
Returns the content of the window specified with the WId handle within the boundaries of
QRect(x, y, width, height).
*/
QPixmap QAndroidPlatformScreen::grabWindow(WId window, int x, int y, int width, int height) const
{
QRectF screenshotRect(x, y, width, height);
QWindow* wnd = 0;
if (window)
{
const auto windowList = qApp->allWindows();
for (QWindow *w : windowList)
if (w->winId() == window) {
wnd = w;
break;
}
}
if (wnd) {
const qreal factor = logicalDpi().first / androidLogicalDpi; //HighDPI factor;
QRectF wndRect = wnd->geometry();
if (wnd->parent())
wndRect.moveTopLeft(wnd->parent()->mapToGlobal(wndRect.topLeft().toPoint()));
if (!qFuzzyCompare(factor, 1))
wndRect = QRectF(wndRect.left() * factor, wndRect.top() * factor,
wndRect.width() * factor, wndRect.height() * factor);
if (!screenshotRect.isEmpty()) {
screenshotRect.moveTopLeft(wndRect.topLeft() + screenshotRect.topLeft());
screenshotRect = screenshotRect.intersected(wndRect);
} else {
screenshotRect = wndRect;
}
} else {
screenshotRect = screenshotRect.isValid() ? screenshotRect : geometry();
}
return const_cast<QAndroidPlatformScreen *>(this)->doScreenShot(screenshotRect.toRect());
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -5,8 +5,6 @@
#ifndef QANDROIDPLATFORMSCREEN_H #ifndef QANDROIDPLATFORMSCREEN_H
#define QANDROIDPLATFORMSCREEN_H #define QANDROIDPLATFORMSCREEN_H
#include "androidsurfaceclient.h"
#include <QList> #include <QList>
#include <QPainter> #include <QPainter>
#include <QTimer> #include <QTimer>
@ -15,14 +13,12 @@
#include <qpa/qplatformscreen.h> #include <qpa/qplatformscreen.h>
#include <qpa/qplatformscreen_p.h> #include <qpa/qplatformscreen_p.h>
#include <android/native_window.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QAndroidPlatformWindow; class QAndroidPlatformWindow;
class QAndroidPlatformScreen: public QObject, class QAndroidPlatformScreen: public QObject,
public QPlatformScreen, public AndroidSurfaceClient, public QPlatformScreen,
public QNativeInterface::Private::QAndroidScreen public QNativeInterface::Private::QAndroidScreen
{ {
Q_OBJECT Q_OBJECT
@ -44,19 +40,15 @@ public:
inline QWindow *topWindow() const; inline QWindow *topWindow() const;
QWindow *topLevelAt(const QPoint & p) const override; QWindow *topLevelAt(const QPoint & p) const override;
// compositor api
void addWindow(QAndroidPlatformWindow *window); void addWindow(QAndroidPlatformWindow *window);
void removeWindow(QAndroidPlatformWindow *window); void removeWindow(QAndroidPlatformWindow *window);
void raise(QAndroidPlatformWindow *window); void raise(QAndroidPlatformWindow *window);
void lower(QAndroidPlatformWindow *window); void lower(QAndroidPlatformWindow *window);
void scheduleUpdate();
void topWindowChanged(QWindow *w); void topWindowChanged(QWindow *w);
int rasterSurfaces();
int displayId() const override; int displayId() const override;
public slots: public slots:
void setDirty(const QRect &rect);
void setPhysicalSize(const QSize &size); void setPhysicalSize(const QSize &size);
void setAvailableGeometry(const QRect &rect); void setAvailableGeometry(const QRect &rect);
void setSize(const QSize &size); void setSize(const QSize &size);
@ -66,12 +58,8 @@ public slots:
void setOrientation(Qt::ScreenOrientation orientation); void setOrientation(Qt::ScreenOrientation orientation);
protected: protected:
bool event(QEvent *event) override;
typedef QList<QAndroidPlatformWindow *> WindowStackType; typedef QList<QAndroidPlatformWindow *> WindowStackType;
WindowStackType m_windowStack; WindowStackType m_windowStack;
QRect m_dirtyRect;
bool m_updatePending = false;
QRect m_availableGeometry; QRect m_availableGeometry;
int m_depth; int m_depth;
@ -88,25 +76,9 @@ private:
QDpi logicalBaseDpi() const override; QDpi logicalBaseDpi() const override;
Qt::ScreenOrientation orientation() const override; Qt::ScreenOrientation orientation() const override;
Qt::ScreenOrientation nativeOrientation() const override; Qt::ScreenOrientation nativeOrientation() const override;
QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
void surfaceChanged(JNIEnv *env, jobject surface, int w, int h) override;
void releaseSurface();
void applicationStateChanged(Qt::ApplicationState); void applicationStateChanged(Qt::ApplicationState);
QPixmap doScreenShot(QRect grabRect = QRect());
private slots:
void doRedraw(QImage *screenGrabImage = nullptr);
private: private:
int m_surfaceId = -1;
QAtomicInt m_rasterSurfaces = 0;
ANativeWindow* m_nativeSurface = nullptr;
QWaitCondition m_surfaceWaitCondition;
QSize m_size; QSize m_size;
QImage m_lastScreenshot;
QImage::Format m_pixelFormat = QImage::Format_RGBA8888_Premultiplied;
bool m_repaintOccurred = false;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -18,7 +18,6 @@ QT_BEGIN_NAMESPACE
QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window) QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window)
: QAndroidPlatformWindow(window), : QAndroidPlatformWindow(window),
m_nativeSurfaceId(-1),
m_nativeWindow(nullptr), m_nativeWindow(nullptr),
m_vkSurface(0), m_vkSurface(0),
m_createVkSurface(nullptr), m_createVkSurface(nullptr),
@ -29,11 +28,7 @@ QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window)
QAndroidPlatformVulkanWindow::~QAndroidPlatformVulkanWindow() QAndroidPlatformVulkanWindow::~QAndroidPlatformVulkanWindow()
{ {
m_surfaceWaitCondition.wakeOne(); m_surfaceWaitCondition.wakeOne();
lockSurface(); destroyAndClearSurface();
if (m_nativeSurfaceId != -1)
QtAndroid::destroySurface(m_nativeSurfaceId);
clearSurface();
unlockSurface();
} }
void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect) void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
@ -44,8 +39,7 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
m_oldGeometry = geometry(); m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect); QAndroidPlatformWindow::setGeometry(rect);
if (m_nativeSurfaceId != -1) setSurfaceGeometry(rect);
QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
QRect availableGeometry = screen()->availableGeometry(); QRect availableGeometry = screen()->availableGeometry();
if (rect.width() > 0 if (rect.width() > 0
@ -54,22 +48,13 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
&& availableGeometry.height() > 0) { && availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
} }
if (rect.topLeft() != m_oldGeometry.topLeft())
repaint(QRegion(rect));
} }
void QAndroidPlatformVulkanWindow::applicationStateChanged(Qt::ApplicationState state) void QAndroidPlatformVulkanWindow::applicationStateChanged(Qt::ApplicationState state)
{ {
QAndroidPlatformWindow::applicationStateChanged(state); QAndroidPlatformWindow::applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) { if (state <= Qt::ApplicationHidden) {
lockSurface(); destroyAndClearSurface();
if (m_nativeSurfaceId != -1) {
QtAndroid::destroySurface(m_nativeSurfaceId);
m_nativeSurfaceId = -1;
}
clearSurface();
unlockSurface();
} }
} }
@ -91,27 +76,12 @@ void QAndroidPlatformVulkanWindow::clearSurface()
} }
} }
void QAndroidPlatformVulkanWindow::sendExpose() void QAndroidPlatformVulkanWindow::destroyAndClearSurface()
{ {
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size())));
}
void QAndroidPlatformVulkanWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h)
{
Q_UNUSED(jniEnv);
Q_UNUSED(w);
Q_UNUSED(h);
lockSurface(); lockSurface();
m_androidSurfaceObject = surface; destroySurface();
if (surface) clearSurface();
m_surfaceWaitCondition.wakeOne();
unlockSurface(); unlockSurface();
if (surface)
sendExpose();
} }
VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface() VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface()
@ -128,8 +98,7 @@ VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface()
AndroidDeadlockProtector protector; AndroidDeadlockProtector protector;
if (!protector.acquire()) if (!protector.acquire())
return &m_vkSurface; return &m_vkSurface;
const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); createSurface();
m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
m_surfaceWaitCondition.wait(&m_surfaceMutex); m_surfaceWaitCondition.wait(&m_surfaceMutex);
} }

View File

@ -10,7 +10,6 @@
#define VK_USE_PLATFORM_ANDROID_KHR #define VK_USE_PLATFORM_ANDROID_KHR
#include "androidsurfaceclient.h"
#include "qandroidplatformvulkaninstance.h" #include "qandroidplatformvulkaninstance.h"
#include "qandroidplatformwindow.h" #include "qandroidplatformwindow.h"
@ -20,7 +19,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow
{ {
public: public:
explicit QAndroidPlatformVulkanWindow(QWindow *window); explicit QAndroidPlatformVulkanWindow(QWindow *window);
@ -32,17 +31,11 @@ public:
VkSurfaceKHR *vkSurface(); VkSurfaceKHR *vkSurface();
protected:
void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
private: private:
void sendExpose();
void clearSurface(); void clearSurface();
void destroyAndClearSurface();
int m_nativeSurfaceId;
ANativeWindow *m_nativeWindow; ANativeWindow *m_nativeWindow;
QJniObject m_androidSurfaceObject;
QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format; QSurfaceFormat m_format;
QRect m_oldGeometry; QRect m_oldGeometry;
VkSurfaceKHR m_vkSurface; VkSurfaceKHR m_vkSurface;

View File

@ -17,10 +17,13 @@ QT_BEGIN_NAMESPACE
Q_CONSTINIT static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0); Q_CONSTINIT static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0);
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
: QPlatformWindow(window) : QPlatformWindow(window), m_androidSurfaceObject(nullptr)
{ {
m_windowFlags = Qt::Widget; m_windowFlags = Qt::Widget;
m_windowState = Qt::WindowNoState; m_windowState = Qt::WindowNoState;
// the surfaceType is overwritten in QAndroidPlatformOpenGLWindow ctor so let's save
// the fact that it's a raster window for now
m_isRaster = window->surfaceType() == QSurface::RasterSurface;
m_windowId = winIdGenerator.fetchAndAddRelaxed(1) + 1; m_windowId = winIdGenerator.fetchAndAddRelaxed(1) + 1;
setWindowState(window->windowStates()); setWindowState(window->windowStates());
@ -171,4 +174,44 @@ void QAndroidPlatformWindow::applicationStateChanged(Qt::ApplicationState)
QWindowSystemInterface::flushWindowSystemEvents(); QWindowSystemInterface::flushWindowSystemEvents();
} }
void QAndroidPlatformWindow::createSurface()
{
const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
}
void QAndroidPlatformWindow::destroySurface()
{
if (m_nativeSurfaceId != -1) {
QtAndroid::destroySurface(m_nativeSurfaceId);
m_nativeSurfaceId = -1;
}
}
void QAndroidPlatformWindow::setSurfaceGeometry(const QRect &rect)
{
if (m_nativeSurfaceId != -1)
QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
}
void QAndroidPlatformWindow::sendExpose()
{
QRect availableGeometry = screen()->availableGeometry();
if (!geometry().isNull() && !availableGeometry.isNull()) {
QWindowSystemInterface::handleExposeEvent(window(),
QRegion(QRect(QPoint(), geometry().size())));
}
}
void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface)
{
lockSurface();
m_androidSurfaceObject = surface;
if (m_androidSurfaceObject.isValid())
m_surfaceWaitCondition.wakeOne();
unlockSurface();
if (m_androidSurfaceObject.isValid())
sendExpose();
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -7,11 +7,19 @@
#include <qobject.h> #include <qobject.h>
#include <qrect.h> #include <qrect.h>
#include <qpa/qplatformwindow.h> #include <qpa/qplatformwindow.h>
#include <QtCore/qjnienvironment.h>
#include <QtCore/qjniobject.h>
#include <QtCore/qjnitypes.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
#include <jni.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
Q_DECLARE_JNI_CLASS(Surface, "android/view/Surface")
class QAndroidPlatformScreen; class QAndroidPlatformScreen;
class QAndroidPlatformBackingStore;
class QAndroidPlatformWindow: public QPlatformWindow class QAndroidPlatformWindow: public QPlatformWindow
{ {
@ -39,32 +47,33 @@ public:
void propagateSizeHints() override; void propagateSizeHints() override;
void requestActivateWindow() override; void requestActivateWindow() override;
void updateSystemUiVisibility(); void updateSystemUiVisibility();
inline bool isRaster() const { inline bool isRaster() const { return m_isRaster; }
if (isForeignWindow())
return false;
return window()->surfaceType() == QSurface::RasterSurface
|| window()->surfaceType() == QSurface::RasterGLSurface;
}
bool isExposed() const override; bool isExposed() const override;
virtual void applicationStateChanged(Qt::ApplicationState); virtual void applicationStateChanged(Qt::ApplicationState);
void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; } void onSurfaceChanged(QtJniTypes::Surface surface);
QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; }
virtual void repaint(const QRegion &) { }
protected: protected:
void setGeometry(const QRect &rect) override; void setGeometry(const QRect &rect) override;
void lockSurface() { m_surfaceMutex.lock(); }
void unlockSurface() { m_surfaceMutex.unlock(); }
void createSurface();
void destroySurface();
void setSurfaceGeometry(const QRect &rect);
void sendExpose();
protected: protected:
Qt::WindowFlags m_windowFlags; Qt::WindowFlags m_windowFlags;
Qt::WindowStates m_windowState; Qt::WindowStates m_windowState;
bool m_isRaster;
WId m_windowId; WId m_windowId;
// The Android Surface, accessed from multiple threads, guarded by m_surfaceMutex
QAndroidPlatformBackingStore *m_backingStore = nullptr; QtJniTypes::Surface m_androidSurfaceObject;
QWaitCondition m_surfaceWaitCondition;
int m_nativeSurfaceId = -1;
QMutex m_surfaceMutex;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE