From 26c104d120aff93f9da24dfeba3b64864d9f6a37 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 9 Oct 2014 16:38:38 +0200 Subject: Add a warning when using QOpenGLWidget as a native child Just like it is done for QQuickWidget. Task-number: QTBUG-41779 Change-Id: I1b27c2ed34ecb2520edf82843b675dbf6b0eab8e Reviewed-by: Michael Bruning Reviewed-by: Paul Olav Tvete --- src/widgets/kernel/qopenglwidget.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/widgets/kernel/qopenglwidget.cpp') diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 543f59d7d1b..7782c4c1d42 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -506,6 +506,12 @@ void QOpenGLWidgetPaintDevice::ensureActiveTarget() GLuint QOpenGLWidgetPrivate::textureId() const { + Q_Q(const QOpenGLWidget); + if (!q->isWindow() && q->internalWinId()) { + qWarning() << "QOpenGLWidget cannot be used as a native child widget." + << "Consider setting Qt::AA_DontCreateNativeWidgetAncestors and Siblings."; + return 0; + } return resolvedFbo ? resolvedFbo->texture() : (fbo ? fbo->texture() : 0); } -- cgit v1.2.3 From ebc835c2aa02f0b3dc6e4806bde03f33513d3556 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 14 Oct 2014 12:07:41 +0200 Subject: Fix QOpenGLWidget on Cocoa when used as viewport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having a QOpenGLWidget as a graphics view viewport was not functioning on OS X: it was showing incomplete content due to accessing the texture attached to the framebuffer object before the rendering is complete. On the normal path, when rendering is done via paintGL(), the flush was there. When used as a viewport however, this path is not used. The missing flush is now added for the other case too. For performance reasons, we will not flush on every paint engine end(). Instead, the flush is deferred until composition starts. QGLWidget also featured a weird on-by-default autoFillBackground concept. To maintain compatibility with apps that used QGLWidget as the viewport for QGraphicsView, we will now do the same for QOpenGLWidget, but only when it is used as a viewport. For regular QOpenGLWidgets autoFillBackground defaults to false, like for any other widget. The docs are extended with a small section about differences between QGLWidget and QOpenGLWidget. Task-number: QTBUG-41046 Change-Id: I42c2033fdd2ef5815783fd640fe11373761061e0 Reviewed-by: Jørgen Lind --- src/widgets/kernel/qopenglwidget.cpp | 70 +++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 4 deletions(-) (limited to 'src/widgets/kernel/qopenglwidget.cpp') diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 7782c4c1d42..dd8dd644704 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -239,6 +239,28 @@ QT_BEGIN_NAMESPACE \note Avoid calling winId() on a QOpenGLWidget. This function triggers the creation of a native window, resulting in reduced performance and possibly rendering glitches. + \section1 Differences to QGLWidget + + Besides the main conceptual difference of being backed by a framebuffer object, there + are a number of smaller, internal differences between QOpenGLWidget and the older + QGLWidget: + + \list + + \li OpenGL state when invoking paintGL(). QOpenGLWidget sets up the viewport via + glViewport(). It does not perform any clearing. + + \li Clearing when starting to paint via QPainter. Unlike regular widgets, QGLWidget + defaulted to a value of \c true for + \l{QWidget::autoFillBackground()}{autoFillBackground}. It then performed clearing to the + palette's background color every time QPainter::begin() was used. QOpenGLWidget does not + follow this: \l{QWidget::autoFillBackground()}{autoFillBackground} defaults to false, + like for any other widget. The only exception is when being used as a viewport for other + widgets like QGraphicsView. In such a case autoFillBackground will be automatically set + to true to ensure compatibility with QGLWidget-based viewports. + + \endlist + \section1 Multisampling To enable multisampling, set the number of requested samples on the @@ -436,6 +458,7 @@ class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice { public: QOpenGLWidgetPaintDevice(QOpenGLWidget *widget) : w(widget) { } + void beginPaint() Q_DECL_OVERRIDE; void ensureActiveTarget() Q_DECL_OVERRIDE; private: @@ -454,7 +477,8 @@ public: initialized(false), fakeHidden(false), paintDevice(0), - inBackingStorePaint(false) + inBackingStorePaint(false), + flushPending(false) { requestedFormat = QSurfaceFormat::defaultFormat(); } @@ -478,6 +502,7 @@ public: void endBackingStorePainting() Q_DECL_OVERRIDE { inBackingStorePaint = false; } void beginCompose() Q_DECL_OVERRIDE; void endCompose() Q_DECL_OVERRIDE; + void initializeViewportFramebuffer() Q_DECL_OVERRIDE; void resizeViewportFramebuffer() Q_DECL_OVERRIDE; void resolveSamples() Q_DECL_OVERRIDE; @@ -490,8 +515,28 @@ public: QOpenGLPaintDevice *paintDevice; bool inBackingStorePaint; QSurfaceFormat requestedFormat; + bool flushPending; }; +void QOpenGLWidgetPaintDevice::beginPaint() +{ + // NB! autoFillBackground is and must be false by default. Otherwise we would clear on + // every QPainter begin() which is not desirable. This is only for legacy use cases, + // like using QOpenGLWidget as the viewport of a graphics view, that expect clearing + // with the palette's background color. + if (w->autoFillBackground()) { + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + if (w->testAttribute(Qt::WA_TranslucentBackground)) { + f->glClearColor(0, 0, 0, 0); + } else { + QColor c = w->palette().brush(w->backgroundRole()).color(); + float alpha = c.alphaF(); + f->glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + } + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } +} + void QOpenGLWidgetPaintDevice::ensureActiveTarget() { QOpenGLWidgetPrivate *d = static_cast(QWidgetPrivate::get(w)); @@ -502,6 +547,11 @@ void QOpenGLWidgetPaintDevice::ensureActiveTarget() w->makeCurrent(); else d->fbo->bind(); + + // When used as a viewport, drawing is done via opening a QPainter on the widget + // without going through paintEvent(). We will have to make sure a glFlush() is done + // before the texture is accessed also in this case. + d->flushPending = true; } GLuint QOpenGLWidgetPrivate::textureId() const @@ -572,6 +622,11 @@ void QOpenGLWidgetPrivate::recreateFbo() void QOpenGLWidgetPrivate::beginCompose() { Q_Q(QOpenGLWidget); + if (flushPending) { + flushPending = false; + q->makeCurrent(); + context->functions()->glFlush(); + } emit q->aboutToCompose(); } @@ -653,9 +708,10 @@ void QOpenGLWidgetPrivate::invokeUserPaint() { Q_Q(QOpenGLWidget); QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio()); + f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio()); q->paintGL(); + f->glFlush(); } void QOpenGLWidgetPrivate::render() @@ -667,7 +723,6 @@ void QOpenGLWidgetPrivate::render() q->makeCurrent(); invokeUserPaint(); - context->functions()->glFlush(); } extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); @@ -686,6 +741,14 @@ QImage QOpenGLWidgetPrivate::grabFramebuffer() return res; } +void QOpenGLWidgetPrivate::initializeViewportFramebuffer() +{ + Q_Q(QOpenGLWidget); + // Legacy behavior for compatibility with QGLWidget when used as a graphics view + // viewport: enable clearing on each painter begin. + q->setAutoFillBackground(true); +} + void QOpenGLWidgetPrivate::resizeViewportFramebuffer() { Q_Q(QOpenGLWidget); @@ -929,7 +992,6 @@ void QOpenGLWidget::resizeEvent(QResizeEvent *e) d->recreateFbo(); resizeGL(width(), height()); d->invokeUserPaint(); - d->context->functions()->glFlush(); d->resolveSamples(); } -- cgit v1.2.3 From 6d1c4c8862161fd4aaffe307c7267ceeb408d8d8 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 14 Oct 2014 12:07:41 +0200 Subject: Avoid breaking BC with new virtuals in QOpenGLPaintDevice Task-number: QTBUG-41046 Change-Id: Iab628d2d6811d528e2cc513b6f8a74baa628541d Reviewed-by: Gunnar Sletta --- src/widgets/kernel/qopenglwidget.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'src/widgets/kernel/qopenglwidget.cpp') diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index dd8dd644704..8a4e0c8ffdd 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -454,17 +455,26 @@ QT_BEGIN_NAMESPACE due to resizing the widget. */ -class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice +class QOpenGLWidgetPaintDevicePrivate : public QOpenGLPaintDevicePrivate { public: - QOpenGLWidgetPaintDevice(QOpenGLWidget *widget) : w(widget) { } + QOpenGLWidgetPaintDevicePrivate(QOpenGLWidget *widget) + : QOpenGLPaintDevicePrivate(QSize()), + w(widget) { } + void beginPaint() Q_DECL_OVERRIDE; - void ensureActiveTarget() Q_DECL_OVERRIDE; -private: QOpenGLWidget *w; }; +class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice +{ +public: + QOpenGLWidgetPaintDevice(QOpenGLWidget *widget) + : QOpenGLPaintDevice(new QOpenGLWidgetPaintDevicePrivate(widget)) { } + void ensureActiveTarget() Q_DECL_OVERRIDE; +}; + class QOpenGLWidgetPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QOpenGLWidget) @@ -518,7 +528,7 @@ public: bool flushPending; }; -void QOpenGLWidgetPaintDevice::beginPaint() +void QOpenGLWidgetPaintDevicePrivate::beginPaint() { // NB! autoFillBackground is and must be false by default. Otherwise we would clear on // every QPainter begin() which is not desirable. This is only for legacy use cases, @@ -539,19 +549,20 @@ void QOpenGLWidgetPaintDevice::beginPaint() void QOpenGLWidgetPaintDevice::ensureActiveTarget() { - QOpenGLWidgetPrivate *d = static_cast(QWidgetPrivate::get(w)); - if (!d->initialized) + QOpenGLWidgetPaintDevicePrivate *d = static_cast(d_ptr.data()); + QOpenGLWidgetPrivate *wd = static_cast(QWidgetPrivate::get(d->w)); + if (!wd->initialized) return; - if (QOpenGLContext::currentContext() != d->context) - w->makeCurrent(); + if (QOpenGLContext::currentContext() != wd->context) + d->w->makeCurrent(); else - d->fbo->bind(); + wd->fbo->bind(); // When used as a viewport, drawing is done via opening a QPainter on the widget // without going through paintEvent(). We will have to make sure a glFlush() is done // before the texture is accessed also in this case. - d->flushPending = true; + wd->flushPending = true; } GLuint QOpenGLWidgetPrivate::textureId() const -- cgit v1.2.3