QOpenGLWidget/QOpenGLWindow: add a destructor which calls makeCurrent

Generally speaking, QOpenGLWindow subclasses are going to use some
various QOpenGL* wrapper object to handle their buffers, FBOs, etc.

Some of those QOpenGL* wrappers are QObjects, hence it should be safe
to have them as child objects, and expect Qt to clean them up properly;
but that doesn't happen because of how the destruction will work.

In particular, when the subclass object is deleted, there may not be
the right OpenGL context set as current. The deletion will go up to
~QObject, where the child objects will be deleted, resulting in a crash.

That will *also* happen if someone connected to the context's
aboutToBeDestroyed() signal: the context will in fact be deleted
after the child objects, since it's stored in QOpenGLWindowPrivate,
whose dtor will be run after ~QObject (!).

Now, in the general case, QOpenGLWindow subclasses should always
have a dtor in which they call makeCurrent() (also because various QOpenGL*
class are not QObjects, hence they're kept around as full members
instead of pointers-to); but at the same time we should clean up
properly the QObject children.

All of the above of course stands for QOpenGLWidget as well.

Task-number: QTBUG-44094
Change-Id: I2379041fe175416936f6d40292039f773a515b35
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
bb10
Giuseppe D'Angelo 2015-01-23 21:02:37 +01:00
parent dd07b1e389
commit 7414c2c404
3 changed files with 41 additions and 2 deletions

View File

@ -336,6 +336,31 @@ QOpenGLWindow::QOpenGLWindow(QOpenGLContext *shareContext, UpdateBehavior update
{
setSurfaceType(QSurface::OpenGLSurface);
}
/*!
Destroys the QOpenGLWindow instance, freeing its resources.
The OpenGLWindow'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 window.
\warning if you have objects wrapping OpenGL resources (such as
QOpenGLBuffer, QOpenGLShaderProgram, etc.), as members of a QOpenGLWindow
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
\since 5.5
*/
QOpenGLWindow::~QOpenGLWindow()
{
makeCurrent();
}
/*!
\return the update behavior for this QOpenGLWindow.
*/

View File

@ -60,6 +60,7 @@ public:
explicit QOpenGLWindow(UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = 0);
explicit QOpenGLWindow(QOpenGLContext *shareContext, UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = 0);
~QOpenGLWindow();
UpdateBehavior updateBehavior() const;
bool isValid() const;

View File

@ -862,10 +862,23 @@ QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)
}
/*!
Destroys the widget
*/
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();
}
/*!