diff options
author | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2014-03-10 10:53:49 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-13 13:39:54 +0100 |
commit | b8afc009afcca84a3fd3d5617dfe96c729c531aa (patch) | |
tree | 10bdbfb63b3aee36da0344cd8f05184b06b47f37 /src | |
parent | d6e932b3682c7f8cd610d7554a52c9856d7e67c1 (diff) |
Consolidate context creation failure handling in Quick.
Add QQuickWidget::sceneGraphError() equivalent to
QQuickWindow::sceneGraphError(), move message formatting code
to QQuickWindowPrivate.
Change-Id: I18cd4d7e0f6ee1011c29375218dc6a044b0d2cf2
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 31 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 5 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgrenderloop.cpp | 43 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgrenderloop_p.h | 3 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgthreadedrenderloop.cpp | 13 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgwindowsrenderloop.cpp | 29 | ||||
-rw-r--r-- | src/quickwidgets/qquickwidget.cpp | 45 | ||||
-rw-r--r-- | src/quickwidgets/qquickwidget.h | 1 | ||||
-rw-r--r-- | src/quickwidgets/qquickwidget_p.h | 1 |
9 files changed, 122 insertions, 49 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index d7a6f071c6..6a56a5dc82 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -65,6 +65,7 @@ #include <QtGui/qstylehints.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qabstractanimation.h> +#include <QtCore/QLibraryInfo> #include <QtQml/qqmlincubator.h> #include <QtQuick/private/qquickpixmapcache_p.h> @@ -2303,6 +2304,36 @@ bool QQuickWindowPrivate::isRenderable() const return ((q->isExposed() && q->isVisible())) && q->geometry().isValid(); } +void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &format, + QString *translatedMessage, + QString *untranslatedMessage, + bool isEs) +{ + const QString contextType = QLatin1String(isEs ? "EGL" : "OpenGL"); + QString formatStr; + QDebug(&formatStr) << format; +#if defined(Q_OS_WIN32) + const bool isDebug = QLibraryInfo::isDebugBuild(); + const QString eglLibName = QLatin1String(isDebug ? "libEGLd.dll" : "libEGL.dll"); + const QString glesLibName = QLatin1String(isDebug ? "libGLESv2d.dll" : "libGLESv2.dll"); + //: %1 Context type (Open GL, EGL), ANGLE %2, %3 library names + const char msg[] = QT_TRANSLATE_NOOP("QQuickWindow", + "Failed to create %1 context for format %2." + "This is most likely caused by not having the necessary graphics drivers installed.\n\n" + "Install a driver providing OpenGL 2.0 or higher, or, if this is not possible, " + "make sure the ANGLE Open GL ES 2.0 emulation libraries (%3, %4 and d3dcompiler_*.dll) " + "are available in the application executable's directory or in a location listed in PATH."); + *translatedMessage = QQuickWindow::tr(msg).arg(contextType, formatStr, eglLibName, glesLibName); + *untranslatedMessage = QString::fromLatin1(msg).arg(contextType, formatStr, eglLibName, glesLibName); +#else // Q_OS_WIN32 + //: %1 Context type (Open GL, EGL), %2 format specification + const char msg[] = QT_TRANSLATE_NOOP("QQuickWindow", + "Failed to create %1 context for format %2"); + *translatedMessage = QQuickWindow::tr(msg).arg(contextType, formatStr); + *untranslatedMessage = QString::fromLatin1(msg).arg(contextType, formatStr); +#endif // !Q_OS_WIN32 +} + /*! Propagates an event \a e to a QQuickItem \a item on the window. diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index e78f00c22f..421651b483 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -242,6 +242,11 @@ public: static QObject *data_at(QQmlListProperty<QObject> *, int); static void data_clear(QQmlListProperty<QObject> *); + static void contextCreationFailureMessage(const QSurfaceFormat &format, + QString *translatedMessage, + QString *untranslatedMessage, + bool isEs); + private: static void cleanupNodesOnShutdown(QQuickItem *); }; diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 644a674749..6647ec83d0 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -46,6 +46,7 @@ #include <QtCore/QCoreApplication> #include <QtCore/QTime> #include <QtCore/QScopedPointer> +#include <QtCore/QLibraryInfo> #include <QtCore/private/qabstractanimation_p.h> #include <QtGui/QOpenGLContext> @@ -59,6 +60,10 @@ #include <QtQuick/private/qsgcontext_p.h> #include <private/qquickprofiler_p.h> +#ifdef Q_OS_WIN +# include <QtCore/qt_windows.h> +#endif + QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qsg_render_timing, QSG_RENDER_TIMING) @@ -208,6 +213,32 @@ void QSGRenderLoop::setInstance(QSGRenderLoop *instance) s_renderLoopInstance->reset(instance); } +void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window, + bool isEs) +{ + QString translatedMessage; + QString untranslatedMessage; + QQuickWindowPrivate::contextCreationFailureMessage(window->requestedFormat(), + &translatedMessage, + &untranslatedMessage, + isEs); + // If there is a slot connected to the error signal, emit it and leave it to + // the application to do something with the message. If nothing is connected, + // show a message on our own and terminate. + const bool signalEmitted = + QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable, + translatedMessage); +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) + if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) { + MessageBox(0, (LPCTSTR) translatedMessage.utf16(), + (LPCTSTR)(QCoreApplication::applicationName().utf16()), + MB_OK | MB_ICONERROR); + } +#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT + if (!signalEmitted) + qFatal("%s", qPrintable(untranslatedMessage)); +} + QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop() : gl(0) , eventPending(false) @@ -283,18 +314,10 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) if (QSGContext::sharedOpenGLContext()) gl->setShareContext(QSGContext::sharedOpenGLContext()); if (!gl->create()) { + const bool isEs = gl->isES(); delete gl; gl = 0; - QString formatStr; - QDebug(&formatStr) << window->requestedFormat(); - QString contextType = QLatin1String("OpenGL"); - const char *msg = QT_TRANSLATE_NOOP("QSGGuiThreadRenderLoop", "Failed to create %1 context for format %2"); - QString translatedMsg = tr(msg).arg(contextType).arg(formatStr); - QString nonTranslatedMsg = QString(QLatin1String(msg)).arg(contextType).arg(formatStr); - bool signalEmitted = QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable, - translatedMsg); - if (!signalEmitted) - qFatal("%s", qPrintable(nonTranslatedMsg)); + handleContextCreationFailure(window, isEs); } else { cd->fireOpenGLContextCreated(gl); current = gl->makeCurrent(window); diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 46edd77eda..2418af4157 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -88,6 +88,9 @@ public: Q_SIGNALS: void timeToIncubate(); + +protected: + void handleContextCreationFailure(QQuickWindow *window, bool isEs); }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index f639841588..ba8c3a7fce 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -946,19 +946,10 @@ void QSGThreadedRenderLoop::handleExposure(Window *w) w->thread->gl->setShareContext(QSGContext::sharedOpenGLContext()); w->thread->gl->setFormat(w->window->requestedFormat()); if (!w->thread->gl->create()) { + const bool isEs = w->thread->gl->isES(); delete w->thread->gl; w->thread->gl = 0; - QString formatStr; - QDebug(&formatStr) << w->window->requestedFormat(); - QString contextType = QLatin1String("OpenGL"); - const char *msg = QT_TRANSLATE_NOOP("QSGThreadedRenderLoop", - "Failed to create %1 context for format %2"); - QString translatedMsg = tr(msg).arg(contextType).arg(formatStr); - QString nonTranslatedMsg = QString(QLatin1String(msg)).arg(contextType).arg(formatStr); - bool signalEmitted = QQuickWindowPrivate::get(w->window)->emitError(QQuickWindow::ContextNotAvailable, - translatedMsg); - if (!signalEmitted) - qFatal("%s", qPrintable(nonTranslatedMsg)); + handleContextCreationFailure(w->window, isEs); return; } diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 31012c7589..913b737798 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -183,35 +183,10 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window) m_gl->setShareContext(QSGContext::sharedOpenGLContext()); bool created = m_gl->create(); if (!created) { - const bool isDebug = QLibraryInfo::isDebugBuild(); - QString eglLibName = QLatin1String(isDebug ? "libEGLd.dll" : "libEGL.dll"); - QString glesLibName = QLatin1String(isDebug ? "libGLESv2d.dll" : "libGLESv2.dll"); - QString contextType = QLatin1String("OpenGL"); - const char *msg = QT_TRANSLATE_NOOP( - "QSGWindowsRenderLoop", - "Failed to create %1 context. " - "This is most likely caused by not having the necessary graphics drivers installed.\n\n" - "Install a driver providing OpenGL 2.0 or higher, or, if this is not possible, " - "make sure the Angle Open GL ES 2.0 emulation libraries (%2, %3 and d3dcompiler_*.dll) " - "are available in the application executable's directory or in a location listed in PATH."); - QString translatedMsg = tr(msg).arg(contextType).arg(eglLibName).arg(glesLibName); - QString nonTranslatedMsg = QString(QLatin1String(msg)).arg(contextType).arg(eglLibName).arg(glesLibName); - // If there is a slot connected to the error signal, emit it and leave it to - // the application to do something with the message. If nothing is connected, - // show a message on our own and terminate. - bool signalEmitted = QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable, - translatedMsg); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) - if (!signalEmitted && !isDebug && !GetConsoleWindow()) { - MessageBox(0, (LPCTSTR) translatedMsg.utf16(), - (LPCTSTR)(QCoreApplication::applicationName().utf16()), - MB_OK | MB_ICONERROR); - } -#endif // !Q_OS_WINCE && !Q_OS_WINRT + const bool isEs = m_gl->isES(); delete m_gl; m_gl = 0; - if (!signalEmitted) - qFatal("%s", qPrintable(nonTranslatedMsg)); + handleContextCreationFailure(window, isEs); return; } diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index dbc7d6c21a..46db2ddfeb 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -56,6 +56,12 @@ #include <QtCore/qbasictimer.h> #include <QtGui/QOffscreenSurface> +#ifdef Q_OS_WIN +# include <QtWidgets/QMessageBox> +# include <QtCore/QLibraryInfo> +# include <QtCore/qt_windows.h> +#endif + QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); @@ -387,6 +393,21 @@ QQmlContext* QQuickWidget::rootContext() const */ /*! + \fn void QQuickWidget::sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message) + + This signal is emitted when an error occurred during scene graph initialization. + + Applications should connect to this signal if they wish to handle errors, + like OpenGL context creation failures, in a custom way. When no slot is + connected to the signal, the behavior will be different: Quick will print + the message, or show a message box, and terminate the application. + + This signal will be emitted from the gui thread. + + \sa QQuickWindow::sceneGraphError() + */ + +/*! \property QQuickWidget::status The component's current \l{QQuickWidget::Status} {status}. */ @@ -510,6 +531,27 @@ QSize QQuickWidgetPrivate::rootObjectSize() const return rootObjectSize; } +void QQuickWidgetPrivate::handleContextCreationFailure(const QSurfaceFormat &format, bool isEs) +{ + Q_Q(QQuickWidget); + + QString translatedMessage; + QString untranslatedMessage; + QQuickWindowPrivate::contextCreationFailureMessage(format, &translatedMessage, &untranslatedMessage, isEs); + + static const QMetaMethod errorSignal = QMetaMethod::fromSignal(&QQuickWidget::sceneGraphError); + const bool signalConnected = q->isSignalConnected(errorSignal); + if (signalConnected) + emit q->sceneGraphError(QQuickWindow::ContextNotAvailable, translatedMessage); + +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) + if (!signalConnected && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) + QMessageBox::critical(q, QCoreApplication::applicationName(), translatedMessage); +#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT + if (!signalConnected) + qFatal("%s", qPrintable(untranslatedMessage)); +} + void QQuickWidgetPrivate::createContext() { if (context) @@ -521,9 +563,10 @@ void QQuickWidgetPrivate::createContext() if (QSGContext::sharedOpenGLContext()) context->setShareContext(QSGContext::sharedOpenGLContext()); // ??? is this correct if (!context->create()) { - qWarning("QQuickWidget: failed to create OpenGL context"); + const bool isEs = context->isES(); delete context; context = 0; + handleContextCreationFailure(offscreenWindow->requestedFormat(), isEs); return; } diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h index 614d5b82a6..2c021c85fb 100644 --- a/src/quickwidgets/qquickwidget.h +++ b/src/quickwidgets/qquickwidget.h @@ -95,6 +95,7 @@ public Q_SLOTS: Q_SIGNALS: void statusChanged(QQuickWidget::Status); + void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message); private Q_SLOTS: void continueExecute(); diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index 2d2d6500b2..1ba06162f9 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -86,6 +86,7 @@ public: void renderSceneGraph(); void createContext(); void destroyContext(); + void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs); GLuint textureId() const Q_DECL_OVERRIDE; |