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(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()