Enhance QOpenGLWidget docs about resource management
Change-Id: Idd1181a34055237b13643dbc58e855db411d0a7c Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
This commit is contained in:
parent
34fbc61f22
commit
68c9a2f82d
@ -107,3 +107,74 @@ widget->setFormat(format); // must be called before the widget or its parent win
|
|||||||
}
|
}
|
||||||
...
|
...
|
||||||
//! [3]
|
//! [3]
|
||||||
|
|
||||||
|
//! [4]
|
||||||
|
class MyGLWidget : public QOpenGLWidget
|
||||||
|
{
|
||||||
|
...
|
||||||
|
|
||||||
|
private:
|
||||||
|
QOpenGLVertexArrayObject m_vao;
|
||||||
|
QOpenGLBuffer m_vbo;
|
||||||
|
QOpenGLShaderProgram *m_program;
|
||||||
|
QOpenGLShader *m_shader;
|
||||||
|
QOpenGLTexture *m_texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
MyGLWidget::MyGLWidget()
|
||||||
|
: m_program(0), m_shader(0), m_texture(0)
|
||||||
|
{
|
||||||
|
// No OpenGL resource initialization is done here.
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGLWidget::~MyGLWidget()
|
||||||
|
{
|
||||||
|
// Make sure the context is current and then explicitly
|
||||||
|
// destroy all underlying OpenGL resources.
|
||||||
|
makeCurrent();
|
||||||
|
|
||||||
|
delete m_texture;
|
||||||
|
delete m_shader;
|
||||||
|
delete m_program;
|
||||||
|
|
||||||
|
m_vbo.destroy();
|
||||||
|
m_vao.destroy();
|
||||||
|
|
||||||
|
doneCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyGLWidget::initializeGL()
|
||||||
|
{
|
||||||
|
m_vao.create();
|
||||||
|
if (m_vao.isCreated())
|
||||||
|
m_vao.bind();
|
||||||
|
|
||||||
|
m_vbo.create();
|
||||||
|
m_vbo.bind();
|
||||||
|
m_vbo.allocate(...);
|
||||||
|
|
||||||
|
m_texture = new QOpenGLTexture(QImage(...));
|
||||||
|
|
||||||
|
m_shader = new QOpenGLShader(...);
|
||||||
|
m_program = new QOpenGLShaderProgram(...);
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
//! [4]
|
||||||
|
|
||||||
|
//! [5]
|
||||||
|
void MyGLWidget::initializeGL()
|
||||||
|
{
|
||||||
|
// context() and QOpenGLContext::currentContext() are equivalent when called from initializeGL or paintGL.
|
||||||
|
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyGLWidget::cleanup()
|
||||||
|
{
|
||||||
|
makeCurrent();
|
||||||
|
delete m_texture;
|
||||||
|
m_texture = 0;
|
||||||
|
...
|
||||||
|
doneCurrent();
|
||||||
|
}
|
||||||
|
//! [5]
|
||||||
|
@ -269,6 +269,54 @@ QT_BEGIN_NAMESPACE
|
|||||||
created later. Some other drivers may behave in unexpected ways when trying to
|
created later. Some other drivers may behave in unexpected ways when trying to
|
||||||
utilize shared resources between different threads.
|
utilize shared resources between different threads.
|
||||||
|
|
||||||
|
\section1 Resource initialization and cleanup
|
||||||
|
|
||||||
|
The QOpenGLWidget's associated OpenGL context is guaranteed to be current
|
||||||
|
whenever initializeGL() and paintGL() are invoked. Do not attempt to create
|
||||||
|
OpenGL resources before initializeGL() is called. For example, attempting to
|
||||||
|
compile shaders, initialize vertex buffer objects or upload texture data will
|
||||||
|
fail when done in a subclass's constructor. These operations must be deferred
|
||||||
|
to initializeGL(). Some of Qt's OpenGL helper classes, like QOpenGLBuffer or
|
||||||
|
QOpenGLVertexArrayObject, have a matching deferred behavior: they can be
|
||||||
|
instantiated without a context, but all initialization is deferred until a
|
||||||
|
create(), or similar, call. This means that they can be used as normal
|
||||||
|
(non-pointer) member variables in a QOpenGLWidget subclass, but the create()
|
||||||
|
or similar function can only be called from initializeGL(). Be aware however
|
||||||
|
that not all classes are designed like this. When in doubt, make the member
|
||||||
|
variable a pointer and create and destroy the instance dynamically in
|
||||||
|
initializeGL() and the destructor, respectively.
|
||||||
|
|
||||||
|
Releasing the resources also needs the context to be current. Therefore
|
||||||
|
destructors that perform such cleanup are expected to call makeCurrent()
|
||||||
|
before moving on to destroy any OpenGL resources or wrappers. Avoid deferred
|
||||||
|
deletion via \l{QObject::deleteLater()}{deleteLater()} or the parenting
|
||||||
|
mechanism of QObject. There is no guarantee the correct context will be
|
||||||
|
current at the time the instance in question is really destroyed.
|
||||||
|
|
||||||
|
A typical subclass will therefore often look like the following when it comes
|
||||||
|
to resource initialization and destruction:
|
||||||
|
|
||||||
|
\snippet code/doc_gui_widgets_qopenglwidget.cpp 4
|
||||||
|
|
||||||
|
This is naturally not the only possible solution. One alternative is to use
|
||||||
|
the \l{QOpenGLContext::aboutToBeDestroyed()}{aboutToBeDestroyed()} signal of
|
||||||
|
QOpenGLContext. By connecting a slot, using direct connection, to this signal,
|
||||||
|
it is possible to perform cleanup whenever the the underlying native context
|
||||||
|
handle, or the entire QOpenGLContext instance, is going to be released. The
|
||||||
|
following snippet is in principal equivalent to the previous one:
|
||||||
|
|
||||||
|
\snippet code/doc_gui_widgets_qopenglwidget.cpp 5
|
||||||
|
|
||||||
|
Proper cleanup is especially important due to context sharing. Even though
|
||||||
|
each QOpenGLWidget's associated context is destroyed together with the
|
||||||
|
QOpenGLWidget, the sharable resources in that context, like textures, will
|
||||||
|
stay valid until the top-level window, in which the QOpenGLWidget lived, is
|
||||||
|
destroyed. Additionally, some Qt modules may trigger an even wider scope for
|
||||||
|
sharing contexts, potentially leading to keeping the resources in question
|
||||||
|
alive for the entire lifetime of the application. Therefore the safest and
|
||||||
|
most robust is always to perform explicit cleanup for all resources and
|
||||||
|
resource wrappers used in the QOpenGLWidget.
|
||||||
|
|
||||||
\section1 Limitations
|
\section1 Limitations
|
||||||
|
|
||||||
Putting other widgets underneath and making the QOpenGLWidget transparent will
|
Putting other widgets underneath and making the QOpenGLWidget transparent will
|
||||||
@ -748,10 +796,13 @@ void QOpenGLWidget::paintGL()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
Handles resize events that are passed in the \a e event parameter.
|
||||||
|
|
||||||
Handles resize events that are passed in the \a event parameter.
|
|
||||||
Calls the virtual function resizeGL().
|
Calls the virtual function resizeGL().
|
||||||
|
|
||||||
|
\note Avoid overriding this function in derived classes. If that is not
|
||||||
|
feasible, make sure that QOpenGLWidget's implementation is invoked
|
||||||
|
too. Otherwise the underlying framebuffer object and related resources will
|
||||||
|
not get resized properly and will lead to incorrect rendering.
|
||||||
*/
|
*/
|
||||||
void QOpenGLWidget::resizeEvent(QResizeEvent *e)
|
void QOpenGLWidget::resizeEvent(QResizeEvent *e)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user