aboutsummaryrefslogtreecommitdiffstats
path: root/examples/quick
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2020-01-15 09:08:24 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2020-04-11 18:23:55 +0200
commit400d176760de84626500787674b1ece387b25893 (patch)
treedbb8b5fd50440e6c01d6b940fe1692ba8e6a1f5c /examples/quick
parent654959e2e2b74855036f949a9c23c9d9c7a614ac (diff)
Allow redirecting QRhi-based rendering via QQuickRenderControl
Implement the Qt 6 TODO for using an externally-provided render target when rendering the scene via QRhi. And say hello to QQuickRenderTarget. This class exists to allow potentially extending later what a "render target" consists of. Instead of hard-coding taking a single void * in the setRenderTarget() function, it takes a (implicitly shared, d-pointered) QQuickRenderTarget, which in turn can be created via static factory functions - of which new ones can be added later on. The new version of QQuickWindow::setRenderTarget() takes a QQuickRenderTarget. QQuickRenderControl gets a new initialize() variant, and a few extra functions (beginFrame(), endFrame()). This allows it to, by using QSGRhiSupport internally, create a QRhi under the hood. As a bonus, this also fixes an existing scenegraph resource leak when destroying the QQuickRenderControl. The qquickrendercontrol autotest is extended, with a QRhi-based test case that is executed for all of the QRhi backends that succeed to initialize. This is the internal verification. In addition, there is a Vulkan-based one that creates its own VkDevice, VkImage, and friends, and then uses Qt Quick with the same Vulkan device, targeting the VkImage. This test verifies the typical application use case. (sadly, life is too short to waste it on writing Vulkan boilerplate for an on-screen version of this, but we have the D3D11 example instead) What QQuickRenderControl loses, when used in combination with QRhi, is the grab() function. This never made much sense as a public API: QQuickWindow::grabWindow() call this when the window is associated with a rendercontrol, so as a public API QQuickRenderControl::grab() is redundant, because one gets the same result via the standard QQuickWindow API. It is now made private. More importantly, reading back the content is no longer supported, unless the 'software' backend is in use. The reasoning here is that, if the client of the API manages and provides the render target (as abstracted by QQuickRenderTarget), it is then expected to be capable of reading back the content in whatever way it sees fit, because it owns and manages the resource (e.g. the texture) in the first place. Providing fragile convenience functions for this is not reasonable anymore, and was questionable even with OpenGL, given that it is not future proof - what if the target is suddenly a floating point texture, for instance? The software backend case makes sense because that relies on private APIs - and has no render target concept either - so there the same cannot be achieved by applications by relying on public APIs only. Another new class is QQuickGraphicsDevice. This is very similar to QQuickRenderTarget, it is a simple container capable of holding a set of of native objects, mostly in the form of void*s, with future extensibility thanks to the static factory functions. (examples of native object sets would be a ID3D11Device + ID3D11DeviceContext, or a QOpenGLContext, or a MTLDevice + MTLCommandQueue, or a number of Vulkan device-related objects, etc.) This allows one to specify that the QRhi created under the hood (either by QQuickRenderControl or by the render loop) should use an existing graphics device (i.e. it is basically a public wrapper for values that go into a QRhi*InitParams under the hood). QQuickRenderTarget and QQuickGraphicsDevice are both demonstrated in a new example: rendercontrol_d3d11. We choose D3D11 because it is reasonably simple to set up a renderer with a window, and, because there is known user demand for Qt Quick - external D3D engine interop. Passing in the custom engine's own ID3D11Device and ID3D11DeviceContext is essential: the texture (ID3D11Texture2D) Qt Quick is targeting would not be usable if Qt Quick's QRhi was using a different ID3D11Device. Task-number: QTBUG-78595 Change-Id: I5dfe7f6cf1540daffc2f11136be114a08e87202b Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'examples/quick')
-rw-r--r--examples/quick/rendercontrol/rendercontrol.pro7
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/CMakeLists.txt51
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/buildshaders.bat2
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/demo.qml208
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/doc/images/rendercontrol-d3d11-example.jpgbin0 -> 48486 bytes
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/doc/src/rendercontrol_d3d11.qdoc33
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp241
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/engine.h95
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/main.cpp79
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag19
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag.inc144
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert36
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert.inc166
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol.qrc5
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol_d3d11.pro19
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/window.cpp389
-rw-r--r--examples/quick/rendercontrol/rendercontrol_d3d11/window.h100
-rw-r--r--examples/quick/rendercontrol/rendercontrol_opengl/doc/images/rendercontrol-opengl-example.jpg (renamed from examples/quick/rendercontrol/rendercontrol_opengl/doc/images/rendercontrol-example.jpg)bin44196 -> 44196 bytes
-rw-r--r--examples/quick/rendercontrol/rendercontrol_opengl/doc/src/rendercontrol_opengl.qdoc (renamed from examples/quick/rendercontrol/rendercontrol_opengl/doc/src/rendercontrol.qdoc)4
19 files changed, 1595 insertions, 3 deletions
diff --git a/examples/quick/rendercontrol/rendercontrol.pro b/examples/quick/rendercontrol/rendercontrol.pro
index cdb431c8fd..d49be63c50 100644
--- a/examples/quick/rendercontrol/rendercontrol.pro
+++ b/examples/quick/rendercontrol/rendercontrol.pro
@@ -1,4 +1,9 @@
TEMPLATE = subdirs
-SUBDIRS = \
+SUBDIRS += \
rendercontrol_opengl
+
+win32 {
+ SUBDIRS += \
+ rendercontrol_d3d11
+}
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/CMakeLists.txt b/examples/quick/rendercontrol/rendercontrol_d3d11/CMakeLists.txt
new file mode 100644
index 0000000000..c2f7a1f806
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/CMakeLists.txt
@@ -0,0 +1,51 @@
+# Generated from rendercontrol_d3d11.pro.
+
+cmake_minimum_required(VERSION 3.14)
+project(rendercontrol_d3d11 LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+set(INSTALL_EXAMPLEDIR "examples/quick/rendercontrol/rendercontrol_d3d11")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Quick)
+find_package(Qt6 COMPONENTS Qml)
+
+add_qt_gui_executable(rendercontrol_d3d11
+ engine.cpp engine.h
+ main.cpp
+ window.cpp window.h
+)
+target_link_libraries(rendercontrol_d3d11 PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Qml
+ Qt::Quick
+ d3d11
+ dxgi
+ dxguid
+)
+
+
+# Resources:
+set(rendercontrol_resource_files
+ "demo.qml"
+)
+
+qt6_add_resources(rendercontrol_d3d11 "rendercontrol"
+ PREFIX
+ "/rendercontrol"
+ FILES
+ ${rendercontrol_resource_files}
+)
+
+install(TARGETS rendercontrol_d3d11
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/buildshaders.bat b/examples/quick/rendercontrol/rendercontrol_d3d11/buildshaders.bat
new file mode 100644
index 0000000000..aedcde2d59
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/buildshaders.bat
@@ -0,0 +1,2 @@
+fxc /T vs_5_0 /E quad_vs_main /Fh quad.vert.inc quad.vert
+fxc /T ps_5_0 /E quad_ps_main /Fh quad.frag.inc quad.frag
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/demo.qml b/examples/quick/rendercontrol/rendercontrol_d3d11/demo.qml
new file mode 100644
index 0000000000..32e2f423d1
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/demo.qml
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Particles 2.0
+
+Rectangle {
+ id: root
+
+ gradient: Gradient {
+ GradientStop { position: 0; color: mouse.pressed ? "lightsteelblue" : "steelblue" }
+ GradientStop { position: 1; color: "black" }
+ }
+
+ Text {
+ anchors.centerIn: parent
+ text: "Qt Quick scene rendered to a ID3D11Texture2D"
+ font.pointSize: 32
+ color: "white"
+
+ SequentialAnimation on rotation {
+ PauseAnimation { duration: 2500 }
+ NumberAnimation { from: 0; to: 360; duration: 5000; easing.type: Easing.InOutCubic }
+ loops: Animation.Infinite
+ }
+ }
+
+ ParticleSystem {
+ id: particles
+ anchors.fill: parent
+
+ ImageParticle {
+ id: smoke
+ system: particles
+ anchors.fill: parent
+ groups: ["A", "B"]
+ source: "qrc:///particleresources/glowdot.png"
+ colorVariation: 0
+ color: "#00111111"
+ }
+ ImageParticle {
+ id: flame
+ anchors.fill: parent
+ system: particles
+ groups: ["C", "D"]
+ source: "qrc:///particleresources/glowdot.png"
+ colorVariation: 0.1
+ color: "#00ff400f"
+ }
+
+ Emitter {
+ id: fire
+ system: particles
+ group: "C"
+
+ y: parent.height
+ width: parent.width
+
+ emitRate: 350
+ lifeSpan: 3500
+
+ acceleration: PointDirection { y: -17; xVariation: 3 }
+ velocity: PointDirection {xVariation: 3}
+
+ size: 24
+ sizeVariation: 8
+ endSize: 4
+ }
+
+ TrailEmitter {
+ id: fireSmoke
+ group: "B"
+ system: particles
+ follow: "C"
+ width: root.width
+ height: root.height - 68
+
+ emitRatePerParticle: 1
+ lifeSpan: 2000
+
+ velocity: PointDirection {y:-17*6; yVariation: -17; xVariation: 3}
+ acceleration: PointDirection {xVariation: 3}
+
+ size: 36
+ sizeVariation: 8
+ endSize: 16
+ }
+
+ TrailEmitter {
+ id: fireballFlame
+ anchors.fill: parent
+ system: particles
+ group: "D"
+ follow: "E"
+
+ emitRatePerParticle: 120
+ lifeSpan: 180
+ emitWidth: TrailEmitter.ParticleSize
+ emitHeight: TrailEmitter.ParticleSize
+ emitShape: EllipseShape{}
+
+ size: 16
+ sizeVariation: 4
+ endSize: 4
+ }
+
+ TrailEmitter {
+ id: fireballSmoke
+ anchors.fill: parent
+ system: particles
+ group: "A"
+ follow: "E"
+
+ emitRatePerParticle: 128
+ lifeSpan: 2400
+ emitWidth: TrailEmitter.ParticleSize
+ emitHeight: TrailEmitter.ParticleSize
+ emitShape: EllipseShape{}
+
+ velocity: PointDirection {yVariation: 16; xVariation: 16}
+ acceleration: PointDirection {y: -16}
+
+ size: 24
+ sizeVariation: 8
+ endSize: 8
+ }
+
+ Emitter {
+ id: balls
+ system: particles
+ group: "E"
+
+ y: parent.height
+ width: parent.width
+
+ emitRate: 2
+ lifeSpan: 7000
+
+ velocity: PointDirection {y:-17*4*2; xVariation: 6*6}
+ acceleration: PointDirection {y: 17*2; xVariation: 6*6}
+
+ size: 8
+ sizeVariation: 4
+ }
+
+ Turbulence { //A bit of turbulence makes the smoke look better
+ anchors.fill: parent
+ groups: ["A","B"]
+ strength: 32
+ system: particles
+ }
+ }
+
+ onWidthChanged: particles.reset()
+ onHeightChanged: particles.reset()
+
+ MouseArea {
+ id: mouse
+ anchors.fill: parent
+ }
+}
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/doc/images/rendercontrol-d3d11-example.jpg b/examples/quick/rendercontrol/rendercontrol_d3d11/doc/images/rendercontrol-d3d11-example.jpg
new file mode 100644
index 0000000000..4d56a946cc
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/doc/images/rendercontrol-d3d11-example.jpg
Binary files differ
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/doc/src/rendercontrol_d3d11.qdoc b/examples/quick/rendercontrol/rendercontrol_d3d11/doc/src/rendercontrol_d3d11.qdoc
new file mode 100644
index 0000000000..63f5477ff4
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/doc/src/rendercontrol_d3d11.qdoc
@@ -0,0 +1,33 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \title QQuickRenderControl D3D11 Example
+ \example rendercontrol/rendercontrol_d3d11
+ \brief Shows how to render a Qt Quick scene into a texture that is then used by a non-Quick based Direct3D 11 renderer.
+ \image rendercontrol-d3d11-example.jpg
+*/
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp b/examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp
new file mode 100644
index 0000000000..be1f6d842c
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "engine.h"
+#include <QLibrary>
+#include <comdef.h>
+
+#define ENABLE_DEBUG_LAYER
+
+Engine::~Engine()
+{
+ RELEASE(m_context);
+ RELEASE(m_device);
+ RELEASE(m_dxgiFactory);
+}
+
+QString comErrorMessage(HRESULT hr)
+{
+#ifndef Q_OS_WINRT
+ const _com_error comError(hr);
+#else
+ const _com_error comError(hr, nullptr);
+#endif
+ QString result = QLatin1String("Error 0x") + QString::number(ulong(hr), 16);
+ if (const wchar_t *msg = comError.ErrorMessage())
+ result += QLatin1String(": ") + QString::fromWCharArray(msg);
+ return result;
+}
+
+bool Engine::create()
+{
+ using PtrCreateDXGIFactory2 = HRESULT (WINAPI *)(UINT, REFIID, void **);
+ QLibrary dxgilib(QStringLiteral("dxgi"));
+ if (auto createDXGIFactory2 = reinterpret_cast<PtrCreateDXGIFactory2>(dxgilib.resolve("CreateDXGIFactory2"))) {
+ const HRESULT hr = createDXGIFactory2(0, IID_IDXGIFactory2, reinterpret_cast<void **>(&m_dxgiFactory));
+ if (FAILED(hr)) {
+ qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+ } else {
+ qWarning("Unable to resolve CreateDXGIFactory2()");
+ return false;
+ }
+
+ ID3D11DeviceContext *ctx = nullptr;
+ uint flags = 0;
+#ifdef ENABLE_DEBUG_LAYER
+ flags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+ // use the default hardware adapter
+ HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags,
+ nullptr, 0, D3D11_SDK_VERSION,
+ &m_device, &m_featureLevel, &ctx);
+ if (FAILED(hr)) {
+ qWarning("Failed to create D3D11 device and context: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+
+ if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&m_context)))) {
+ ctx->Release();
+ } else {
+ qWarning("ID3D11DeviceContext1 not supported");
+ return false;
+ }
+
+ return true;
+}
+
+QSize Engine::swapchainSizeForWindow(QWindow *window) const
+{
+ const QSize size = window->size() * window->devicePixelRatio();
+ return QSize(qMax(8, size.width()), qMax(8, size.height()));
+}
+
+Swapchain Engine::createSwapchain(QWindow *window)
+{
+ Swapchain sc = {};
+ const HWND hwnd = reinterpret_cast<HWND>(window->winId());
+ const QSize pixelSize = swapchainSizeForWindow(window);
+
+ // only care about flip discard swapchains here; the old stuff (discard) is
+ // not supported in this example
+
+ DXGI_SWAP_CHAIN_DESC1 desc = {};
+ desc.Width = UINT(pixelSize.width());
+ desc.Height = UINT(pixelSize.height());
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ desc.BufferCount = 2;
+ desc.Scaling = DXGI_SCALING_STRETCH;
+ desc.SwapEffect = DXGI_SWAP_EFFECT(4); // DXGI_SWAP_EFFECT_FLIP_DISCARD
+
+ IDXGISwapChain1 *swapchain = nullptr;
+ HRESULT hr = static_cast<IDXGIFactory2 *>(m_dxgiFactory)->CreateSwapChainForHwnd(m_device, hwnd, &desc,
+ nullptr, nullptr, &swapchain);
+ if (FAILED(hr)) {
+ qWarning("Failed to create D3D11 swapchain: %s", qPrintable(comErrorMessage(hr)));
+ return sc;
+ }
+
+ sc.swapchain = swapchain;
+ sc.pixelSize = pixelSize;
+ createSwapchainBuffers(&sc);
+ return sc;
+}
+
+void Engine::createSwapchainBuffers(Swapchain *sc)
+{
+ ID3D11Texture2D *tex = nullptr;
+ HRESULT hr = sc->swapchain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast<void **>(&tex));
+ if (FAILED(hr)) {
+ qWarning("Failed to query swapchain backbuffer: %s", qPrintable(comErrorMessage(hr)));
+ return;
+ }
+
+ ID3D11RenderTargetView *rtv = nullptr;
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
+ rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ hr = m_device->CreateRenderTargetView(tex, &rtvDesc, &rtv);
+ if (FAILED(hr)) {
+ qWarning("Failed to create rtv for swapchain backbuffer: %s", qPrintable(comErrorMessage(hr)));
+ tex->Release();
+ return;
+ }
+
+ D3D11_TEXTURE2D_DESC texDesc = {};
+ texDesc.Width = UINT(sc->pixelSize.width());
+ texDesc.Height = UINT(sc->pixelSize.height());
+ texDesc.MipLevels = 1;
+ texDesc.ArraySize = 1;
+ texDesc.SampleDesc.Count = 1;
+ texDesc.Usage = D3D11_USAGE_DEFAULT;
+ texDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
+ texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+
+ ID3D11Texture2D *ds = nullptr;
+ hr = m_device->CreateTexture2D(&texDesc, nullptr, &ds);
+ if (FAILED(hr)) {
+ qWarning("Failed to create depth-stencil buffer: %s", qPrintable(comErrorMessage(hr)));
+ tex->Release();
+ rtv->Release();
+ return;
+ }
+
+ ID3D11DepthStencilView *dsv = nullptr;
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
+ dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+ hr = m_device->CreateDepthStencilView(ds, &dsvDesc, &dsv);
+ if (FAILED(hr)) {
+ qWarning("Failed to create dsv: %s", qPrintable(comErrorMessage(hr)));
+ tex->Release();
+ rtv->Release();
+ ds->Release();
+ return;
+ }
+
+ sc->tex = tex;
+ sc->rtv = rtv;
+ sc->ds = ds;
+ sc->dsv = dsv;
+}
+
+void Engine::resizeSwapchain(Swapchain *sc, QWindow *window)
+{
+ const QSize pixelSize = swapchainSizeForWindow(window);
+
+ RELEASE(sc->dsv);
+ RELEASE(sc->ds);
+ RELEASE(sc->rtv);
+ RELEASE(sc->tex);
+
+ HRESULT hr = sc->swapchain->ResizeBuffers(2, UINT(pixelSize.width()), UINT(pixelSize.height()),
+ DXGI_FORMAT_R8G8B8A8_UNORM, 0);
+ if (FAILED(hr)) {
+ qWarning("Failed to resize D3D11 swapchain: %s", qPrintable(comErrorMessage(hr)));
+ return;
+ }
+
+ sc->pixelSize = pixelSize;
+ createSwapchainBuffers(sc);
+}
+
+void Swapchain::destroy()
+{
+ RELEASE(dsv);
+ RELEASE(ds);
+ RELEASE(rtv);
+ RELEASE(tex);
+ RELEASE(swapchain);
+ pixelSize = QSize();
+}
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/engine.h b/examples/quick/rendercontrol/rendercontrol_d3d11/engine.h
new file mode 100644
index 0000000000..8b1b3ebf39
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/engine.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <QWindow>
+
+#include <d3d11_1.h>
+#include <dxgi1_3.h>
+
+#define RELEASE(obj) { if (obj) { obj->Release(); obj = nullptr; } }
+
+QString comErrorMessage(HRESULT hr);
+
+struct Swapchain
+{
+ IDXGISwapChain1 *swapchain;
+ ID3D11Texture2D *tex;
+ ID3D11RenderTargetView *rtv;
+ ID3D11Texture2D *ds;
+ ID3D11DepthStencilView *dsv;
+ QSize pixelSize;
+
+ void destroy();
+};
+
+class Engine
+{
+public:
+ ~Engine();
+ bool create();
+ QSize swapchainSizeForWindow(QWindow *window) const;
+ Swapchain createSwapchain(QWindow *window);
+ void resizeSwapchain(Swapchain *sc, QWindow *window);
+ ID3D11Device *device() { return m_device; }
+ ID3D11DeviceContext1 *context() { return m_context; }
+
+private:
+ void createSwapchainBuffers(Swapchain *sc);
+
+ IDXGIFactory1 *m_dxgiFactory = nullptr;
+ ID3D11Device *m_device = nullptr;
+ ID3D11DeviceContext1 *m_context = nullptr;
+ D3D_FEATURE_LEVEL m_featureLevel;
+};
+
+#endif
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/main.cpp b/examples/quick/rendercontrol/rendercontrol_d3d11/main.cpp
new file mode 100644
index 0000000000..f9a1dbb75f
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/main.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This example is only functional on Windows with Direct 3D 11.
+
+#include <QGuiApplication>
+#include <QQuickWindow>
+#include "engine.h"
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ QCoreApplication::setApplicationName("Qt Render Control D3D11 Example");
+ QCoreApplication::setOrganizationName("QtProject");
+ QCoreApplication::setApplicationVersion(QT_VERSION_STR);
+
+ // only functional when Qt Quick is also using D3D11
+ QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Direct3D11Rhi);
+
+ Engine engine;
+ if (!engine.create())
+ qFatal("Failed to initialize D3D (this example requires D3D 11.1 and DXGI 1.3)");
+
+ Window window(&engine);
+
+ window.resize(1024, 768);
+ window.show();
+
+ return app.exec();
+}
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag
new file mode 100644
index 0000000000..09914ccdbe
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag
@@ -0,0 +1,19 @@
+struct PSIn
+{
+ float2 coord : TEXCOORD0;
+};
+
+struct PSOut
+{
+ float4 color : SV_Target;
+};
+
+Texture2D tex : register(t0);
+SamplerState samp : register(s0);
+
+PSOut quad_ps_main(PSIn input)
+{
+ PSOut output;
+ output.color = tex.Sample(samp, input.coord);
+ return output;
+}
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag.inc b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag.inc
new file mode 100644
index 0000000000..495db447dd
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.frag.inc
@@ -0,0 +1,144 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim HLSL Bind Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// samp sampler NA NA s0 1
+// tex texture float4 2d t0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// TEXCOORD 0 xy 0 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target 0 xyzw 0 TARGET float xyzw
+//
+ps_5_0
+dcl_globalFlags refactoringAllowed
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v0.xy
+dcl_output o0.xyzw
+sample_indexable(texture2d)(float,float,float,float) o0.xyzw, v0.xyxx, t0.xyzw, s0
+ret
+// Approximately 2 instruction slots used
+#endif
+
+const BYTE g_quad_ps_main[] =
+{
+ 68, 88, 66, 67, 206, 95,
+ 68, 205, 198, 6, 36, 106,
+ 90, 50, 92, 169, 136, 220,
+ 65, 219, 1, 0, 0, 0,
+ 104, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 236, 0, 0, 0, 32, 1,
+ 0, 0, 84, 1, 0, 0,
+ 204, 1, 0, 0, 82, 68,
+ 69, 70, 176, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 60, 0, 0, 0, 0, 5,
+ 255, 255, 0, 1, 0, 0,
+ 133, 0, 0, 0, 82, 68,
+ 49, 49, 60, 0, 0, 0,
+ 24, 0, 0, 0, 32, 0,
+ 0, 0, 40, 0, 0, 0,
+ 36, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0,
+ 124, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 129, 0, 0, 0,
+ 2, 0, 0, 0, 5, 0,
+ 0, 0, 4, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 13, 0, 0, 0, 115, 97,
+ 109, 112, 0, 116, 101, 120,
+ 0, 77, 105, 99, 114, 111,
+ 115, 111, 102, 116, 32, 40,
+ 82, 41, 32, 72, 76, 83,
+ 76, 32, 83, 104, 97, 100,
+ 101, 114, 32, 67, 111, 109,
+ 112, 105, 108, 101, 114, 32,
+ 49, 48, 46, 49, 0, 171,
+ 171, 171, 73, 83, 71, 78,
+ 44, 0, 0, 0, 1, 0,
+ 0, 0, 8, 0, 0, 0,
+ 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 0, 0,
+ 84, 69, 88, 67, 79, 79,
+ 82, 68, 0, 171, 171, 171,
+ 79, 83, 71, 78, 44, 0,
+ 0, 0, 1, 0, 0, 0,
+ 8, 0, 0, 0, 32, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 15, 0, 0, 0, 83, 86,
+ 95, 84, 97, 114, 103, 101,
+ 116, 0, 171, 171, 83, 72,
+ 69, 88, 112, 0, 0, 0,
+ 80, 0, 0, 0, 28, 0,
+ 0, 0, 106, 8, 0, 1,
+ 90, 0, 0, 3, 0, 96,
+ 16, 0, 0, 0, 0, 0,
+ 88, 24, 0, 4, 0, 112,
+ 16, 0, 0, 0, 0, 0,
+ 85, 85, 0, 0, 98, 16,
+ 0, 3, 50, 16, 16, 0,
+ 0, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 0, 0, 0, 0, 69, 0,
+ 0, 139, 194, 0, 0, 128,
+ 67, 85, 21, 0, 242, 32,
+ 16, 0, 0, 0, 0, 0,
+ 70, 16, 16, 0, 0, 0,
+ 0, 0, 70, 126, 16, 0,
+ 0, 0, 0, 0, 0, 96,
+ 16, 0, 0, 0, 0, 0,
+ 62, 0, 0, 1, 83, 84,
+ 65, 84, 148, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert
new file mode 100644
index 0000000000..a6ba07f686
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert
@@ -0,0 +1,36 @@
+struct VSIn
+{
+ uint id : SV_VertexId;
+};
+
+struct VSOut
+{
+ float2 coord : TEXCOORD0;
+ float4 pos : SV_Position;
+};
+
+static const float2 quadPos[6] = {
+ float2(-0.5, 0.5),
+ float2(0.5, -0.5),
+ float2(-0.5, -0.5),
+ float2(0.5, 0.5),
+ float2(0.5, -0.5),
+ float2(-0.5, 0.5)
+};
+
+static const float2 quadUv[6] = {
+ float2(0.0, 0.0),
+ float2(1.0, 1.0),
+ float2(0.0, 1.0),
+ float2(1.0, 0.0),
+ float2(1.0, 1.0),
+ float2(0.0, 0.0),
+};
+
+VSOut quad_vs_main(VSIn input)
+{
+ VSOut output;
+ output.pos = float4(quadPos[input.id].xy, 0.0, 1.0);
+ output.coord = quadUv[input.id];
+ return output;
+}
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert.inc b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert.inc
new file mode 100644
index 0000000000..6af657f775
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/quad.vert.inc
@@ -0,0 +1,166 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_VertexId 0 x 0 VERTID uint x
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// TEXCOORD 0 xy 0 NONE float xy
+// SV_Position 0 xyzw 1 POS float xyzw
+//
+vs_5_0
+dcl_globalFlags refactoringAllowed
+dcl_immediateConstantBuffer { { -0.500000, 0.500000, 0, 0},
+ { 0.500000, -0.500000, 1.000000, 1.000000},
+ { -0.500000, -0.500000, 0, 1.000000},
+ { 0.500000, 0.500000, 1.000000, 0},
+ { 0.500000, -0.500000, 1.000000, 1.000000},
+ { -0.500000, 0.500000, 0, 0} }
+dcl_input_sgv v0.x, vertex_id
+dcl_output o0.xy
+dcl_output_siv o1.xyzw, position
+dcl_temps 1
+mov r0.x, v0.x
+mov o0.xy, icb[r0.x + 0].zwzz
+mov o1.xy, icb[r0.x + 0].xyxx
+mov o1.zw, l(0,0,0,1.000000)
+ret
+// Approximately 5 instruction slots used
+#endif
+
+const BYTE g_quad_vs_main[] =
+{
+ 68, 88, 66, 67, 34, 115,
+ 52, 103, 138, 223, 96, 45,
+ 170, 110, 183, 248, 246, 24,
+ 17, 250, 1, 0, 0, 0,
+ 224, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 160, 0, 0, 0, 212, 0,
+ 0, 0, 44, 1, 0, 0,
+ 68, 2, 0, 0, 82, 68,
+ 69, 70, 100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 60, 0, 0, 0, 0, 5,
+ 254, 255, 0, 1, 0, 0,
+ 60, 0, 0, 0, 82, 68,
+ 49, 49, 60, 0, 0, 0,
+ 24, 0, 0, 0, 32, 0,
+ 0, 0, 40, 0, 0, 0,
+ 36, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0,
+ 77, 105, 99, 114, 111, 115,
+ 111, 102, 116, 32, 40, 82,
+ 41, 32, 72, 76, 83, 76,
+ 32, 83, 104, 97, 100, 101,
+ 114, 32, 67, 111, 109, 112,
+ 105, 108, 101, 114, 32, 49,
+ 48, 46, 49, 0, 73, 83,
+ 71, 78, 44, 0, 0, 0,
+ 1, 0, 0, 0, 8, 0,
+ 0, 0, 32, 0, 0, 0,
+ 0, 0, 0, 0, 6, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1,
+ 0, 0, 83, 86, 95, 86,
+ 101, 114, 116, 101, 120, 73,
+ 100, 0, 79, 83, 71, 78,
+ 80, 0, 0, 0, 2, 0,
+ 0, 0, 8, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 3, 12, 0, 0,
+ 65, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 15, 0, 0, 0,
+ 84, 69, 88, 67, 79, 79,
+ 82, 68, 0, 83, 86, 95,
+ 80, 111, 115, 105, 116, 105,
+ 111, 110, 0, 171, 171, 171,
+ 83, 72, 69, 88, 16, 1,
+ 0, 0, 80, 0, 1, 0,
+ 68, 0, 0, 0, 106, 8,
+ 0, 1, 53, 24, 0, 0,
+ 26, 0, 0, 0, 0, 0,
+ 0, 191, 0, 0, 0, 63,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 63,
+ 0, 0, 0, 191, 0, 0,
+ 128, 63, 0, 0, 128, 63,
+ 0, 0, 0, 191, 0, 0,
+ 0, 191, 0, 0, 0, 0,
+ 0, 0, 128, 63, 0, 0,
+ 0, 63, 0, 0, 0, 63,
+ 0, 0, 128, 63, 0, 0,
+ 0, 0, 0, 0, 0, 63,
+ 0, 0, 0, 191, 0, 0,
+ 128, 63, 0, 0, 128, 63,
+ 0, 0, 0, 191, 0, 0,
+ 0, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 96, 0,
+ 0, 4, 18, 16, 16, 0,
+ 0, 0, 0, 0, 6, 0,
+ 0, 0, 101, 0, 0, 3,
+ 50, 32, 16, 0, 0, 0,
+ 0, 0, 103, 0, 0, 4,
+ 242, 32, 16, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 104, 0, 0, 2, 1, 0,
+ 0, 0, 54, 0, 0, 5,
+ 18, 0, 16, 0, 0, 0,
+ 0, 0, 10, 16, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 6, 50, 32, 16, 0,
+ 0, 0, 0, 0, 230, 154,
+ 144, 0, 10, 0, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 6, 50, 32, 16, 0,
+ 1, 0, 0, 0, 70, 144,
+ 144, 0, 10, 0, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 8, 194, 32, 16, 0,
+ 1, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 128, 63,
+ 62, 0, 0, 1, 83, 84,
+ 65, 84, 148, 0, 0, 0,
+ 5, 0, 0, 0, 1, 0,
+ 0, 0, 6, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol.qrc b/examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol.qrc
new file mode 100644
index 0000000000..2246eeb842
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/rendercontrol">
+ <file>demo.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol_d3d11.pro b/examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol_d3d11.pro
new file mode 100644
index 0000000000..29cee7580b
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/rendercontrol_d3d11.pro
@@ -0,0 +1,19 @@
+TEMPLATE = app
+
+QT += quick qml
+
+SOURCES += \
+ main.cpp \
+ window.cpp \
+ engine.cpp
+
+HEADERS += \
+ window.h \
+ engine.h
+
+RESOURCES += rendercontrol.qrc
+
+LIBS += -ld3d11 -ldxgi -ldxguid
+
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/rendercontrol/rendercontrol_d3d11
+INSTALLS += target
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/window.cpp b/examples/quick/rendercontrol/rendercontrol_d3d11/window.cpp
new file mode 100644
index 0000000000..cb84371fed
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/window.cpp
@@ -0,0 +1,389 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include <QCoreApplication>
+#include <QMouseEvent>
+#include <QQuickRenderControl>
+#include <QQuickWindow>
+#include <QQuickItem>
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QQuickRenderTarget>
+#include <QQuickGraphicsDevice>
+
+#include "quad.vert.inc"
+#include "quad.frag.inc"
+
+// In this example the Qt Quick scene will always render at 720p regardless of
+// the window size.
+const int QML_WIDTH = 1280;
+const int QML_HEIGHT = 720;
+
+// Set to 4 or 8 to enable MSAA. This will lead to creating a multisample
+// texture, passing in the sample count to Qt Quick (so it sets the graphics
+// pipelines up as appropriate), and then doing a resolve to a non-multisample
+// texture every time Quick has rendered its content.
+const int SAMPLE_COUNT = 1;
+
+// by subclassing QQuickRenderControl we gain the ability to report a QWindow
+// to which certain operations, such as the querying of devicePixelRatio()
+// should be redirected
+class RenderControl : public QQuickRenderControl
+{
+public:
+ RenderControl(QWindow *w) : m_window(w) { }
+ QWindow *renderWindow(QPoint *offset) override;
+
+private:
+ QWindow *m_window;
+};
+
+QWindow *RenderControl::renderWindow(QPoint *offset)
+{
+ if (offset)
+ *offset = QPoint(0, 0);
+ return m_window;
+}
+
+Window::Window(Engine *engine)
+ : m_engine(engine)
+{
+ setSurfaceType(QSurface::OpenGLSurface);
+
+ m_renderControl = new RenderControl(this);
+
+ // Whenever something changed in the Quick scene, or rendering was
+ // requested via others means (e.g. QQuickWindow::update()), it should
+ // trigger rendering into the texture when preparing the next frame.
+ connect(m_renderControl, &QQuickRenderControl::renderRequested, this, [this] { m_quickDirty = true; });
+ connect(m_renderControl, &QQuickRenderControl::sceneChanged, this, [this] { m_quickDirty = true; });
+
+ // Note that on its own this is not sufficient to get MSAA, the render
+ // target (the texture in this case) must be set up accordingly as well,
+ // and the sample count also needs to be passed to
+ // QQuickRenderTarget::fromNativeTexture().
+ m_renderControl->setSamples(SAMPLE_COUNT);
+
+ // Create a QQuickWindow that is associated with out render control. Note that this
+ // window never gets created or shown, meaning that it will never get an underlying
+ // native (platform) window.
+ m_quickWindow = new QQuickWindow(m_renderControl);
+
+ m_qmlEngine = new QQmlEngine;
+ m_qmlComponent = new QQmlComponent(m_qmlEngine, QUrl(QLatin1String("qrc:/rendercontrol/demo.qml")));
+ if (m_qmlComponent->isError()) {
+ for (const QQmlError &error : m_qmlComponent->errors())
+ qWarning() << error.url() << error.line() << error;
+ }
+
+ QObject *rootObject = m_qmlComponent->create();
+ if (m_qmlComponent->isError()) {
+ for (const QQmlError &error : m_qmlComponent->errors())
+ qWarning() << error.url() << error.line() << error;
+ }
+
+ QQuickItem *rootItem = qobject_cast<QQuickItem *>(rootObject);
+ rootItem->setSize(QSize(QML_WIDTH, QML_HEIGHT));
+ m_quickWindow->contentItem()->setSize(rootItem->size());
+ m_quickWindow->setGeometry(0, 0, rootItem->width(), rootItem->height());
+
+ rootItem->setParentItem(m_quickWindow->contentItem());
+}
+
+Window::~Window()
+{
+ delete m_qmlComponent;
+ delete m_qmlEngine;
+ delete m_quickWindow;
+ delete m_renderControl;
+
+ releaseResources();
+
+ // Often a no-op (if we already got SurfaceAboutToBeDestroyed), but there
+ // are cases when that's not sent.
+ m_swapchain.destroy();
+}
+
+// Expose (and UpdateRequest) are all the events we need: resize and screen dpr
+// changes are handled implicitly since every render() checks for size changes
+// so no separate event handlers are needed for that.
+
+void Window::exposeEvent(QExposeEvent *)
+{
+ if (isExposed()) {
+ // initialize if this is the first expose
+ if (!m_swapchain.swapchain)
+ m_swapchain = m_engine->createSwapchain(this);
+ // must always render and present a frame on expose
+ if (!size().isEmpty())
+ render();
+ }
+}
+
+// Input is severly limited in this example: there is no mapping or projection
+// of any kind, so it all behaves as if the Qt Quick content was covering the
+// entire window. The example only cares about button down/up, not the position
+// so this is acceptable here.
+
+void Window::mousePressEvent(QMouseEvent *e)
+{
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(m_quickWindow, &mappedEvent);
+}
+
+void Window::mouseReleaseEvent(QMouseEvent *e)
+{
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
+ QCoreApplication::sendEvent(m_quickWindow, &mappedEvent);
+}
+
+bool Window::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::UpdateRequest:
+ render();
+ break;
+
+ case QEvent::PlatformSurface:
+ // trying to be nice, not strictly required for D3D
+ if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
+ m_swapchain.destroy();
+ break;
+
+ default:
+ break;
+ }
+
+ return QWindow::event(e);
+}
+
+bool Window::initResources()
+{
+ ID3D11Device *dev = m_engine->device();
+
+ // vertex and pixel shader to render a textured quad
+
+ HRESULT hr = dev->CreateVertexShader(g_quad_vs_main, sizeof(g_quad_vs_main), nullptr, &m_res.vertexShader);
+ if (FAILED(hr)) {
+ qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+
+ hr = dev->CreatePixelShader(g_quad_ps_main, sizeof(g_quad_ps_main), nullptr, &m_res.pixelShader);
+ if (FAILED(hr)) {
+ qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+
+ // texture into which Qt Quick will render and which we will then sample
+
+ D3D11_TEXTURE2D_DESC texDesc = {};
+ texDesc.Width = QML_WIDTH;
+ texDesc.Height = QML_HEIGHT;
+ texDesc.MipLevels = 1;
+ texDesc.ArraySize = 1;
+ texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ if (SAMPLE_COUNT > 1) {
+ texDesc.SampleDesc.Count = SAMPLE_COUNT;
+ texDesc.SampleDesc.Quality = UINT(D3D11_STANDARD_MULTISAMPLE_PATTERN);
+ } else {
+ texDesc.SampleDesc.Count = 1;
+ }
+ // we have to use BIND_SHADER_RESOURCE even if the texture is MSAA because
+ // an SRV may still get created internally by Qt Quick
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ texDesc.Usage = D3D11_USAGE_DEFAULT;
+
+ hr = dev->CreateTexture2D(&texDesc, nullptr, &m_res.texture);
+ if (FAILED(hr)) {
+ qWarning("Failed to create texture: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+
+ if (SAMPLE_COUNT > 1) {
+ texDesc.SampleDesc.Count = 1;
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ hr = dev->CreateTexture2D(&texDesc, nullptr, &m_res.resolveTexture);
+ if (FAILED(hr)) {
+ qWarning("Failed to create resolve texture: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = 1;
+
+ hr = dev->CreateShaderResourceView(SAMPLE_COUNT > 1 ? m_res.resolveTexture : m_res.texture, &srvDesc, &m_res.textureSrv);
+ if (FAILED(hr)) {
+ qWarning("Failed to create srv: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+
+ D3D11_SAMPLER_DESC sampDesc = {};
+ sampDesc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
+ sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ sampDesc.MaxAnisotropy = 1.0f;
+
+ hr = dev->CreateSamplerState(&sampDesc, &m_res.sampler);
+ if (FAILED(hr)) {
+ qWarning("Failed to create sampler state: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+
+ m_res.valid = true;
+ return true;
+}
+
+void Window::releaseResources()
+{
+ RELEASE(m_res.vertexShader);
+ RELEASE(m_res.pixelShader);
+ RELEASE(m_res.texture);
+ RELEASE(m_res.resolveTexture);
+ RELEASE(m_res.textureSrv);
+ RELEASE(m_res.sampler);
+
+ m_res.valid = false;
+}
+
+void Window::render()
+{
+ if (!isExposed() || !m_swapchain.swapchain || !m_swapchain.tex || !m_swapchain.rtv)
+ return;
+
+ // if the window got resized, the swapchain buffers must be resized as well
+ if (m_swapchain.pixelSize != m_engine->swapchainSizeForWindow(this))
+ m_engine->resizeSwapchain(&m_swapchain, this);
+
+ if (!m_res.valid) {
+ if (!initResources())
+ return;
+ }
+
+ // get some content into m_res.texture from Qt Quick
+ updateQuick();
+
+ // now onto our own drawing, targeting the window
+ ID3D11DeviceContext1 *ctx = m_engine->context();
+ const QSize viewSize = m_swapchain.pixelSize;
+
+ const float clearColor[] = { 0.4f, 0.7f, 0.0f, 1.0f };
+ ctx->ClearRenderTargetView(m_swapchain.rtv, clearColor);
+ ctx->ClearDepthStencilView(m_swapchain.dsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
+
+ ctx->OMSetRenderTargets(1, &m_swapchain.rtv, m_swapchain.dsv);
+
+ const D3D11_VIEWPORT viewport = { 0.0f, 0.0f, float(viewSize.width()), float(viewSize.height()),
+ 0.f, 1.0f };
+ ctx->RSSetViewports(1, &viewport);
+
+ // draw a textured quad
+
+ ctx->VSSetShader(m_res.vertexShader, nullptr, 0);
+ ctx->PSSetShader(m_res.pixelShader, nullptr, 0);
+
+ ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ ctx->IASetInputLayout(nullptr);
+ ctx->OMSetDepthStencilState(nullptr, 0);
+ ctx->OMSetBlendState(nullptr, nullptr, 0xffffffff);
+ ctx->RSSetState(nullptr);
+
+ ctx->PSSetShaderResources(0, 1, &m_res.textureSrv);
+ ctx->PSSetSamplers(0, 1, &m_res.sampler);
+
+ ctx->Draw(6, 0);
+
+ m_swapchain.swapchain->Present(1, 0);
+
+ requestUpdate(); // will lead to eventually getting a QEvent::UpdateRequest
+}
+
+void Window::updateQuick()
+{
+ if (!m_quickDirty)
+ return;
+
+ m_quickDirty = false;
+
+ if (!m_quickInitialized) {
+ // In addition to setSceneGraphBackend, we need a call to
+ // setGraphicsDevice to tell Qt Quick what ID3D11Device(Context) to use
+ // (i.e. we want it to use ours, not to create new ones).
+ m_quickWindow->setGraphicsDevice(QQuickGraphicsDevice::fromDeviceAndContext(m_engine->device(), m_engine->context()));
+
+ // Now we can kick off the scenegraph.
+ if (!m_renderControl->initialize())
+ qWarning("Failed to initialize redirected Qt Quick rendering");
+
+ // Redirect Qt Quick's output. (note that the QSGTexture::NativeTexture
+ // struct is expected to contain a pointer to the native object, even
+ // if the native object type is a pointer, such as ID3D11Texture2D*)
+ m_quickWindow->setRenderTarget(QQuickRenderTarget::fromNativeTexture({ &m_res.texture, 0 },
+ QSize(QML_WIDTH, QML_HEIGHT),
+ SAMPLE_COUNT));
+
+ m_quickInitialized = true;
+ }
+
+ m_renderControl->polishItems();
+
+ m_renderControl->beginFrame();
+ m_renderControl->sync();
+ m_renderControl->render();
+ m_renderControl->endFrame(); // Qt Quick's rendering commands are submitted to the device context here
+
+ if (SAMPLE_COUNT > 1)
+ m_engine->context()->ResolveSubresource(m_res.resolveTexture, 0, m_res.texture, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
+}
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/window.h b/examples/quick/rendercontrol/rendercontrol_d3d11/window.h
new file mode 100644
index 0000000000..6020be288e
--- /dev/null
+++ b/examples/quick/rendercontrol/rendercontrol_d3d11/window.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <QWindow>
+#include "engine.h"
+
+class QQuickRenderControl;
+class QQuickWindow;
+class QQmlEngine;
+class QQmlComponent;
+
+class Window : public QWindow
+{
+public:
+ Window(Engine *engine);
+ ~Window();
+
+protected:
+ void exposeEvent(QExposeEvent *e) override;
+ void mousePressEvent(QMouseEvent *e) override;
+ void mouseReleaseEvent(QMouseEvent *e) override;
+ bool event(QEvent *e) override;
+
+private:
+ void render();
+ bool initResources();
+ void releaseResources();
+ void updateQuick();
+
+ Engine *m_engine;
+ QQuickRenderControl *m_renderControl;
+ QQuickWindow *m_quickWindow;
+ QQmlEngine *m_qmlEngine;
+ QQmlComponent *m_qmlComponent;
+ bool m_quickInitialized = false;
+ bool m_quickDirty = true;
+
+ Swapchain m_swapchain = {};
+ struct {
+ bool valid = false;
+ ID3D11VertexShader *vertexShader = nullptr;
+ ID3D11PixelShader *pixelShader = nullptr;
+ ID3D11Texture2D *texture = nullptr;
+ ID3D11Texture2D *resolveTexture = nullptr;
+ ID3D11ShaderResourceView *textureSrv = nullptr;
+ ID3D11SamplerState *sampler = nullptr;
+ } m_res;
+};
+
+#endif
diff --git a/examples/quick/rendercontrol/rendercontrol_opengl/doc/images/rendercontrol-example.jpg b/examples/quick/rendercontrol/rendercontrol_opengl/doc/images/rendercontrol-opengl-example.jpg
index a899ebe7f5..a899ebe7f5 100644
--- a/examples/quick/rendercontrol/rendercontrol_opengl/doc/images/rendercontrol-example.jpg
+++ b/examples/quick/rendercontrol/rendercontrol_opengl/doc/images/rendercontrol-opengl-example.jpg
Binary files differ
diff --git a/examples/quick/rendercontrol/rendercontrol_opengl/doc/src/rendercontrol.qdoc b/examples/quick/rendercontrol/rendercontrol_opengl/doc/src/rendercontrol_opengl.qdoc
index 9b6b075a5b..a4a648e5de 100644
--- a/examples/quick/rendercontrol/rendercontrol_opengl/doc/src/rendercontrol.qdoc
+++ b/examples/quick/rendercontrol/rendercontrol_opengl/doc/src/rendercontrol_opengl.qdoc
@@ -26,8 +26,8 @@
****************************************************************************/
/*!
- \title QQuickRenderControl Example
+ \title QQuickRenderControl OpenGL Example
\example rendercontrol/rendercontrol_opengl
\brief Shows how to render a Qt Quick scene into a texture that is then used by a non-Quick based OpenGL renderer.
- \image rendercontrol-example.jpg
+ \image rendercontrol-opengl-example.jpg
*/