aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <[email protected]>2023-06-01 14:39:48 +0200
committerLaszlo Agocs <[email protected]>2023-06-01 19:22:29 +0200
commit040189e8e2a5b777b9d1f069a10efdadb723f485 (patch)
treede41d44ededcbcebe0eab54e7657f42cf4f710a3
parent9982f16eadac1a252353a31972b03e3d3449f815 (diff)
rhi examples: expand docs
Change-Id: I88991ffe3612b76aaa687f86acd59e24c5543a76 Reviewed-by: Andy Nichols <[email protected]>
-rw-r--r--examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc11
-rw-r--r--examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc118
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp12
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.h3
-rw-r--r--examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc16
-rw-r--r--src/quick/doc/src/examples.qdoc1
6 files changed, 157 insertions, 4 deletions
diff --git a/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc b/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
index 4240e30558..47bf3489c5 100644
--- a/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
+++ b/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
@@ -29,4 +29,15 @@
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,
+ or to generate a whole separate render pass targeting a dedicated render
+ target (a texture) and then have an item in the scene display the texture.
+ The QSGRenderNode-based approach is similar to the former, in the sense
+ that no additional render passes or render targets are involved, and allows
+ injecting custom rendering commands "inline" with the Qt Quick scene's
+ own rendering.
+
+ \sa {Scene Graph - RHI Under QML}, {Scene Graph - RHI Texture Item}
*/
diff --git a/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc
index 97f0588314..596984dfdf 100644
--- a/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc
+++ b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc
@@ -35,6 +35,12 @@
comes at the expense of being more expensive in terms of resources and
performance since it involves rendering to a texture first.
+ \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>}.
+
\section1 Walkthrough
\c ExampleRhiItem is the QQuickItem subclass that is exposed to QML
@@ -49,13 +55,119 @@
\c ExampleRhiItem drives from \c RhiItem, which contains the generic
implementation of a \l QQuickItem that maintains and displays a \l
- QRhiTexture.
+ QRhiTexture. The design is somewhat similar to the legacy \l
+ QQuickFramebufferObject and its inner Renderer class. In essence what is
+ implemented here offers the core functionality of \l
+ QQuickFramebufferObject, but without being tied to OpenGL. To support the
+ threaded rendering model of the Qt Quick scene graph, the a separate \c
+ RhiItemRenderer object is instantiated that then lives on the Qt Quick
+ render thread, if there is one. \c RhiItem, being a \l QQuickItem, lives
+ and operates on the main (gui) thread.
\snippet scenegraph/rhitextureitem/rhitextureitem.h itembase
- The corresponding scene graph node is implemented using \l
- QSGSimpleTextureNode.
+ \c RhiItemRenderer has three pure virtual functions expected to be
+ reimplemented in subclasses. \c initialize() is called to let the
+ application-provided renderer to know the \l QRhi and \l QRhiTexture
+ instances to use. The example also handles the resizing of the item, which
+ leads to having to use a new texture with a size different than before.
+ This means \c initialize() may be called multiple times during the lifetime
+ of a \c RhiItemRenderer.
+
+ \c synchronize() is called from the scene graph's synchronizing phase, i.e.
+ from the \c RhiItem's \l{QQuickItem::updatePaintNode()}{updatePaintNode()}.
+ That implies that, if the threaded rendering model is used, that it is safe
+ to copy data between the main and the render thread since the main thread is
+ blocked.
+
+ \c render() is the function that is called every time the \c RhiItem's
+ texture's content needs updating. This function is expected to record a
+ render pass onto the provided \l QRhiCommandBuffer, targeting a \l
+ QRhiTextureRenderTarget associated with the \l QRhiTexture passed to \c
+ initialize().
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.h rendererbase
+
+ The scene graph node that is instantied by \c RhiItem is implemented using
+ \l QSGSimpleTextureNode.
\snippet scenegraph/rhitextureitem/rhitextureitem.h itemnode
+ \c RhiItemNode connects to the window's
+ \l{QQuickWindow::beforeRendering()}{beforeRendering()} signal. This signal
+ is emitted on the render thread, if there is one, every time the Qt Quick
+ scene graph has started to prepare a new frame.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp nodector
+
+ The slot connected to this signal retrieves the \l QRhiCommandBuffer used by
+ the \l QQuickWindow, while also providing an example of what to do if there
+ is no on-screen window, and so no \l QRhiSwapChain associated with the \l
+ QQuickWindow. Then the \c RhiItemRenderer's \c render() function is invoked.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp noderender
+
+ The application-provided \c initialize and \c synchronize steps are invoked
+ from the \c RhiItemNode's sync() function which in turn is called from \c
+ RhiItem's \c updatePaintNode().
+
+ Once the \l QRhi is retrieved from the \l QQuickWindow, the need for a new
+ \l QRhiTexture is examined. If there is no texture yet, or it looks like the
+ item's size (in pixels, note the multiplication with the device pixel ratio)
+ has changed, a new texture is created. The \l QRhiTexture is then wrapped in
+ a \l QSGTexture, which also involves passing ownership. The wrapping \l
+ QSGTexture is created using a \l QQuickWindow helper function,
+ \l{QQuickWindow::createTextureFromRhiTexture()}{createTextureFromRhiTexture()}. In
+ spirit this is similar to the
+ \l{QQuickWindow::createTextureFromImage()}{createTextureFromImage()}, but
+ while the traditional QImage-based function creates a new \l QRhiTexture
+ under the hood, this variant takes an existing \l QRhiTexture.
+
+ Finally, the application-provided \c synchronize() function is invoked.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp nodesync
+
+ The example's implementation makes a copy of the angle value, meaning the
+ renderer's copy of the value is updated based on the current value of the
+ property in \c ExampleRhiItem.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp examplesync
+
+ The example's implementation of the initialization step stores the \l QRhi
+ for future use. This example does not handle the case of the \l QRhi
+ changing over the lifetime of the item. If moving (reparenting) the item
+ between \l QQuickWindow instances is involved, then that would need to be
+ handled as well. What is handled however, is the case of the \c
+ outputTexture changing. With the implementation of \c RhiItem and \c
+ RhiItemNode, the \l QRhiTexture is different whenever the window, and so the
+ item in the scene, is resized.
+
+ If not yet done, a \l QRhiTextureRenderTarget is created. The example also
+ demonstrates rendering with a depth buffer present. Care must be taken to
+ correctly resize this buffer whenever its size no longer matches the \c
+ outputTexture's size in the previous invocation of the function.
+
+ Finally, if not yet done, the resources needed for rendering the scene are
+ prepared: vertex buffer, uniform buffer, graphics pipeline.
+
+ The traditional Qt logo renderer, that has been ported from the OpenGL-based
+ examples of Qt 4 and 5, provides vertex positions and normals in two
+ separate chunks, hence using a non-interleaved layout for the vertex buffer.
+
+ The vertex and fragment shaders are loaded from \c{.qsb} files generated at
+ build time (if using CMake).
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp exampleinit
+
+ In the \c render step, the uniform buffer is updated. Note how the
+ \l{QRhi::clipSpaceCorrMatrix()}{QRhi-provided correction matrix} is
+ multiplied in. This allows ignoring the 3D API specific differences when it
+ comes to coordinate systems, and continuing to work with OpenGL-style
+ vertices and normals.
+
+ A single render pass is recorded, containing a single draw call.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp examplerender
+
+ \sa {Scene Graph - RHI Under QML}, {Scene Graph - Custom QSGRenderNode}
*/
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp
index 92615a4d5b..99e2f79dc3 100644
--- a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp
@@ -4,12 +4,14 @@
#include "rhitextureitem.h"
#include <QFile>
+//! [nodector]
RhiItemNode::RhiItemNode(RhiItem *item)
: m_item(item)
{
m_window = m_item->window();
connect(m_window, &QQuickWindow::beforeRendering, this, &RhiItemNode::render,
Qt::DirectConnection);
+//! [nodector]
connect(m_window, &QQuickWindow::screenChanged, this, [this]() {
if (m_window->effectiveDevicePixelRatio() != m_dpr)
m_item->update();
@@ -21,6 +23,7 @@ QSGTexture *RhiItemNode::texture() const
return m_sgTexture.get();
}
+//! [nodesync]
void RhiItemNode::sync()
{
if (!m_rhi) {
@@ -56,7 +59,9 @@ void RhiItemNode::sync()
m_renderer->synchronize(m_item);
}
+//! [nodesync]
+//! [noderender]
void RhiItemNode::render()
{
// called before Qt Quick starts recording its main render pass
@@ -86,6 +91,7 @@ void RhiItemNode::render()
markDirty(QSGNode::DirtyMaterial);
emit textureChanged();
}
+//! [noderender]
void RhiItemNode::scheduleUpdate()
{
@@ -213,6 +219,7 @@ static QShader getShader(const QString &name)
return QShader();
}
+//! [exampleinit]
void ExampleRhiItemRenderer::initialize(QRhi *rhi, QRhiTexture *outputTexture)
{
m_rhi = rhi;
@@ -247,6 +254,7 @@ void ExampleRhiItemRenderer::initialize(QRhi *rhi, QRhiTexture *outputTexture)
const quint32 vbufSize = vsize + nsize;
scene.vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, vbufSize));
scene.vbuf->create();
+//! [exampleinit]
scene.resourceUpdates = m_rhi->nextResourceUpdateBatch();
scene.resourceUpdates->uploadStaticBuffer(scene.vbuf.get(), 0, vsize, m_vertices.constData());
@@ -284,6 +292,7 @@ void ExampleRhiItemRenderer::initialize(QRhi *rhi, QRhiTexture *outputTexture)
}
}
+//! [examplesync]
void ExampleRhiItemRenderer::synchronize(RhiItem *rhiItem)
{
// called on the render thread (if there is one), while the main (gui) thread is blocked
@@ -292,7 +301,9 @@ void ExampleRhiItemRenderer::synchronize(RhiItem *rhiItem)
if (item->angle() != scene.logoAngle)
scene.logoAngle = item->angle();
}
+//! [examplesync]
+//! [examplerender]
void ExampleRhiItemRenderer::render(QRhiCommandBuffer *cb)
{
QRhiResourceUpdateBatch *rub = scene.resourceUpdates;
@@ -320,6 +331,7 @@ void ExampleRhiItemRenderer::render(QRhiCommandBuffer *cb)
cb->endPass();
}
+//! [examplerender]
void ExampleRhiItemRenderer::createGeometry()
{
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h
index d32ef34f11..8a36b2b4f1 100644
--- a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h
@@ -15,6 +15,7 @@ class RhiItemNode;
QT_FORWARD_DECLARE_CLASS(QSGPlainTexture)
+//! [rendererbase]
class RhiItemRenderer
{
public:
@@ -22,7 +23,7 @@ public:
virtual void initialize(QRhi *rhi, QRhiTexture *outputTexture) = 0;
virtual void synchronize(RhiItem *item) = 0;
virtual void render(QRhiCommandBuffer *cb) = 0;
-
+//! [rendererbase]
void update();
private:
diff --git a/examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc b/examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc
index 358b89123c..fed4d1d54a 100644
--- a/examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc
+++ b/examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc
@@ -34,6 +34,20 @@
with all the 3D APIs supported by QRhi (such as, OpenGL, Vulkan, Metal,
Direct 3D 11 and 12).
+ \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>}.
+
+ Adding custom rendering as an underlay/overlay is 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 "inline" with the Qt Quick scene's own rendering using QSGRenderNode,
+ or to generate a whole separate render pass targeting a dedicated render target
+ (a texture) and then have an item in the scene display the texture.
+ Refer to the \l{Scene Graph - RHI Texture Item} and the
+ \l{Scene Graph - Custom QSGRenderNode} examples regarding those approaches.
+
\section1 Core Concepts
The beforeRendering() signal is emitted at the start of every frame, before
@@ -216,4 +230,6 @@
normally be generated at build time, and lists them in the qrc file. This
approach is however not recommended for new applications that use CMake as
the build system.
+
+ \sa {Scene Graph - RHI Texture Item}, {Scene Graph - Custom QSGRenderNode}
*/
diff --git a/src/quick/doc/src/examples.qdoc b/src/quick/doc/src/examples.qdoc
index 2f0cff62bc..6a513071a8 100644
--- a/src/quick/doc/src/examples.qdoc
+++ b/src/quick/doc/src/examples.qdoc
@@ -151,6 +151,7 @@ Creator.
\li \l{Scene Graph - Custom Material}{Custom Material}
\li \l{Scene Graph - RHI Under QML}{Portable QRhi-based 3D rendering as a scene underlay}
\li \l{Scene Graph - RHI Texture Item}{Displaying a QRhi-rendered image in a QQuickItem}
+ \li \l{Scene Graph - Custom QSGRenderNode}{Implementing a QRhi-based QSGRenderNode}
\li \l{Scene Graph - Two Texture Providers}{Texture Providers and Materials}
\li \l{Scene Graph - Custom Geometry}{Custom Geometry}
\li \l{Scene Graph - Graph}{Graph}