diff options
Diffstat (limited to 'examples')
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 Binary files differnew file mode 100644 index 0000000000..4d56a946cc --- /dev/null +++ b/examples/quick/rendercontrol/rendercontrol_d3d11/doc/images/rendercontrol-d3d11-example.jpg 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 Binary files differindex 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 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 */ |