summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/ios')
-rw-r--r--src/plugins/platforms/ios/qioscontext.h1
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm66
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm2
3 files changed, 59 insertions, 10 deletions
diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h
index 5b7917f7b4..ce50eff1d9 100644
--- a/src/plugins/platforms/ios/qioscontext.h
+++ b/src/plugins/platforms/ios/qioscontext.h
@@ -87,6 +87,7 @@ private:
bool isComplete;
};
+ static bool verifyGraphicsHardwareAvailability();
static void deleteBuffers(const FramebufferObject &framebufferObject);
FramebufferObject &backingFramebufferObjectFor(QPlatformSurface *) const;
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 6a6cbb4324..03643c19a9 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -38,10 +38,13 @@
****************************************************************************/
#include "qioscontext.h"
+
+#include "qiosintegration.h"
#include "qioswindow.h"
#include <dlfcn.h>
+#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLContext>
#import <OpenGLES/EAGL.h>
@@ -136,6 +139,9 @@ bool QIOSContext::makeCurrent(QPlatformSurface *surface)
{
Q_ASSERT_IS_GL_SURFACE(surface);
+ if (!verifyGraphicsHardwareAvailability())
+ return false;
+
[EAGLContext setCurrentContext:m_eaglContext];
// For offscreen surfaces we don't prepare a default FBO
@@ -214,18 +220,12 @@ void QIOSContext::swapBuffers(QPlatformSurface *surface)
{
Q_ASSERT_IS_GL_SURFACE(surface);
+ if (!verifyGraphicsHardwareAvailability())
+ return;
+
if (surface->surface()->surfaceClass() == QSurface::Offscreen)
return; // Nothing to do
- // When using threaded rendering, the render-thread may not have picked up
- // yet on the fact that a window is no longer exposed, and will try to swap
- // a non-exposed window. This may in some cases result in crashes, e.g. when
- // iOS is suspending an application, so we have an extra guard here.
- if (!static_cast<QIOSWindow *>(surface)->isExposed()) {
- qCDebug(lcQpaGLContext, "Detected swapBuffers on a non-exposed window, skipping flush");
- return;
- }
-
FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
Q_ASSERT_X(framebufferObject.isComplete, "QIOSContext", "swapBuffers on incomplete FBO");
@@ -287,6 +287,54 @@ bool QIOSContext::needsRenderbufferResize(QPlatformSurface *surface) const
return false;
}
+bool QIOSContext::verifyGraphicsHardwareAvailability()
+{
+ // Per the iOS OpenGL ES Programming Guide, background apps may not execute commands on the
+ // graphics hardware. Specifically: "In your app delegate’s applicationDidEnterBackground:
+ // method, your app may want to delete some of its OpenGL ES objects to make memory and
+ // resources available to the foreground app. Call the glFinish function to ensure that
+ // the resources are removed immediately. After your app exits its applicationDidEnterBackground:
+ // method, it must not make any new OpenGL ES calls. If it makes an OpenGL ES call, it is
+ // terminated by iOS.".
+ static bool applicationBackgrounded = QGuiApplication::applicationState() == Qt::ApplicationSuspended;
+
+ static dispatch_once_t onceToken = 0;
+ dispatch_once(&onceToken, ^{
+ QIOSApplicationState *applicationState = &QIOSIntegration::instance()->applicationState;
+ connect(applicationState, &QIOSApplicationState::applicationStateWillChange, [](Qt::ApplicationState state) {
+ if (applicationBackgrounded && state != Qt::ApplicationSuspended) {
+ qCDebug(lcQpaGLContext) << "app no longer backgrounded, rendering enabled";
+ applicationBackgrounded = false;
+ }
+ });
+ connect(applicationState, &QIOSApplicationState::applicationStateDidChange, [](Qt::ApplicationState state) {
+ if (state != Qt::ApplicationSuspended)
+ return;
+
+ qCDebug(lcQpaGLContext) << "app backgrounded, rendering disabled";
+ applicationBackgrounded = true;
+
+ // By the time we receive this signal the application has moved into
+ // Qt::ApplactionStateSuspended, and all windows have been obscured,
+ // which should stop all rendering. If there's still an active GL context,
+ // we follow Apple's advice and call glFinish before making it inactive.
+ if (QOpenGLContext *currentContext = QOpenGLContext::currentContext()) {
+ qCWarning(lcQpaGLContext) << "explicitly glFinishing and deactivating" << currentContext;
+ glFinish();
+ currentContext->doneCurrent();
+ }
+ });
+ });
+
+ if (applicationBackgrounded) {
+ static const char warning[] = "OpenGL ES calls are not allowed while an application is backgrounded";
+ Q_ASSERT_X(!applicationBackgrounded, "QIOSContext", warning);
+ qCWarning(lcQpaGLContext, warning);
+ }
+
+ return !applicationBackgrounded;
+}
+
void QIOSContext::windowDestroyed(QObject *object)
{
QIOSWindow *window = static_cast<QIOSWindow *>(object);
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index fb161febda..e934cb90fa 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -225,7 +225,7 @@ void QIOSWindow::applyGeometry(const QRect &rect)
bool QIOSWindow::isExposed() const
{
- return qApp->applicationState() >= Qt::ApplicationActive
+ return qApp->applicationState() != Qt::ApplicationSuspended
&& window()->isVisible() && !window()->geometry().isEmpty();
}