aboutsummaryrefslogtreecommitdiffstats
path: root/examples/quick
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2023-09-14 14:02:07 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2023-09-25 09:01:17 +0000
commitaeb3bd235a7eaba163b9867b97a9869cc9ecaf7d (patch)
tree27862c5bcca313c51a2bd598698517263c19e209 /examples/quick
parent9000c9f17c66455071c0b7eed0e9168b94c8553d (diff)
Clean up customrendernode example
Make it more consistent with other scenegraph examples, and make it more compact, in particular when it comes to handling the QRhi resources (smart pointers are quite useful in this case since they help dropping a bunch of lines) Expand the docs. Pick-to: 6.6 6.6.0 Change-Id: I97bceca7759db9738d34f0fbf7eb29b0ae6e4c0f Reviewed-by: Christian Strømme <christian.stromme@qt.io>
Diffstat (limited to 'examples/quick')
-rw-r--r--examples/quick/scenegraph/customrendernode/customrender.cpp171
-rw-r--r--examples/quick/scenegraph/customrendernode/customrender.h5
-rw-r--r--examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.gifbin44088 -> 0 bytes
-rw-r--r--examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.jpgbin0 -> 38552 bytes
-rw-r--r--examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc104
-rw-r--r--examples/quick/scenegraph/customrendernode/main.cpp26
-rw-r--r--examples/quick/scenegraph/customrendernode/main.qml9
7 files changed, 189 insertions, 126 deletions
diff --git a/examples/quick/scenegraph/customrendernode/customrender.cpp b/examples/quick/scenegraph/customrendernode/customrender.cpp
index e67cdddd46..d83b364127 100644
--- a/examples/quick/scenegraph/customrendernode/customrender.cpp
+++ b/examples/quick/scenegraph/customrendernode/customrender.cpp
@@ -10,11 +10,11 @@
#include <rhi/qrhi.h>
+//![node]
class CustomRenderNode : public QSGRenderNode
{
public:
CustomRenderNode(QQuickWindow *window);
- virtual ~CustomRenderNode();
void setVertices(const QList<QVector2D> &vertices);
@@ -25,44 +25,31 @@ public:
QSGRenderNode::StateFlags changedStates() const override;
protected:
- QQuickWindow *m_window = nullptr;
- QRhiBuffer *m_vertexBuffer = nullptr;
- QRhiBuffer *m_uniformBuffer = nullptr;
- QRhiShaderResourceBindings *m_resourceBindings = nullptr;
- QRhiGraphicsPipeline *m_pipeLine = nullptr;
+ QQuickWindow *m_window;
+ std::unique_ptr<QRhiBuffer> m_vertexBuffer;
+ std::unique_ptr<QRhiBuffer> m_uniformBuffer;
+ std::unique_ptr<QRhiShaderResourceBindings> m_resourceBindings;
+ std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
QList<QRhiShaderStage> m_shaders;
bool m_verticesDirty = true;
QList<QVector2D> m_vertices;
};
+//![node]
-CustomRenderNode::CustomRenderNode(QQuickWindow *window) : m_window(window)
+CustomRenderNode::CustomRenderNode(QQuickWindow *window)
+ : m_window(window)
{
- Q_ASSERT(QFile::exists(":/scenegraph/customrendernode/shaders/customrender.vert.qsb"));
- Q_ASSERT(QFile::exists(":/scenegraph/customrendernode/shaders/customrender.frag.qsb"));
-
QFile file;
file.setFileName(":/scenegraph/customrendernode/shaders/customrender.vert.qsb");
- file.open(QFile::ReadOnly);
- m_shaders.append(
- QRhiShaderStage(QRhiShaderStage::Vertex, QShader::fromSerialized(file.readAll())));
+ if (!file.open(QFile::ReadOnly))
+ qFatal("Failed to load vertex shader");
+ m_shaders.append(QRhiShaderStage(QRhiShaderStage::Vertex, QShader::fromSerialized(file.readAll())));
file.close();
file.setFileName(":/scenegraph/customrendernode/shaders/customrender.frag.qsb");
- file.open(QFile::ReadOnly);
- m_shaders.append(
- QRhiShaderStage(QRhiShaderStage::Fragment, QShader::fromSerialized(file.readAll())));
-}
-
-CustomRenderNode::~CustomRenderNode()
-{
- if (m_pipeLine)
- delete m_pipeLine;
- if (m_resourceBindings)
- delete m_resourceBindings;
- if (m_vertexBuffer)
- delete m_vertexBuffer;
- if (m_uniformBuffer)
- delete m_uniformBuffer;
+ if (!file.open(QFile::ReadOnly))
+ qFatal("Failed to load fragment shader");
+ m_shaders.append(QRhiShaderStage(QRhiShaderStage::Fragment, QShader::fromSerialized(file.readAll())));
}
void CustomRenderNode::setVertices(const QList<QVector2D> &vertices)
@@ -76,143 +63,129 @@ void CustomRenderNode::setVertices(const QList<QVector2D> &vertices)
markDirty(QSGNode::DirtyGeometry);
}
+//![node-release]
void CustomRenderNode::releaseResources()
{
- if (m_vertexBuffer) {
- delete m_vertexBuffer;
- m_vertexBuffer = nullptr;
- }
-
- if (m_uniformBuffer) {
- delete m_uniformBuffer;
- m_uniformBuffer = nullptr;
- }
-
- if (m_pipeLine) {
- delete m_pipeLine;
- m_pipeLine = nullptr;
- }
-
- if (m_resourceBindings) {
- delete m_resourceBindings;
- m_resourceBindings = nullptr;
- }
-
+ m_vertexBuffer.reset();
+ m_uniformBuffer.reset();
+ m_pipeline.reset();
+ m_resourceBindings.reset();
}
+//![node-release]
+//![node-flags]
QSGRenderNode::RenderingFlags CustomRenderNode::flags() const
{
- // We are rendering 2D content directly into the scene graph
- return { QSGRenderNode::NoExternalRendering | QSGRenderNode::DepthAwareRendering };
+ // We are rendering 2D content directly into the scene graph using QRhi, no
+ // direct usage of a 3D API. Hence NoExternalRendering. This is a minor
+ // optimization.
+
+ // Additionally, the node takes the item transform into account by relying
+ // on projectionMatrix() and matrix() (see prepare()) and never rendering at
+ // other Z coordinates. Hence DepthAwareRendering. This is a potentially
+ // bigger optimization.
+
+ return QSGRenderNode::NoExternalRendering | QSGRenderNode::DepthAwareRendering;
}
+//![node-flags]
QSGRenderNode::StateFlags CustomRenderNode::changedStates() const
{
- return {QSGRenderNode::StateFlag::ViewportState | QSGRenderNode::StateFlag::CullState};
+ // In Qt 6 only ViewportState and ScissorState matter, the rest is ignored.
+ return QSGRenderNode::StateFlag::ViewportState | QSGRenderNode::StateFlag::CullState;
}
+//![node-prepare]
void CustomRenderNode::prepare()
{
- QRhiSwapChain *swapChain = m_window->swapChain();
QRhi *rhi = m_window->rhi();
- Q_ASSERT(swapChain);
- Q_ASSERT(rhi);
-
QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
if (m_verticesDirty) {
- if (m_vertexBuffer) {
- delete m_vertexBuffer;
- m_vertexBuffer = nullptr;
- }
+ m_vertexBuffer.reset();
m_verticesDirty = false;
}
if (!m_vertexBuffer) {
- m_vertexBuffer = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer,
- m_vertices.count() * sizeof(QVector2D));
+ m_vertexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer,
+ m_vertices.count() * sizeof(QVector2D)));
m_vertexBuffer->create();
- resourceUpdates->uploadStaticBuffer(m_vertexBuffer, m_vertices.constData());
+ resourceUpdates->uploadStaticBuffer(m_vertexBuffer.get(), m_vertices.constData());
}
-
+//![node-prepare]
if (!m_uniformBuffer) {
- m_uniformBuffer = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
+ m_uniformBuffer.reset(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68));
m_uniformBuffer->create();
}
if (!m_resourceBindings) {
- m_resourceBindings = rhi->newShaderResourceBindings();
+ m_resourceBindings.reset(rhi->newShaderResourceBindings());
m_resourceBindings->setBindings({ QRhiShaderResourceBinding::uniformBuffer(
0,
QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
- m_uniformBuffer) });
+ m_uniformBuffer.get()) });
m_resourceBindings->create();
}
- if (!m_pipeLine) {
+ if (!m_pipeline) {
+ m_pipeline.reset(rhi->newGraphicsPipeline());
- m_pipeLine = rhi->newGraphicsPipeline();
-
- //
// If layer.enabled == true on our QQuickItem, the rendering face is flipped for
// backends with isYUpInFrameBuffer == true (OpenGL). This does not happen with
// RHI backends with isYUpInFrameBuffer == false. We swap the triangle winding
// order to work around this.
- //
- m_pipeLine->setFrontFace(renderTarget()->resourceType() == QRhiResource::TextureRenderTarget
+ m_pipeline->setFrontFace(renderTarget()->resourceType() == QRhiResource::TextureRenderTarget
&& rhi->isYUpInFramebuffer()
? QRhiGraphicsPipeline::CW
: QRhiGraphicsPipeline::CCW);
- m_pipeLine->setCullMode(QRhiGraphicsPipeline::Back);
- m_pipeLine->setTopology(QRhiGraphicsPipeline::TriangleStrip);
+ m_pipeline->setCullMode(QRhiGraphicsPipeline::Back);
+ m_pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
QRhiGraphicsPipeline::TargetBlend blend;
blend.enable = true;
- m_pipeLine->setTargetBlends({ blend });
- m_pipeLine->setShaderResourceBindings(m_resourceBindings);
- m_pipeLine->setShaderStages(m_shaders.cbegin(), m_shaders.cend());
- m_pipeLine->setDepthTest(true);
+ m_pipeline->setTargetBlends({ blend });
+ m_pipeline->setShaderResourceBindings(m_resourceBindings.get());
+ m_pipeline->setShaderStages(m_shaders.cbegin(), m_shaders.cend());
+ m_pipeline->setDepthTest(true);
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({ { 2 * sizeof(float) } });
inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
- m_pipeLine->setVertexInputLayout(inputLayout);
- m_pipeLine->setRenderPassDescriptor(renderTarget()->renderPassDescriptor());
- m_pipeLine->create();
+ m_pipeline->setVertexInputLayout(inputLayout);
+ m_pipeline->setRenderPassDescriptor(renderTarget()->renderPassDescriptor());
+ m_pipeline->create();
}
- QMatrix4x4 mvp = *projectionMatrix() * *matrix();
- float opacity = inheritedOpacity();
-
- resourceUpdates->updateDynamicBuffer(m_uniformBuffer, 0, 64, mvp.constData());
- resourceUpdates->updateDynamicBuffer(m_uniformBuffer, 64, 4, &opacity);
+ const QMatrix4x4 mvp = *projectionMatrix() * *matrix();
+ const float opacity = inheritedOpacity();
- swapChain->currentFrameCommandBuffer()->resourceUpdate(resourceUpdates);
+ resourceUpdates->updateDynamicBuffer(m_uniformBuffer.get(), 0, 64, mvp.constData());
+ resourceUpdates->updateDynamicBuffer(m_uniformBuffer.get(), 64, 4, &opacity);
+ commandBuffer()->resourceUpdate(resourceUpdates);
}
+//![node-render]
void CustomRenderNode::render(const RenderState *state)
{
-
- QRhiSwapChain *swapChain = m_window->swapChain();
- Q_ASSERT(swapChain);
-
- QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
- Q_ASSERT(cb);
-
- cb->setGraphicsPipeline(m_pipeLine);
+ QRhiCommandBuffer *cb = commandBuffer();
+ cb->setGraphicsPipeline(m_pipeline.get());
QSize renderTargetSize = renderTarget()->pixelSize();
cb->setViewport(QRhiViewport(0, 0, renderTargetSize.width(), renderTargetSize.height()));
cb->setShaderResources();
- QRhiCommandBuffer::VertexInput vertexBindings[] = { { m_vertexBuffer, 0 } };
+ QRhiCommandBuffer::VertexInput vertexBindings[] = { { m_vertexBuffer.get(), 0 } };
cb->setVertexInput(0, 1, vertexBindings);
cb->draw(m_vertices.count());
}
+//![node-render]
-CustomRender::CustomRender(QQuickItem *parent) : QQuickItem(parent)
+//![item-ctor]
+CustomRender::CustomRender(QQuickItem *parent)
+ : QQuickItem(parent)
{
setFlag(ItemHasContents, true);
connect(this, &CustomRender::verticesChanged, this, &CustomRender::update);
}
+//![item-ctor]
-const QList<QVector2D> &CustomRender::vertices() const
+QList<QVector2D> CustomRender::vertices() const
{
return m_vertices;
}
@@ -226,6 +199,7 @@ void CustomRender::setVertices(const QList<QVector2D> &newVertices)
emit verticesChanged();
}
+//![item-update]
QSGNode *CustomRender::updatePaintNode(QSGNode *old, UpdatePaintNodeData *)
{
CustomRenderNode *node = static_cast<CustomRenderNode *>(old);
@@ -237,3 +211,4 @@ QSGNode *CustomRender::updatePaintNode(QSGNode *old, UpdatePaintNodeData *)
return node;
}
+//![item-update]
diff --git a/examples/quick/scenegraph/customrendernode/customrender.h b/examples/quick/scenegraph/customrendernode/customrender.h
index ef6c29fa7d..530e692678 100644
--- a/examples/quick/scenegraph/customrendernode/customrender.h
+++ b/examples/quick/scenegraph/customrendernode/customrender.h
@@ -7,6 +7,7 @@
#include <QQuickItem>
#include <QVector2D>
+//![item]
class CustomRender : public QQuickItem
{
Q_OBJECT
@@ -16,11 +17,10 @@ class CustomRender : public QQuickItem
public:
explicit CustomRender(QQuickItem *parent = nullptr);
- const QList<QVector2D> &vertices() const;
+ QList<QVector2D> vertices() const;
void setVertices(const QList<QVector2D> &newVertices);
signals:
-
void verticesChanged();
protected:
@@ -29,5 +29,6 @@ protected:
private:
QList<QVector2D> m_vertices;
};
+//![item]
#endif // CUSTOMRENDER_H
diff --git a/examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.gif b/examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.gif
deleted file mode 100644
index c4b36d19fb..0000000000
--- a/examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.gif
+++ /dev/null
Binary files differ
diff --git a/examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.jpg b/examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.jpg
new file mode 100644
index 0000000000..db4b50bbc0
--- /dev/null
+++ b/examples/quick/scenegraph/customrendernode/doc/images/customrendernode-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc b/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
index df93a05c1a..a33166870d 100644
--- a/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
+++ b/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
@@ -8,10 +8,17 @@
\ingroup qtquickexamples
\brief Shows how to use QSGRenderNode to implement custom rendering in the Qt Quick scenegraph.
- The custom render node example shows how to implement an item that is rendered using
- a custom QSGRenderNode.
+ The custom render node example shows how to implement a QQuickItem subclass
+ that is backed by a scene graph node derived from QSGRenderNode, providing
+ it's own QRhi-based rendering.
- \image customrendernode-example.gif
+ \image customrendernode-example.jpg
+
+ \note This example demonstrates advanced, low-level functionality performing
+ portable, cross-platform 3D rendering, while relying on APIs with limited
+ compatibility guarantee from the Qt Gui module. To be able to use the QRhi
+ APIs, the application links to \c{Qt::GuiPrivate} and includes
+ \c{<rhi/qrhi.h>}.
QSGRenderNode allows direct access to the Render Hardware Interface (RHI)
within the scenegraph. This example demonstrates how to create QSGRenderNode
@@ -24,12 +31,6 @@
native 3D API such as OpenGL, Metal, or Vulkan. Rather, the application uses
Qt's graphics and shader abstraction layer.
- \note This example demonstrates advanced, low-level functionality performing
- portable, cross-platform 3D rendering, while relying on APIs with limited
- compatibility guarantee from the Qt Gui module. To be able to use the QRhi
- APIs, the application links to \c{Qt::GuiPrivate} and includes
- \c{<rhi/qrhi.h>}.
-
QSGRenderNode is the enabler for one of the three ways to integrate custom
2D/3D rendering into a Qt Quick scene. The other two options are to perform
the rendering \c before or \c after the Qt Quick scene's own rendering,
@@ -40,5 +41,88 @@
injecting custom rendering commands "inline" with the Qt Quick scene's
own rendering.
- \sa {Scene Graph - RHI Under QML}, {Scene Graph - RHI Texture Item}
+ Refer to the following examples for these three approaches:
+
+ \list
+
+ \li \l{Scene Graph - RHI Under QML} - Demonstrates an "underlay" approach
+ based on the \l{QQuickWindow::beforeRendering()} signal. No additional
+ render pass and resources are needed, but composition and blending with the
+ rest of the Qt Quick scene is quite limited. Rendering "under" or "over" the
+ Qt Quick scene is the simplest approach.
+
+ \li \l{Scene Graph - RHI Texture Item} - Demonstrates creating a custom
+ QQuickItem that renders into a texture and displays a quad textured with the
+ generated content. This is very flexible and allows complete blending and
+ composition of the resulting 2D image with the rest of the Qt Quick scene.
+ That comes at the expense of an additional render pass and render target.
+
+ \li This example - Demonstrates the "inline" approach, where the Qt Quick
+ scene graph calls into the custom item and node implementation during the
+ main render pass. This approach can be great for performance (no extra
+ render passes, texturing, and blending are involved), but has potential
+ pitfalls and is the most complicated method.
+
+ \endlist
+
+ The custom item derives from QQuickItem. Most importantly, it reimplements
+ \l{QQuickItem::}updatePaintNode().
+
+ \snippet scenegraph/customrendernode/customrender.h item
+
+ The constructor sets the \l{QQuickItem::}ItemHasContents flag to indicate
+ that this is a visual item.
+
+ \snippet scenegraph/customrendernode/customrender.cpp item-ctor
+
+ The updatePaintNode() implementation creates an instance of the custom
+ scenegraph node, if not yet done. The backing QSGNode tree for this item
+ consists of a single node, an instance of a QSGRenderNode-derived class.
+ When Qt Quick's threaded rendering model is in use, this function is called
+ on the render thread with the main thread blocked. That is why it is safe to
+ access main thread data (such as data stored in QQuickItems). The node, the
+ instance of the QSGRenderNode subclass, is going to "live on" the render
+ thread.
+
+ \snippet scenegraph/customrendernode/customrender.cpp item-update
+
+ The \c CustomRenderNode class derives from QSGRenderNode, reimplementing a
+ number of virtual functions. To manage QRhi resources (buffers, pipelines,
+ etc.), smart pointers are quite useful in this case, because the node is
+ destroyed by the scene graph together with the rest of the scene on the
+ render thread (if there is one) while the QRhi is still available, and
+ therefore releasing resources from the destructor or via smart pointers is
+ legal and safe.
+
+ \snippet scenegraph/customrendernode/customrender.cpp node
+
+ Well-behaving QSGRenderNode subclasses also reimplement
+ \l{QSGRenderNode::}releaseResources(),which in this case can be a simple set
+ of reset() calls.
+
+ \snippet scenegraph/customrendernode/customrender.cpp node-release
+
+ This QSGRenderNode is performing its rendering through the QRhi APIs (and
+ not directly through OpenGL, Vulkan, Metal, etc.), and it takes the item
+ transform into account (as it only really does 2D rendering). Hence
+ specifying the appropriate flags, which may bring a small performance
+ improvement.
+
+ \snippet scenegraph/customrendernode/customrender.cpp node-flags
+
+ The prepare() and render() functions are called every time the Qt Quick
+ scene renders. The first is called when preparing (but not yet recording)
+ the render pass. This typically creates resources, such as buffers,
+ textures, and graphics pipelines, if not yet done, and enqueues uploading
+ data to them.
+
+ \snippet scenegraph/customrendernode/customrender.cpp node-prepare
+
+ The render() function is called while the recording of a render pass,
+ targeting either the QQuickWindow's swapchain, or a texture (in case of
+ layered items, or when within a ShaderEffectSource), is active.
+
+ \snippet scenegraph/customrendernode/customrender.cpp node-render
+
+ \sa QSGRenderNode, QRhi, {Scene Graph - RHI Under QML}, {Scene Graph - RHI Texture Item}, {Qt Quick Scene Graph}
*/
diff --git a/examples/quick/scenegraph/customrendernode/main.cpp b/examples/quick/scenegraph/customrendernode/main.cpp
index 0eeb9214d9..0ad93ec1de 100644
--- a/examples/quick/scenegraph/customrendernode/main.cpp
+++ b/examples/quick/scenegraph/customrendernode/main.cpp
@@ -2,11 +2,14 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
-#include <QtQuick/QQuickView>
+#include <QQuickView>
#include <QSurfaceFormat>
int main(int argc, char **argv)
{
+ QGuiApplication app(argc, argv);
+
+ // On macOS, request a core profile context in the unlikely case of using OpenGL.
#ifdef Q_OS_MACOS
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
format.setMajorVersion(4);
@@ -15,30 +18,31 @@ int main(int argc, char **argv)
QSurfaceFormat::setDefaultFormat(format);
#endif
- QGuiApplication app(argc, argv);
-
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:///scenegraph/customrendernode/main.qml"));
- view.setColor(QColor(0, 0, 0));
+ view.setColor(Qt::black);
view.show();
QString api;
switch (view.graphicsApi()) {
- case QSGRendererInterface::GraphicsApi::OpenGLRhi:
+ case QSGRendererInterface::OpenGL:
api = "RHI OpenGL";
break;
- case QSGRendererInterface::GraphicsApi::Direct3D11Rhi:
- api = "RHI Direct3D";
+ case QSGRendererInterface::Direct3D11:
+ api = "RHI Direct 3D 11";
+ break;
+ case QSGRendererInterface::Direct3D12:
+ api = "RHI Direct 3D 12";
break;
- case QSGRendererInterface::GraphicsApi::VulkanRhi:
+ case QSGRendererInterface::Vulkan:
api = "RHI Vulkan";
break;
- case QSGRendererInterface::GraphicsApi::MetalRhi:
+ case QSGRendererInterface::Metal:
api = "RHI Metal";
break;
- case QSGRendererInterface::GraphicsApi::NullRhi:
+ case QSGRendererInterface::Null:
api = "RHI Null";
break;
default:
@@ -48,5 +52,5 @@ int main(int argc, char **argv)
view.setTitle(QStringLiteral("Custom QSGRenderNode - ") + api);
- return QGuiApplication::exec();
+ return app.exec();
}
diff --git a/examples/quick/scenegraph/customrendernode/main.qml b/examples/quick/scenegraph/customrendernode/main.qml
index bd6869cc19..a0b62c4bf8 100644
--- a/examples/quick/scenegraph/customrendernode/main.qml
+++ b/examples/quick/scenegraph/customrendernode/main.qml
@@ -45,11 +45,10 @@ Item {
anchors.bottom: parent.bottom
anchors.margins: 20
wrapMode: Text.WordWrap
- text: qsTr("This example creates a custom scenegraph QSGRenderNode render node and " +
- "demonstrates its use. The render node is placed in front of a red " +
- "rectangle, and behind a white rectangle. Rendering is demonstrated " +
- "directly into the scenegraph, and as a layered item. Opacity and " +
- "rotation transform changes are exercised.")
+ text: qsTr("This example creates a custom QQuickItem backed by a QSGRenderNode in the scene graph. " +
+ "The render node is placed in front of a red rectangle, and behind a white rectangle. " +
+ "Rendering is demonstrated directly into the scenegraph, and as a layered, texture-backed item (layer.enabled set to true). " +
+ "Opacity and rotation transform changes are exercised as well.")
Rectangle {
z:-1