diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2015-03-19 14:49:54 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2015-03-23 09:26:42 +0000 |
commit | cafd54d34b0e4e0fb9d99650c7c6ffd1969811a1 (patch) | |
tree | 116c309bfcd0ab6c2b54730fc5fd90e24a992adf | |
parent | 09f631d78710420d25fa0765772bef3ef37e78cb (diff) |
Use glFinish() in QOpenGLWidget unless glFlush() is known to be enough
The driver used on the Odroid-XU3 does not like doing just glFlush()
before accessing the texture in another context. There is no guarantee
that glFlush() is enough to sync access to resources between contexts, so
start using glFinish() as the default, except on common desktop hw + iOS
where flush is enough and presumably more efficient.
To unify the code pathes, remove the separate flushes and do it only
once, before the backingstore compositor indicates that it is about to
access the textures. This should improve performance a bit, esp. when
doing multisampling since we flush only once then.
A helper function is added to the internal QOpenGLExtensions because
it is highly likely that QQuickWidget will need the same.
Task-number: QTBUG-45106
Change-Id: Ifb405c5723f29f2f6c04df8e15fb70280681755e
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-rw-r--r-- | src/gui/opengl/qopenglextensions_p.h | 5 | ||||
-rw-r--r-- | src/gui/opengl/qopenglfunctions.cpp | 32 | ||||
-rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 6 |
3 files changed, 39 insertions, 4 deletions
diff --git a/src/gui/opengl/qopenglextensions_p.h b/src/gui/opengl/qopenglextensions_p.h index aa2f784d86..ff5d79566c 100644 --- a/src/gui/opengl/qopenglextensions_p.h +++ b/src/gui/opengl/qopenglextensions_p.h @@ -135,6 +135,8 @@ public: QOpenGLES3Helper *gles3Helper(); + void flushShared(); + private: static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; } }; @@ -158,6 +160,9 @@ public: GLsizei width, GLsizei height); void (QOPENGLF_APIENTRYP GetBufferSubData)(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, GLvoid *data); void (QOPENGLF_APIENTRYP DiscardFramebuffer)(GLenum target, GLsizei numAttachments, const GLenum *attachments); + + bool flushVendorChecked; + bool flushIsSufficientToSyncContexts; }; inline GLvoid *QOpenGLExtensions::glMapBuffer(GLenum target, GLenum access) diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index 587995515d..c60532b90b 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -3538,7 +3538,8 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *) } QOpenGLExtensionsPrivate::QOpenGLExtensionsPrivate(QOpenGLContext *ctx) - : QOpenGLFunctionsPrivate(ctx) + : QOpenGLFunctionsPrivate(ctx), + flushVendorChecked(false) { MapBuffer = qopenglfResolveMapBuffer; MapBufferRange = qopenglfResolveMapBufferRange; @@ -3554,4 +3555,33 @@ QOpenGLES3Helper *QOpenGLExtensions::gles3Helper() return qgles3Helper(); } +void QOpenGLExtensions::flushShared() +{ + Q_D(QOpenGLExtensions); + + if (!d->flushVendorChecked) { + d->flushVendorChecked = true; + // It is not quite clear if glFlush() is sufficient to synchronize access to + // resources between sharing contexts in the same thread. On most platforms this + // is enough (e.g. iOS explicitly documents it), while certain drivers only work + // properly when doing glFinish(). + d->flushIsSufficientToSyncContexts = false; // default to false, not guaranteed by the spec + const char *vendor = (const char *) glGetString(GL_VENDOR); + if (vendor) { + static const char *flushEnough[] = { "Apple", "ATI", "Intel", "NVIDIA" }; + for (size_t i = 0; i < sizeof(flushEnough) / sizeof(const char *); ++i) { + if (strstr(vendor, flushEnough[i])) { + d->flushIsSufficientToSyncContexts = true; + break; + } + } + } + } + + if (d->flushIsSufficientToSyncContexts) + glFlush(); + else + glFinish(); +} + QT_END_NAMESPACE diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 3b33894627..8faa9f8681 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -691,7 +691,7 @@ void QOpenGLWidgetPrivate::beginCompose() if (flushPending) { flushPending = false; q->makeCurrent(); - context->functions()->glFlush(); + static_cast<QOpenGLExtensions *>(context->functions())->flushShared(); } hasBeenComposed = true; emit q->aboutToCompose(); @@ -768,7 +768,7 @@ void QOpenGLWidgetPrivate::resolveSamples() q->makeCurrent(); QRect rect(QPoint(0, 0), fbo->size()); QOpenGLFramebufferObject::blitFramebuffer(resolvedFbo, rect, fbo, rect); - QOpenGLContext::currentContext()->functions()->glFlush(); + flushPending = true; } } @@ -779,7 +779,7 @@ void QOpenGLWidgetPrivate::invokeUserPaint() f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio()); q->paintGL(); - f->glFlush(); + flushPending = true; } void QOpenGLWidgetPrivate::render() |