summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/opengl/qopenglpaintdevice.cpp27
-rw-r--r--src/gui/opengl/qopenglpaintdevice.h2
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp4
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp70
-rw-r--r--src/widgets/kernel/qwidget_p.h2
-rw-r--r--src/widgets/widgets/qabstractscrollarea.cpp3
6 files changed, 103 insertions, 5 deletions
diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp
index 59bca6efdf..c2f3295bc3 100644
--- a/src/gui/opengl/qopenglpaintdevice.cpp
+++ b/src/gui/opengl/qopenglpaintdevice.cpp
@@ -351,14 +351,39 @@ bool QOpenGLPaintDevice::paintFlipped() const
}
/*!
+ This virtual method is called when starting to paint.
+
+ The default implementation does nothing.
+
+ \sa endPaint()
+ */
+void QOpenGLPaintDevice::beginPaint()
+{
+}
+
+/*!
This virtual method is provided as a callback to allow re-binding a target
frame buffer object or context when different QOpenGLPaintDevice instances
are issuing draw calls alternately.
- QPainter::beginNativePainting will also trigger this method.
+ \l{QPainter::beginNativePainting()}{beginNativePainting()} will also trigger
+ this method.
+
+ The default implementation does nothing.
*/
void QOpenGLPaintDevice::ensureActiveTarget()
{
}
+/*!
+ This virtual method is called when the painting has finished.
+
+ The default implementation does nothing.
+
+ \sa beginPaint()
+*/
+void QOpenGLPaintDevice::endPaint()
+{
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglpaintdevice.h b/src/gui/opengl/qopenglpaintdevice.h
index e1be9b525d..d88992d6db 100644
--- a/src/gui/opengl/qopenglpaintdevice.h
+++ b/src/gui/opengl/qopenglpaintdevice.h
@@ -73,7 +73,9 @@ public:
void setPaintFlipped(bool flipped);
bool paintFlipped() const;
+ virtual void beginPaint();
virtual void ensureActiveTarget();
+ virtual void endPaint();
protected:
int metric(QPaintDevice::PaintDeviceMetric metric) const;
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index 21bc4a95e8..40c836b2bb 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -1994,6 +1994,8 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->ctx = QOpenGLContext::currentContext();
d->ctx->d_func()->active_engine = this;
+ d->device->beginPaint();
+
d->funcs.initializeOpenGLFunctions();
for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
@@ -2044,6 +2046,8 @@ bool QOpenGL2PaintEngineEx::end()
{
Q_D(QOpenGL2PaintEngineEx);
+ d->device->endPaint();
+
QOpenGLContext *ctx = d->ctx;
d->funcs.glUseProgram(0);
d->transferMode(BrushDrawingMode);
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
index 7782c4c1d4..dd8dd64470 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<QOpenGLWidgetPrivate *>(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();
}
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index e80447c477..bbdbabc14b 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -641,6 +641,8 @@ public:
}
}
static void sendComposeStatus(QWidget *w, bool end);
+ // Called on setViewport().
+ virtual void initializeViewportFramebuffer() { }
// When using a QOpenGLWidget as viewport with QAbstractScrollArea, resize events are
// filtered away from the widget. This is fine for QGLWidget but bad for QOpenGLWidget
// since the fbo must be resized. We need an alternative way to notify.
diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp
index 3b75591998..4cafeafcec 100644
--- a/src/widgets/widgets/qabstractscrollarea.cpp
+++ b/src/widgets/widgets/qabstractscrollarea.cpp
@@ -609,6 +609,9 @@ void QAbstractScrollArea::setViewport(QWidget *widget)
#endif
#endif
d->layoutChildren();
+#ifndef QT_NO_OPENGL
+ QWidgetPrivate::get(d->viewport)->initializeViewportFramebuffer();
+#endif
if (isVisible())
d->viewport->show();
setupViewport(widget);