diff options
Diffstat (limited to 'src/plugins/platforms/android')
18 files changed, 524 insertions, 49 deletions
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 03592bfa7d..73db9e93a3 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -11,6 +11,8 @@ QT += \ eventdispatcher_support-private accessibility_support-private \ fontdatabase_support-private egl_support-private +qtConfig(vulkan): QT += vulkan_support-private + OTHER_FILES += $$PWD/android.json INCLUDEPATH += \ @@ -78,6 +80,13 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp else: SOURCES += $$PWD/extract-dummy.cpp +qtConfig(vulkan) { + SOURCES += $$PWD/qandroidplatformvulkaninstance.cpp \ + $$PWD/qandroidplatformvulkanwindow.cpp + HEADERS += $$PWD/qandroidplatformvulkaninstance.h \ + $$PWD/qandroidplatformvulkanwindow.h +} + PLUGIN_TYPE = platforms load(qt_plugin) diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index dc55ccd615..dabab553c2 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -50,7 +50,7 @@ #include <QGuiApplication> #include <QDebug> -#include <math.h> +#include <QtMath> QT_BEGIN_NAMESPACE @@ -252,7 +252,7 @@ namespace QtAndroidInput QWindowSystemInterface::TouchPoint touchPoint; touchPoint.id = id; touchPoint.pressure = pressure; - touchPoint.rotation = rotation * 180 / M_PI; + touchPoint.rotation = qRadiansToDegrees(rotation); touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh)); touchPoint.state = state; touchPoint.area = QRectF(x - double(minor), diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index ad2fef7070..8b0b18a846 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -529,7 +529,14 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para if (sem_init(&m_terminateSemaphore, 0, 0) == -1) return false; - return pthread_create(&m_qtAppThread, nullptr, startMainMethod, nullptr) == 0; + jboolean res = pthread_create(&m_qtAppThread, nullptr, startMainMethod, nullptr) == 0; + + // The service must wait until the QCoreApplication starts otherwise onBind will be + // called too early + if (m_serviceObject) + QtAndroidPrivate::waitForServiceSetup(); + + return res; } static void quitQtCoreApplication(JNIEnv *env, jclass /*clazz*/) @@ -734,6 +741,11 @@ static void onNewIntent(JNIEnv *env, jclass /*cls*/, jobject data) QtAndroidPrivate::handleNewIntent(env, data); } +static jobject onBind(JNIEnv */*env*/, jclass /*cls*/, jobject intent) +{ + return QtAndroidPrivate::callOnBindListener(intent); +} + static JNINativeMethod methods[] = { {"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin}, {"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication}, @@ -746,7 +758,8 @@ static JNINativeMethod methods[] = { {"updateApplicationState", "(I)V", (void *)updateApplicationState}, {"handleOrientationChanged", "(II)V", (void *)handleOrientationChanged}, {"onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult}, - {"onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent} + {"onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent}, + {"onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind} }; #define FIND_AND_CHECK_CLASS(CLASS_NAME) \ diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp index 08498d0582..ced35c4cfa 100644 --- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp +++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp @@ -103,11 +103,7 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags if (!str.isEmpty()) m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object()); - // http://developer.android.com/design/building-blocks/dialogs.html - // dismissive action on the left, affirmative on the right - // There don't seem to be more fine-grained rules, but the OS X layout - // at least conforms to this one rule and makes the rest deterministic. - const int * currentLayout = buttonLayout(Qt::Horizontal, MacLayout); + const int * currentLayout = buttonLayout(Qt::Horizontal, AndroidLayout); while (*currentLayout != QPlatformDialogHelper::EOL) { int role = (*currentLayout & ~QPlatformDialogHelper::Reverse); addButtons(opt, static_cast<ButtonRole>(role)); diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 7185b573cd..763b294660 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -69,6 +69,11 @@ #include <QtPlatformHeaders/QEGLNativeContext> +#if QT_CONFIG(vulkan) +#include "qandroidplatformvulkanwindow.h" +#include "qandroidplatformvulkaninstance.h" +#endif + QT_BEGIN_NAMESPACE int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320; @@ -119,6 +124,23 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA return 0; } +void *QAndroidPlatformNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ +#if QT_CONFIG(vulkan) + if (resource == "vkSurface") { + if (window->surfaceType() == QSurface::VulkanSurface) { + QAndroidPlatformVulkanWindow *w = static_cast<QAndroidPlatformVulkanWindow *>(window->handle()); + // return a pointer to the VkSurfaceKHR, not the value + return w ? w->vkSurface() : nullptr; + } + } +#else + Q_UNUSED(resource); + Q_UNUSED(window); +#endif + return nullptr; +} + void QAndroidPlatformNativeInterface::customEvent(QEvent *event) { if (event->type() != QEvent::User) @@ -243,6 +265,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const case ForeignWindows: return QtAndroid::activity(); case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroid::activity(); case RasterGLSurface: return QtAndroid::activity(); + case TopStackedNativeChildWindows: return false; default: return QPlatformIntegration::hasCapability(cap); } @@ -295,6 +318,11 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind if (!QtAndroid::activity()) return nullptr; +#if QT_CONFIG(vulkan) + if (window->surfaceType() == QSurface::VulkanSurface) + return new QAndroidPlatformVulkanWindow(window); +#endif + return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); } @@ -443,4 +471,13 @@ void QAndroidPlatformIntegration::setScreenSize(int width, int height) QMetaObject::invokeMethod(m_primaryScreen, "setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height))); } +#if QT_CONFIG(vulkan) + +QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return new QAndroidPlatformVulkanInstance(instance); +} + +#endif // QT_CONFIG(vulkan) + QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index 337f4a9279..c795c499bc 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -40,6 +40,8 @@ #ifndef QANDROIDPLATFORMINTERATION_H #define QANDROIDPLATFORMINTERATION_H +#include <QtGui/qtguiglobal.h> + #include <qpa/qplatformintegration.h> #include <qpa/qplatformmenu.h> #include <qpa/qplatformnativeinterface.h> @@ -64,6 +66,7 @@ class QAndroidPlatformNativeInterface: public QPlatformNativeInterface { public: void *nativeResourceForIntegration(const QByteArray &resource) override; + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override; std::shared_ptr<AndroidStyle> m_androidStyle; protected: @@ -128,6 +131,10 @@ public: void flushPendingUpdates(); +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif + private: EGLDisplay m_eglDisplay; QTouchDevice *m_touchDevice; diff --git a/src/plugins/platforms/android/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp index 06b297a1ad..d9cecebf2c 100644 --- a/src/plugins/platforms/android/qandroidplatformmenu.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp @@ -46,7 +46,6 @@ QT_BEGIN_NAMESPACE QAndroidPlatformMenu::QAndroidPlatformMenu() { - m_tag = reinterpret_cast<quintptr>(this); // QMenu will overwrite this later, but we need a unique ID for QtQuick m_enabled = true; m_isVisible = true; } @@ -92,16 +91,6 @@ void QAndroidPlatformMenu::syncSeparatorsCollapsible(bool enable) Q_UNUSED(enable) } -void QAndroidPlatformMenu::setTag(quintptr tag) -{ - m_tag = tag; -} - -quintptr QAndroidPlatformMenu::tag() const -{ - return m_tag; -} - void QAndroidPlatformMenu::setText(const QString &text) { m_text = text; diff --git a/src/plugins/platforms/android/qandroidplatformmenu.h b/src/plugins/platforms/android/qandroidplatformmenu.h index 00968672c5..47e650f2d7 100644 --- a/src/plugins/platforms/android/qandroidplatformmenu.h +++ b/src/plugins/platforms/android/qandroidplatformmenu.h @@ -61,8 +61,6 @@ public: void syncMenuItem(QPlatformMenuItem *menuItem) override; void syncSeparatorsCollapsible(bool enable) override; - void setTag(quintptr tag) override; - quintptr tag() const override; void setText(const QString &text) override; QString text() const; void setIcon(const QIcon &icon) override; @@ -81,7 +79,6 @@ public: private: PlatformMenuItemsType m_menuItems; - quintptr m_tag; QString m_text; QIcon m_icon; bool m_enabled; diff --git a/src/plugins/platforms/android/qandroidplatformmenuitem.cpp b/src/plugins/platforms/android/qandroidplatformmenuitem.cpp index 0591522e55..e24c5f974e 100644 --- a/src/plugins/platforms/android/qandroidplatformmenuitem.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenuitem.cpp @@ -44,7 +44,6 @@ QT_BEGIN_NAMESPACE QAndroidPlatformMenuItem::QAndroidPlatformMenuItem() { - m_tag = reinterpret_cast<quintptr>(this); // QMenu will overwrite this later, but we need a unique ID for QtQuick m_menu = 0; m_isVisible = true; m_isSeparator = false; @@ -54,16 +53,6 @@ QAndroidPlatformMenuItem::QAndroidPlatformMenuItem() m_isEnabled = true; } -void QAndroidPlatformMenuItem::setTag(quintptr tag) -{ - m_tag = tag; -} - -quintptr QAndroidPlatformMenuItem::tag() const -{ - return m_tag; -} - void QAndroidPlatformMenuItem::setText(const QString &text) { m_text = text; diff --git a/src/plugins/platforms/android/qandroidplatformmenuitem.h b/src/plugins/platforms/android/qandroidplatformmenuitem.h index be5240cfa6..b8782f995d 100644 --- a/src/plugins/platforms/android/qandroidplatformmenuitem.h +++ b/src/plugins/platforms/android/qandroidplatformmenuitem.h @@ -49,8 +49,6 @@ class QAndroidPlatformMenuItem: public QPlatformMenuItem { public: QAndroidPlatformMenuItem(); - void setTag(quintptr tag) override; - quintptr tag() const override; void setText(const QString &text) override; QString text() const; @@ -86,7 +84,6 @@ public: void setIconSize(int size) override; private: - quintptr m_tag; QString m_text; QIcon m_icon; QAndroidPlatformMenu *m_menu; diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 3b59b293a5..3a79e32abe 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -85,7 +85,8 @@ private: # define PROFILE_SCOPE #endif -QAndroidPlatformScreen::QAndroidPlatformScreen():QObject(),QPlatformScreen() +QAndroidPlatformScreen::QAndroidPlatformScreen() + : QObject(), QPlatformScreen() { m_availableGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, QAndroidPlatformIntegration::m_defaultGeometryHeight); m_size = QSize(QAndroidPlatformIntegration::m_defaultScreenWidth, QAndroidPlatformIntegration::m_defaultScreenHeight); @@ -100,9 +101,6 @@ QAndroidPlatformScreen::QAndroidPlatformScreen():QObject(),QPlatformScreen() } m_physicalSize.setHeight(QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight); m_physicalSize.setWidth(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth); - m_redrawTimer.setSingleShot(true); - m_redrawTimer.setInterval(0); - connect(&m_redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw())); connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QAndroidPlatformScreen::applicationStateChanged); } @@ -136,6 +134,16 @@ 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()) @@ -209,8 +217,10 @@ void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window) void QAndroidPlatformScreen::scheduleUpdate() { - if (!m_redrawTimer.isActive()) - m_redrawTimer.start(); + if (!m_updatePending) { + m_updatePending = true; + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); + } } void QAndroidPlatformScreen::setDirty(const QRect &rect) diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index 923c9e8832..f15aeae3fd 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -89,10 +89,12 @@ public slots: void setSize(const QSize &size); protected: + bool event(QEvent *event) override; + typedef QList<QAndroidPlatformWindow *> WindowStackType; WindowStackType m_windowStack; QRect m_dirtyRect; - QTimer m_redrawTimer; + bool m_updatePending = false; QRect m_availableGeometry; int m_depth; diff --git a/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp b/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp new file mode 100644 index 0000000000..a411d0f007 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkaninstance.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qandroidplatformvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +QAndroidPlatformVulkanInstance::QAndroidPlatformVulkanInstance(QVulkanInstance *instance) + : m_instance(instance) +{ + m_lib.setFileName(QStringLiteral("vulkan")); + + if (!m_lib.load()) { + qWarning("Failed to load %s", qPrintable(m_lib.fileName())); + return; + } + + init(&m_lib); +} + +void QAndroidPlatformVulkanInstance::createOrAdoptInstance() +{ + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_KHR_android_surface")); +} + +QAndroidPlatformVulkanInstance::~QAndroidPlatformVulkanInstance() +{ +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformvulkaninstance.h b/src/plugins/platforms/android/qandroidplatformvulkaninstance.h new file mode 100644 index 0000000000..67edcceed9 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkaninstance.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANDROIDPLATFORMVULKANINSTANCE_H +#define QANDROIDPLATFORMVULKANINSTANCE_H + +#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h> +#include <QLibrary> + +QT_BEGIN_NAMESPACE + +class QAndroidPlatformVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + QAndroidPlatformVulkanInstance(QVulkanInstance *instance); + ~QAndroidPlatformVulkanInstance(); + + void createOrAdoptInstance() override; + +private: + QVulkanInstance *m_instance; + QLibrary m_lib; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMVULKANINSTANCE_H diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp new file mode 100644 index 0000000000..cc41a871f3 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qandroidplatformvulkanwindow.h" +#include "qandroidplatformscreen.h" +#include "androidjnimain.h" +#include "qandroideventdispatcher.h" +#include "androiddeadlockprotector.h" + +#include <QSurfaceFormat> +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformscreen.h> + +#include <android/native_window.h> +#include <android/native_window_jni.h> + +QT_BEGIN_NAMESPACE + +QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window) + : QAndroidPlatformWindow(window), + m_nativeSurfaceId(-1), + m_nativeWindow(nullptr), + m_vkSurface(0), + m_createVkSurface(nullptr), + m_destroyVkSurface(nullptr) +{ +} + +QAndroidPlatformVulkanWindow::~QAndroidPlatformVulkanWindow() +{ + m_surfaceWaitCondition.wakeOne(); + lockSurface(); + if (m_nativeSurfaceId != -1) + QtAndroid::destroySurface(m_nativeSurfaceId); + clearSurface(); + unlockSurface(); +} + +void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect) +{ + if (rect == geometry()) + return; + + m_oldGeometry = geometry(); + + QAndroidPlatformWindow::setGeometry(rect); + if (m_nativeSurfaceId != -1) + QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); + + QRect availableGeometry = screen()->availableGeometry(); + 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)); +} + +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(); + } +} + +QSurfaceFormat QAndroidPlatformVulkanWindow::format() const +{ + return window()->requestedFormat(); +} + +void QAndroidPlatformVulkanWindow::clearSurface() +{ + if (m_vkSurface && m_destroyVkSurface) { + m_destroyVkSurface(window()->vulkanInstance()->vkInstance(), m_vkSurface, nullptr); + m_vkSurface = 0; + } + + if (m_nativeWindow) { + ANativeWindow_release(m_nativeWindow); + m_nativeWindow = nullptr; + } +} + +void QAndroidPlatformVulkanWindow::sendExpose() +{ + 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(); + unlockSurface(); + + if (surface) + sendExpose(); +} + +VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface() +{ + if (QAndroidEventDispatcherStopper::stopped()) + return &m_vkSurface; + + bool needsExpose = false; + if (!m_vkSurface) { + clearSurface(); + + QMutexLocker lock(&m_surfaceMutex); + if (m_nativeSurfaceId == -1) { + AndroidDeadlockProtector protector; + if (!protector.acquire()) + return &m_vkSurface; + const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); + m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32); + m_surfaceWaitCondition.wait(&m_surfaceMutex); + } + + if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid()) + return &m_vkSurface; + + QJNIEnvironmentPrivate env; + m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurfaceObject.object()); + + VkAndroidSurfaceCreateInfoKHR surfaceInfo; + memset(&surfaceInfo, 0, sizeof(surfaceInfo)); + surfaceInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + surfaceInfo.window = m_nativeWindow; + QVulkanInstance *inst = window()->vulkanInstance(); + if (!inst) { + qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"); + return &m_vkSurface; + } + if (!m_createVkSurface) { + m_createVkSurface = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>( + inst->getInstanceProcAddr("vkCreateAndroidSurfaceKHR")); + } + if (!m_destroyVkSurface) { + m_destroyVkSurface = reinterpret_cast<PFN_vkDestroySurfaceKHR>( + inst->getInstanceProcAddr("vkDestroySurfaceKHR")); + } + VkResult err = m_createVkSurface(inst->vkInstance(), &surfaceInfo, nullptr, &m_vkSurface); + if (err != VK_SUCCESS) + qWarning("Failed to create Android VkSurface: %d", err); + + needsExpose = true; + } + + if (needsExpose) + sendExpose(); + + return &m_vkSurface; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h new file mode 100644 index 0000000000..19eca98720 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANDROIDPLATFORMVULKANWINDOW_H +#define QANDROIDPLATFORMVULKANWINDOW_H + +#if defined(VULKAN_H_) && !defined(VK_USE_PLATFORM_ANDROID_KHR) +#error "vulkan.h included without Android WSI" +#endif + +#define VK_USE_PLATFORM_ANDROID_KHR + +#include <QWaitCondition> +#include <QtCore/private/qjni_p.h> + +#include "androidsurfaceclient.h" +#include "qandroidplatformwindow.h" + +#include "qandroidplatformvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient +{ +public: + explicit QAndroidPlatformVulkanWindow(QWindow *window); + ~QAndroidPlatformVulkanWindow(); + + void setGeometry(const QRect &rect) override; + QSurfaceFormat format() const override; + void applicationStateChanged(Qt::ApplicationState) override; + + VkSurfaceKHR *vkSurface(); + +protected: + void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override; + +private: + void sendExpose(); + void clearSurface(); + + int m_nativeSurfaceId; + ANativeWindow *m_nativeWindow; + QJNIObjectPrivate m_androidSurfaceObject; + QWaitCondition m_surfaceWaitCondition; + QSurfaceFormat m_format; + QRect m_oldGeometry; + VkSurfaceKHR m_vkSurface; + PFN_vkCreateAndroidSurfaceKHR m_createVkSurface; + PFN_vkDestroySurfaceKHR m_destroyVkSurface; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMVULKANWINDOW_H diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 424cfefc6c..c095f51fa3 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -56,7 +56,7 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) m_windowState = Qt::WindowNoState; static QAtomicInt winIdGenerator(1); m_windowId = winIdGenerator.fetchAndAddRelaxed(1); - setWindowState(window->windowState()); + setWindowState(window->windowStates()); } void QAndroidPlatformWindow::lower() @@ -73,7 +73,6 @@ void QAndroidPlatformWindow::raise() void QAndroidPlatformWindow::setGeometry(const QRect &rect) { QWindowSystemInterface::handleGeometryChange(window(), rect); - QPlatformWindow::setGeometry(rect); } void QAndroidPlatformWindow::setVisible(bool visible) @@ -98,7 +97,7 @@ void QAndroidPlatformWindow::setVisible(bool visible) QPlatformWindow::setVisible(visible); } -void QAndroidPlatformWindow::setWindowState(Qt::WindowState state) +void QAndroidPlatformWindow::setWindowState(Qt::WindowStates state) { if (m_windowState == state) return; diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 91cb1e76e6..f2e51bd3df 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -59,7 +59,7 @@ public: void setVisible(bool visible) override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; void setWindowFlags(Qt::WindowFlags flags) override; Qt::WindowFlags windowFlags() const; void setParent(const QPlatformWindow *window) override; @@ -91,7 +91,7 @@ protected: protected: Qt::WindowFlags m_windowFlags; - Qt::WindowState m_windowState; + Qt::WindowStates m_windowState; WId m_windowId; |