aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-02-13 21:31:15 +0100
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-02-19 14:51:37 +0000
commit2d1f8937acf874a37b7ef1d0814ee6dc7912f81b (patch)
tree684f38ebd72bffc9ad484e43e1ecd33721471230
parent3b6ebe6338747b4b24558c9b5f2c9702f4cce1be (diff)
Add the skeleton for a D3D12 backend
Proof of concept. The plan is to proceed slowly with supporting node types one by one, starting with QSGRectangleNode. Opaque rectangles work already, but only non-smooth for now. The renderer is incomplete (no clip/opacity) and is based on simplerenderer on scenegraph playground. Buffer handling is not necessarily optimal yet. Use QT_QUICK_BACKEND=d3d12 to request this backend. Set QT_D3D_DEBUG=1 to enable the D3D debug layer. The render loop handles everything, incl. swap chain setup, handling resizes, etc. This being D3D, there are no further enablers needed from the QtGui or platform plugin side. By default the first hardware adapter is picked. In the absence of that, WARP is tried. The list of adapters is printed at startup, use QT_D3D_ADAPTER_INDEX to force a given card in case there are multiple ones in the system. The goal is not to productize a fast and great renderer, but to pave the way to better future backends for D3D12 and similar graphics APIs. Compiling in the support into Qt Quick is bad since the dependency onto d3d12.dll is not necessarily acceptable, but it's good enough for now, this being a wip branch. Change-Id: Ifbe088e7507223328096b22eec2c73f77bb5680e Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
-rw-r--r--.gitignore4
-rw-r--r--config.tests/d3d12/d3d12.cpp51
-rw-r--r--config.tests/d3d12/d3d12.pro4
-rw-r--r--features/hlsl_bytecode_header.prf10
-rw-r--r--qtdeclarative.pro3
-rw-r--r--src/quick/scenegraph/adaptations/adaptations.pri2
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/d3d12.pri28
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation.cpp71
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation_p.h77
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp95
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h75
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp996
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h226
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h225
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp163
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h133
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp72
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h74
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext.cpp79
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext_p.h80
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp477
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h101
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop.cpp277
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop_p.h109
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri12
-rw-r--r--src/quick/scenegraph/adaptations/d3d12/shaders/vertexcolor.hlsl32
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp17
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.h71
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h3
-rw-r--r--src/quick/scenegraph/qsgcontextplugin.cpp6
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp74
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode_p.h47
-rw-r--r--tests/manual/nodetypes/main.qml87
-rw-r--r--tests/manual/nodetypes/nodetypes.cpp57
-rw-r--r--tests/manual/nodetypes/nodetypes.pro7
-rw-r--r--tests/manual/nodetypes/nodetypes.qrc5
36 files changed, 3778 insertions, 72 deletions
diff --git a/.gitignore b/.gitignore
index e949cddb22..67c40bff90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -282,3 +282,7 @@ src/qml/RegExpJitTables.h
src/qml/udis86_itab.c
src/qml/udis86_itab.h
+# Generated HLSL bytecode headers
+hlsl_vs_*.h
+hlsl_ps_*.h
+hlsl_cs_*.h
diff --git a/config.tests/d3d12/d3d12.cpp b/config.tests/d3d12/d3d12.cpp
new file mode 100644
index 0000000000..0bf90cc457
--- /dev/null
+++ b/config.tests/d3d12/d3d12.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <d3d12.h>
+#include <dxgi1_4.h>
+#include <wrl/client.h>
+
+using namespace Microsoft::WRL;
+
+int main(int, char **)
+{
+ ID3D12Device *dev = 0;
+
+ return 0;
+}
diff --git a/config.tests/d3d12/d3d12.pro b/config.tests/d3d12/d3d12.pro
new file mode 100644
index 0000000000..24c5991a4b
--- /dev/null
+++ b/config.tests/d3d12/d3d12.pro
@@ -0,0 +1,4 @@
+SOURCES = d3d12.cpp
+CONFIG -= qt dylib
+CONFIG += console
+LIBS += -ldxgi -ld3d12
diff --git a/features/hlsl_bytecode_header.prf b/features/hlsl_bytecode_header.prf
new file mode 100644
index 0000000000..0fa27a75d5
--- /dev/null
+++ b/features/hlsl_bytecode_header.prf
@@ -0,0 +1,10 @@
+for (SHADER, HLSL_SHADERS) {
+ INPUT = $$eval($${SHADER}.input)
+ fxc_$${SHADER}.input = $$INPUT
+ fxc_$${SHADER}.commands = fxc.exe /nologo /E $$eval($${SHADER}.entry) /T $$eval($${SHADER}.type) /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
+ fxc_$${SHADER}.output = $$eval($${SHADER}.header)
+ fxc_$${SHADER}.dependency_type = TYPE_C
+ fxc_$${SHADER}.variable_out = HEADERS
+ fxc_$${SHADER}.CONFIG += target_predeps
+ QMAKE_EXTRA_COMPILERS += fxc_$${SHADER}
+}
diff --git a/qtdeclarative.pro b/qtdeclarative.pro
index 0e746c3c65..b4991db4ee 100644
--- a/qtdeclarative.pro
+++ b/qtdeclarative.pro
@@ -1,3 +1,6 @@
+load(configure)
+qtCompileTest(d3d12)
+
CONFIG += tests_need_tools examples_need_tools
load(qt_parts)
diff --git a/src/quick/scenegraph/adaptations/adaptations.pri b/src/quick/scenegraph/adaptations/adaptations.pri
index 3511971cac..850d2a3bbe 100644
--- a/src/quick/scenegraph/adaptations/adaptations.pri
+++ b/src/quick/scenegraph/adaptations/adaptations.pri
@@ -1 +1,3 @@
include(dummy/dummy.pri)
+
+config_d3d12: include(d3d12/d3d12.pri)
diff --git a/src/quick/scenegraph/adaptations/d3d12/d3d12.pri b/src/quick/scenegraph/adaptations/d3d12/d3d12.pri
new file mode 100644
index 0000000000..8123b9d19b
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/d3d12.pri
@@ -0,0 +1,28 @@
+SOURCES += \
+ $$PWD/qsgd3d12adaptation.cpp \
+ $$PWD/qsgd3d12renderloop.cpp \
+ $$PWD/qsgd3d12renderer.cpp \
+ $$PWD/qsgd3d12context.cpp \
+ $$PWD/qsgd3d12rendercontext.cpp \
+ $$PWD/qsgd3d12rectanglenode.cpp \
+ $$PWD/qsgd3d12material.cpp
+
+NO_PCH_SOURCES += \
+ $$PWD/qsgd3d12engine.cpp
+
+HEADERS += \
+ $$PWD/qsgd3d12adaptation_p.h \
+ $$PWD/qsgd3d12renderloop_p.h \
+ $$PWD/qsgd3d12renderer_p.h \
+ $$PWD/qsgd3d12context_p.h \
+ $$PWD/qsgd3d12rendercontext_p.h \
+ $$PWD/qsgd3d12engine_p.h \
+ $$PWD/qsgd3d12engine_p_p.h \
+ $$PWD/qsgd3d12rectanglenode_p.h \
+ $$PWD/qsgd3d12material_p.h
+
+LIBS += -ldxgi -ld3d12
+
+DEFINES += QSG_D3D12
+
+include($$PWD/shaders/shaders.pri)
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation.cpp
new file mode 100644
index 0000000000..826a1cc5cb
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12adaptation_p.h"
+#include "qsgd3d12renderloop_p.h"
+#include "qsgd3d12context_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGD3D12Adaptation::QSGD3D12Adaptation(QObject *parent)
+ : QSGContextPlugin(parent)
+{
+}
+
+QStringList QSGD3D12Adaptation::keys() const
+{
+ return QStringList() << QLatin1String("d3d12");
+}
+
+QSGContext *QSGD3D12Adaptation::create(const QString &) const
+{
+ if (!contextInstance)
+ contextInstance = new QSGD3D12Context;
+
+ return contextInstance;
+}
+
+QSGRenderLoop *QSGD3D12Adaptation::createWindowManager()
+{
+ return new QSGD3D12RenderLoop;
+}
+
+QSGD3D12Context *QSGD3D12Adaptation::contextInstance = nullptr;
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation_p.h
new file mode 100644
index 0000000000..f3f5d5706e
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12adaptation_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12ADAPTATION_P_H
+#define QSGD3D12ADAPTATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgcontextplugin_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12Context;
+class QSGContext;
+class QSGRenderLoop;
+
+class QSGD3D12Adaptation : public QSGContextPlugin
+{
+public:
+ QSGD3D12Adaptation(QObject *parent = 0);
+
+ QStringList keys() const override;
+ QSGContext *create(const QString &key) const override;
+ QSGRenderLoop *createWindowManager() override;
+
+private:
+ static QSGD3D12Context *contextInstance;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12ADAPTATION_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp
new file mode 100644
index 0000000000..b75d6ebb89
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12context_p.h"
+#include "qsgd3d12rendercontext_p.h"
+#include "qsgd3d12rectanglenode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGRenderContext *QSGD3D12Context::createRenderContext()
+{
+ return new QSGD3D12RenderContext(this);
+}
+
+QSGRectangleNode *QSGD3D12Context::createRectangleNode()
+{
+ return new QSGD3D12RectangleNode;
+}
+
+QSGImageNode *QSGD3D12Context::createImageNode()
+{
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+QSGPainterNode *QSGD3D12Context::createPainterNode(QQuickPaintedItem *item)
+{
+ Q_UNUSED(item);
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+QSGGlyphNode *QSGD3D12Context::createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode)
+{
+ Q_UNUSED(rc);
+ Q_UNUSED(preferNativeGlyphNode);
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+QSGNinePatchNode *QSGD3D12Context::createNinePatchNode()
+{
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+QSGLayer *QSGD3D12Context::createLayer(QSGRenderContext *rc)
+{
+ Q_UNUSED(rc);
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+QSurfaceFormat QSGD3D12Context::defaultSurfaceFormat() const
+{
+ return QSGContext::defaultSurfaceFormat();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h
new file mode 100644
index 0000000000..6a092e8606
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12CONTEXT_P_H
+#define QSGD3D12CONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12Context : public QSGContext
+{
+public:
+ QSGD3D12Context(QObject *parent = 0) : QSGContext(parent) { }
+
+ QSGRenderContext *createRenderContext() override;
+ QSGRectangleNode *createRectangleNode() override;
+ QSGImageNode *createImageNode() override;
+ QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override;
+ QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override;
+ QSGNinePatchNode *createNinePatchNode() override;
+ QSGLayer *createLayer(QSGRenderContext *rc) override;
+ QSurfaceFormat defaultSurfaceFormat() const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12CONTEXT_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
new file mode 100644
index 0000000000..a623956e72
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp
@@ -0,0 +1,996 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12engine_p.h"
+#include "qsgd3d12engine_p_p.h"
+#include <QString>
+#include <QColor>
+
+QT_BEGIN_NAMESPACE
+
+// Recommended reading before moving further: https://github.com/Microsoft/DirectXTK/wiki/ComPtr
+// Note esp. operator= vs. Attach and operator& vs. GetAddressOf
+
+static const int MAX_DESCRIPTORS_PER_HEAP = 256;
+
+QSGD3D12DescriptorHandle QSGD3D12DescriptorHeapManager::allocate(D3D12_DESCRIPTOR_HEAP_TYPE type, Flags flags)
+{
+ QSGD3D12DescriptorHandle h;
+ for (Heap &heap : m_heaps) {
+ if (heap.type == type && heap.count < MAX_DESCRIPTORS_PER_HEAP) {
+ h = heap.start;
+ h.cpu.ptr += heap.count * heap.handleSize;
+ if (h.gpu.ptr)
+ h.gpu.ptr += heap.count * heap.handleSize;
+ ++heap.count;
+ return h;
+ }
+ }
+
+ Heap heap;
+ heap.type = type;
+ heap.handleSize = m_handleSizes[type];
+
+ D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
+ heapDesc.NumDescriptors = MAX_DESCRIPTORS_PER_HEAP;
+ heapDesc.Type = type;
+ if (flags & ShaderVisible)
+ heapDesc.Flags |= D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+
+ HRESULT hr = m_device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&heap.heap));
+ if (FAILED(hr)) {
+ qWarning("Failed to create heap with type 0x%x: %x", type, hr);
+ return h;
+ }
+
+ heap.start.cpu = heap.heap->GetCPUDescriptorHandleForHeapStart();
+ qDebug("type %x start is %llu", type, heap.start.cpu.ptr);
+ if (flags & ShaderVisible)
+ heap.start.gpu = heap.heap->GetGPUDescriptorHandleForHeapStart();
+
+ heap.count = 1;
+ h = heap.start;
+ m_heaps.append(heap);
+
+ return h;
+}
+
+void QSGD3D12DescriptorHeapManager::initialize(ID3D12Device *device)
+{
+ m_device = device;
+
+ for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
+ m_handleSizes[i] = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE(i));
+}
+
+void QSGD3D12DescriptorHeapManager::releaseResources()
+{
+ for (Heap &heap : m_heaps)
+ heap.heap = nullptr;
+
+ m_heaps.clear();
+
+ m_device = nullptr;
+}
+
+// One device per process, one everything else (engine) per window.
+Q_GLOBAL_STATIC(QSGD3D12DeviceManager, deviceManager)
+
+static void getHardwareAdapter(IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapter)
+{
+ const D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_0;
+ ComPtr<IDXGIAdapter1> adapter;
+ DXGI_ADAPTER_DESC1 desc;
+
+ for (int adapterIndex = 0; factory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
+ DXGI_ADAPTER_DESC1 desc;
+ adapter->GetDesc1(&desc);
+ const QString name = QString::fromUtf16((char16_t *) desc.Description);
+ qDebug("Adapter %d: '%s' (flags 0x%x)", adapterIndex, qPrintable(name), desc.Flags);
+ }
+
+ if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX")) {
+ const int adapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
+ if (SUCCEEDED(factory->EnumAdapters1(adapterIndex, &adapter))
+ && SUCCEEDED(D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr))) {
+ adapter->GetDesc1(&desc);
+ const QString name = QString::fromUtf16((char16_t *) desc.Description);
+ qDebug("Using requested adapter '%s'", qPrintable(name));
+ *outAdapter = adapter.Detach();
+ return;
+ }
+ }
+
+ for (int adapterIndex = 0; factory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
+ adapter->GetDesc1(&desc);
+ if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
+ continue;
+
+ if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr))) {
+ const QString name = QString::fromUtf16((char16_t *) desc.Description);
+ qDebug("Using adapter '%s'", qPrintable(name));
+ break;
+ }
+ }
+
+ *outAdapter = adapter.Detach();
+}
+
+ID3D12Device *QSGD3D12DeviceManager::ref()
+{
+ ensureCreated();
+ m_ref.ref();
+ return m_device.Get();
+}
+
+void QSGD3D12DeviceManager::unref()
+{
+ if (!m_ref.deref()) {
+ qDebug("destroying d3d device");
+ m_device = nullptr;
+ m_factory = nullptr;
+ }
+}
+
+void QSGD3D12DeviceManager::deviceLossDetected()
+{
+ for (DeviceLossObserver *observer : qAsConst(m_observers))
+ observer->deviceLost();
+
+ // Nothing else to do here. All windows are expected to release their
+ // resources and call unref() in response immediately.
+}
+
+IDXGIFactory4 *QSGD3D12DeviceManager::dxgi()
+{
+ ensureCreated();
+ return m_factory.Get();
+}
+
+void QSGD3D12DeviceManager::ensureCreated()
+{
+ if (m_device)
+ return;
+
+ HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&m_factory));
+ if (FAILED(hr)) {
+ qWarning("Failed to create DXGI: 0x%x", hr);
+ return;
+ }
+
+ ComPtr<IDXGIAdapter1> adapter;
+ getHardwareAdapter(m_factory.Get(), &adapter);
+
+ bool warp = true;
+ if (adapter) {
+ HRESULT hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
+ if (SUCCEEDED(hr))
+ warp = false;
+ else
+ qWarning("Failed to create device: 0x%x", hr);
+ }
+
+ if (warp) {
+ qDebug("Using WARP");
+ ComPtr<IDXGIAdapter> warpAdapter;
+ m_factory->EnumWarpAdapter(IID_PPV_ARGS(&warpAdapter));
+ HRESULT hr = D3D12CreateDevice(warpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
+ if (FAILED(hr)) {
+ qWarning("Failed to create WARP device: 0x%x", hr);
+ return;
+ }
+ }
+}
+
+void QSGD3D12DeviceManager::registerDeviceLossObserver(DeviceLossObserver *observer)
+{
+ if (!m_observers.contains(observer))
+ m_observers.append(observer);
+}
+
+QSGD3D12Engine::QSGD3D12Engine()
+{
+ d = new QSGD3D12EnginePrivate;
+}
+
+QSGD3D12Engine::~QSGD3D12Engine()
+{
+ d->releaseResources();
+ delete d;
+}
+
+bool QSGD3D12Engine::attachToWindow(QWindow *window)
+{
+ if (d->isInitialized()) {
+ qWarning("QSGD3D12Engine: Cannot attach active engine to window");
+ return false;
+ }
+
+ d->initialize(window);
+ return d->isInitialized();
+}
+
+void QSGD3D12Engine::releaseResources()
+{
+ d->releaseResources();
+}
+
+void QSGD3D12Engine::resize()
+{
+ d->resize();
+}
+
+void QSGD3D12Engine::beginFrame()
+{
+ d->beginFrame();
+}
+
+void QSGD3D12Engine::endFrame()
+{
+ d->endFrame();
+}
+
+void QSGD3D12Engine::setPipelineState(const QSGD3D12PipelineState &pipelineState)
+{
+ d->setPipelineState(pipelineState);
+}
+
+void QSGD3D12Engine::setVertexBuffer(const quint8 *data, int size)
+{
+ d->setVertexBuffer(data, size);
+}
+
+void QSGD3D12Engine::setIndexBuffer(const quint8 *data, int size)
+{
+ d->setIndexBuffer(data, size);
+}
+
+void QSGD3D12Engine::setConstantBuffer(const quint8 *data, int size)
+{
+ d->setConstantBuffer(data, size);
+}
+
+void QSGD3D12Engine::queueViewport(const QRect &rect)
+{
+ d->queueViewport(rect);
+}
+
+void QSGD3D12Engine::queueScissor(const QRect &rect)
+{
+ d->queueScissor(rect);
+}
+
+void QSGD3D12Engine::queueSetRenderTarget()
+{
+ d->queueSetRenderTarget();
+}
+
+void QSGD3D12Engine::queueClearRenderTarget(const QColor &color)
+{
+ d->queueClearRenderTarget(color);
+}
+
+void QSGD3D12Engine::queueClearDepthStencil(float depthValue, quint8 stencilValue)
+{
+ d->queueClearDepthStencil(depthValue, stencilValue);
+}
+
+void QSGD3D12Engine::queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
+ int cboOffset,
+ int startIndexIndex, QSGD3D12Format indexFormat)
+{
+ d->queueDraw(mode, count, vboOffset, vboStride, cboOffset, startIndexIndex, indexFormat);
+}
+
+void QSGD3D12Engine::present()
+{
+ d->present();
+}
+
+void QSGD3D12Engine::waitGPU()
+{
+ d->waitGPU();
+}
+
+quint32 QSGD3D12Engine::alignedConstantBufferSize(quint32 size)
+{
+ return (size + D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1) & ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1);
+}
+
+void QSGD3D12EnginePrivate::releaseResources()
+{
+ if (!initialized)
+ return;
+
+ bundleAllocator = nullptr;
+ commandAllocator = nullptr;
+
+ depthStencil = nullptr;
+ for (int i = 0; i < swapChainBufferCount; ++i)
+ renderTargets[i] = nullptr;
+
+ vertexBuffer = nullptr;
+ indexBuffer = nullptr;
+ constantBuffer = nullptr;
+
+ for (ComPtr<ID3D12PipelineState> &ps : m_psoCache)
+ ps = nullptr;
+ m_psoCache.clear();
+ m_rootSig = nullptr;
+
+ descHeapManager.releaseResources();
+
+ commandQueue = nullptr;
+ swapChain = nullptr;
+
+ delete presentFence;
+
+ deviceManager()->unref();
+
+ initialized = false;
+
+ // 'window' must be kept, may just be a device loss
+}
+
+void QSGD3D12EnginePrivate::initialize(QWindow *w)
+{
+ if (initialized)
+ return;
+
+ window = w;
+
+ HWND hwnd = reinterpret_cast<HWND>(window->winId());
+
+ if (qEnvironmentVariableIntValue("QT_D3D_DEBUG") != 0) {
+ qDebug("Enabling debug layer");
+ ComPtr<ID3D12Debug> debugController;
+ if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
+ debugController->EnableDebugLayer();
+ }
+
+ QSGD3D12DeviceManager *dev = deviceManager();
+ device = dev->ref();
+ dev->registerDeviceLossObserver(this);
+
+ D3D12_COMMAND_QUEUE_DESC queueDesc = {};
+ queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+
+ if (FAILED(device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)))) {
+ qWarning("Failed to create command queue");
+ return;
+ }
+
+ DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
+ swapChainDesc.BufferCount = swapChainBufferCount;
+ swapChainDesc.BufferDesc.Width = window->width() * window->devicePixelRatio();
+ swapChainDesc.BufferDesc.Height = window->height() * window->devicePixelRatio();
+ swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // D3D12 requires the flip model
+ swapChainDesc.OutputWindow = hwnd;
+ swapChainDesc.SampleDesc.Count = 1; // Flip does not support MSAA so no choice here
+ swapChainDesc.Windowed = TRUE;
+
+ ComPtr<IDXGISwapChain> baseSwapChain;
+ HRESULT hr = dev->dxgi()->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &baseSwapChain);
+ if (FAILED(hr)) {
+ qWarning("Failed to create swap chain: 0x%x", hr);
+ return;
+ }
+ if (FAILED(baseSwapChain.As(&swapChain))) {
+ qWarning("Failed to cast swap chain");
+ return;
+ }
+
+ dev->dxgi()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
+
+ if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator)))) {
+ qWarning("Failed to create command allocator");
+ return;
+ }
+
+ if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_BUNDLE, IID_PPV_ARGS(&bundleAllocator)))) {
+ qWarning("Failed to create command bundle allocator");
+ return;
+ }
+
+ descHeapManager.initialize(device);
+
+ setupRenderTargets();
+
+ if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.Get(),
+ nullptr, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+ // created in recording state, close it for now
+ commandList->Close();
+
+ presentFence = createFence();
+
+ vertexData = StagingBufferRef();
+ indexData = StagingBufferRef();
+ constantData = StagingBufferRef();
+
+ initialized = true;
+}
+
+DXGI_SAMPLE_DESC QSGD3D12EnginePrivate::makeSampleDesc(DXGI_FORMAT format, int samples)
+{
+ DXGI_SAMPLE_DESC sampleDesc;
+ sampleDesc.Count = 1;
+ sampleDesc.Quality = 0;
+
+ if (samples > 1) {
+ D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
+ msaaInfo.Format = format;
+ msaaInfo.SampleCount = samples;
+ if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo, sizeof(msaaInfo)))) {
+ if (msaaInfo.NumQualityLevels > 0) {
+ sampleDesc.Count = samples;
+ sampleDesc.Quality = msaaInfo.NumQualityLevels - 1;
+ } else {
+ qWarning("No quality levels for multisampling?");
+ }
+ } else {
+ qWarning("Failed to query multisample quality levels");
+ }
+ }
+
+ return sampleDesc;
+}
+
+ID3D12Resource *QSGD3D12EnginePrivate::createDepthStencil(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, int samples)
+{
+ D3D12_CLEAR_VALUE depthClearValue = {};
+ depthClearValue.Format = DXGI_FORMAT_D32_FLOAT;
+ depthClearValue.DepthStencil.Depth = 1.0f;
+ depthClearValue.DepthStencil.Stencil = 0;
+
+ D3D12_HEAP_PROPERTIES heapProp = {};
+ heapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
+
+ D3D12_RESOURCE_DESC bufDesc = {};
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+ bufDesc.Width = size.width();
+ bufDesc.Height = size.height();
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_D32_FLOAT;
+ bufDesc.SampleDesc = makeSampleDesc(bufDesc.Format, samples);
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+ bufDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
+
+ ID3D12Resource *resource = nullptr;
+ if (FAILED(device->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_DEPTH_WRITE, &depthClearValue, IID_PPV_ARGS(&resource)))) {
+ qWarning("Failed to create depth-stencil buffer of size %dx%d", size.width(), size.height());
+ return nullptr;
+ }
+
+ D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};
+ depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
+ depthStencilDesc.ViewDimension = bufDesc.SampleDesc.Count <= 1 ? D3D12_DSV_DIMENSION_TEXTURE2D : D3D12_DSV_DIMENSION_TEXTURE2DMS;
+
+ device->CreateDepthStencilView(resource, &depthStencilDesc, viewHandle);
+
+ return resource;
+}
+
+void QSGD3D12EnginePrivate::setupRenderTargets()
+{
+ for (int i = 0; i < swapChainBufferCount; ++i) {
+ if (FAILED(swapChain->GetBuffer(i, IID_PPV_ARGS(&renderTargets[i])))) {
+ qWarning("Failed to get buffer %d from swap chain", i);
+ return;
+ }
+ D3D12_CPU_DESCRIPTOR_HANDLE h = descHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_RTV).cpu;
+ if (i == 0)
+ rtv0 = h;
+ device->CreateRenderTargetView(renderTargets[i].Get(), nullptr, h);
+ }
+
+ dsv = descHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_DSV).cpu;
+ ID3D12Resource *ds = createDepthStencil(dsv, window->size(), 0);
+ if (ds)
+ depthStencil.Attach(ds);
+}
+
+void QSGD3D12EnginePrivate::resize()
+{
+ if (!initialized)
+ return;
+
+ qDebug() << window->size();
+
+ // Clear these, otherwise resizing will fail.
+ depthStencil = nullptr;
+ for (int i = 0; i < swapChainBufferCount; ++i)
+ renderTargets[i] = nullptr;
+
+ HRESULT hr = swapChain->ResizeBuffers(swapChainBufferCount, window->width(), window->height(), DXGI_FORMAT_R8G8B8A8_UNORM, 0);
+ if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
+ deviceManager()->deviceLossDetected();
+ return;
+ } else if (FAILED(hr)) {
+ qWarning("Failed to resize buffers: 0x%x", hr);
+ return;
+ }
+
+ setupRenderTargets();
+}
+
+void QSGD3D12EnginePrivate::deviceLost()
+{
+ qWarning("D3D device lost, will attempt to reinitialize");
+
+ // Release all resources. This is important because otherwise reinitialization may fail.
+ releaseResources();
+
+ // Now in uninitialized state (but 'window' is still valid). Will recreate
+ // all the resources on the next beginFrame().
+}
+
+QSGD3D12Fence *QSGD3D12EnginePrivate::createFence() const
+{
+ QSGD3D12Fence *f = new QSGD3D12Fence;
+ HRESULT hr = device->CreateFence(f->value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&f->fence));
+ if (FAILED(hr)) {
+ qWarning("Failed to create fence: 0x%x", hr);
+ return f;
+ }
+ f->event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ return f;
+}
+
+void QSGD3D12EnginePrivate::waitForGPU(QSGD3D12Fence *f) const
+{
+ const UINT64 newValue = f->value.fetchAndAddAcquire(1) + 1;
+ commandQueue->Signal(f->fence.Get(), newValue);
+ if (f->fence->GetCompletedValue() < newValue) {
+ HRESULT hr = f->fence->SetEventOnCompletion(newValue, f->event);
+ if (FAILED(hr)) {
+ qWarning("SetEventOnCompletion failed: 0x%x", hr);
+ return;
+ }
+ WaitForSingleObject(f->event, INFINITE);
+ }
+}
+
+void QSGD3D12EnginePrivate::transitionResource(ID3D12Resource *resource, ID3D12GraphicsCommandList *commandList,
+ D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after) const
+{
+ D3D12_RESOURCE_BARRIER barrier;
+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ barrier.Transition.pResource = resource;
+ barrier.Transition.StateBefore = before;
+ barrier.Transition.StateAfter = after;
+ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+
+ commandList->ResourceBarrier(1, &barrier);
+}
+
+ID3D12Resource *QSGD3D12EnginePrivate::createBuffer(int size)
+{
+ ID3D12Resource *buf;
+
+ D3D12_HEAP_PROPERTIES uploadHeapProp = {};
+ uploadHeapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc = {};
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Width = size;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+
+ HRESULT hr = device->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&buf));
+ if (FAILED(hr))
+ qWarning("Failed to create buffer resource: 0x%x", hr);
+
+ return buf;
+}
+
+ID3D12Resource *QSGD3D12EnginePrivate::backBufferRT() const
+{
+ return renderTargets[swapChain->GetCurrentBackBufferIndex()].Get();
+}
+
+D3D12_CPU_DESCRIPTOR_HANDLE QSGD3D12EnginePrivate::backBufferRTV() const
+{
+ const int frameIndex = swapChain->GetCurrentBackBufferIndex();
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtv0;
+ rtvHandle.ptr += frameIndex * descHeapManager.handleSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
+ return rtvHandle;
+}
+
+void QSGD3D12EnginePrivate::beginFrame()
+{
+ static int cnt = 0;
+ qDebug() << "***** begin frame" << cnt;
+ ++cnt;
+
+ // The device may have been lost. This is the point to attempt to start again from scratch.
+ if (!initialized && window)
+ initialize(window);
+
+ commandAllocator->Reset();
+ commandList->Reset(commandAllocator.Get(), nullptr);
+
+ transitionResource(backBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+}
+
+void QSGD3D12EnginePrivate::endFrame()
+{
+ qDebug() << "***** end frame";
+
+ transitionResource(backBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+
+ HRESULT hr = commandList->Close();
+ if (FAILED(hr)) {
+ qWarning("Failed to close command list: 0x%x", hr);
+ if (hr == E_INVALIDARG)
+ qWarning("Invalid arguments. Some of the commands in the list is invalid in some way.");
+ }
+
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue->ExecuteCommandLists(_countof(commandLists), commandLists);
+}
+
+void QSGD3D12EnginePrivate::setPipelineState(const QSGD3D12PipelineState &pipelineState)
+{
+ // One single root signature for now. This will obviously need some improvements later on...
+ if (!m_rootSig) {
+ D3D12_ROOT_PARAMETER rootParameter;
+ rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+ rootParameter.Descriptor.ShaderRegister = 0; // b0
+ rootParameter.Descriptor.RegisterSpace = 0;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 1;
+ desc.pParameters = &rootParameter;
+ desc.NumStaticSamplers = 0;
+ desc.pStaticSamplers = nullptr;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ qWarning("Failed to serialize root signature");
+ return;
+ }
+ if (FAILED(device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
+ IID_PPV_ARGS(&m_rootSig)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+ }
+
+ // Unlimited number of cached PSOs for now, may want to change this later.
+ ComPtr<ID3D12PipelineState> pso = m_psoCache[pipelineState];
+
+ if (!pso) {
+ qDebug("NEW PSO");
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+
+ D3D12_INPUT_ELEMENT_DESC inputElements[8];
+ Q_ASSERT(pipelineState.inputElements.count() <= _countof(inputElements));
+ UINT ieIdx = 0;
+ for (const QSGD3D12InputElement &ie : pipelineState.inputElements) {
+ D3D12_INPUT_ELEMENT_DESC ieDesc = {};
+ ieDesc.SemanticName = ie.name;
+ ieDesc.Format = DXGI_FORMAT(ie.format);
+ ieDesc.InputSlot = ie.slot;
+ ieDesc.AlignedByteOffset = ie.offset;
+ ieDesc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
+ qDebug("input [%d]: %s %d 0x%x %d", ieIdx, ie.name, ie.offset, ie.format, ie.slot);
+ inputElements[ieIdx++] = ieDesc;
+ }
+
+ psoDesc.InputLayout = { inputElements, ieIdx };
+
+ psoDesc.pRootSignature = m_rootSig.Get();
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = pipelineState.shaders.vs;
+ vshader.BytecodeLength = pipelineState.shaders.vsSize;
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = pipelineState.shaders.ps;
+ pshader.BytecodeLength = pipelineState.shaders.psSize;
+
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+
+ D3D12_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
+ rastDesc.CullMode = D3D12_CULL_MODE(pipelineState.cullMode);
+ rastDesc.FrontCounterClockwise = pipelineState.frontCCW;
+ rastDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rastDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rastDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rastDesc.DepthClipEnable = TRUE;
+
+ psoDesc.RasterizerState = rastDesc;
+
+ // ### this is wrong
+ const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
+ TRUE, FALSE,
+ D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
+ D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+ D3D12_LOGIC_OP_NOOP,
+ D3D12_COLOR_WRITE_ENABLE_ALL
+ };
+ D3D12_BLEND_DESC blendDesc = {};
+ blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
+
+ psoDesc.BlendState = blendDesc;
+
+ psoDesc.DepthStencilState.DepthEnable = pipelineState.depthEnable;
+ psoDesc.DepthStencilState.DepthWriteMask = pipelineState.depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC(pipelineState.depthFunc);
+ psoDesc.DepthStencilState.StencilEnable = pipelineState.stencilEnable;
+ // ### stencil stuff
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE(pipelineState.topologyType);
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.SampleDesc.Count = 1;
+
+ HRESULT hr = device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pso));
+ if (FAILED(hr)) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+ m_psoCache[pipelineState] = pso;
+ }
+
+ commandList->SetPipelineState(pso.Get());
+
+ commandList->SetGraphicsRootSignature(m_rootSig.Get()); // invalidates bindings
+}
+
+void QSGD3D12EnginePrivate::setVertexBuffer(const quint8 *data, int size)
+{
+ vertexData.p = data;
+ vertexData.size = size;
+ vertexData.changed = true;
+}
+
+void QSGD3D12EnginePrivate::setIndexBuffer(const quint8 *data, int size)
+{
+ indexData.p = data;
+ indexData.size = size;
+ indexData.changed = true;
+}
+
+void QSGD3D12EnginePrivate::setConstantBuffer(const quint8 *data, int size)
+{
+ constantData.p = data;
+ constantData.size = size;
+ constantData.changed = true;
+}
+
+void QSGD3D12EnginePrivate::queueViewport(const QRect &rect)
+{
+ const D3D12_VIEWPORT viewport = { 0, 0, float(rect.width()), float(rect.height()), 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+}
+
+void QSGD3D12EnginePrivate::queueScissor(const QRect &rect)
+{
+ const D3D12_RECT scissorRect = { 0, 0, rect.width() - 1, rect.height() - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+}
+
+void QSGD3D12EnginePrivate::queueSetRenderTarget()
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRTV();
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsv;
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+}
+
+void QSGD3D12EnginePrivate::queueClearRenderTarget(const QColor &color)
+{
+ const float clearColor[] = { float(color.redF()), float(color.blueF()), float(color.greenF()), float(color.alphaF()) };
+ commandList->ClearRenderTargetView(backBufferRTV(), clearColor, 0, nullptr);
+}
+
+void QSGD3D12EnginePrivate::queueClearDepthStencil(float depthValue, quint8 stencilValue)
+{
+ commandList->ClearDepthStencilView(dsv, D3D12_CLEAR_FLAG_DEPTH, depthValue, stencilValue, 0, nullptr);
+}
+
+void QSGD3D12EnginePrivate::queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
+ int cboOffset,
+ int startIndexIndex, QSGD3D12Format indexFormat)
+{
+ // Due to the simplistic way our current renderer works, we can just upload the
+ // entire vertex/index data in case it was rebuilt.
+
+ if (vertexData.changed) {
+ vertexData.changed = false;
+ qDebug("upload vertex");
+ // Only enlarge, never shrink
+ const bool newBufferNeeded = vertexBuffer ? (vertexData.size > vertexBuffer->GetDesc().Width) : true;
+ if (newBufferNeeded) {
+ qDebug("new vertex buffer of size %d", vertexData.size);
+ vertexBuffer.Attach(createBuffer(vertexData.size));
+ }
+ if (!vertexBuffer)
+ return;
+ quint8 *p = nullptr;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed for buffer of size %d", vertexData.size);
+ return;
+ }
+ memcpy(p, vertexData.p, vertexData.size);
+ vertexBuffer->Unmap(0, nullptr);
+ }
+
+ if (indexData.changed) {
+ indexData.changed = false;
+ if (indexData.size > 0) {
+ qDebug("upload index");
+ const bool newBufferNeeded = indexBuffer ? (indexData.size > indexBuffer->GetDesc().Width) : true;
+ if (newBufferNeeded) {
+ qDebug("new index buffer of size %d", indexData.size);
+ indexBuffer.Attach(createBuffer(indexData.size));
+ }
+ if (!indexBuffer)
+ return;
+ quint8 *p = nullptr;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(indexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed for buffer of size %d", indexData.size);
+ return;
+ }
+ memcpy(p, indexData.p, indexData.size);
+ indexBuffer->Unmap(0, nullptr);
+ } else {
+ indexBuffer = nullptr;
+ }
+ }
+
+ if (constantData.changed) {
+ constantData.changed = false;
+ qDebug("upload constant");
+ const bool newBufferNeeded = constantBuffer ? (constantData.size > constantBuffer->GetDesc().Width) : true;
+ if (newBufferNeeded) {
+ qDebug("new constant buffer of size %d", constantData.size);
+ constantBuffer.Attach(createBuffer(constantData.size));
+ }
+ if (!constantBuffer)
+ return;
+ quint8 *p = nullptr;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed for buffer of size %d", constantData.size);
+ return;
+ }
+ memcpy(p, constantData.p, constantData.size);
+ constantBuffer->Unmap(0, nullptr);
+ }
+
+ if (cboOffset >= 0 && constantBuffer)
+ commandList->SetGraphicsRootConstantBufferView(0, constantBuffer->GetGPUVirtualAddress() + cboOffset);
+
+ Q_ASSERT(vertexBuffer);
+
+ D3D12_VERTEX_BUFFER_VIEW vbv;
+ vbv.BufferLocation = vertexBuffer->GetGPUVirtualAddress() + vboOffset;
+ vbv.SizeInBytes = vboStride * count;
+ vbv.StrideInBytes = vboStride;
+
+ Q_ASSERT(indexBuffer || startIndexIndex < 0);
+
+ D3D_PRIMITIVE_TOPOLOGY topology;
+ switch (mode) {
+ case QSGGeometry::DrawPoints:
+ topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
+ break;
+ case QSGGeometry::DrawLines:
+ topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
+ break;
+ case QSGGeometry::DrawLineStrip:
+ topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
+ break;
+ case QSGGeometry::DrawTriangles:
+ topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ break;
+ case QSGGeometry::DrawTriangleStrip:
+ topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
+ break;
+ default:
+ qFatal("Unsupported drawing mode 0x%x", mode);
+ break;
+ }
+
+ commandList->IASetPrimitiveTopology(topology);
+
+ commandList->IASetVertexBuffers(0, 1, &vbv);
+
+ if (startIndexIndex >= 0) {
+ D3D12_INDEX_BUFFER_VIEW ibv;
+ ibv.BufferLocation = indexBuffer->GetGPUVirtualAddress();
+ ibv.SizeInBytes = indexData.size;
+ ibv.Format = DXGI_FORMAT(indexFormat);
+ commandList->IASetIndexBuffer(&ibv);
+ }
+
+ if (startIndexIndex >= 0)
+ commandList->DrawIndexedInstanced(count, 1, startIndexIndex, 0, 0);
+ else
+ commandList->DrawInstanced(count, 1, 0, 0);
+}
+
+void QSGD3D12EnginePrivate::present()
+{
+ if (!initialized)
+ return;
+
+ qDebug("--- present with vsync ---");
+
+ HRESULT hr = swapChain->Present(1, 0);
+ if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
+ deviceManager()->deviceLossDetected();
+ return;
+ } else if (FAILED(hr)) {
+ qWarning("Present failed: 0x%x", hr);
+ return;
+ }
+}
+
+void QSGD3D12EnginePrivate::waitGPU()
+{
+ if (!initialized)
+ return;
+
+ qDebug("--- blocking wait for GPU ---");
+ waitForGPU(presentFence);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
new file mode 100644
index 0000000000..d5f038fd0c
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12ENGINE_P_H
+#define QSGD3D12ENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QWindow>
+#include <qsggeometry.h>
+
+QT_BEGIN_NAMESPACE
+
+// No D3D or COM headers must be pulled in here. All that has to be isolated
+// to engine_p_p.h and engine.cpp.
+
+class QSGD3D12EnginePrivate;
+
+// Shader bytecode and other strings are expected to be static so that a
+// different pointer == different shader.
+
+enum QSGD3D12Format {
+ FmtUnknown = 0,
+
+ FmtFloat4 = 2, // DXGI_FORMAT_R32G32B32A32_FLOAT
+ FmtFloat3 = 6, // DXGI_FORMAT_R32G32B32_FLOAT
+ FmtFloat2 = 16, // DXGI_FORMAT_R32G32_FLOAT
+ FmtFloat = 41, // DXGI_FORMAT_R32_FLOAT
+
+ // glVertexAttribPointer with GL_UNSIGNED_BYTE and normalized == true maps to the UNORM formats below
+ FmtUNormByte4 = 28, // DXGI_FORMAT_R8G8B8A8_UNORM
+ FmtUNormByte2 = 49, // DXGI_FORMAT_R8G8_UNORM
+ FmtUNormByte = 61, // DXGI_FORMAT_R8_UNORM
+
+ // Index data types
+ FmtUnsignedShort = 57, // DXGI_FORMAT_R16_UINT
+ FmtUnsignedInt = 42 // DXGI_FORMAT_R32_UINT
+};
+
+struct QSGD3D12InputElement
+{
+ QSGD3D12InputElement() { }
+ QSGD3D12InputElement(const char *name, QSGD3D12Format format, quint32 slot, quint32 offset)
+ : name(name), format(format), slot(slot), offset(offset) { }
+
+ const char *name = nullptr;
+ QSGD3D12Format format = FmtFloat4;
+ quint32 slot = 0;
+ quint32 offset = 0;
+
+ bool operator==(const QSGD3D12InputElement &other) const {
+ return name == other.name && format == other.format
+ && slot == other.slot && offset == other.offset;
+ }
+};
+
+inline uint qHash(const QSGD3D12InputElement &key, uint seed = 0)
+{
+ return qHash(key.name, seed) + key.format + key.offset;
+}
+
+struct QSGD3D12ShaderState
+{
+ const quint8 *vs = nullptr;
+ quint32 vsSize = 0;
+ const quint8 *ps = nullptr;
+ quint32 psSize = 0;
+
+ bool operator==(const QSGD3D12ShaderState &other) const {
+ return vs == other.vs && vsSize == other.vsSize
+ && ps == other.ps && psSize == other.psSize;
+ }
+};
+
+inline uint qHash(const QSGD3D12ShaderState &key, uint seed = 0)
+{
+ return qHash(key.vs, seed) + key.vsSize + qHash(key.ps, seed) + key.psSize;
+}
+
+struct QSGD3D12PipelineState
+{
+ enum CullMode {
+ CullNone = 1,
+ CullFront,
+ CullBack
+ };
+
+ enum DepthFunc {
+ DepthNever = 1,
+ DepthLess,
+ DepthEqual,
+ DepthLessEqual,
+ DepthGreater,
+ DepthNotEqual,
+ DepthGreaterEqual,
+ DepthAlways
+ };
+
+ enum TopologyType {
+ TopologyTypePoint = 1,
+ TopologyTypeLine,
+ TopologyTypeTriangle
+ };
+
+ QSGD3D12ShaderState shaders;
+
+ QVector<QSGD3D12InputElement> inputElements;
+
+ CullMode cullMode = CullNone;
+ bool frontCCW = true;
+ bool premulBlend = false; // == GL_ONE, GL_ONE_MINUS_SRC_ALPHA
+ bool depthEnable = true;
+ DepthFunc depthFunc = DepthLess;
+ bool depthWrite = true;
+ bool stencilEnable = false;
+ // ### stencil stuff
+ TopologyType topologyType = TopologyTypeTriangle;
+
+ bool operator==(const QSGD3D12PipelineState &other) const {
+ return shaders == other.shaders
+ && inputElements == other.inputElements
+ && cullMode == other.cullMode
+ && frontCCW == other.frontCCW
+ && premulBlend == other.premulBlend
+ && depthEnable == other.depthEnable
+ && depthFunc == other.depthFunc
+ && depthWrite == other.depthWrite
+ && stencilEnable == other.stencilEnable
+ && topologyType == other.topologyType;
+ }
+};
+
+inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0)
+{
+ return qHash(key.shaders, seed) + qHash(key.inputElements, seed)
+ + key.cullMode + key.frontCCW + key.premulBlend + key.depthEnable
+ + key.depthFunc + key.depthWrite + key.stencilEnable + key.topologyType;
+}
+
+class QSGD3D12Engine
+{
+public:
+ QSGD3D12Engine();
+ ~QSGD3D12Engine();
+
+ bool attachToWindow(QWindow *window);
+ void releaseResources();
+ void resize();
+
+ void beginFrame();
+ void endFrame();
+
+ void setPipelineState(const QSGD3D12PipelineState &pipelineState);
+
+ void setVertexBuffer(const quint8 *data, int size);
+ void setIndexBuffer(const quint8 *data, int size);
+ void setConstantBuffer(const quint8 *data, int size);
+
+ void queueViewport(const QRect &rect);
+ void queueScissor(const QRect &rect);
+ void queueSetRenderTarget();
+ void queueClearRenderTarget(const QColor &color);
+ void queueClearDepthStencil(float depthValue, quint8 stencilValue);
+
+ void queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
+ int cboOffset,
+ int startIndexIndex = -1, QSGD3D12Format indexFormat = FmtUnsignedShort);
+
+ void present();
+ void waitGPU();
+
+ static quint32 alignedConstantBufferSize(quint32 size);
+
+private:
+ QSGD3D12EnginePrivate *d;
+ Q_DISABLE_COPY(QSGD3D12Engine)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12ENGINE_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
new file mode 100644
index 0000000000..733444339c
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12ENGINE_P_P_H
+#define QSGD3D12ENGINE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsgd3d12engine_p.h"
+
+#include <d3d12.h>
+#include <dxgi1_4.h>
+#include <wrl/client.h>
+
+using namespace Microsoft::WRL;
+
+// No moc-related features (Q_OBJECT, signals, etc.) can be used here to due
+// moc-generated code failing to compile when combined with COM stuff.
+
+QT_BEGIN_NAMESPACE
+
+struct QSGD3D12DescriptorHandle
+{
+ QSGD3D12DescriptorHandle() { cpu.ptr = 0; gpu.ptr = 0; }
+ D3D12_CPU_DESCRIPTOR_HANDLE cpu;
+ D3D12_GPU_DESCRIPTOR_HANDLE gpu;
+};
+
+class QSGD3D12DescriptorHeapManager
+{
+public:
+ void initialize(ID3D12Device *device);
+
+ void releaseResources();
+
+ enum Flag {
+ ShaderVisible = 0x01
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QSGD3D12DescriptorHandle allocate(D3D12_DESCRIPTOR_HEAP_TYPE type, Flags flags = 0);
+ quint32 handleSize(D3D12_DESCRIPTOR_HEAP_TYPE type) const { return m_handleSizes[type]; }
+
+private:
+ ID3D12Device *m_device = nullptr;
+ struct Heap {
+ D3D12_DESCRIPTOR_HEAP_TYPE type;
+ ComPtr<ID3D12DescriptorHeap> heap;
+ int count = 0;
+ QSGD3D12DescriptorHandle start;
+ quint32 handleSize;
+ };
+ QVector<Heap> m_heaps;
+ quint32 m_handleSizes[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
+};
+
+class QSGD3D12DeviceManager
+{
+public:
+ ID3D12Device *ref();
+ void unref();
+ void deviceLossDetected();
+ IDXGIFactory4 *dxgi();
+
+ struct DeviceLossObserver {
+ virtual void deviceLost() = 0;
+ };
+ void registerDeviceLossObserver(DeviceLossObserver *observer);
+
+private:
+ void ensureCreated();
+
+ ComPtr<ID3D12Device> m_device;
+ ComPtr<IDXGIFactory4> m_factory;
+ QAtomicInt m_ref;
+ QVector<DeviceLossObserver *> m_observers;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12DescriptorHeapManager::Flags)
+
+struct QSGD3D12Fence
+{
+ ~QSGD3D12Fence() {
+ if (event)
+ CloseHandle(event);
+ }
+ ComPtr<ID3D12Fence> fence;
+ HANDLE event = nullptr;
+ QAtomicInt value;
+};
+
+class QSGD3D12EnginePrivate : public QSGD3D12DeviceManager::DeviceLossObserver
+{
+public:
+ void initialize(QWindow *w);
+ bool isInitialized() const { return initialized; }
+ void releaseResources();
+ void resize();
+
+ void beginFrame();
+ void endFrame();
+
+ void setPipelineState(const QSGD3D12PipelineState &pipelineState);
+
+ void setVertexBuffer(const quint8 *data, int size);
+ void setIndexBuffer(const quint8 *data, int size);
+ void setConstantBuffer(const quint8 *data, int size);
+
+ void queueViewport(const QRect &rect);
+ void queueScissor(const QRect &rect);
+ void queueSetRenderTarget();
+ void queueClearRenderTarget(const QColor &color);
+ void queueClearDepthStencil(float depthValue, quint8 stencilValue);
+
+ void queueDraw(QSGGeometry::DrawingMode mode, int count, int vboOffset, int vboStride,
+ int cboOffset,
+ int startIndexIndex, QSGD3D12Format indexFormat);
+
+ void present();
+ void waitGPU();
+
+ // the device is intentionally hidden here. all resources have to go
+ // through the engine and, unlike with GL, cannot just be created in random
+ // places due to the need for proper tracking, managing and releasing.
+private:
+ void setupRenderTargets();
+ void deviceLost() override;
+
+ DXGI_SAMPLE_DESC makeSampleDesc(DXGI_FORMAT format, int samples);
+ ID3D12Resource *createDepthStencil(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, int samples);
+
+ QSGD3D12Fence *createFence() const;
+ void waitForGPU(QSGD3D12Fence *f) const;
+
+ void transitionResource(ID3D12Resource *resource, ID3D12GraphicsCommandList *commandList,
+ D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after) const;
+
+ ID3D12Resource *createBuffer(int size);
+
+ ID3D12Resource *backBufferRT() const;
+ D3D12_CPU_DESCRIPTOR_HANDLE backBufferRTV() const;
+
+ struct StagingBufferRef {
+ const quint8 *p = nullptr;
+ int size = 0;
+ bool changed = true;
+ };
+
+ bool initialized = false;
+ QWindow *window = nullptr;
+ int swapChainBufferCount = 2;
+ ID3D12Device *device;
+ ComPtr<ID3D12CommandQueue> commandQueue;
+ ComPtr<IDXGISwapChain3> swapChain;
+ ComPtr<ID3D12Resource> renderTargets[2];
+ D3D12_CPU_DESCRIPTOR_HANDLE rtv0;
+ D3D12_CPU_DESCRIPTOR_HANDLE dsv;
+ ComPtr<ID3D12Resource> depthStencil;
+ ComPtr<ID3D12CommandAllocator> commandAllocator;
+ ComPtr<ID3D12CommandAllocator> bundleAllocator;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ QSGD3D12DescriptorHeapManager descHeapManager;
+ QSGD3D12Fence *presentFence = nullptr;
+
+ StagingBufferRef vertexData;
+ StagingBufferRef indexData;
+ StagingBufferRef constantData;
+
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> indexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+
+ QHash<QSGD3D12PipelineState, ComPtr<ID3D12PipelineState> > m_psoCache;
+
+ ComPtr<ID3D12RootSignature> m_rootSig;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp
new file mode 100644
index 0000000000..e7cee712d3
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12material_p.h"
+#include <private/qsgrenderer_p.h>
+
+#include "hlsl_vs_vertexcolor.h"
+#include "hlsl_ps_vertexcolor.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGD3D12Material::RenderState QSGD3D12Material::makeRenderState(QSGRenderer *renderer, RenderState::DirtyStates dirty)
+{
+ RenderState rs;
+ rs.m_dirty = dirty;
+ rs.m_data = renderer;
+ return rs;
+}
+
+float QSGD3D12Material::RenderState::opacity() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->currentOpacity();
+}
+
+float QSGD3D12Material::RenderState::determinant() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->determinant();
+}
+
+QMatrix4x4 QSGD3D12Material::RenderState::combinedMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix();
+}
+
+float QSGD3D12Material::RenderState::devicePixelRatio() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->devicePixelRatio();
+}
+
+QMatrix4x4 QSGD3D12Material::RenderState::modelViewMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
+}
+
+QMatrix4x4 QSGD3D12Material::RenderState::projectionMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->currentProjectionMatrix();
+}
+
+QRect QSGD3D12Material::RenderState::viewportRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->viewportRect();
+}
+
+QRect QSGD3D12Material::RenderState::deviceRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->deviceRect();
+}
+
+QSGMaterialShader *QSGD3D12Material::createShader() const
+{
+ return nullptr;
+}
+
+QSGMaterialType QSGD3D12VertexColorMaterial::mtype;
+
+QSGMaterialType *QSGD3D12VertexColorMaterial::type() const
+{
+ return &QSGD3D12VertexColorMaterial::mtype;
+}
+
+int QSGD3D12VertexColorMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ // As the vertex color material has all its state in the vertex attributes
+ // defined by the geometry, all such materials will be equal.
+ return 0;
+}
+
+static const int VERTEX_COLOR_CB_SIZE_0 = 16 * sizeof(float); // float4x4
+static const int VERTEX_COLOR_CB_SIZE_1 = sizeof(float); // float
+static const int VERTEX_COLOR_CB_SIZE = VERTEX_COLOR_CB_SIZE_0 + VERTEX_COLOR_CB_SIZE_1;
+
+int QSGD3D12VertexColorMaterial::constantBufferSize() const
+{
+ return QSGD3D12Engine::alignedConstantBufferSize(VERTEX_COLOR_CB_SIZE);
+}
+
+void QSGD3D12VertexColorMaterial::preparePipeline(QSGD3D12ShaderState *shaders)
+{
+ shaders->vs = g_VS_VertexColor;
+ shaders->vsSize = sizeof(g_VS_VertexColor);
+ shaders->ps = g_PS_VertexColor;
+ shaders->psSize = sizeof(g_PS_VertexColor);
+}
+
+QSGD3D12Material::UpdateResults QSGD3D12VertexColorMaterial::updatePipeline(const RenderState &state,
+ QSGD3D12ShaderState *,
+ quint8 *constantBuffer)
+{
+ QSGD3D12Material::UpdateResults r = 0;
+ quint8 *p = constantBuffer;
+
+ if (state.isMatrixDirty()) {
+ memcpy(p, state.combinedMatrix().constData(), VERTEX_COLOR_CB_SIZE_0);
+ r |= UpdatedConstantBuffer;
+ }
+ p += VERTEX_COLOR_CB_SIZE_0;
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(p, &opacity, VERTEX_COLOR_CB_SIZE_1);
+ r |= UpdatedConstantBuffer;
+ }
+
+ return r;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h
new file mode 100644
index 0000000000..d61b1e94dc
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12material_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12MATERIAL_P_H
+#define QSGD3D12MATERIAL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/qsgmaterial.h>
+#include "qsgd3d12engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGRenderer;
+
+// The D3D renderer works with QSGD3D12Material as the "base" class since
+// QSGMaterial and its GL program related bits are not suitable. Also, there is
+// no split like with QSGMaterialShader.
+
+class QSGD3D12Material : public QSGMaterial
+{
+public:
+ struct RenderState {
+ enum DirtyState {
+ DirtyMatrix = 0x0001,
+ DirtyOpacity = 0x0002,
+ DirtyAll = 0xFFFF
+ };
+ Q_DECLARE_FLAGS(DirtyStates, DirtyState)
+
+ DirtyStates dirtyStates() const { return m_dirty; }
+
+ bool isMatrixDirty() const { return m_dirty & DirtyMatrix; }
+ bool isOpacityDirty() const { return m_dirty & DirtyOpacity; }
+
+ float opacity() const;
+ QMatrix4x4 combinedMatrix() const;
+ QMatrix4x4 modelViewMatrix() const;
+ QMatrix4x4 projectionMatrix() const;
+ QRect viewportRect() const;
+ QRect deviceRect() const;
+ float determinant() const;
+ float devicePixelRatio() const;
+
+ DirtyStates m_dirty = 0;
+ void *m_data = nullptr;
+ };
+
+ enum UpdateResult {
+ UpdatedShaders = 0x0001,
+ UpdatedConstantBuffer = 0x0002
+ };
+ Q_DECLARE_FLAGS(UpdateResults, UpdateResult)
+
+ static RenderState makeRenderState(QSGRenderer *renderer, RenderState::DirtyStates dirty);
+
+ virtual int constantBufferSize() const = 0;
+ virtual void preparePipeline(QSGD3D12ShaderState *shaders) = 0;
+ virtual UpdateResults updatePipeline(const RenderState &state,
+ QSGD3D12ShaderState *shaders,
+ quint8 *constantBuffer) = 0;
+
+private:
+ QSGMaterialShader *createShader() const override; // dummy, QSGMaterialShader is too GL dependent
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Material::RenderState::DirtyStates)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Material::UpdateResults)
+
+class QSGD3D12VertexColorMaterial : public QSGD3D12Material
+{
+public:
+ QSGMaterialType *type() const override;
+ int compare(const QSGMaterial *other) const override;
+
+ virtual int constantBufferSize() const override;
+ void preparePipeline(QSGD3D12ShaderState *shaders) override;
+ UpdateResults updatePipeline(const RenderState &state,
+ QSGD3D12ShaderState *shaders,
+ quint8 *constantBuffer) override;
+
+private:
+ static QSGMaterialType mtype;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12MATERIAL_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp
new file mode 100644
index 0000000000..5956a06e2f
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12rectanglenode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGD3D12RectangleNode::QSGD3D12RectangleNode()
+{
+ setMaterial(&m_material);
+}
+
+void QSGD3D12RectangleNode::updateMaterialAntialiasing()
+{
+ //if (m_antialiasing)
+ // setMaterial(&m_smoothMaterial);
+ //else
+ setMaterial(&m_material);
+}
+
+void QSGD3D12RectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
+{
+ // smoothed material is always blended, so no change in material state
+ if (material() == &m_material) {
+ bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
+ bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
+ || (m_color.alpha() < 255 && m_color.alpha() != 0)
+ || (m_pen_width > 0 && m_border_color.alpha() < 255);
+ if (wasBlending != isBlending) {
+ m_material.setFlag(QSGMaterial::Blending, isBlending);
+ *state |= QSGNode::DirtyMaterial;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h
new file mode 100644
index 0000000000..464dc763a6
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rectanglenode_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12RECTANGLENODE_P_H
+#define QSGD3D12RECTANGLENODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgdefaultrectanglenode_p.h>
+#include "qsgd3d12material_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12RectangleNode : public QSGDefaultNoMaterialRectangleNode
+{
+public:
+ QSGD3D12RectangleNode();
+
+private:
+ void updateMaterialAntialiasing() override;
+ void updateMaterialBlending(QSGNode::DirtyState *state) override;
+
+ QSGD3D12VertexColorMaterial m_material;
+ //QSGD3D12Material m_smoothMaterial;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12RECTANGLENODE_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext.cpp
new file mode 100644
index 0000000000..a9dea49200
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12rendercontext_p.h"
+#include "qsgd3d12renderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGD3D12RenderContext::QSGD3D12RenderContext(QSGContext *ctx)
+ : QSGRenderContext(ctx)
+{
+ qDebug("new d3d12 render context");
+}
+
+void QSGD3D12RenderContext::initialize(QOpenGLContext *)
+{
+ Q_UNREACHABLE();
+}
+
+void QSGD3D12RenderContext::invalidate()
+{
+ QSGRenderContext::invalidate();
+}
+
+QSGTexture *QSGD3D12RenderContext::createTexture(const QImage &image, uint flags) const
+{
+ Q_UNUSED(image);
+ Q_UNUSED(flags);
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+QSGRenderer *QSGD3D12RenderContext::createRenderer()
+{
+ return new QSGD3D12Renderer(this);
+}
+
+void QSGD3D12RenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fbo)
+{
+ QSGRenderContext::renderNextFrame(renderer, fbo);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext_p.h
new file mode 100644
index 0000000000..2e05632ad9
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12rendercontext_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12RENDERCONTEXT_P_H
+#define QSGD3D12RENDERCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12Engine;
+
+class QSGD3D12RenderContext : public QSGRenderContext
+{
+public:
+ QSGD3D12RenderContext(QSGContext *ctx);
+
+ void initialize(QOpenGLContext *) override; // not in use
+ void invalidate() override;
+ void renderNextFrame(QSGRenderer *renderer, GLuint fbo) override;
+ QSGTexture *createTexture(const QImage &image, uint flags) const override;
+ QSGRenderer *createRenderer() override;
+
+ void setEngine(QSGD3D12Engine *engine) { m_engine = engine; }
+ QSGD3D12Engine *engine() { return m_engine; }
+
+private:
+ QSGD3D12Engine *m_engine = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12RENDERCONTEXT_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
new file mode 100644
index 0000000000..b063138d74
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer.cpp
@@ -0,0 +1,477 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12renderer_p.h"
+#include "qsgd3d12rendercontext_p.h"
+#include "qsgd3d12material_p.h"
+#include <private/qsgnodeupdater_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling())
+
+#define DECLARE_DEBUG_VAR(variable) \
+ static bool debug_ ## variable() \
+ { static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
+
+DECLARE_DEBUG_VAR(build)
+DECLARE_DEBUG_VAR(change)
+DECLARE_DEBUG_VAR(render)
+
+class DummyUpdater : public QSGNodeUpdater
+{
+public:
+ void updateState(QSGNode *) { };
+};
+
+QSGD3D12Renderer::QSGD3D12Renderer(QSGRenderContext *context)
+ : QSGRenderer(context),
+ m_renderList(16),
+ m_vboData(1024),
+ m_iboData(256),
+ m_cboData(256)
+{
+ setNodeUpdater(new DummyUpdater);
+}
+
+void QSGD3D12Renderer::renderScene(GLuint fboId)
+{
+ Q_UNUSED(fboId);
+
+ struct B : public QSGBindable {
+ void bind() const { }
+ } bindable;
+
+ QSGRenderer::renderScene(bindable);
+}
+
+// Search through the node set and remove nodes that are leaves of other
+// nodes in the same set.
+static QSet<QSGNode *> qsg_filterSubTree(const QSet<QSGNode *> &nodes, QSGRootNode *root)
+{
+ QSet<QSGNode *> result = nodes;
+ for (QSGNode *node : nodes) {
+ QSGNode *n = node;
+ while (n != root) {
+ if (result.contains(n)) {
+ result.remove(node);
+ break;
+ }
+ n = n->parent();
+ }
+ }
+ return result;
+}
+
+void QSGD3D12Renderer::updateMatrices(QSGNode *node, QSGTransformNode *xform)
+{
+ if (node->isSubtreeBlocked())
+ return;
+
+ if (node->type() == QSGNode::TransformNodeType) {
+ QSGTransformNode *tn = static_cast<QSGTransformNode *>(node);
+ if (xform)
+ tn->setCombinedMatrix(xform->combinedMatrix() * tn->matrix());
+ else
+ tn->setCombinedMatrix(tn->matrix());
+ QSGNODE_TRAVERSE(node)
+ updateMatrices(child, tn);
+
+ } else {
+ if (node->type() == QSGNode::GeometryNodeType || node->type() == QSGNode::ClipNodeType) {
+ static_cast<QSGBasicGeometryNode *>(node)->setMatrix(xform ? &xform->combinedMatrix() : 0);
+ }
+ QSGNODE_TRAVERSE(node)
+ updateMatrices(child, xform);
+ }
+}
+
+void QSGD3D12Renderer::buildRenderList(QSGNode *node, QSGClipNode *clip)
+{
+ if (node->isSubtreeBlocked())
+ return;
+
+ if (node->type() == QSGNode::GeometryNodeType || node->type() == QSGNode::ClipNodeType) {
+ QSGBasicGeometryNode *gn = static_cast<QSGBasicGeometryNode *>(node);
+ QSGGeometry *g = gn->geometry();
+
+ Element e;
+ e.node = gn;
+
+ if (g->vertexCount() > 0) {
+ e.vboOffset = m_vboData.size();
+ const int vertexSize = g->sizeOfVertex() * g->vertexCount();
+ m_vboData.resize(m_vboData.size() + vertexSize);
+ memcpy(m_vboData.data() + e.vboOffset, g->vertexData(), vertexSize);
+ }
+
+ if (g->indexCount() > 0) {
+ e.iboOffset = m_iboData.size();
+ e.iboStride = g->sizeOfIndex();
+ const int indexSize = e.iboStride * g->indexCount();
+ m_iboData.resize(m_iboData.size() + indexSize);
+ memcpy(m_iboData.data() + e.iboOffset, g->indexData(), indexSize);
+ }
+
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGD3D12Material *m = static_cast<QSGD3D12Material *>(static_cast<QSGGeometryNode *>(node)->activeMaterial());
+ e.cboOffset = m_cboData.size();
+ e.cboSize = m->constantBufferSize();
+ m_cboData.resize(m_cboData.size() + e.cboSize);
+ }
+
+ m_renderList.add(e);
+
+ gn->setClipList(clip);
+ if (node->type() == QSGNode::ClipNodeType)
+ clip = static_cast<QSGClipNode *>(node);
+ }
+
+ QSGNODE_TRAVERSE(node)
+ buildRenderList(child, clip);
+}
+
+void QSGD3D12Renderer::render()
+{
+ QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(context());
+ m_engine = rc->engine();
+ m_engine->beginFrame();
+
+ if (m_rebuild) {
+ // This changes everything, so discard all cached states
+ m_rebuild = false;
+ m_dirtyTransformNodes.clear();
+ m_dirtyTransformNodes.insert(rootNode());
+
+ m_renderList.reset();
+ m_vboData.reset();
+ m_iboData.reset();
+ m_cboData.reset();
+
+ buildRenderList(rootNode(), 0);
+
+ m_engine->setVertexBuffer(m_vboData.data(), m_vboData.size());
+ m_engine->setIndexBuffer(m_iboData.data(), m_iboData.size());
+
+ if (Q_UNLIKELY(debug_build())) {
+ qDebug("renderList: %d elements in total", m_renderList.size());
+ for (int i = 0; i < m_renderList.size(); ++i) {
+ const Element &e = m_renderList.at(i);
+ qDebug() << " - " << e.vboOffset << e.iboOffset << e.cboOffset << e.cboSize << e.node;
+ }
+ }
+ }
+
+ if (m_dirtyTransformNodes.size()) {
+ const QSet<QSGNode *> subTreeRoots = qsg_filterSubTree(m_dirtyTransformNodes, rootNode());
+ for (QSGNode *node : subTreeRoots) {
+ // First find the parent transform so we have the accumulated
+ // matrix up until this point.
+ QSGTransformNode *xform = 0;
+ QSGNode *n = node;
+ if (n->type() == QSGNode::TransformNodeType)
+ n = node->parent();
+ while (n != rootNode() && n->type() != QSGNode::TransformNodeType)
+ n = n->parent();
+ if (n != rootNode())
+ xform = static_cast<QSGTransformNode *>(n);
+
+ // Then update in the subtree
+ updateMatrices(node, xform);
+ }
+ }
+
+ if (m_dirtyOpaqueElements) {
+ m_dirtyOpaqueElements = false;
+ m_opaqueElements.clear();
+ m_opaqueElements.resize(m_renderList.size());
+ for (int i = 0; i < m_renderList.size(); ++i) {
+ const Element &e = m_renderList.at(i);
+ if (e.node->type() == QSGNode::GeometryNodeType) {
+ const QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(e.node);
+ if (gn->inheritedOpacity() > 0.999f && ((gn->activeMaterial()->flags() & QSGMaterial::Blending) == 0))
+ m_opaqueElements.setBit(i);
+ }
+ }
+ }
+
+ renderElements();
+
+ m_engine->endFrame();
+ m_engine = nullptr;
+}
+
+void QSGD3D12Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
+{
+ // note that with DirtyNodeRemoved the window and all the graphics engine may already be gone
+
+ if (Q_UNLIKELY(debug_change())) {
+ QDebug debug = qDebug();
+ debug << "dirty:";
+ if (state & QSGNode::DirtyGeometry)
+ debug << "Geometry";
+ if (state & QSGNode::DirtyMaterial)
+ debug << "Material";
+ if (state & QSGNode::DirtyMatrix)
+ debug << "Matrix";
+ if (state & QSGNode::DirtyNodeAdded)
+ debug << "Added";
+ if (state & QSGNode::DirtyNodeRemoved)
+ debug << "Removed";
+ if (state & QSGNode::DirtyOpacity)
+ debug << "Opacity";
+ if (state & QSGNode::DirtySubtreeBlocked)
+ debug << "SubtreeBlocked";
+ if (state & QSGNode::DirtyForceUpdate)
+ debug << "ForceUpdate";
+
+ // when removed, some parts of the node could already have been destroyed
+ // so don't debug it out.
+ if (state & QSGNode::DirtyNodeRemoved)
+ debug << (void *) node << node->type();
+ else
+ debug << node;
+ }
+
+ if (state & (QSGNode::DirtyNodeAdded
+ | QSGNode::DirtyNodeRemoved
+ | QSGNode::DirtySubtreeBlocked
+ | QSGNode::DirtyGeometry
+ | QSGNode::DirtyForceUpdate))
+ m_rebuild = true;
+
+ if (state & QSGNode::DirtyMatrix)
+ m_dirtyTransformNodes << node;
+
+ if (state & QSGNode::DirtyMaterial)
+ m_dirtyOpaqueElements = true;
+
+ QSGRenderer::nodeChanged(node, state);
+}
+
+void QSGD3D12Renderer::renderElements()
+{
+ QRect r = viewportRect();
+ r.setY(deviceRect().bottom() - r.bottom());
+ m_engine->queueViewport(r);
+ m_engine->queueScissor(r);
+ m_engine->queueSetRenderTarget();
+ m_engine->queueClearRenderTarget(clearColor());
+ m_engine->queueClearDepthStencil(1, 0);
+
+ m_pipelineState.premulBlend = false;
+ m_pipelineState.depthEnable = true;
+ m_pipelineState.depthWrite = true;
+
+ m_current_projection_matrix = projectionMatrix();
+
+ // First do opaque...
+ // The algorithm is quite simple. We traverse the list back-to-from
+ // and for every item, we start a second traversal from this point
+ // and draw all elements which have identical material. Then we clear
+ // the bit for this in the rendered list so we don't draw it again
+ // when we come to that index.
+ QBitArray rendered = m_opaqueElements;
+ for (int i = m_renderList.size() - 1; i >= 0; --i) {
+ if (rendered.testBit(i)) {
+ renderElement(i);
+ for (int j = i - 1; j >= 0; --j) {
+ if (rendered.testBit(j)) {
+ const QSGGeometryNode *gni = static_cast<QSGGeometryNode *>(m_renderList.at(i).node);
+ const QSGGeometryNode *gnj = static_cast<QSGGeometryNode *>(m_renderList.at(j).node);
+ if (gni->clipList() == gnj->clipList()
+ && gni->inheritedOpacity() == gnj->inheritedOpacity()
+ && gni->geometry()->drawingMode() == gnj->geometry()->drawingMode()
+ && gni->geometry()->attributes() == gnj->geometry()->attributes()) {
+ const QSGMaterial *ami = gni->activeMaterial();
+ const QSGMaterial *amj = gnj->activeMaterial();
+ if (ami->type() == amj->type()
+ && ami->flags() == amj->flags()
+ && ami->compare(amj) == 0) {
+ renderElement(j);
+ rendered.clearBit(j);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_pipelineState.premulBlend = true;
+ m_pipelineState.depthWrite = false;
+
+ // ...then the alpha ones
+ for (int i = 0; i < m_renderList.size(); ++i) {
+ if (m_renderList.at(i).node->type() == QSGNode::GeometryNodeType && !m_opaqueElements.testBit(i))
+ renderElement(i);
+ }
+}
+
+void QSGD3D12Renderer::renderElement(int elementIndex)
+{
+ Element &e = m_renderList.at(elementIndex);
+ Q_ASSERT(e.node->type() == QSGNode::GeometryNodeType);
+
+ if (e.vboOffset < 0)
+ return;
+
+ Q_ASSERT(e.cboOffset >= 0);
+
+ const QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(e.node);
+ if (Q_UNLIKELY(debug_render()))
+ qDebug() << "renderElement:" << elementIndex << gn << e.vboOffset << e.iboOffset << gn->inheritedOpacity() << gn->clipList();
+
+ if (gn->inheritedOpacity() < 0.001f) // pretty much invisible, don't draw it
+ return;
+
+ QSGD3D12Material::RenderState::DirtyStates dirtyState = QSGD3D12Material::RenderState::DirtyMatrix;
+ m_current_projection_matrix = projectionMatrix();
+ qreal scale = 1.0 / m_renderList.size();
+ m_current_projection_matrix(2, 2) = scale;
+ m_current_projection_matrix(2, 3) = 1.0f - (elementIndex + 1) * scale;
+ m_current_model_view_matrix = gn->matrix() ? *gn->matrix() : QMatrix4x4();
+ m_current_determinant = m_current_model_view_matrix.determinant();
+ if (gn->inheritedOpacity() != m_current_opacity) {
+ m_current_opacity = gn->inheritedOpacity();
+ dirtyState |= QSGD3D12Material::RenderState::DirtyOpacity;
+ }
+
+ const QSGGeometry *g = gn->geometry();
+ QSGD3D12Material *m = static_cast<QSGD3D12Material *>(gn->activeMaterial());
+
+ if (m->type() != m_lastMaterialType)
+ m->preparePipeline(&m_pipelineState.shaders);
+
+ if (!e.cboPrepared) {
+ e.cboPrepared = true;
+ dirtyState = QSGD3D12Material::RenderState::DirtyAll;
+ }
+
+ quint8 *cboPtr = nullptr;
+ if (e.cboSize > 0)
+ cboPtr = m_cboData.data() + e.cboOffset;
+
+ qDebug() << "ds" << dirtyState;
+ QSGD3D12Material::UpdateResults updRes = m->updatePipeline(QSGD3D12Material::makeRenderState(this, dirtyState),
+ &m_pipelineState.shaders,
+ cboPtr);
+ // For now there is no way to have extra SRVs and such. Once texturing is
+ // introduced, the above update call will have to be able to affect the
+ // root signature and communicate the need for SRVs or UAVs to the engine.
+
+ if (updRes.testFlag(QSGD3D12Material::UpdatedConstantBuffer))
+ m_engine->setConstantBuffer(m_cboData.data(), m_cboData.size());
+
+ // Input element layout
+ m_pipelineState.inputElements.resize(g->attributeCount());
+ const QSGGeometry::Attribute *attrs = g->attributes();
+ quint32 offset = 0;
+ for (int i = 0; i < g->attributeCount(); ++i) {
+ QSGD3D12InputElement &ie(m_pipelineState.inputElements[i]);
+ static const char *semanticNames[] = { "UNKNOWN", "POSITION", "COLOR", "TEXCOORD" };
+ Q_ASSERT(attrs[i].semantic >= 1 && attrs[i].semantic < _countof(semanticNames));
+ const int tupleSize = attrs[i].tupleSize;
+ ie.name = semanticNames[attrs[i].semantic];
+ ie.offset = offset;
+ // ### move format mapping to engine
+ static const QSGD3D12Format formatMap_ub[] = { FmtUnknown,
+ FmtUNormByte,
+ FmtUNormByte2,
+ FmtUnknown,
+ FmtUNormByte4 };
+ static const QSGD3D12Format formatMap_f[] = { FmtUnknown,
+ FmtFloat,
+ FmtFloat2,
+ FmtFloat3,
+ FmtFloat4 };
+ switch (attrs[i].type) {
+ case QSGGeometry::TypeUnsignedByte:
+ ie.format = formatMap_ub[tupleSize];
+ offset += tupleSize;
+ break;
+ case QSGGeometry::TypeFloat:
+ ie.format = formatMap_f[tupleSize];
+ offset += sizeof(float) * tupleSize;
+ break;
+ case QSGGeometry::TypeByte:
+ case QSGGeometry::TypeInt:
+ case QSGGeometry::TypeUnsignedInt:
+ case QSGGeometry::TypeShort:
+ case QSGGeometry::TypeUnsignedShort:
+ qFatal("QSGD3D12Renderer: attribute type 0x%x is not currently supported", attrs[i].type);
+ break;
+ }
+ if (ie.format == FmtUnknown)
+ qFatal("QSGD3D12Renderer: unsupported tuple size for attribute type 0x%x", attrs[i].type);
+
+ // There is one buffer with interleaved data so the slot is always 0.
+ ie.slot = 0;
+ }
+
+ m_lastMaterialType = m->type();
+
+ // ### line width / point size ??
+
+ m_engine->setPipelineState(m_pipelineState);
+
+ if (e.iboOffset >= 0) {
+ // ### move format mapping to engine
+ QSGD3D12Format indexFormat;
+ const QSGGeometry::Type indexType = QSGGeometry::Type(g->indexType());
+ switch (indexType) {
+ case QSGGeometry::TypeUnsignedShort:
+ indexFormat = FmtUnsignedShort;
+ break;
+ case QSGGeometry::TypeUnsignedInt:
+ indexFormat = FmtUnsignedInt;
+ break;
+ default:
+ qFatal("QSGD3D12Renderer: unsupported index data type 0x%x", indexType);
+ break;
+ };
+ m_engine->queueDraw(QSGGeometry::DrawingMode(g->drawingMode()), g->indexCount(), e.vboOffset, g->sizeOfVertex(),
+ e.cboOffset,
+ e.iboOffset / e.iboStride, indexFormat);
+ } else {
+ m_engine->queueDraw(QSGGeometry::DrawingMode(g->drawingMode()), g->vertexCount(), e.vboOffset, g->sizeOfVertex(),
+ e.cboOffset);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
new file mode 100644
index 0000000000..a0ae99a2e0
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderer_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12RENDERER_P_H
+#define QSGD3D12RENDERER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgrenderer_p.h>
+#include <QtGui/private/qdatabuffer_p.h>
+#include "qsgd3d12engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12Renderer : public QSGRenderer
+{
+public:
+ QSGD3D12Renderer(QSGRenderContext *context);
+
+ void renderScene(GLuint fboId) override;
+ void render() override;
+ void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override;
+
+private:
+ void updateMatrices(QSGNode *node, QSGTransformNode *xform);
+ void buildRenderList(QSGNode *node, QSGClipNode *clip);
+ void renderElements();
+ void renderElement(int elementIndex);
+
+ struct Element {
+ QSGBasicGeometryNode *node = nullptr;
+ qint32 vboOffset = -1;
+ qint32 iboOffset = -1;
+ quint32 iboStride = 0;
+ qint32 cboOffset = -1;
+ quint32 cboSize = 0;
+ bool cboPrepared = false;
+ };
+
+ QSet<QSGNode *> m_dirtyTransformNodes;
+ QBitArray m_opaqueElements;
+ bool m_rebuild = true;
+ bool m_dirtyOpaqueElements = true;
+ QDataBuffer<quint8> m_vboData;
+ QDataBuffer<quint8> m_iboData;
+ QDataBuffer<quint8> m_cboData;
+ QDataBuffer<Element> m_renderList;
+ QSGD3D12Engine *m_engine;
+
+ QSGMaterialType *m_lastMaterialType = nullptr;
+ QSGD3D12PipelineState m_pipelineState;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12RENDERER_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop.cpp
new file mode 100644
index 0000000000..e0ee5e02dd
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgd3d12renderloop_p.h"
+#include "qsgd3d12engine_p.h"
+#include "qsgd3d12context_p.h"
+#include "qsgd3d12rendercontext_p.h"
+#include <private/qquickwindow_p.h>
+#include <private/qquickprofiler_p.h>
+#include <QElapsedTimer>
+
+QT_BEGIN_NAMESPACE
+
+QSGD3D12RenderLoop::QSGD3D12RenderLoop()
+{
+ qDebug("new d3d12 render loop");
+ sg = new QSGD3D12Context;
+ rc = new QSGD3D12RenderContext(sg);
+}
+
+QSGD3D12RenderLoop::~QSGD3D12RenderLoop()
+{
+ delete rc;
+ delete sg;
+}
+
+void QSGD3D12RenderLoop::show(QQuickWindow *window)
+{
+ qDebug() << "show" << window;
+
+ WindowData data;
+ data.engine = new QSGD3D12Engine;
+ m_windows[window] = data;
+
+ data.engine->attachToWindow(window);
+
+ maybeUpdate(window);
+}
+
+void QSGD3D12RenderLoop::hide(QQuickWindow *window)
+{
+ qDebug() << "hide" << window;
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->fireAboutToStop();
+}
+
+void QSGD3D12RenderLoop::resize(QQuickWindow *window)
+{
+ if (!window->isExposed() || window->size().isEmpty())
+ return;
+
+ qDebug() << "resize" << window;
+
+ WindowData &data(m_windows[window]);
+ if (data.engine)
+ data.engine->resize();
+}
+
+void QSGD3D12RenderLoop::windowDestroyed(QQuickWindow *window)
+{
+ qDebug() << "window destroyed" << window;
+
+ WindowData &data(m_windows[window]);
+ delete data.engine;
+ m_windows.remove(window);
+
+ hide(window);
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ wd->cleanupNodesOnShutdown();
+
+ if (m_windows.isEmpty()) {
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+}
+
+void QSGD3D12RenderLoop::exposureChanged(QQuickWindow *window)
+{
+ qDebug() << "exposure changed" << window;
+
+ if (window->isExposed()) {
+ m_windows[window].updatePending = true;
+ renderWindow(window);
+ }
+}
+
+QImage QSGD3D12RenderLoop::grab(QQuickWindow *window)
+{
+ Q_UNUSED(window);
+ Q_UNREACHABLE();
+ return QImage();
+}
+
+void QSGD3D12RenderLoop::update(QQuickWindow *window)
+{
+ //qDebug() << "update" << window;
+
+ if (!m_windows.contains(window))
+ return;
+
+ m_windows[window].updatePending = true;
+ window->requestUpdate();
+}
+
+void QSGD3D12RenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ //qDebug() << "maybeUpdate" << window;
+
+ update(window);
+}
+
+// called in response to window->requestUpdate()
+void QSGD3D12RenderLoop::handleUpdateRequest(QQuickWindow *window)
+{
+ qDebug() << "handleUpdateRequest" << window;
+
+ renderWindow(window);
+}
+
+QAnimationDriver *QSGD3D12RenderLoop::animationDriver() const
+{
+ return nullptr;
+}
+
+QSGContext *QSGD3D12RenderLoop::sceneGraphContext() const
+{
+ return sg;
+}
+
+QSGRenderContext *QSGD3D12RenderLoop::createRenderContext(QSGContext *) const
+{
+ return rc;
+}
+
+void QSGD3D12RenderLoop::releaseResources(QQuickWindow *window)
+{
+ qDebug() << "releaseResources" << window;
+}
+
+void QSGD3D12RenderLoop::postJob(QQuickWindow *window, QRunnable *job)
+{
+ Q_UNUSED(window);
+ Q_UNUSED(job);
+ Q_UNREACHABLE();
+}
+
+QSurface::SurfaceType QSGD3D12RenderLoop::windowSurfaceType() const
+{
+ return QSurface::OpenGLSurface;
+}
+
+void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
+{
+ qDebug() << "renderWindow" << window;
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ if (!wd->isRenderable() || !m_windows.contains(window))
+ return;
+
+ WindowData &data(m_windows[window]);
+
+ const bool needsSwap = data.updatePending;
+ data.updatePending = false;
+
+ if (!data.grabOnly) {
+ wd->flushDelayedTouchEvent();
+ if (!m_windows.contains(window))
+ return;
+ }
+
+ rc->setEngine(data.engine);
+
+ QElapsedTimer renderTimer;
+ qint64 renderTime = 0, syncTime = 0, polishTime = 0;
+ const bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled();
+ if (profileFrames)
+ renderTimer.start();
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
+
+ wd->polishItems();
+
+ if (profileFrames)
+ polishTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
+ QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ emit window->afterAnimating();
+
+ wd->syncSceneGraph();
+
+ if (profileFrames)
+ syncTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ wd->renderSceneGraph(window->size());
+
+ if (profileFrames)
+ renderTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ if (data.grabOnly) {
+ Q_UNREACHABLE();
+ data.grabOnly = false;
+ }
+
+ if (needsSwap && window->isVisible()) {
+ data.engine->present();
+ data.engine->waitGPU();
+ wd->fireFrameSwapped();
+ } else {
+ data.engine->waitGPU();
+ }
+
+ qint64 swapTime = 0;
+ if (profileFrames)
+ swapTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
+ static QTime lastFrameTime = QTime::currentTime();
+ qCDebug(QSG_LOG_TIME_RENDERLOOP,
+ "Frame rendered with 'd3d12' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
+ int(swapTime / 1000000),
+ int(polishTime / 1000000),
+ int((syncTime - polishTime) / 1000000),
+ int((renderTime - syncTime) / 1000000),
+ int((swapTime - renderTime) / 10000000),
+ int(lastFrameTime.msecsTo(QTime::currentTime())));
+ lastFrameTime = QTime::currentTime();
+ }
+
+ rc->setEngine(nullptr);
+
+ // Might have been set during syncSceneGraph()
+ if (data.updatePending)
+ maybeUpdate(window);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop_p.h
new file mode 100644
index 0000000000..63848ed723
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12renderloop_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGD3D12RENDERLOOP_P_H
+#define QSGD3D12RENDERLOOP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgrenderloop_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGD3D12Engine;
+class QSGD3D12Context;
+class QSGD3D12RenderContext;
+
+class QSGD3D12RenderLoop : public QSGRenderLoop
+{
+public:
+ QSGD3D12RenderLoop();
+ ~QSGD3D12RenderLoop();
+
+ void show(QQuickWindow *window) override;
+ void hide(QQuickWindow *window) override;
+ void resize(QQuickWindow *window) override;
+
+ void windowDestroyed(QQuickWindow *window) override;
+
+ void exposureChanged(QQuickWindow *window) override;
+
+ QImage grab(QQuickWindow *window) override;
+
+ void update(QQuickWindow *window) override;
+ void maybeUpdate(QQuickWindow *window) override;
+ void handleUpdateRequest(QQuickWindow *window) override;
+
+ QAnimationDriver *animationDriver() const override;
+
+ QSGContext *sceneGraphContext() const override;
+ QSGRenderContext *createRenderContext(QSGContext *) const override;
+
+ void releaseResources(QQuickWindow *window) override;
+ void postJob(QQuickWindow *window, QRunnable *job) override;
+
+ QSurface::SurfaceType windowSurfaceType() const override;
+
+private:
+ void renderWindow(QQuickWindow *window);
+
+ QSGD3D12Context *sg;
+ QSGD3D12RenderContext *rc;
+
+ struct WindowData {
+ QSGD3D12Engine *engine = nullptr;
+ bool updatePending = false;
+ bool grabOnly = false;
+ };
+
+ QHash<QQuickWindow *, WindowData> m_windows;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGD3D12RENDERLOOP_P_H
diff --git a/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
new file mode 100644
index 0000000000..c3745cc682
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/shaders/shaders.pri
@@ -0,0 +1,12 @@
+vertexcolor_VSPS = $$PWD/vertexcolor.hlsl
+vertexcolor_vshader.input = vertexcolor_VSPS
+vertexcolor_vshader.header = hlsl_vs_vertexcolor.h
+vertexcolor_vshader.entry = VS_VertexColor
+vertexcolor_vshader.type = vs_5_0
+vertexcolor_pshader.input = vertexcolor_VSPS
+vertexcolor_pshader.header = hlsl_ps_vertexcolor.h
+vertexcolor_pshader.entry = PS_VertexColor
+vertexcolor_pshader.type = ps_5_0
+
+HLSL_SHADERS = vertexcolor_vshader vertexcolor_pshader
+load(hlsl_bytecode_header)
diff --git a/src/quick/scenegraph/adaptations/d3d12/shaders/vertexcolor.hlsl b/src/quick/scenegraph/adaptations/d3d12/shaders/vertexcolor.hlsl
new file mode 100644
index 0000000000..a0569bb5c1
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/d3d12/shaders/vertexcolor.hlsl
@@ -0,0 +1,32 @@
+struct VSInput
+{
+ float4 position : POSITION;
+ float4 color : COLOR;
+};
+
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 mvp;
+ float opacity;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float4 color : COLOR;
+};
+
+PSInput VS_VertexColor(VSInput input)
+{
+ PSInput result;
+
+ result.position = mul(mvp, input.position);
+ result.color = input.color * opacity;
+
+ return result;
+}
+
+float4 PS_VertexColor(PSInput input) : SV_TARGET
+{
+ return input.color;
+}
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index 5012f6a31b..152bb253d7 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -53,10 +53,15 @@ QT_BEGIN_NAMESPACE
QSGGeometry::Attribute QSGGeometry::Attribute::create(int attributeIndex, int tupleSize, int primitiveType, bool isPrimitive)
{
- Attribute a = { attributeIndex, tupleSize, primitiveType, isPrimitive, 0 };
+ Attribute a = { attributeIndex, tupleSize, primitiveType, isPrimitive, UNKNOWN, 0 };
return a;
}
+QSGGeometry::Attribute QSGGeometry::Attribute::createWithSemantic(int pos, int tupleSize, int type, Semantic semantic)
+{
+ Attribute a = { pos, tupleSize, type, semantic == POSITION, semantic, 0 };
+ return a;
+}
/*!
Convenience function which returns attributes to be used for 2D solid
@@ -66,7 +71,7 @@ QSGGeometry::Attribute QSGGeometry::Attribute::create(int attributeIndex, int tu
const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
{
static Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true)
+ Attribute::createWithSemantic(0, 2, GL_FLOAT, Attribute::POSITION)
};
static AttributeSet attrs = { 1, sizeof(float) * 2, data };
return attrs;
@@ -79,8 +84,8 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_TexturedPoint2D()
{
static Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
- QSGGeometry::Attribute::create(1, 2, GL_FLOAT)
+ Attribute::createWithSemantic(0, 2, GL_FLOAT, Attribute::POSITION),
+ Attribute::createWithSemantic(1, 2, GL_FLOAT, Attribute::TEXCOORD)
};
static AttributeSet attrs = { 2, sizeof(float) * 4, data };
return attrs;
@@ -93,8 +98,8 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_TexturedPoint2D(
const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
{
static Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
- QSGGeometry::Attribute::create(1, 4, GL_UNSIGNED_BYTE)
+ Attribute::createWithSemantic(0, 2, GL_FLOAT, Attribute::POSITION),
+ Attribute::createWithSemantic(1, 4, GL_UNSIGNED_BYTE, Attribute::COLOR)
};
static AttributeSet attrs = { 2, 2 * sizeof(float) + 4 * sizeof(char), data };
return attrs;
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h
index 5773b6abd1..6b1e3e3f4e 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.h
+++ b/src/quick/scenegraph/coreapi/qsggeometry.h
@@ -54,15 +54,25 @@ public:
struct Q_QUICK_EXPORT Attribute
{
+ enum Semantic {
+ UNKNOWN,
+ POSITION,
+ COLOR,
+ TEXCOORD
+ };
+
int position;
int tupleSize;
int type;
uint isVertexCoordinate : 1;
- uint reserved : 31;
+ Semantic semantic : 4;
+
+ uint reserved : 27;
static Attribute create(int pos, int tupleSize, int primitiveType, bool isPosition = false);
+ static Attribute createWithSemantic(int pos, int tupleSize, int type, Semantic semantic);
};
struct AttributeSet {
@@ -104,12 +114,35 @@ public:
StaticPattern = 3
};
+ // Equivalents to GL_* drawing modes.
+ enum DrawingMode {
+ DrawPoints = 0x0000,
+ DrawLines = 0x0001,
+ DrawLineLoop = 0x0002,
+ DrawLineStrip = 0x0003,
+ DrawTriangles = 0x0004,
+ DrawTriangleStrip = 0x0005,
+ DrawTriangleFan = 0x0006
+ };
+
+ // Equivalents to GL_BYTE and similar type constants.
+ enum Type {
+ TypeByte = 0x1400,
+ TypeUnsignedByte = 0x1401,
+ TypeShort = 0x1402,
+ TypeUnsignedShort = 0x1403,
+ TypeInt = 0x1404,
+ TypeUnsignedInt = 0x1405,
+ TypeFloat = 0x1406
+ };
+
QSGGeometry(const QSGGeometry::AttributeSet &attribs,
int vertexCount,
int indexCount = 0,
- int indexType = GL_UNSIGNED_SHORT);
+ int indexType = TypeUnsignedShort);
virtual ~QSGGeometry();
+ // ### Qt 6: GL types to be removed from the public API
void setDrawingMode(GLenum mode);
inline GLenum drawingMode() const { return m_drawing_mode; }
@@ -187,25 +220,25 @@ private:
inline uint *QSGGeometry::indexDataAsUInt()
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ Q_ASSERT(m_index_type == TypeUnsignedInt);
return static_cast<uint *>(indexData());
}
inline quint16 *QSGGeometry::indexDataAsUShort()
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ Q_ASSERT(m_index_type == TypeUnsignedShort);
return static_cast<quint16 *>(indexData());
}
inline const uint *QSGGeometry::indexDataAsUInt() const
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ Q_ASSERT(m_index_type == TypeUnsignedInt);
return static_cast<const uint *>(indexData());
}
inline const quint16 *QSGGeometry::indexDataAsUShort() const
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ Q_ASSERT(m_index_type == TypeUnsignedShort);
return static_cast<const quint16 *>(indexData());
}
@@ -214,7 +247,7 @@ inline QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D()
Q_ASSERT(m_attributes.count == 1);
Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[0].position == 0);
return static_cast<Point2D *>(m_data);
}
@@ -225,10 +258,10 @@ inline QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D()
Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeFloat);
return static_cast<TexturedPoint2D *>(m_data);
}
@@ -238,10 +271,10 @@ inline QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D()
Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
- Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeUnsignedByte);
return static_cast<ColoredPoint2D *>(m_data);
}
@@ -250,7 +283,7 @@ inline const QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D() const
Q_ASSERT(m_attributes.count == 1);
Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[0].position == 0);
return static_cast<const Point2D *>(m_data);
}
@@ -261,10 +294,10 @@ inline const QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoin
Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeFloat);
return static_cast<const TexturedPoint2D *>(m_data);
}
@@ -274,18 +307,18 @@ inline const QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2
Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
- Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeUnsignedByte);
return static_cast<const ColoredPoint2D *>(m_data);
}
int QSGGeometry::sizeOfIndex() const
{
- if (m_index_type == GL_UNSIGNED_SHORT) return 2;
- else if (m_index_type == GL_UNSIGNED_BYTE) return 1;
- else if (m_index_type == GL_UNSIGNED_INT) return 4;
+ if (m_index_type == TypeUnsignedShort) return 2;
+ else if (m_index_type == TypeUnsignedByte) return 1;
+ else if (m_index_type == TypeUnsignedInt) return 4;
return 0;
}
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index d294e6f3ca..144f42da1c 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -204,6 +204,9 @@ public:
const QMatrix4x4 *matrix() const { return m_matrix; }
const QSGClipNode *clipList() const { return m_clip_list; }
+ void setMatrix(const QMatrix4x4 *matrix) { m_matrix = matrix; }
+ void setClipList(const QSGClipNode *clipList) { m_clip_list = clipList; }
+
protected:
QSGBasicGeometryNode(NodeType type);
QSGBasicGeometryNode(QSGBasicGeometryNodePrivate &dd, NodeType type);
diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp
index bc5d2a0a0d..87b4ed5b8e 100644
--- a/src/quick/scenegraph/qsgcontextplugin.cpp
+++ b/src/quick/scenegraph/qsgcontextplugin.cpp
@@ -45,6 +45,9 @@
// Built-in adaptations
#include <QtQuick/private/qsgdummyadaptation_p.h>
+#ifdef QSG_D3D12
+#include <QtQuick/private/qsgd3d12adaptation_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -81,6 +84,9 @@ QSGAdaptionBackendData::QSGAdaptionBackendData()
{
// Fill in the table with the built-in adaptations.
builtIns.append(new QSGDummyAdaptation);
+#ifdef QSG_D3D12
+ builtIns.append(new QSGD3D12Adaptation);
+#endif
}
Q_GLOBAL_STATIC(QSGAdaptionBackendData, qsg_adaptation_data)
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index 551575573e..9a219ece63 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -96,9 +96,9 @@ namespace
const QSGGeometry::AttributeSet &smoothAttributeSet()
{
static QSGGeometry::Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
- QSGGeometry::Attribute::create(1, 4, GL_UNSIGNED_BYTE, false),
- QSGGeometry::Attribute::create(2, 2, GL_FLOAT, false)
+ QSGGeometry::Attribute::create(0, 2, QSGGeometry::TypeFloat, true),
+ QSGGeometry::Attribute::create(1, 4, QSGGeometry::TypeUnsignedByte, false),
+ QSGGeometry::Attribute::create(2, 2, QSGGeometry::TypeFloat, false)
};
static QSGGeometry::AttributeSet attrs = { 3, sizeof(SmoothVertex), data };
return attrs;
@@ -184,7 +184,7 @@ QSGMaterialShader *QSGSmoothColorMaterial::createShader() const
}
-QSGDefaultRectangleNode::QSGDefaultRectangleNode()
+QSGDefaultNoMaterialRectangleNode::QSGDefaultNoMaterialRectangleNode()
: m_radius(0)
, m_pen_width(0)
, m_aligned(true)
@@ -194,14 +194,13 @@ QSGDefaultRectangleNode::QSGDefaultRectangleNode()
, m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
{
setGeometry(&m_geometry);
- setMaterial(&m_material);
#ifdef QSG_RUNTIME_DESCRIPTION
qsgnode_set_description(this, QLatin1String("rectangle"));
#endif
}
-void QSGDefaultRectangleNode::setRect(const QRectF &rect)
+void QSGDefaultNoMaterialRectangleNode::setRect(const QRectF &rect)
{
if (rect == m_rect)
return;
@@ -209,7 +208,7 @@ void QSGDefaultRectangleNode::setRect(const QRectF &rect)
m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::setColor(const QColor &color)
+void QSGDefaultNoMaterialRectangleNode::setColor(const QColor &color)
{
if (color == m_color)
return;
@@ -218,7 +217,7 @@ void QSGDefaultRectangleNode::setColor(const QColor &color)
m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::setPenColor(const QColor &color)
+void QSGDefaultNoMaterialRectangleNode::setPenColor(const QColor &color)
{
if (color == m_border_color)
return;
@@ -227,7 +226,7 @@ void QSGDefaultRectangleNode::setPenColor(const QColor &color)
m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::setPenWidth(qreal width)
+void QSGDefaultNoMaterialRectangleNode::setPenWidth(qreal width)
{
if (width == m_pen_width)
return;
@@ -236,7 +235,7 @@ void QSGDefaultRectangleNode::setPenWidth(qreal width)
}
-void QSGDefaultRectangleNode::setGradientStops(const QGradientStops &stops)
+void QSGDefaultNoMaterialRectangleNode::setGradientStops(const QGradientStops &stops)
{
if (stops.constData() == m_gradient_stops.constData())
return;
@@ -249,7 +248,7 @@ void QSGDefaultRectangleNode::setGradientStops(const QGradientStops &stops)
m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::setRadius(qreal radius)
+void QSGDefaultNoMaterialRectangleNode::setRadius(qreal radius)
{
if (radius == m_radius)
return;
@@ -257,24 +256,23 @@ void QSGDefaultRectangleNode::setRadius(qreal radius)
m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::setAntialiasing(bool antialiasing)
+void QSGDefaultNoMaterialRectangleNode::setAntialiasing(bool antialiasing)
{
if (antialiasing == m_antialiasing)
return;
m_antialiasing = antialiasing;
if (m_antialiasing) {
- setMaterial(&m_smoothMaterial);
setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
setFlag(OwnsGeometry, true);
} else {
- setMaterial(&m_material);
setGeometry(&m_geometry);
setFlag(OwnsGeometry, false);
}
+ updateMaterialAntialiasing();
m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::setAligned(bool aligned)
+void QSGDefaultNoMaterialRectangleNode::setAligned(bool aligned)
{
if (aligned == m_aligned)
return;
@@ -282,30 +280,19 @@ void QSGDefaultRectangleNode::setAligned(bool aligned)
m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::update()
+void QSGDefaultNoMaterialRectangleNode::update()
{
if (m_dirty_geometry) {
updateGeometry();
m_dirty_geometry = false;
QSGNode::DirtyState state = QSGNode::DirtyGeometry;
- // smoothed material is always blended, so no change in material state
- if (material() == &m_material) {
- bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
- bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
- || (m_color.alpha() < 255 && m_color.alpha() != 0)
- || (m_pen_width > 0 && m_border_color.alpha() < 255);
- if (wasBlending != isBlending) {
- m_material.setFlag(QSGMaterial::Blending, isBlending);
- state |= QSGNode::DirtyMaterial;
- }
- }
-
+ updateMaterialBlending(&state);
markDirty(state);
}
}
-void QSGDefaultRectangleNode::updateGeometry()
+void QSGDefaultNoMaterialRectangleNode::updateGeometry()
{
float width = float(m_rect.width());
float height = float(m_rect.height());
@@ -315,7 +302,7 @@ void QSGDefaultRectangleNode::updateGeometry()
penWidth = qRound(penWidth);
QSGGeometry *g = geometry();
- g->setDrawingMode(GL_TRIANGLE_STRIP);
+ g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
int vertexStride = g->sizeOfVertex();
union {
@@ -782,5 +769,32 @@ void QSGDefaultRectangleNode::updateGeometry()
}
}
+QSGDefaultRectangleNode::QSGDefaultRectangleNode()
+{
+ setMaterial(&m_material);
+}
+
+void QSGDefaultRectangleNode::updateMaterialAntialiasing()
+{
+ if (m_antialiasing)
+ setMaterial(&m_smoothMaterial);
+ else
+ setMaterial(&m_material);
+}
+
+void QSGDefaultRectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
+{
+ // smoothed material is always blended, so no change in material state
+ if (material() == &m_material) {
+ bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
+ bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
+ || (m_color.alpha() < 255 && m_color.alpha() != 0)
+ || (m_pen_width > 0 && m_border_color.alpha() < 255);
+ if (wasBlending != isBlending) {
+ m_material.setFlag(QSGMaterial::Blending, isBlending);
+ *state |= QSGNode::DirtyMaterial;
+ }
+ }
+}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
index 4cfe921127..61bf4fb4ae 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
@@ -68,32 +68,32 @@ public:
int compare(const QSGMaterial *other) const;
protected:
- virtual QSGMaterialType *type() const;
- virtual QSGMaterialShader *createShader() const;
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
};
-class Q_QUICK_PRIVATE_EXPORT QSGDefaultRectangleNode : public QSGRectangleNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultNoMaterialRectangleNode : public QSGRectangleNode
{
public:
- QSGDefaultRectangleNode();
+ QSGDefaultNoMaterialRectangleNode();
+
+ void setRect(const QRectF &rect) override;
+ void setColor(const QColor &color) override;
+ void setPenColor(const QColor &color) override;
+ void setPenWidth(qreal width) override;
+ void setGradientStops(const QGradientStops &stops) override;
+ void setRadius(qreal radius) override;
+ void setAntialiasing(bool antialiasing) override;
+ void setAligned(bool aligned) override;
+ void update() override;
- virtual void setRect(const QRectF &rect);
- virtual void setColor(const QColor &color);
- virtual void setPenColor(const QColor &color);
- virtual void setPenWidth(qreal width);
- virtual void setGradientStops(const QGradientStops &stops);
- virtual void setRadius(qreal radius);
- virtual void setAntialiasing(bool antialiasing);
- virtual void setAligned(bool aligned);
- virtual void update();
+protected:
+ virtual void updateMaterialAntialiasing() = 0;
+ virtual void updateMaterialBlending(QSGNode::DirtyState *state) = 0;
-private:
void updateGeometry();
void updateGradientTexture();
- QSGVertexColorMaterial m_material;
- QSGSmoothColorMaterial m_smoothMaterial;
-
QRectF m_rect;
QGradientStops m_gradient_stops;
QColor m_color;
@@ -109,6 +109,19 @@ private:
QSGGeometry m_geometry;
};
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultRectangleNode : public QSGDefaultNoMaterialRectangleNode
+{
+public:
+ QSGDefaultRectangleNode();
+
+private:
+ void updateMaterialAntialiasing() override;
+ void updateMaterialBlending(QSGNode::DirtyState *state) override;
+
+ QSGVertexColorMaterial m_material;
+ QSGSmoothColorMaterial m_smoothMaterial;
+};
+
QT_END_NAMESPACE
#endif
diff --git a/tests/manual/nodetypes/main.qml b/tests/manual/nodetypes/main.qml
new file mode 100644
index 0000000000..c4d0a5266d
--- /dev/null
+++ b/tests/manual/nodetypes/main.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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
+
+Item {
+ Rectangle {
+ width: 100
+ height: 100
+ anchors.centerIn: parent
+ color: "red"
+ NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; }
+ }
+
+ Rectangle {
+ color: "green"
+ width: 100
+ height: 200
+ x: 0
+ y: 0
+
+ NumberAnimation on x {
+ from: 0
+ to: 300
+ duration: 10000
+ }
+ }
+
+ Rectangle {
+ color: "blue"
+ width: 200
+ height: 100
+ x: 100
+ y: 300
+
+ SequentialAnimation on y {
+ loops: Animation.Infinite
+ NumberAnimation {
+ from: 300
+ to: 500
+ duration: 7000
+ }
+ NumberAnimation {
+ from: 500
+ to: 300
+ duration: 3000
+ }
+ }
+ }
+}
diff --git a/tests/manual/nodetypes/nodetypes.cpp b/tests/manual/nodetypes/nodetypes.cpp
new file mode 100644
index 0000000000..506a202ec7
--- /dev/null
+++ b/tests/manual/nodetypes/nodetypes.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 <QQuickView>
+
+int main(int argc, char **argv)
+{
+ qputenv("QT_QUICK_BACKEND", "d3d12");
+
+ QGuiApplication app(argc, argv);
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.resize(1024, 768);
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/tests/manual/nodetypes/nodetypes.pro b/tests/manual/nodetypes/nodetypes.pro
new file mode 100644
index 0000000000..c0b258d9ae
--- /dev/null
+++ b/tests/manual/nodetypes/nodetypes.pro
@@ -0,0 +1,7 @@
+QT += qml quick
+
+SOURCES += nodetypes.cpp
+
+RESOURCES += nodetypes.qrc
+
+OTHER_FILES += main.qml
diff --git a/tests/manual/nodetypes/nodetypes.qrc b/tests/manual/nodetypes/nodetypes.qrc
new file mode 100644
index 0000000000..5f6483ac33
--- /dev/null
+++ b/tests/manual/nodetypes/nodetypes.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>