diff options
author | Jørgen Lind <jorgen.lind@digia.com> | 2014-09-08 13:50:26 +0200 |
---|---|---|
committer | Jørgen Lind <jorgen.lind@theqtcompany.com> | 2014-12-11 10:36:46 +0100 |
commit | 4c712744a91bcf08f73422442cac05b4d4ec45dd (patch) | |
tree | ccf648bcad43599848acee779afde86a9029602e /src/widgets/kernel | |
parent | d46d3ef044c6f2a03d2eb5446420ecf5940d57a8 (diff) |
Add NoPartialUpdate support to QOpenGLWidget
[ChangeLog][QtWidgets][QOpenGLWidget] Added an UpdateBehavior flag to
QOpenGLWidget and enabled support for NoParitalUpdate for QOpenGLWidget.
NoPartialUpdate is the default update behavior for QOpenGLWidget.
Task-number: QTBUG-40717
Change-Id: I47d11460e4ef899a24cfd4964ddcac57bc3f91ff
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
Diffstat (limited to 'src/widgets/kernel')
-rw-r--r-- | src/widgets/kernel/qopenglwidget.cpp | 98 | ||||
-rw-r--r-- | src/widgets/kernel/qopenglwidget.h | 8 |
2 files changed, 101 insertions, 5 deletions
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index db116b070c..a111a72e11 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -420,10 +420,25 @@ QT_BEGIN_NAMESPACE the intention is to have a semi-transparent window. In that case the traditional approach of setting Qt::WA_TranslucentBackground is sufficient. + QOpenGLWidget supports multiple update behaviors, just like QOpenGLWindow. In + preserved mode the rendered content from the previous paintGL() call is + available in the next one, allowing incremental rendering. In non-preserved + mode the content is lost and paintGL() implementations are expected to redraw + everything in the view. + + Before Qt 5.5 the default behavior of QOpenGLWidget was to preserve the + rendered contents between paintGL() calls. Since Qt 5.5 the default behavior + is non-preserved because this provides better performance and the majority of + applications have no need for the previous content. This also resembles the + semantics of an OpenGL-based QWindow and matches the default behavior of + QOpenGLWindow in that the color and ancillary buffers are invalidated for + each frame. To restore the preserved behavior, call setUpdateBehavior() with + \c PartialUpdate. + \e{OpenGL is a trademark of Silicon Graphics, Inc. in the United States and other countries.} - \sa QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts + \sa QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts, UpdateBehavior */ /*! @@ -455,6 +470,30 @@ QT_BEGIN_NAMESPACE due to resizing the widget. */ +/*! + \enum QOpenGLWidget::UpdateBehavior + \since 5.5 + + This enum describes the update semantics of QOpenGLWidget. + + \value NoPartialUpdate QOpenGLWidget will discard the + contents of the color buffer and the ancillary buffers after the + QOpenGLWidget is rendered to screen. This is the same behavior that can be + expected by calling QOpenGLContext::swapBuffers with a default opengl + enabled QWindow as the argument. NoPartialUpdate can have some performance + benefits on certain hardware architectures common in the mobile and + embedded space when a framebuffer object is used as the rendering target. + The framebuffer object is invalidated between frames with + glDiscardFramebufferEXT if supported or a glClear. Please see the + documentation of EXT_discard_framebuffer for more information: + https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt + + \value PartialUpdate The framebuffer objects color buffer and ancillary + buffers are not invalidated between frames. + + \sa updateBehavior(), setUpdateBehavior() +*/ + class QOpenGLWidgetPaintDevicePrivate : public QOpenGLPaintDevicePrivate { public: @@ -486,9 +525,11 @@ public: surface(0), initialized(false), fakeHidden(false), - paintDevice(0), inBackingStorePaint(false), - flushPending(false) + hasBeenComposed(false), + flushPending(false), + paintDevice(0), + updateBehavior(QOpenGLWidget::NoPartialUpdate) { requestedFormat = QSurfaceFormat::defaultFormat(); } @@ -507,6 +548,8 @@ public: void invokeUserPaint(); void render(); + void invalidateFbo(); + QImage grabFramebuffer() Q_DECL_OVERRIDE; void beginBackingStorePainting() Q_DECL_OVERRIDE { inBackingStorePaint = true; } void endBackingStorePainting() Q_DECL_OVERRIDE { inBackingStorePaint = false; } @@ -522,10 +565,12 @@ public: QOffscreenSurface *surface; bool initialized; bool fakeHidden; - QOpenGLPaintDevice *paintDevice; bool inBackingStorePaint; - QSurfaceFormat requestedFormat; + bool hasBeenComposed; bool flushPending; + QOpenGLPaintDevice *paintDevice; + QSurfaceFormat requestedFormat; + QOpenGLWidget::UpdateBehavior updateBehavior; }; void QOpenGLWidgetPaintDevicePrivate::beginPaint() @@ -648,6 +693,7 @@ void QOpenGLWidgetPrivate::beginCompose() q->makeCurrent(); context->functions()->glFlush(); } + hasBeenComposed = true; emit q->aboutToCompose(); } @@ -743,9 +789,31 @@ void QOpenGLWidgetPrivate::render() return; q->makeCurrent(); + + if (updateBehavior == QOpenGLWidget::NoPartialUpdate && hasBeenComposed) { + invalidateFbo(); + hasBeenComposed = false; + } + invokeUserPaint(); } +void QOpenGLWidgetPrivate::invalidateFbo() +{ + QOpenGLExtensions *f = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions()); + if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) { + const int gl_color_ext = 0x1800; + const int gl_depth_ext = 0x1801; + const int gl_stencil_ext = 0x1802; + const GLenum attachments[] = { + gl_color_ext, gl_depth_ext, gl_stencil_ext + }; + f->glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof attachments / sizeof *attachments, attachments); + } else { + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } +} + extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); QImage QOpenGLWidgetPrivate::grabFramebuffer() @@ -801,6 +869,26 @@ QOpenGLWidget::~QOpenGLWidget() } /*! + Sets this widget's update behavior to \a updateBehavior. + \since 5.5 +*/ +void QOpenGLWidget::setUpdateBehavior(UpdateBehavior updateBehavior) +{ + Q_D(QOpenGLWidget); + d->updateBehavior = updateBehavior; +} + +/*! + \return the update behavior of the widget. + \since 5.5 +*/ +QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const +{ + Q_D(const QOpenGLWidget); + return d->updateBehavior; +} + +/*! Sets the requested surface \a format. When the format is not explicitly set via this function, the format returned by diff --git a/src/widgets/kernel/qopenglwidget.h b/src/widgets/kernel/qopenglwidget.h index 2439fe65ce..3a4c1780dd 100644 --- a/src/widgets/kernel/qopenglwidget.h +++ b/src/widgets/kernel/qopenglwidget.h @@ -52,9 +52,17 @@ class Q_WIDGETS_EXPORT QOpenGLWidget : public QWidget Q_DECLARE_PRIVATE(QOpenGLWidget) public: + enum UpdateBehavior { + NoPartialUpdate, + PartialUpdate + }; + explicit QOpenGLWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); ~QOpenGLWidget(); + void setUpdateBehavior(UpdateBehavior updateBehavior); + UpdateBehavior updateBehavior() const; + void setFormat(const QSurfaceFormat &format); QSurfaceFormat format() const; |