aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/qml/referenceexamples/extended/lineedit.cpp48
-rw-r--r--examples/quick/imageresponseprovider/imageresponseprovider.cpp71
-rw-r--r--examples/quick/localstorage/localstorage/Header.qml10
-rw-r--r--examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp426
-rw-r--r--examples/quick/scenegraph/d3d11underqml/d3d11squircle.h86
-rw-r--r--examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro10
-rw-r--r--examples/quick/scenegraph/d3d11underqml/d3d11underqml.qrc7
-rw-r--r--examples/quick/scenegraph/d3d11underqml/main.cpp69
-rw-r--r--examples/quick/scenegraph/d3d11underqml/main.qml89
-rw-r--r--examples/quick/scenegraph/d3d11underqml/squircle.frag35
-rw-r--r--examples/quick/scenegraph/d3d11underqml/squircle.vert30
-rw-r--r--examples/quick/scenegraph/metalunderqml/main.cpp69
-rw-r--r--examples/quick/scenegraph/metalunderqml/main.qml89
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalsquircle.h86
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalsquircle.mm364
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalunderqml.pro10
-rw-r--r--examples/quick/scenegraph/metalunderqml/metalunderqml.qrc7
-rw-r--r--examples/quick/scenegraph/metalunderqml/squircle.frag29
-rw-r--r--examples/quick/scenegraph/metalunderqml/squircle.vert23
-rw-r--r--examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc41
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.cpp53
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.h3
-rw-r--r--examples/quick/scenegraph/scenegraph.pro8
-rw-r--r--examples/quick/scenegraph/shared/squircle_rhi.frag16
-rw-r--r--examples/quick/scenegraph/shared/squircle_rhi.vert13
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/blur.fragbin0 -> 2247 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/colorize.fragbin0 -> 2106 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/genie.vertbin0 -> 2629 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/outline.fragbin0 -> 2538 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/shadow.fragbin0 -> 2151 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/wobble.fragbin0 -> 2049 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/rhi/blur.frag21
-rw-r--r--examples/quick/shadereffects/content/shaders/rhi/colorize.frag20
-rwxr-xr-xexamples/quick/shadereffects/content/shaders/rhi/compile.bat56
-rw-r--r--examples/quick/shadereffects/content/shaders/rhi/genie.vert29
-rw-r--r--examples/quick/shadereffects/content/shaders/rhi/outline.frag24
-rw-r--r--examples/quick/shadereffects/content/shaders/rhi/shadow.frag21
-rw-r--r--examples/quick/shadereffects/content/shaders/rhi/wobble.frag20
-rw-r--r--examples/quick/shadereffects/doc/src/shadereffects.qdoc16
-rw-r--r--examples/quick/shadereffects/shadereffects.qrc6
40 files changed, 1807 insertions, 98 deletions
diff --git a/examples/qml/referenceexamples/extended/lineedit.cpp b/examples/qml/referenceexamples/extended/lineedit.cpp
index f2f5ec0efc..777e15db07 100644
--- a/examples/qml/referenceexamples/extended/lineedit.cpp
+++ b/examples/qml/referenceexamples/extended/lineedit.cpp
@@ -57,58 +57,50 @@ LineEditExtension::LineEditExtension(QObject *object)
int LineEditExtension::leftMargin() const
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- return l;
+ return m_lineedit->textMargins().left();
}
-void LineEditExtension::setLeftMargin(int m)
+void LineEditExtension::setLeftMargin(int l)
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- m_lineedit->setTextMargins(m, t, r, b);
+ QMargins m = m_lineedit->textMargins();
+ m.setLeft(l);
+ m_lineedit->setTextMargins(m);
}
int LineEditExtension::rightMargin() const
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- return r;
+ return m_lineedit->textMargins().right();
}
-void LineEditExtension::setRightMargin(int m)
+void LineEditExtension::setRightMargin(int r)
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- m_lineedit->setTextMargins(l, t, m, b);
+ QMargins m = m_lineedit->textMargins();
+ m.setRight(r);
+ m_lineedit->setTextMargins(m);
}
int LineEditExtension::topMargin() const
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- return t;
+ return m_lineedit->textMargins().top();
}
-void LineEditExtension::setTopMargin(int m)
+void LineEditExtension::setTopMargin(int t)
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- m_lineedit->setTextMargins(l, m, r, b);
+ QMargins m = m_lineedit->textMargins();
+ m.setTop(t);
+ m_lineedit->setTextMargins(m);
}
int LineEditExtension::bottomMargin() const
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- return b;
+ return m_lineedit->textMargins().bottom();
}
-void LineEditExtension::setBottomMargin(int m)
+void LineEditExtension::setBottomMargin(int b)
{
- int l, r, t, b;
- m_lineedit->getTextMargins(&l, &t, &r, &b);
- m_lineedit->setTextMargins(l, t, r, m);
+ QMargins m = m_lineedit->textMargins();
+ m.setBottom(b);
+ m_lineedit->setTextMargins(m);
}
diff --git a/examples/quick/imageresponseprovider/imageresponseprovider.cpp b/examples/quick/imageresponseprovider/imageresponseprovider.cpp
index 4f7c12b1d8..32510dbec8 100644
--- a/examples/quick/imageresponseprovider/imageresponseprovider.cpp
+++ b/examples/quick/imageresponseprovider/imageresponseprovider.cpp
@@ -57,40 +57,60 @@
#include <QImage>
#include <QThreadPool>
-class AsyncImageResponse : public QQuickImageResponse, public QRunnable
+class AsyncImageResponseRunnable : public QObject, public QRunnable
+{
+ Q_OBJECT
+
+signals:
+ void done(QImage image);
+
+public:
+ AsyncImageResponseRunnable(const QString &id, const QSize &requestedSize)
+ : m_id(id), m_requestedSize(requestedSize) {}
+
+ void run() override
+ {
+ auto image = QImage(50, 50, QImage::Format_RGB32);
+ if (m_id == QLatin1String("slow")) {
+ qDebug() << "Slow, red, sleeping for 5 seconds";
+ QThread::sleep(5);
+ image.fill(Qt::red);
+ } else {
+ qDebug() << "Fast, blue, sleeping for 1 second";
+ QThread::sleep(1);
+ image.fill(Qt::blue);
+ }
+ if (m_requestedSize.isValid())
+ image = image.scaled(m_requestedSize);
+
+ emit done(image);
+ }
+
+private:
+ QString m_id;
+ QSize m_requestedSize;
+};
+
+class AsyncImageResponse : public QQuickImageResponse
{
public:
- AsyncImageResponse(const QString &id, const QSize &requestedSize)
- : m_id(id), m_requestedSize(requestedSize)
+ AsyncImageResponse(const QString &id, const QSize &requestedSize, QThreadPool *pool)
{
- setAutoDelete(false);
+ auto runnable = new AsyncImageResponseRunnable(id, requestedSize);
+ connect(runnable, &AsyncImageResponseRunnable::done, this, &AsyncImageResponse::handleDone);
+ pool->start(runnable);
}
- QQuickTextureFactory *textureFactory() const override
- {
- return QQuickTextureFactory::textureFactoryForImage(m_image);
+ void handleDone(QImage image) {
+ m_image = image;
+ emit finished();
}
- void run() override
+ QQuickTextureFactory *textureFactory() const override
{
- m_image = QImage(50, 50, QImage::Format_RGB32);
- if (m_id == "slow") {
- qDebug() << "Slow, red, sleeping for 5 seconds";
- QThread::sleep(5);
- m_image.fill(Qt::red);
- } else {
- qDebug() << "Fast, blue, sleeping for 1 second";
- QThread::sleep(1);
- m_image.fill(Qt::blue);
- }
- if (m_requestedSize.isValid())
- m_image = m_image.scaled(m_requestedSize);
-
- emit finished();
+ return QQuickTextureFactory::textureFactoryForImage(m_image);
}
- QString m_id;
- QSize m_requestedSize;
QImage m_image;
};
@@ -99,8 +119,7 @@ class AsyncImageProvider : public QQuickAsyncImageProvider
public:
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override
{
- AsyncImageResponse *response = new AsyncImageResponse(id, requestedSize);
- pool.start(response);
+ AsyncImageResponse *response = new AsyncImageResponse(id, requestedSize, &pool);
return response;
}
diff --git a/examples/quick/localstorage/localstorage/Header.qml b/examples/quick/localstorage/localstorage/Header.qml
index 18f51c1b6e..b3807f6e40 100644
--- a/examples/quick/localstorage/localstorage/Header.qml
+++ b/examples/quick/localstorage/localstorage/Header.qml
@@ -48,7 +48,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-import QtQuick 2.7
+import QtQuick 2.14
import QtQuick.Window 2.0
import QtQuick.LocalStorage 2.0
import "Database.js" as JS
@@ -143,8 +143,8 @@ Item {
font.pixelSize: 22
activeFocusOnPress: true
activeFocusOnTab: true
- validator: RegExpValidator {
- regExp: /[0-9/,:.]+/
+ validator: RegularExpressionValidator {
+ regularExpression: /[0-9/,:.]+/
}
onEditingFinished: {
if (dateInput.text == "") {
@@ -174,8 +174,8 @@ Item {
font.pixelSize: 22
activeFocusOnPress: true
activeFocusOnTab: true
- validator: RegExpValidator {
- regExp: /\d{1,3}/
+ validator: RegularExpressionValidator {
+ regularExpression: /\d{1,3}/
}
onEditingFinished: {
if (distInput.text == "") {
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp
new file mode 100644
index 0000000000..f05bf2f843
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** 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 "d3d11squircle.h"
+#include <QtCore/QRunnable>
+#include <QtQuick/QQuickWindow>
+
+#include <d3d11.h>
+#include <d3dcompiler.h>
+
+class SquircleRenderer : public QObject
+{
+ Q_OBJECT
+public:
+ SquircleRenderer();
+ ~SquircleRenderer();
+
+ void setT(qreal t) { m_t = t; }
+ void setViewportSize(const QSize &size) { m_viewportSize = size; }
+ void setWindow(QQuickWindow *window) { m_window = window; }
+
+public slots:
+ void frameStart();
+ void mainPassRecordingStart();
+
+private:
+ enum Stage {
+ VertexStage,
+ FragmentStage
+ };
+ void prepareShader(Stage stage);
+ QByteArray compileShader(Stage stage,
+ const QByteArray &source,
+ const QByteArray &entryPoint);
+ void init();
+
+ QSize m_viewportSize;
+ qreal m_t;
+ QQuickWindow *m_window;
+
+ ID3D11Device *m_device = nullptr;
+ ID3D11DeviceContext *m_context = nullptr;
+ QByteArray m_vert;
+ QByteArray m_vertEntryPoint;
+ QByteArray m_frag;
+ QByteArray m_fragEntryPoint;
+
+ bool m_initialized = false;
+ ID3D11Buffer *m_vbuf = nullptr;
+ ID3D11Buffer *m_cbuf = nullptr;
+ ID3D11VertexShader *m_vs = nullptr;
+ ID3D11PixelShader *m_ps = nullptr;
+ ID3D11InputLayout *m_inputLayout = nullptr;
+ ID3D11RasterizerState *m_rastState = nullptr;
+ ID3D11DepthStencilState *m_dsState = nullptr;
+ ID3D11BlendState *m_blendState = nullptr;
+};
+
+D3D11Squircle::D3D11Squircle()
+ : m_t(0)
+ , m_renderer(nullptr)
+{
+ connect(this, &QQuickItem::windowChanged, this, &D3D11Squircle::handleWindowChanged);
+}
+
+void D3D11Squircle::setT(qreal t)
+{
+ if (t == m_t)
+ return;
+ m_t = t;
+ emit tChanged();
+ if (window())
+ window()->update();
+}
+
+void D3D11Squircle::handleWindowChanged(QQuickWindow *win)
+{
+ if (win) {
+ connect(win, &QQuickWindow::beforeSynchronizing, this, &D3D11Squircle::sync, Qt::DirectConnection);
+ connect(win, &QQuickWindow::sceneGraphInvalidated, this, &D3D11Squircle::cleanup, Qt::DirectConnection);
+
+ // Ensure we start with cleared to black. The squircle's blend mode relies on this.
+ win->setColor(Qt::black);
+ }
+}
+
+SquircleRenderer::SquircleRenderer()
+ : m_t(0)
+{
+}
+
+// The safe way to release custom graphics resources it to both connect to
+// sceneGraphInvalidated() and implement releaseResources(). To support
+// threaded render loops the latter performs the SquircleRenderer destruction
+// via scheduleRenderJob(). Note that the D3D11Squircle may be gone by the time
+// the QRunnable is invoked.
+
+void D3D11Squircle::cleanup()
+{
+ delete m_renderer;
+ m_renderer = nullptr;
+}
+
+class CleanupJob : public QRunnable
+{
+public:
+ CleanupJob(SquircleRenderer *renderer) : m_renderer(renderer) { }
+ void run() override { delete m_renderer; }
+private:
+ SquircleRenderer *m_renderer;
+};
+
+void D3D11Squircle::releaseResources()
+{
+ window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage);
+ m_renderer = nullptr;
+}
+
+SquircleRenderer::~SquircleRenderer()
+{
+ qDebug("cleanup");
+
+ if (m_vs)
+ m_vs->Release();
+
+ if (m_ps)
+ m_ps->Release();
+
+ if (m_vbuf)
+ m_vbuf->Release();
+
+ if (m_cbuf)
+ m_cbuf->Release();
+
+ if (m_inputLayout)
+ m_inputLayout->Release();
+
+ if (m_rastState)
+ m_rastState->Release();
+
+ if (m_dsState)
+ m_dsState->Release();
+
+ if (m_blendState)
+ m_blendState->Release();
+}
+
+void D3D11Squircle::sync()
+{
+ if (!m_renderer) {
+ m_renderer = new SquircleRenderer;
+ connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::frameStart, Qt::DirectConnection);
+ connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::mainPassRecordingStart, Qt::DirectConnection);
+ }
+ m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
+ m_renderer->setT(m_t);
+ m_renderer->setWindow(window());
+}
+
+void SquircleRenderer::frameStart()
+{
+ QSGRendererInterface *rif = m_window->rendererInterface();
+
+ // We are not prepared for anything other than running with the RHI and its D3D11 backend.
+ Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::Direct3D11Rhi);
+
+ m_device = reinterpret_cast<ID3D11Device *>(rif->getResource(m_window, QSGRendererInterface::DeviceResource));
+ Q_ASSERT(m_device);
+ m_context = reinterpret_cast<ID3D11DeviceContext *>(rif->getResource(m_window, QSGRendererInterface::DeviceContextResource));
+ Q_ASSERT(m_context);
+
+ if (m_vert.isEmpty())
+ prepareShader(VertexStage);
+ if (m_frag.isEmpty())
+ prepareShader(FragmentStage);
+
+ if (!m_initialized)
+ init();
+}
+
+static const float vertices[] = {
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ 1, 1
+};
+
+void SquircleRenderer::mainPassRecordingStart()
+{
+ m_window->beginExternalCommands();
+
+ D3D11_MAPPED_SUBRESOURCE mp;
+ // will copy the entire constant buffer every time -> pass WRITE_DISCARD -> prevent pipeline stalls
+ HRESULT hr = m_context->Map(m_cbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
+ if (SUCCEEDED(hr)) {
+ float t = m_t;
+ memcpy(mp.pData, &t, 4);
+ m_context->Unmap(m_cbuf, 0);
+ } else {
+ qFatal("Failed to map constant buffer: 0x%x", hr);
+ }
+
+ D3D11_VIEWPORT v;
+ v.TopLeftX = 0;
+ v.TopLeftY = 0;
+ v.Width = m_viewportSize.width();
+ v.Height = m_viewportSize.height();
+ v.MinDepth = 0;
+ v.MaxDepth = 1;
+ m_context->RSSetViewports(1, &v);
+
+ m_context->VSSetShader(m_vs, nullptr, 0);
+ m_context->PSSetShader(m_ps, nullptr, 0);
+ m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ m_context->IASetInputLayout(m_inputLayout);
+ m_context->OMSetDepthStencilState(m_dsState, 0);
+ float blendConstants[] = { 1, 1, 1, 1 };
+ m_context->OMSetBlendState(m_blendState, blendConstants, 0xFFFFFFFF);
+ m_context->RSSetState(m_rastState);
+
+ const UINT stride = 2 * sizeof(float); // vec2
+ const UINT offset = 0;
+ m_context->IASetVertexBuffers(0, 1, &m_vbuf, &stride, &offset);
+ m_context->PSSetConstantBuffers(0, 1, &m_cbuf);
+
+ m_context->Draw(4, 0);
+
+ m_window->endExternalCommands();
+}
+
+void SquircleRenderer::prepareShader(Stage stage)
+{
+ QString filename;
+ if (stage == VertexStage) {
+ filename = QLatin1String(":/scenegraph/d3d11underqml/squircle.vert");
+ } else {
+ Q_ASSERT(stage == FragmentStage);
+ filename = QLatin1String(":/scenegraph/d3d11underqml/squircle.frag");
+ }
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly))
+ qFatal("Failed to read shader %s", qPrintable(filename));
+
+ const QByteArray contents = f.readAll();
+
+ if (stage == VertexStage) {
+ m_vert = contents;
+ Q_ASSERT(!m_vert.isEmpty());
+ m_vertEntryPoint = QByteArrayLiteral("main");
+ } else {
+ m_frag = contents;
+ Q_ASSERT(!m_frag.isEmpty());
+ m_fragEntryPoint = QByteArrayLiteral("main");
+ }
+}
+
+QByteArray SquircleRenderer::compileShader(Stage stage,
+ const QByteArray &source,
+ const QByteArray &entryPoint)
+{
+ const char *target;
+ switch (stage) {
+ case VertexStage:
+ target = "vs_5_0";
+ break;
+ case FragmentStage:
+ target = "ps_5_0";
+ break;
+ default:
+ qFatal("Unknown shader stage %d", stage);
+ return QByteArray();
+ }
+
+ ID3DBlob *bytecode = nullptr;
+ ID3DBlob *errors = nullptr;
+ HRESULT hr = D3DCompile(source.constData(), source.size(),
+ nullptr, nullptr, nullptr,
+ entryPoint.constData(), target, 0, 0, &bytecode, &errors);
+ if (FAILED(hr) || !bytecode) {
+ qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
+ if (errors) {
+ const QByteArray msg(static_cast<const char *>(errors->GetBufferPointer()),
+ errors->GetBufferSize());
+ errors->Release();
+ qWarning("%s", msg.constData());
+ }
+ return QByteArray();
+ }
+
+ QByteArray result;
+ result.resize(bytecode->GetBufferSize());
+ memcpy(result.data(), bytecode->GetBufferPointer(), result.size());
+ bytecode->Release();
+
+ return result;
+}
+
+void SquircleRenderer::init()
+{
+ qDebug("init");
+ m_initialized = true;
+
+ const QByteArray vs = compileShader(VertexStage, m_vert, m_vertEntryPoint);
+ const QByteArray fs = compileShader(FragmentStage, m_frag, m_fragEntryPoint);
+
+ HRESULT hr = m_device->CreateVertexShader(vs.constData(), vs.size(), nullptr, &m_vs);
+ if (FAILED(hr))
+ qFatal("Failed to create vertex shader: 0x%x", hr);
+
+ hr = m_device->CreatePixelShader(fs.constData(), fs.size(), nullptr, &m_ps);
+ if (FAILED(hr))
+ qFatal("Failed to create pixel shader: 0x%x", hr);
+
+ D3D11_BUFFER_DESC bufDesc;
+ memset(&bufDesc, 0, sizeof(bufDesc));
+ bufDesc.ByteWidth = sizeof(vertices);
+ bufDesc.Usage = D3D11_USAGE_DEFAULT;
+ bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ hr = m_device->CreateBuffer(&bufDesc, nullptr, &m_vbuf);
+ if (FAILED(hr))
+ qFatal("Failed to create buffer: 0x%x", hr);
+
+ m_context->UpdateSubresource(m_vbuf, 0, nullptr, vertices, 0, 0);
+
+ bufDesc.ByteWidth = 256;
+ bufDesc.Usage = D3D11_USAGE_DYNAMIC;
+ bufDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ hr = m_device->CreateBuffer(&bufDesc, nullptr, &m_cbuf);
+ if (FAILED(hr))
+ qFatal("Failed to create buffer: 0x%x", hr);
+
+ D3D11_INPUT_ELEMENT_DESC inputDesc;
+ memset(&inputDesc, 0, sizeof(inputDesc));
+ // the output from SPIRV-Cross uses TEXCOORD<location> as the semantic
+ inputDesc.SemanticName = "TEXCOORD";
+ inputDesc.SemanticIndex = 0;
+ inputDesc.Format = DXGI_FORMAT_R32G32_FLOAT; // vec2
+ inputDesc.InputSlot = 0;
+ inputDesc.AlignedByteOffset = 0;
+ inputDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
+ hr = m_device->CreateInputLayout(&inputDesc, 1, vs.constData(), vs.size(), &m_inputLayout);
+ if (FAILED(hr))
+ qFatal("Failed to create input layout: 0x%x", hr);
+
+ D3D11_RASTERIZER_DESC rastDesc;
+ memset(&rastDesc, 0, sizeof(rastDesc));
+ rastDesc.FillMode = D3D11_FILL_SOLID;
+ rastDesc.CullMode = D3D11_CULL_NONE;
+ hr = m_device->CreateRasterizerState(&rastDesc, &m_rastState);
+ if (FAILED(hr))
+ qFatal("Failed to create rasterizer state: 0x%x", hr);
+
+ D3D11_DEPTH_STENCIL_DESC dsDesc;
+ memset(&dsDesc, 0, sizeof(dsDesc));
+ hr = m_device->CreateDepthStencilState(&dsDesc, &m_dsState);
+ if (FAILED(hr))
+ qFatal("Failed to create depth/stencil state: 0x%x", hr);
+
+ D3D11_BLEND_DESC blendDesc;
+ memset(&blendDesc, 0, sizeof(blendDesc));
+ blendDesc.IndependentBlendEnable = true;
+ D3D11_RENDER_TARGET_BLEND_DESC blend;
+ memset(&blend, 0, sizeof(blend));
+ blend.BlendEnable = true;
+ blend.SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ blend.DestBlend = D3D11_BLEND_ONE;
+ blend.BlendOp = D3D11_BLEND_OP_ADD;
+ blend.SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
+ blend.DestBlendAlpha = D3D11_BLEND_ONE;
+ blend.BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ blend.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ blendDesc.RenderTarget[0] = blend;
+ hr = m_device->CreateBlendState(&blendDesc, &m_blendState);
+ if (FAILED(hr))
+ qFatal("Failed to create blend state: 0x%x", hr);
+}
+
+#include "d3d11squircle.moc"
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
new file mode 100644
index 0000000000..be9aadc43b
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef D3D11SQUIRCLE_H
+#define D3D11SQUIRCLE_H
+
+#include <QtQuick/QQuickItem>
+
+class SquircleRenderer;
+
+class D3D11Squircle : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+
+public:
+ D3D11Squircle();
+
+ qreal t() const { return m_t; }
+ void setT(qreal t);
+
+signals:
+ void tChanged();
+
+public slots:
+ void sync();
+ void cleanup();
+
+private slots:
+ void handleWindowChanged(QQuickWindow *win);
+
+private:
+ void releaseResources() override;
+
+ qreal m_t;
+ SquircleRenderer *m_renderer = nullptr;
+};
+
+#endif
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro
new file mode 100644
index 0000000000..3c94d48ac4
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro
@@ -0,0 +1,10 @@
+QT += qml quick
+
+HEADERS += d3d11squircle.h
+SOURCES += d3d11squircle.cpp main.cpp
+RESOURCES += d3d11underqml.qrc
+
+LIBS += -ld3d11 -ld3dcompiler
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/d3d11underqml
+INSTALLS += target
diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.qrc b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.qrc
new file mode 100644
index 0000000000..fa16b88279
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/scenegraph/d3d11underqml">
+ <file>main.qml</file>
+ <file>squircle.vert</file>
+ <file>squircle.frag</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/scenegraph/d3d11underqml/main.cpp b/examples/quick/scenegraph/d3d11underqml/main.cpp
new file mode 100644
index 0000000000..d26de1144a
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QtQuick/QQuickView>
+#include "d3d11squircle.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<D3D11Squircle>("D3D11UnderQML", 1, 0, "D3D11Squircle");
+
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Direct3D11Rhi);
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:///scenegraph/d3d11underqml/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/quick/scenegraph/d3d11underqml/main.qml b/examples/quick/scenegraph/d3d11underqml/main.qml
new file mode 100644
index 0000000000..da128bead6
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/main.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [1]
+import QtQuick 2.0
+import D3D11UnderQML 1.0
+
+Item {
+
+ width: 320
+ height: 480
+
+ D3D11Squircle {
+ SequentialAnimation on t {
+ NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
+ NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
+ loops: Animation.Infinite
+ running: true
+ }
+ }
+//! [1] //! [2]
+ Rectangle {
+ color: Qt.rgba(1, 1, 1, 0.7)
+ radius: 10
+ border.width: 1
+ border.color: "white"
+ anchors.fill: label
+ anchors.margins: -10
+ }
+
+ Text {
+ id: label
+ color: "black"
+ wrapMode: Text.WordWrap
+ text: "The background here is a squircle rendered with raw Direct3D 11 using the beforeRendering() and beforeRenderPassRecording() signals in QQuickWindow. This text label and its border is rendered using QML"
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.margins: 20
+ }
+}
+//! [2]
diff --git a/examples/quick/scenegraph/d3d11underqml/squircle.frag b/examples/quick/scenegraph/d3d11underqml/squircle.frag
new file mode 100644
index 0000000000..a907c84e58
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/squircle.frag
@@ -0,0 +1,35 @@
+cbuffer buf : register(b0)
+{
+ float ubuf_t : packoffset(c0);
+};
+
+
+static float2 coords;
+static float4 fragColor;
+
+struct SPIRV_Cross_Input
+{
+ float2 coords : TEXCOORD0;
+};
+
+struct SPIRV_Cross_Output
+{
+ float4 fragColor : SV_Target0;
+};
+
+void frag_main()
+{
+ float i = 1.0f - (pow(abs(coords.x), 4.0f) + pow(abs(coords.y), 4.0f));
+ i = smoothstep(ubuf_t - 0.800000011920928955078125f, ubuf_t + 0.800000011920928955078125f, i);
+ i = floor(i * 20.0f) / 20.0f;
+ fragColor = float4((coords * 0.5f) + 0.5f.xx, i, i);
+}
+
+SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
+{
+ coords = stage_input.coords;
+ frag_main();
+ SPIRV_Cross_Output stage_output;
+ stage_output.fragColor = fragColor;
+ return stage_output;
+}
diff --git a/examples/quick/scenegraph/d3d11underqml/squircle.vert b/examples/quick/scenegraph/d3d11underqml/squircle.vert
new file mode 100644
index 0000000000..077a1ad096
--- /dev/null
+++ b/examples/quick/scenegraph/d3d11underqml/squircle.vert
@@ -0,0 +1,30 @@
+static float4 gl_Position;
+static float4 vertices;
+static float2 coords;
+
+struct SPIRV_Cross_Input
+{
+ float4 vertices : TEXCOORD0;
+};
+
+struct SPIRV_Cross_Output
+{
+ float2 coords : TEXCOORD0;
+ float4 gl_Position : SV_Position;
+};
+
+void vert_main()
+{
+ gl_Position = vertices;
+ coords = vertices.xy;
+}
+
+SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
+{
+ vertices = stage_input.vertices;
+ vert_main();
+ SPIRV_Cross_Output stage_output;
+ stage_output.gl_Position = gl_Position;
+ stage_output.coords = coords;
+ return stage_output;
+}
diff --git a/examples/quick/scenegraph/metalunderqml/main.cpp b/examples/quick/scenegraph/metalunderqml/main.cpp
new file mode 100644
index 0000000000..5ad337abb1
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QtQuick/QQuickView>
+#include "metalsquircle.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<MetalSquircle>("MetalUnderQML", 1, 0, "MetalSquircle");
+
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::MetalRhi);
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:///scenegraph/metalunderqml/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/quick/scenegraph/metalunderqml/main.qml b/examples/quick/scenegraph/metalunderqml/main.qml
new file mode 100644
index 0000000000..d41a0b8e81
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/main.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [1]
+import QtQuick 2.0
+import MetalUnderQML 1.0
+
+Item {
+
+ width: 320
+ height: 480
+
+ MetalSquircle {
+ SequentialAnimation on t {
+ NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
+ NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
+ loops: Animation.Infinite
+ running: true
+ }
+ }
+//! [1] //! [2]
+ Rectangle {
+ color: Qt.rgba(1, 1, 1, 0.7)
+ radius: 10
+ border.width: 1
+ border.color: "white"
+ anchors.fill: label
+ anchors.margins: -10
+ }
+
+ Text {
+ id: label
+ color: "black"
+ wrapMode: Text.WordWrap
+ text: "The background here is a squircle rendered with raw Metal using the beforeRendering() and beforeRenderPassRecording() signals in QQuickWindow. This text label and its border is rendered using QML"
+ anchors.right: parent.right
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.margins: 20
+ }
+}
+//! [2]
diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.h b/examples/quick/scenegraph/metalunderqml/metalsquircle.h
new file mode 100644
index 0000000000..43c4afad21
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef METALSQUIRCLE_H
+#define METALSQUIRCLE_H
+
+#include <QtQuick/QQuickItem>
+
+class SquircleRenderer;
+
+class MetalSquircle : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged)
+
+public:
+ MetalSquircle();
+
+ qreal t() const { return m_t; }
+ void setT(qreal t);
+
+signals:
+ void tChanged();
+
+public slots:
+ void sync();
+ void cleanup();
+
+private slots:
+ void handleWindowChanged(QQuickWindow *win);
+
+private:
+ void releaseResources() override;
+
+ qreal m_t;
+ SquircleRenderer *m_renderer = nullptr;
+};
+
+#endif
diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.mm b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
new file mode 100644
index 0000000000..92aceeb433
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm
@@ -0,0 +1,364 @@
+/****************************************************************************
+**
+** 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 "metalsquircle.h"
+#include <QtCore/QRunnable>
+#include <QtQuick/QQuickWindow>
+
+#include <Metal/Metal.h>
+
+class SquircleRenderer : public QObject
+{
+ Q_OBJECT
+public:
+ SquircleRenderer();
+ ~SquircleRenderer();
+
+ void setT(qreal t) { m_t = t; }
+ void setViewportSize(const QSize &size) { m_viewportSize = size; }
+ void setWindow(QQuickWindow *window) { m_window = window; }
+
+public slots:
+ void frameStart();
+ void mainPassRecordingStart();
+
+private:
+ enum Stage {
+ VertexStage,
+ FragmentStage
+ };
+ void prepareShader(Stage stage);
+ using FuncAndLib = QPair<id<MTLFunction>, id<MTLLibrary> >;
+ FuncAndLib compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint);
+ void init(int framesInFlight);
+
+ QSize m_viewportSize;
+ qreal m_t;
+ QQuickWindow *m_window;
+
+ QByteArray m_vert;
+ QByteArray m_vertEntryPoint;
+ QByteArray m_frag;
+ QByteArray m_fragEntryPoint;
+
+ bool m_initialized = false;
+ id<MTLDevice> m_device;
+ id<MTLBuffer> m_vbuf;
+ id<MTLBuffer> m_ubuf[3];
+ FuncAndLib m_vs;
+ FuncAndLib m_fs;
+ id<MTLRenderPipelineState> m_pipeline;
+};
+
+MetalSquircle::MetalSquircle()
+ : m_t(0)
+ , m_renderer(nullptr)
+{
+ connect(this, &QQuickItem::windowChanged, this, &MetalSquircle::handleWindowChanged);
+}
+
+void MetalSquircle::setT(qreal t)
+{
+ if (t == m_t)
+ return;
+ m_t = t;
+ emit tChanged();
+ if (window())
+ window()->update();
+}
+
+void MetalSquircle::handleWindowChanged(QQuickWindow *win)
+{
+ if (win) {
+ connect(win, &QQuickWindow::beforeSynchronizing, this, &MetalSquircle::sync, Qt::DirectConnection);
+ connect(win, &QQuickWindow::sceneGraphInvalidated, this, &MetalSquircle::cleanup, Qt::DirectConnection);
+
+ // Ensure we start with cleared to black. The squircle's blend mode relies on this.
+ win->setColor(Qt::black);
+ }
+}
+
+SquircleRenderer::SquircleRenderer()
+ : m_t(0)
+{
+ m_vbuf = nil;
+
+ for (int i = 0; i < 3; ++i)
+ m_ubuf[i] = nil;
+
+ m_vs.first = nil;
+ m_vs.second = nil;
+
+ m_fs.first = nil;
+ m_fs.second = nil;
+}
+
+// The safe way to release custom graphics resources is to both connect to
+// sceneGraphInvalidated() and implement releaseResources(). To support
+// threaded render loops the latter performs the SquircleRenderer destruction
+// via scheduleRenderJob(). Note that the MetalSquircle may be gone by the time
+// the QRunnable is invoked.
+
+void MetalSquircle::cleanup()
+{
+ delete m_renderer;
+ m_renderer = nullptr;
+}
+
+class CleanupJob : public QRunnable
+{
+public:
+ CleanupJob(SquircleRenderer *renderer) : m_renderer(renderer) { }
+ void run() override { delete m_renderer; }
+private:
+ SquircleRenderer *m_renderer;
+};
+
+void MetalSquircle::releaseResources()
+{
+ window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage);
+ m_renderer = nullptr;
+}
+
+SquircleRenderer::~SquircleRenderer()
+{
+ qDebug("cleanup");
+
+ [m_vbuf release];
+ for (int i = 0; i < 3; ++i)
+ [m_ubuf[i] release];
+
+ [m_vs.first release];
+ [m_vs.second release];
+
+ [m_fs.first release];
+ [m_fs.second release];
+}
+
+void MetalSquircle::sync()
+{
+ if (!m_renderer) {
+ m_renderer = new SquircleRenderer;
+ connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::frameStart, Qt::DirectConnection);
+ connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::mainPassRecordingStart, Qt::DirectConnection);
+ }
+ m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
+ m_renderer->setT(m_t);
+ m_renderer->setWindow(window());
+}
+
+void SquircleRenderer::frameStart()
+{
+ QSGRendererInterface *rif = m_window->rendererInterface();
+
+ // We are not prepared for anything other than running with the RHI and its Metal backend.
+ Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::MetalRhi);
+
+ m_device = (id<MTLDevice>) rif->getResource(m_window, QSGRendererInterface::DeviceResource);
+ Q_ASSERT(m_device);
+
+ if (m_vert.isEmpty())
+ prepareShader(VertexStage);
+ if (m_frag.isEmpty())
+ prepareShader(FragmentStage);
+
+ if (!m_initialized)
+ init(m_window->graphicsStateInfo()->framesInFlight);
+}
+
+static const float vertices[] = {
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ 1, 1
+};
+
+const int UBUF_SIZE = 4;
+
+void SquircleRenderer::mainPassRecordingStart()
+{
+ // This example demonstrates the simple case: prepending some commands to
+ // the scenegraph's main renderpass. It does not create its own passes,
+ // rendertargets, etc. so no synchronization is needed.
+
+ const QQuickWindow::GraphicsStateInfo *stateInfo = m_window->graphicsStateInfo();
+
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>) rif->getResource(
+ m_window, QSGRendererInterface::CommandEncoderResource);
+ Q_ASSERT(encoder);
+
+ m_window->beginExternalCommands();
+
+ void *p = [m_ubuf[stateInfo->currentFrameSlot] contents];
+ float t = m_t;
+ memcpy(p, &t, 4);
+
+ MTLViewport vp;
+ vp.originX = 0;
+ vp.originY = 0;
+ vp.width = m_viewportSize.width();
+ vp.height = m_viewportSize.height();
+ vp.znear = 0;
+ vp.zfar = 1;
+ [encoder setViewport: vp];
+
+ [encoder setFragmentBuffer: m_ubuf[stateInfo->currentFrameSlot] offset: 0 atIndex: 0];
+ [encoder setVertexBuffer: m_vbuf offset: 0 atIndex: 1];
+ [encoder setRenderPipelineState: m_pipeline];
+ [encoder drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: 4 instanceCount: 1 baseInstance: 0];
+
+ m_window->endExternalCommands();
+}
+
+void SquircleRenderer::prepareShader(Stage stage)
+{
+ QString filename;
+ if (stage == VertexStage) {
+ filename = QLatin1String(":/scenegraph/metalunderqml/squircle.vert");
+ } else {
+ Q_ASSERT(stage == FragmentStage);
+ filename = QLatin1String(":/scenegraph/metalunderqml/squircle.frag");
+ }
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly))
+ qFatal("Failed to read shader %s", qPrintable(filename));
+
+ const QByteArray contents = f.readAll();
+
+ if (stage == VertexStage) {
+ m_vert = contents;
+ Q_ASSERT(!m_vert.isEmpty());
+ m_vertEntryPoint = QByteArrayLiteral("main0");
+ } else {
+ m_frag = contents;
+ Q_ASSERT(!m_frag.isEmpty());
+ m_fragEntryPoint = QByteArrayLiteral("main0");
+ }
+}
+
+SquircleRenderer::FuncAndLib SquircleRenderer::compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint)
+{
+ FuncAndLib fl;
+
+ NSString *srcstr = [NSString stringWithUTF8String: src.constData()];
+ MTLCompileOptions *opts = [[MTLCompileOptions alloc] init];
+ opts.languageVersion = MTLLanguageVersion1_2;
+ NSError *err = nil;
+ fl.second = [m_device newLibraryWithSource: srcstr options: opts error: &err];
+ [opts release];
+ // srcstr is autoreleased
+
+ if (err) {
+ const QString msg = QString::fromNSString(err.localizedDescription);
+ qFatal("%s", qPrintable(msg));
+ return fl;
+ }
+
+ NSString *name = [NSString stringWithUTF8String: entryPoint.constData()];
+ fl.first = [fl.second newFunctionWithName: name];
+ [name release];
+
+ return fl;
+}
+
+void SquircleRenderer::init(int framesInFlight)
+{
+ qDebug("init");
+
+ Q_ASSERT(framesInFlight <= 3);
+ m_initialized = true;
+
+ m_vbuf = [m_device newBufferWithLength: sizeof(vertices) options: MTLResourceStorageModeShared];
+ void *p = [m_vbuf contents];
+ memcpy(p, vertices, sizeof(vertices));
+
+ for (int i = 0; i < framesInFlight; ++i)
+ m_ubuf[i] = [m_device newBufferWithLength: UBUF_SIZE options: MTLResourceStorageModeShared];
+
+ MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor];
+ inputLayout.attributes[0].format = MTLVertexFormatFloat2;
+ inputLayout.attributes[0].offset = 0;
+ inputLayout.attributes[0].bufferIndex = 1; // ubuf is 0, vbuf is 1
+ inputLayout.layouts[1].stride = 2 * sizeof(float);
+
+ MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init];
+ rpDesc.vertexDescriptor = inputLayout;
+
+ m_vs = compileShaderFromSource(m_vert, m_vertEntryPoint);
+ rpDesc.vertexFunction = m_vs.first;
+ m_fs = compileShaderFromSource(m_frag, m_fragEntryPoint);
+ rpDesc.fragmentFunction = m_fs.first;
+
+ rpDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
+ rpDesc.colorAttachments[0].blendingEnabled = true;
+ rpDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
+ rpDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha;
+ rpDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne;
+ rpDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne;
+
+ if (m_device.depth24Stencil8PixelFormatSupported) {
+ rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8;
+ rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8;
+ } else {
+ rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
+ rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
+ }
+
+ NSError *err = nil;
+ m_pipeline = [m_device newRenderPipelineStateWithDescriptor: rpDesc error: &err];
+ if (!m_pipeline) {
+ const QString msg = QString::fromNSString(err.localizedDescription);
+ qFatal("Failed to create render pipeline state: %s", qPrintable(msg));
+ }
+ [rpDesc release];
+}
+
+#include "metalsquircle.moc"
diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
new file mode 100644
index 0000000000..9b27638a6d
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro
@@ -0,0 +1,10 @@
+QT += qml quick
+
+HEADERS += metalsquircle.h
+SOURCES += metalsquircle.mm main.cpp
+RESOURCES += metalunderqml.qrc
+
+LIBS += -framework Metal -framework AppKit
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/metalunderqml
+INSTALLS += target
diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.qrc b/examples/quick/scenegraph/metalunderqml/metalunderqml.qrc
new file mode 100644
index 0000000000..7172f1fcb7
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/scenegraph/metalunderqml">
+ <file>main.qml</file>
+ <file>squircle.vert</file>
+ <file>squircle.frag</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/scenegraph/metalunderqml/squircle.frag b/examples/quick/scenegraph/metalunderqml/squircle.frag
new file mode 100644
index 0000000000..15f34624fe
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/squircle.frag
@@ -0,0 +1,29 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct buf
+{
+ float t;
+};
+
+struct main0_out
+{
+ float4 fragColor [[color(0)]];
+};
+
+struct main0_in
+{
+ float2 coords [[user(locn0)]];
+};
+
+fragment main0_out main0(main0_in in [[stage_in]], constant buf& ubuf [[buffer(0)]])
+{
+ main0_out out = {};
+ float i = 1.0 - (pow(abs(in.coords.x), 4.0) + pow(abs(in.coords.y), 4.0));
+ i = smoothstep(ubuf.t - 0.800000011920928955078125, ubuf.t + 0.800000011920928955078125, i);
+ i = floor(i * 20.0) / 20.0;
+ out.fragColor = float4((in.coords * 0.5) + float2(0.5), i, i);
+ return out;
+}
diff --git a/examples/quick/scenegraph/metalunderqml/squircle.vert b/examples/quick/scenegraph/metalunderqml/squircle.vert
new file mode 100644
index 0000000000..a88c59f541
--- /dev/null
+++ b/examples/quick/scenegraph/metalunderqml/squircle.vert
@@ -0,0 +1,23 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct main0_out
+{
+ float2 coords [[user(locn0)]];
+ float4 gl_Position [[position]];
+};
+
+struct main0_in
+{
+ float4 vertices [[attribute(0)]];
+};
+
+vertex main0_out main0(main0_in in [[stage_in]])
+{
+ main0_out out = {};
+ out.gl_Position = in.vertices;
+ out.coords = in.vertices.xy;
+ return out;
+}
diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
index 3d4f4443e9..69a9d2ce4b 100644
--- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
+++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc
@@ -94,17 +94,18 @@
\snippet scenegraph/openglunderqml/squircle.cpp 3
- The default behavior of the scene graph is to clear the
- framebuffer before rendering. Since we render before the scene
- graph, we need to turn this clearing off. This means that we need
- to clear ourselves in the \c paint() function.
+ The default behavior of the scene graph is to clear the framebuffer before
+ rendering. This is fine since we will insert our own rendering code after
+ this clear is enqueued. Make sure however that we clear to the desired
+ color (black).
\snippet scenegraph/openglunderqml/squircle.cpp 9
- We use the \c sync() function to initialize the renderer and to
- copy the state in our item into the renderer. When the renderer is
- created, we also connect the \l QQuickWindow::beforeRendering() to
- the renderer's \c paint() slot.
+ We use the \c sync() function to initialize the renderer and to copy the
+ state in our item into the renderer. When the renderer is created, we also
+ connect the \l QQuickWindow::beforeRendering() and \l
+ QQuickWindow::beforeRenderPassRecording() to the renderer's \c init() and
+ \c paint() slots.
\note The \l QQuickWindow::beforeSynchronizing() signal is emitted
on the rendering thread while the GUI thread is blocked, so it is
@@ -112,8 +113,11 @@
\snippet scenegraph/openglunderqml/squircle.cpp 6
- In the \c cleanup() function we delete the renderer which in turn
- cleans up its own resources.
+ In the \c cleanup() function we delete the renderer which in turn cleans up
+ its own resources. This is complemented by reimplementing \l
+ QQuickWindow::releaseResources() since just connecting to the
+ sceneGraphInvalidated() signal is not sufficient on its own to handle all
+ cases.
\snippet scenegraph/openglunderqml/squircle.cpp 8
@@ -124,22 +128,13 @@
\snippet scenegraph/openglunderqml/squircle.cpp 4
- In the SquircleRenderer's \c paint() function we start by
- initializing the shader program. By initializing the shader
- program here, we make sure that the OpenGL context is bound and
- that we are on the correct thread.
+ In the SquircleRenderer's \c init() function we start by initializing the
+ shader program if not yet done. The OpenGL context is current on the thread
+ when the slot is invoked.
\snippet scenegraph/openglunderqml/squircle.cpp 5
- We use the shader program to draw the squircle. At the end of the
- \c paint function we release the program and disable the
- attributes we used so that the OpenGL context is in a "clean"
- state for the scene graph to pick it up.
-
- \note If tracking the changes in the OpenGL context's state is not
- feasible, one can use the function \l
- QQuickWindow::resetOpenGLState() which will reset all state that
- the scene graph relies on.
+ We use the shader program to draw the squircle in \c paint().
\snippet scenegraph/openglunderqml/main.cpp 1
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp
index d6f6b327f2..828857fe24 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.cpp
+++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp
@@ -53,6 +53,7 @@
#include <QtQuick/qquickwindow.h>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
+#include <QtCore/QRunnable>
//! [7]
Squircle::Squircle()
@@ -82,10 +83,9 @@ void Squircle::handleWindowChanged(QQuickWindow *win)
connect(win, &QQuickWindow::beforeSynchronizing, this, &Squircle::sync, Qt::DirectConnection);
connect(win, &QQuickWindow::sceneGraphInvalidated, this, &Squircle::cleanup, Qt::DirectConnection);
//! [1]
- // If we allow QML to do the clearing, they would clear what we paint
- // and nothing would show.
//! [3]
- win->setClearBeforeRendering(false);
+ // Ensure we start with cleared to black. The squircle's blend mode relies on this.
+ win->setColor(Qt::black);
}
}
//! [3]
@@ -93,10 +93,23 @@ void Squircle::handleWindowChanged(QQuickWindow *win)
//! [6]
void Squircle::cleanup()
{
- if (m_renderer) {
- delete m_renderer;
- m_renderer = nullptr;
- }
+ delete m_renderer;
+ m_renderer = nullptr;
+}
+
+class CleanupJob : public QRunnable
+{
+public:
+ CleanupJob(SquircleRenderer *renderer) : m_renderer(renderer) { }
+ void run() override { delete m_renderer; }
+private:
+ SquircleRenderer *m_renderer;
+};
+
+void Squircle::releaseResources()
+{
+ window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage);
+ m_renderer = nullptr;
}
SquircleRenderer::~SquircleRenderer()
@@ -110,7 +123,8 @@ void Squircle::sync()
{
if (!m_renderer) {
m_renderer = new SquircleRenderer();
- connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection);
+ connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::init, Qt::DirectConnection);
+ connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection);
}
m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
m_renderer->setT(m_t);
@@ -119,9 +133,12 @@ void Squircle::sync()
//! [9]
//! [4]
-void SquircleRenderer::paint()
+void SquircleRenderer::init()
{
if (!m_program) {
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL || rif->graphicsApi() == QSGRendererInterface::OpenGLRhi);
+
initializeOpenGLFunctions();
m_program = new QOpenGLShaderProgram();
@@ -146,7 +163,15 @@ void SquircleRenderer::paint()
m_program->link();
}
+}
+
//! [4] //! [5]
+void SquircleRenderer::paint()
+{
+ // Play nice with the RHI. Not strictly needed when the scenegraph uses
+ // OpenGL directly.
+ m_window->beginExternalCommands();
+
m_program->bind();
m_program->enableAttributeArray(0);
@@ -157,6 +182,11 @@ void SquircleRenderer::paint()
-1, 1,
1, 1
};
+
+ // This example relies on (deprecated) client-side pointers for the vertex
+ // input. Therefore, we have to make sure no vertex buffer is bound.
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
m_program->setAttributeArray(0, GL_FLOAT, values, 2);
m_program->setUniformValue("t", (float) m_t);
@@ -164,9 +194,6 @@ void SquircleRenderer::paint()
glDisable(GL_DEPTH_TEST);
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT);
-
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
@@ -178,5 +205,7 @@ void SquircleRenderer::paint()
// Not strictly needed for this example, but generally useful for when
// mixing with raw OpenGL.
m_window->resetOpenGLState();
+
+ m_window->endExternalCommands();
}
//! [5]
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h
index 652e679f81..1b9995bc1e 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.h
+++ b/examples/quick/scenegraph/openglunderqml/squircle.h
@@ -70,6 +70,7 @@ public:
void setWindow(QQuickWindow *window) { m_window = window; }
public slots:
+ void init();
void paint();
private:
@@ -103,6 +104,8 @@ private slots:
void handleWindowChanged(QQuickWindow *win);
private:
+ void releaseResources() override;
+
qreal m_t;
SquircleRenderer *m_renderer;
};
diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro
index 2efeb5ed83..ac368c79a5 100644
--- a/examples/quick/scenegraph/scenegraph.pro
+++ b/examples/quick/scenegraph/scenegraph.pro
@@ -16,5 +16,13 @@ SUBDIRS += \
rendernode \
threadedanimation
+macos {
+ SUBDIRS += metalunderqml
+}
+
+win32 {
+ SUBDIRS += d3d11underqml
+}
+
EXAMPLE_FILES += \
shared
diff --git a/examples/quick/scenegraph/shared/squircle_rhi.frag b/examples/quick/scenegraph/shared/squircle_rhi.frag
new file mode 100644
index 0000000000..8da62b93e6
--- /dev/null
+++ b/examples/quick/scenegraph/shared/squircle_rhi.frag
@@ -0,0 +1,16 @@
+#version 440
+
+layout(location = 0) in vec2 coords;
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ float t;
+} ubuf;
+
+void main()
+{
+ float i = 1. - (pow(abs(coords.x), 4.) + pow(abs(coords.y), 4.));
+ i = smoothstep(ubuf.t - 0.8, ubuf.t + 0.8, i);
+ i = floor(i * 20.) / 20.;
+ fragColor = vec4(coords * .5 + .5, i, i);
+}
diff --git a/examples/quick/scenegraph/shared/squircle_rhi.vert b/examples/quick/scenegraph/shared/squircle_rhi.vert
new file mode 100644
index 0000000000..b57dfdfe10
--- /dev/null
+++ b/examples/quick/scenegraph/shared/squircle_rhi.vert
@@ -0,0 +1,13 @@
+#version 440
+
+layout(location = 0) in vec4 vertices;
+
+layout(location = 0) out vec2 coords;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main()
+{
+ gl_Position = vertices;
+ coords = vertices.xy;
+}
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/blur.frag b/examples/quick/shadereffects/content/shaders/+qsb/blur.frag
new file mode 100644
index 0000000000..1c79359297
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+qsb/blur.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag b/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag
new file mode 100644
index 0000000000..45c5301f31
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/genie.vert b/examples/quick/shadereffects/content/shaders/+qsb/genie.vert
new file mode 100644
index 0000000000..dd94129cf7
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+qsb/genie.vert
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/outline.frag b/examples/quick/shadereffects/content/shaders/+qsb/outline.frag
new file mode 100644
index 0000000000..470e2bd6e6
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+qsb/outline.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag b/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag
new file mode 100644
index 0000000000..128af21daa
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag b/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag
new file mode 100644
index 0000000000..9b27ae87cb
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/rhi/blur.frag b/examples/quick/shadereffects/content/shaders/rhi/blur.frag
new file mode 100644
index 0000000000..0c914d4244
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/rhi/blur.frag
@@ -0,0 +1,21 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ vec2 delta;
+} ubuf;
+
+void main()
+{
+ fragColor =(0.0538 * texture(source, qt_TexCoord0 - 3.182 * ubuf.delta)
+ + 0.3229 * texture(source, qt_TexCoord0 - 1.364 * ubuf.delta)
+ + 0.2466 * texture(source, qt_TexCoord0)
+ + 0.3229 * texture(source, qt_TexCoord0 + 1.364 * ubuf.delta)
+ + 0.0538 * texture(source, qt_TexCoord0 + 3.182 * ubuf.delta)) * ubuf.qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/rhi/colorize.frag b/examples/quick/shadereffects/content/shaders/rhi/colorize.frag
new file mode 100644
index 0000000000..bc8067cc8c
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/rhi/colorize.frag
@@ -0,0 +1,20 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ vec4 tint;
+} ubuf;
+
+void main()
+{
+ vec4 c = texture(source, qt_TexCoord0);
+ float lo = min(min(c.x, c.y), c.z);
+ float hi = max(max(c.x, c.y), c.z);
+ fragColor = ubuf.qt_Opacity * vec4(mix(vec3(lo), vec3(hi), ubuf.tint.xyz), c.w);
+}
diff --git a/examples/quick/shadereffects/content/shaders/rhi/compile.bat b/examples/quick/shadereffects/content/shaders/rhi/compile.bat
new file mode 100755
index 0000000000..93dfb7b2a9
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/rhi/compile.bat
@@ -0,0 +1,56 @@
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Copyright (C) 2019 The Qt Company Ltd.
+:: Contact: https://www.qt.io/licensing/
+::
+:: This file is part of the examples 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$
+::
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/blur.frag blur.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/colorize.frag colorize.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/outline.frag outline.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/shadow.frag shadow.frag
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/wobble.frag wobble.frag
+qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/genie.vert genie.vert
diff --git a/examples/quick/shadereffects/content/shaders/rhi/genie.vert b/examples/quick/shadereffects/content/shaders/rhi/genie.vert
new file mode 100644
index 0000000000..2cb1e71046
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/rhi/genie.vert
@@ -0,0 +1,29 @@
+#version 440
+
+layout(location = 0) in vec4 qt_Vertex;
+layout(location = 1) in vec2 qt_MultiTexCoord0;
+
+layout(location = 0) out vec2 qt_TexCoord0;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ float bend;
+ float minimize;
+ float side;
+ float width;
+ float height;
+} ubuf;
+
+out gl_PerVertex { vec4 gl_Position; };
+
+void main()
+{
+ qt_TexCoord0 = qt_MultiTexCoord0;
+ vec4 pos = qt_Vertex;
+ pos.y = mix(qt_Vertex.y, ubuf.height, ubuf.minimize);
+ float t = pos.y / ubuf.height;
+ t = (3. - 2. * t) * t * t;
+ pos.x = mix(qt_Vertex.x, ubuf.side * ubuf.width, t * ubuf.bend);
+ gl_Position = ubuf.qt_Matrix * pos;
+}
diff --git a/examples/quick/shadereffects/content/shaders/rhi/outline.frag b/examples/quick/shadereffects/content/shaders/rhi/outline.frag
new file mode 100644
index 0000000000..26df69c5fe
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/rhi/outline.frag
@@ -0,0 +1,24 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ vec2 delta;
+} ubuf;
+
+void main()
+{
+ vec4 tl = texture(source, qt_TexCoord0 - ubuf.delta);
+ vec4 tr = texture(source, qt_TexCoord0 + vec2(ubuf.delta.x, -ubuf.delta.y));
+ vec4 bl = texture(source, qt_TexCoord0 - vec2(ubuf.delta.x, -ubuf.delta.y));
+ vec4 br = texture(source, qt_TexCoord0 + ubuf.delta);
+ vec4 gx = (tl + bl) - (tr + br);
+ vec4 gy = (tl + tr) - (bl + br);
+ fragColor.xyz = vec3(0.);
+ fragColor.w = clamp(dot(sqrt(gx * gx + gy * gy), vec4(1.)), 0., 1.) * ubuf.qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/rhi/shadow.frag b/examples/quick/shadereffects/content/shaders/rhi/shadow.frag
new file mode 100644
index 0000000000..8247517b6d
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/rhi/shadow.frag
@@ -0,0 +1,21 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+layout(binding = 2) uniform sampler2D shadow;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ float darkness;
+ vec2 delta;
+} ubuf;
+
+void main()
+{
+ vec4 fg = texture(source, qt_TexCoord0);
+ vec4 bg = texture(shadow, qt_TexCoord0 + ubuf.delta);
+ fragColor = (fg + vec4(0., 0., 0., ubuf.darkness * bg.a) * (1. - fg.a)) * ubuf.qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/content/shaders/rhi/wobble.frag b/examples/quick/shadereffects/content/shaders/rhi/wobble.frag
new file mode 100644
index 0000000000..a34481c2f2
--- /dev/null
+++ b/examples/quick/shadereffects/content/shaders/rhi/wobble.frag
@@ -0,0 +1,20 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ float amplitude;
+ float frequency;
+ float time;
+} ubuf;
+
+void main()
+{
+ vec2 p = sin(ubuf.time + ubuf.frequency * qt_TexCoord0);
+ fragColor = texture(source, qt_TexCoord0 + ubuf.amplitude * vec2(p.y, -p.x)) * ubuf.qt_Opacity;
+}
diff --git a/examples/quick/shadereffects/doc/src/shadereffects.qdoc b/examples/quick/shadereffects/doc/src/shadereffects.qdoc
index 8cb4024da2..d35989c262 100644
--- a/examples/quick/shadereffects/doc/src/shadereffects.qdoc
+++ b/examples/quick/shadereffects/doc/src/shadereffects.qdoc
@@ -52,10 +52,18 @@
\snippet shadereffects/shadereffects.qml fragment
In order to support multiple graphics APIs, not just OpenGL, the shader
- source is not embedded into QML. Instead, file selectors are used to select
- the correct variant at runtime. Based on the Qt Quick backend in use, Qt
- will automatically select either \c{shaders/wobble.frag} with the GLSL
- source code or \c{shaders/+hlsl/wobble.frag} with the HLSL source code.
+ source is not embedded into QML. When running with the graphics API
+ independent scene graph, the actual file in use is a pre-generated shader
+ pack containing multiple variants of the shader code. The appropriate
+ shader is then chosen by Qt Quick, regardless of running on Vulkan, Metal,
+ Direct 3D, or OpenGL. Qt automatically selects the file under the \c qsb
+ selector, for example \c{shaders/+qsb/wobble.frag}, when present.
+
+ On the traditional code path, which can mean using OpenGL or Direct3D 12,
+ file selectors are used to select the correct variant at runtime. Based on
+ the Qt Quick backend in use, Qt will automatically select either
+ \c{shaders/wobble.frag} with the GLSL source code or
+ \c{shaders/+hlsl/wobble.frag} with the HLSL source code.
\note For simplicity shader source code is used in all variants of the
files. However, with the Direct3D backend of Qt Quick pre-compiled shaders
diff --git a/examples/quick/shadereffects/shadereffects.qrc b/examples/quick/shadereffects/shadereffects.qrc
index e66b98a6df..762ad0d037 100644
--- a/examples/quick/shadereffects/shadereffects.qrc
+++ b/examples/quick/shadereffects/shadereffects.qrc
@@ -6,15 +6,21 @@
<file>content/Slider.qml</file>
<file>content/shaders/wobble.frag</file>
<file>content/shaders/+hlsl/wobble.frag</file>
+ <file>content/shaders/+qsb/wobble.frag</file>
<file>content/shaders/blur.frag</file>
<file>content/shaders/+hlsl/blur.frag</file>
+ <file>content/shaders/+qsb/blur.frag</file>
<file>content/shaders/shadow.frag</file>
<file>content/shaders/+hlsl/shadow.frag</file>
+ <file>content/shaders/+qsb/shadow.frag</file>
<file>content/shaders/outline.frag</file>
<file>content/shaders/+hlsl/outline.frag</file>
+ <file>content/shaders/+qsb/outline.frag</file>
<file>content/shaders/colorize.frag</file>
<file>content/shaders/+hlsl/colorize.frag</file>
+ <file>content/shaders/+qsb/colorize.frag</file>
<file>content/shaders/genie.vert</file>
<file>content/shaders/+hlsl/genie.vert</file>
+ <file>content/shaders/+qsb/genie.vert</file>
</qresource>
</RCC>