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>
bb10
Jørgen Lind 2014-09-08 13:50:26 +02:00 committed by Jørgen Lind
parent d46d3ef044
commit 4c712744a9
2 changed files with 101 additions and 5 deletions

View File

@ -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()
@ -800,6 +868,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.

View File

@ -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;