From 2020ce5fd2478389c56f34742fdeee9cd24ca8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tinja=20Paavosepp=C3=A4?= Date: Mon, 6 Nov 2023 13:02:10 +0200 Subject: [PATCH] Android: Give raster windows their own surface, and flush via RHI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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ø --- .../org/qtproject/qt/android/QtNative.java | 2 +- .../org/qtproject/qt/android/QtSurface.java | 4 +- src/gui/CMakeLists.txt | 2 + src/plugins/platforms/android/CMakeLists.txt | 2 - .../platforms/android/androidjnimain.cpp | 20 +- .../platforms/android/androidjnimain.h | 4 +- .../platforms/android/androidsurfaceclient.h | 24 -- .../android/qandroidplatformbackingstore.cpp | 48 ---- .../android/qandroidplatformbackingstore.h | 28 -- .../android/qandroidplatformforeignwindow.h | 1 - .../android/qandroidplatformintegration.cpp | 7 +- .../android/qandroidplatformopenglwindow.cpp | 62 +---- .../android/qandroidplatformopenglwindow.h | 9 +- .../android/qandroidplatformscreen.cpp | 258 +----------------- .../android/qandroidplatformscreen.h | 30 +- .../android/qandroidplatformvulkanwindow.cpp | 45 +-- .../android/qandroidplatformvulkanwindow.h | 11 +- .../android/qandroidplatformwindow.cpp | 45 ++- .../android/qandroidplatformwindow.h | 37 ++- 19 files changed, 108 insertions(+), 531 deletions(-) delete mode 100644 src/plugins/platforms/android/androidsurfaceclient.h delete mode 100644 src/plugins/platforms/android/qandroidplatformbackingstore.cpp delete mode 100644 src/plugins/platforms/android/qandroidplatformbackingstore.h diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/QtNative.java index ee67362fece..e4d3ce5b7b5 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java @@ -377,7 +377,7 @@ class QtNative // application 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 // window methods diff --git a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java index 704574384af..92050c88855 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java @@ -50,13 +50,13 @@ class QtSurface extends SurfaceView implements SurfaceHolder.Callback if (width < 1 || height < 1) return; - QtNative.setSurface(getId(), holder.getSurface(), width, height); + QtNative.setSurface(getId(), holder.getSurface()); } @Override public void surfaceDestroyed(SurfaceHolder holder) { - QtNative.setSurface(getId(), null, 0, 0); + QtNative.setSurface(getId(), null); } @Override diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 1f1fbc65c8e..0b2bc18f949 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -641,6 +641,8 @@ endif() qt_internal_extend_target(Gui CONDITION ANDROID SOURCES 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) diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt index db961e7a938..a3344bfd712 100644 --- a/src/plugins/platforms/android/CMakeLists.txt +++ b/src/plugins/platforms/android/CMakeLists.txt @@ -17,13 +17,11 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin androidjniinput.cpp androidjniinput.h androidjnimain.cpp androidjnimain.h androidjnimenu.cpp androidjnimenu.h - androidsurfaceclient.h main.cpp qandroidassetsfileenginehandler.cpp qandroidassetsfileenginehandler.h qandroideventdispatcher.cpp qandroideventdispatcher.h qandroidinputcontext.cpp qandroidinputcontext.h qandroidplatformaccessibility.cpp qandroidplatformaccessibility.h - qandroidplatformbackingstore.cpp qandroidplatformbackingstore.h qandroidplatformclipboard.cpp qandroidplatformclipboard.h qandroidplatformdialoghelpers.cpp qandroidplatformdialoghelpers.h qandroidplatformfiledialoghelper.cpp qandroidplatformfiledialoghelper.h diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 1a451b61e70..fdf4611ff64 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -18,6 +18,7 @@ #include "qandroidplatformdialoghelpers.h" #include "qandroidplatformintegration.h" #include "qandroidplatformclipboard.h" +#include "qandroidplatformwindow.h" #include #include @@ -69,7 +70,7 @@ static void *m_mainLibraryHnd = nullptr; static QList m_applicationParams; static sem_t m_exitSemaphore, m_terminateSemaphore; -QHash m_surfaces; +QHash m_surfaces; Q_CONSTINIT static QBasicMutex m_surfacesMutex; @@ -323,7 +324,7 @@ namespace QtAndroid return QJniObject::callStaticMethod("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; if (!env.jniEnv()) @@ -331,7 +332,7 @@ namespace QtAndroid m_surfacesMutex.lock(); jint surfaceId = generateViewId(); - m_surfaces[surfaceId] = client; + m_surfaces[surfaceId] = window; m_surfacesMutex.unlock(); jint x = 0, y = 0, w = -1, h = -1; @@ -594,8 +595,11 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) 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); const auto &it = m_surfaces.find(id); if (it == m_surfaces.end()) @@ -603,7 +607,7 @@ static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, auto surfaceClient = it.value(); if (surfaceClient) - surfaceClient->surfaceChanged(env, jSurface, w, h); + surfaceClient->onSurfaceChanged(jSurface); } 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()))); } } - - QAndroidPlatformScreen *screen = static_cast(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) @@ -802,7 +802,7 @@ static JNINativeMethod methods[] = { { "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication }, { "terminateQt", "()V", (void *)terminateQt }, { "waitForServiceSetup", "()V", (void *)waitForServiceSetup }, - { "setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface }, + { "setSurface", "(ILjava/lang/Object;)V", (void *)setSurface }, { "updateWindow", "()V", (void *)updateWindow }, { "updateApplicationState", "(I)V", (void *)updateApplicationState }, { "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult }, diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 349eba99623..090e87d7f7b 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -23,7 +23,7 @@ class QAndroidPlatformIntegration; class QWidget; class QString; class QWindow; -class AndroidSurfaceClient; +class QAndroidPlatformWindow; class QBasicMutex; Q_DECLARE_JNI_CLASS(QtActivityDelegate, "org/qtproject/qt/android/QtActivityDelegate") @@ -37,7 +37,7 @@ namespace QtAndroid void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration); 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); void setViewVisibility(jobject view, bool visible); void setSurfaceGeometry(int surfaceId, const QRect &geometry); diff --git a/src/plugins/platforms/android/androidsurfaceclient.h b/src/plugins/platforms/android/androidsurfaceclient.h deleted file mode 100644 index dded9a1f663..00000000000 --- a/src/plugins/platforms/android/androidsurfaceclient.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2014 BogDan Vatra -// 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 -#include - -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 diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp deleted file mode 100644 index 09cc9ce8c6b..00000000000 --- a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2014 BogDan Vatra -// 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 - -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 ®ion, const QPoint &offset) -{ - Q_UNUSED(offset); - - auto *platformWindow = static_cast(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(window->handle()))->setBackingStore(this); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.h b/src/plugins/platforms/android/qandroidplatformbackingstore.h deleted file mode 100644 index b64a9f27bb7..00000000000 --- a/src/plugins/platforms/android/qandroidplatformbackingstore.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2014 BogDan Vatra -// 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 -#include - -QT_BEGIN_NAMESPACE - -class QAndroidPlatformBackingStore : public QPlatformBackingStore -{ -public: - explicit QAndroidPlatformBackingStore(QWindow *window); - QPaintDevice *paintDevice() override; - void flush(QWindow *window, const QRegion ®ion, 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 diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h index 7b576ecec42..7ddacda17f0 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h @@ -4,7 +4,6 @@ #ifndef QANDROIDPLATFORMFOREIGNWINDOW_H #define QANDROIDPLATFORMFOREIGNWINDOW_H -#include "androidsurfaceclient.h" #include "qandroidplatformwindow.h" #include diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index a31e3c8f69b..d6d4ded3f2f 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -9,7 +9,6 @@ #include "qabstracteventdispatcher.h" #include "qandroideventdispatcher.h" #include "qandroidplatformaccessibility.h" -#include "qandroidplatformbackingstore.h" #include "qandroidplatformclipboard.h" #include "qandroidplatformfontdatabase.h" #include "qandroidplatformforeignwindow.h" @@ -29,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -323,6 +323,9 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const case RasterGLSurface: return QtAndroidPrivate::activity().isValid(); case TopStackedNativeChildWindows: return false; 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: return QPlatformIntegration::hasCapability(cap); } @@ -333,7 +336,7 @@ QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(Q if (!QtAndroidPrivate::activity().isValid()) return nullptr; - return new QAndroidPlatformBackingStore(window); + return new QRhiBackingStore(window); } QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index c1ec2fbdd64..7f2252a4e93 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -24,41 +24,19 @@ QT_BEGIN_NAMESPACE QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display) :QAndroidPlatformWindow(window), m_eglDisplay(display) { + if (window->surfaceType() == QSurface::RasterSurface) + window->setSurfaceType(QSurface::OpenGLSurface); } QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow() { m_surfaceWaitCondition.wakeOne(); lockSurface(); - if (m_nativeSurfaceId != -1) - QtAndroid::destroySurface(m_nativeSurfaceId); + destroySurface(); clearEgl(); unlockSurface(); } -void QAndroidPlatformOpenGLWindow::repaint(const QRegion ®ion) -{ - // 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()) @@ -67,8 +45,7 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) m_oldGeometry = geometry(); QAndroidPlatformWindow::setGeometry(rect); - if (m_nativeSurfaceId != -1) - QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); + setSurfaceGeometry(rect); QRect availableGeometry = screen()->availableGeometry(); if (rect.width() > 0 @@ -77,9 +54,6 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) && 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) @@ -94,8 +68,7 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) if (!protector.acquire()) return m_eglSurface; - const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); - m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32); + createSurface(); m_surfaceWaitCondition.wait(&m_surfaceMutex); } @@ -127,10 +100,7 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState QAndroidPlatformWindow::applicationStateChanged(state); if (state <= Qt::ApplicationHidden) { lockSurface(); - if (m_nativeSurfaceId != -1) { - QtAndroid::destroySurface(m_nativeSurfaceId); - m_nativeSurfaceId = -1; - } + destroySurface(); clearEgl(); 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 diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h index 8c31368b654..c1ae57fe859 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h @@ -5,7 +5,6 @@ #ifndef QANDROIDPLATFORMOPENGLWINDOW_H #define QANDROIDPLATFORMOPENGLWINDOW_H -#include "androidsurfaceclient.h" #include "qandroidplatformwindow.h" #include @@ -16,7 +15,7 @@ QT_BEGIN_NAMESPACE -class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient +class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow { public: explicit QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display); @@ -30,10 +29,7 @@ public: void applicationStateChanged(Qt::ApplicationState) override; - void repaint(const QRegion ®ion) override; - protected: - void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override; void createEgl(EGLConfig config); void clearEgl(); @@ -42,9 +38,6 @@ private: EGLSurface m_eglSurface = EGL_NO_SURFACE; EGLNativeWindowType m_nativeWindow = nullptr; - int m_nativeSurfaceId = -1; - QJniObject m_androidSurfaceObject; - QWaitCondition m_surfaceWaitCondition; QSurfaceFormat m_format; QRect m_oldGeometry; }; diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 20f414b48fe..268772e2655 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -8,7 +8,6 @@ #include #include "qandroidplatformscreen.h" -#include "qandroidplatformbackingstore.h" #include "qandroidplatformintegration.h" #include "qandroidplatformwindow.h" #include "androidjnimain.h" @@ -131,11 +130,6 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject) QAndroidPlatformScreen::~QAndroidPlatformScreen() { - if (m_surfaceId != -1) { - QtAndroid::destroySurface(m_surfaceId); - m_surfaceWaitCondition.wakeOne(); - releaseSurface(); - } } QWindow *QAndroidPlatformScreen::topWindow() const @@ -159,16 +153,6 @@ QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const 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) { if (window->parent() && window->isRaster()) @@ -178,10 +162,6 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window) return; m_windowStack.prepend(window); - if (window->isRaster()) { - m_rasterSurfaces.ref(); - setDirty(window->geometry()); - } QWindow *w = topWindow(); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); @@ -198,11 +178,6 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) if (m_windowStack.contains(window)) qWarning() << "Failed to remove window"; - if (window->isRaster()) { - m_rasterSurfaces.deref(); - setDirty(window->geometry()); - } - QWindow *w = topWindow(); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); topWindowChanged(w); @@ -210,16 +185,11 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) { - if (window->parent() && window->isRaster()) - return; - int index = m_windowStack.indexOf(window); if (index <= 0) return; m_windowStack.move(index, 0); - if (window->isRaster()) { - setDirty(window->geometry()); - } + QWindow *w = topWindow(); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); topWindowChanged(w); @@ -227,36 +197,16 @@ void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window) { - if (window->parent() && window->isRaster()) - return; - int index = m_windowStack.indexOf(window); if (index == -1 || index == (m_windowStack.size() - 1)) return; m_windowStack.move(index, m_windowStack.size() - 1); - if (window->isRaster()) { - setDirty(window->geometry()); - } + QWindow *w = topWindow(); QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); 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) { m_physicalSize = size; @@ -306,7 +256,6 @@ void QAndroidPlatformScreen::setOrientation(Qt::ScreenOrientation orientation) void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect) { - QMutexLocker lock(&m_surfaceMutex); if (m_availableGeometry == rect) 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) { for (QAndroidPlatformWindow *w : std::as_const(m_windowStack)) w->applicationStateChanged(state); - - if (state <= Qt::ApplicationHidden) { - lockSurface(); - QtAndroid::destroySurface(m_surfaceId); - m_surfaceId = -1; - releaseSurface(); - unlockSurface(); - } } 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(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(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(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(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; QDpi QAndroidPlatformScreen::logicalDpi() const @@ -508,67 +317,4 @@ Qt::ScreenOrientation QAndroidPlatformScreen::nativeOrientation() const { 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(this)->doScreenShot(screenshotRect.toRect()); -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index 076530613b5..0e2f788886b 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -5,8 +5,6 @@ #ifndef QANDROIDPLATFORMSCREEN_H #define QANDROIDPLATFORMSCREEN_H -#include "androidsurfaceclient.h" - #include #include #include @@ -15,14 +13,12 @@ #include #include -#include - QT_BEGIN_NAMESPACE class QAndroidPlatformWindow; class QAndroidPlatformScreen: public QObject, - public QPlatformScreen, public AndroidSurfaceClient, + public QPlatformScreen, public QNativeInterface::Private::QAndroidScreen { Q_OBJECT @@ -44,19 +40,15 @@ public: inline QWindow *topWindow() const; QWindow *topLevelAt(const QPoint & p) const override; - // compositor api void addWindow(QAndroidPlatformWindow *window); void removeWindow(QAndroidPlatformWindow *window); void raise(QAndroidPlatformWindow *window); void lower(QAndroidPlatformWindow *window); - void scheduleUpdate(); void topWindowChanged(QWindow *w); - int rasterSurfaces(); int displayId() const override; public slots: - void setDirty(const QRect &rect); void setPhysicalSize(const QSize &size); void setAvailableGeometry(const QRect &rect); void setSize(const QSize &size); @@ -66,12 +58,8 @@ public slots: void setOrientation(Qt::ScreenOrientation orientation); protected: - bool event(QEvent *event) override; - typedef QList WindowStackType; WindowStackType m_windowStack; - QRect m_dirtyRect; - bool m_updatePending = false; QRect m_availableGeometry; int m_depth; @@ -88,25 +76,9 @@ private: QDpi logicalBaseDpi() const override; Qt::ScreenOrientation orientation() 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); - QPixmap doScreenShot(QRect grabRect = QRect()); - -private slots: - void doRedraw(QImage *screenGrabImage = nullptr); - private: - int m_surfaceId = -1; - QAtomicInt m_rasterSurfaces = 0; - ANativeWindow* m_nativeSurface = nullptr; - QWaitCondition m_surfaceWaitCondition; QSize m_size; - - QImage m_lastScreenshot; - QImage::Format m_pixelFormat = QImage::Format_RGBA8888_Premultiplied; - bool m_repaintOccurred = false; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp index cb6bb6d390c..df87240c2b0 100644 --- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp @@ -18,7 +18,6 @@ QT_BEGIN_NAMESPACE QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window) : QAndroidPlatformWindow(window), - m_nativeSurfaceId(-1), m_nativeWindow(nullptr), m_vkSurface(0), m_createVkSurface(nullptr), @@ -29,11 +28,7 @@ QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window) QAndroidPlatformVulkanWindow::~QAndroidPlatformVulkanWindow() { m_surfaceWaitCondition.wakeOne(); - lockSurface(); - if (m_nativeSurfaceId != -1) - QtAndroid::destroySurface(m_nativeSurfaceId); - clearSurface(); - unlockSurface(); + destroyAndClearSurface(); } void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect) @@ -44,8 +39,7 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect) m_oldGeometry = geometry(); QAndroidPlatformWindow::setGeometry(rect); - if (m_nativeSurfaceId != -1) - QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); + setSurfaceGeometry(rect); QRect availableGeometry = screen()->availableGeometry(); if (rect.width() > 0 @@ -54,22 +48,13 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect) && availableGeometry.height() > 0) { QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); } - - if (rect.topLeft() != m_oldGeometry.topLeft()) - repaint(QRegion(rect)); } void QAndroidPlatformVulkanWindow::applicationStateChanged(Qt::ApplicationState state) { QAndroidPlatformWindow::applicationStateChanged(state); if (state <= Qt::ApplicationHidden) { - lockSurface(); - if (m_nativeSurfaceId != -1) { - QtAndroid::destroySurface(m_nativeSurfaceId); - m_nativeSurfaceId = -1; - } - clearSurface(); - unlockSurface(); + destroyAndClearSurface(); } } @@ -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(); - m_androidSurfaceObject = surface; - if (surface) - m_surfaceWaitCondition.wakeOne(); + destroySurface(); + clearSurface(); unlockSurface(); - - if (surface) - sendExpose(); } VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface() @@ -128,8 +98,7 @@ VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface() AndroidDeadlockProtector protector; if (!protector.acquire()) return &m_vkSurface; - const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); - m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32); + createSurface(); m_surfaceWaitCondition.wait(&m_surfaceMutex); } diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h index 14d5b7fc0ef..fa959239d11 100644 --- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h @@ -10,7 +10,6 @@ #define VK_USE_PLATFORM_ANDROID_KHR -#include "androidsurfaceclient.h" #include "qandroidplatformvulkaninstance.h" #include "qandroidplatformwindow.h" @@ -20,7 +19,7 @@ QT_BEGIN_NAMESPACE -class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient +class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow { public: explicit QAndroidPlatformVulkanWindow(QWindow *window); @@ -32,17 +31,11 @@ public: VkSurfaceKHR *vkSurface(); -protected: - void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override; - private: - void sendExpose(); void clearSurface(); + void destroyAndClearSurface(); - int m_nativeSurfaceId; ANativeWindow *m_nativeWindow; - QJniObject m_androidSurfaceObject; - QWaitCondition m_surfaceWaitCondition; QSurfaceFormat m_format; QRect m_oldGeometry; VkSurfaceKHR m_vkSurface; diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 61d326228c3..23b83834d45 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -17,10 +17,13 @@ QT_BEGIN_NAMESPACE Q_CONSTINIT static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0); QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) - : QPlatformWindow(window) + : QPlatformWindow(window), m_androidSurfaceObject(nullptr) { m_windowFlags = Qt::Widget; 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; setWindowState(window->windowStates()); @@ -171,4 +174,44 @@ void QAndroidPlatformWindow::applicationStateChanged(Qt::ApplicationState) 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 diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 6fccc2e7fea..a676ef1dd3b 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -7,11 +7,19 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE +Q_DECLARE_JNI_CLASS(Surface, "android/view/Surface") + class QAndroidPlatformScreen; -class QAndroidPlatformBackingStore; class QAndroidPlatformWindow: public QPlatformWindow { @@ -39,32 +47,33 @@ public: void propagateSizeHints() override; void requestActivateWindow() override; void updateSystemUiVisibility(); - inline bool isRaster() const { - if (isForeignWindow()) - return false; - - return window()->surfaceType() == QSurface::RasterSurface - || window()->surfaceType() == QSurface::RasterGLSurface; - } + inline bool isRaster() const { return m_isRaster; } bool isExposed() const override; virtual void applicationStateChanged(Qt::ApplicationState); - void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; } - QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; } - - virtual void repaint(const QRegion &) { } + void onSurfaceChanged(QtJniTypes::Surface surface); protected: 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: Qt::WindowFlags m_windowFlags; Qt::WindowStates m_windowState; + bool m_isRaster; WId m_windowId; - - QAndroidPlatformBackingStore *m_backingStore = nullptr; + // The Android Surface, accessed from multiple threads, guarded by m_surfaceMutex + QtJniTypes::Surface m_androidSurfaceObject; + QWaitCondition m_surfaceWaitCondition; + int m_nativeSurfaceId = -1; + QMutex m_surfaceMutex; }; QT_END_NAMESPACE