summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel/qopenglwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/kernel/qopenglwidget.cpp')
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp135
1 files changed, 118 insertions, 17 deletions
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
index 12e054626c..f63685c37a 100644
--- a/src/widgets/kernel/qopenglwidget.cpp
+++ b/src/widgets/kernel/qopenglwidget.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtWidgets module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -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_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0
+ const int gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT
+ const int gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT
+ const GLenum attachments[] = {
+ gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment
+ };
+ 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()
@@ -795,10 +863,45 @@ QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)
}
/*!
- Destroys the widget
- */
+ Destroys the QOpenGLWidget instance, freeing its resources.
+
+ The QOpenGLWidget's context is made current in the destructor, allowing for
+ safe destruction of any child object that may need to release OpenGL
+ resources belonging to the context provided by this widget.
+
+ \warning if you have objects wrapping OpenGL resources (such as
+ QOpenGLBuffer, QOpenGLShaderProgram, etc.) as members of a OpenGLWidget
+ subclass, you may need to add a call to makeCurrent() in that subclass'
+ destructor as well. Due to the rules of C++ object destruction, those objects
+ will be destroyed \e{before} calling this function (but after that the
+ destructor of the subclass has run), therefore making the OpenGL context
+ current in this function happens too late for their safe disposal.
+
+ \sa makeCurrent
+*/
QOpenGLWidget::~QOpenGLWidget()
{
+ makeCurrent();
+}
+
+/*!
+ 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;
}
/*!
@@ -877,10 +980,8 @@ bool QOpenGLWidget::isValid() const
void QOpenGLWidget::makeCurrent()
{
Q_D(QOpenGLWidget);
- if (!d->initialized) {
- qWarning("QOpenGLWidget: Cannot make uninitialized widget current");
+ if (!d->initialized)
return;
- }
d->context->makeCurrent(d->surface);