From 867fc30c7c9be51b4b3813d2cc558b5a9df0256d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 23 Sep 2015 14:38:48 +0200 Subject: windows: Improve error handling with EGL When disabling the graphics adapter, things start failing with context lost and then bad_alloc and bad_access failures when creating contexts/window surfaces. Swap buffers now handles context loss. This makes it possible for Qt Quick to act when the graphics adapter goes away. Similarly, the window surface creation failure EGL_BAD_ACCESS is treated the same way as context loss. Note that this will not really help the main issue, because rendering is not possible without a GPU (reinit attempts will fail either at context creation or window surface creation), but proper logging and context loss reporting improves the situation somewhat. Also unify and prettyify the warning and debug prints. This makes it easier to understand what is going on. Change-Id: Iec3a9b54f1134e78e87eefcf938525283ec9412a Task-number: QTBUG-48095 Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowseglcontext.cpp | 43 ++++++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 06c9985cac..e4ec3f3cf8 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -350,16 +350,16 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: { const HDC dc = QWindowsContext::instance()->displayContext(); if (!dc){ - qWarning("%s: No Display", Q_FUNC_INFO); + qWarning("%s: No Display", __FUNCTION__); return 0; } if (!libEGL.init()) { - qWarning("%s: Failed to load and resolve libEGL functions", Q_FUNC_INFO); + qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__); return 0; } if (!libGLESv2.init()) { - qWarning("%s: Failed to load and resolve libGLESv2 functions", Q_FUNC_INFO); + qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__); return 0; } @@ -396,15 +396,15 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: if (display == EGL_NO_DISPLAY) display = libEGL.eglGetDisplay((EGLNativeDisplayType)dc); if (!display) { - qWarning("%s: Could not obtain EGL display", Q_FUNC_INFO); + qWarning("%s: Could not obtain EGL display", __FUNCTION__); return 0; } if (!major && !libEGL.eglInitialize(display, &major, &minor)) { int err = libEGL.eglGetError(); - qWarning("%s: Could not initialize EGL display: error 0x%x\n", Q_FUNC_INFO, err); + qWarning("%s: Could not initialize EGL display: error 0x%x", __FUNCTION__, err); if (err == 0x3001) - qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", Q_FUNC_INFO); + qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", __FUNCTION__); return 0; } @@ -430,7 +430,7 @@ void *QWindowsEGLStaticContext::createWindowSurface(void *nativeWindow, void *na (EGLNativeWindowType) nativeWindow, 0); if (surface == EGL_NO_SURFACE) { *err = libEGL.eglGetError(); - qWarning("%s: Could not create the EGL window surface: 0x%x\n", Q_FUNC_INFO, *err); + qWarning("%s: Could not create the EGL window surface: 0x%x", __FUNCTION__, *err); } return surface; @@ -533,7 +533,12 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, } if (m_eglContext == EGL_NO_CONTEXT) { - qWarning("QWindowsEGLContext: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + int err = QWindowsEGLStaticContext::libEGL.eglGetError(); + qWarning("QWindowsEGLContext: Failed to create context, eglError: %x, this: %p", err, this); + // ANGLE gives bad alloc when it fails to reset a previously lost D3D device. + // A common cause for this is disabling the graphics adapter used by the app. + if (err == EGL_BAD_ALLOC) + qWarning("QWindowsEGLContext: Graphics device lost. (Did the adapter get disabled?)"); return; } @@ -594,6 +599,12 @@ bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) if (err == EGL_CONTEXT_LOST) { m_eglContext = EGL_NO_CONTEXT; qCDebug(lcQpaGl) << "Got EGL context lost in createWindowSurface() for context" << this; + } else if (err == EGL_BAD_ACCESS) { + // With ANGLE this means no (D3D) device and can happen when disabling/changing graphics adapters. + qCDebug(lcQpaGl) << "Bad access (missing device?) in createWindowSurface() for context" << this; + // Simulate context loss as the context is useless. + QWindowsEGLStaticContext::libEGL.eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; } return false; } @@ -623,7 +634,7 @@ bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) // Drop the surface. Will recreate on the next makeCurrent. window->invalidateSurface(); } else { - qWarning("QWindowsEGLContext::makeCurrent: eglError: %x, this: %p \n", err, this); + qWarning("%s: Failed to make surface current. eglError: %x, this: %p", __FUNCTION__, err, this); } } @@ -635,7 +646,8 @@ void QWindowsEGLContext::doneCurrent() QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!ok) - qWarning("QWindowsEGLContext::doneCurrent: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + qWarning("%s: Failed to make no context/surface current. eglError: %d, this: %p", __FUNCTION__, + QWindowsEGLStaticContext::libEGL.eglGetError(), this); } void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) @@ -653,8 +665,15 @@ void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) } bool ok = QWindowsEGLStaticContext::libEGL.eglSwapBuffers(m_eglDisplay, eglSurface); - if (!ok) - qWarning("QWindowsEGLContext::swapBuffers: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + if (!ok) { + err = QWindowsEGLStaticContext::libEGL.eglGetError(); + if (err == EGL_CONTEXT_LOST) { + m_eglContext = EGL_NO_CONTEXT; + qCDebug(lcQpaGl) << "Got EGL context lost in eglSwapBuffers()"; + } else { + qWarning("%s: Failed to swap buffers. eglError: %d, this: %p", __FUNCTION__, err, this); + } + } } QFunctionPointer QWindowsEGLContext::getProcAddress(const QByteArray &procName) -- cgit v1.2.3