diff options
Diffstat (limited to 'examples/quick/scenegraph')
76 files changed, 1851 insertions, 299 deletions
diff --git a/examples/quick/scenegraph/customgeometry/beziercurve.h b/examples/quick/scenegraph/customgeometry/beziercurve.h index f2f7832e6d..fd0085a08e 100644 --- a/examples/quick/scenegraph/customgeometry/beziercurve.h +++ b/examples/quick/scenegraph/customgeometry/beziercurve.h @@ -64,6 +64,9 @@ class BezierCurve : public QQuickItem Q_PROPERTY(QPointF p4 READ p4 WRITE setP4 NOTIFY p4Changed) Q_PROPERTY(int segmentCount READ segmentCount WRITE setSegmentCount NOTIFY segmentCountChanged) +//! [3] + QML_ELEMENT +//! [3] public: BezierCurve(QQuickItem *parent = 0); diff --git a/examples/quick/scenegraph/customgeometry/customgeometry.pro b/examples/quick/scenegraph/customgeometry/customgeometry.pro index 17c30fc560..3785f88c7e 100644 --- a/examples/quick/scenegraph/customgeometry/customgeometry.pro +++ b/examples/quick/scenegraph/customgeometry/customgeometry.pro @@ -1,6 +1,10 @@ TARGET = customgeometry QT += quick +CONFIG += qmltypes +QML_IMPORT_NAME = CustomGeometry +QML_IMPORT_MAJOR_VERSION = 1 + SOURCES += \ main.cpp \ beziercurve.cpp diff --git a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc index 959114b424..bd235e5dfb 100644 --- a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc +++ b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc @@ -169,11 +169,16 @@ \snippet scenegraph/customgeometry/main.cpp 1 The application is a straightforward QML application, with a - QGuiApplication and a QQuickView that we pass a .qml file. To make - use of the BezierCurve item, we need to register it in the QML - engine, using the qmlRegisterType() function. We give it the name - BezierCurve and make it part of the \c {CustomGeometry 1.0} - module. + QGuiApplication and a QQuickView that we pass a .qml file. + + \snippet scenegraph/customgeometry/beziercurve.h 3 + + To make use of the BezierCurve item, we need to register it in the QML + engine, using the QML_ELEMENT macro. This gives it the name + BezierCurve and makes it part of the \c {CustomGeometry 1.0} + module as defined in the customgeometry.pro file: + + \quotefile scenegraph/customgeometry/customgeometry.pro As the bezier curve is drawn using GL_LINE_STRIP, we specify that the view should be multisampled to get antialiasing. This is not diff --git a/examples/quick/scenegraph/customgeometry/main.cpp b/examples/quick/scenegraph/customgeometry/main.cpp index 6f3c24e87b..0b9b2eb3f9 100644 --- a/examples/quick/scenegraph/customgeometry/main.cpp +++ b/examples/quick/scenegraph/customgeometry/main.cpp @@ -56,10 +56,9 @@ //! [1] int main(int argc, char **argv) { + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); - qmlRegisterType<BezierCurve>("CustomGeometry", 1, 0, "BezierCurve"); - QQuickView view; QSurfaceFormat format = view.format(); format.setSamples(16); diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp index f05bf2f843..5737e419b0 100644 --- a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp +++ b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp @@ -49,6 +49,7 @@ ****************************************************************************/ #include "d3d11squircle.h" +#include <QtCore/QFile> #include <QtCore/QRunnable> #include <QtQuick/QQuickWindow> 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 7658a9a813..4f052cf388 100644 --- a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro +++ b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro @@ -2,6 +2,10 @@ QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = D3D11UnderQML +QML_IMPORT_MAJOR_VERSION = 1 + HEADERS += d3d11squircle.h SOURCES += d3d11squircle.cpp main.cpp RESOURCES += d3d11underqml.qrc diff --git a/examples/quick/scenegraph/d3d11underqml/main.cpp b/examples/quick/scenegraph/d3d11underqml/main.cpp index d26de1144a..bcefae6cb5 100644 --- a/examples/quick/scenegraph/d3d11underqml/main.cpp +++ b/examples/quick/scenegraph/d3d11underqml/main.cpp @@ -56,8 +56,6 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType<D3D11Squircle>("D3D11UnderQML", 1, 0, "D3D11Squircle"); - QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Direct3D11Rhi); QQuickView view; diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h index e1a9ce22c8..1b92b56851 100644 --- a/examples/quick/scenegraph/fboitem/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/fboitem/fboitem.pro b/examples/quick/scenegraph/fboitem/fboitem.pro index e40e5f4cf8..180c2288e2 100644 --- a/examples/quick/scenegraph/fboitem/fboitem.pro +++ b/examples/quick/scenegraph/fboitem/fboitem.pro @@ -1,5 +1,9 @@ QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = SceneGraphRendering +QML_IMPORT_MAJOR_VERSION = 1 + HEADERS += fboinsgrenderer.h SOURCES += fboinsgrenderer.cpp main.cpp diff --git a/examples/quick/scenegraph/fboitem/fboitem.qrc b/examples/quick/scenegraph/fboitem/fboitem.qrc index 9d9db70654..eeb5c36afd 100644 --- a/examples/quick/scenegraph/fboitem/fboitem.qrc +++ b/examples/quick/scenegraph/fboitem/fboitem.qrc @@ -1,5 +1,7 @@ <RCC> <qresource prefix="/scenegraph/fboitem"> <file>main.qml</file> + <file>shaders/checker.frag</file> + <file>shaders/+qsb/checker.frag</file> </qresource> </RCC> diff --git a/examples/quick/scenegraph/fboitem/main.cpp b/examples/quick/scenegraph/fboitem/main.cpp index 429224ba95..153bd931ec 100644 --- a/examples/quick/scenegraph/fboitem/main.cpp +++ b/examples/quick/scenegraph/fboitem/main.cpp @@ -58,8 +58,6 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType<FboInSGRenderer>("SceneGraphRendering", 1, 0, "Renderer"); - QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:///scenegraph/fboitem/main.qml")); diff --git a/examples/quick/scenegraph/fboitem/main.qml b/examples/quick/scenegraph/fboitem/main.qml index 92fa99e847..1f1829deda 100644 --- a/examples/quick/scenegraph/fboitem/main.qml +++ b/examples/quick/scenegraph/fboitem/main.qml @@ -67,20 +67,7 @@ Item { property size pixelSize: Qt.size(width / tileSize, height / tileSize); - fragmentShader: - " - uniform lowp vec4 color1; - uniform lowp vec4 color2; - uniform highp vec2 pixelSize; - varying highp vec2 qt_TexCoord0; - void main() { - highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize)); - if (tc.x != tc.y) - gl_FragColor = color1; - else - gl_FragColor = color2; - } - " + fragmentShader: "qrc:/scenegraph/fboitem/shaders/checker.frag" } Renderer { diff --git a/examples/quick/scenegraph/fboitem/shaders/+qsb/checker.frag b/examples/quick/scenegraph/fboitem/shaders/+qsb/checker.frag Binary files differnew file mode 100644 index 0000000000..5037899d19 --- /dev/null +++ b/examples/quick/scenegraph/fboitem/shaders/+qsb/checker.frag diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag b/examples/quick/scenegraph/fboitem/shaders/checker.frag new file mode 100644 index 0000000000..044b3bad58 --- /dev/null +++ b/examples/quick/scenegraph/fboitem/shaders/checker.frag @@ -0,0 +1,14 @@ +uniform lowp vec4 color1; +uniform lowp vec4 color2; +uniform highp vec2 pixelSize; + +varying highp vec2 qt_TexCoord0; + +void main() +{ + highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize)); + if (tc.x != tc.y) + gl_FragColor = color1; + else + gl_FragColor = color2; +} diff --git a/examples/quick/scenegraph/fboitem/shaders/checker_rhi.frag b/examples/quick/scenegraph/fboitem/shaders/checker_rhi.frag new file mode 100644 index 0000000000..1e4131d026 --- /dev/null +++ b/examples/quick/scenegraph/fboitem/shaders/checker_rhi.frag @@ -0,0 +1,22 @@ +#version 440 + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + + vec4 color1; + vec4 color2; + vec2 pixelSize; +} ubuf; + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +void main() +{ + vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * ubuf.pixelSize)); + if (tc.x != tc.y) + fragColor = ubuf.color1; + else + fragColor = ubuf.color2; +} diff --git a/examples/quick/scenegraph/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/graph.pro b/examples/quick/scenegraph/graph/graph.pro index 1a880b61f1..fe36585d77 100644 --- a/examples/quick/scenegraph/graph/graph.pro +++ b/examples/quick/scenegraph/graph/graph.pro @@ -4,6 +4,10 @@ TARGET = graph TEMPLATE = app +CONFIG += qmltypes +QML_IMPORT_NAME = Graph +QML_IMPORT_MAJOR_VERSION = 1 + SOURCES += main.cpp \ graph.cpp \ noisynode.cpp \ diff --git a/examples/quick/scenegraph/graph/main.cpp b/examples/quick/scenegraph/graph/main.cpp index 2406457ab5..854fad84e3 100644 --- a/examples/quick/scenegraph/graph/main.cpp +++ b/examples/quick/scenegraph/graph/main.cpp @@ -58,8 +58,6 @@ int main(int argc, char *argv[]) { QGuiApplication a(argc, argv); - qmlRegisterType<Graph>("Graph", 1, 0, "Graph"); - QQuickView view; view.resize(800, 400); view.setResizeMode(QQuickView::SizeRootObjectToView); diff --git a/examples/quick/scenegraph/metaltextureimport/main.cpp b/examples/quick/scenegraph/metaltextureimport/main.cpp index c969817e8f..4fc010e710 100644 --- a/examples/quick/scenegraph/metaltextureimport/main.cpp +++ b/examples/quick/scenegraph/metaltextureimport/main.cpp @@ -50,14 +50,10 @@ #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; diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h index afc5aced97..49a29565a7 100644 --- a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h +++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.h @@ -60,6 +60,7 @@ class CustomTextureItem : public QQuickItem { Q_OBJECT Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + QML_ELEMENT public: CustomTextureItem(); diff --git a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro index 5b11606946..9e88c50dc6 100644 --- a/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro +++ b/examples/quick/scenegraph/metaltextureimport/metaltextureimport.pro @@ -1,12 +1,16 @@ -!macos: error("This example requires macOS") +!macos:!ios: error("This example requires macOS or iOS") QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = MetalTextureImport +QML_IMPORT_MAJOR_VERSION = 1 HEADERS += metaltextureimport.h SOURCES += metaltextureimport.mm main.cpp RESOURCES += metaltextureimport.qrc -LIBS += -framework Metal -framework AppKit +LIBS += -framework Metal +macos: LIBS += -framework AppKit target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/metaltextureimport INSTALLS += target diff --git a/examples/quick/scenegraph/metalunderqml/main.cpp b/examples/quick/scenegraph/metalunderqml/main.cpp index 5ad337abb1..cefb1c10a9 100644 --- a/examples/quick/scenegraph/metalunderqml/main.cpp +++ b/examples/quick/scenegraph/metalunderqml/main.cpp @@ -56,8 +56,6 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType<MetalSquircle>("MetalUnderQML", 1, 0, "MetalSquircle"); - QQuickWindow::setSceneGraphBackend(QSGRendererInterface::MetalRhi); QQuickView view; 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 5ca6daa01a..4844df0c70 100644 --- a/examples/quick/scenegraph/metalunderqml/metalsquircle.mm +++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm @@ -349,10 +349,13 @@ void SquircleRenderer::init(int framesInFlight) rpDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne; rpDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne; +#ifdef Q_OS_MACOS if (m_device.depth24Stencil8PixelFormatSupported) { rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8; rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8; - } else { + } else +#endif + { rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; } diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro index 9fd131fe1b..3b0489ecdf 100644 --- a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro +++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro @@ -1,12 +1,17 @@ -!macos: error("This example requires macOS") +!macos:!ios: error("This example requires macOS or iOS") QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = MetalUnderQML +QML_IMPORT_MAJOR_VERSION = 1 + HEADERS += metalsquircle.h SOURCES += metalsquircle.mm main.cpp RESOURCES += metalunderqml.qrc -LIBS += -framework Metal -framework AppKit +LIBS += -framework Metal +macos: LIBS += -framework AppKit target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/metalunderqml INSTALLS += target diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc index 9676815c44..c2944970a5 100644 --- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc +++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc @@ -60,6 +60,7 @@ First of all, we need an object we can expose to QML. This is a subclass of QQuickItem so we can easily access \l QQuickItem::window(). + We expose it to QML using the QML_ELEMENT macro. \snippet scenegraph/openglunderqml/squircle.h 1 @@ -145,9 +146,7 @@ \snippet scenegraph/openglunderqml/main.cpp 1 The application's \c main() function instantiates a QQuickView and - launches the \c main.qml file. The only thing worth noting is that - we export the \c Squircle class to QML using the \l - qmlRegisterType() macro. + launches the \c main.qml file. \snippet scenegraph/openglunderqml/main.qml 1 diff --git a/examples/quick/scenegraph/openglunderqml/main.cpp b/examples/quick/scenegraph/openglunderqml/main.cpp index 022d6a75bb..4ca8d05f1c 100644 --- a/examples/quick/scenegraph/openglunderqml/main.cpp +++ b/examples/quick/scenegraph/openglunderqml/main.cpp @@ -59,8 +59,6 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType<Squircle>("OpenGLUnderQML", 1, 0, "Squircle"); - QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:///scenegraph/openglunderqml/main.qml")); diff --git a/examples/quick/scenegraph/openglunderqml/openglunderqml.pro b/examples/quick/scenegraph/openglunderqml/openglunderqml.pro index 54558ce9e9..7eaace1133 100644 --- a/examples/quick/scenegraph/openglunderqml/openglunderqml.pro +++ b/examples/quick/scenegraph/openglunderqml/openglunderqml.pro @@ -1,5 +1,9 @@ QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = OpenGLUnderQML +QML_IMPORT_MAJOR_VERSION = 1 + HEADERS += squircle.h SOURCES += squircle.cpp main.cpp RESOURCES += openglunderqml.qrc 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.h b/examples/quick/scenegraph/rendernode/customrenderitem.h index a0ac3468e4..28be54925b 100644 --- a/examples/quick/scenegraph/rendernode/customrenderitem.h +++ b/examples/quick/scenegraph/rendernode/customrenderitem.h @@ -53,13 +53,16 @@ #include <QQuickItem> +//! [0] class CustomRenderItem : public QQuickItem { Q_OBJECT + QML_ELEMENT public: CustomRenderItem(QQuickItem *parent = nullptr); QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; }; +//! [0] #endif diff --git a/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc index ba6551fddf..87e3c8b506 100644 --- a/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc +++ b/examples/quick/scenegraph/rendernode/doc/src/rendernode.qdoc @@ -69,7 +69,7 @@ Let's go through the most important parts of the code: - \snippet scenegraph/rendernode/main.cpp 1 + \snippet scenegraph/rendernode/customrenderitem.h 0 Our custom QML type is implemented in the class CustomRenderItem. diff --git a/examples/quick/scenegraph/rendernode/main.cpp b/examples/quick/scenegraph/rendernode/main.cpp index 146d787e50..645360eaba 100644 --- a/examples/quick/scenegraph/rendernode/main.cpp +++ b/examples/quick/scenegraph/rendernode/main.cpp @@ -58,10 +58,6 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); -//! [1] - qmlRegisterType<CustomRenderItem>("SceneGraphRendering", 2, 0, "CustomRenderItem"); -//! [1] - QQuickView view; QCoreApplication::setApplicationName("Qt Scene Graph Render Node Example"); diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml index 153a71e097..5631df317c 100644 --- a/examples/quick/scenegraph/rendernode/main.qml +++ b/examples/quick/scenegraph/rendernode/main.qml @@ -66,7 +66,7 @@ Item { MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: { + onClicked: (mouse) => { if (mouse.button === Qt.LeftButton) { clipper.clip = !clipper.clip } else if (mouse.button === Qt.RightButton) { diff --git a/examples/quick/scenegraph/rendernode/rendernode.pro b/examples/quick/scenegraph/rendernode/rendernode.pro index 897b0b1f08..cfec905764 100644 --- a/examples/quick/scenegraph/rendernode/rendernode.pro +++ b/examples/quick/scenegraph/rendernode/rendernode.pro @@ -1,5 +1,9 @@ QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = SceneGraphRendering +QML_IMPORT_MAJOR_VERSION = 2 + HEADERS += customrenderitem.h \ openglrenderer.h \ softwarerenderer.h diff --git a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp index bba364ac97..d6d97a8151 100644 --- a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp +++ b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp @@ -53,6 +53,7 @@ #include <QQuickWindow> #include <QSGRendererInterface> #include <QPainter> +#include <QPainterPath> SoftwareRenderNode::~SoftwareRenderNode() { @@ -95,7 +96,7 @@ void SoftwareRenderNode::render(const RenderState *renderState) QSGRenderNode::StateFlags SoftwareRenderNode::changedStates() const { - return nullptr; + return {}; } QSGRenderNode::RenderingFlags SoftwareRenderNode::flags() const diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro index 5fea3b974a..08ca18fa0c 100644 --- a/examples/quick/scenegraph/scenegraph.pro +++ b/examples/quick/scenegraph/scenegraph.pro @@ -16,7 +16,7 @@ SUBDIRS += \ rendernode \ threadedanimation -macos { +macos|ios { SUBDIRS += \ metalunderqml \ metaltextureimport @@ -27,7 +27,9 @@ win32 { } qtConfig(vulkan) { - SUBDIRS += vulkanunderqml + SUBDIRS += \ + vulkanunderqml \ + vulkantextureimport } EXAMPLE_FILES += \ diff --git a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc index 67ca2d8dbd..d7de1613e4 100644 --- a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc +++ b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc @@ -47,7 +47,7 @@ material state is what we assign to each individual node; in this case to give them different colors. - \snippet scenegraph/simplematerial/simplematerial.cpp 1 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 1 The first thing we do when creating custom materials with the simplified scheme is to create a state class. In this case the @@ -55,7 +55,7 @@ compare function which the scene graph can use to reorder the node rendering. - \snippet scenegraph/simplematerial/simplematerial.cpp 2 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 2 Next we define the material shader, by subclassing a template instantiation of \l QSGSimpleMaterialShader with our \c State. @@ -74,21 +74,21 @@ classes. Using the same \c State class in multiple shaders will will lead to undefined behavior. - \snippet scenegraph/simplematerial/simplematerial.cpp 3 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 3 Next comes the declaration of the shader source code, where we define a vertex and fragment shader. The simple material assumes the presence of \c qt_Matrix in the vertex shader and \c qt_Opacity in the fragment shader. - \snippet scenegraph/simplematerial/simplematerial.cpp 4 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 4 We reimplement the \c attributes function to return the name of the \c aVertex and \c aTexCoord attributes. These attributes will be mapped to attribute indices 0 and 1 in the node's geometry. - \snippet scenegraph/simplematerial/simplematerial.cpp 6 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 6 Uniforms can be accessed either by name or by index, where index is faster than name. We reimplement the \c resolveUniforms() @@ -96,7 +96,7 @@ to worry about resolving \c qt_Opacity or \c qt_Matrix as these are handled by the baseclass. - \snippet scenegraph/simplematerial/simplematerial.cpp 5 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 5 The \c updateState() function is called once for every unique state and we use it to update the shader program with the current @@ -105,7 +105,7 @@ use case, where all the colors are different, the updateState() function will be called once for every node. - \snippet scenegraph/simplematerial/simplematerial.cpp 7 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 7 The \c ColorNode class is supposed to draw something, so it needs to be a subclass of \l QSGGeometryNode. @@ -129,12 +129,13 @@ Finally, we tell the node to take ownership of the material, so we do not have to explicitly memory-manage it. - \snippet scenegraph/simplematerial/simplematerial.cpp 8 + \snippet scenegraph/simplematerial/simplematerialitem.h 8 Since the Item is providing its own graphics to the scene graph, - we set the flag \l QQuickItem::ItemHasContents. + we set the flag \l QQuickItem::ItemHasContents. We also make sure + the item is exposed to QML by adding the QML_ELEMENT macro. - \snippet scenegraph/simplematerial/simplematerial.cpp 9 + \snippet scenegraph/simplematerial/simplematerialitem.cpp 9 Whenever the Item has changed graphically, the \l QQuickItem::updatePaintNode() function is called. @@ -159,9 +160,8 @@ \snippet scenegraph/simplematerial/simplematerial.cpp 11 - The \c main() function of the application adds the custom QML type - using \l qmlRegisterType() and opens up a \l QQuickView with our - QML file. + The \c main() function of the application opens up a \l QQuickView + with our QML file. \snippet scenegraph/simplematerial/main.qml 1 diff --git a/examples/quick/scenegraph/simplematerial/simplematerial.cpp b/examples/quick/scenegraph/simplematerial/simplematerial.cpp index 6773b6fb5a..35866bd6d0 100644 --- a/examples/quick/scenegraph/simplematerial/simplematerial.cpp +++ b/examples/quick/scenegraph/simplematerial/simplematerial.cpp @@ -49,162 +49,13 @@ ****************************************************************************/ #include <qguiapplication.h> - -#include <qsgmaterial.h> -#include <qsgnode.h> - -#include <qquickitem.h> #include <qquickview.h> -#include <qsgsimplerectnode.h> - -#include <qsgsimplematerial.h> - -//! [1] -struct State -{ - QColor color; - - int compare(const State *other) const { - uint rgb = color.rgba(); - uint otherRgb = other->color.rgba(); - - if (rgb == otherRgb) { - return 0; - } else if (rgb < otherRgb) { - return -1; - } else { - return 1; - } - } -}; -//! [1] - -//! [2] -class Shader : public QSGSimpleMaterialShader<State> -{ - QSG_DECLARE_SIMPLE_COMPARABLE_SHADER(Shader, State); -//! [2] //! [3] -public: - - const char *vertexShader() const override { - return - "attribute highp vec4 aVertex; \n" - "attribute highp vec2 aTexCoord; \n" - "uniform highp mat4 qt_Matrix; \n" - "varying highp vec2 texCoord; \n" - "void main() { \n" - " gl_Position = qt_Matrix * aVertex; \n" - " texCoord = aTexCoord; \n" - "}"; - } - - const char *fragmentShader() const override { - return - "uniform lowp float qt_Opacity; \n" - "uniform lowp vec4 color; \n" - "varying highp vec2 texCoord; \n" - "void main () \n" - "{ \n" - " gl_FragColor = texCoord.y * texCoord.x * color * qt_Opacity; \n" - "}"; - } -//! [3] //! [4] - QList<QByteArray> attributes() const override - { - return QList<QByteArray>() << "aVertex" << "aTexCoord"; - } -//! [4] //! [5] - void updateState(const State *state, const State *) override - { - program()->setUniformValue(id_color, state->color); - } -//! [5] //! [6] - void resolveUniforms() override - { - id_color = program()->uniformLocation("color"); - } - -private: - int id_color; -//! [6] -}; - - -//! [7] -class ColorNode : public QSGGeometryNode -{ -public: - ColorNode() - : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) - { - setGeometry(&m_geometry); - - QSGSimpleMaterial<State> *material = Shader::createMaterial(); - material->setFlag(QSGMaterial::Blending); - setMaterial(material); - setFlag(OwnsMaterial); - } - - QSGGeometry m_geometry; -}; -//! [7] - - -//! [8] -class Item : public QQuickItem -{ - Q_OBJECT - - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - -public: - - Item() - { - setFlag(ItemHasContents, true); - } - - void setColor(const QColor &color) { - if (m_color != color) { - m_color = color; - emit colorChanged(); - update(); - } - } - QColor color() const { - return m_color; - } - -signals: - void colorChanged(); - -private: - QColor m_color; - -//! [8] //! [9] -public: - QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override - { - ColorNode *n = static_cast<ColorNode *>(node); - if (!node) - n = new ColorNode(); - - QSGGeometry::updateTexturedRectGeometry(n->geometry(), boundingRect(), QRectF(0, 0, 1, 1)); - static_cast<QSGSimpleMaterial<State>*>(n->material())->state()->color = m_color; - - n->markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial); - - return n; - } -}; -//! [9] //! [11] +//! [11] int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType<Item>("SimpleMaterial", 1, 0, "SimpleMaterialItem"); - QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:///scenegraph/simplematerial/main.qml")); @@ -212,6 +63,4 @@ int main(int argc, char **argv) return app.exec(); } - -#include "simplematerial.moc" //! [11] diff --git a/examples/quick/scenegraph/simplematerial/simplematerial.pro b/examples/quick/scenegraph/simplematerial/simplematerial.pro index 6ae935f357..131af45974 100644 --- a/examples/quick/scenegraph/simplematerial/simplematerial.pro +++ b/examples/quick/scenegraph/simplematerial/simplematerial.pro @@ -1,8 +1,13 @@ QT += quick +CONFIG += qmltypes +QML_IMPORT_NAME = SimpleMaterial +QML_IMPORT_MAJOR_VERSION = 1 + SOURCES += \ - simplematerial.cpp + simplematerial.cpp \ + simplematerialitem.cpp RESOURCES += simplematerial.qrc target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/simplematerial @@ -10,3 +15,6 @@ qml.files = main.qml qml.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/simplematerial INSTALLS += target qml + +HEADERS += \ + simplematerialitem.h diff --git a/examples/quick/scenegraph/simplematerial/simplematerialitem.cpp b/examples/quick/scenegraph/simplematerial/simplematerialitem.cpp new file mode 100644 index 0000000000..c4c7b2e07e --- /dev/null +++ b/examples/quick/scenegraph/simplematerial/simplematerialitem.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "simplematerialitem.h" + +#include <QtQuick/qsgsimplematerial.h> +#include <QtQuick/qsggeometry.h> +#include <QtQuick/qsgnode.h> + +//! [1] +struct State +{ + QColor color; + + int compare(const State *other) const { + uint rgb = color.rgba(); + uint otherRgb = other->color.rgba(); + + if (rgb == otherRgb) { + return 0; + } else if (rgb < otherRgb) { + return -1; + } else { + return 1; + } + } +}; +//! [1] + +//! [2] +class Shader : public QSGSimpleMaterialShader<State> +{ + QSG_DECLARE_SIMPLE_COMPARABLE_SHADER(Shader, State); +//! [2] //! [3] +public: + + const char *vertexShader() const override { + return + "attribute highp vec4 aVertex; \n" + "attribute highp vec2 aTexCoord; \n" + "uniform highp mat4 qt_Matrix; \n" + "varying highp vec2 texCoord; \n" + "void main() { \n" + " gl_Position = qt_Matrix * aVertex; \n" + " texCoord = aTexCoord; \n" + "}"; + } + + const char *fragmentShader() const override { + return + "uniform lowp float qt_Opacity; \n" + "uniform lowp vec4 color; \n" + "varying highp vec2 texCoord; \n" + "void main () \n" + "{ \n" + " gl_FragColor = texCoord.y * texCoord.x * color * qt_Opacity; \n" + "}"; + } +//! [3] //! [4] + QList<QByteArray> attributes() const override + { + return QList<QByteArray>() << "aVertex" << "aTexCoord"; + } +//! [4] //! [5] + void updateState(const State *state, const State *) override + { + program()->setUniformValue(id_color, state->color); + } +//! [5] //! [6] + void resolveUniforms() override + { + id_color = program()->uniformLocation("color"); + } + +private: + int id_color; +//! [6] +}; + + +//! [7] +class ColorNode : public QSGGeometryNode +{ +public: + ColorNode() + : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) + { + setGeometry(&m_geometry); + + QSGSimpleMaterial<State> *material = Shader::createMaterial(); + material->setFlag(QSGMaterial::Blending); + setMaterial(material); + setFlag(OwnsMaterial); + } + + QSGGeometry m_geometry; +}; +//! [7] + +void SimpleMaterialItem::setColor(const QColor &color) { + if (m_color != color) { + m_color = color; + emit colorChanged(); + update(); + } +} + +//! [9] +QSGNode *SimpleMaterialItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *) +{ + ColorNode *n = static_cast<ColorNode *>(node); + if (!node) + n = new ColorNode(); + + QSGGeometry::updateTexturedRectGeometry(n->geometry(), boundingRect(), QRectF(0, 0, 1, 1)); + static_cast<QSGSimpleMaterial<State>*>(n->material())->state()->color = m_color; + + n->markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial); + + return n; +} +//! [9] diff --git a/examples/quick/scenegraph/simplematerial/simplematerialitem.h b/examples/quick/scenegraph/simplematerial/simplematerialitem.h new file mode 100644 index 0000000000..5775ad097b --- /dev/null +++ b/examples/quick/scenegraph/simplematerial/simplematerialitem.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 SIMPLEMATERIALITEM_H +#define SIMPLEMATERIALITEM_H + +#include <QtQuick/qquickitem.h> + +//! [8] +class SimpleMaterialItem : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + QML_ELEMENT + +public: + + SimpleMaterialItem() { setFlag(ItemHasContents, true); } + + void setColor(const QColor &color); + QColor color() const { return m_color; } + +signals: + void colorChanged(); + +private: + QColor m_color; + +public: + QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; +}; +//! [8] + +#endif // SIMPLEMATERIALITEM_H diff --git a/examples/quick/scenegraph/textureinthread/main.cpp b/examples/quick/scenegraph/textureinthread/main.cpp index 7a46f25390..cb00946bf7 100644 --- a/examples/quick/scenegraph/textureinthread/main.cpp +++ b/examples/quick/scenegraph/textureinthread/main.cpp @@ -70,7 +70,6 @@ int main(int argc, char **argv) return app.exec(); } - qmlRegisterType<ThreadRenderer>("SceneGraphRendering", 1, 0, "Renderer"); int execReturn = 0; { diff --git a/examples/quick/scenegraph/textureinthread/textureinthread.pro b/examples/quick/scenegraph/textureinthread/textureinthread.pro index 7f5fbb76e9..4d41daa7bf 100644 --- a/examples/quick/scenegraph/textureinthread/textureinthread.pro +++ b/examples/quick/scenegraph/textureinthread/textureinthread.pro @@ -3,6 +3,10 @@ QT += quick # To make threaded gl check... QT += core-private gui-private +CONFIG += qmltypes +QML_IMPORT_NAME = SceneGraphRendering +QML_IMPORT_MAJOR_VERSION = 1 + HEADERS += threadrenderer.h SOURCES += threadrenderer.cpp main.cpp 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..85ff486b16 100644 --- a/examples/quick/scenegraph/threadedanimation/main.cpp +++ b/examples/quick/scenegraph/threadedanimation/main.cpp @@ -57,8 +57,6 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType<Spinner>("Spinner", 1, 0, "Spinner"); - QQuickView view; view.setSource(QUrl("qrc:///scenegraph/threadedanimation/main.qml")); view.show(); 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/threadedanimation/threadedanimation.pro b/examples/quick/scenegraph/threadedanimation/threadedanimation.pro index 419ee97e2e..3caf3fa94b 100644 --- a/examples/quick/scenegraph/threadedanimation/threadedanimation.pro +++ b/examples/quick/scenegraph/threadedanimation/threadedanimation.pro @@ -1,5 +1,9 @@ QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = Spinner +QML_IMPORT_MAJOR_VERSION = 1 + HEADERS += spinner.h SOURCES += spinner.cpp main.cpp RESOURCES += threadedanimation.qrc diff --git a/examples/quick/scenegraph/twotextureproviders/main.cpp b/examples/quick/scenegraph/twotextureproviders/main.cpp index a5d23b6adc..df0454ce40 100644 --- a/examples/quick/scenegraph/twotextureproviders/main.cpp +++ b/examples/quick/scenegraph/twotextureproviders/main.cpp @@ -58,8 +58,6 @@ int main(int argc, char **argv) { QGuiApplication app(argc, argv); - qmlRegisterType<XorBlender>("SceneGraphRendering", 1, 0, "XorBlender"); - QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:///scenegraph/twotextureproviders/main.qml")); diff --git a/examples/quick/scenegraph/twotextureproviders/main.qml b/examples/quick/scenegraph/twotextureproviders/main.qml index 296df766a1..b9e516f4b7 100644 --- a/examples/quick/scenegraph/twotextureproviders/main.qml +++ b/examples/quick/scenegraph/twotextureproviders/main.qml @@ -64,20 +64,9 @@ Item { property size pixelSize: Qt.size(width / tileSize, height / tileSize); - fragmentShader: - " - uniform lowp vec4 color1; - uniform lowp vec4 color2; - uniform highp vec2 pixelSize; - varying highp vec2 qt_TexCoord0; - void main() { - highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize)); - if (tc.x != tc.y) - gl_FragColor = color1; - else - gl_FragColor = color2; - } - " + // Will automatically pick either checker.frag or +qsb/checker.frag + // thanks to file selectors. + fragmentShader: "qrc:/scenegraph/twotextureproviders/shaders/checker.frag" } width: 320 diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/checker.frag b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/checker.frag Binary files differnew file mode 100644 index 0000000000..edcfad488b --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/checker.frag diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag Binary files differnew file mode 100644 index 0000000000..7a5280ba08 --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert Binary files differnew file mode 100644 index 0000000000..d643c7be6a --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag b/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag new file mode 100644 index 0000000000..044b3bad58 --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/checker.frag @@ -0,0 +1,14 @@ +uniform lowp vec4 color1; +uniform lowp vec4 color2; +uniform highp vec2 pixelSize; + +varying highp vec2 qt_TexCoord0; + +void main() +{ + highp vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize)); + if (tc.x != tc.y) + gl_FragColor = color1; + else + gl_FragColor = color2; +} diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/checker_rhi.frag b/examples/quick/scenegraph/twotextureproviders/shaders/checker_rhi.frag new file mode 100644 index 0000000000..0932bc8c37 --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/checker_rhi.frag @@ -0,0 +1,25 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + // preamble as required by ShaderEffect + mat4 qt_Matrix; + float qt_Opacity; + + // our custom members, connected automatically to QML object properties + vec4 color1; + vec4 color2; + vec2 pixelSize; +} ubuf; + +void main() +{ + vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * ubuf.pixelSize)); + if (tc.x != tc.y) + fragColor = ubuf.color1; + else + fragColor = ubuf.color2; +} diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag new file mode 100644 index 0000000000..f67735312d --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.frag @@ -0,0 +1,12 @@ +uniform lowp float qt_Opacity; +uniform lowp sampler2D uSource1; +uniform lowp sampler2D uSource2; + +varying highp vec2 vTexCoord; + +void main() +{ + lowp vec4 p1 = texture2D(uSource1, vTexCoord); + lowp vec4 p2 = texture2D(uSource2, vTexCoord); + gl_FragColor = (p1 * (1.0 - p2.a) + p2 * (1.0 - p1.a)) * qt_Opacity; +} diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.vert b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.vert new file mode 100644 index 0000000000..ac9f1364d6 --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender.vert @@ -0,0 +1,12 @@ +attribute highp vec4 aVertex; +attribute highp vec2 aTexCoord; + +uniform highp mat4 qt_Matrix; + +varying highp vec2 vTexCoord; + +void main() +{ + gl_Position = qt_Matrix * aVertex; + vTexCoord = aTexCoord; +} diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.frag b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.frag new file mode 100644 index 0000000000..bc68160c1f --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.frag @@ -0,0 +1,20 @@ +#version 440 + +layout(location = 0) in vec2 vTexCoord; + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; +} ubuf; + +layout(binding = 1) uniform sampler2D uSource1; +layout(binding = 2) uniform sampler2D uSource2; + +void main() +{ + lowp vec4 p1 = texture(uSource1, vTexCoord); + lowp vec4 p2 = texture(uSource2, vTexCoord); + fragColor = (p1 * (1.0 - p2.a) + p2 * (1.0 - p1.a)) * ubuf.qt_Opacity; +} diff --git a/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.vert b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.vert new file mode 100644 index 0000000000..41000bde04 --- /dev/null +++ b/examples/quick/scenegraph/twotextureproviders/shaders/xorblender_rhi.vert @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec4 aVertex; +layout(location = 1) in vec2 aTexCoord; + +layout(location = 0) out vec2 vTexCoord; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + gl_Position = ubuf.qt_Matrix * aVertex; + vTexCoord = aTexCoord; +} diff --git a/examples/quick/scenegraph/twotextureproviders/twotextureproviders.pro b/examples/quick/scenegraph/twotextureproviders/twotextureproviders.pro index 7b7c093b48..b87a0a2611 100644 --- a/examples/quick/scenegraph/twotextureproviders/twotextureproviders.pro +++ b/examples/quick/scenegraph/twotextureproviders/twotextureproviders.pro @@ -1,5 +1,9 @@ QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = SceneGraphRendering +QML_IMPORT_MAJOR_VERSION = 1 + HEADERS += xorblender.h SOURCES += xorblender.cpp main.cpp diff --git a/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc b/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc index 1424333ce5..8022a77a1e 100644 --- a/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc +++ b/examples/quick/scenegraph/twotextureproviders/twotextureproviders.qrc @@ -1,5 +1,13 @@ <RCC> <qresource prefix="/scenegraph/twotextureproviders"> <file>main.qml</file> + + <file>shaders/checker.frag</file> + <file>shaders/xorblender.vert</file> + <file>shaders/xorblender.frag</file> + + <file>shaders/+qsb/checker.frag</file> + <file>shaders/+qsb/xorblender.vert</file> + <file>shaders/+qsb/xorblender.frag</file> </qresource> </RCC> diff --git a/examples/quick/scenegraph/twotextureproviders/xorblender.cpp b/examples/quick/scenegraph/twotextureproviders/xorblender.cpp index 8d7597addf..d5881b9adc 100644 --- a/examples/quick/scenegraph/twotextureproviders/xorblender.cpp +++ b/examples/quick/scenegraph/twotextureproviders/xorblender.cpp @@ -55,7 +55,7 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLFunctions> -#include <QtQuick/QSGSimpleMaterial> +#include <QtQuick/QSGMaterial> #include <QtQuick/QSGTexture> #include <QtQuick/QSGGeometryNode> #include <QtQuick/QSGTextureProvider> @@ -67,64 +67,170 @@ * a custom material. */ -struct XorBlendState { - QSGTexture *texture1; - QSGTexture *texture2; +class XorBlendMaterial : public QSGMaterial +{ +public: + XorBlendMaterial(); + QSGMaterialType *type() const override; + QSGMaterialShader *createShader() const override; + int compare(const QSGMaterial *other) const override; + + struct { + QSGTexture *texture1 = nullptr; + QSGTexture *texture2 = nullptr; + } state; }; -class XorBlendShader : public QSGSimpleMaterialShader<XorBlendState> +class XorBlendShader : public QSGMaterialShader // for when the scenegraph is using OpenGL directly { - QSG_DECLARE_SIMPLE_SHADER(XorBlendShader, XorBlendState) public: + XorBlendShader(); + void initialize() override; + char const *const *attributeNames() const override; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; - const char *vertexShader() const override { - return - "attribute highp vec4 aVertex; \n" - "attribute highp vec2 aTexCoord; \n" - "uniform highp mat4 qt_Matrix; \n" - "varying highp vec2 vTexCoord; \n" - "void main() { \n" - " gl_Position = qt_Matrix * aVertex; \n" - " vTexCoord = aTexCoord; \n" - "}"; - } +private: + int m_matrix_id; + int m_opacity_id; +}; - const char *fragmentShader() const override { - return - "uniform lowp float qt_Opacity; \n" - "uniform lowp sampler2D uSource1; \n" - "uniform lowp sampler2D uSource2; \n" - "varying highp vec2 vTexCoord; \n" - "void main() { \n" - " lowp vec4 p1 = texture2D(uSource1, vTexCoord); \n" - " lowp vec4 p2 = texture2D(uSource2, vTexCoord); \n" - " gl_FragColor = (p1 * (1.0 - p2.a) + p2 * (1.0 - p1.a)) * qt_Opacity; \n" - "}"; - } +class XorBlendRhiShader : public QSGMaterialRhiShader // for when the scenegraph is using QRhi +{ +public: + XorBlendRhiShader(); + bool updateUniformData(RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; + void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; +}; + +XorBlendMaterial::XorBlendMaterial() +{ + setFlag(SupportsRhiShader); + setFlag(Blending); +} + +QSGMaterialShader *XorBlendMaterial::createShader() const +{ + if (flags().testFlag(RhiShaderWanted)) + return new XorBlendRhiShader; + else + return new XorBlendShader; +} + +QSGMaterialType *XorBlendMaterial::type() const +{ + static QSGMaterialType type; + return &type; +} + +int XorBlendMaterial::compare(const QSGMaterial *o) const +{ + Q_ASSERT(o && type() == o->type()); + const XorBlendMaterial *other = static_cast<const XorBlendMaterial *>(o); + + if (!state.texture1 || !other->state.texture1) + return state.texture1 ? 1 : -1; + + if (!state.texture2 || !other->state.texture2) + return state.texture2 ? -1 : 1; + + if (int diff = state.texture1->comparisonKey() - other->state.texture1->comparisonKey()) + return diff; + + if (int diff = state.texture2->comparisonKey() - other->state.texture2->comparisonKey()) + return diff; - QList<QByteArray> attributes() const override { - return QList<QByteArray>() << "aVertex" << "aTexCoord"; + return 0; +} + +XorBlendShader::XorBlendShader() +{ + setShaderSourceFile(QOpenGLShader::Vertex, QLatin1String(":/scenegraph/twotextureproviders/shaders/xorblender.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, QLatin1String(":/scenegraph/twotextureproviders/shaders/xorblender.frag")); +} + +void XorBlendShader::initialize() +{ + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + // The texture units never change, only the textures we bind to them so + // we set these once and for all here. + program()->setUniformValue("uSource1", 0); // GL_TEXTURE0 + program()->setUniformValue("uSource2", 1); // GL_TEXTURE1 +} + +char const *const *XorBlendShader::attributeNames() const +{ + static char const *const attr[] = { "aVertex", "aTexCoord", nullptr }; + return attr; +} + +void XorBlendShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) +{ + XorBlendMaterial *material = static_cast<XorBlendMaterial *>(newEffect); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); + + if (state.isOpacityDirty()) + program()->setUniformValue(m_opacity_id, state.opacity()); + + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + // We bind the textures in inverse order so that we leave the updateState + // function with GL_TEXTURE0 as the active texture unit. This is maintain + // the "contract" that updateState should not mess up the GL state beyond + // what is needed for this material. + f->glActiveTexture(GL_TEXTURE1); + material->state.texture2->bind(); + f->glActiveTexture(GL_TEXTURE0); + material->state.texture1->bind(); +} + +XorBlendRhiShader::XorBlendRhiShader() +{ + setShaderFileName(VertexStage, QLatin1String(":/scenegraph/twotextureproviders/shaders/+qsb/xorblender.vert")); + setShaderFileName(FragmentStage, QLatin1String(":/scenegraph/twotextureproviders/shaders/+qsb/xorblender.frag")); +} + +bool XorBlendRhiShader::updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *) +{ + bool changed = false; + QByteArray *buf = state.uniformData(); + Q_ASSERT(buf->size() >= 68); + + if (state.isMatrixDirty()) { + const QMatrix4x4 m = state.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + changed = true; } - void updateState(const XorBlendState *state, const XorBlendState *) override { - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - // We bind the textures in inverse order so that we leave the updateState - // function with GL_TEXTURE0 as the active texture unit. This is maintain - // the "contract" that updateState should not mess up the GL state beyond - // what is needed for this material. - f->glActiveTexture(GL_TEXTURE1); - state->texture2->bind(); - f->glActiveTexture(GL_TEXTURE0); - state->texture1->bind(); + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + changed = true; } - void resolveUniforms() override { - // The texture units never change, only the texturess we bind to them so - // we set these once and for all here. - program()->setUniformValue("uSource1", 0); // GL_TEXTURE0 - program()->setUniformValue("uSource2", 1); // GL_TEXTURE1 + return changed; +} + +void XorBlendRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) +{ + Q_UNUSED(state); + + XorBlendMaterial *mat = static_cast<XorBlendMaterial *>(newMaterial); + switch (binding) { // the binding for the sampler2Ds in the fragment shader + case 1: + *texture = mat->state.texture1; + break; + case 2: + *texture = mat->state.texture2; + break; + default: + return; } -}; +} /* The rendering is split into two nodes. The top-most node is not actually * rendering anything, but is responsible for managing the texture providers. @@ -148,10 +254,7 @@ public: setFlag(QSGNode::UsePreprocess, true); // Set up material so it is all set for later.. - m_material = XorBlendShader::createMaterial(); - m_material->state()->texture1 = nullptr; - m_material->state()->texture2 = nullptr; - m_material->setFlag(QSGMaterial::Blending); + m_material = new XorBlendMaterial; m_node.setMaterial(m_material); m_node.setFlag(QSGNode::OwnsMaterial); @@ -166,25 +269,24 @@ public: } void preprocess() override { - XorBlendState *state = m_material->state(); // Update the textures from the providers, calling into QSGDynamicTexture if required if (m_provider1) { - state->texture1 = m_provider1->texture(); - if (QSGDynamicTexture *dt1 = qobject_cast<QSGDynamicTexture *>(state->texture1)) + m_material->state.texture1 = m_provider1->texture(); + if (QSGDynamicTexture *dt1 = qobject_cast<QSGDynamicTexture *>(m_material->state.texture1)) dt1->updateTexture(); } if (m_provider2) { - state->texture2 = m_provider2->texture(); - if (QSGDynamicTexture *dt2 = qobject_cast<QSGDynamicTexture *>(state->texture2)) + m_material->state.texture2 = m_provider2->texture(); + if (QSGDynamicTexture *dt2 = qobject_cast<QSGDynamicTexture *>(m_material->state.texture2)) dt2->updateTexture(); } // Remove node from the scene graph if it is there and either texture is missing... - if (m_node.parent() && (!state->texture1 || !state->texture2)) + if (m_node.parent() && (!m_material->state.texture1 || !m_material->state.texture2)) removeChildNode(&m_node); // Add it if it is not already there and both textures are present.. - else if (!m_node.parent() && state->texture1 && state->texture2) + else if (!m_node.parent() && m_material->state.texture1 && m_material->state.texture2) appendChildNode(&m_node); } @@ -206,7 +308,7 @@ public slots: private: QRectF m_rect; - QSGSimpleMaterial<XorBlendState> *m_material; + XorBlendMaterial *m_material; QSGGeometryNode m_node; QPointer<QSGTextureProvider> m_provider1; QPointer<QSGTextureProvider> m_provider2; 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/vulkantextureimport/doc/images/vulkantextureimport-example.jpg b/examples/quick/scenegraph/vulkantextureimport/doc/images/vulkantextureimport-example.jpg Binary files differnew file mode 100644 index 0000000000..e7bbe62bf3 --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/doc/images/vulkantextureimport-example.jpg diff --git a/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc b/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc new file mode 100644 index 0000000000..334291f990 --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/doc/src/vulkantextureimport.qdoc @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** 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/vulkantextureimport + \title Scene Graph - Vulkan Texture Import + \ingroup qtquickexamples + \brief Shows how to use a texture created directly with use a texture created directly withulkan. + + \image vulkantextureimport-example.jpg + + + The Vulkan Texture Import example shows how an application can import and + use a + \l{https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImage.html} + {VkImage} in the Qt Quick scene. This provides an alternative to the \l{Scene Graph - + Vulkan Under QML}{underlay}, overlay, or \l{Scene Graph - Custom Rendering + with QSGRenderNode}{render node} approaches when it comes to integrating + native Vulkan rendering. + + This example is equivalent in most ways to the \l{Scene Graph - Metal Texture Import}{Metal Texture Import} + example. The Vulkan rendering code is taken from the \l{Scene Graph - Vulkan Under QML}{Vulkan Under QML} example. + + */ diff --git a/examples/quick/scenegraph/vulkantextureimport/main.cpp b/examples/quick/scenegraph/vulkantextureimport/main.cpp new file mode 100644 index 0000000000..5dc28eb8a3 --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/main.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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> + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QQuickWindow::setSceneGraphBackend(QSGRendererInterface::VulkanRhi); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:///scenegraph/vulkantextureimport/main.qml")); + view.resize(400, 400); + view.show(); + + return app.exec(); +} diff --git a/examples/quick/scenegraph/vulkantextureimport/main.qml b/examples/quick/scenegraph/vulkantextureimport/main.qml new file mode 100644 index 0000000000..91adf4c394 --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/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 VulkanTextureImport 1.0 +//! [1] + +Rectangle { + gradient: Gradient { + GradientStop { position: 0; color: "firebrick" } + 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 vulkanunderqml example, is rendered into a texture directly with Vulkan. The VkImage is then imported and used in a custom Qt Quick item." + } +} diff --git a/examples/quick/scenegraph/vulkantextureimport/squircle.frag.spv b/examples/quick/scenegraph/vulkantextureimport/squircle.frag.spv Binary files differnew file mode 100644 index 0000000000..e4d13a871d --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/squircle.frag.spv diff --git a/examples/quick/scenegraph/vulkantextureimport/squircle.vert.spv b/examples/quick/scenegraph/vulkantextureimport/squircle.vert.spv Binary files differnew file mode 100644 index 0000000000..5df94a47e4 --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/squircle.vert.spv diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp new file mode 100644 index 0000000000..a4201c1dfa --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.cpp @@ -0,0 +1,823 @@ +/**************************************************************************** +** +** 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 "vulkantextureimport.h" + +#include <QtGui/QScreen> +#include <QtQuick/QQuickWindow> +#include <QtQuick/QSGTextureProvider> +#include <QtQuick/QSGSimpleTextureNode> + +#include <QVulkanInstance> +#include <QVulkanFunctions> + +class CustomTextureNode : public QSGTextureProvider, public QSGSimpleTextureNode +{ + Q_OBJECT + +public: + CustomTextureNode(QQuickItem *item); + ~CustomTextureNode() override; + + QSGTexture *texture() const override; + + void sync(); + +private slots: + void render(); + +private: + enum Stage { + VertexStage, + FragmentStage + }; + void prepareShader(Stage stage); + bool buildTexture(const QSize &size); + void freeTexture(); + bool createRenderPass(); + bool initialize(); + + QQuickItem *m_item; + QQuickWindow *m_window; + QSize m_size; + qreal m_dpr; + + QByteArray m_vert; + QByteArray m_frag; + + VkImage m_texture = VK_NULL_HANDLE; + VkDeviceMemory m_textureMemory = VK_NULL_HANDLE; + VkFramebuffer m_textureFramebuffer = VK_NULL_HANDLE; + VkImageView m_textureView = VK_NULL_HANDLE; + + bool m_initialized = false; + + float m_t; + + 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; + + VkRenderPass m_renderPass = VK_NULL_HANDLE; +}; + +CustomTextureItem::CustomTextureItem() +{ + setFlag(ItemHasContents, true); +} + +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; +} + +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; +} + +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(); +} + +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(); + }); +} + +CustomTextureNode::~CustomTextureNode() +{ + m_devFuncs->vkDestroyBuffer(m_dev, m_vbuf, nullptr); + m_devFuncs->vkDestroyBuffer(m_dev, m_ubuf, nullptr); + m_devFuncs->vkFreeMemory(m_dev, m_vbufMem, nullptr); + m_devFuncs->vkFreeMemory(m_dev, m_ubufMem, nullptr); + + m_devFuncs->vkDestroyPipelineCache(m_dev, m_pipelineCache, nullptr); + m_devFuncs->vkDestroyPipelineLayout(m_dev, m_pipelineLayout, nullptr); + m_devFuncs->vkDestroyPipeline(m_dev, m_pipeline, nullptr); + + m_devFuncs->vkDestroyRenderPass(m_dev, m_renderPass, nullptr); + + m_devFuncs->vkDestroyDescriptorSetLayout(m_dev, m_resLayout, nullptr); + m_devFuncs->vkDestroyDescriptorPool(m_dev, m_descriptorPool, nullptr); + + delete texture(); + freeTexture(); +} + +QSGTexture *CustomTextureNode::texture() const +{ + return QSGSimpleTextureNode::texture(); +} + +static const float vertices[] = { + -1, -1, + 1, -1, + -1, 1, + 1, 1 +}; + +const int UBUF_SIZE = 4; + + +bool CustomTextureNode::buildTexture(const QSize &size) +{ + VkImageCreateInfo imageInfo; + memset(&imageInfo, 0, sizeof(imageInfo)); + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.flags = 0; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imageInfo.extent.width = uint32_t(size.width()); + imageInfo.extent.height = uint32_t(size.height()); + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + + imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + VkImage image = VK_NULL_HANDLE; + if (m_devFuncs->vkCreateImage(m_dev, &imageInfo, nullptr, &image) != VK_SUCCESS) { + qCritical("VulkanWrapper: failed to create image!"); + return false; + } + + m_texture = image; + + VkMemoryRequirements memReq; + m_devFuncs->vkGetImageMemoryRequirements(m_dev, image, &memReq); + + quint32 memIndex = 0; + VkPhysicalDeviceMemoryProperties physDevMemProps; + m_window->vulkanInstance()->functions()->vkGetPhysicalDeviceMemoryProperties(m_physDev, &physDevMemProps); + for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) { + if (!(memReq.memoryTypeBits & (1 << i))) + continue; + memIndex = i; + } + + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + nullptr, + memReq.size, + memIndex + }; + + VkResult err = m_devFuncs->vkAllocateMemory(m_dev, &allocInfo, nullptr, &m_textureMemory); + if (err != VK_SUCCESS) { + qWarning("Failed to allocate memory for linear image: %d", err); + return false; + } + + err = m_devFuncs->vkBindImageMemory(m_dev, image, m_textureMemory, 0); + if (err != VK_SUCCESS) { + qWarning("Failed to bind linear image memory: %d", err); + return false; + } + + VkImageViewCreateInfo viewInfo; + memset(&viewInfo, 0, sizeof(viewInfo)); + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = imageInfo.format; + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + err = m_devFuncs->vkCreateImageView(m_dev, &viewInfo, nullptr, &m_textureView); + if (err != VK_SUCCESS) { + qWarning("Failed to create render target image view: %d", err); + return false; + } + + VkFramebufferCreateInfo fbInfo; + memset(&fbInfo, 0, sizeof(fbInfo)); + fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbInfo.renderPass = m_renderPass; + fbInfo.attachmentCount = 1; + fbInfo.pAttachments = &m_textureView; + fbInfo.width = uint32_t(size.width()); + fbInfo.height = uint32_t(size.height()); + fbInfo.layers = 1; + + err = m_devFuncs->vkCreateFramebuffer(m_dev, &fbInfo, nullptr, &m_textureFramebuffer); + if (err != VK_SUCCESS) { + qWarning("Failed to create framebuffer: %d", err); + return false; + } + return true; +} + +void CustomTextureNode::freeTexture() +{ + if (m_texture) { + m_devFuncs->vkDestroyFramebuffer(m_dev, m_textureFramebuffer, nullptr); + m_textureFramebuffer = VK_NULL_HANDLE; + m_devFuncs->vkFreeMemory(m_dev, m_textureMemory, nullptr); + m_textureMemory = VK_NULL_HANDLE; + m_devFuncs->vkDestroyImageView(m_dev, m_textureView, nullptr); + m_textureView = VK_NULL_HANDLE; + m_devFuncs->vkDestroyImage(m_dev, m_texture, nullptr); + m_texture = VK_NULL_HANDLE; + } +} + + + +static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign) +{ + return (v + byteAlign - 1) & ~(byteAlign - 1); +} + +bool CustomTextureNode::createRenderPass() +{ + const VkFormat vkformat = VK_FORMAT_R8G8B8A8_UNORM; + const VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; + VkAttachmentDescription colorAttDesc; + memset(&colorAttDesc, 0, sizeof(colorAttDesc)); + colorAttDesc.format = vkformat; + colorAttDesc.samples = samples; + colorAttDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + const VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpassDesc; + memset(&subpassDesc, 0, sizeof(subpassDesc)); + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.colorAttachmentCount = 1; + subpassDesc.pColorAttachments = &colorRef; + subpassDesc.pDepthStencilAttachment = nullptr; + subpassDesc.pResolveAttachments = nullptr; + + VkRenderPassCreateInfo rpInfo; + memset(&rpInfo, 0, sizeof(rpInfo)); + rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpInfo.attachmentCount = 1; + rpInfo.pAttachments = &colorAttDesc; + rpInfo.subpassCount = 1; + rpInfo.pSubpasses = &subpassDesc; + + VkResult err = m_devFuncs->vkCreateRenderPass(m_dev, &rpInfo, nullptr, &m_renderPass); + if (err != VK_SUCCESS) { + qWarning("Failed to create renderpass: %d", err); + return false; + } + + return true; +} + +bool CustomTextureNode::initialize() +{ + const int framesInFlight = m_window->graphicsStateInfo().framesInFlight; + 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 = *static_cast<VkPhysicalDevice *>(rif->getResource(m_window, QSGRendererInterface::PhysicalDeviceResource)); + m_dev = *static_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); + + createRenderPass(); + + 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); + + 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 = qMax(memReq.size, 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 = m_renderPass; + + 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); + return true; +} + +void CustomTextureNode::sync() +{ + m_dpr = m_window->effectiveDevicePixelRatio(); + const QSize newSize = m_window->size() * m_dpr; + bool needsNew = false; + + if (!m_initialized) { + prepareShader(VertexStage); + prepareShader(FragmentStage); + initialize(); + m_initialized = true; + } + + if (!texture()) + needsNew = true; + + if (newSize != m_size) { + needsNew = true; + m_size = newSize; + } + + if (needsNew) { + delete texture(); + freeTexture(); + buildTexture(m_size); + QSGTexture *wrapper = m_window->createTextureFromNativeObject(QQuickWindow::NativeObjectTexture, + &m_texture, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + m_size); + setTexture(wrapper); + } + + m_t = float(static_cast<CustomTextureItem *>(m_item)->t()); +} + +void CustomTextureNode::render() +{ + if (!m_initialized) + return; + + VkResult err = VK_SUCCESS; + + uint currentFrameSlot = m_window->graphicsStateInfo().currentFrameSlot; + VkDeviceSize ubufOffset = currentFrameSlot * m_allocPerUbuf; + void *p = nullptr; + 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); + + VkClearValue clearColor = {{ {0, 0, 0, 1} }}; + + VkRenderPassBeginInfo rpBeginInfo = {}; + rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpBeginInfo.renderPass = m_renderPass; + rpBeginInfo.framebuffer = m_textureFramebuffer; + rpBeginInfo.renderArea.extent.width = m_size.width(); + rpBeginInfo.renderArea.extent.height = m_size.height(); + rpBeginInfo.clearValueCount = 1; + rpBeginInfo.pClearValues = &clearColor; + + QSGRendererInterface *rif = m_window->rendererInterface(); + VkCommandBuffer cmdBuf = *reinterpret_cast<VkCommandBuffer *>( + rif->getResource(m_window, QSGRendererInterface::CommandListResource)); + + m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + m_devFuncs->vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); + + VkDeviceSize vbufOffset = 0; + m_devFuncs->vkCmdBindVertexBuffers(cmdBuf, 0, 1, &m_vbuf, &vbufOffset); + + uint32_t dynamicOffset = m_allocPerUbuf * currentFrameSlot; + m_devFuncs->vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, + &m_ubufDescriptor, 1, &dynamicOffset); + + VkViewport vp = { 0, 0, float(m_size.width()), float(m_size.height()), 0.0f, 1.0f }; + m_devFuncs->vkCmdSetViewport(cmdBuf, 0, 1, &vp); + VkRect2D scissor = { { 0, 0 }, { uint32_t(m_size.width()), uint32_t(m_size.height()) } }; + m_devFuncs->vkCmdSetScissor(cmdBuf, 0, 1, &scissor); + + m_devFuncs->vkCmdDraw(cmdBuf, 4, 1, 0, 0); + m_devFuncs->vkCmdEndRenderPass(cmdBuf); + + // Memory barrier before the texture can be used as a source. + // Since we are not using a sub-pass, we have to do this explicitly. + + VkImageMemoryBarrier imageTransitionBarrier = {}; + imageTransitionBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageTransitionBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + imageTransitionBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imageTransitionBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageTransitionBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageTransitionBarrier.image = m_texture; + imageTransitionBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageTransitionBarrier.subresourceRange.levelCount = imageTransitionBarrier.subresourceRange.layerCount = 1; + + m_devFuncs->vkCmdPipelineBarrier(cmdBuf, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, 0, nullptr, 0, nullptr, + 1, &imageTransitionBarrier); +} + +void CustomTextureNode::prepareShader(Stage stage) +{ + QString filename; + if (stage == VertexStage) { + filename = QLatin1String(":/scenegraph/vulkantextureimport/squircle.vert.spv"); + } else { + Q_ASSERT(stage == FragmentStage); + filename = QLatin1String(":/scenegraph/vulkantextureimport/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()); + } +} + +#include "vulkantextureimport.moc" diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h new file mode 100644 index 0000000000..b8c13b44f6 --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.h @@ -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$ +** +****************************************************************************/ + +#ifndef VULKANTEXTUREIMPORT_H +#define VULKANTEXTUREIMPORT_H + +#include <QtQuick/QQuickItem> + +class CustomTextureNode; + +//! [1] +class CustomTextureItem : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + QML_ELEMENT + +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 // VULKANTEXTUREIMPORT_H diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro new file mode 100644 index 0000000000..11e422ecad --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.pro @@ -0,0 +1,13 @@ +!qtConfig(vulkan): error("This example requires Qt built with Vulkan support") + +QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = VulkanTextureImport +QML_IMPORT_MAJOR_VERSION = 1 + +HEADERS += vulkantextureimport.h +SOURCES += vulkantextureimport.cpp main.cpp +RESOURCES += vulkantextureimport.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/vulkantextureimport +INSTALLS += target diff --git a/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.qrc b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.qrc new file mode 100644 index 0000000000..a1aec6c950 --- /dev/null +++ b/examples/quick/scenegraph/vulkantextureimport/vulkantextureimport.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/scenegraph/vulkantextureimport"> + <file>main.qml</file> + <file>squircle.vert.spv</file> + <file>squircle.frag.spv</file> + </qresource> +</RCC> diff --git a/examples/quick/scenegraph/vulkanunderqml/main.cpp b/examples/quick/scenegraph/vulkanunderqml/main.cpp index a04497b1d6..6ed0efacdd 100644 --- a/examples/quick/scenegraph/vulkanunderqml/main.cpp +++ b/examples/quick/scenegraph/vulkanunderqml/main.cpp @@ -50,14 +50,11 @@ #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); diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h index 7e65d01a15..16feeacb5b 100644 --- a/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h +++ b/examples/quick/scenegraph/vulkanunderqml/vulkansquircle.h @@ -59,6 +59,7 @@ class VulkanSquircle : public QQuickItem { Q_OBJECT Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + QML_ELEMENT public: VulkanSquircle(); diff --git a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro index 9ea57b91c3..8f7ea5861d 100644 --- a/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro +++ b/examples/quick/scenegraph/vulkanunderqml/vulkanunderqml.pro @@ -1,6 +1,9 @@ !qtConfig(vulkan): error("This example requires Qt built with Vulkan support") QT += qml quick +CONFIG += qmltypes +QML_IMPORT_NAME = VulkanUnderQML +QML_IMPORT_MAJOR_VERSION = 1 HEADERS += vulkansquircle.h SOURCES += vulkansquircle.cpp main.cpp |