aboutsummaryrefslogtreecommitdiffstats
path: root/examples/quick/scenegraph
diff options
context:
space:
mode:
Diffstat (limited to 'examples/quick/scenegraph')
-rw-r--r--examples/quick/scenegraph/CMakeLists.txt5
-rw-r--r--examples/quick/scenegraph/customgeometry/CMakeLists.txt29
-rw-r--r--examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc34
-rw-r--r--examples/quick/scenegraph/custommaterial/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc1
-rw-r--r--examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag22
-rw-r--r--examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsbbin2538 -> 2603 bytes
-rw-r--r--examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsbbin1547 -> 1521 bytes
-rw-r--r--examples/quick/scenegraph/customrendernode/CMakeLists.txt33
-rw-r--r--examples/quick/scenegraph/customrendernode/customrender.cpp189
-rw-r--r--examples/quick/scenegraph/customrendernode/customrender.h7
-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.qdoc128
-rw-r--r--examples/quick/scenegraph/customrendernode/main.cpp28
-rw-r--r--examples/quick/scenegraph/customrendernode/main.qml16
-rw-r--r--examples/quick/scenegraph/customrendernode/shaders/customrender.frag3
-rw-r--r--examples/quick/scenegraph/d3d11underqml/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc1
-rw-r--r--examples/quick/scenegraph/d3d11underqml/squircle.frag3
-rw-r--r--examples/quick/scenegraph/fboitem/CMakeLists.txt46
-rw-r--r--examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpgbin25863 -> 0 bytes
-rw-r--r--examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc12
-rw-r--r--examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp38
-rw-r--r--examples/quick/scenegraph/fboitem/fboinsgrenderer.h19
-rw-r--r--examples/quick/scenegraph/fboitem/fboitem.pro20
-rw-r--r--examples/quick/scenegraph/fboitem/fboitem.qrc6
-rw-r--r--examples/quick/scenegraph/fboitem/main.qml82
-rw-r--r--examples/quick/scenegraph/fboitem/shaders/checker.frag22
-rw-r--r--examples/quick/scenegraph/fboitem/shaders/checker.frag.qsbbin953 -> 0 bytes
-rw-r--r--examples/quick/scenegraph/graph/CMakeLists.txt29
-rw-r--r--examples/quick/scenegraph/graph/doc/src/graph.qdoc1
-rw-r--r--examples/quick/scenegraph/graph/main.cpp2
-rw-r--r--examples/quick/scenegraph/graph/main.qml12
-rw-r--r--examples/quick/scenegraph/graph/shaders/line.frag3
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.frag5
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.frag.qsbbin1763 -> 1760 bytes
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.vert4
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.vert.qsbbin1650 -> 1646 bytes
-rw-r--r--examples/quick/scenegraph/metaltextureimport/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc6
-rw-r--r--examples/quick/scenegraph/metaltextureimport/squircle.frag3
-rw-r--r--examples/quick/scenegraph/metalunderqml/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc1
-rw-r--r--examples/quick/scenegraph/metalunderqml/squircle.frag3
-rw-r--r--examples/quick/scenegraph/openglunderqml/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc2
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.cpp30
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.h2
-rw-r--r--examples/quick/scenegraph/rhitextureitem/CMakeLists.txt77
-rw-r--r--examples/quick/scenegraph/rhitextureitem/SettingsDrawer.qml117
-rw-r--r--examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpgbin0 -> 96428 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc106
-rw-r--r--examples/quick/scenegraph/rhitextureitem/icon_settings.pngbin0 -> 3175 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/icon_settings@2x.pngbin0 -> 6616 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/icon_settings@3x.pngbin0 -> 10083 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/icon_settings@4x.pngbin0 -> 13502 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/main.cpp (renamed from examples/quick/scenegraph/fboitem/main.cpp)12
-rw-r--r--examples/quick/scenegraph/rhitextureitem/main.qml259
-rw-r--r--examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsbbin0 -> 1611 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.frag.qsbbin0 -> 853 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.vert.qsbbin0 -> 1256 bytes
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp141
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.h57
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro16
-rw-r--r--examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc8
-rw-r--r--examples/quick/scenegraph/rhitextureitem/shaders/checker.frag26
-rw-r--r--examples/quick/scenegraph/rhitextureitem/shaders/color.frag13
-rw-r--r--examples/quick/scenegraph/rhitextureitem/shaders/color.vert16
-rw-r--r--examples/quick/scenegraph/rhiunderqml/CMakeLists.txt61
-rw-r--r--examples/quick/scenegraph/rhiunderqml/doc/images/rhiunderqml-example.jpgbin0 -> 35984 bytes
-rw-r--r--examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc236
-rw-r--r--examples/quick/scenegraph/rhiunderqml/main.cpp17
-rw-r--r--examples/quick/scenegraph/rhiunderqml/main.qml39
-rw-r--r--examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.frag.qsbbin0 -> 1537 bytes
-rw-r--r--examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.vert.qsbbin0 -> 1214 bytes
-rw-r--r--examples/quick/scenegraph/rhiunderqml/rhisquircle.cpp224
-rw-r--r--examples/quick/scenegraph/rhiunderqml/rhisquircle.h43
-rw-r--r--examples/quick/scenegraph/rhiunderqml/rhiunderqml.pro11
-rw-r--r--examples/quick/scenegraph/rhiunderqml/rhiunderqml.qrc7
-rw-r--r--examples/quick/scenegraph/scenegraph.pro7
-rw-r--r--examples/quick/scenegraph/shared/logorenderer.cpp219
-rw-r--r--examples/quick/scenegraph/shared/logorenderer.h41
-rw-r--r--examples/quick/scenegraph/shared/squircle_rhi.frag14
-rw-r--r--examples/quick/scenegraph/shared/squircle_rhi.vert7
-rw-r--r--examples/quick/scenegraph/threadedanimation/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/threadedanimation/doc/images/threadedanimation-example.jpgbin0 -> 37409 bytes
-rw-r--r--examples/quick/scenegraph/threadedanimation/doc/src/threadedanimation.qdoc33
-rw-r--r--examples/quick/scenegraph/twotextureproviders/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/twotextureproviders/doc/src/twotextureproviders.qdoc1
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/checker.frag3
-rw-r--r--examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag3
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc3
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/CMakeLists.txt31
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc88
96 files changed, 2126 insertions, 905 deletions
diff --git a/examples/quick/scenegraph/CMakeLists.txt b/examples/quick/scenegraph/CMakeLists.txt
index 834267b46e..19ab9fc73d 100644
--- a/examples/quick/scenegraph/CMakeLists.txt
+++ b/examples/quick/scenegraph/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
qt_internal_add_example(customgeometry)
qt_internal_add_example(custommaterial)
@@ -7,8 +7,9 @@ qt_internal_add_example(graph)
qt_internal_add_example(threadedanimation)
qt_internal_add_example(twotextureproviders)
qt_internal_add_example(customrendernode)
+qt_internal_add_example(rhiunderqml)
+qt_internal_add_example(rhitextureitem)
if(QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3)
- qt_internal_add_example(fboitem)
qt_internal_add_example(openglunderqml)
endif()
if(IOS OR MACOS)
diff --git a/examples/quick/scenegraph/customgeometry/CMakeLists.txt b/examples/quick/scenegraph/customgeometry/CMakeLists.txt
index 5662266f41..14b585aa0d 100644
--- a/examples/quick/scenegraph/customgeometry/CMakeLists.txt
+++ b/examples/quick/scenegraph/customgeometry/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(customgeometry_declarative LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/customgeometry")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick)
qt_standard_project_setup()
@@ -20,9 +14,9 @@ qt_add_executable(customgeometry_declarative WIN32 MACOSX_BUNDLE
)
target_link_libraries(customgeometry_declarative PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Quick
)
qt_add_qml_module(customgeometry_declarative
@@ -33,7 +27,16 @@ qt_add_qml_module(customgeometry_declarative
)
install(TARGETS customgeometry_declarative
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET customgeometry_declarative
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc
index 80ba600a7d..3ac09dd367 100644
--- a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc
+++ b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc
@@ -4,12 +4,13 @@
/*!
\example scenegraph/customgeometry
\title Scene Graph - Custom Geometry
+ \examplecategory {Graphics}
\ingroup qtquickexamples
\brief Shows how to implement a custom geometry in the Qt Quick Scene Graph.
- The custom geometry example shows how to create a QQuickItem which
+ The custom geometry example shows how to create a \l QQuickItem that
uses the scene graph API to build a custom geometry for the scene
- graph. It does this by creating a BezierCurve item which is made
+ graph. It does this by creating a \c BezierCurve item, which is made
part of the CustomGeometry module and makes use of this in a QML
file.
@@ -114,7 +115,7 @@
\snippet scenegraph/customgeometry/beziercurve.cpp 6
The scene graph API provides a few commonly used material
- implementations. In this example we use the QSGFlatColorMaterial
+ implementations. In this example we use the QSGFlatColorMaterial,
which will fill the shape defined by the geometry with a solid
color. Again we pass the ownership of the material to the node, so
it can be cleaned up by the scene graph.
@@ -129,7 +130,7 @@
\snippet scenegraph/customgeometry/beziercurve.cpp 8
- To fill the geometry, we first extract the vertex array from
+ To fill the geometry we first extract the vertex array from
it. Since we are using one of the default attribute sets, we can
use the convenience function QSGGeometry::vertexDataAsPoint2D().
Then we go through each segment and calculate its position and
@@ -137,7 +138,7 @@
\snippet scenegraph/customgeometry/beziercurve.cpp 9
- In the end of the function, we return the node so the scene graph
+ At the end of the function we return the node so the scene graph
can render it.
\section1 Application Entry-Point
@@ -152,9 +153,26 @@
To make use of the BezierCurve item, we need to register it in the QML
engine, using the QML_ELEMENT macro. This gives it the name
BezierCurve and makes it part of the \c {CustomGeometry 1.0}
- module as defined in the customgeometry.pro file:
-
- \quotefile scenegraph/customgeometry/customgeometry.pro
+ module as defined in the project's build files:
+
+ \if defined(onlinedocs)
+ \tab {build-qt-app}{tab-cmake}{CMake}{checked}
+ \tab {build-qt-app}{tab-qmake}{qmake}{}
+ \tabcontent {tab-cmake}
+ \else
+ \section1 Using CMake
+ \endif
+ \quotefile scenegraph/customgeometry/CMakeLists.txt
+ \if defined(onlinedocs)
+ \endtabcontent
+ \tabcontent {tab-qmake}
+ \else
+ \section1 Using qmake
+ \endif
+ \quotefile scenegraph/customgeometry/customgeometry.pro
+ \if defined(onlinedocs)
+ \endtabcontent
+ \endif
As the bezier curve is drawn as line strips, we specify that
the view should be multisampled to get antialiasing. This is not
diff --git a/examples/quick/scenegraph/custommaterial/CMakeLists.txt b/examples/quick/scenegraph/custommaterial/CMakeLists.txt
index eacdd80642..8fe276d248 100644
--- a/examples/quick/scenegraph/custommaterial/CMakeLists.txt
+++ b/examples/quick/scenegraph/custommaterial/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(custommaterial_declarative LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/custommaterial")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
qt_standard_project_setup()
@@ -20,10 +14,10 @@ qt_add_executable(custommaterial_declarative WIN32 MACOSX_BUNDLE
)
target_link_libraries(custommaterial_declarative PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
qt_add_qml_module(custommaterial_declarative
@@ -46,7 +40,16 @@ qt6_add_shaders(custommaterial_declarative "shaders"
)
install(TARGETS custommaterial_declarative
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET custommaterial_declarative
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc b/examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc
index 997db4a88f..2bbcbbe263 100644
--- a/examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc
+++ b/examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc
@@ -4,6 +4,7 @@
/*!
\example scenegraph/custommaterial
\title Scene Graph - Custom Material
+ \examplecategory {Graphics}
\ingroup qtquickexamples
\brief Shows how to implement a custom material in the Qt Quick Scene Graph.
diff --git a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag
index 0e5f63e7a8..72d63bb32c 100644
--- a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag
+++ b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
//! [1]
#version 440
@@ -27,21 +30,30 @@ void main()
c.x = (vTexCoord.x - 0.5) / ubuf.zoom + ubuf.center.x;
c.y = aspect_ratio * (vTexCoord.y - 0.5) / ubuf.zoom + ubuf.center.y;
- int i;
+ int iLast;
z = c;
- for (i = 0; i < ubuf.limit; i++) {
+ for (int i = 0; i < 1000000; i++) {
+ if (i >= ubuf.limit)
+ {
+ iLast = i;
+ break;
+ }
float x = (z.x * z.x - z.y * z.y) + c.x;
float y = (z.y * z.x + z.x * z.y) + c.y;
- if ((x * x + y * y) > 4.0) break;
+ if ((x * x + y * y) > 4.0)
+ {
+ iLast = i;
+ break;
+ }
z.x = x;
z.y = y;
}
- if (i == ubuf.limit) {
+ if (iLast == ubuf.limit) {
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
- float f = (i * 1.0) / ubuf.limit;
+ float f = (iLast * 1.0) / ubuf.limit;
fragColor = mix(color1, color2, sqrt(f));
}
}
diff --git a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb
index 550c0377ae..97ec1c2633 100644
--- a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb
+++ b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb
index ba2904d1c9..37105cfe60 100644
--- a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb
+++ b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/customrendernode/CMakeLists.txt b/examples/quick/scenegraph/customrendernode/CMakeLists.txt
index bff303029a..c00f019839 100644
--- a/examples/quick/scenegraph/customrendernode/CMakeLists.txt
+++ b/examples/quick/scenegraph/customrendernode/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(customrendernode LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/customrendernode")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
qt_standard_project_setup()
@@ -20,10 +14,10 @@ qt_add_executable(customrendernode WIN32 MACOSX_BUNDLE
)
target_link_libraries(customrendernode PRIVATE
- Qt::Core
- Qt::GuiPrivate
- Qt::Qml
- Qt::QuickPrivate
+ Qt6::Core
+ Qt6::GuiPrivate
+ Qt6::Qml
+ Qt6::Quick
)
qt_add_qml_module(customrendernode
@@ -35,6 +29,8 @@ qt_add_qml_module(customrendernode
)
qt6_add_shaders(customrendernode "shaders"
+ # gl_VertexId is in earliest OpenGL ES 3.00, and GLSL 130
+ GLSL "300 es,130"
PREFIX
"/scenegraph/customrendernode"
FILES
@@ -43,7 +39,16 @@ qt6_add_shaders(customrendernode "shaders"
)
install(TARGETS customrendernode
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET customrendernode
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/customrendernode/customrender.cpp b/examples/quick/scenegraph/customrendernode/customrender.cpp
index e95341438e..ff5274c163 100644
--- a/examples/quick/scenegraph/customrendernode/customrender.cpp
+++ b/examples/quick/scenegraph/customrendernode/customrender.cpp
@@ -1,21 +1,20 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "customrender.h"
#include <QSGTextureProvider>
#include <QSGRenderNode>
#include <QSGTransformNode>
-#include <QSGRendererInterface>
#include <QQuickWindow>
#include <QFile>
-#include <private/qrhi_p.h>
-#include <private/qsgrendernode_p.h>
+#include <rhi/qrhi.h>
+
+//![node]
class CustomRenderNode : public QSGRenderNode
{
public:
CustomRenderNode(QQuickWindow *window);
- virtual ~CustomRenderNode();
void setVertices(const QList<QVector2D> &vertices);
@@ -26,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)
@@ -77,148 +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()
{
- QSGRendererInterface *renderInterface = m_window->rendererInterface();
- QRhiSwapChain *swapChain = static_cast<QRhiSwapChain *>(
- renderInterface->getResource(m_window, QSGRendererInterface::RhiSwapchainResource));
- QRhi *rhi = static_cast<QRhi *>(
- renderInterface->getResource(m_window, QSGRendererInterface::RhiResource));
- Q_ASSERT(swapChain);
- Q_ASSERT(rhi);
-
+ QRhi *rhi = m_window->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(QSGRenderNodePrivate::get(this)->m_rt.rt->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(QSGRenderNodePrivate::get(this)->m_rt.rpDesc);
- 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);
}
-void CustomRenderNode::render(const RenderState *state)
+//![node-render]
+void CustomRenderNode::render(const RenderState *)
{
-
- QSGRendererInterface *renderInterface = m_window->rendererInterface();
- QRhiSwapChain *swapChain = static_cast<QRhiSwapChain *>(
- renderInterface->getResource(m_window, QSGRendererInterface::RhiSwapchainResource));
- Q_ASSERT(swapChain);
-
- QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
- Q_ASSERT(cb);
-
- cb->setGraphicsPipeline(m_pipeLine);
- QSize renderTargetSize = QSGRenderNodePrivate::get(this)->m_rt.rt->pixelSize();
+ 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;
}
@@ -232,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);
@@ -243,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 962551c0b1..530e692678 100644
--- a/examples/quick/scenegraph/customrendernode/customrender.h
+++ b/examples/quick/scenegraph/customrendernode/customrender.h
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CUSTOMRENDER_H
#define 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 1972d99c4d..3e3dd7d023 100644
--- a/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
+++ b/examples/quick/scenegraph/customrendernode/doc/src/customrendernode.qdoc
@@ -4,23 +4,125 @@
/*!
\example scenegraph/customrendernode
\title Scene Graph - Custom QSGRenderNode
+ \examplecategory {Graphics}
\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
- QSGRenderNode allows direct access to the Render Hardware Interface (RHI) within the
- scenegraph. This example demonstrates how to create QSGRenderNode based render node
- and manage it with a custom item. The render node creates an RHI pipeline, updates
- vertex and uniform buffers, and renders into the RHI command buffer.
+ \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>}.
- \warning This example demonstrates advanced, low-level functionality
- performing portable, cross-platform 3D rendering, while relying on private
- APIs from the Qt Gui and Qt Quick modules. Developers are encouraged to
- carefully evaluate the potential lack of source and binary compatibility
- guarantees before using these APIs in their applications.
+ QSGRenderNode allows direct access to the Render Hardware Interface (RHI)
+ within the scenegraph. This example demonstrates how to create QSGRenderNode
+ based render node and manage it with a custom item. The render node creates
+ an RHI pipeline, updates vertex and uniform buffers, and renders into the
+ RHI command buffer.
- */
+ In practice this is a portable, cross-platform approach to perform custom
+ rendering inline with the scenegraph's own rendering, without resorting to a
+ native 3D API such as OpenGL, Metal, or Vulkan. Rather, the application uses
+ Qt's graphics and shader abstraction layer.
+
+ 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.
+
+ 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 5cc870b1aa..0ad93ec1de 100644
--- a/examples/quick/scenegraph/customrendernode/main.cpp
+++ b/examples/quick/scenegraph/customrendernode/main.cpp
@@ -1,12 +1,15 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// 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 5c9bc240ad..6a098e47f7 100644
--- a/examples/quick/scenegraph/customrendernode/main.qml
+++ b/examples/quick/scenegraph/customrendernode/main.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick.Controls
@@ -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
@@ -103,6 +102,11 @@ Item {
}
+ Button {
+ text: qsTr("Toggle custom item visibility")
+ onClicked: custom.visible = !custom.visible
+ }
+
CustomRender {
id: custom
width: Math.min(parent.width, parent.height)
diff --git a/examples/quick/scenegraph/customrendernode/shaders/customrender.frag b/examples/quick/scenegraph/customrendernode/shaders/customrender.frag
index 5d284b7696..d9586ba90e 100644
--- a/examples/quick/scenegraph/customrendernode/shaders/customrender.frag
+++ b/examples/quick/scenegraph/customrendernode/shaders/customrender.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#version 440
layout(location = 0) in vec3 color;
diff --git a/examples/quick/scenegraph/d3d11underqml/CMakeLists.txt b/examples/quick/scenegraph/d3d11underqml/CMakeLists.txt
index 2a08c39d59..dec029d8da 100644
--- a/examples/quick/scenegraph/d3d11underqml/CMakeLists.txt
+++ b/examples/quick/scenegraph/d3d11underqml/CMakeLists.txt
@@ -1,17 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(d3d11underqml LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/d3d11underqml")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_add_executable(d3d11underqml
@@ -25,10 +19,10 @@ set_target_properties(d3d11underqml PROPERTIES
)
target_link_libraries(d3d11underqml PUBLIC
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
d3d11
d3dcompiler
)
@@ -45,7 +39,16 @@ qt_add_qml_module(d3d11underqml
)
install(TARGETS d3d11underqml
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET d3d11underqml
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
index 944d9de611..3d5a171d49 100644
--- a/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
+++ b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
@@ -4,6 +4,7 @@
/*!
\example scenegraph/d3d11underqml
\title Scene Graph - Direct3D 11 Under QML
+ \examplecategory {Graphics}
\ingroup qtquickexamples
\brief Shows how to render directly with Direct3D 11 under a Qt Quick scene.
diff --git a/examples/quick/scenegraph/d3d11underqml/squircle.frag b/examples/quick/scenegraph/d3d11underqml/squircle.frag
index a907c84e58..713b2d89f2 100644
--- a/examples/quick/scenegraph/d3d11underqml/squircle.frag
+++ b/examples/quick/scenegraph/d3d11underqml/squircle.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cbuffer buf : register(b0)
{
float ubuf_t : packoffset(c0);
diff --git a/examples/quick/scenegraph/fboitem/CMakeLists.txt b/examples/quick/scenegraph/fboitem/CMakeLists.txt
deleted file mode 100644
index f3fbce11aa..0000000000
--- a/examples/quick/scenegraph/fboitem/CMakeLists.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
-
-cmake_minimum_required(VERSION 3.16)
-project(fboitem LANGUAGES CXX)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/fboitem")
-
-find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
-
-qt_standard_project_setup()
-
-qt_add_executable(fboitem WIN32 MACOSX_BUNDLE
- ../shared/logorenderer.cpp ../shared/logorenderer.h
- fboinsgrenderer.cpp fboinsgrenderer.h
- main.cpp
-)
-
-target_include_directories(fboitem PUBLIC
- ../shared
-)
-
-target_link_libraries(fboitem PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
-)
-
-qt_add_qml_module(fboitem
- URI SceneGraphRendering
- QML_FILES main.qml
- RESOURCES shaders/checker.frag.qsb
- RESOURCE_PREFIX /scenegraph/fboitem
- NO_RESOURCE_TARGET_PATH
-)
-
-install(TARGETS fboitem
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
-)
diff --git a/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg b/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg
deleted file mode 100644
index 306b8bab20..0000000000
--- a/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg
+++ /dev/null
Binary files differ
diff --git a/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc b/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc
deleted file mode 100644
index daa784bf79..0000000000
--- a/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \example scenegraph/fboitem
- \title Scene Graph - Rendering FBOs
- \ingroup qtquickexamples
-
- \brief Shows how to use FramebufferObjects with Qt Quick.
-
- \image fboitem-example.jpg
- */
diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp b/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp
deleted file mode 100644
index e4c0e61843..0000000000
--- a/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#include "fboinsgrenderer.h"
-#include "logorenderer.h"
-
-#include <QOpenGLFramebufferObject>
-
-#include <QtQuick/QQuickWindow>
-#include <qsgsimpletexturenode.h>
-
-class LogoInFboRenderer : public QQuickFramebufferObject::Renderer
-{
-public:
- LogoInFboRenderer()
- {
- logo.initialize();
- }
-
- void render() override {
- logo.render();
- update();
- }
-
- QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override {
- QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
- format.setSamples(4);
- return new QOpenGLFramebufferObject(size, format);
- }
-
- LogoRenderer logo;
-};
-
-QQuickFramebufferObject::Renderer *FboInSGRenderer::createRenderer() const
-{
- return new LogoInFboRenderer();
-}
diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
deleted file mode 100644
index c6eb745d5f..0000000000
--- a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#ifndef FBOINSGRENDERER_H
-#define FBOINSGRENDERER_H
-
-#include <QtQuick/QQuickFramebufferObject>
-
-class LogoRenderer;
-
-class FboInSGRenderer : public QQuickFramebufferObject
-{
- Q_OBJECT
- QML_NAMED_ELEMENT(Renderer)
-public:
- Renderer *createRenderer() const;
-};
-
-#endif
diff --git a/examples/quick/scenegraph/fboitem/fboitem.pro b/examples/quick/scenegraph/fboitem/fboitem.pro
deleted file mode 100644
index 180c2288e2..0000000000
--- a/examples/quick/scenegraph/fboitem/fboitem.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-QT += qml quick
-
-CONFIG += qmltypes
-QML_IMPORT_NAME = SceneGraphRendering
-QML_IMPORT_MAJOR_VERSION = 1
-
-HEADERS += fboinsgrenderer.h
-SOURCES += fboinsgrenderer.cpp main.cpp
-
-INCLUDEPATH += ../shared
-HEADERS += ../shared/logorenderer.h
-SOURCES += ../shared/logorenderer.cpp
-
-RESOURCES += fboitem.qrc
-
-target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/fboitem
-INSTALLS += target
-
-OTHER_FILES += \
- main.qml
diff --git a/examples/quick/scenegraph/fboitem/fboitem.qrc b/examples/quick/scenegraph/fboitem/fboitem.qrc
deleted file mode 100644
index 1782429798..0000000000
--- a/examples/quick/scenegraph/fboitem/fboitem.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource prefix="/scenegraph/fboitem">
- <file>main.qml</file>
- <file>shaders/checker.frag.qsb</file>
- </qresource>
-</RCC>
diff --git a/examples/quick/scenegraph/fboitem/main.qml b/examples/quick/scenegraph/fboitem/main.qml
deleted file mode 100644
index db2df19197..0000000000
--- a/examples/quick/scenegraph/fboitem/main.qml
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-import QtQuick
-
-import SceneGraphRendering
-
-Item {
- width: 400
- height: 400
-
- // The checkers background
- ShaderEffect {
- id: tileBackground
- anchors.fill: parent
-
- property real tileSize: 16
- property color color1: Qt.rgba(0.9, 0.9, 0.9, 1);
- property color color2: Qt.rgba(0.85, 0.85, 0.85, 1);
-
- property size pixelSize: Qt.size(width / tileSize, height / tileSize);
-
- fragmentShader: "qrc:/scenegraph/fboitem/shaders/checker.frag.qsb"
- }
-
- Renderer {
- id: renderer
- anchors.fill: parent
- anchors.margins: 10
-
- // The transform is just to show something interesting..
- transform: [
- Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; },
- Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 },
- Scale { id: scale; },
- Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 }
- ]
- }
-
- // Just to show something interesting
- SequentialAnimation {
- PauseAnimation { duration: 5000 }
- ParallelAnimation {
- NumberAnimation { target: scale; property: "xScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack }
- NumberAnimation { target: scale; property: "yScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack }
- }
- NumberAnimation { target: rotation; property: "angle"; to: 80; duration: 1000; easing.type: Easing.InOutCubic }
- NumberAnimation { target: rotation; property: "angle"; to: -80; duration: 1000; easing.type: Easing.InOutCubic }
- NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 1000; easing.type: Easing.InOutCubic }
- NumberAnimation { target: renderer; property: "opacity"; to: 0.5; duration: 1000; easing.type: Easing.InOutCubic }
- PauseAnimation { duration: 1000 }
- NumberAnimation { target: renderer; property: "opacity"; to: 0.8; duration: 1000; easing.type: Easing.InOutCubic }
- ParallelAnimation {
- NumberAnimation { target: scale; property: "xScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack }
- NumberAnimation { target: scale; property: "yScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack }
- }
- running: true
- loops: Animation.Infinite
- }
-
- Rectangle {
- id: labelFrame
- anchors.margins: -10
- radius: 5
- color: "white"
- border.color: "black"
- opacity: 0.8
- anchors.fill: label
- }
-
- Text {
- id: label
- anchors.bottom: renderer.bottom
- anchors.left: renderer.left
- anchors.right: renderer.right
- anchors.margins: 20
- wrapMode: Text.WordWrap
- text: qsTr("The blue rectangle with the vintage 'Q' is an FBO, rendered by the application on the scene graph rendering thread. The FBO is managed and displayed using the QQuickFramebufferObject convenience class.")
- }
-
-
-}
diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag b/examples/quick/scenegraph/fboitem/shaders/checker.frag
deleted file mode 100644
index 1e4131d026..0000000000
--- a/examples/quick/scenegraph/fboitem/shaders/checker.frag
+++ /dev/null
@@ -1,22 +0,0 @@
-#version 440
-
-layout(std140, binding = 0) uniform buf {
- mat4 qt_Matrix;
- float qt_Opacity;
-
- vec4 color1;
- vec4 color2;
- vec2 pixelSize;
-} ubuf;
-
-layout(location = 0) in vec2 qt_TexCoord0;
-layout(location = 0) out vec4 fragColor;
-
-void main()
-{
- vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * ubuf.pixelSize));
- if (tc.x != tc.y)
- fragColor = ubuf.color1;
- else
- fragColor = ubuf.color2;
-}
diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb b/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb
deleted file mode 100644
index 77cbf0b867..0000000000
--- a/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb
+++ /dev/null
Binary files differ
diff --git a/examples/quick/scenegraph/graph/CMakeLists.txt b/examples/quick/scenegraph/graph/CMakeLists.txt
index fee1e498d7..36d8c34f19 100644
--- a/examples/quick/scenegraph/graph/CMakeLists.txt
+++ b/examples/quick/scenegraph/graph/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(graph LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/graph")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick)
qt_standard_project_setup()
@@ -28,9 +22,9 @@ set_target_properties(graph PROPERTIES
)
target_link_libraries(graph PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Quick
)
qt_add_qml_module(graph
@@ -47,7 +41,16 @@ qt_add_qml_module(graph
)
install(TARGETS graph
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET graph
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/graph/doc/src/graph.qdoc b/examples/quick/scenegraph/graph/doc/src/graph.qdoc
index fb9dc08357..a76652498c 100644
--- a/examples/quick/scenegraph/graph/doc/src/graph.qdoc
+++ b/examples/quick/scenegraph/graph/doc/src/graph.qdoc
@@ -4,6 +4,7 @@
/*!
\example scenegraph/graph
\title Scene Graph - Graph
+ \examplecategory {Graphics}
\ingroup qtquickexamples
\brief Demonstrates how one can combine custom materials and geometries
diff --git a/examples/quick/scenegraph/graph/main.cpp b/examples/quick/scenegraph/graph/main.cpp
index 1b56c03daf..7070196a79 100644
--- a/examples/quick/scenegraph/graph/main.cpp
+++ b/examples/quick/scenegraph/graph/main.cpp
@@ -9,8 +9,6 @@
int main(int argc, char *argv[])
{
- qputenv("QSG_RHI", "1"); // ### Qt 6 remove, this will be the default anyway
-
QGuiApplication a(argc, argv);
QQuickView view;
diff --git a/examples/quick/scenegraph/graph/main.qml b/examples/quick/scenegraph/graph/main.qml
index e9b684c3ba..5f2abbbd58 100644
--- a/examples/quick/scenegraph/graph/main.qml
+++ b/examples/quick/scenegraph/graph/main.qml
@@ -15,27 +15,23 @@ Item {
anchors.margins: 100
function newSample(i) {
- return (Math.sin(i / 100.0 * Math.PI * 2) + 1) * 0.4 + Math.random() * 0.05;
+ return (Math.sin(i / 200.0 * Math.PI * 2) + 1) * 0.4 + Math.random() * 0.05;
}
Component.onCompleted: {
- for (var i=0; i<100; ++i)
+ for (var i=0; i<graph.offset; ++i)
appendSample(newSample(i));
}
- property int offset: 100;
+ property int offset: 200
}
- Timer {
- id: timer
- interval: 500
- repeat: true
+ FrameAnimation {
running: true
onTriggered: {
graph.removeFirstSample();
graph.appendSample(graph.newSample(++graph.offset));
}
-
}
Rectangle {
diff --git a/examples/quick/scenegraph/graph/shaders/line.frag b/examples/quick/scenegraph/graph/shaders/line.frag
index 44b5b24c94..b9531cede6 100644
--- a/examples/quick/scenegraph/graph/shaders/line.frag
+++ b/examples/quick/scenegraph/graph/shaders/line.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#version 440
layout(location = 0) in float vT;
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.frag b/examples/quick/scenegraph/graph/shaders/noisy.frag
index 8cea9de02b..0f13b83fd4 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.frag
+++ b/examples/quick/scenegraph/graph/shaders/noisy.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#version 440
layout(location = 0) in vec2 vTexCoord;
@@ -8,7 +11,7 @@ layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
vec4 color;
- vec2 textureSize;
+ vec2 texCoordScale;
float qt_Opacity;
};
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb b/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb
index 1a49e93cf3..dd1739b1fe 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb
+++ b/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.vert b/examples/quick/scenegraph/graph/shaders/noisy.vert
index 5728f2a02f..057f1c8d16 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.vert
+++ b/examples/quick/scenegraph/graph/shaders/noisy.vert
@@ -9,7 +9,7 @@ layout(location = 1) out vec2 vShadeCoord;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
vec4 color;
- vec2 textureSize;
+ vec2 texCoordScale;
float qt_Opacity;
};
@@ -17,6 +17,6 @@ out gl_PerVertex { vec4 gl_Position; };
void main() {
gl_Position = qt_Matrix * aVertex;
- vTexCoord = aVertex.xy * textureSize;
+ vTexCoord = aVertex.xy * texCoordScale;
vShadeCoord = aTexCoord;
}
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb b/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb
index ce2a828ead..9de384e3a6 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb
+++ b/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/metaltextureimport/CMakeLists.txt b/examples/quick/scenegraph/metaltextureimport/CMakeLists.txt
index 70cb10dc6a..f76489116a 100644
--- a/examples/quick/scenegraph/metaltextureimport/CMakeLists.txt
+++ b/examples/quick/scenegraph/metaltextureimport/CMakeLists.txt
@@ -1,17 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(metaltextureimport LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/metaltextureimport")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_add_executable(metaltextureimport
@@ -29,10 +23,10 @@ set_target_properties(metaltextureimport PROPERTIES
target_link_libraries(metaltextureimport PUBLIC
"-framework Metal"
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
if(MACOS)
@@ -53,7 +47,16 @@ qt_add_qml_module(metaltextureimport
)
install(TARGETS metaltextureimport
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET metaltextureimport
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc b/examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc
index e8383c7cf8..3b4912829e 100644
--- a/examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc
+++ b/examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc
@@ -4,6 +4,7 @@
/*!
\example scenegraph/metaltextureimport
\title Scene Graph - Metal Texture Import
+ \examplecategory {Graphics}
\ingroup qtquickexamples
\brief Shows how to use a texture created directly with Metal.
@@ -63,9 +64,8 @@
After copying the values we need, sync() also performs some graphics
resource initialization. The MTLDevice is queried from the scenegraph. Once
a MTLTexture is available, a QSGTexture wrapping (not owning) it is created
- via QQuickWindow::createTextureFromNativeObject(). This function is a
- modern equivalent to QQuickWindow::createTextureFromId() that is not tied
- to OpenGL. Finally, the QSGTexture is associated with the underlying
+ via \l QNativeInterface::QSGOpenGLTexture::fromNative().
+ Finally, the QSGTexture is associated with the underlying
materials by calling the base class' setTexture() function.
\snippet scenegraph/metaltextureimport/metaltextureimport.mm 6
diff --git a/examples/quick/scenegraph/metaltextureimport/squircle.frag b/examples/quick/scenegraph/metaltextureimport/squircle.frag
index 15f34624fe..8303e97006 100644
--- a/examples/quick/scenegraph/metaltextureimport/squircle.frag
+++ b/examples/quick/scenegraph/metaltextureimport/squircle.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#include <metal_stdlib>
#include <simd/simd.h>
diff --git a/examples/quick/scenegraph/metalunderqml/CMakeLists.txt b/examples/quick/scenegraph/metalunderqml/CMakeLists.txt
index 9bd54c637e..21c7b5c763 100644
--- a/examples/quick/scenegraph/metalunderqml/CMakeLists.txt
+++ b/examples/quick/scenegraph/metalunderqml/CMakeLists.txt
@@ -1,17 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(metalunderqml LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/metalunderqml")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_add_executable(metalunderqml
@@ -26,10 +20,10 @@ set_target_properties(metalunderqml PROPERTIES
target_link_libraries(metalunderqml PUBLIC
"-framework Metal"
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
if(MACOS)
@@ -50,7 +44,16 @@ qt_add_qml_module(metalunderqml
)
install(TARGETS metalunderqml
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET metalunderqml
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
index b8e3750271..fa41ca489f 100644
--- a/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
+++ b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
@@ -4,6 +4,7 @@
/*!
\example scenegraph/metalunderqml
\title Scene Graph - Metal Under QML
+ \examplecategory {Graphics}
\ingroup qtquickexamples
\brief Shows how to render directly with Metal under a Qt Quick scene.
diff --git a/examples/quick/scenegraph/metalunderqml/squircle.frag b/examples/quick/scenegraph/metalunderqml/squircle.frag
index 15f34624fe..8303e97006 100644
--- a/examples/quick/scenegraph/metalunderqml/squircle.frag
+++ b/examples/quick/scenegraph/metalunderqml/squircle.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#include <metal_stdlib>
#include <simd/simd.h>
diff --git a/examples/quick/scenegraph/openglunderqml/CMakeLists.txt b/examples/quick/scenegraph/openglunderqml/CMakeLists.txt
index cd64bb6172..8a95221811 100644
--- a/examples/quick/scenegraph/openglunderqml/CMakeLists.txt
+++ b/examples/quick/scenegraph/openglunderqml/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(openglunderqml LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/openglunderqml")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_standard_project_setup()
@@ -26,10 +20,10 @@ set_target_properties(openglunderqml PROPERTIES
)
target_link_libraries(openglunderqml PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
qt_add_qml_module(openglunderqml
@@ -40,7 +34,16 @@ qt_add_qml_module(openglunderqml
)
install(TARGETS openglunderqml
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET openglunderqml
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
index 317c824d06..aba95b471a 100644
--- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
+++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
@@ -4,7 +4,9 @@
/*!
\example scenegraph/openglunderqml
\title Scene Graph - OpenGL Under QML
+ \examplecategory {Graphics}
\ingroup qtquickexamples
+ \examplecategory {Mobile}
\brief Shows how to render OpenGL under a Qt Quick scene.
\image openglunderqml-example.jpg
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp
index 13f3075a28..98a004ee80 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.cpp
+++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp
@@ -94,6 +94,15 @@ void SquircleRenderer::init()
initializeOpenGLFunctions();
+ const float values[] = { -1, -1, 1, -1, -1, 1, 1, 1 };
+
+ m_vbo.create();
+ m_vbo.bind();
+ m_vbo.allocate(values, sizeof(values));
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
+
m_program = new QOpenGLShaderProgram();
m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 vertices;"
@@ -125,23 +134,12 @@ void SquircleRenderer::paint()
// OpenGL directly.
m_window->beginExternalCommands();
+ m_vbo.bind();
m_program->bind();
+ m_program->setUniformValue("t", (float)m_t);
- m_program->enableAttributeArray(0);
-
- float values[] = {
- -1, -1,
- 1, -1,
- -1, 1,
- 1, 1
- };
-
- // This example relies on (deprecated) client-side pointers for the vertex
- // input. Therefore, we have to make sure no vertex buffer is bound.
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- m_program->setAttributeArray(0, GL_FLOAT, values, 2);
- m_program->setUniformValue("t", (float) m_t);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
@@ -152,7 +150,7 @@ void SquircleRenderer::paint()
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- m_program->disableAttributeArray(0);
+ glDisableVertexAttribArray(0);
m_program->release();
m_window->endExternalCommands();
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h
index 2112d658b0..e59e7882c8 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.h
+++ b/examples/quick/scenegraph/openglunderqml/squircle.h
@@ -8,6 +8,7 @@
#include <QtQuick/QQuickWindow>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
+#include <QOpenGLBuffer>
@@ -31,6 +32,7 @@ private:
qreal m_t = 0.0;
QOpenGLShaderProgram *m_program = nullptr;
QQuickWindow *m_window = nullptr;
+ QOpenGLBuffer m_vbo;
};
//! [1]
diff --git a/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt b/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt
new file mode 100644
index 0000000000..9440c7b25b
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt
@@ -0,0 +1,77 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(rhitextureitem LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
+
+qt_standard_project_setup()
+
+qt_add_executable(rhitextureitem WIN32 MACOSX_BUNDLE
+ rhitextureitem.cpp rhitextureitem.h
+ main.cpp
+)
+
+target_include_directories(rhitextureitem PUBLIC
+ ../shared
+)
+
+target_link_libraries(rhitextureitem PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::GuiPrivate
+ Qt6::Qml
+ Qt6::Quick
+)
+
+qt_add_qml_module(rhitextureitem
+ URI
+ SceneGraphRendering
+ QML_FILES
+ main.qml
+ SettingsDrawer.qml
+ RESOURCE_PREFIX
+ /scenegraph/rhitextureitem
+ RESOURCES
+ icon_settings.png
+ icon_settings@2x.png
+ icon_settings@3x.png
+ icon_settings@4x.png
+ NO_RESOURCE_TARGET_PATH
+)
+
+qt_add_shaders(rhitextureitem "rhitextureitem_shaders"
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ /scenegraph/rhitextureitem
+ FILES
+ shaders/color.vert
+ shaders/color.frag
+)
+
+qt_add_shaders(rhitextureitem "rhitextureitem_effect_shaders"
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ /scenegraph/rhitextureitem
+ FILES
+ shaders/checker.frag
+)
+
+install(TARGETS rhitextureitem
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET rhitextureitem
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
+)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/rhitextureitem/SettingsDrawer.qml b/examples/quick/scenegraph/rhitextureitem/SettingsDrawer.qml
new file mode 100644
index 0000000000..2b7e146c43
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/SettingsDrawer.qml
@@ -0,0 +1,117 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+Page {
+ id: settingsDrawer
+ default property alias content: contentLayout.children
+ required property bool isLandscape
+ readonly property bool isMobile: Qt.platform.os === "android" || Qt.platform.os === "ios"
+ property bool isOpen: isMobile ? false : true
+
+ title: "Settings"
+
+ onIsLandscapeChanged: updateState();
+ Component.onCompleted: updateState();
+ onIsOpenChanged: updateState();
+ x: 0
+ y: 0
+
+ function updateState() {
+ if (isOpen)
+ if (isLandscape)
+ settingsDrawer.state = "Landscape_Visible"
+ else
+ settingsDrawer.state = "Portrait_Visible"
+ else
+ if (isLandscape)
+ settingsDrawer.state = "Landscape_Hidden"
+ else
+ settingsDrawer.state = "Portrait_Hidden"
+ }
+
+ states: [
+ State {
+ name: "Landscape_Visible"
+ PropertyChanges {
+ settingsDrawer.x: 0
+ }
+ },
+ State {
+ name: "Landscape_Hidden"
+ PropertyChanges {
+ settingsDrawer.x: -settingsDrawer.width
+ }
+ },
+ State {
+ name: "Portrait_Visible"
+ PropertyChanges {
+ settingsDrawer.y: 0
+ }
+ },
+ State {
+ name: "Portrait_Hidden"
+ PropertyChanges {
+ settingsDrawer.y: -settingsDrawer.height
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Landscape_Visible"
+ to: "Landscape_Hidden"
+ NumberAnimation {
+ duration: 400
+ property: "x"
+ easing.type: Easing.InOutQuad
+ }
+ },
+ Transition {
+ from: "Landscape_Hidden"
+ to: "Landscape_Visible"
+ NumberAnimation {
+ duration: 400
+ property: "x"
+ easing.type: Easing.InOutQuad
+ }
+ },
+ Transition {
+ from: "Portrait_Visible"
+ to: "Portrait_Hidden"
+ NumberAnimation {
+ duration: 400
+ property: "y"
+ easing.type: Easing.InOutQuad
+ }
+ },
+ Transition {
+ from: "Portrait_Hidden"
+ to: "Portrait_Visible"
+ NumberAnimation {
+ duration: 400
+ property: "y"
+ easing.type: Easing.InOutQuad
+ }
+ }
+ ]
+
+ header: Label {
+ text: settingsDrawer.title
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pointSize: 20
+ }
+
+ ScrollView {
+ anchors.fill: parent
+ padding: 10
+
+ ColumnLayout {
+ id: contentLayout
+ }
+ }
+}
diff --git a/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg b/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg
new file mode 100644
index 0000000000..909d0619fe
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc
new file mode 100644
index 0000000000..ee4031a7d9
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc
@@ -0,0 +1,106 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example scenegraph/rhitextureitem
+ \title Scene Graph - RHI Texture Item
+ \examplecategory {Graphics}
+ \ingroup qtquickexamples
+
+ \brief Shows how to implement a custom QQuickItem that displays a QRhi-rendered texture.
+
+ \image rhitextureitem-example.jpg
+
+ This example shows how to implement an item that performs cross-platform,
+ portable 3D rendering into a texture using the QRhi APIs and then displays
+ that image.
+
+ \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>}.
+
+ \section2 Comparison with other approaches
+
+ The \l{Scene Graph - RHI Under QML}{RHI Under QML} example shows how to
+ implement portable, cross-platform 3D rendering with the \l QRhi APIs in a
+ manner where the custom rendering is issued before the Qt Quick scene
+ graph's own rendering, effectively providing an "underlay". That approach
+ is efficient since now additional render targets and render passes are
+ needed, the custom rendering is injected in the main render pass before the
+ scene graph's own draw calls.
+
+ In contrast, this example involves a separate render target, a QRhiTexture,
+ the \l{QRhiTexture::pixelSize()}{dimensions} of which match the
+ QQuickItem's size in the scene, and a whole render pass that is used to
+ clear and then draw into that texture. The texture is then sampled in the
+ main render pass and is used to texture a quad, effectively displaying a 2D
+ image.
+
+ Compared to the underlay/overlay approach, this allows displaying,
+ blending, and transforming the flattened 2D image of the 3D rendering
+ anywhere in the Qt Quick scene since here we have a true QQuickItem. This
+ comes at the expense of being more expensive in terms of resources and
+ performance since it involves rendering to a texture first.
+
+ \section2 Overview
+
+ The example is implemented using \l QQuickRhiItem and
+ \l QQuickRhiItemRenderer. QQuickRhiItem is a convenience class that can be
+ subclassed to easily and quickly get a fully featured, custom QQuickItem that
+ displays the contents of a QRhiTexture by using QSGSimpleTextureNode under the
+ hood. The contents of the texture is generated by the application-provided
+ logic implemented in its QQuickRhiItemRenderer subclass.
+
+ \c ExampleRhiItem is a QQuickRhiItem subclass that offers a few properties,
+ such as \c angle and \c backgroundAlpha. These are going to be read,
+ written, and animated from QML. In order to support Qt Quick's threaded
+ rendering model, the QQQuickRhiItemRenderer has a virtual
+ \l{QQuickRhiItemRenderer::synchronize()}{synchronize()} function that can
+ be reimplemented to safely perform copying of data between the
+ QQuickRhiItem (belonging to the main/GUI thread) and the
+ QQuickRhiItemRenderer (belonging to the render thread, if there is one).
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp 0
+
+ \l{QQuickRhiItemRenderer::initialize()}{initialize()} is called at least
+ once before the first call to render(), but may in practice be invoked
+ multiple times: if the QQuickItem geometry changes (due to some layout
+ change, resizing the window, etc.), if QQuickRhiItem setting such as the
+ sample count and texture format change, or if the item is reparented so
+ that is belong to a new QQuickWindow, these all trigger calling
+ initialize() again because they imply that one or more of the resources
+ QQuickRhiItem-managed resources change, which is going to have implications
+ on the subclass as well. The example code here is prepared to handle these
+ special situations (changing QRhi, changing sample count, changing texture
+ format). (as it does not hold on to the texture used as the color buffer,
+ the case when the texture is recreated due to a different size needs no
+ special handling)
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp 1
+
+ The rest if initialize() is straightforward QRhi-based code.
+
+ The 3D scene uses a perspective projection, which is calculated based on
+ the output size, queried from the QRhiRenderTarget for convenience (because
+ this works regardless of using multisampling or not, whereas accessing
+ \l{QQuickRhiItemRenderer::colorTexture()}{colorTexture()} and
+ \l{QQuickRhiItemRenderer::msaaColorBuffer()}{msaaColorBuffer()} would need
+ branching logic based on which of the objects happens to be valid)
+
+ Note the usage of \l QRhi::clipSpaceCorrMatrix() to cater for the
+ coordinate system differences between 3D graphics APIs.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp 2
+
+ The implementation of \l{QQuickRhiItemRenderer::render()}{render()} records
+ the drawing of a single triangle. The uniform buffer with the 4x4 matrix is
+ updated every time since we expect the rotation angle to change. The clear
+ color has the item-provided background alpha baked in. Remember the need to
+ premultiply the alpha value in the red, green, and blue components as well.
+
+ \snippet scenegraph/rhitextureitem/rhitextureitem.cpp 3
+
+ \sa QQuickRhiItem, {Scene Graph - RHI Under QML}, {Scene Graph - Custom QSGRenderNode}
+ */
diff --git a/examples/quick/scenegraph/rhitextureitem/icon_settings.png b/examples/quick/scenegraph/rhitextureitem/icon_settings.png
new file mode 100644
index 0000000000..943316040d
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/icon_settings.png
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/icon_settings@2x.png b/examples/quick/scenegraph/rhitextureitem/icon_settings@2x.png
new file mode 100644
index 0000000000..b3dbf8fa28
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/icon_settings@2x.png
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/icon_settings@3x.png b/examples/quick/scenegraph/rhitextureitem/icon_settings@3x.png
new file mode 100644
index 0000000000..0532debcfc
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/icon_settings@3x.png
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/icon_settings@4x.png b/examples/quick/scenegraph/rhitextureitem/icon_settings@4x.png
new file mode 100644
index 0000000000..3b6df374dc
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/icon_settings@4x.png
Binary files differ
diff --git a/examples/quick/scenegraph/fboitem/main.cpp b/examples/quick/scenegraph/rhitextureitem/main.cpp
index bbf3805002..5092552691 100644
--- a/examples/quick/scenegraph/fboitem/main.cpp
+++ b/examples/quick/scenegraph/rhitextureitem/main.cpp
@@ -1,21 +1,17 @@
-// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
-
-#include <QtQuick/QQuickView>
-
-#include "fboinsgrenderer.h"
+#include <QQuickView>
+#include "rhitextureitem.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
-
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
- view.setSource(QUrl("qrc:///scenegraph/fboitem/main.qml"));
+ view.setSource(QUrl("qrc:///scenegraph/rhitextureitem/main.qml"));
view.show();
return QGuiApplication::exec();
diff --git a/examples/quick/scenegraph/rhitextureitem/main.qml b/examples/quick/scenegraph/rhitextureitem/main.qml
new file mode 100644
index 0000000000..dc386d2cf2
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/main.qml
@@ -0,0 +1,259 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import SceneGraphRendering
+
+Item {
+ width: 800
+ height: 600
+
+ // The checkers background
+ ShaderEffect {
+ id: tileBackground
+ anchors.fill: parent
+
+ property real tileSize: 16
+ property color color1: Qt.rgba(0.9, 0.9, 0.9, 1);
+ property color color2: Qt.rgba(0.85, 0.85, 0.85, 1);
+
+ property size pixelSize: Qt.size(width / tileSize, height / tileSize);
+
+ fragmentShader: "qrc:/scenegraph/rhitextureitem/shaders/checker.frag.qsb"
+ }
+
+ //! [0]
+ ExampleRhiItem {
+ id: renderer
+ anchors.fill: parent
+ anchors.margins: 10
+
+ mirrorVertically: cbMirror.checked
+ sampleCount: cbMSAA.checked ? 4 : 1
+ fixedColorBufferWidth: cbSize.checked ? slSize.value.toFixed(0) : 0
+ fixedColorBufferHeight: cbSize.checked ? slSize.value.toFixed(0) : 0
+ alphaBlending: cbBlend.checked
+ colorBufferFormat: rdFormatRGBA8.checked ? ExampleRhiItem.TextureFormat.RGBA8
+ : rdFormatFP16.checked ? ExampleRhiItem.TextureFormat.RGBA16F
+ : rdFormatFP32.checked ? ExampleRhiItem.TextureFormat.RGBA32F
+ : ExampleRhiItem.TextureFormat.RGB10A2
+
+ // custom properties provided by the QQuickRhiItem subclass: angle, backgroundAlpha
+ NumberAnimation on angle {
+ from: 0
+ to: 360
+ duration: 5000
+ loops: Animation.Infinite
+ running: cbAnimate.checked
+ }
+
+ backgroundAlpha: slAlpha.value
+ //! [0]
+
+ // The transform is just to show something interesting..
+ transform: [
+ Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; },
+ Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 },
+ Scale { id: scale; },
+ Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 }
+ ]
+ }
+
+ // Just to show something interesting
+ SequentialAnimation {
+ PauseAnimation { duration: 5000 }
+ ParallelAnimation {
+ NumberAnimation { target: scale; property: "xScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack }
+ NumberAnimation { target: scale; property: "yScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack }
+ }
+ NumberAnimation { target: rotation; property: "angle"; to: 80; duration: 1000; easing.type: Easing.InOutCubic }
+ NumberAnimation { target: rotation; property: "angle"; to: -80; duration: 1000; easing.type: Easing.InOutCubic }
+ NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 1000; easing.type: Easing.InOutCubic }
+ NumberAnimation { target: renderer; property: "opacity"; to: 0.5; duration: 1000; easing.type: Easing.InOutCubic }
+ PauseAnimation { duration: 1000 }
+ NumberAnimation { target: renderer; property: "opacity"; to: 1.0; duration: 1000; easing.type: Easing.InOutCubic }
+ ParallelAnimation {
+ NumberAnimation { target: scale; property: "xScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack }
+ NumberAnimation { target: scale; property: "yScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack }
+ }
+ running: cbAnimate.checked
+ loops: Animation.Infinite
+ }
+
+ Rectangle {
+ id: labelFrame
+ anchors.margins: -10
+ radius: 5
+ color: "white"
+ border.color: "black"
+ anchors.fill: label
+ }
+
+ Text {
+ id: label
+ anchors.bottom: renderer.bottom
+ anchors.left: renderer.left
+ anchors.right: renderer.right
+ anchors.margins: 20
+ wrapMode: Text.WordWrap
+ text: qsTr("The triangle on the blue background is rendered by working directly the QRhi APIs on the scene graph render thread. The custom QQuickItem subclasses QQuickRhiItem, and it in effect draws a quad textured with the QRhiTexture containing the custom 3D rendering. Thanks to being a true QQuickItem, 2D/2.5D transforms, blending/opacity, stacking, clipping, etc. all work as usual.")
+ }
+
+ RowLayout {
+ anchors.top: renderer.top
+ anchors.right: renderer.right
+ anchors.margins: 10
+ Item {
+ id: settingsButton
+ implicitWidth: 64
+ implicitHeight: 64
+ Image {
+ anchors.centerIn: parent
+ source: "icon_settings.png"
+ }
+ HoverHandler {
+ id: hoverHandler
+ }
+ }
+ Text {
+ Layout.alignment: Qt.AlignVCenter
+ text: settingsDrawer.title
+ color: "white"
+ font.pointSize: 16
+ }
+ TapHandler {
+ // qmllint disable signal-handler-parameters
+ onTapped: settingsDrawer.isOpen = !settingsDrawer.isOpen;
+ // qmllint enable signal-handler-parameters
+ }
+ }
+
+ SettingsDrawer {
+ id: settingsDrawer
+ title: qsTr("Settings")
+ isOpen: false
+ isLandscape: true
+ width: isLandscape ? implicitWidth * 1.2 : parent.width
+ height: isLandscape ? parent.height * 0.8 : parent.height * 0.33
+
+ CheckBox {
+ id: cbAnimate
+ text: qsTr("Animate")
+ checked: true
+ }
+
+ CheckBox {
+ id: cbMirror
+ text: qsTr("Mirror vertically")
+ checked: false
+ }
+
+ CheckBox {
+ id: cbMSAA
+ text: qsTr("Enable 4x MSAA")
+ checked: false
+ }
+
+ CheckBox {
+ id: cbSize
+ text: qsTr("Use fixed size")
+ checked: false
+ }
+ RowLayout {
+ Label {
+ text: qsTr("Texture size")
+ }
+ Slider {
+ id: slSize
+ enabled: cbSize.checked
+ from: 8
+ to: 2048
+ value: 128
+ Layout.fillWidth: false
+ }
+ }
+
+ Label {
+ text: qsTr("Backing texture size: %1x%2 pixels").arg(renderer.effectiveColorBufferSize.width).arg(renderer.effectiveColorBufferSize.height)
+ }
+
+ Label {
+ text: qsTr("Item logical size: %1x%2").arg(renderer.width).arg(renderer.height)
+ }
+
+ CheckBox {
+ id: cbBlend
+ text: qsTr("Force alpha blending\nregardless of item opacity")
+ checked: false
+ }
+ RowLayout {
+ Label {
+ text: qsTr("Background alpha")
+ }
+ Slider {
+ id: slAlpha
+ from: 0
+ to: 1.0
+ value: 1.0
+ Layout.fillWidth: false
+ }
+ }
+
+ Label {
+ text: qsTr("Background alpha: %1").arg(renderer.backgroundAlpha.toFixed(2))
+ }
+
+ Label {
+ text: qsTr("Item opacity: %1").arg(renderer.opacity.toFixed(2))
+ }
+
+ Label {
+ property string apiName:
+ if (GraphicsInfo.api === GraphicsInfo.OpenGL)
+ "OpenGL";
+ else if (GraphicsInfo.api === GraphicsInfo.Direct3D11)
+ "D3D11";
+ else if (GraphicsInfo.api === GraphicsInfo.Direct3D12)
+ "D3D12";
+ else if (GraphicsInfo.api === GraphicsInfo.Vulkan)
+ "Vulkan";
+ else if (GraphicsInfo.api === GraphicsInfo.Metal)
+ "Metal";
+ else if (GraphicsInfo.api === GraphicsInfo.Null)
+ "Null";
+ else
+ "Unknown API";
+ text: "The underlying graphics API is " + apiName
+ }
+
+ GroupBox {
+ title: qsTr("Texture format")
+ ColumnLayout {
+ RadioButton {
+ id: rdFormatRGBA8
+ text: qsTr("8-bit RGBA")
+ checked: true
+ Layout.fillWidth: false
+ }
+ RadioButton {
+ id: rdFormatFP16
+ text: qsTr("Half-float RGBA")
+ Layout.fillWidth: false
+ }
+ RadioButton {
+ id: rdFormatFP32
+ text: qsTr("Float RGBA")
+ Layout.fillWidth: false
+ }
+ RadioButton {
+ id: rdFormatRGB10A2
+ text: qsTr("10-bit RGB, 2-bit A")
+ Layout.fillWidth: false
+ }
+ }
+ }
+ }
+}
diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb
new file mode 100644
index 0000000000..31ad25de20
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.frag.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.frag.qsb
new file mode 100644
index 0000000000..10b0bbc436
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.vert.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.vert.qsb
new file mode 100644
index 0000000000..72a0574852
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/color.vert.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp
new file mode 100644
index 0000000000..2b96320869
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp
@@ -0,0 +1,141 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "rhitextureitem.h"
+#include <QFile>
+
+//![0]
+QQuickRhiItemRenderer *ExampleRhiItem::createRenderer()
+{
+ return new ExampleRhiItemRenderer;
+}
+
+void ExampleRhiItem::setAngle(float a)
+{
+ if (m_angle == a)
+ return;
+
+ m_angle = a;
+ emit angleChanged();
+ update();
+}
+
+void ExampleRhiItem::setBackgroundAlpha(float a)
+{
+ if (m_alpha == a)
+ return;
+
+ m_alpha = a;
+ emit backgroundAlphaChanged();
+ update();
+}
+
+void ExampleRhiItemRenderer::synchronize(QQuickRhiItem *rhiItem)
+{
+ ExampleRhiItem *item = static_cast<ExampleRhiItem *>(rhiItem);
+ if (item->angle() != m_angle)
+ m_angle = item->angle();
+ if (item->backgroundAlpha() != m_alpha)
+ m_alpha = item->backgroundAlpha();
+}
+//![0]
+
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
+}
+
+static float vertexData[] = {
+ 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
+ -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
+};
+
+//![1]
+void ExampleRhiItemRenderer::initialize(QRhiCommandBuffer *cb)
+{
+ if (m_rhi != rhi()) {
+ m_rhi = rhi();
+ m_pipeline.reset();
+ }
+
+ if (m_sampleCount != renderTarget()->sampleCount()) {
+ m_sampleCount = renderTarget()->sampleCount();
+ m_pipeline.reset();
+ }
+
+ QRhiTexture *finalTex = m_sampleCount > 1 ? resolveTexture() : colorTexture();
+ if (m_textureFormat != finalTex->format()) {
+ m_textureFormat = finalTex->format();
+ m_pipeline.reset();
+ }
+//![1]
+//![2]
+ if (!m_pipeline) {
+ m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
+ m_vbuf->create();
+
+ m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64));
+ m_ubuf->create();
+
+ m_srb.reset(m_rhi->newShaderResourceBindings());
+ m_srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, m_ubuf.get()),
+ });
+ m_srb->create();
+
+ m_pipeline.reset(m_rhi->newGraphicsPipeline());
+ m_pipeline->setShaderStages({
+ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/color.vert.qsb")) },
+ { QRhiShaderStage::Fragment, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/color.frag.qsb")) }
+ });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 5 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
+ });
+ m_pipeline->setSampleCount(m_sampleCount);
+ m_pipeline->setVertexInputLayout(inputLayout);
+ m_pipeline->setShaderResourceBindings(m_srb.get());
+ m_pipeline->setRenderPassDescriptor(renderTarget()->renderPassDescriptor());
+ m_pipeline->create();
+
+ QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
+ cb->resourceUpdate(resourceUpdates);
+ }
+
+ const QSize outputSize = renderTarget()->pixelSize();
+ m_viewProjection = m_rhi->clipSpaceCorrMatrix();
+ m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
+ m_viewProjection.translate(0, 0, -4);
+//![2]
+}
+
+//![3]
+void ExampleRhiItemRenderer::render(QRhiCommandBuffer *cb)
+{
+ QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ QMatrix4x4 modelViewProjection = m_viewProjection;
+ modelViewProjection.rotate(m_angle, 0, 1, 0);
+ resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData());
+
+ // Qt Quick expects premultiplied alpha
+ const QColor clearColor = QColor::fromRgbF(0.5f * m_alpha, 0.5f * m_alpha, 0.7f * m_alpha, m_alpha);
+ cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates);
+
+ cb->setGraphicsPipeline(m_pipeline.get());
+ const QSize outputSize = renderTarget()->pixelSize();
+ cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(3);
+
+ cb->endPass();
+}
+//![3]
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h
new file mode 100644
index 0000000000..745cc3bf12
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef RHITEXTUREITEM_H
+#define RHITEXTUREITEM_H
+
+#include <QQuickRhiItem>
+#include <rhi/qrhi.h>
+
+class ExampleRhiItemRenderer : public QQuickRhiItemRenderer
+{
+public:
+ void initialize(QRhiCommandBuffer *cb) override;
+ void synchronize(QQuickRhiItem *item) override;
+ void render(QRhiCommandBuffer *cb) override;
+
+private:
+ QRhi *m_rhi = nullptr;
+ int m_sampleCount = 1;
+ QRhiTexture::Format m_textureFormat = QRhiTexture::RGBA8;
+
+ std::unique_ptr<QRhiBuffer> m_vbuf;
+ std::unique_ptr<QRhiBuffer> m_ubuf;
+ std::unique_ptr<QRhiShaderResourceBindings> m_srb;
+ std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
+
+ QMatrix4x4 m_viewProjection;
+ float m_angle = 0.0f;
+ float m_alpha = 1.0f;
+};
+
+class ExampleRhiItem : public QQuickRhiItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ExampleRhiItem)
+ Q_PROPERTY(float angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_PROPERTY(float backgroundAlpha READ backgroundAlpha WRITE setBackgroundAlpha NOTIFY backgroundAlphaChanged)
+
+public:
+ QQuickRhiItemRenderer *createRenderer() override;
+
+ float angle() const { return m_angle; }
+ void setAngle(float a);
+
+ float backgroundAlpha() const { return m_alpha; }
+ void setBackgroundAlpha(float a);
+
+signals:
+ void angleChanged();
+ void backgroundAlphaChanged();
+
+private:
+ float m_angle = 0.0f;
+ float m_alpha = 1.0f;
+};
+
+#endif
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro
new file mode 100644
index 0000000000..4d5c132a42
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro
@@ -0,0 +1,16 @@
+QT += gui-private qml quick
+
+CONFIG += qmltypes
+QML_IMPORT_NAME = SceneGraphRendering
+QML_IMPORT_MAJOR_VERSION = 1
+
+HEADERS += rhitextureitem.h
+SOURCES += rhitextureitem.cpp main.cpp
+
+RESOURCES += rhitextureitem.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/rhitextureitem
+INSTALLS += target
+
+OTHER_FILES += \
+ main.qml
diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc
new file mode 100644
index 0000000000..ad996ef3f2
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/scenegraph/rhitextureitem">
+ <file>main.qml</file>
+ <file alias="shaders/color.vert.qsb">prebuilts_for_qmake/color.vert.qsb</file>
+ <file alias="shaders/color.frag.qsb">prebuilts_for_qmake/color.frag.qsb</file>
+ <file alias="shaders/checker.frag.qsb">prebuilts_for_qmake/checker.frag.qsb</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/scenegraph/rhitextureitem/shaders/checker.frag b/examples/quick/scenegraph/rhitextureitem/shaders/checker.frag
new file mode 100644
index 0000000000..53f4a8aed1
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/shaders/checker.frag
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#version 440
+
+layout(std140, binding = 0) uniform buf {
+ // built-in Qt data
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ // custom data
+ vec4 color1;
+ vec4 color2;
+ vec2 pixelSize;
+};
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize));
+ if (tc.x != tc.y)
+ fragColor = color1;
+ else
+ fragColor = color2;
+}
diff --git a/examples/quick/scenegraph/rhitextureitem/shaders/color.frag b/examples/quick/scenegraph/rhitextureitem/shaders/color.frag
new file mode 100644
index 0000000000..b7e36638e3
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/shaders/color.frag
@@ -0,0 +1,13 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#version 440
+
+layout(location = 0) in vec3 v_color;
+
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(v_color, 1.0);
+}
diff --git a/examples/quick/scenegraph/rhitextureitem/shaders/color.vert b/examples/quick/scenegraph/rhitextureitem/shaders/color.vert
new file mode 100644
index 0000000000..e876f290e7
--- /dev/null
+++ b/examples/quick/scenegraph/rhitextureitem/shaders/color.vert
@@ -0,0 +1,16 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+
+layout(location = 0) out vec3 v_color;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+};
+
+void main()
+{
+ v_color = color;
+ gl_Position = mvp * position;
+}
diff --git a/examples/quick/scenegraph/rhiunderqml/CMakeLists.txt b/examples/quick/scenegraph/rhiunderqml/CMakeLists.txt
new file mode 100644
index 0000000000..c1fdc114b6
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/CMakeLists.txt
@@ -0,0 +1,61 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(rhiunderqml LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
+
+qt_standard_project_setup()
+
+qt_add_executable(rhiunderqml WIN32 MACOSX_BUNDLE
+ main.cpp
+ rhisquircle.cpp rhisquircle.h
+)
+
+set_target_properties(rhiunderqml PROPERTIES
+ # Prevent name clash with build subdirectory on case-insensitive file systems
+ OUTPUT_NAME rhiunderqmlapp
+)
+
+target_link_libraries(rhiunderqml PRIVATE
+ Qt6::Core
+ Qt6::GuiPrivate
+ Qt6::Qml
+ Qt6::Quick
+)
+
+qt_add_qml_module(rhiunderqml
+ URI RhiUnderQML
+ QML_FILES
+ main.qml
+ RESOURCE_PREFIX /scenegraph/rhiunderqml
+ NO_RESOURCE_TARGET_PATH
+)
+
+qt_add_shaders(rhiunderqml "rhiunderqml_shaders"
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ /scenegraph/rhiunderqml
+ BASE
+ ../shared
+ FILES
+ ../shared/squircle_rhi.vert
+ ../shared/squircle_rhi.frag
+)
+
+install(TARGETS rhiunderqml
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET rhiunderqml
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
+)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/rhiunderqml/doc/images/rhiunderqml-example.jpg b/examples/quick/scenegraph/rhiunderqml/doc/images/rhiunderqml-example.jpg
new file mode 100644
index 0000000000..e9c5bde3f0
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/doc/images/rhiunderqml-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc b/examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc
new file mode 100644
index 0000000000..175148c9c0
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/doc/src/rhiunderqml.qdoc
@@ -0,0 +1,236 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example scenegraph/rhiunderqml
+ \title Scene Graph - RHI Under QML
+ \examplecategory {Graphics}
+ \ingroup qtquickexamples
+ \brief Shows how to render directly with \l QRhi under a Qt Quick scene.
+
+ \image rhiunderqml-example.jpg
+
+ \section1 Introduction
+
+ The RHI Under QML example shows how an application can make use of the \l
+ QQuickWindow::beforeRendering() and \l
+ QQuickWindow::beforeRenderPassRecording() signals to draw custom \l{QRhi}-based
+ content under a Qt Quick scene.
+
+ Applications that wish to render \l QRhi content on top of the Qt Quick scene,
+ can do so by connecting to the \l QQuickWindow::afterRendering() and \l
+ QQuickWindow::afterRenderPassRecording() signals.
+
+ In this example, we will also see how it is possible to have values that
+ are exposed to QML which affect the QRhi-based rendering. We animate the
+ threshold value using a NumberAnimation in the QML file and this float
+ value is then passed on in a uniform buffer to the fragment shader.
+
+ The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under
+ QML}{OpenGL Under QML}, \l{Scene Graph - Direct3D 11 Under QML}{Direct3D 11
+ Under QML}, \l{Scene Graph - Metal Under QML}{Metal Under QML}, and \l{Scene
+ Graph - Vulkan Under QML}{Vulkan Under QML} examples. Those examples render
+ the same content by directly using a 3D API. This example on the other hand
+ is fully cross-platform and portable, as it inherently supports operating
+ 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
+ the scene graph starts its rendering, thus any \l QRhi draw calls that are
+ made as a response to this signal, will stack under the Qt Quick items.
+ However, there are two signals that are relevant here: the application's own
+ \l QRhi commands should be recorded onto the same command buffer that is
+ used by the scene graph, and what's more, the commands should belong to the
+ same render pass. beforeRendering() on its own is not sufficient for this
+ because it gets emitted at the start of the frame, before starting to record
+ a render pass via \l QRhiCommandBuffer::beginPass(). By also connecting to
+ beforeRenderPassRecording(), the application's own commands and the scene
+ graph's own rendering will end up in the right order:
+
+ \list
+ \li The scene graph's render loop calls \l QRhi::beginFrame()
+ \li \l QQuickWindow::beforeRendering() is emitted - the application prepares resources for its custom rendering
+ \li The scene graph calls \l QRhiCommandBuffer::beginPass()
+ \li \l QQuickWindow::beforeRenderPassRecording() is emitted - the application records draw calls
+ \li The scene graph records draw calls
+ \endlist
+
+ \section1 Walkthrough
+
+ The custom rendering is encapsulated within a custom QQuickItem. \c
+ RhiSquircle derives from \l QQuickItem, and is exposed to QML (note the
+ \c{QML_ELEMENT}). The QML scene instantiates \c RhiSquircle. Note however
+ that this is not a visual item: the \l QQuickItem::ItemHasContents flag is
+ not set. Thus the item's position and size has no relevance and it does not
+ reimplement \l{QQuickItem::updatePaintNode()}{updatePaintNode()}.
+
+ \snippet scenegraph/rhiunderqml/rhisquircle.h 0
+
+ Instead, when the item gets associated with a \l QQuickWindow, it connects
+ to the \l{QQuickWindow::beforeSynchronizing()} signal. Using
+ Qt::DirectConnection is important since this signal is emitted on the Qt
+ Quick render thread, if there is one. We want the connected slot to be
+ invoked on this same thread.
+
+ \snippet scenegraph/rhiunderqml/rhisquircle.cpp init
+
+ In the scene graph's synchronizing phase, the rendering infrastructure is
+ created, if not yet done, and the data relevant for rendering is
+ synchronized, i.e. copied from the \c RhiSquircle item, that lives on the
+ main thread, to the \c SquircleRenderer object that lives on the render
+ thread. (if there is no render thread, then both objects live on the main
+ thread) Accessing data is safe because the main thread is blocked while the
+ render thread is executing its synchronize phase. See \l{Qt Quick Scene
+ Graph} for more information on the scene graph threading and rendering
+ model.
+
+ In addition to the value of \c t, the associated QQuickWindow pointer is
+ copied as well. While the \c SquircleRenderer could query
+ \l{QQuickItem::window()}{window()} on the \c RhiSquircle item even when
+ operating on the render thread, that is, in theory, not entirely safe. Hence
+ making a copy.
+
+ When setting up the \c SquircleRenderer, connections to the
+ \l{QQuickWindow::beforeRendering()}{beforeRendering()} and
+ \l{QQuickWindow::beforeRenderPassRecording()}{beforeRenderPassRecording()}
+ are made, which are the key to be able to act and inject the application's
+ custom 3D rendering commands at the appropriate time.
+
+ \snippet scenegraph/rhiunderqml/rhisquircle.cpp sync
+
+ When \l{QQuickWindow::beforeRendering()}{beforeRendering()} is emitted, the
+ QRhi resources needed for our custom rendering, such as \l QRhiBuffer, \l
+ QRhiGraphicsPipeline, and related objects, are created if not yet done.
+
+ The data in the buffers is updated (more precisely, the data update
+ operations are enqueued) using \l QRhiResourceUpdateBatch and \l
+ QRhiCommandBuffer::resourceUpdate(). The vertex buffer does not change its
+ contents once the initial set of vertices are uploaded to it. The uniform
+ buffer however is a \l{QRhiBuffer::Dynamic}{dynamic} buffer, as is typical
+ for such buffers. Its content, some regions at least, is updated for every
+ frame. Hence the unconditional call to
+ \l{QRhiResourceUpdateBatch::updateDynamicBuffer()}{updateDynamicBuffer()}
+ for offset 0 and a byte size of 4 (which is \c{sizeof(float)} since the C++
+ \c float type happens to match GLSL's 32-bit \c float). What is stored at
+ that position is the value of \c t, and that is updated in every frame,
+ meaning in every invocation of frameStart().
+
+ There is an additional float value in the buffer, starting at offset 4. This
+ is used to cater to the coordinate system differences of the 3D APIs: when
+ \l{QRhi::isYUpInNDC()}{isYUpInNDC()} returns \c false, which is the case
+ with Vulkan in particular, the value is set to -1.0 which leads to flipping
+ the Y value in the 2 component vector that is passed on (with interpolation)
+ to the fragment shader based on which the color is calculated. This way the
+ output on the screen is identical (i.e. the top-left corner is green-ish,
+ the bottom-left is red-ish), regardless of which 3D API is in use. This
+ value is updated only once in the uniform buffer, similarly to the vertex
+ buffer. This highlights an issue low-level rendering code that aims to be
+ portable often needs to deal with: the coordinate system differences in
+ normalized device coordinates (NDC) and in images and framebuffers. For
+ example, the NDC uses a origin-at-bottom-left system everywhere except
+ Vulkan. Whereas framebuffers use an origin-at-top-left system everywhere
+ except OpenGL. Typical renderers that work with a perspective projection can
+ often be oblivious to this problem by conveniently relying on
+ \l{QRhi::clipSpaceCorrMatrix()}, which is a matrix that can be multiplied in
+ to the projection matrix, and applies both an Y flip when needed, and also
+ caters to the fact that clip space depth runs \c{-1..1} with OpenGL but
+ \c{0..1} everywhere else. However, in some cases, such as in this example,
+ this is not applicable. Rather, the application and shader logic needs to
+ perform the necessary adjustment of vertex and UV positions as appropriate
+ based on querying \l QRhi::isYUpInNDC() and \l QRhi::isYUpInFramebuffer().
+
+ To gain access to the \l QRhi and \l QRhiSwapChain objects Qt Quick uses,
+ they can simply be queried from the \l QQuickWindow. Note that this assumes
+ that the QQuickWindow is a regular, on-screen window. If it used \l
+ QQuickRenderControl instead, e.g. to perform off-screen rendering into a
+ texture, querying the swapchain would be wrong since there is no swapchain
+ then.
+
+ Due to the signal being emitted after Qt Quick calls \l QRhi::beginFrame(),
+ it is already possible to query the command buffer and render target from
+ the swapchain. This is what allows to conveniently issue a \l
+ QRhiCommandBuffer::resourceUpdate() on the object returned from \l
+ QRhiSwapChain::currentFrameCommandBuffer(). When creating a graphics
+ pipeline, a QRhiRenderPassDescriptor can be retrieved from the
+ QRhiRenderTarget returned from \l QRhiSwapChain::currentFrameRenderTarget().
+ (note that this means the graphics pipeline built here is suitable only for
+ rendering to the swapchain, or at best another render target that is
+ \l{QRhiRenderPassDescriptor::isCompatible()}{compatible} with it; it is
+ likely that if we wanted to render to a texture, then a different
+ QRhiRenderPassDescriptor, and so a different graphics pipeline, would be
+ needed since the texture and swapchain formats may differ)
+
+ \snippet scenegraph/rhiunderqml/rhisquircle.cpp frame-start
+
+ Finally, upon \l QQuickWindow::beforeRenderPassRecording(), a draw call for
+ a triangle strip with 4 vertices is recorded. This example simply draws a
+ quad in practice, and calculates the pixel colors using the logic in the
+ fragment shaders, but applications are free to do more complicated drawing:
+ creating multiple graphics pipelines and recording multiple draw calls is
+ perfectly fine as well. The important thing to keep in mind is that whatever
+ is recorded on the \l QRhiCommandBuffer retrieved from the window's
+ \l{QRhiSwapChain}{swapchain}, it is effectively prepended before the Qt Quick
+ scene graph's own rendering within the main render pass.
+
+ \note This means that if depth buffer usage with depth testing and writing
+ out depth values is involved, then the Qt Quick content may be affected by
+ the values written to the depth buffer. See \l{Qt Quick Scene Graph Default
+ Renderer} for details on the scene graph's renderer, in particular the
+ sections about the handling of \e opaque and \e{alpha blended} primitives.
+
+ To get the window size in pixels, \l QRhiRenderTarget::pixelSize() is used.
+ This is convenient because this way the example does not need to calculate
+ the viewport size by other means and does not have to worry about applying
+ the \l{QWindow::devicePixelRatio()}{high DPI scale factor}, if there is any.
+
+ \snippet scenegraph/rhiunderqml/rhisquircle.cpp frame-render
+
+ The vertex and fragment shaders go through the standard QRhi shader
+ conditioning pipeline. Initially written as Vulkan-compatible GLSL, they get
+ compiled to SPIR-V and then transpiled to other shading languages by Qt's
+ tools. When using CMake, the example relies on the \c qt_add_shaders command
+ that makes it simple and convenient to bundle the shaders with the
+ application and perform the necessary processing at build time. See \l{Qt
+ Shader Tools Build System Integration} for details.
+
+ Specifying \c BASE helps removing the \c{../shared} prefix, while \c PREFIX
+ adds the intended \c{/scenegraph/rhiunderqml} prefix. Thus the final path is
+ \c{:/scenegraph/rhiunderqml/squircle_rhi.vert.qsb}.
+
+ \badcode
+ qt_add_shaders(rhiunderqml "rhiunderqml_shaders"
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ /scenegraph/rhiunderqml
+ BASE
+ ../shared
+ FILES
+ ../shared/squircle_rhi.vert
+ ../shared/squircle_rhi.frag
+ )
+ \endcode
+
+ To support qmake, the example still ships the \c{.qsb} files that would
+ 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/examples/quick/scenegraph/rhiunderqml/main.cpp b/examples/quick/scenegraph/rhiunderqml/main.cpp
new file mode 100644
index 0000000000..51b8d18ddb
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/main.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QGuiApplication>
+#include <QtQuick/QQuickView>
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:///scenegraph/rhiunderqml/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/quick/scenegraph/rhiunderqml/main.qml b/examples/quick/scenegraph/rhiunderqml/main.qml
new file mode 100644
index 0000000000..3faa028457
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/main.qml
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import RhiUnderQML
+
+Item {
+ width: 320
+ height: 480
+
+ RhiSquircle {
+ SequentialAnimation on t {
+ NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
+ NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
+ loops: Animation.Infinite
+ running: true
+ }
+ }
+
+ Rectangle {
+ color: Qt.rgba(1, 1, 1, 0.7)
+ radius: 10
+ border.width: 1
+ border.color: "white"
+ anchors.fill: label
+ anchors.margins: -10
+ }
+
+ Text {
+ id: label
+ color: "black"
+ wrapMode: Text.WordWrap
+ text: qsTr("The background here is a squircle rendered with QRhi using the beforeRendering() and beforeRenderPassRecording() signals in QQuickWindow. This text label and its border is rendered using QML")
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.margins: 20
+ }
+}
diff --git a/examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.frag.qsb b/examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.frag.qsb
new file mode 100644
index 0000000000..077a31f945
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.vert.qsb b/examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.vert.qsb
new file mode 100644
index 0000000000..1e87cf09a7
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/prebuilts_for_qmake/squircle_rhi.vert.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/rhiunderqml/rhisquircle.cpp b/examples/quick/scenegraph/rhiunderqml/rhisquircle.cpp
new file mode 100644
index 0000000000..135cf128e3
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/rhisquircle.cpp
@@ -0,0 +1,224 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "rhisquircle.h"
+#include <QtQuick/QQuickWindow>
+#include <QtCore/QFile>
+#include <QtCore/QRunnable>
+
+#include <rhi/qrhi.h>
+
+class SquircleRenderer : public QObject
+{
+ Q_OBJECT
+public:
+ void setT(qreal t) { m_t = t; }
+ void setWindow(QQuickWindow *window) { m_window = window; }
+
+public slots:
+ void frameStart();
+ void mainPassRecordingStart();
+
+private:
+ qreal m_t = 0;
+ QQuickWindow *m_window;
+ QShader m_vertexShader;
+ QShader m_fragmentShader;
+ std::unique_ptr<QRhiBuffer> m_vertexBuffer;
+ std::unique_ptr<QRhiBuffer> m_uniformBuffer;
+ std::unique_ptr<QRhiShaderResourceBindings> m_srb;
+ std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
+};
+
+//! [init]
+RhiSquircle::RhiSquircle()
+{
+ connect(this, &QQuickItem::windowChanged, this, &RhiSquircle::handleWindowChanged);
+}
+
+void RhiSquircle::handleWindowChanged(QQuickWindow *win)
+{
+ if (win) {
+ connect(win, &QQuickWindow::beforeSynchronizing, this, &RhiSquircle::sync, Qt::DirectConnection);
+ connect(win, &QQuickWindow::sceneGraphInvalidated, this, &RhiSquircle::cleanup, Qt::DirectConnection);
+ // Ensure we start with cleared to black. The squircle's blend mode relies on this.
+ win->setColor(Qt::black);
+ }
+}
+//! [init]
+
+// The safe way to release custom graphics resources is to both connect to
+// sceneGraphInvalidated() and implement releaseResources(). To support
+// threaded render loops the latter performs the SquircleRenderer destruction
+// via scheduleRenderJob(). Note that the RhiSquircle may be gone by the time
+// the QRunnable is invoked.
+
+void RhiSquircle::cleanup()
+{
+ // This function is invoked on the render thread, if there is one.
+
+ delete m_renderer;
+ m_renderer = nullptr;
+}
+
+class CleanupJob : public QRunnable
+{
+public:
+ CleanupJob(SquircleRenderer *renderer) : m_renderer(renderer) { }
+ void run() override { delete m_renderer; }
+private:
+ SquircleRenderer *m_renderer;
+};
+
+void RhiSquircle::releaseResources()
+{
+ window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage);
+ m_renderer = nullptr;
+}
+
+void RhiSquircle::setT(qreal t)
+{
+ if (t == m_t)
+ return;
+ m_t = t;
+ emit tChanged();
+ if (window())
+ window()->update();
+}
+
+//! [sync]
+void RhiSquircle::sync()
+{
+ // This function is invoked on the render thread, if there is one.
+
+ if (!m_renderer) {
+ m_renderer = new SquircleRenderer;
+ // Initializing resources is done before starting to record the
+ // renderpass, regardless of wanting an underlay or overlay.
+ connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::frameStart, Qt::DirectConnection);
+ // Here we want an underlay and therefore connect to
+ // beforeRenderPassRecording. Changing to afterRenderPassRecording
+ // would render the squircle on top (overlay).
+ connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::mainPassRecordingStart, Qt::DirectConnection);
+ }
+ m_renderer->setT(m_t);
+ m_renderer->setWindow(window());
+}
+//! [sync]
+
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ return QShader();
+}
+
+static const float vertices[] = {
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ 1, 1
+};
+
+//! [frame-start]
+void SquircleRenderer::frameStart()
+{
+ // This function is invoked on the render thread, if there is one.
+
+ QRhi *rhi = m_window->rhi();
+ if (!rhi) {
+ qWarning("QQuickWindow is not using QRhi for rendering");
+ return;
+ }
+ QRhiSwapChain *swapChain = m_window->swapChain();
+ if (!swapChain) {
+ qWarning("No QRhiSwapChain?");
+ return;
+ }
+ QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
+
+ if (!m_pipeline) {
+ m_vertexShader = getShader(QLatin1String(":/scenegraph/rhiunderqml/squircle_rhi.vert.qsb"));
+ if (!m_vertexShader.isValid())
+ qWarning("Failed to load vertex shader; rendering will be incorrect");
+
+ m_fragmentShader = getShader(QLatin1String(":/scenegraph/rhiunderqml/squircle_rhi.frag.qsb"));
+ if (!m_fragmentShader.isValid())
+ qWarning("Failed to load fragment shader; rendering will be incorrect");
+
+ m_vertexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
+ m_vertexBuffer->create();
+ resourceUpdates->uploadStaticBuffer(m_vertexBuffer.get(), vertices);
+
+ const quint32 UBUF_SIZE = 4 + 4; // 2 floats
+ m_uniformBuffer.reset(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE));
+ m_uniformBuffer->create();
+
+ float yDir = rhi->isYUpInNDC() ? 1.0f : -1.0f;
+ resourceUpdates->updateDynamicBuffer(m_uniformBuffer.get(), 4, 4, &yDir);
+
+ m_srb.reset(rhi->newShaderResourceBindings());
+ const auto visibleToAll = QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage;
+ m_srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, visibleToAll, m_uniformBuffer.get())
+ });
+ m_srb->create();
+
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 2 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 }
+ });
+
+ m_pipeline.reset(rhi->newGraphicsPipeline());
+ m_pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
+ QRhiGraphicsPipeline::TargetBlend blend;
+ blend.enable = true;
+ blend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
+ blend.srcAlpha = QRhiGraphicsPipeline::SrcAlpha;
+ blend.dstColor = QRhiGraphicsPipeline::One;
+ blend.dstAlpha = QRhiGraphicsPipeline::One;
+ m_pipeline->setTargetBlends({ blend });
+ m_pipeline->setShaderStages({
+ { QRhiShaderStage::Vertex, m_vertexShader },
+ { QRhiShaderStage::Fragment, m_fragmentShader }
+ });
+ m_pipeline->setVertexInputLayout(inputLayout);
+ m_pipeline->setShaderResourceBindings(m_srb.get());
+ m_pipeline->setRenderPassDescriptor(swapChain->currentFrameRenderTarget()->renderPassDescriptor());
+ m_pipeline->create();
+ }
+
+ float t = m_t;
+ resourceUpdates->updateDynamicBuffer(m_uniformBuffer.get(), 0, 4, &t);
+
+ swapChain->currentFrameCommandBuffer()->resourceUpdate(resourceUpdates);
+}
+//! [frame-start]
+
+//! [frame-render]
+void SquircleRenderer::mainPassRecordingStart()
+{
+ // This function is invoked on the render thread, if there is one.
+
+ QRhi *rhi = m_window->rhi();
+ QRhiSwapChain *swapChain = m_window->swapChain();
+ if (!rhi || !swapChain)
+ return;
+
+ const QSize outputPixelSize = swapChain->currentFrameRenderTarget()->pixelSize();
+ QRhiCommandBuffer *cb = m_window->swapChain()->currentFrameCommandBuffer();
+ cb->setViewport({ 0.0f, 0.0f, float(outputPixelSize.width()), float(outputPixelSize.height()) });
+ cb->setGraphicsPipeline(m_pipeline.get());
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vertexBuffer.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(4);
+}
+//! [frame-render]
+
+#include "rhisquircle.moc"
diff --git a/examples/quick/scenegraph/rhiunderqml/rhisquircle.h b/examples/quick/scenegraph/rhiunderqml/rhisquircle.h
new file mode 100644
index 0000000000..507e7b930f
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/rhisquircle.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef RHISQUIRCLE_H
+#define RHISQUIRCLE_H
+
+#include <QtQuick/QQuickItem>
+#include <QtQuick/QQuickWindow>
+
+class SquircleRenderer;
+
+//! [0]
+class RhiSquircle : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+ QML_ELEMENT
+
+public:
+ RhiSquircle();
+
+ qreal t() const { return m_t; }
+ void setT(qreal t);
+
+signals:
+ void tChanged();
+
+public slots:
+ void sync();
+ void cleanup();
+
+private slots:
+ void handleWindowChanged(QQuickWindow *win);
+
+private:
+ void releaseResources() override;
+
+ qreal m_t = 0;
+ SquircleRenderer *m_renderer = nullptr;
+};
+//! [0]
+
+#endif
diff --git a/examples/quick/scenegraph/rhiunderqml/rhiunderqml.pro b/examples/quick/scenegraph/rhiunderqml/rhiunderqml.pro
new file mode 100644
index 0000000000..af85005e80
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/rhiunderqml.pro
@@ -0,0 +1,11 @@
+QT += gui-private qml quick
+CONFIG += qmltypes
+QML_IMPORT_NAME = RhiUnderQML
+QML_IMPORT_MAJOR_VERSION = 1
+
+HEADERS += rhisquircle.h
+SOURCES += rhisquircle.cpp main.cpp
+RESOURCES += rhiunderqml.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/rhiunderqml
+INSTALLS += target
diff --git a/examples/quick/scenegraph/rhiunderqml/rhiunderqml.qrc b/examples/quick/scenegraph/rhiunderqml/rhiunderqml.qrc
new file mode 100644
index 0000000000..690cb36444
--- /dev/null
+++ b/examples/quick/scenegraph/rhiunderqml/rhiunderqml.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/scenegraph/rhiunderqml">
+ <file>main.qml</file>
+ <file alias="squircle_rhi.vert.qsb">prebuilts_for_qmake/squircle_rhi.vert.qsb</file>
+ <file alias="squircle_rhi.frag.qsb">prebuilts_for_qmake/squircle_rhi.frag.qsb</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro
index a438bb8341..c37e822680 100644
--- a/examples/quick/scenegraph/scenegraph.pro
+++ b/examples/quick/scenegraph/scenegraph.pro
@@ -2,8 +2,7 @@ TEMPLATE = subdirs
qtConfig(opengl(es1|es2)?) {
SUBDIRS += \
- fboitem \
- openglunderqml \
+ openglunderqml
}
SUBDIRS += \
@@ -11,7 +10,9 @@ SUBDIRS += \
custommaterial \
graph \
threadedanimation \
- twotextureproviders
+ twotextureproviders \
+ rhiunderqml \
+ rhitextureitem
macos|ios {
SUBDIRS += \
diff --git a/examples/quick/scenegraph/shared/logorenderer.cpp b/examples/quick/scenegraph/shared/logorenderer.cpp
deleted file mode 100644
index b95ae0d21d..0000000000
--- a/examples/quick/scenegraph/shared/logorenderer.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#include "logorenderer.h"
-#include <QPainter>
-#include <QPaintEngine>
-#include <qmath.h>
-
-LogoRenderer::LogoRenderer()
-{
-}
-
-LogoRenderer::~LogoRenderer()
-{
-}
-
-
-void LogoRenderer::paintQtLogo()
-{
- program1.enableAttributeArray(normalAttr1);
- program1.enableAttributeArray(vertexAttr1);
- program1.setAttributeArray(vertexAttr1, vertices.constData());
- program1.setAttributeArray(normalAttr1, normals.constData());
- glDrawArrays(GL_TRIANGLES, 0, vertices.size());
- program1.disableAttributeArray(normalAttr1);
- program1.disableAttributeArray(vertexAttr1);
-}
-
-
-void LogoRenderer::initialize()
-{
- initializeOpenGLFunctions();
-
- glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
-
- const char *vsrc1 =
- "attribute highp vec4 vertex;\n"
- "attribute mediump vec3 normal;\n"
- "uniform mediump mat4 matrix;\n"
- "varying mediump vec4 color;\n"
- "void main(void)\n"
- "{\n"
- " vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n"
- " float angle = max(dot(normal, toLight), 0.0);\n"
- " vec3 col = vec3(0.40, 1.0, 0.0);\n"
- " color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n"
- " color = clamp(color, 0.0, 1.0);\n"
- " gl_Position = matrix * vertex;\n"
- "}\n";
-
- const char *fsrc1 =
- "varying mediump vec4 color;\n"
- "void main(void)\n"
- "{\n"
- " gl_FragColor = color;\n"
- "}\n";
-
- program1.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vsrc1);
- program1.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fsrc1);
- program1.link();
-
- vertexAttr1 = program1.attributeLocation("vertex");
- normalAttr1 = program1.attributeLocation("normal");
- matrixUniform1 = program1.uniformLocation("matrix");
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
- m_fAngle = 0;
- m_fScale = 1;
- createGeometry();
-}
-
-void LogoRenderer::render()
-{
- glDepthMask(true);
-
- glClearColor(0.5f, 0.5f, 0.7f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
- glFrontFace(GL_CW);
- glCullFace(GL_FRONT);
- glEnable(GL_CULL_FACE);
- glEnable(GL_DEPTH_TEST);
-
- QMatrix4x4 modelview;
- modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
- modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
- modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
- modelview.scale(m_fScale);
- modelview.translate(0.0f, -0.2f, 0.0f);
-
- program1.bind();
- program1.setUniformValue(matrixUniform1, modelview);
- paintQtLogo();
- program1.release();
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
-
- m_fAngle += 1.0f;
-}
-
-void LogoRenderer::createGeometry()
-{
- vertices.clear();
- normals.clear();
-
- qreal x1 = +0.06f;
- qreal y1 = -0.14f;
- qreal x2 = +0.14f;
- qreal y2 = -0.06f;
- qreal x3 = +0.08f;
- qreal y3 = +0.00f;
- qreal x4 = +0.30f;
- qreal y4 = +0.22f;
-
- quad(x1, y1, x2, y2, y2, x2, y1, x1);
- quad(x3, y3, x4, y4, y4, x4, y3, x3);
-
- extrude(x1, y1, x2, y2);
- extrude(x2, y2, y2, x2);
- extrude(y2, x2, y1, x1);
- extrude(y1, x1, x1, y1);
- extrude(x3, y3, x4, y4);
- extrude(x4, y4, y4, x4);
- extrude(y4, x4, y3, x3);
-
- const qreal Pi = M_PI;
- const int NumSectors = 100;
-
- for (int i = 0; i < NumSectors; ++i) {
- qreal angle1 = (i * 2 * Pi) / NumSectors;
- qreal x5 = 0.30 * sin(angle1);
- qreal y5 = 0.30 * cos(angle1);
- qreal x6 = 0.20 * sin(angle1);
- qreal y6 = 0.20 * cos(angle1);
-
- qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors;
- qreal x7 = 0.20 * sin(angle2);
- qreal y7 = 0.20 * cos(angle2);
- qreal x8 = 0.30 * sin(angle2);
- qreal y8 = 0.30 * cos(angle2);
-
- quad(x5, y5, x6, y6, x7, y7, x8, y8);
-
- extrude(x6, y6, x7, y7);
- extrude(x8, y8, x5, y5);
- }
-
- for (int i = 0;i < vertices.size();i++)
- vertices[i] *= 2.0f;
-}
-
-void LogoRenderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4)
-{
- vertices << QVector3D(x1, y1, -0.05f);
- vertices << QVector3D(x2, y2, -0.05f);
- vertices << QVector3D(x4, y4, -0.05f);
-
- vertices << QVector3D(x3, y3, -0.05f);
- vertices << QVector3D(x4, y4, -0.05f);
- vertices << QVector3D(x2, y2, -0.05f);
-
- QVector3D n = QVector3D::normal
- (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f));
-
- normals << n;
- normals << n;
- normals << n;
-
- normals << n;
- normals << n;
- normals << n;
-
- vertices << QVector3D(x4, y4, 0.05f);
- vertices << QVector3D(x2, y2, 0.05f);
- vertices << QVector3D(x1, y1, 0.05f);
-
- vertices << QVector3D(x2, y2, 0.05f);
- vertices << QVector3D(x4, y4, 0.05f);
- vertices << QVector3D(x3, y3, 0.05f);
-
- n = QVector3D::normal
- (QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f));
-
- normals << n;
- normals << n;
- normals << n;
-
- normals << n;
- normals << n;
- normals << n;
-}
-
-void LogoRenderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2)
-{
- vertices << QVector3D(x1, y1, +0.05f);
- vertices << QVector3D(x2, y2, +0.05f);
- vertices << QVector3D(x1, y1, -0.05f);
-
- vertices << QVector3D(x2, y2, -0.05f);
- vertices << QVector3D(x1, y1, -0.05f);
- vertices << QVector3D(x2, y2, +0.05f);
-
- QVector3D n = QVector3D::normal
- (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f));
-
- normals << n;
- normals << n;
- normals << n;
-
- normals << n;
- normals << n;
- normals << n;
-}
diff --git a/examples/quick/scenegraph/shared/logorenderer.h b/examples/quick/scenegraph/shared/logorenderer.h
deleted file mode 100644
index 06c49baab1..0000000000
--- a/examples/quick/scenegraph/shared/logorenderer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-#ifndef LOGORENDERER_H
-#define LOGORENDERER_H
-
-#include <QtGui/qvector3d.h>
-#include <QtGui/qmatrix4x4.h>
-#include <qopenglshaderprogram.h>
-#include <qopenglfunctions.h>
-
-#include <QTime>
-#include <QList>
-
-class LogoRenderer : protected QOpenGLFunctions
-{
-public:
- LogoRenderer();
- ~LogoRenderer();
-
- void render();
- void initialize();
-
-private:
-
- qreal m_fAngle;
- qreal m_fScale;
-
- void paintQtLogo();
- void createGeometry();
- void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4);
- void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
-
- QList<QVector3D> vertices;
- QList<QVector3D> normals;
- QOpenGLShaderProgram program1;
- int vertexAttr1;
- int normalAttr1;
- int matrixUniform1;
-};
-#endif
diff --git a/examples/quick/scenegraph/shared/squircle_rhi.frag b/examples/quick/scenegraph/shared/squircle_rhi.frag
index 8da62b93e6..83669bdfaa 100644
--- a/examples/quick/scenegraph/shared/squircle_rhi.frag
+++ b/examples/quick/scenegraph/shared/squircle_rhi.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#version 440
layout(location = 0) in vec2 coords;
@@ -5,12 +8,13 @@ layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
float t;
-} ubuf;
+ float y_dir;
+};
void main()
{
- float i = 1. - (pow(abs(coords.x), 4.) + pow(abs(coords.y), 4.));
- i = smoothstep(ubuf.t - 0.8, ubuf.t + 0.8, i);
- i = floor(i * 20.) / 20.;
- fragColor = vec4(coords * .5 + .5, i, i);
+ float i = 1.0 - (pow(abs(coords.x), 4.0) + pow(abs(coords.y), 4.0));
+ i = smoothstep(t - 0.8, t + 0.8, i);
+ i = floor(i * 20.0) / 20.0;
+ fragColor = vec4(coords * 0.5 + 0.5, i, i);
}
diff --git a/examples/quick/scenegraph/shared/squircle_rhi.vert b/examples/quick/scenegraph/shared/squircle_rhi.vert
index b57dfdfe10..bf079ab786 100644
--- a/examples/quick/scenegraph/shared/squircle_rhi.vert
+++ b/examples/quick/scenegraph/shared/squircle_rhi.vert
@@ -1,13 +1,16 @@
#version 440
layout(location = 0) in vec4 vertices;
-
layout(location = 0) out vec2 coords;
-out gl_PerVertex { vec4 gl_Position; };
+layout(std140, binding = 0) uniform buf {
+ float t;
+ float y_dir;
+};
void main()
{
gl_Position = vertices;
coords = vertices.xy;
+ coords.y *= y_dir;
}
diff --git a/examples/quick/scenegraph/threadedanimation/CMakeLists.txt b/examples/quick/scenegraph/threadedanimation/CMakeLists.txt
index a0e98f5e99..0945a13c98 100644
--- a/examples/quick/scenegraph/threadedanimation/CMakeLists.txt
+++ b/examples/quick/scenegraph/threadedanimation/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(threadedanimation LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/threadedanimation")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_standard_project_setup()
@@ -20,10 +14,10 @@ qt_add_executable(threadedanimation WIN32 MACOSX_BUNDLE
)
target_link_libraries(threadedanimation PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
qt_add_qml_module(threadedanimation
@@ -35,7 +29,16 @@ qt_add_qml_module(threadedanimation
)
install(TARGETS threadedanimation
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET threadedanimation
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/threadedanimation/doc/images/threadedanimation-example.jpg b/examples/quick/scenegraph/threadedanimation/doc/images/threadedanimation-example.jpg
new file mode 100644
index 0000000000..42c886b7ab
--- /dev/null
+++ b/examples/quick/scenegraph/threadedanimation/doc/images/threadedanimation-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/threadedanimation/doc/src/threadedanimation.qdoc b/examples/quick/scenegraph/threadedanimation/doc/src/threadedanimation.qdoc
new file mode 100644
index 0000000000..01b842d07a
--- /dev/null
+++ b/examples/quick/scenegraph/threadedanimation/doc/src/threadedanimation.qdoc
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example scenegraph/threadedanimation
+ \title Scene Graph - Threaded Animation
+ \examplecategory {Graphics}
+ \ingroup qtquickexamples
+ \brief Shows benefits of custom items animating independently of the main thread while using the threaded render loop of Qt Quick.
+
+ \image threadedanimation-example.jpg
+
+ This example shows the fundamental concept behind the \l Animator types, by
+ implementing a custom item that effectively animates itself by not relying
+ on the standard Qt Quick animation framework driven on the main thread.
+
+ The left and right spinners should behave identically under normal
+ conditions. However, once the example blocks the main thread by peforming
+ some heavy operation, it will become noticeable that the left spinner is not
+ animating smoothly anymore.
+
+ \note This example should be run with the \c threaded render loop of Qt
+ Quick. This is the default in most cases. There are no positive effects when
+ using the \c basic render loop, because there everything, including all
+ rendering, happens on the main thread.
+
+ Applications without custom QQuickItem implementations can get the same
+ benefits by using one of the \l Animator types, such as \l XAnimator or \l
+ OpacityAnimator from QML. Whereas when building custom items, similar
+ results can be achieved by following the example's implementation.
+
+ \sa {Qt Quick Scene Graph}
+ */
diff --git a/examples/quick/scenegraph/twotextureproviders/CMakeLists.txt b/examples/quick/scenegraph/twotextureproviders/CMakeLists.txt
index 153b9d123b..cf597d3f0b 100644
--- a/examples/quick/scenegraph/twotextureproviders/CMakeLists.txt
+++ b/examples/quick/scenegraph/twotextureproviders/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(twotextureproviders LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/twotextureproviders")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools)
qt_standard_project_setup()
@@ -20,10 +14,10 @@ qt_add_executable(twotextureproviders WIN32 MACOSX_BUNDLE
)
target_link_libraries(twotextureproviders PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
qt_add_qml_module(twotextureproviders
@@ -47,7 +41,16 @@ qt6_add_shaders(twotextureproviders "shaders"
)
install(TARGETS twotextureproviders
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET twotextureproviders
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/twotextureproviders/doc/src/twotextureproviders.qdoc b/examples/quick/scenegraph/twotextureproviders/doc/src/twotextureproviders.qdoc
index a639c9b350..1bdd1ab551 100644
--- a/examples/quick/scenegraph/twotextureproviders/doc/src/twotextureproviders.qdoc
+++ b/examples/quick/scenegraph/twotextureproviders/doc/src/twotextureproviders.qdoc
@@ -4,6 +4,7 @@
/*!
\example scenegraph/twotextureproviders
\title Scene Graph - Two Texture Providers
+ \examplecategory {Graphics}
\ingroup qtquickexamples
\brief Shows how to combine two textures from two texture providers in a custom scene graph node.
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag b/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag
index 0932bc8c37..c684a2cedd 100644
--- a/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#version 440
layout(location = 0) in vec2 qt_TexCoord0;
diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag
index bc68160c1f..8587ae5316 100644
--- a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag
+++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag
@@ -1,3 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
#version 440
layout(location = 0) in vec2 vTexCoord;
diff --git a/examples/quick/scenegraph/vulkantextureimport/CMakeLists.txt b/examples/quick/scenegraph/vulkantextureimport/CMakeLists.txt
index 246fb2d6d2..778fe5bd87 100644
--- a/examples/quick/scenegraph/vulkantextureimport/CMakeLists.txt
+++ b/examples/quick/scenegraph/vulkantextureimport/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(vulkantextureimport LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/vulkantextureimport")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_standard_project_setup()
@@ -25,10 +19,10 @@ set_target_properties(vulkantextureimport PROPERTIES
)
target_link_libraries(vulkantextureimport PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
qt_add_qml_module(vulkantextureimport
@@ -43,7 +37,16 @@ qt_add_qml_module(vulkantextureimport
)
install(TARGETS vulkantextureimport
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET vulkantextureimport
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc b/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc
index 0d5571054a..97e7d8045f 100644
--- a/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc
+++ b/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc
@@ -4,8 +4,9 @@
/*!
\example scenegraph/vulkantextureimport
\title Scene Graph - Vulkan Texture Import
+ \examplecategory {Graphics}
\ingroup qtquickexamples
- \brief Shows how to use a texture created directly with use a texture created directly withulkan.
+ \brief Shows how to use a texture created directly with Vulkan.
\image vulkantextureimport-example.jpg
diff --git a/examples/quick/scenegraph/vulkanunderqml/CMakeLists.txt b/examples/quick/scenegraph/vulkanunderqml/CMakeLists.txt
index 79cbc60477..12b07b4518 100644
--- a/examples/quick/scenegraph/vulkanunderqml/CMakeLists.txt
+++ b/examples/quick/scenegraph/vulkanunderqml/CMakeLists.txt
@@ -1,15 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(vulkanunderqml LANGUAGES CXX)
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
-endif()
-
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/vulkanunderqml")
-
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_standard_project_setup()
@@ -25,10 +19,10 @@ set_target_properties(vulkanunderqml PROPERTIES
)
target_link_libraries(vulkanunderqml PRIVATE
- Qt::Core
- Qt::Gui
- Qt::Qml
- Qt::Quick
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
)
qt_add_qml_module(vulkanunderqml
@@ -43,7 +37,16 @@ qt_add_qml_module(vulkanunderqml
)
install(TARGETS vulkanunderqml
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET vulkanunderqml
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc b/examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc
index 08b84da7df..bb29731554 100644
--- a/examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc
+++ b/examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc
@@ -4,36 +4,20 @@
/*!
\example scenegraph/vulkanunderqml
\title Scene Graph - Vulkan Under QML
+ \examplecategory {Graphics}
\ingroup qtquickexamples
- \brief Shows how to render directly with vulkan under a Qt Quick scene.
+ \brief Shows how to render directly with Vulkan under a Qt Quick scene.
\image vulkanunderqml-example.jpg
- The Vulkan Under QML example shows how an application can make use of the
- \l QQuickWindow::beforeRendering() and \l
- QQuickWindow::beforeRenderPassRecording() signals to draw custom Vulkan
- content under a Qt Quick scene. This signal is emitted at the start of
- every frame, before the scene graph starts its rendering, thus any Vulkan
- draw calls that are made as a response to this signal, will stack under the
- Qt Quick items. There are two signals, because the custom Vulkan commands
- are recorded onto the same command buffer that is used by the scene graph.
- beforeRendering() on its own is not sufficient for this because it gets
- emitted at the start of the frame, before recording the start of a
- renderpass instance via
- \l{https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdBeginRenderPass.html}{vkCmdBeginRenderPass}.
- By also connecting to beforeRenderPassRecording(), the application's own
- commands and the scene graph's scaffolding will end up in the right order.
+ \note Compiling this example requires an SDK. See \l{Vulkan Integration} for
+ information on what to install.
- As an alternative, applications that wish to render Vulkan content
- on top of the Qt Quick scene, can do so by connecting to the \l
- QQuickWindow::afterRendering() and \l
- QQuickWindow::afterRenderPassRecording() signals.
+ \section1 Overview
- In this example, we will also see how it is possible to have
- values that are exposed to QML which affect the Vulkan
- rendering. We animate the threshold value using a NumberAnimation
- in the QML file and this value is used by the SPIR-V shader
- program that draws the squircles.
+ This example makes use of the \l QQuickWindow::beforeRendering()
+ and \l QQuickWindow::beforeRenderPassRecording() signals to draw custom Vulkan
+ content under a Qt Quick scene. QML is used to render a text label on top.
The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under
QML}{OpenGL Under QML}, \l{Scene Graph - Direct3D 11 Under QML}{Direct3D 11
@@ -41,4 +25,60 @@
examples, they all render the same custom content, just via different
native APIs.
+ The particulars of utilizing QML will be covered in this documentation
+ without delving into the detail of custom Vulkan rendering.
+
+ \section1 Affecting Vulkan rendering from QML
+
+ The example shows how to use values that are exposed to QML to control
+ Vulkan rendering.
+
+ To expose the threshold value \c t to QML, in the definition of \c VulkanSquircle,
+ we use the \l Q_OBJECT, \l Q_PROPERTY, and \l QML_ELEMENT macros like so:
+
+ \quotefromfile scenegraph/vulkanunderqml/vulkansquircle.h
+ \skipto class VulkanSquircle
+ \printto public:
+
+ We then go on to declare public and private items:
+
+ \printto };
+
+ Then in \c main.qml we animate the threshold value using a \l NumberAnimation.
+
+ \quotefromfile scenegraph/vulkanunderqml/main.qml
+ \skipto VulkanSquircle {
+ \printto running: true
+ The \c t variable is ultimately used by the SPIR-V shader program that draws
+ the squircles.
+
+ \section1 Using signals to render custom Vulkan content
+
+ The \l QQuickWindow::beforeRendering()
+ and \l QQuickWindow::beforeRenderPassRecording() signals are what are used.
+
+ The QQuickWindow::beforeRendering() signal is emitted at the start of
+ every frame, before the scene graph starts its rendering. This means any Vulkan
+ draw calls that are made as a response to this signal, will stack under the
+ Qt Quick items. There are two signals because the custom Vulkan commands
+ are recorded onto the same command buffer used by the scene graph.
+
+ The beforeRendering() function on its own is not sufficient for this, because
+ it gets emitted at the start of the frame, before recording the start of a
+ \c renderpass instance by using
+ \l{https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdBeginRenderPass.html}{vkCmdBeginRenderPass}.
+
+ The solution: by connecting to beforeRenderPassRecording(), the application's
+ own commands and the scene graph's scaffolding will end up in the right order.
+
+ Connecting the signals is done by the \c sync() function:
+
+ \quotefromfile scenegraph/vulkanunderqml/vulkansquircle.cpp
+ \skipto void VulkanSquircle::sync()
+ \printto m_renderer->setWindow(window());
+
+ Another way you can render Vulkan content on top of the Qt Quick scene is by
+ connecting to the \l QQuickWindow::afterRendering() and
+ \l QQuickWindow::afterRenderPassRecording() signals.
+
*/