summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormread <qt-info@nokia.com>2012-01-09 15:04:18 +0000
committerPasi Pentikäinen <ext-pasi.a.pentikainen@nokia.com>2012-01-16 10:40:59 +0100
commit5a8d6d4598ca4b84b3b4f19554de7bb880cb7412 (patch)
tree9576fcea85141255ad10d442f7287ae05049d620
parent9c8f7acde756e11734109e3f8a4bfd7554b492c5 (diff)
downloadqt4-tools-5a8d6d4598ca4b84b3b4f19554de7bb880cb7412.tar.gz
Recovering from draw failures after EGL surface creation failure
The Qt drawing system is not designed to handle failures in beginPaint and endPaint. But the Symbian port is creating EGL contexts and surfaces on demand in these functions. These can fail, eg in the defect reported the app gets a visibile=true event for such a short period that it fails to create the surface before it is invisible again. These failures have to be coped with. Brush image drawing is failing if the app is asked to draw while in the background, because the EGL surface cannot be created. After this, if the app comes to the foreground at the wrong time, the failed drawing is shown on the screen as a flat colored area. A failedToAlloc variable in the openvg paint engine was locking in this failed drawing, so that it would never redraw. This is fixed by removing all use of that variable. Failed surface creation during a draw in response to a visibility change event was also leaving the window backing store with bad content. This is now cleared on a surface creation failure so that drawing is retried when the next visibility change event arrives. The retry mechanism for creating a surface on failure also makes the problem circumstances more likely to occur and can block the app unnecessarily. Now, instead of blocking for 1 second every time on failed surface creation, it only blocks on the first failure in a sequence thereby allowing other parts of the app to run freely while it is in the background. Task-number: ou1cimx1#951921 Change-Id: I1e27746957ff624b0d9a1cdc9b319d0a3477135d Reviewed-by: Gareth Stockwell <gareth.stockwell@accenture.com> Reviewed-by: Shane Kearns <ext-shane.2.kearns@nokia.com> (cherry picked from commit 854e72538426b32f72acd6c6c76af04bc8b78994) Reviewed-by: Juha Kukkonen Reviewed-by: Pasi Pentikäinen <ext-pasi.a.pentikainen@nokia.com>
-rw-r--r--src/gui/egl/qegl.cpp19
-rw-r--r--src/gui/kernel/qapplication_s60.cpp3
-rw-r--r--src/gui/kernel/qt_s60_p.h15
-rw-r--r--src/openvg/qpaintengine_vg.cpp16
-rw-r--r--src/openvg/qpixmapdata_vg.cpp4
-rw-r--r--src/openvg/qpixmapdata_vg_p.h1
6 files changed, 27 insertions, 31 deletions
diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp
index 6fe1c8c446..6e88ecafc7 100644
--- a/src/gui/egl/qegl.cpp
+++ b/src/gui/egl/qegl.cpp
@@ -48,6 +48,9 @@
#include "qegl_p.h"
#include "qeglcontext_p.h"
+#ifdef Q_OS_SYMBIAN
+#include "private/qt_s60_p.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -398,6 +401,9 @@ bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties
ctx = eglCreateContext(display(), cfg, EGL_NO_CONTEXT, contextProps.properties());
if (ctx == EGL_NO_CONTEXT) {
qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << QEgl::errorString();
+#ifdef Q_OS_SYMBIAN
+ S60->eglSurfaceCreationError = true;
+#endif
return false;
}
}
@@ -683,7 +689,7 @@ EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglPr
props = properties->properties();
else
props = 0;
- EGLSurface surf;
+ EGLSurface surf = EGL_NO_SURFACE;
#ifdef Q_OS_SYMBIAN
// On Symbian there might be situations (especially on 32MB GPU devices)
// where Qt is trying to create EGL surface while some other application
@@ -695,8 +701,11 @@ EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglPr
// alloc, let's try recreating it four times within ~1 second if needed.
// This strategy gives some time for video recorder to tear down its stack
// and a chance to Qt for creating a valid surface.
- int tries = 4;
- while(tries--) {
+ // If the surface is still failing however, we don't keep the app blocked.
+ static int tries = 4;
+ if (tries <= 0)
+ tries = 1;
+ while (tries-- > 0) {
if (devType == QInternal::Widget)
surf = eglCreateWindowSurface(QEgl::display(), cfg, windowDrawable, props);
else
@@ -704,13 +713,15 @@ EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglPr
if (surf == EGL_NO_SURFACE) {
EGLint error = eglGetError();
if (error == EGL_BAD_ALLOC) {
- if (tries) {
+ if (tries > 0) {
User::After(1000 * 250); // 250ms
continue;
}
}
qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", error);
+ S60->eglSurfaceCreationError = true;
} else {
+ tries = 4;
break;
}
}
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index 1518d2ddf4..3d901c4474 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -246,10 +246,13 @@ void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible)
if (backingStore.data()) {
backingStore.registerWidget(widget);
} else {
+ S60->eglSurfaceCreationError = false;
backingStore.create(window);
backingStore.registerWidget(widget);
qt_widget_private(widget)->invalidateBuffer(widget->rect());
widget->repaint();
+ if (S60->eglSurfaceCreationError)
+ backingStore.unregisterWidget(widget);
}
} else {
QApplicationPrivate *d = QApplicationPrivate::instance();
diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h
index c75b20e8cc..8c2728a0db 100644
--- a/src/gui/kernel/qt_s60_p.h
+++ b/src/gui/kernel/qt_s60_p.h
@@ -168,6 +168,9 @@ public:
int partialKeyboardOpen : 1;
int handleStatusPaneResizeNotifications : 1;
int screenFurnitureFullyCreated : 1;
+ int beginFullScreenCalled : 1;
+ int endFullScreenCalled : 1;
+ int eglSurfaceCreationError : 1;
QApplication::QS60MainApplicationFactory s60ApplicationFactory; // typedef'ed pointer type
QPointer<QWidget> splitViewLastWidget;
@@ -208,9 +211,7 @@ public:
static void controlVisibilityChanged(CCoeControl *control, bool visible);
static TRect clientRect();
-#ifdef Q_OS_SYMBIAN
TTrapHandler *s60InstalledTrapHandler;
-#endif
int screenWidthInPixelsForScreen[qt_symbian_max_screens];
int screenHeightInPixelsForScreen[qt_symbian_max_screens];
@@ -228,8 +229,6 @@ public:
};
ScreenRotation screenRotation;
- int beginFullScreenCalled : 1;
- int endFullScreenCalled : 1;
int editorFlags;
};
@@ -386,12 +385,10 @@ inline QS60Data::QS60Data()
partialKeyboardOpen(0),
handleStatusPaneResizeNotifications(1),
screenFurnitureFullyCreated(0),
- s60ApplicationFactory(0)
-#ifdef Q_OS_SYMBIAN
- ,s60InstalledTrapHandler(0)
-#endif
- ,beginFullScreenCalled(0),
+ beginFullScreenCalled(0),
endFullScreenCalled(0),
+ s60ApplicationFactory(0),
+ s60InstalledTrapHandler(0),
editorFlags(0)
{
}
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp
index de8ea88e3c..23eb01cde3 100644
--- a/src/openvg/qpaintengine_vg.cpp
+++ b/src/openvg/qpaintengine_vg.cpp
@@ -3343,15 +3343,9 @@ void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF
else
drawVGImage(d, r, vgpd->toVGImage(d->opacity), vgpd->size(), sr);
- if(!vgpd->failedToAlloc)
+ if (vgpd->vgImage != VG_INVALID_HANDLE)
return;
- // try to reallocate next time if reasonable small pixmap
- QSize screenSize = QApplication::desktop()->screenGeometry().size();
- if (pm.size().width() <= screenSize.width()
- && pm.size().height() <= screenSize.height())
- vgpd->failedToAlloc = false;
-
vgpd->source.beginDataAccess();
drawImage(r, vgpd->source.imageRef(), sr, Qt::AutoColor);
vgpd->source.endDataAccess(true);
@@ -3375,15 +3369,9 @@ void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
else
drawVGImage(d, pos, vgpd->toVGImage(d->opacity));
- if (!vgpd->failedToAlloc)
+ if (vgpd->vgImage != VG_INVALID_HANDLE)
return;
- // try to reallocate next time if reasonable small pixmap
- QSize screenSize = QApplication::desktop()->screenGeometry().size();
- if (pm.size().width() <= screenSize.width()
- && pm.size().height() <= screenSize.height())
- vgpd->failedToAlloc = false;
-
vgpd->source.beginDataAccess();
drawImage(pos, vgpd->source.imageRef());
vgpd->source.endDataAccess(true);
diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp
index 597f3fa47b..895c694287 100644
--- a/src/openvg/qpixmapdata_vg.cpp
+++ b/src/openvg/qpixmapdata_vg.cpp
@@ -67,7 +67,6 @@ QVGPixmapData::QVGPixmapData(PixelType type)
recreate = true;
inImagePool = false;
inLRU = false;
- failedToAlloc = false;
#if defined(Q_OS_SYMBIAN)
nativeImageHandleProvider = 0;
nativeImageHandle = 0;
@@ -344,7 +343,7 @@ QPaintEngine* QVGPixmapData::paintEngine() const
VGImage QVGPixmapData::toVGImage()
{
- if (!isValid() || failedToAlloc)
+ if (!isValid())
return VG_INVALID_HANDLE;
#if !defined(QT_NO_EGL)
@@ -370,7 +369,6 @@ VGImage QVGPixmapData::toVGImage()
// Bail out if we run out of GPU memory - try again next time.
if (vgImage == VG_INVALID_HANDLE) {
- failedToAlloc = true;
return VG_INVALID_HANDLE;
}
diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h
index 4a969c0e46..8acff7e76a 100644
--- a/src/openvg/qpixmapdata_vg_p.h
+++ b/src/openvg/qpixmapdata_vg_p.h
@@ -158,7 +158,6 @@ private:
QVGPixmapData *nextLRU;
QVGPixmapData *prevLRU;
bool inLRU;
- bool failedToAlloc;
friend class QVGImagePool;
friend class QVGPaintEngine;