iOS: Pause display link when app moves out of active state
The applicationWillResignActive documentation describes that the app should "use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates". Similarly, the more modern sceneWillResignActive describes that the app should "use this method to quiet your interface and prepare it to stop interacting with the user. Specifically, pause ongoing tasks, disable timers, and decrease frame rates or stop updating your interface altogether." In practice the application enters the inactive (as opposed to the backgrounded) state when the user brings up the app switcher, or enters split-view mode, as described by the "Adopting Multitasking Enhancements on iPad" documentation. We do propagate the inactive state as Qt::ApplicationInactive, but it was up to the application itself to react to the state. To adhere to the documented behavior, we now skip update request delivery if the app is not active. Once it becomes active again we re-try the update request delivery. Relying on the exposed state of window was not an option, as the window is still technically exposed, even if the app itself is inactive. This hopefully fixes a GPU crash observed (only) on A10 iPads (iPad 7) with iOS 18, when the user entered split-view mode, possibly due to changes in the system Metal-based OpenGL driver: void IOGPUScheduler::signalHardwareError(eRestartRequest, int32_t) void IOGPUScheduler::hardware_error_interrupt(IOInterruptEventSource *, int) void IOGPUCommandQueue::retireCommandBuffer(IOGPUEventFence *) Deny submissions/ignore app[openglwindow] with 2 GPURestarts in 31 submissions. Execution of the command buffer was aborted due to an error during execution Caused GPU Timeout Error (00000002:kIOGPUCommandBufferCallbackErrorTimeout) GLDRendererMetal command buffer completion error Error Domain=MTLCommandBufferErrorDomain Code=2 Execution of the command buffer was aborted due to an error during execution Ignored (for causing prior/excessive GPU errors) Terminating due to blacklisting by kernel driver The back-trace always pointed to the display-link callback, so the assumption is that the crash was triggered by the app rendering when it shouldn't, during the split-view transition. Fixes: QTBUG-132314 Pick-to: 6.8 6.5 5.15 Change-Id: Idf1f692daa9d437ee69f9436706777b220fbfbf4 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io> (cherry picked from commit c812190a921660c748be3324c3a34245b24354e9) Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
4ed56eaafc
commit
1b993a787d
@ -180,6 +180,15 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
|
||||
m_displayLink.paused = YES; // Enabled when clients call QWindow::requestUpdate()
|
||||
[m_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
|
||||
// We're pausing the display link if the application moves out of the active state,
|
||||
// so make sure to deliver to any windows that need it once the app becomes active.
|
||||
QObject::connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, [this](auto newState) {
|
||||
if (newState == Qt::ApplicationActive) {
|
||||
qCDebug(lcQpaApplication) << "Attempting update request delivery after becoming active";
|
||||
deliverUpdateRequests();
|
||||
}
|
||||
});
|
||||
|
||||
#endif // !defined(Q_OS_VISIONOS))
|
||||
|
||||
updateProperties();
|
||||
@ -265,6 +274,17 @@ void QIOSScreen::deliverUpdateRequests() const
|
||||
{
|
||||
bool pauseUpdates = true;
|
||||
|
||||
if (QGuiApplication::applicationState() != Qt::ApplicationActive) {
|
||||
// The applicationWillResignActive documentation describes that the app
|
||||
// should "use this method to pause ongoing tasks, disable timers, and
|
||||
// throttle down OpenGL ES frame rates", so we skip update request
|
||||
// delivery if the app is not active. Once it becomes active again
|
||||
// we re-try the update request delivery (see QIOSScreen constructor).
|
||||
qCDebug(lcQpaApplication) << "Skipping update request delivery and pausing display link";
|
||||
m_displayLink.paused = true;
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QWindow*> windows = QGuiApplication::allWindows();
|
||||
for (int i = 0; i < windows.size(); ++i) {
|
||||
QWindow *window = windows.at(i);
|
||||
|
Loading…
x
Reference in New Issue
Block a user