aboutsummaryrefslogtreecommitdiffstats
path: root/examples/quick/rendercontrol/rendercontrol_rhi/doc/src/rendercontrol_rhi.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'examples/quick/rendercontrol/rendercontrol_rhi/doc/src/rendercontrol_rhi.qdoc')
-rw-r--r--examples/quick/rendercontrol/rendercontrol_rhi/doc/src/rendercontrol_rhi.qdoc140
1 files changed, 140 insertions, 0 deletions
diff --git a/examples/quick/rendercontrol/rendercontrol_rhi/doc/src/rendercontrol_rhi.qdoc b/examples/quick/rendercontrol/rendercontrol_rhi/doc/src/rendercontrol_rhi.qdoc
new file mode 100644
index 0000000000..521dee3abc
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_rhi/doc/src/rendercontrol_rhi.qdoc
@@ -0,0 +1,140 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \title QQuickRenderControl RHI Example
+ \example rendercontrol/rendercontrol_rhi
+ \brief Shows how to render a Qt Quick scene into a QRhiTexture.
+ \examplecategory {Graphics}
+ \image rendercontrol-rhi-example.jpg
+
+ This example demonstrates how to set up a Qt Quick scene that has its
+ rendering redirected into a \l QRhiTexture. The application is then free to
+ do whatever it wants with the resulting texture from each frame.
+ This example is a QWidget-based application that performs a readback of the
+ image data, and then displays the collected per-frame renders with CPU and
+ GPU-based timing information for each.
+
+ By using Qt's 3D graphics API abstraction, this example is not tied to any
+ particular graphics API. At startup, a dialog is shown with the platforms'
+ potentially supported 3D APIs.
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp apiselect
+
+ \note It is not guaranteed that all selections will be functional on a given
+ platform.
+
+ Once a selection is made, a QML file is loaded. However, we will not simply
+ create a \l QQuickView instance and \l{QQuickView::show()}{show()} it.
+ Rather, the \l QQuickWindow that manages the Qt Quick scene is never shown
+ on-screen. Instead, the application takes control over when and to where
+ render, via \l QQuickRenderControl.
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp load-1
+
+ Once the object tree is instantiated, the root item (a \l Rectangle) is
+ queried, its size is ensured to be valid and then propagated.
+
+ \note Scenes that use the \l Window element within the object tree are not
+ supported.
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp load-instantiate
+
+ At this point there are no rendering resources initialized, i.e., nothing has
+ been done with the native 3D graphics API yet. A \l QRhi is instantiated
+ only in the next step, and that is what triggers setting up the Vulkan,
+ Metal, Direct 3D, etc. rendering system under the hood.
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp load-graphicsinit
+
+ \note This application uses a model where Qt creates an instance of QRhi.
+ This is not the only possible approach: if the application maintains its own
+ QRhi (and so OpenGL context, Vulkan device, etc.), then Qt Quick can be
+ requested to adopt and use that existing QRhi. That is done via passing a \l
+ QQuickGraphicsDevice created by \l{QQuickGraphicsDevice::fromRhi()} to
+ \l QQuickWindow, similarly to how \l QQuickGraphicsConfiguration is set in
+ the snippet above. Consider for example the case of wanting to use the Qt
+ Quick rendered textures in a QRhiWidget: in that case the QRhiWidget's QRhi
+ will need to passed on to Qt Quick, instead of letting Qt Quick create its
+ own.
+
+ Once \l QQuickRenderControl::initialize() succeeds, the renderer is live and
+ ready to go. For that, we need a color buffer to render into.
+
+ \l QQuickRenderTarget is a lightweight implicitly-shared class that carries
+ (but those not own) various sets of native or QRhi objects that describe
+ textures, render targets, or similar. Calling
+ \l{QQuickWindow::setRenderTarget()}{setRenderTarget()} on the \l
+ QQuickWindow (remember that we have a QQuickWindow that is not visible
+ on-screen) is what triggers redirecting the Qt Quick scene graph's rendering
+ into the texture provided by the application. When working with \l QRhi (and
+ not with native 3D API objects such as OpenGL texture IDs or VkImage
+ objects), the application should set up a \l QRhiTextureRenderTarget and
+ then pass it to Qt Quick via \l QQuickRenderTarget::fromRhiRenderTarget().
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp texture-setup
+
+ \note Always provide a depth-stencil buffer for Qt Quick since both of these
+ buffers and the depth and stencil test may get utilized by the Qt Quick
+ scenegraph when rendering.
+
+ The main render loop is the following. This also shows how to perform
+ GPU->CPU readbacks of images. Once a QImage is available, the
+ QWidget-based user interface updates accordingly. We will omit diving
+ into the details for that here.
+
+ The example also demonstrates a simple way of measuring the cost of
+ rendering a frame on the CPU and the GPU. Offscreen-rendered frames are well
+ suited for this due to certain internal QRhi behavior, which implies that
+ operations that otherwise are asynchronous (in the sense that they complete
+ only when rendering a subsequent frame), are guaranteed to be ready once \l
+ QRhi::endOffscreenFrame() (i.e., QQuickRenderControl::endFrame()) returns.
+ We use this knowledge when reading back the texture, and it applies also to
+ GPU timestamps as well. That is why the application can display the GPU time
+ for each frame, while guaranteeing that the time actually refers to that
+ particular frame (not an earlier one). See
+ \l{QRhiCommandBuffer::lastCompletedGpuTime()}{lastCompletedGpuTime()} for
+ details around GPU timings. The CPU side timings are taken using
+ \l QElapsedTimer.
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp render-core
+
+ One important piece is the stepping of Qt Quick animations. As we do not
+ have an on-screen window that can drive the animation system either via
+ measuring elapsed time, an ordinary timer, or presentation rate-based
+ throttling, redirecting the Qt Quick rendering often implies that the
+ driving of animations needs to be taken over by the application. Otherwise,
+ animations function based on a plain system timer, but the actual elapsed
+ time will often have nothing to do with what the offscreen-rendered scene is
+ expected to perceive. Consider rendering 5 frames in a row, in a tight loop.
+ How the animations in those 5 frames move depends on the speed with which
+ the CPU executes the loop iterations. That is almost never ideal. To ensure
+ consistent animations, install a custom QAnimationDriver. While this is
+ an undocumented (but public) API meant for advanced users, the example here
+ provides a simple example of using it.
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp anim-driver
+
+ The application has a \l QSlider that can be used to change the animation
+ step value from the default 16 milliseconds to something else. Note the call
+ to the setStep() function of our QAnimationDriver subclass.
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp anim-slider
+
+ \note Installing the custom animation driver is made optional via the
+ \c animCheckBox check box. This allows comparing the effect of having and
+ not having a custom animation driver installed. In addition, on some
+ platforms (and perhaps depending on the theme), having the custom driver
+ enabled may lead to lags in widget drawing. This is as expected, because if
+ some widget animation (e.g. highlight of a QPushButton or QCheckBox) is
+ managed via \l QPropertyAnimation and similar, then those animation are
+ driven by the same QAnimationDriver, and that does not advance until a new
+ frame is requested by clicking on the buttons.
+
+ Advancing the animations is done before each frame (i.e., before the
+ QQuickRenderControl::beginFrame() call) by simply calling advance():
+
+ \snippet rendercontrol/rendercontrol_rhi/main.cpp anim-step
+
+ \sa QRhi, QQuickRenderControl, QQuickWindow
+*/