aboutsummaryrefslogtreecommitdiffstats
path: root/examples/quick/scenegraph
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2019-10-14 18:46:38 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2019-10-14 19:02:37 +0200
commitc2f8b9535d34da6948ccf45b7d5fd90de2f1bc9e (patch)
treec6f7e058a985d7c18b51cadc76283caf555071c9 /examples/quick/scenegraph
parent9e633bbda7608ac0231809e2a6a97ae8f2d849d6 (diff)
parent803f18f02e5609a1ca00a5b78ea6d3613d44e1a0 (diff)
Merge remote-tracking branch 'origin/dev' into wip/cmake
Removed dependencies.yaml because we don't use it yet in wip/cmake. Fixed conflict in qmlcachegen.cpp. Change-Id: Ie1060c737bee1daa85779903598e5b6d5020d922
Diffstat (limited to 'examples/quick/scenegraph')
-rw-r--r--examples/quick/scenegraph/customgeometry/beziercurve.h1
-rw-r--r--examples/quick/scenegraph/customgeometry/main.cpp2
-rw-r--r--examples/quick/scenegraph/d3d11underqml/d3d11squircle.h1
-rw-r--r--examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro2
-rw-r--r--examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc6
-rw-r--r--examples/quick/scenegraph/d3d11underqml/main.cpp2
-rw-r--r--examples/quick/scenegraph/fboitem/CMakeLists.txt (renamed from examples/quick/scenegraph/textureinsgnode/CMakeLists.txt)0
-rw-r--r--examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg (renamed from examples/quick/scenegraph/textureinsgnode/doc/images/textureinsgnode-example.jpg)bin25863 -> 25863 bytes
-rw-r--r--examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc (renamed from examples/quick/scenegraph/textureinsgnode/doc/src/textureinsgnode.qdoc)4
-rw-r--r--examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp (renamed from examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.cpp)0
-rw-r--r--examples/quick/scenegraph/fboitem/fboinsgrenderer.h (renamed from examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.h)1
-rw-r--r--examples/quick/scenegraph/fboitem/fboitem.pro (renamed from examples/quick/scenegraph/textureinsgnode/textureinsgnode.pro)4
-rw-r--r--examples/quick/scenegraph/fboitem/fboitem.qrc (renamed from examples/quick/scenegraph/textureinsgnode/textureinsgnode.qrc)2
-rw-r--r--examples/quick/scenegraph/fboitem/main.cpp (renamed from examples/quick/scenegraph/textureinsgnode/main.cpp)4
-rw-r--r--examples/quick/scenegraph/fboitem/main.qml (renamed from examples/quick/scenegraph/textureinsgnode/main.qml)0
-rw-r--r--examples/quick/scenegraph/graph/graph.h1
-rw-r--r--examples/quick/scenegraph/graph/main.cpp2
-rw-r--r--examples/quick/scenegraph/metaltextureimport/doc/images/metaltextureimport-example.jpgbin0 -> 44545 bytes
-rw-r--r--examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc101
-rw-r--r--examples/quick/scenegraph/metaltextureimport/main.cpp70
-rw-r--r--examples/quick/scenegraph/metaltextureimport/main.qml123
-rw-r--r--examples/quick/scenegraph/metaltextureimport/metaltextureimport.h88
-rw-r--r--examples/quick/scenegraph/metaltextureimport/metaltextureimport.mm424
-rw-r--r--examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro12
-rw-r--r--examples/quick/scenegraph/metaltextureimport/metaltextureimport.qrc7
-rw-r--r--examples/quick/scenegraph/metaltextureimport/squircle.frag29
-rw-r--r--examples/quick/scenegraph/metaltextureimport/squircle.vert23
-rw-r--r--examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc7
-rw-r--r--examples/quick/scenegraph/metalunderqml/main.cpp2
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalsquircle.h1
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalsquircle.mm13
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalunderqml.pro2
-rw-r--r--examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc7
-rw-r--r--examples/quick/scenegraph/openglunderqml/main.cpp2
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.h1
-rw-r--r--examples/quick/scenegraph/rendernode/customrenderitem.cpp62
-rw-r--r--examples/quick/scenegraph/rendernode/customrenderitem.h1
-rw-r--r--examples/quick/scenegraph/rendernode/d3d12renderer.cpp28
-rw-r--r--examples/quick/scenegraph/rendernode/d3d12renderer.h11
-rw-r--r--examples/quick/scenegraph/rendernode/main.cpp2
-rw-r--r--examples/quick/scenegraph/rendernode/metalrenderer.h16
-rw-r--r--examples/quick/scenegraph/rendernode/metalrenderer.mm33
-rw-r--r--examples/quick/scenegraph/rendernode/openglrenderer.cpp17
-rw-r--r--examples/quick/scenegraph/rendernode/openglrenderer.h8
-rw-r--r--examples/quick/scenegraph/rendernode/softwarerenderer.cpp26
-rw-r--r--examples/quick/scenegraph/rendernode/softwarerenderer.h7
-rw-r--r--examples/quick/scenegraph/scenegraph.pro10
-rw-r--r--examples/quick/scenegraph/simplematerial/simplematerial.cpp3
-rw-r--r--examples/quick/scenegraph/textureinthread/main.cpp2
-rw-r--r--examples/quick/scenegraph/textureinthread/threadrenderer.h1
-rw-r--r--examples/quick/scenegraph/threadedanimation/main.cpp2
-rw-r--r--examples/quick/scenegraph/threadedanimation/spinner.h1
-rw-r--r--examples/quick/scenegraph/twotextureproviders/main.cpp2
-rw-r--r--examples/quick/scenegraph/twotextureproviders/xorblender.h1
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/doc/images/vulkanunderqml-example.jpgbin0 -> 39962 bytes
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc68
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/main.cpp70
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/main.qml89
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/squircle.frag.spvbin0 -> 1432 bytes
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/squircle.vert.spvbin0 -> 644 bytes
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/vulkansquircle.cpp623
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h86
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro10
-rw-r--r--examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.qrc7
64 files changed, 2012 insertions, 118 deletions
diff --git a/examples/quick/scenegraph/customgeometry/beziercurve.h b/examples/quick/scenegraph/customgeometry/beziercurve.h
index f2f7832e6d..be9e4ef49f 100644
--- a/examples/quick/scenegraph/customgeometry/beziercurve.h
+++ b/examples/quick/scenegraph/customgeometry/beziercurve.h
@@ -64,6 +64,7 @@ class BezierCurve : public QQuickItem
Q_PROPERTY(QPointF p4 READ p4 WRITE setP4 NOTIFY p4Changed)
Q_PROPERTY(int segmentCount READ segmentCount WRITE setSegmentCount NOTIFY segmentCountChanged)
+ QML_ELEMENT
public:
BezierCurve(QQuickItem *parent = 0);
diff --git a/examples/quick/scenegraph/customgeometry/main.cpp b/examples/quick/scenegraph/customgeometry/main.cpp
index 6f3c24e87b..9352e4bd24 100644
--- a/examples/quick/scenegraph/customgeometry/main.cpp
+++ b/examples/quick/scenegraph/customgeometry/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<BezierCurve>("CustomGeometry", 1, 0, "BezierCurve");
+ qmlRegisterTypesAndRevisions<BezierCurve>("CustomGeometry", 1);
QQuickView view;
QSurfaceFormat format = view.format();
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
index be9aadc43b..4be3671d1c 100644
--- a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
+++ b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
@@ -59,6 +59,7 @@ class D3D11Squircle : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+ QML_ELEMENT
public:
D3D11Squircle();
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro
index 3c94d48ac4..7658a9a813 100644
--- a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro
+++ b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro
@@ -1,3 +1,5 @@
+!win32: error("This example requires Windows")
+
QT += qml quick
HEADERS += d3d11squircle.h
diff --git a/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
index d7b60d3b81..1f0c15e1c6 100644
--- a/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
+++ b/examples/quick/scenegraph/d3d11underqml/doc/src/d3d11underqml.qdoc
@@ -51,8 +51,8 @@
program that draws the squircles.
The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under
- QML}{OpenGL Under QML} and \l{Scene Graph - Metal Under QML}{Metal Under
- QML} examples, they all render the same custom content, just via different
- native APIs.
+ QML}{OpenGL Under QML}, \l{Scene Graph - Metal Under QML}{Metal Under QML},
+ and \l{Scene Graph - Vulkan Under QML}{Vulkan Under QML} examples, they all
+ render the same custom content, just via different native APIs.
*/
diff --git a/examples/quick/scenegraph/d3d11underqml/main.cpp b/examples/quick/scenegraph/d3d11underqml/main.cpp
index d26de1144a..dcab8c879c 100644
--- a/examples/quick/scenegraph/d3d11underqml/main.cpp
+++ b/examples/quick/scenegraph/d3d11underqml/main.cpp
@@ -56,7 +56,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<D3D11Squircle>("D3D11UnderQML", 1, 0, "D3D11Squircle");
+ qmlRegisterTypesAndRevisions<D3D11Squircle>("D3D11UnderQML", 1);
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Direct3D11Rhi);
diff --git a/examples/quick/scenegraph/textureinsgnode/CMakeLists.txt b/examples/quick/scenegraph/fboitem/CMakeLists.txt
index 1117ef22a9..1117ef22a9 100644
--- a/examples/quick/scenegraph/textureinsgnode/CMakeLists.txt
+++ b/examples/quick/scenegraph/fboitem/CMakeLists.txt
diff --git a/examples/quick/scenegraph/textureinsgnode/doc/images/textureinsgnode-example.jpg b/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg
index 306b8bab20..306b8bab20 100644
--- a/examples/quick/scenegraph/textureinsgnode/doc/images/textureinsgnode-example.jpg
+++ b/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/textureinsgnode/doc/src/textureinsgnode.qdoc b/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc
index c1c830338b..b5add02991 100644
--- a/examples/quick/scenegraph/textureinsgnode/doc/src/textureinsgnode.qdoc
+++ b/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc
@@ -26,11 +26,11 @@
****************************************************************************/
/*!
- \example scenegraph/textureinsgnode
+ \example scenegraph/fboitem
\title Scene Graph - Rendering FBOs
\ingroup qtquickexamples
\brief Shows how to use FramebufferObjects with Qt Quick.
- \image textureinsgnode-example.jpg
+ \image fboitem-example.jpg
*/
diff --git a/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.cpp b/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp
index 8ba5bddb2a..8ba5bddb2a 100644
--- a/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.cpp
+++ b/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp
diff --git a/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.h b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
index e1a9ce22c8..1b92b56851 100644
--- a/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.h
+++ b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h
@@ -58,6 +58,7 @@ class LogoRenderer;
class FboInSGRenderer : public QQuickFramebufferObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Renderer)
public:
Renderer *createRenderer() const;
};
diff --git a/examples/quick/scenegraph/textureinsgnode/textureinsgnode.pro b/examples/quick/scenegraph/fboitem/fboitem.pro
index 238e20a553..e40e5f4cf8 100644
--- a/examples/quick/scenegraph/textureinsgnode/textureinsgnode.pro
+++ b/examples/quick/scenegraph/fboitem/fboitem.pro
@@ -7,9 +7,9 @@ INCLUDEPATH += ../shared
HEADERS += ../shared/logorenderer.h
SOURCES += ../shared/logorenderer.cpp
-RESOURCES += textureinsgnode.qrc
+RESOURCES += fboitem.qrc
-target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/textureinsgnode
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/fboitem
INSTALLS += target
OTHER_FILES += \
diff --git a/examples/quick/scenegraph/textureinsgnode/textureinsgnode.qrc b/examples/quick/scenegraph/fboitem/fboitem.qrc
index 9ecf0ada1c..9d9db70654 100644
--- a/examples/quick/scenegraph/textureinsgnode/textureinsgnode.qrc
+++ b/examples/quick/scenegraph/fboitem/fboitem.qrc
@@ -1,5 +1,5 @@
<RCC>
- <qresource prefix="/scenegraph/textureinsgnode">
+ <qresource prefix="/scenegraph/fboitem">
<file>main.qml</file>
</qresource>
</RCC>
diff --git a/examples/quick/scenegraph/textureinsgnode/main.cpp b/examples/quick/scenegraph/fboitem/main.cpp
index 8eececc0aa..056bf24ade 100644
--- a/examples/quick/scenegraph/textureinsgnode/main.cpp
+++ b/examples/quick/scenegraph/fboitem/main.cpp
@@ -58,11 +58,11 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<FboInSGRenderer>("SceneGraphRendering", 1, 0, "Renderer");
+ qmlRegisterTypesAndRevisions<FboInSGRenderer>("SceneGraphRendering", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
- view.setSource(QUrl("qrc:///scenegraph/textureinsgnode/main.qml"));
+ view.setSource(QUrl("qrc:///scenegraph/fboitem/main.qml"));
view.show();
return app.exec();
diff --git a/examples/quick/scenegraph/textureinsgnode/main.qml b/examples/quick/scenegraph/fboitem/main.qml
index 92fa99e847..92fa99e847 100644
--- a/examples/quick/scenegraph/textureinsgnode/main.qml
+++ b/examples/quick/scenegraph/fboitem/main.qml
diff --git a/examples/quick/scenegraph/graph/graph.h b/examples/quick/scenegraph/graph/graph.h
index a1a00cb6dc..e32e657e0e 100644
--- a/examples/quick/scenegraph/graph/graph.h
+++ b/examples/quick/scenegraph/graph/graph.h
@@ -56,6 +56,7 @@
class Graph : public QQuickItem
{
Q_OBJECT
+ QML_ELEMENT
public:
Graph();
diff --git a/examples/quick/scenegraph/graph/main.cpp b/examples/quick/scenegraph/graph/main.cpp
index 2406457ab5..9a575944b9 100644
--- a/examples/quick/scenegraph/graph/main.cpp
+++ b/examples/quick/scenegraph/graph/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
- qmlRegisterType<Graph>("Graph", 1, 0, "Graph");
+ qmlRegisterTypesAndRevisions<Graph>("Graph", 1);
QQuickView view;
view.resize(800, 400);
diff --git a/examples/quick/scenegraph/metaltextureimport/doc/images/metaltextureimport-example.jpg b/examples/quick/scenegraph/metaltextureimport/doc/images/metaltextureimport-example.jpg
new file mode 100644
index 0000000000..19ad40cd85
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/doc/images/metaltextureimport-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc b/examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc
new file mode 100644
index 0000000000..2a584c26cc
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/doc/src/metaltextureimport.qdoc
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example scenegraph/metaltextureimport
+ \title Scene Graph - Metal Texture Import
+ \ingroup qtquickexamples
+ \brief Shows how to use a texture created directly with Metal
+
+ \image metaltextureimport-example.jpg
+
+ The Metal Texture Import example shows how an application can import and
+ use a
+ \l{https://developer.apple.com/documentation/metal/mtltexture}{MTLTexture}
+ in the Qt Quick scene. This provides an alternative to the \l{Scene Graph -
+ Metal Under QML}{underlay}, overlay, or \l{Scene Graph - Custom Rendering
+ with QSGRenderNode}{render node} approaches when it comes to integrating
+ native Metal rendering. In many cases going through a texture, and
+ therefore "flattening" the 3D contents first, is the best option to
+ integrate and mix custom 3D contents with the 2D UI elements provided by Qt
+ Quick.
+
+ \snippet scenegraph/metaltextureimport/main.qml 1
+ \snippet scenegraph/metaltextureimport/main.qml 2
+
+ The application exposes a custom QQuickItem subclass under ther name of
+ CustomTextureItem. This is instantiated in QML. The value of the \c t
+ property is animated as well.
+
+ \snippet scenegraph/metaltextureimport/metaltextureimport.h 1
+
+ The implementation of our custom item involves overriding
+ QQuickItem::updatePaintNode(), as well as functions and slots related to
+ geometry changes and cleanup.
+
+ \snippet scenegraph/metaltextureimport/metaltextureimport.mm 1
+
+ We also need a scenegraph node. Instead of deriving directly from QSGNode,
+ we can use QSGSimpleTextureNode which gives us some of the functionality
+ pre-implemented as a convenience.
+
+ \snippet scenegraph/metaltextureimport/metaltextureimport.mm 2
+
+ The updatePaintNode() function of the item is called on the render thread
+ (if there is one), with the main (gui) thread blocked. Here we create a new
+ node if there has not yet been one, and update it. Accessing Qt objects
+ living on the main thread is safe here, so sync() will calculate and copy
+ the values it needs from QQuickItem or QQuickWindow.
+
+ \snippet scenegraph/metaltextureimport/metaltextureimport.mm 3
+
+ The node does not merely rely on the typical QQuickItem - QSGNode
+ update sequence, it connects to QQuickWindow::beforeRendering() as
+ well. That is where the contents of the Metal texture will be updated by
+ encoding a full render pass, targeting the texture, on the Qt Quicks
+ scenegraph's command buffer. beforeRendering() is the right place for this,
+ because the signal is emitted before Qt Quick starts to encode its own
+ rendering commands. Choosing QQuickWindow::beforeRenderPassRecording()
+ instead would be an error in this exanple.
+
+ \snippet scenegraph/metaltextureimport/metaltextureimport.mm 4
+ \snippet scenegraph/metaltextureimport/metaltextureimport.mm 5
+
+ 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
+ materials by calling the base class' setTexture() function.
+
+ \snippet scenegraph/metaltextureimport/metaltextureimport.mm 6
+
+ render(), the slot connected to beforeRendering(), encodes the rendering
+ commands using the buffers and pipeline state objects created in sync().
+
+ */
diff --git a/examples/quick/scenegraph/metaltextureimport/main.cpp b/examples/quick/scenegraph/metaltextureimport/main.cpp
new file mode 100644
index 0000000000..c969817e8f
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/main.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QtQuick/QQuickView>
+#include "metaltextureimport.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<CustomTextureItem>("MetalTextureImport", 1, 0, "CustomTextureItem");
+
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::MetalRhi);
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:///scenegraph/metaltextureimport/main.qml"));
+ view.resize(400, 400);
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/quick/scenegraph/metaltextureimport/main.qml b/examples/quick/scenegraph/metaltextureimport/main.qml
new file mode 100644
index 0000000000..facab4e440
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/main.qml
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+//! [1]
+import MetalTextureImport 1.0
+//! [1]
+
+Rectangle {
+ gradient: Gradient {
+ GradientStop { position: 0; color: "steelblue" }
+ GradientStop { position: 1; color: "black" }
+ }
+
+ //! [2]
+ CustomTextureItem {
+ id: renderer
+ anchors.fill: parent
+ anchors.margins: 10
+
+ 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
+ }
+ //! [2]
+
+ 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 }
+ ]
+ }
+
+ 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.1; 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: true
+ loops: Animation.Infinite
+ }
+
+ Rectangle {
+ id: labelFrame
+ anchors.margins: -10
+ radius: 5
+ color: "white"
+ border.color: "black"
+ opacity: 0.5
+ 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: "The squircle, using rendering code borrowed from the metalunderqml example, is rendered into a texture directly with Metal. The MTLTexture is then imported and used in a custom Qt Quick item."
+ }
+}
diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h
new file mode 100644
index 0000000000..afc5aced97
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef METALTEXTUREIMPORT_H
+#define METALTEXTUREIMPORT_H
+
+#include <QtQuick/QQuickItem>
+
+class CustomTextureNode;
+
+//! [1]
+class CustomTextureItem : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+
+public:
+ CustomTextureItem();
+
+ qreal t() const { return m_t; }
+ void setT(qreal t);
+
+signals:
+ void tChanged();
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+private slots:
+ void invalidateSceneGraph();
+
+private:
+ void releaseResources() override;
+
+ CustomTextureNode *m_node = nullptr;
+ qreal m_t = 0;
+};
+//! [1]
+
+#endif // METALTEXTUREIMPORT_H
diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.mm b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.mm
new file mode 100644
index 0000000000..66a39083f7
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.mm
@@ -0,0 +1,424 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "metaltextureimport.h"
+#include <QtGui/QScreen>
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/QSGTextureProvider>
+#include <QtQuick/QSGSimpleTextureNode>
+
+#include <Metal/Metal.h>
+
+//! [1]
+class CustomTextureNode : public QSGTextureProvider, public QSGSimpleTextureNode
+{
+ Q_OBJECT
+
+public:
+ CustomTextureNode(QQuickItem *item);
+ ~CustomTextureNode();
+
+ QSGTexture *texture() const override;
+
+ void sync();
+//! [1]
+private slots:
+ void render();
+
+private:
+ enum Stage {
+ VertexStage,
+ FragmentStage
+ };
+ void prepareShader(Stage stage);
+ using FuncAndLib = QPair<id<MTLFunction>, id<MTLLibrary> >;
+ FuncAndLib compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint);
+
+ QQuickItem *m_item;
+ QQuickWindow *m_window;
+ QSize m_size;
+ qreal m_dpr;
+ id<MTLDevice> m_device = nil;
+ id<MTLTexture> m_texture = nil;
+
+ bool m_initialized = false;
+ QByteArray m_vert;
+ QByteArray m_vertEntryPoint;
+ QByteArray m_frag;
+ QByteArray m_fragEntryPoint;
+ FuncAndLib m_vs;
+ FuncAndLib m_fs;
+ id<MTLBuffer> m_vbuf;
+ id<MTLBuffer> m_ubuf[3];
+ id<MTLRenderPipelineState> m_pipeline;
+
+ float m_t;
+};
+
+CustomTextureItem::CustomTextureItem()
+{
+ setFlag(ItemHasContents, true);
+}
+
+// The beauty of using a true QSGNode: no need for complicated cleanup
+// arrangements, unlike in other examples like metalunderqml, because the
+// scenegraph will handle destroying the node at the appropriate time.
+
+void CustomTextureItem::invalidateSceneGraph() // called on the render thread when the scenegraph is invalidated
+{
+ m_node = nullptr;
+}
+
+void CustomTextureItem::releaseResources() // called on the gui thread if the item is removed from scene
+{
+ m_node = nullptr;
+}
+
+//! [2]
+QSGNode *CustomTextureItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
+{
+ CustomTextureNode *n = static_cast<CustomTextureNode *>(node);
+
+ if (!n && (width() <= 0 || height() <= 0))
+ return nullptr;
+
+ if (!n) {
+ m_node = new CustomTextureNode(this);
+ n = m_node;
+ }
+
+ m_node->sync();
+
+ n->setTextureCoordinatesTransform(QSGSimpleTextureNode::NoTransform);
+ n->setFiltering(QSGTexture::Linear);
+ n->setRect(0, 0, width(), height());
+
+ window()->update(); // ensure getting to beforeRendering() at some point
+
+ return n;
+}
+//! [2]
+
+void CustomTextureItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+
+ if (newGeometry.size() != oldGeometry.size())
+ update();
+}
+
+void CustomTextureItem::setT(qreal t)
+{
+ if (t == m_t)
+ return;
+
+ m_t = t;
+ emit tChanged();
+
+ update();
+}
+
+//! [3]
+CustomTextureNode::CustomTextureNode(QQuickItem *item)
+ : m_item(item)
+{
+ m_window = m_item->window();
+ connect(m_window, &QQuickWindow::beforeRendering, this, &CustomTextureNode::render);
+ connect(m_window, &QQuickWindow::screenChanged, this, [this]() {
+ if (m_window->effectiveDevicePixelRatio() != m_dpr)
+ m_item->update();
+ });
+//! [3]
+ m_vs.first = nil;
+ m_vs.second = nil;
+
+ m_fs.first = nil;
+ m_fs.second = nil;
+
+ m_vbuf = nil;
+
+ for (int i = 0; i < 3; ++i)
+ m_ubuf[i] = nil;
+
+ m_pipeline = nil;
+
+ qDebug("renderer created");
+}
+
+CustomTextureNode::~CustomTextureNode()
+{
+ [m_pipeline release];
+
+ [m_vbuf release];
+
+ for (int i = 0; i < 3; ++i)
+ [m_ubuf[i] release];
+
+ [m_vs.first release];
+ [m_vs.second release];
+
+ [m_fs.first release];
+ [m_fs.second release];
+
+ delete texture();
+ [m_texture release];
+
+ qDebug("renderer destroyed");
+}
+
+QSGTexture *CustomTextureNode::texture() const
+{
+ return QSGSimpleTextureNode::texture();
+}
+
+static const float vertices[] = {
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ 1, 1
+};
+
+const int UBUF_SIZE = 4;
+
+//! [4]
+void CustomTextureNode::sync()
+{
+ m_dpr = m_window->effectiveDevicePixelRatio();
+ const QSize newSize = m_window->size() * m_dpr;
+ bool needsNew = false;
+
+ if (!texture())
+ needsNew = true;
+
+ if (newSize != m_size) {
+ needsNew = true;
+ m_size = newSize;
+ }
+
+ if (needsNew) {
+ delete texture();
+ [m_texture release];
+
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ m_device = (id<MTLDevice>) rif->getResource(m_window, QSGRendererInterface::DeviceResource);
+ Q_ASSERT(m_device);
+
+ MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
+ desc.textureType = MTLTextureType2D;
+ desc.pixelFormat = MTLPixelFormatRGBA8Unorm;
+ desc.width = m_size.width();
+ desc.height = m_size.height();
+ desc.mipmapLevelCount = 1;
+ desc.resourceOptions = MTLResourceStorageModePrivate;
+ desc.storageMode = MTLStorageModePrivate;
+ desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
+ m_texture = [m_device newTextureWithDescriptor: desc];
+ [desc release];
+
+ QSGTexture *wrapper = m_window->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture,
+ &m_texture,
+ 0,
+ m_size);
+
+ qDebug() << "Got QSGTexture wrapper" << wrapper << "for an MTLTexture of size" << m_size;
+
+ setTexture(wrapper);
+ }
+//! [4]
+ if (!m_initialized && texture()) {
+ m_initialized = true;
+
+ prepareShader(VertexStage);
+ prepareShader(FragmentStage);
+
+ m_vs = compileShaderFromSource(m_vert, m_vertEntryPoint);
+ m_fs = compileShaderFromSource(m_frag, m_fragEntryPoint);
+
+ const int framesInFlight = m_window->graphicsStateInfo().framesInFlight;
+
+ m_vbuf = [m_device newBufferWithLength: sizeof(vertices) options: MTLResourceStorageModeShared];
+ void *p = [m_vbuf contents];
+ memcpy(p, vertices, sizeof(vertices));
+
+ for (int i = 0; i < framesInFlight; ++i)
+ m_ubuf[i] = [m_device newBufferWithLength: UBUF_SIZE options: MTLResourceStorageModeShared];
+
+ MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor];
+ inputLayout.attributes[0].format = MTLVertexFormatFloat2;
+ inputLayout.attributes[0].offset = 0;
+ inputLayout.attributes[0].bufferIndex = 1; // ubuf is 0, vbuf is 1
+ inputLayout.layouts[1].stride = 2 * sizeof(float);
+
+ MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init];
+ rpDesc.vertexDescriptor = inputLayout;
+
+ rpDesc.vertexFunction = m_vs.first;
+ rpDesc.fragmentFunction = m_fs.first;
+
+ rpDesc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;
+ rpDesc.colorAttachments[0].blendingEnabled = true;
+ rpDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
+ rpDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
+ rpDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne;
+ rpDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne;
+
+ NSError *err = nil;
+ m_pipeline = [m_device newRenderPipelineStateWithDescriptor: rpDesc error: &err];
+ if (!m_pipeline) {
+ const QString msg = QString::fromNSString(err.localizedDescription);
+ qFatal("Failed to create render pipeline state: %s", qPrintable(msg));
+ }
+ [rpDesc release];
+
+ qDebug("resources initialized");
+ }
+
+//! [5]
+ m_t = float(static_cast<CustomTextureItem *>(m_item)->t());
+//! [5]
+}
+
+// This is hooked up to beforeRendering() so we can start our own render
+// command encoder. If we instead wanted to use the scenegraph's render command
+// encoder (targeting the window), it should be connected to
+// beforeRenderPassRecording() instead.
+//! [6]
+void CustomTextureNode::render()
+{
+ if (!m_initialized)
+ return;
+
+ // Render to m_texture.
+ MTLRenderPassDescriptor *renderpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
+ MTLClearColor c = MTLClearColorMake(0, 0, 0, 1);
+ renderpassdesc.colorAttachments[0].loadAction = MTLLoadActionClear;
+ renderpassdesc.colorAttachments[0].storeAction = MTLStoreActionStore;
+ renderpassdesc.colorAttachments[0].clearColor = c;
+ renderpassdesc.colorAttachments[0].texture = m_texture;
+
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ id<MTLCommandBuffer> cb = (id<MTLCommandBuffer>) rif->getResource(m_window, QSGRendererInterface::CommandListResource);
+ Q_ASSERT(cb);
+ id<MTLRenderCommandEncoder> encoder = [cb renderCommandEncoderWithDescriptor: renderpassdesc];
+
+ const QQuickWindow::GraphicsStateInfo &stateInfo(m_window->graphicsStateInfo());
+ void *p = [m_ubuf[stateInfo.currentFrameSlot] contents];
+ memcpy(p, &m_t, 4);
+
+ MTLViewport vp;
+ vp.originX = 0;
+ vp.originY = 0;
+ vp.width = m_size.width();
+ vp.height = m_size.height();
+ vp.znear = 0;
+ vp.zfar = 1;
+ [encoder setViewport: vp];
+
+ [encoder setFragmentBuffer: m_ubuf[stateInfo.currentFrameSlot] offset: 0 atIndex: 0];
+ [encoder setVertexBuffer: m_vbuf offset: 0 atIndex: 1];
+ [encoder setRenderPipelineState: m_pipeline];
+ [encoder drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: 4 instanceCount: 1 baseInstance: 0];
+
+ [encoder endEncoding];
+}
+//! [6]
+
+void CustomTextureNode::prepareShader(Stage stage)
+{
+ QString filename;
+ if (stage == VertexStage) {
+ filename = QLatin1String(":/scenegraph/metaltextureimport/squircle.vert");
+ } else {
+ Q_ASSERT(stage == FragmentStage);
+ filename = QLatin1String(":/scenegraph/metaltextureimport/squircle.frag");
+ }
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly))
+ qFatal("Failed to read shader %s", qPrintable(filename));
+
+ const QByteArray contents = f.readAll();
+
+ if (stage == VertexStage) {
+ m_vert = contents;
+ Q_ASSERT(!m_vert.isEmpty());
+ m_vertEntryPoint = QByteArrayLiteral("main0");
+ } else {
+ m_frag = contents;
+ Q_ASSERT(!m_frag.isEmpty());
+ m_fragEntryPoint = QByteArrayLiteral("main0");
+ }
+}
+
+CustomTextureNode::FuncAndLib CustomTextureNode::compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint)
+{
+ FuncAndLib fl;
+
+ NSString *srcstr = [NSString stringWithUTF8String: src.constData()];
+ MTLCompileOptions *opts = [[MTLCompileOptions alloc] init];
+ opts.languageVersion = MTLLanguageVersion1_2;
+ NSError *err = nil;
+ fl.second = [m_device newLibraryWithSource: srcstr options: opts error: &err];
+ [opts release];
+ // srcstr is autoreleased
+
+ if (err) {
+ const QString msg = QString::fromNSString(err.localizedDescription);
+ qFatal("%s", qPrintable(msg));
+ return fl;
+ }
+
+ NSString *name = [NSString stringWithUTF8String: entryPoint.constData()];
+ fl.first = [fl.second newFunctionWithName: name];
+ [name release];
+
+ return fl;
+}
+
+#include "metaltextureimport.moc"
diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro
new file mode 100644
index 0000000000..5b11606946
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro
@@ -0,0 +1,12 @@
+!macos: error("This example requires macOS")
+
+QT += qml quick
+
+HEADERS += metaltextureimport.h
+SOURCES += metaltextureimport.mm main.cpp
+RESOURCES += metaltextureimport.qrc
+
+LIBS += -framework Metal -framework AppKit
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/metaltextureimport
+INSTALLS += target
diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.qrc b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.qrc
new file mode 100644
index 0000000000..7a8dd7a860
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/scenegraph/metaltextureimport">
+ <file>main.qml</file>
+ <file>squircle.vert</file>
+ <file>squircle.frag</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/scenegraph/metaltextureimport/squircle.frag b/examples/quick/scenegraph/metaltextureimport/squircle.frag
new file mode 100644
index 0000000000..15f34624fe
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/squircle.frag
@@ -0,0 +1,29 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct buf
+{
+ float t;
+};
+
+struct main0_out
+{
+ float4 fragColor [[color(0)]];
+};
+
+struct main0_in
+{
+ float2 coords [[user(locn0)]];
+};
+
+fragment main0_out main0(main0_in in [[stage_in]], constant buf& ubuf [[buffer(0)]])
+{
+ main0_out out = {};
+ float i = 1.0 - (pow(abs(in.coords.x), 4.0) + pow(abs(in.coords.y), 4.0));
+ i = smoothstep(ubuf.t - 0.800000011920928955078125, ubuf.t + 0.800000011920928955078125, i);
+ i = floor(i * 20.0) / 20.0;
+ out.fragColor = float4((in.coords * 0.5) + float2(0.5), i, i);
+ return out;
+}
diff --git a/examples/quick/scenegraph/metaltextureimport/squircle.vert b/examples/quick/scenegraph/metaltextureimport/squircle.vert
new file mode 100644
index 0000000000..a88c59f541
--- /dev/null
+++ b/examples/quick/scenegraph/metaltextureimport/squircle.vert
@@ -0,0 +1,23 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct main0_out
+{
+ float2 coords [[user(locn0)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ float4 vertices [[attribute(0)]];
+};
+
+vertex main0_out main0(main0_in in [[stage_in]])
+{
+ main0_out out = {};
+ out.gl_Position = in.vertices;
+ out.coords = in.vertices.xy;
+ return out;
+}
diff --git a/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
index d499f47de3..fb28270315 100644
--- a/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
+++ b/examples/quick/scenegraph/metalunderqml/doc/src/metalunderqml.qdoc
@@ -61,8 +61,9 @@
program that draws the squircles.
The example is equivalent in most ways to the \l{Scene Graph - OpenGL Under
- QML}{OpenGL Under QML} and \l{Scene Graph - Direct3D 11 Under QML}{Direct3D
- 11 Under QML} examples, they all render the same custom content, just via
- different native APIs.
+ QML}{OpenGL Under QML}, \l{Scene Graph - Direct3D 11 Under QML}{Direct3D 11
+ Under QML}, and \l{Scene Graph - Vulkan Under QML}{Vulkan Under QML}
+ examples, they all render the same custom content, just via different
+ native APIs.
*/
diff --git a/examples/quick/scenegraph/metalunderqml/main.cpp b/examples/quick/scenegraph/metalunderqml/main.cpp
index 5ad337abb1..3e620137cd 100644
--- a/examples/quick/scenegraph/metalunderqml/main.cpp
+++ b/examples/quick/scenegraph/metalunderqml/main.cpp
@@ -56,7 +56,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<MetalSquircle>("MetalUnderQML", 1, 0, "MetalSquircle");
+ qmlRegisterTypesAndRevisions<MetalSquircle>("MetalUnderQML", 1);
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::MetalRhi);
diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.h b/examples/quick/scenegraph/metalunderqml/metalsquircle.h
index 43c4afad21..18db7d45f3 100644
--- a/examples/quick/scenegraph/metalunderqml/metalsquircle.h
+++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.h
@@ -59,6 +59,7 @@ class MetalSquircle : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+ QML_ELEMENT
public:
MetalSquircle();
diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.mm b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
index 92aceeb433..5ca6daa01a 100644
--- a/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
+++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
@@ -186,7 +186,12 @@ void MetalSquircle::sync()
{
if (!m_renderer) {
m_renderer = new SquircleRenderer;
+ // Initializing resources is done before starting to encode render
+ // commands, 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->setViewportSize(window()->size() * window()->devicePixelRatio());
@@ -210,7 +215,7 @@ void SquircleRenderer::frameStart()
prepareShader(FragmentStage);
if (!m_initialized)
- init(m_window->graphicsStateInfo()->framesInFlight);
+ init(m_window->graphicsStateInfo().framesInFlight);
}
static const float vertices[] = {
@@ -228,7 +233,7 @@ void SquircleRenderer::mainPassRecordingStart()
// the scenegraph's main renderpass. It does not create its own passes,
// rendertargets, etc. so no synchronization is needed.
- const QQuickWindow::GraphicsStateInfo *stateInfo = m_window->graphicsStateInfo();
+ const QQuickWindow::GraphicsStateInfo &stateInfo(m_window->graphicsStateInfo());
QSGRendererInterface *rif = m_window->rendererInterface();
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>) rif->getResource(
@@ -237,7 +242,7 @@ void SquircleRenderer::mainPassRecordingStart()
m_window->beginExternalCommands();
- void *p = [m_ubuf[stateInfo->currentFrameSlot] contents];
+ void *p = [m_ubuf[stateInfo.currentFrameSlot] contents];
float t = m_t;
memcpy(p, &t, 4);
@@ -250,7 +255,7 @@ void SquircleRenderer::mainPassRecordingStart()
vp.zfar = 1;
[encoder setViewport: vp];
- [encoder setFragmentBuffer: m_ubuf[stateInfo->currentFrameSlot] offset: 0 atIndex: 0];
+ [encoder setFragmentBuffer: m_ubuf[stateInfo.currentFrameSlot] offset: 0 atIndex: 0];
[encoder setVertexBuffer: m_vbuf offset: 0 atIndex: 1];
[encoder setRenderPipelineState: m_pipeline];
[encoder drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: 4 instanceCount: 1 baseInstance: 0];
diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
index 9b27638a6d..9fd131fe1b 100644
--- a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
+++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
@@ -1,3 +1,5 @@
+!macos: error("This example requires macOS")
+
QT += qml quick
HEADERS += metalsquircle.h
diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
index ed46b40420..9676815c44 100644
--- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
+++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
@@ -50,9 +50,10 @@
in the QML file and this value is used by the OpenGL shader
program that draws the squircles.
- The example is equivalent in most ways to the \l{Scene Graph - Direct3D 11 Under
- QML}{Direct3D 11 Under QML} and \l{Scene Graph - Metal Under QML}{Metal Under
- QML} examples, they all render the same custom content, just via different
+ The example is equivalent in most ways to the \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, they all render the same custom content, just via different
native APIs.
\snippet scenegraph/openglunderqml/squircle.h 2
diff --git a/examples/quick/scenegraph/openglunderqml/main.cpp b/examples/quick/scenegraph/openglunderqml/main.cpp
index 022d6a75bb..c04d0da68f 100644
--- a/examples/quick/scenegraph/openglunderqml/main.cpp
+++ b/examples/quick/scenegraph/openglunderqml/main.cpp
@@ -59,7 +59,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<Squircle>("OpenGLUnderQML", 1, 0, "Squircle");
+ qmlRegisterTypesAndRevisions<Squircle>("OpenGLUnderQML", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h
index 1b9995bc1e..c24fdd50c2 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.h
+++ b/examples/quick/scenegraph/openglunderqml/squircle.h
@@ -86,6 +86,7 @@ class Squircle : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+ QML_ELEMENT
public:
Squircle();
diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.cpp b/examples/quick/scenegraph/rendernode/customrenderitem.cpp
index 67a9cccfc6..e55cf0a2f4 100644
--- a/examples/quick/scenegraph/rendernode/customrenderitem.cpp
+++ b/examples/quick/scenegraph/rendernode/customrenderitem.cpp
@@ -70,48 +70,58 @@ CustomRenderItem::CustomRenderItem(QQuickItem *parent)
QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
QSGRenderNode *n = static_cast<QSGRenderNode *>(node);
- if (!n) {
- QSGRendererInterface *ri = window()->rendererInterface();
- if (!ri)
- return nullptr;
- switch (ri->graphicsApi()) {
- case QSGRendererInterface::OpenGL:
- Q_FALLTHROUGH();
- case QSGRendererInterface::OpenGLRhi:
+
+ QSGRendererInterface *ri = window()->rendererInterface();
+ if (!ri)
+ return nullptr;
+
+ switch (ri->graphicsApi()) {
+ case QSGRendererInterface::OpenGL:
+ Q_FALLTHROUGH();
+ case QSGRendererInterface::OpenGLRhi:
#if QT_CONFIG(opengl)
- n = new OpenGLRenderNode(this);
+ if (!n)
+ n = new OpenGLRenderNode;
+ static_cast<OpenGLRenderNode *>(n)->sync(this);
#endif
- break;
+ break;
- case QSGRendererInterface::MetalRhi:
-#ifdef Q_OS_DARWIN
- {
- MetalRenderNode *metalNode = new MetalRenderNode(this);
+ case QSGRendererInterface::MetalRhi:
+// Restore when QTBUG-78580 is done and the .pro is updated accordingly
+//#ifdef Q_OS_DARWIN
+#ifdef Q_OS_MACOS
+ if (!n) {
+ MetalRenderNode *metalNode = new MetalRenderNode;
n = metalNode;
metalNode->resourceBuilder()->setWindow(window());
QObject::connect(window(), &QQuickWindow::beforeRendering,
metalNode->resourceBuilder(), &MetalRenderNodeResourceBuilder::build);
}
+ static_cast<MetalRenderNode *>(n)->sync(this);
#endif
- break;
+ break;
- case QSGRendererInterface::Direct3D12: // ### Qt 6: remove
+ case QSGRendererInterface::Direct3D12: // ### Qt 6: remove
#if QT_CONFIG(d3d12)
- n = new D3D12RenderNode(this);
+ if (!n)
+ n = new D3D12RenderNode;
+ static_cast<D3D12RenderNode *>(n)->sync(this);
#endif
- break;
+ break;
- case QSGRendererInterface::Software:
- n = new SoftwareRenderNode(this);
- break;
-
- default:
- break;
- }
+ case QSGRendererInterface::Software:
if (!n)
- qWarning("QSGRendererInterface reports unknown graphics API %d", ri->graphicsApi());
+ n = new SoftwareRenderNode;
+ static_cast<SoftwareRenderNode *>(n)->sync(this);
+ break;
+
+ default:
+ break;
}
+ if (!n)
+ qWarning("QSGRendererInterface reports unknown graphics API %d", ri->graphicsApi());
+
return n;
}
//! [2]
diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.h b/examples/quick/scenegraph/rendernode/customrenderitem.h
index a0ac3468e4..74115b2505 100644
--- a/examples/quick/scenegraph/rendernode/customrenderitem.h
+++ b/examples/quick/scenegraph/rendernode/customrenderitem.h
@@ -56,6 +56,7 @@
class CustomRenderItem : public QQuickItem
{
Q_OBJECT
+ QML_ELEMENT
public:
CustomRenderItem(QQuickItem *parent = nullptr);
diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
index 878b022950..e85811c089 100644
--- a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
+++ b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp
@@ -58,11 +58,6 @@
#if QT_CONFIG(d3d12)
-D3D12RenderNode::D3D12RenderNode(QQuickItem *item)
- : m_item(item)
-{
-}
-
D3D12RenderNode::~D3D12RenderNode()
{
releaseResources();
@@ -87,8 +82,8 @@ void D3D12RenderNode::releaseResources()
void D3D12RenderNode::init()
{
- QSGRendererInterface *rif = m_item->window()->rendererInterface();
- m_device = static_cast<ID3D12Device *>(rif->getResource(m_item->window(), QSGRendererInterface::DeviceResource));
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ m_device = static_cast<ID3D12Device *>(rif->getResource(m_window, QSGRendererInterface::DeviceResource));
Q_ASSERT(m_device);
D3D12_ROOT_PARAMETER rootParameter;
@@ -178,7 +173,7 @@ void D3D12RenderNode::init()
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; // not in use due to !DepthEnable, but this would be the correct format otherwise
// We are rendering on the default render target so if the QuickWindow/View
// has requested samples > 0 then we have to follow suit.
- const uint samples = qMax(1, m_item->window()->format().samples());
+ const uint samples = qMax(1, m_window->format().samples());
psoDesc.SampleDesc.Count = samples;
if (samples > 1) {
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
@@ -257,9 +252,9 @@ void D3D12RenderNode::render(const RenderState *state)
if (!m_device)
init();
- QSGRendererInterface *rif = m_item->window()->rendererInterface();
+ QSGRendererInterface *rif = m_window->rendererInterface();
ID3D12GraphicsCommandList *commandList = static_cast<ID3D12GraphicsCommandList *>(
- rif->getResource(m_item->window(), QSGRendererInterface::CommandListResource));
+ rif->getResource(m_window, QSGRendererInterface::CommandListResource));
Q_ASSERT(commandList);
const int msize = 16 * sizeof(float);
@@ -268,9 +263,9 @@ void D3D12RenderNode::render(const RenderState *state)
const float opacity = inheritedOpacity();
memcpy(cbPtr + 2 * msize, &opacity, sizeof(float));
- const QPointF p0(m_item->width() - 1, m_item->height() - 1);
+ const QPointF p0(m_width - 1, m_height - 1);
const QPointF p1(0, 0);
- const QPointF p2(0, m_item->height() - 1);
+ const QPointF p2(0, m_height - 1);
float *vp = reinterpret_cast<float *>(vbPtr);
*vp++ = p0.x();
@@ -301,7 +296,14 @@ QSGRenderNode::RenderingFlags D3D12RenderNode::flags() const
QRectF D3D12RenderNode::rect() const
{
- return QRect(0, 0, m_item->width(), m_item->height());
+ return QRect(0, 0, m_width, m_height);
+}
+
+void D3D12RenderNode::sync(QQuickItem *item)
+{
+ m_window = item->window();
+ m_width = item->width();
+ m_height = item->height();
}
#endif // d3d12
diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.h b/examples/quick/scenegraph/rendernode/d3d12renderer.h
index ec4b5f85e8..7186b72c04 100644
--- a/examples/quick/scenegraph/rendernode/d3d12renderer.h
+++ b/examples/quick/scenegraph/rendernode/d3d12renderer.h
@@ -52,11 +52,10 @@
#define D3D12RENDERER_H
#include <qsgrendernode.h>
+#include <QQuickItem>
#if QT_CONFIG(d3d12)
-QT_FORWARD_DECLARE_CLASS(QQuickItem)
-
#include <d3d12.h>
#include <wrl/client.h>
@@ -65,7 +64,6 @@ using namespace Microsoft::WRL;
class D3D12RenderNode : public QSGRenderNode
{
public:
- D3D12RenderNode(QQuickItem *item);
~D3D12RenderNode();
void render(const RenderState *state) override;
@@ -73,10 +71,15 @@ public:
RenderingFlags flags() const override;
QRectF rect() const override;
+ void sync(QQuickItem *item);
+
private:
void init();
- QQuickItem *m_item;
+ QQuickWindow *m_window = nullptr;
+ int m_width = 0;
+ int m_height = 0;
+
ID3D12Device *m_device = nullptr;
ComPtr<ID3D12PipelineState> pipelineState;
ComPtr<ID3D12RootSignature> rootSignature;
diff --git a/examples/quick/scenegraph/rendernode/main.cpp b/examples/quick/scenegraph/rendernode/main.cpp
index 146d787e50..b1dfe47829 100644
--- a/examples/quick/scenegraph/rendernode/main.cpp
+++ b/examples/quick/scenegraph/rendernode/main.cpp
@@ -59,7 +59,7 @@ int main(int argc, char **argv)
QGuiApplication app(argc, argv);
//! [1]
- qmlRegisterType<CustomRenderItem>("SceneGraphRendering", 2, 0, "CustomRenderItem");
+ qmlRegisterTypesAndRevisions<CustomRenderItem>("SceneGraphRendering", 2);
//! [1]
QQuickView view;
diff --git a/examples/quick/scenegraph/rendernode/metalrenderer.h b/examples/quick/scenegraph/rendernode/metalrenderer.h
index 77c9892313..cf7fccb930 100644
--- a/examples/quick/scenegraph/rendernode/metalrenderer.h
+++ b/examples/quick/scenegraph/rendernode/metalrenderer.h
@@ -52,14 +52,13 @@
#define METALRENDERER_H
#include <qsgrendernode.h>
+#include <QQuickItem>
-#ifdef Q_OS_DARWIN
+//#ifdef Q_OS_DARWIN
+#ifdef Q_OS_MACOS
QT_BEGIN_NAMESPACE
-class QQuickItem;
-class QQuickWindow;
-
QT_END_NAMESPACE
class MetalRenderNodeResourceBuilder : public QObject
@@ -79,7 +78,7 @@ private:
class MetalRenderNode : public QSGRenderNode
{
public:
- MetalRenderNode(QQuickItem *item);
+ MetalRenderNode();
~MetalRenderNode();
void render(const RenderState *state) override;
@@ -90,9 +89,14 @@ public:
MetalRenderNodeResourceBuilder *resourceBuilder() { return &m_resourceBuilder; }
+ void sync(QQuickItem *item);
+
private:
- QQuickItem *m_item;
MetalRenderNodeResourceBuilder m_resourceBuilder;
+ QQuickWindow *m_window = nullptr;
+ int m_width = 0;
+ int m_height = 0;
+ int m_outputHeight = 0;
};
#endif // Q_OS_DARWIN
diff --git a/examples/quick/scenegraph/rendernode/metalrenderer.mm b/examples/quick/scenegraph/rendernode/metalrenderer.mm
index 4cb973abee..b83dc62c48 100644
--- a/examples/quick/scenegraph/rendernode/metalrenderer.mm
+++ b/examples/quick/scenegraph/rendernode/metalrenderer.mm
@@ -131,7 +131,7 @@ void MetalRenderNodeResourceBuilder::build()
g.fs = compileShaderFromSource(g.fsSource, QByteArrayLiteral("main0"));
}
- const int framesInFlight = m_window->graphicsStateInfo()->framesInFlight;
+ const int framesInFlight = m_window->graphicsStateInfo().framesInFlight;
// For simplicity's sake we use shared mode (something like host visible +
// host coherent) for everything.
@@ -214,8 +214,7 @@ void MetalRenderNodeResourceBuilder::build()
}
}
-MetalRenderNode::MetalRenderNode(QQuickItem *item)
- : m_item(item)
+MetalRenderNode::MetalRenderNode()
{
g.vs.first = g.fs.first = nil;
g.vs.second = g.fs.second = nil;
@@ -258,14 +257,14 @@ void MetalRenderNode::releaseResources()
void MetalRenderNode::render(const RenderState *state)
{
- QQuickWindow *window = m_item->window();
- const QQuickWindow::GraphicsStateInfo *stateInfo = window->graphicsStateInfo();
- id<MTLBuffer> vbuf = g.vbuf[stateInfo->currentFrameSlot];
- id<MTLBuffer> ubuf = g.ubuf[stateInfo->currentFrameSlot];
+ Q_ASSERT(m_window);
+ const QQuickWindow::GraphicsStateInfo &stateInfo(m_window->graphicsStateInfo());
+ id<MTLBuffer> vbuf = g.vbuf[stateInfo.currentFrameSlot];
+ id<MTLBuffer> ubuf = g.ubuf[stateInfo.currentFrameSlot];
- QPointF p0(m_item->width() - 1, m_item->height() - 1);
+ QPointF p0(m_width - 1, m_height - 1);
QPointF p1(0, 0);
- QPointF p2(0, m_item->height() - 1);
+ QPointF p2(0, m_height - 1);
float vertices[6] = { float(p0.x()), float(p0.y()),
float(p1.x()), float(p1.y()),
@@ -280,9 +279,9 @@ void MetalRenderNode::render(const RenderState *state)
memcpy(p, mvp.constData(), 64);
memcpy(p + 64, &opacity, 4);
- QSGRendererInterface *rif = window->rendererInterface();
+ QSGRendererInterface *rif = m_window->rendererInterface();
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>) rif->getResource(
- window, QSGRendererInterface::CommandEncoderResource);
+ m_window, QSGRendererInterface::CommandEncoderResource);
Q_ASSERT(encoder);
[encoder setVertexBuffer: vbuf offset: 0 atIndex: 1];
@@ -296,7 +295,7 @@ void MetalRenderNode::render(const RenderState *state)
const QRect r = state->scissorRect(); // bottom-up
MTLScissorRect s;
s.x = r.x();
- s.y = (window->height() * window->effectiveDevicePixelRatio()) - (r.y() + r.height());
+ s.y = m_outputHeight - (r.y() + r.height());
s.width = r.width();
s.height = r.height();
[encoder setScissorRect: s];
@@ -322,5 +321,13 @@ QSGRenderNode::RenderingFlags MetalRenderNode::flags() const
QRectF MetalRenderNode::rect() const
{
- return QRect(0, 0, m_item->width(), m_item->height());
+ return QRect(0, 0, m_width, m_height);
+}
+
+void MetalRenderNode::sync(QQuickItem *item)
+{
+ m_window = item->window();
+ m_width = item->width();
+ m_height = item->height();
+ m_outputHeight = m_window->height() * m_window->effectiveDevicePixelRatio();
}
diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.cpp b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
index 0633731617..a4e619bea9 100644
--- a/examples/quick/scenegraph/rendernode/openglrenderer.cpp
+++ b/examples/quick/scenegraph/rendernode/openglrenderer.cpp
@@ -58,11 +58,6 @@
#include <QOpenGLFunctions>
//! [1]
-OpenGLRenderNode::OpenGLRenderNode(QQuickItem *item)
- : m_item(item)
-{
-}
-
OpenGLRenderNode::~OpenGLRenderNode()
{
releaseResources();
@@ -138,9 +133,9 @@ void OpenGLRenderNode::render(const RenderState *state)
m_vbo->bind();
//! [5]
- QPointF p0(m_item->width() - 1, m_item->height() - 1);
+ QPointF p0(m_width - 1, m_height - 1);
QPointF p1(0, 0);
- QPointF p2(0, m_item->height() - 1);
+ QPointF p2(0, m_height - 1);
GLfloat vertices[6] = { GLfloat(p0.x()), GLfloat(p0.y()),
GLfloat(p1.x()), GLfloat(p1.y()),
@@ -192,8 +187,14 @@ QSGRenderNode::RenderingFlags OpenGLRenderNode::flags() const
QRectF OpenGLRenderNode::rect() const
{
- return QRect(0, 0, m_item->width(), m_item->height());
+ return QRect(0, 0, m_width, m_height);
}
//! [4]
+void OpenGLRenderNode::sync(QQuickItem *item)
+{
+ m_width = item->width();
+ m_height = item->height();
+}
+
#endif // opengl
diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.h b/examples/quick/scenegraph/rendernode/openglrenderer.h
index 8d2d3caad1..1e7977481a 100644
--- a/examples/quick/scenegraph/rendernode/openglrenderer.h
+++ b/examples/quick/scenegraph/rendernode/openglrenderer.h
@@ -52,12 +52,12 @@
#define OPENGLRENDERER_H
#include <qsgrendernode.h>
+#include <QQuickItem>
#if QT_CONFIG(opengl)
QT_BEGIN_NAMESPACE
-class QQuickItem;
class QOpenGLShaderProgram;
class QOpenGLBuffer;
@@ -67,7 +67,6 @@ QT_END_NAMESPACE
class OpenGLRenderNode : public QSGRenderNode
{
public:
- OpenGLRenderNode(QQuickItem *item);
~OpenGLRenderNode();
void render(const RenderState *state) override;
@@ -77,10 +76,13 @@ public:
QRectF rect() const override;
//! [1]
+ void sync(QQuickItem *item);
+
private:
void init();
- QQuickItem *m_item;
+ int m_width = 0;
+ int m_height = 0;
QOpenGLShaderProgram *m_program = nullptr;
int m_matrixUniform;
int m_opacityUniform;
diff --git a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
index 0a0ec4b485..bba364ac97 100644
--- a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
+++ b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp
@@ -54,11 +54,6 @@
#include <QSGRendererInterface>
#include <QPainter>
-SoftwareRenderNode::SoftwareRenderNode(QQuickItem *item)
- : m_item(item)
-{
-}
-
SoftwareRenderNode::~SoftwareRenderNode()
{
releaseResources();
@@ -70,8 +65,10 @@ void SoftwareRenderNode::releaseResources()
void SoftwareRenderNode::render(const RenderState *renderState)
{
- QSGRendererInterface *rif = m_item->window()->rendererInterface();
- QPainter *p = static_cast<QPainter *>(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource));
+ Q_ASSERT(m_window);
+
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ QPainter *p = static_cast<QPainter *>(rif->getResource(m_window, QSGRendererInterface::PainterResource));
Q_ASSERT(p);
const QRegion *clipRegion = renderState->clipRegion();
@@ -81,15 +78,15 @@ void SoftwareRenderNode::render(const RenderState *renderState)
p->setTransform(matrix()->toTransform());
p->setOpacity(inheritedOpacity());
- const QPointF p0(m_item->width() - 1, m_item->height() - 1);
+ const QPointF p0(m_width - 1, m_height - 1);
const QPointF p1(0, 0);
- const QPointF p2(0, m_item->height() - 1);
+ const QPointF p2(0, m_height - 1);
QPainterPath path(p0);
path.lineTo(p1);
path.lineTo(p2);
path.closeSubpath();
- QLinearGradient gradient(QPointF(0, 0), QPointF(m_item->width(), m_item->height()));
+ QLinearGradient gradient(QPointF(0, 0), QPointF(m_width, m_height));
gradient.setColorAt(0, Qt::green);
gradient.setColorAt(1, Qt::red);
@@ -108,5 +105,12 @@ QSGRenderNode::RenderingFlags SoftwareRenderNode::flags() const
QRectF SoftwareRenderNode::rect() const
{
- return QRect(0, 0, m_item->width(), m_item->height());
+ return QRect(0, 0, m_width, m_height);
+}
+
+void SoftwareRenderNode::sync(QQuickItem *item)
+{
+ m_window = item->window();
+ m_width = item->width();
+ m_height = item->height();
}
diff --git a/examples/quick/scenegraph/rendernode/softwarerenderer.h b/examples/quick/scenegraph/rendernode/softwarerenderer.h
index cc2aaf7ed3..6091a13ca3 100644
--- a/examples/quick/scenegraph/rendernode/softwarerenderer.h
+++ b/examples/quick/scenegraph/rendernode/softwarerenderer.h
@@ -57,7 +57,6 @@
class SoftwareRenderNode : public QSGRenderNode
{
public:
- SoftwareRenderNode(QQuickItem *item);
~SoftwareRenderNode();
void render(const RenderState *state) override;
@@ -66,8 +65,12 @@ public:
RenderingFlags flags() const override;
QRectF rect() const override;
+ void sync(QQuickItem *item);
+
private:
- QQuickItem *m_item;
+ QQuickWindow *m_window = nullptr;
+ int m_width = 0;
+ int m_height = 0;
};
#endif
diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro
index ac368c79a5..5fea3b974a 100644
--- a/examples/quick/scenegraph/scenegraph.pro
+++ b/examples/quick/scenegraph/scenegraph.pro
@@ -5,7 +5,7 @@ qtConfig(opengl(es1|es2)?) {
graph \
simplematerial \
sgengine \
- textureinsgnode \
+ fboitem \
openglunderqml \
textureinthread \
twotextureproviders
@@ -17,12 +17,18 @@ SUBDIRS += \
threadedanimation
macos {
- SUBDIRS += metalunderqml
+ SUBDIRS += \
+ metalunderqml \
+ metaltextureimport
}
win32 {
SUBDIRS += d3d11underqml
}
+qtConfig(vulkan) {
+ SUBDIRS += vulkanunderqml
+}
+
EXAMPLE_FILES += \
shared
diff --git a/examples/quick/scenegraph/simplematerial/simplematerial.cpp b/examples/quick/scenegraph/simplematerial/simplematerial.cpp
index 6773b6fb5a..55e1d879ca 100644
--- a/examples/quick/scenegraph/simplematerial/simplematerial.cpp
+++ b/examples/quick/scenegraph/simplematerial/simplematerial.cpp
@@ -157,6 +157,7 @@ class Item : public QQuickItem
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ QML_NAMED_ELEMENT(SimpleMaterialItem)
public:
@@ -203,7 +204,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<Item>("SimpleMaterial", 1, 0, "SimpleMaterialItem");
+ qmlRegisterTypesAndRevisions<Item>("SimpleMaterial", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/quick/scenegraph/textureinthread/main.cpp b/examples/quick/scenegraph/textureinthread/main.cpp
index 7a46f25390..7c22fa7fdf 100644
--- a/examples/quick/scenegraph/textureinthread/main.cpp
+++ b/examples/quick/scenegraph/textureinthread/main.cpp
@@ -70,7 +70,7 @@ int main(int argc, char **argv)
return app.exec();
}
- qmlRegisterType<ThreadRenderer>("SceneGraphRendering", 1, 0, "Renderer");
+ qmlRegisterTypesAndRevisions<ThreadRenderer>("SceneGraphRendering", 1);
int execReturn = 0;
{
diff --git a/examples/quick/scenegraph/textureinthread/threadrenderer.h b/examples/quick/scenegraph/textureinthread/threadrenderer.h
index 8442041bf8..96c00e7b2e 100644
--- a/examples/quick/scenegraph/textureinthread/threadrenderer.h
+++ b/examples/quick/scenegraph/textureinthread/threadrenderer.h
@@ -58,6 +58,7 @@ class RenderThread;
class ThreadRenderer : public QQuickItem
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Renderer)
public:
ThreadRenderer();
diff --git a/examples/quick/scenegraph/threadedanimation/main.cpp b/examples/quick/scenegraph/threadedanimation/main.cpp
index b1b0c05085..c77a291f5d 100644
--- a/examples/quick/scenegraph/threadedanimation/main.cpp
+++ b/examples/quick/scenegraph/threadedanimation/main.cpp
@@ -57,7 +57,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<Spinner>("Spinner", 1, 0, "Spinner");
+ qmlRegisterTypesAndRevisions<Spinner>("Spinner", 1);
QQuickView view;
view.setSource(QUrl("qrc:///scenegraph/threadedanimation/main.qml"));
diff --git a/examples/quick/scenegraph/threadedanimation/spinner.h b/examples/quick/scenegraph/threadedanimation/spinner.h
index c3f3394c93..fd3eaa7751 100644
--- a/examples/quick/scenegraph/threadedanimation/spinner.h
+++ b/examples/quick/scenegraph/threadedanimation/spinner.h
@@ -58,6 +58,7 @@ class Spinner : public QQuickItem
Q_OBJECT
Q_PROPERTY(bool spinning READ spinning WRITE setSpinning NOTIFY spinningChanged)
+ QML_ELEMENT
public:
Spinner();
diff --git a/examples/quick/scenegraph/twotextureproviders/main.cpp b/examples/quick/scenegraph/twotextureproviders/main.cpp
index a5d23b6adc..3f53bb6e32 100644
--- a/examples/quick/scenegraph/twotextureproviders/main.cpp
+++ b/examples/quick/scenegraph/twotextureproviders/main.cpp
@@ -58,7 +58,7 @@ int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
- qmlRegisterType<XorBlender>("SceneGraphRendering", 1, 0, "XorBlender");
+ qmlRegisterTypesAndRevisions<XorBlender>("SceneGraphRendering", 1);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
diff --git a/examples/quick/scenegraph/twotextureproviders/xorblender.h b/examples/quick/scenegraph/twotextureproviders/xorblender.h
index 94132f09fb..17557b8efd 100644
--- a/examples/quick/scenegraph/twotextureproviders/xorblender.h
+++ b/examples/quick/scenegraph/twotextureproviders/xorblender.h
@@ -58,6 +58,7 @@ class XorBlender : public QQuickItem
Q_OBJECT
Q_PROPERTY(QQuickItem *source1 READ source1 WRITE setSource1 NOTIFY source1Changed)
Q_PROPERTY(QQuickItem *source2 READ source2 WRITE setSource2 NOTIFY source2Changed)
+ QML_ELEMENT
public:
explicit XorBlender(QQuickItem *parent = 0);
diff --git a/examples/quick/scenegraph/vulkanunderqml/doc/images/vulkanunderqml-example.jpg b/examples/quick/scenegraph/vulkanunderqml/doc/images/vulkanunderqml-example.jpg
new file mode 100644
index 0000000000..c3f51b6194
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/doc/images/vulkanunderqml-example.jpg
Binary files differ
diff --git a/examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc b/examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc
new file mode 100644
index 0000000000..d11982c074
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/doc/src/vulkanunderqml.qdoc
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example scenegraph/vulkanunderqml
+ \title Scene Graph - Vulkan Under QML
+ \ingroup qtquickexamples
+ \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.
+
+ 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.
+
+ 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.
+
+ 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}, and \l{Scene Graph - Metal Under QML}{Metal Under QML}
+ examples, they all render the same custom content, just via different
+ native APIs.
+
+ */
diff --git a/examples/quick/scenegraph/vulkanunderqml/main.cpp b/examples/quick/scenegraph/vulkanunderqml/main.cpp
new file mode 100644
index 0000000000..a04497b1d6
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/main.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QtQuick/QQuickView>
+#include "vulkansquircle.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<VulkanSquircle>("VulkanUnderQML", 1, 0, "VulkanSquircle");
+
+ // This example needs Vulkan. It will not run otherwise.
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi);
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:///scenegraph/vulkanunderqml/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/quick/scenegraph/vulkanunderqml/main.qml b/examples/quick/scenegraph/vulkanunderqml/main.qml
new file mode 100644
index 0000000000..c364ca7636
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/main.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [1]
+import QtQuick 2.0
+import VulkanUnderQML 1.0
+
+Item {
+
+ width: 320
+ height: 480
+
+ VulkanSquircle {
+ 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
+ }
+ }
+//! [1] //! [2]
+ 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: "The background here is a squircle rendered with raw Vulkan 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
+ }
+}
+//! [2]
diff --git a/examples/quick/scenegraph/vulkanunderqml/squircle.frag.spv b/examples/quick/scenegraph/vulkanunderqml/squircle.frag.spv
new file mode 100644
index 0000000000..e4d13a871d
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/squircle.frag.spv
Binary files differ
diff --git a/examples/quick/scenegraph/vulkanunderqml/squircle.vert.spv b/examples/quick/scenegraph/vulkanunderqml/squircle.vert.spv
new file mode 100644
index 0000000000..5df94a47e4
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/squircle.vert.spv
Binary files differ
diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.cpp b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.cpp
new file mode 100644
index 0000000000..21f46a25c1
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.cpp
@@ -0,0 +1,623 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "vulkansquircle.h"
+#include <QtCore/QRunnable>
+#include <QtQuick/QQuickWindow>
+
+#include <QVulkanInstance>
+#include <QVulkanFunctions>
+
+class SquircleRenderer : public QObject
+{
+ Q_OBJECT
+public:
+ ~SquircleRenderer();
+
+ void setT(qreal t) { m_t = t; }
+ void setViewportSize(const QSize &size) { m_viewportSize = size; }
+ void setWindow(QQuickWindow *window) { m_window = window; }
+
+public slots:
+ void frameStart();
+ void mainPassRecordingStart();
+
+private:
+ enum Stage {
+ VertexStage,
+ FragmentStage
+ };
+ void prepareShader(Stage stage);
+ void init(int framesInFlight);
+
+ QSize m_viewportSize;
+ qreal m_t = 0;
+ QQuickWindow *m_window;
+
+ QByteArray m_vert;
+ QByteArray m_frag;
+
+ bool m_initialized = false;
+ VkPhysicalDevice m_physDev = VK_NULL_HANDLE;
+ VkDevice m_dev = VK_NULL_HANDLE;
+ QVulkanDeviceFunctions *m_devFuncs = nullptr;
+ QVulkanFunctions *m_funcs = nullptr;
+
+ VkBuffer m_vbuf = VK_NULL_HANDLE;
+ VkDeviceMemory m_vbufMem = VK_NULL_HANDLE;
+ VkBuffer m_ubuf = VK_NULL_HANDLE;
+ VkDeviceMemory m_ubufMem = VK_NULL_HANDLE;
+ VkDeviceSize m_allocPerUbuf = 0;
+
+ VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
+
+ VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
+ VkDescriptorSetLayout m_resLayout = VK_NULL_HANDLE;
+ VkPipeline m_pipeline = VK_NULL_HANDLE;
+
+ VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
+ VkDescriptorSet m_ubufDescriptor = VK_NULL_HANDLE;
+};
+
+VulkanSquircle::VulkanSquircle()
+{
+ connect(this, &QQuickItem::windowChanged, this, &VulkanSquircle::handleWindowChanged);
+}
+
+void VulkanSquircle::setT(qreal t)
+{
+ if (t == m_t)
+ return;
+ m_t = t;
+ emit tChanged();
+ if (window())
+ window()->update();
+}
+
+void VulkanSquircle::handleWindowChanged(QQuickWindow *win)
+{
+ if (win) {
+ connect(win, &QQuickWindow::beforeSynchronizing, this, &VulkanSquircle::sync, Qt::DirectConnection);
+ connect(win, &QQuickWindow::sceneGraphInvalidated, this, &VulkanSquircle::cleanup, Qt::DirectConnection);
+
+ // Ensure we start with cleared to black. The squircle's blend mode relies on this.
+ win->setColor(Qt::black);
+ }
+}
+
+// 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 VulkanSquircle may be gone by the time
+// the QRunnable is invoked.
+
+void VulkanSquircle::cleanup()
+{
+ 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 VulkanSquircle::releaseResources()
+{
+ window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage);
+ m_renderer = nullptr;
+}
+
+SquircleRenderer::~SquircleRenderer()
+{
+ qDebug("cleanup");
+ if (!m_devFuncs)
+ return;
+
+ m_devFuncs->vkDestroyPipeline(m_dev, m_pipeline, nullptr);
+ m_devFuncs->vkDestroyPipelineLayout(m_dev, m_pipelineLayout, nullptr);
+ m_devFuncs->vkDestroyDescriptorSetLayout(m_dev, m_resLayout, nullptr);
+
+ m_devFuncs->vkDestroyDescriptorPool(m_dev, m_descriptorPool, nullptr);
+
+ m_devFuncs->vkDestroyPipelineCache(m_dev, m_pipelineCache, nullptr);
+
+ m_devFuncs->vkDestroyBuffer(m_dev, m_vbuf, nullptr);
+ m_devFuncs->vkFreeMemory(m_dev, m_vbufMem, nullptr);
+
+ m_devFuncs->vkDestroyBuffer(m_dev, m_ubuf, nullptr);
+ m_devFuncs->vkFreeMemory(m_dev, m_ubufMem, nullptr);
+
+ qDebug("released");
+}
+
+void VulkanSquircle::sync()
+{
+ 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->setViewportSize(window()->size() * window()->devicePixelRatio());
+ m_renderer->setT(m_t);
+ m_renderer->setWindow(window());
+}
+
+void SquircleRenderer::frameStart()
+{
+ QSGRendererInterface *rif = m_window->rendererInterface();
+
+ // We are not prepared for anything other than running with the RHI and its Vulkan backend.
+ Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::VulkanRhi);
+
+ if (m_vert.isEmpty())
+ prepareShader(VertexStage);
+ if (m_frag.isEmpty())
+ prepareShader(FragmentStage);
+
+ if (!m_initialized)
+ init(m_window->graphicsStateInfo().framesInFlight);
+}
+
+static const float vertices[] = {
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ 1, 1
+};
+
+const int UBUF_SIZE = 4;
+
+void SquircleRenderer::mainPassRecordingStart()
+{
+ // This example demonstrates the simple case: prepending some commands to
+ // the scenegraph's main renderpass. It does not create its own passes,
+ // rendertargets, etc. so no synchronization is needed.
+
+ const QQuickWindow::GraphicsStateInfo &stateInfo(m_window->graphicsStateInfo());
+ QSGRendererInterface *rif = m_window->rendererInterface();
+
+ VkDeviceSize ubufOffset = stateInfo.currentFrameSlot * m_allocPerUbuf;
+ void *p = nullptr;
+ VkResult err = m_devFuncs->vkMapMemory(m_dev, m_ubufMem, ubufOffset, m_allocPerUbuf, 0, &p);
+ if (err != VK_SUCCESS || !p)
+ qFatal("Failed to map uniform buffer memory: %d", err);
+ float t = m_t;
+ memcpy(p, &t, 4);
+ m_devFuncs->vkUnmapMemory(m_dev, m_ubufMem);
+
+ m_window->beginExternalCommands();
+
+ // Must query the command buffer _after_ beginExternalCommands(), this is
+ // actually important when running on Vulkan because what we get here is a
+ // new secondary command buffer, not the primary one.
+ VkCommandBuffer cb = *reinterpret_cast<VkCommandBuffer *>(
+ rif->getResource(m_window, QSGRendererInterface::CommandListResource));
+ Q_ASSERT(cb);
+
+ // Do not assume any state persists on the command buffer. (it may be a
+ // brand new one that just started recording)
+
+ m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
+
+ VkDeviceSize vbufOffset = 0;
+ m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_vbuf, &vbufOffset);
+
+ uint32_t dynamicOffset = m_allocPerUbuf * stateInfo.currentFrameSlot;
+ m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1,
+ &m_ubufDescriptor, 1, &dynamicOffset);
+
+ VkViewport vp = { 0, 0, float(m_viewportSize.width()), float(m_viewportSize.height()), 0.0f, 1.0f };
+ m_devFuncs->vkCmdSetViewport(cb, 0, 1, &vp);
+ VkRect2D scissor = { { 0, 0 }, { uint32_t(m_viewportSize.width()), uint32_t(m_viewportSize.height()) } };
+ m_devFuncs->vkCmdSetScissor(cb, 0, 1, &scissor);
+
+ m_devFuncs->vkCmdDraw(cb, 4, 1, 0, 0);
+
+ m_window->endExternalCommands();
+}
+
+void SquircleRenderer::prepareShader(Stage stage)
+{
+ QString filename;
+ if (stage == VertexStage) {
+ filename = QLatin1String(":/scenegraph/vulkanunderqml/squircle.vert.spv");
+ } else {
+ Q_ASSERT(stage == FragmentStage);
+ filename = QLatin1String(":/scenegraph/vulkanunderqml/squircle.frag.spv");
+ }
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly))
+ qFatal("Failed to read shader %s", qPrintable(filename));
+
+ const QByteArray contents = f.readAll();
+
+ if (stage == VertexStage) {
+ m_vert = contents;
+ Q_ASSERT(!m_vert.isEmpty());
+ } else {
+ m_frag = contents;
+ Q_ASSERT(!m_frag.isEmpty());
+ }
+}
+
+static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)
+{
+ return (v + byteAlign - 1) & ~(byteAlign - 1);
+}
+
+void SquircleRenderer::init(int framesInFlight)
+{
+ qDebug("init");
+
+ Q_ASSERT(framesInFlight <= 3);
+ m_initialized = true;
+
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ QVulkanInstance *inst = reinterpret_cast<QVulkanInstance *>(
+ rif->getResource(m_window, QSGRendererInterface::VulkanInstanceResource));
+ Q_ASSERT(inst && inst->isValid());
+
+ m_physDev = *reinterpret_cast<VkPhysicalDevice *>(rif->getResource(m_window, QSGRendererInterface::PhysicalDeviceResource));
+ m_dev = *reinterpret_cast<VkDevice *>(rif->getResource(m_window, QSGRendererInterface::DeviceResource));
+ Q_ASSERT(m_physDev && m_dev);
+
+ m_devFuncs = inst->deviceFunctions(m_dev);
+ m_funcs = inst->functions();
+ Q_ASSERT(m_devFuncs && m_funcs);
+
+ VkRenderPass rp = *reinterpret_cast<VkRenderPass *>(
+ rif->getResource(m_window, QSGRendererInterface::RenderPassResource));
+ Q_ASSERT(rp);
+
+ // For simplicity we just use host visible buffers instead of device local + staging.
+
+ VkPhysicalDeviceProperties physDevProps;
+ m_funcs->vkGetPhysicalDeviceProperties(m_physDev, &physDevProps);
+
+ VkPhysicalDeviceMemoryProperties physDevMemProps;
+ m_funcs->vkGetPhysicalDeviceMemoryProperties(m_physDev, &physDevMemProps);
+
+ VkBufferCreateInfo bufferInfo;
+ memset(&bufferInfo, 0, sizeof(bufferInfo));
+ bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferInfo.size = sizeof(vertices);
+ bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ VkResult err = m_devFuncs->vkCreateBuffer(m_dev, &bufferInfo, nullptr, &m_vbuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create vertex buffer: %d", err);
+
+ VkMemoryRequirements memReq;
+ m_devFuncs->vkGetBufferMemoryRequirements(m_dev, m_vbuf, &memReq);
+ VkMemoryAllocateInfo allocInfo;
+ memset(&allocInfo, 0, sizeof(allocInfo));
+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocInfo.allocationSize = memReq.size;
+
+ uint32_t memTypeIndex = uint32_t(-1);
+ const VkMemoryType *memType = physDevMemProps.memoryTypes;
+ for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
+ if (memReq.memoryTypeBits & (1 << i)) {
+ if ((memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ && (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
+ {
+ memTypeIndex = i;
+ break;
+ }
+ }
+ }
+ if (memTypeIndex == uint32_t(-1))
+ qFatal("Failed to find host visible and coherent memory type");
+
+ allocInfo.memoryTypeIndex = memTypeIndex;
+ err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_vbufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate vertex buffer memory of size %u: %d", uint(allocInfo.allocationSize), err);
+
+ void *p = nullptr;
+ err = m_devFuncs->vkMapMemory(m_dev, m_vbufMem, 0, allocInfo.allocationSize, 0, &p);
+ if (err != VK_SUCCESS || !p)
+ qFatal("Failed to map vertex buffer memory: %d", err);
+ memcpy(p, vertices, sizeof(vertices));
+ m_devFuncs->vkUnmapMemory(m_dev, m_vbufMem);
+ err = m_devFuncs->vkBindBufferMemory(m_dev, m_vbuf, m_vbufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind vertex buffer memory: %d", err);
+
+ // Now have a uniform buffer with enough space for the buffer data for each
+ // (potentially) in-flight frame. (as we will write the contents every
+ // frame, and so would need to wait for command buffer completion if there
+ // was only one, and that would not be nice)
+
+ // Could have three buffers and three descriptor sets, or one buffer and
+ // one descriptor set and dynamic offset. We chose the latter in this
+ // example.
+
+ // We use one memory allocation for all uniform buffers, but then have to
+ // watch out for the buffer offset aligment requirement, which may be as
+ // large as 256 bytes.
+
+ m_allocPerUbuf = aligned(UBUF_SIZE, physDevProps.limits.minUniformBufferOffsetAlignment);
+
+ bufferInfo.size = framesInFlight * m_allocPerUbuf;
+ bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ err = m_devFuncs->vkCreateBuffer(m_dev, &bufferInfo, nullptr, &m_ubuf);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create uniform buffer: %d", err);
+ m_devFuncs->vkGetBufferMemoryRequirements(m_dev, m_ubuf, &memReq);
+ memTypeIndex = -1;
+ for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
+ if (memReq.memoryTypeBits & (1 << i)) {
+ if ((memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ && (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
+ {
+ memTypeIndex = i;
+ break;
+ }
+ }
+ }
+ if (memTypeIndex == uint32_t(-1))
+ qFatal("Failed to find host visible and coherent memory type");
+
+ allocInfo.allocationSize = framesInFlight * m_allocPerUbuf;
+ allocInfo.memoryTypeIndex = memTypeIndex;
+ err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_ubufMem);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate uniform buffer memory of size %u: %d", uint(allocInfo.allocationSize), err);
+
+ err = m_devFuncs->vkBindBufferMemory(m_dev, m_ubuf, m_ubufMem, 0);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to bind uniform buffer memory: %d", err);
+
+ // Now onto the pipeline.
+
+ VkPipelineCacheCreateInfo pipelineCacheInfo;
+ memset(&pipelineCacheInfo, 0, sizeof(pipelineCacheInfo));
+ pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+ err = m_devFuncs->vkCreatePipelineCache(m_dev, &pipelineCacheInfo, nullptr, &m_pipelineCache);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create pipeline cache: %d", err);
+
+ VkDescriptorSetLayoutBinding descLayoutBinding;
+ memset(&descLayoutBinding, 0, sizeof(descLayoutBinding));
+ descLayoutBinding.binding = 0;
+ descLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+ descLayoutBinding.descriptorCount = 1;
+ descLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
+ VkDescriptorSetLayoutCreateInfo layoutInfo;
+ memset(&layoutInfo, 0, sizeof(layoutInfo));
+ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layoutInfo.bindingCount = 1;
+ layoutInfo.pBindings = &descLayoutBinding;
+ err = m_devFuncs->vkCreateDescriptorSetLayout(m_dev, &layoutInfo, nullptr, &m_resLayout);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor set layout: %d", err);
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo;
+ memset(&pipelineLayoutInfo, 0, sizeof(pipelineLayoutInfo));
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &m_resLayout;
+ err = m_devFuncs->vkCreatePipelineLayout(m_dev, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
+ if (err != VK_SUCCESS)
+ qWarning("Failed to create pipeline layout: %d", err);
+
+ VkGraphicsPipelineCreateInfo pipelineInfo;
+ memset(&pipelineInfo, 0, sizeof(pipelineInfo));
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+
+ VkShaderModuleCreateInfo shaderInfo;
+ memset(&shaderInfo, 0, sizeof(shaderInfo));
+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shaderInfo.codeSize = m_vert.size();
+ shaderInfo.pCode = reinterpret_cast<const quint32 *>(m_vert.constData());
+ VkShaderModule vertShaderModule;
+ err = m_devFuncs->vkCreateShaderModule(m_dev, &shaderInfo, nullptr, &vertShaderModule);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create vertex shader module: %d", err);
+
+ shaderInfo.codeSize = m_frag.size();
+ shaderInfo.pCode = reinterpret_cast<const quint32 *>(m_frag.constData());
+ VkShaderModule fragShaderModule;
+ err = m_devFuncs->vkCreateShaderModule(m_dev, &shaderInfo, nullptr, &fragShaderModule);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create fragment shader module: %d", err);
+
+ VkPipelineShaderStageCreateInfo stageInfo[2];
+ memset(&stageInfo, 0, sizeof(stageInfo));
+ stageInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stageInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
+ stageInfo[0].module = vertShaderModule;
+ stageInfo[0].pName = "main";
+ stageInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stageInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ stageInfo[1].module = fragShaderModule;
+ stageInfo[1].pName = "main";
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = stageInfo;
+
+ VkVertexInputBindingDescription vertexBinding = {
+ 0, // binding
+ 2 * sizeof(float), // stride
+ VK_VERTEX_INPUT_RATE_VERTEX
+ };
+ VkVertexInputAttributeDescription vertexAttr = {
+ 0, // location
+ 0, // binding
+ VK_FORMAT_R32G32_SFLOAT, // 'vertices' only has 2 floats per vertex
+ 0 // offset
+ };
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo;
+ memset(&vertexInputInfo, 0, sizeof(vertexInputInfo));
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &vertexBinding;
+ vertexInputInfo.vertexAttributeDescriptionCount = 1;
+ vertexInputInfo.pVertexAttributeDescriptions = &vertexAttr;
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+
+ VkDynamicState dynStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+ VkPipelineDynamicStateCreateInfo dynamicInfo;
+ memset(&dynamicInfo, 0, sizeof(dynamicInfo));
+ dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynamicInfo.dynamicStateCount = 2;
+ dynamicInfo.pDynamicStates = dynStates;
+ pipelineInfo.pDynamicState = &dynamicInfo;
+
+ VkPipelineViewportStateCreateInfo viewportInfo;
+ memset(&viewportInfo, 0, sizeof(viewportInfo));
+ viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewportInfo.viewportCount = viewportInfo.scissorCount = 1;
+ pipelineInfo.pViewportState = &viewportInfo;
+
+ VkPipelineInputAssemblyStateCreateInfo iaInfo;
+ memset(&iaInfo, 0, sizeof(iaInfo));
+ iaInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ iaInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ pipelineInfo.pInputAssemblyState = &iaInfo;
+
+ VkPipelineRasterizationStateCreateInfo rsInfo;
+ memset(&rsInfo, 0, sizeof(rsInfo));
+ rsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rsInfo.lineWidth = 1.0f;
+ pipelineInfo.pRasterizationState = &rsInfo;
+
+ VkPipelineMultisampleStateCreateInfo msInfo;
+ memset(&msInfo, 0, sizeof(msInfo));
+ msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ msInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ pipelineInfo.pMultisampleState = &msInfo;
+
+ VkPipelineDepthStencilStateCreateInfo dsInfo;
+ memset(&dsInfo, 0, sizeof(dsInfo));
+ dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ pipelineInfo.pDepthStencilState = &dsInfo;
+
+ // SrcAlpha, One
+ VkPipelineColorBlendStateCreateInfo blendInfo;
+ memset(&blendInfo, 0, sizeof(blendInfo));
+ blendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ VkPipelineColorBlendAttachmentState blend;
+ memset(&blend, 0, sizeof(blend));
+ blend.blendEnable = true;
+ blend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ blend.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ blend.colorBlendOp = VK_BLEND_OP_ADD;
+ blend.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
+ blend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ blend.alphaBlendOp = VK_BLEND_OP_ADD;
+ blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT
+ | VK_COLOR_COMPONENT_A_BIT;
+ blendInfo.attachmentCount = 1;
+ blendInfo.pAttachments = &blend;
+ pipelineInfo.pColorBlendState = &blendInfo;
+
+ pipelineInfo.layout = m_pipelineLayout;
+
+ pipelineInfo.renderPass = rp;
+
+ err = m_devFuncs->vkCreateGraphicsPipelines(m_dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline);
+
+ m_devFuncs->vkDestroyShaderModule(m_dev, vertShaderModule, nullptr);
+ m_devFuncs->vkDestroyShaderModule(m_dev, fragShaderModule, nullptr);
+
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create graphics pipeline: %d", err);
+
+ // Now just need some descriptors.
+ VkDescriptorPoolSize descPoolSizes[] = {
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1 }
+ };
+ VkDescriptorPoolCreateInfo descPoolInfo;
+ memset(&descPoolInfo, 0, sizeof(descPoolInfo));
+ descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ descPoolInfo.flags = 0; // won't use vkFreeDescriptorSets
+ descPoolInfo.maxSets = 1;
+ descPoolInfo.poolSizeCount = sizeof(descPoolSizes) / sizeof(descPoolSizes[0]);
+ descPoolInfo.pPoolSizes = descPoolSizes;
+ err = m_devFuncs->vkCreateDescriptorPool(m_dev, &descPoolInfo, nullptr, &m_descriptorPool);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to create descriptor pool: %d", err);
+
+ VkDescriptorSetAllocateInfo descAllocInfo;
+ memset(&descAllocInfo, 0, sizeof(descAllocInfo));
+ descAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ descAllocInfo.descriptorPool = m_descriptorPool;
+ descAllocInfo.descriptorSetCount = 1;
+ descAllocInfo.pSetLayouts = &m_resLayout;
+ err = m_devFuncs->vkAllocateDescriptorSets(m_dev, &descAllocInfo, &m_ubufDescriptor);
+ if (err != VK_SUCCESS)
+ qFatal("Failed to allocate descriptor set");
+
+ VkWriteDescriptorSet writeInfo;
+ memset(&writeInfo, 0, sizeof(writeInfo));
+ writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ writeInfo.dstSet = m_ubufDescriptor;
+ writeInfo.dstBinding = 0;
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+ VkDescriptorBufferInfo bufInfo;
+ bufInfo.buffer = m_ubuf;
+ bufInfo.offset = 0; // dynamic offset is used so this is ignored
+ bufInfo.range = UBUF_SIZE;
+ writeInfo.pBufferInfo = &bufInfo;
+ m_devFuncs->vkUpdateDescriptorSets(m_dev, 1, &writeInfo, 0, nullptr);
+}
+
+#include "vulkansquircle.moc"
diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h
new file mode 100644
index 0000000000..7e65d01a15
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VULKANSQUIRCLE_H
+#define VULKANSQUIRCLE_H
+
+#include <QtQuick/QQuickItem>
+
+class SquircleRenderer;
+
+class VulkanSquircle : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+
+public:
+ VulkanSquircle();
+
+ 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;
+};
+
+#endif
diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro
new file mode 100644
index 0000000000..9ea57b91c3
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro
@@ -0,0 +1,10 @@
+!qtConfig(vulkan): error("This example requires Qt built with Vulkan support")
+
+QT += qml quick
+
+HEADERS += vulkansquircle.h
+SOURCES += vulkansquircle.cpp main.cpp
+RESOURCES += vulkanunderqml.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/vulkanunderqml
+INSTALLS += target
diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.qrc b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.qrc
new file mode 100644
index 0000000000..c85be0f238
--- /dev/null
+++ b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/scenegraph/vulkanunderqml">
+ <file>main.qml</file>
+ <file>squircle.vert.spv</file>
+ <file>squircle.frag.spv</file>
+ </qresource>
+</RCC>