diff options
41 files changed, 1807 insertions, 120 deletions
diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.cpp b/examples/quick/scenegraph/rendernode/customrenderitem.cpp new file mode 100644 index 0000000000..124a57a5d6 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/customrenderitem.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "customrenderitem.h" +#include <QQuickWindow> +#include <QSGRendererInterface> + +#include "openglrenderer.h" +#include "d3d12renderer.h" + +CustomRenderNode::~CustomRenderNode() +{ + releaseResources(); +} + +void CustomRenderNode::render(const RenderState *state) +{ + QSGRendererInterface *ri = m_item->window()->rendererInterface(); + if (!ri) + return; + + m_api = ri->graphicsAPI(); + + if (!m_renderer) { + switch (m_api) { + case QSGRendererInterface::OpenGL: +#ifndef QT_NO_OPENGL + m_renderer = new OpenGLRenderer(m_item, this); +#endif + break; + case QSGRendererInterface::Direct3D12: +#ifdef HAS_D3D12 + m_renderer = new D3D12Renderer(m_item, this); +#endif + break; + default: + break; + } + Q_ASSERT(m_renderer); + m_renderer->init(); + } + + m_renderer->render(state); +} + +// No need to reimplement changedStates() since our rendering is so simple, +// without involving any state changes. + +void CustomRenderNode::releaseResources() +{ + if (!m_renderer) + return; + + delete m_renderer; + m_renderer = nullptr; +} + +CustomRenderItem::CustomRenderItem(QQuickItem *parent) + : QQuickItem(parent) +{ + // Our item shows something so set the flag. + setFlag(ItemHasContents); + + // We want the graphics API type to be exposed to QML. The value is easy to + // get during rendering on the render thread in CustomRenderNode::render(), + // but is more tricky here since the item gets a window associated later, + // which in turn will get the underlying scenegraph started at some later + // point. So defer. + connect(this, &QQuickItem::windowChanged, this, &CustomRenderItem::onWindowChanged); +} + +QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) +{ + CustomRenderNode *n = static_cast<CustomRenderNode *>(node); + if (!node) + n = new CustomRenderNode(this); + + return n; +} + +void CustomRenderItem::onWindowChanged(QQuickWindow *w) +{ + if (w) { + if (w->isSceneGraphInitialized()) + updateGraphicsAPI(); + else + connect(w, &QQuickWindow::sceneGraphInitialized, this, &CustomRenderItem::updateGraphicsAPI); + } else { + updateGraphicsAPI(); + } +} + +void CustomRenderItem::updateGraphicsAPI() +{ + QString newAPI; + if (!window()) { + newAPI = QLatin1String("[no window]"); + } else { + QSGRendererInterface *ri = window()->rendererInterface(); + if (!ri) { + newAPI = QLatin1String("[no renderer interface]"); + } else { + switch (ri->graphicsAPI()) { + case QSGRendererInterface::OpenGL: + newAPI = QLatin1String("OpenGL"); + break; + case QSGRendererInterface::Direct3D12: + newAPI = QLatin1String("D3D12"); + break; + default: + newAPI = QString(QLatin1String("[unsupported graphics API %1]")).arg(ri->graphicsAPI()); + break; + } + } + } + + if (newAPI != m_api) { + m_api = newAPI; + emit graphicsAPIChanged(); + } +} diff --git a/examples/quick/scenegraph/rendernode/customrenderitem.h b/examples/quick/scenegraph/rendernode/customrenderitem.h new file mode 100644 index 0000000000..fb4c392148 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/customrenderitem.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CUSTOMRENDERITEM_H +#define CUSTOMRENDERITEM_H + +#include <QQuickItem> +#include <QSGRenderNode> + +class CustomRenderer +{ +public: + virtual ~CustomRenderer() { } + virtual void init() = 0; + virtual void render(const QSGRenderNode::RenderState *state) = 0; +}; + +class CustomRenderNode : public QSGRenderNode +{ +public: + CustomRenderNode(QQuickItem *item) : m_item(item) { } + ~CustomRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + +private: + QQuickItem *m_item; + int m_api; + CustomRenderer *m_renderer = nullptr; +}; + +class CustomRenderItem : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QString graphicsAPI READ graphicsAPI NOTIFY graphicsAPIChanged) + +public: + CustomRenderItem(QQuickItem *parent = nullptr); + + QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; + + QString graphicsAPI() const { return m_api; } + +private slots: + void onWindowChanged(QQuickWindow *w); + void updateGraphicsAPI(); + +signals: + void graphicsAPIChanged(); + +private: + QString m_api; +}; + +#endif diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp new file mode 100644 index 0000000000..a48719e5dd --- /dev/null +++ b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "d3d12renderer.h" +#include <QQuickWindow> +#include <QSGRendererInterface> + +#ifdef HAS_D3D12 + +#include "vs_shader.hlslh" +#include "ps_shader.hlslh" + +D3D12Renderer::D3D12Renderer(QQuickItem *item, QSGRenderNode *node) + : m_item(item), + m_node(node), + vbPtr(nullptr), + cbPtr(nullptr) +{ +} + +void D3D12Renderer::init() +{ + QSGRendererInterface *rif = m_item->window()->rendererInterface(); + m_device = static_cast<ID3D12Device *>(rif->getResource(QSGRendererInterface::Device)); + Q_ASSERT(m_device); + + D3D12_ROOT_PARAMETER rootParameter; + rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + rootParameter.Descriptor.ShaderRegister = 0; // b0 + rootParameter.Descriptor.RegisterSpace = 0; + + D3D12_ROOT_SIGNATURE_DESC desc; + desc.NumParameters = 1; + desc.pParameters = &rootParameter; + desc.NumStaticSamplers = 0; + desc.pStaticSamplers = nullptr; + desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ComPtr<ID3DBlob> signature; + ComPtr<ID3DBlob> error; + if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) { + qWarning("Failed to serialize root signature"); + return; + } + if (FAILED(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), + IID_PPV_ARGS(&rootSignature)))) { + qWarning("Failed to create root signature"); + return; + } + + D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } + }; + + D3D12_SHADER_BYTECODE vshader; + vshader.pShaderBytecode = g_VS_Simple; + vshader.BytecodeLength = sizeof(g_VS_Simple); + D3D12_SHADER_BYTECODE pshader; + pshader.pShaderBytecode = g_PS_Simple; + pshader.BytecodeLength = sizeof(g_PS_Simple); + + D3D12_RASTERIZER_DESC rastDesc = {}; + rastDesc.FillMode = D3D12_FILL_MODE_SOLID; + rastDesc.CullMode = D3D12_CULL_MODE_BACK; + rastDesc.FrontCounterClockwise = TRUE; // Vertices are given CCW + + // No blending, just enable color write. + D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {}; + defaultRenderTargetBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + D3D12_BLEND_DESC blendDesc = {}; + blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; + psoDesc.pRootSignature = rootSignature.Get(); + psoDesc.VS = vshader; + psoDesc.PS = pshader; + psoDesc.RasterizerState = rastDesc; + psoDesc.BlendState = blendDesc; + // No depth. The correct stacking of the item is ensured by the projection matrix. + // Do not bother with stencil since we do not apply clipping in the + // example. If clipping is desired, render() needs to set a different PSO + // with stencil enabled whenever the RenderState indicates so. + psoDesc.SampleMask = UINT_MAX; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; + psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; // not in use due to !DepthEnable, but this would be the correct format otherwise + psoDesc.SampleDesc.Count = 1; + if (FAILED(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)))) { + qWarning("Failed to create graphics pipeline state"); + return; + } + + const UINT vertexBufferSize = (2 + 3) * 3 * sizeof(float); + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_UPLOAD; + + D3D12_RESOURCE_DESC bufDesc; + bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufDesc.Alignment = 0; + bufDesc.Width = vertexBufferSize; + bufDesc.Height = 1; + bufDesc.DepthOrArraySize = 1; + bufDesc.MipLevels = 1; + bufDesc.Format = DXGI_FORMAT_UNKNOWN; + bufDesc.SampleDesc.Count = 1; + bufDesc.SampleDesc.Quality = 0; + bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + bufDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + if (FAILED(m_device->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + IID_PPV_ARGS(&vertexBuffer)))) { + qWarning("Failed to create committed resource (vertex buffer)"); + return; + } + + vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress(); + vertexBufferView.StrideInBytes = (2 + 3) * sizeof(float); + vertexBufferView.SizeInBytes = vertexBufferSize; + + bufDesc.Width = 256; + if (FAILED(m_device->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + IID_PPV_ARGS(&constantBuffer)))) { + qWarning("Failed to create committed resource (constant buffer)"); + return; + } + + const D3D12_RANGE readRange = { 0, 0 }; + if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&vbPtr)))) { + qWarning("Map failed"); + return; + } + + if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&cbPtr)))) { + qWarning("Map failed (constant buffer)"); + return; + } +} + +D3D12Renderer::~D3D12Renderer() +{ + if (vbPtr) + vertexBuffer->Unmap(0, nullptr); + if (cbPtr) + constantBuffer->Unmap(0, nullptr); +} + +void D3D12Renderer::render(const QSGRenderNode::RenderState *state) +{ + QSGRendererInterface *rif = m_item->window()->rendererInterface(); + ID3D12GraphicsCommandList *commandList = static_cast<ID3D12GraphicsCommandList *>(rif->getResource(QSGRendererInterface::CommandList)); + Q_ASSERT(commandList); + + const int msize = 16 * sizeof(float); + memcpy(cbPtr, m_node->matrix()->constData(), msize); + memcpy(cbPtr + msize, state->projectionMatrix()->constData(), msize); + + const QPointF p0(m_item->width() - 1, m_item->height() - 1); + const QPointF p1(0, 0); + const QPointF p2(0, m_item->height() - 1); + + float *vp = reinterpret_cast<float *>(vbPtr); + *vp++ = p0.x(); + *vp++ = p0.y(); + *vp++ = 1.0f; *vp++ = 0.0f; *vp++ = 0.0f; + + *vp++ = p1.x(); + *vp++ = p1.y(); + *vp++ = 0.0f; *vp++ = 1.0f; *vp++ = 0.0f; + + *vp++ = p2.x(); + *vp++ = p2.y(); + *vp++ = 0.0f; *vp++ = 0.0f; *vp++ = 1.0f; + + commandList->SetPipelineState(pipelineState.Get()); + commandList->SetGraphicsRootSignature(rootSignature.Get()); + commandList->SetGraphicsRootConstantBufferView(0, constantBuffer->GetGPUVirtualAddress()); + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + commandList->IASetVertexBuffers(0, 1, &vertexBufferView); + + commandList->DrawInstanced(3, 1, 0, 0); + + // we won't implement changedStates() since no viewport/scissor/stencil/blend related commands were added +} + +#endif // HAS_D3D12 diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.h b/examples/quick/scenegraph/rendernode/d3d12renderer.h new file mode 100644 index 0000000000..365b483422 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/d3d12renderer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef D3D12RENDERER_H +#define D3D12RENDERER_H + +#include "customrenderitem.h" +#include <qsgrendernode.h> + +#ifdef HAS_D3D12 + +#include <d3d12.h> +#include <wrl/client.h> + +using namespace Microsoft::WRL; + +class D3D12Renderer : public CustomRenderer +{ +public: + D3D12Renderer(QQuickItem *item, QSGRenderNode *node); + ~D3D12Renderer(); + void init() override; + void render(const QSGRenderNode::RenderState *state) override; + +private: + QQuickItem *m_item; + QSGRenderNode *m_node; + ID3D12Device *m_device; + ComPtr<ID3D12PipelineState> pipelineState; + ComPtr<ID3D12RootSignature> rootSignature; + ComPtr<ID3D12Resource> vertexBuffer; + ComPtr<ID3D12Resource> constantBuffer; + D3D12_VERTEX_BUFFER_VIEW vertexBufferView; + quint8 *vbPtr; + quint8 *cbPtr; +}; + +#endif // HAS_D3D12 + +#endif diff --git a/examples/quick/scenegraph/rendernode/main.cpp b/examples/quick/scenegraph/rendernode/main.cpp new file mode 100644 index 0000000000..9128cdc5be --- /dev/null +++ b/examples/quick/scenegraph/rendernode/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QQuickView> +#include "customrenderitem.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType<CustomRenderItem>("SceneGraphRendering", 2, 0, "CustomRenderItem"); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:///scenegraph/rendernode/main.qml")); + view.resize(1024, 768); + view.show(); + + return app.exec(); +} diff --git a/examples/quick/scenegraph/rendernode/main.qml b/examples/quick/scenegraph/rendernode/main.qml new file mode 100644 index 0000000000..32154cc930 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/main.qml @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import SceneGraphRendering 2.0 + +Item { + Rectangle { + anchors.fill: parent + gradient: Gradient { + GradientStop { position: 0; color: "steelblue" } + GradientStop { position: 1; color: "black" } + } + + CustomRenderItem { + id: renderer + anchors.fill: parent + anchors.margins: 10 + + transform: [ + Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; }, + Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 }, + Scale { id: scale; }, + Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 } + ] + } + + SequentialAnimation { + PauseAnimation { duration: 3000 } + ParallelAnimation { + NumberAnimation { target: scale; property: "xScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack } + NumberAnimation { target: scale; property: "yScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack } + } + NumberAnimation { target: rotation; property: "angle"; to: 80; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: rotation; property: "angle"; to: -80; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: renderer; property: "opacity"; to: 0.5; duration: 1000; easing.type: Easing.InOutCubic } + PauseAnimation { duration: 1000 } + NumberAnimation { target: renderer; property: "opacity"; to: 0.8; duration: 1000; easing.type: Easing.InOutCubic } + ParallelAnimation { + NumberAnimation { target: scale; property: "xScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack } + NumberAnimation { target: scale; property: "yScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack } + } + running: true + loops: Animation.Infinite + } + + Text { + id: label + anchors.bottom: renderer.bottom + anchors.left: renderer.left + anchors.right: renderer.right + anchors.margins: 20 + wrapMode: Text.WordWrap + text: "Custom rendering via the graphics API " + renderer.graphicsAPI + color: "yellow" + } + } +} diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.cpp b/examples/quick/scenegraph/rendernode/openglrenderer.cpp new file mode 100644 index 0000000000..e9c1be071c --- /dev/null +++ b/examples/quick/scenegraph/rendernode/openglrenderer.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "openglrenderer.h" + +#ifndef QT_NO_OPENGL + +#include <QOpenGLShaderProgram> +#include <QOpenGLBuffer> +#include <QOpenGLFunctions> + +OpenGLRenderer::OpenGLRenderer(QQuickItem *item, QSGRenderNode *node) + : m_item(item), + m_node(node) +{ +} + +void OpenGLRenderer::init() +{ + m_program = new QOpenGLShaderProgram; + + static const char *vertexShaderSource = + "attribute highp vec4 posAttr;\n" + "attribute lowp vec4 colAttr;\n" + "varying lowp vec4 col;\n" + "uniform highp mat4 matrix;\n" + "void main() {\n" + " col = colAttr;\n" + " gl_Position = matrix * posAttr;\n" + "}\n"; + + static const char *fragmentShaderSource = + "varying lowp vec4 col;\n" + "void main() {\n" + " gl_FragColor = col;\n" + "}\n"; + + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource); + m_program->bindAttributeLocation("posAttr", 0); + m_program->bindAttributeLocation("colAttr", 1); + m_program->link(); + + m_matrixUniform = m_program->uniformLocation("matrix"); + + const int VERTEX_SIZE = 6 * sizeof(GLfloat); + + // A fully featured renderer should also take inheritedOpacity() into account + // and blend, but ignore that for now. + static GLfloat colors[] = { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f + }; + + m_vbo = new QOpenGLBuffer; + m_vbo->create(); + m_vbo->bind(); + m_vbo->allocate(VERTEX_SIZE + sizeof(colors)); + m_vbo->write(VERTEX_SIZE, colors, sizeof(colors)); + m_vbo->release(); +} + +OpenGLRenderer::~OpenGLRenderer() +{ + delete m_program; + delete m_vbo; +} + +void OpenGLRenderer::render(const QSGRenderNode::RenderState *state) +{ + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + + m_program->bind(); + m_program->setUniformValue(m_matrixUniform, *state->projectionMatrix() * *m_node->matrix()); + + m_vbo->bind(); + + QPointF p0(m_item->width() - 1, m_item->height() - 1); + QPointF p1(0, 0); + QPointF p2(0, m_item->height() - 1); + + GLfloat vertices[6] = { GLfloat(p0.x()), GLfloat(p0.y()), + GLfloat(p1.x()), GLfloat(p1.y()), + GLfloat(p2.x()), GLfloat(p2.y()) }; + m_vbo->write(0, vertices, sizeof(vertices)); + + m_program->setAttributeBuffer(0, GL_FLOAT, 0, 2); + m_program->setAttributeBuffer(1, GL_FLOAT, sizeof(vertices), 3); + m_program->enableAttributeArray(0); + m_program->enableAttributeArray(1); + + f->glDrawArrays(GL_TRIANGLES, 0, 3); +} + +#endif // QT_NO_OPENGL diff --git a/examples/quick/scenegraph/rendernode/openglrenderer.h b/examples/quick/scenegraph/rendernode/openglrenderer.h new file mode 100644 index 0000000000..d445b35c1e --- /dev/null +++ b/examples/quick/scenegraph/rendernode/openglrenderer.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OPENGLRENDERER_H +#define OPENGLRENDERER_H + +#include "customrenderitem.h" +#include <qsgrendernode.h> + +#ifndef QT_NO_OPENGL + +class QOpenGLShaderProgram; +class QOpenGLBuffer; + +class OpenGLRenderer : public CustomRenderer +{ +public: + OpenGLRenderer(QQuickItem *item, QSGRenderNode *node); + ~OpenGLRenderer(); + void init() override; + void render(const QSGRenderNode::RenderState *state) override; + +private: + QQuickItem *m_item; + QSGRenderNode *m_node; + QOpenGLShaderProgram *m_program = nullptr; + int m_matrixUniform; + QOpenGLBuffer *m_vbo = nullptr; +}; + +#endif // QT_NO_OPENGL + +#endif diff --git a/examples/quick/scenegraph/rendernode/rendernode.pro b/examples/quick/scenegraph/rendernode/rendernode.pro new file mode 100644 index 0000000000..d7ae715a7d --- /dev/null +++ b/examples/quick/scenegraph/rendernode/rendernode.pro @@ -0,0 +1,37 @@ +QT += qml quick + +HEADERS += customrenderitem.h \ + openglrenderer.h + +SOURCES += customrenderitem.cpp \ + openglrenderer.cpp \ + main.cpp + +RESOURCES += rendernode.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/rendernode +INSTALLS += target + +OTHER_FILES += \ + main.qml \ + shader.hlsl + +config_d3d12 { + DEFINES += HAS_D3D12 + HEADERS += d3d12renderer.h + SOURCES += d3d12renderer.cpp + LIBS += -ld3d12 + + VSPS = shader.hlsl + vshader.input = VSPS + vshader.header = vs_shader.hlslh + vshader.entry = VS_Simple + vshader.type = vs_5_0 + pshader.input = VSPS + pshader.header = ps_shader.hlslh + pshader.entry = PS_Simple + pshader.type = ps_5_0 + + HLSL_SHADERS = vshader pshader + load(hlsl_bytecode_header) +} diff --git a/examples/quick/scenegraph/rendernode/rendernode.qrc b/examples/quick/scenegraph/rendernode/rendernode.qrc new file mode 100644 index 0000000000..3674baccd8 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/rendernode.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/scenegraph/rendernode"> + <file>main.qml</file> + </qresource> +</RCC> diff --git a/examples/quick/scenegraph/rendernode/shader.hlsl b/examples/quick/scenegraph/rendernode/shader.hlsl new file mode 100644 index 0000000000..8b9b9ff9d8 --- /dev/null +++ b/examples/quick/scenegraph/rendernode/shader.hlsl @@ -0,0 +1,27 @@ +cbuffer ConstantBuffer : register(b0) +{ + float4x4 modelview; + float4x4 projection; +}; + +struct PSInput +{ + float4 position : SV_POSITION; + float4 color : COLOR; +}; + +PSInput VS_Simple(float4 position : POSITION, float4 color : COLOR) +{ + PSInput result; + + float4x4 mvp = mul(projection, modelview); + result.position = mul(mvp, position); + result.color = color; + + return result; +} + +float4 PS_Simple(PSInput input) : SV_TARGET +{ + return input.color; +} diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp index 0bb342226b..d43dcd5997 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp @@ -97,4 +97,14 @@ QSurfaceFormat QSGD3D12Context::defaultSurfaceFormat() const return QSurfaceFormat::defaultFormat(); } +QSGRendererInterface *QSGD3D12Context::rendererInterface(QSGRenderContext *renderContext) +{ + QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext); + if (!rc->engine()) { + qWarning("No D3D12 engine available yet (no render thread due to window not exposed?)"); + return nullptr; + } + return rc->engine(); +} + QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h index 2afe22e3af..c597ed90dd 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h @@ -69,6 +69,7 @@ public: QSGLayer *createLayer(QSGRenderContext *rc) override; QSize minimumFBOSize() const override; QSurfaceFormat defaultSurfaceFormat() const override; + QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override; }; QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp index afeeea760c..cbdf54a9ea 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp @@ -360,6 +360,16 @@ void QSGD3D12Engine::endLayer() d->endLayer(); } +void QSGD3D12Engine::invalidateCachedFrameState() +{ + d->invalidateCachedFrameState(); +} + +void QSGD3D12Engine::restoreFrameState(bool minimal) +{ + d->restoreFrameState(minimal); +} + void QSGD3D12Engine::finalizePipeline(const QSGD3D12PipelineState &pipelineState) { d->finalizePipeline(pipelineState); @@ -495,6 +505,16 @@ void QSGD3D12Engine::activateRenderTargetAsTexture(uint id) d->activateRenderTargetAsTexture(id); } +QSGRendererInterface::GraphicsAPI QSGD3D12Engine::graphicsAPI() const +{ + return Direct3D12; +} + +void *QSGD3D12Engine::getResource(Resource resource) const +{ + return d->getResource(resource); +} + static inline quint32 alignedSize(quint32 size, quint32 byteAlign) { return (size + byteAlign - 1) & ~(byteAlign - 1); @@ -1296,7 +1316,11 @@ void QSGD3D12EnginePrivate::beginDrawCalls() { frameCommandList->Reset(frameCommandAllocator[frameIndex % frameInFlightCount].Get(), nullptr); commandList = frameCommandList.Get(); + invalidateCachedFrameState(); +} +void QSGD3D12EnginePrivate::invalidateCachedFrameState() +{ tframeData.drawingMode = QSGGeometry::DrawingMode(-1); tframeData.currentIndexBuffer = 0; tframeData.drawCount = 0; @@ -1305,6 +1329,18 @@ void QSGD3D12EnginePrivate::beginDrawCalls() tframeData.descHeapSet = false; } +void QSGD3D12EnginePrivate::restoreFrameState(bool minimal) +{ + queueSetRenderTarget(currentRenderTarget); + if (!minimal) { + queueViewport(tframeData.viewport); + queueScissor(tframeData.scissor); + queueSetBlendFactor(tframeData.blendFactor); + queueSetStencilRef(tframeData.stencilRef); + } + finalizePipeline(tframeData.pipelineState); +} + void QSGD3D12EnginePrivate::beginFrameDraw() { if (windowSamples == 1) @@ -1886,12 +1922,7 @@ void QSGD3D12EnginePrivate::queueDraw(const QSGD3D12Engine::DrawParams ¶ms) // start a new one beginDrawCalls(); // prepare for the upcoming drawcalls - queueSetRenderTarget(currentRenderTarget); - queueViewport(tframeData.viewport); - queueScissor(tframeData.scissor); - queueSetBlendFactor(tframeData.blendFactor); - queueSetStencilRef(tframeData.stencilRef); - finalizePipeline(tframeData.pipelineState); + restoreFrameState(); } } @@ -2737,4 +2768,19 @@ void QSGD3D12EnginePrivate::activateRenderTargetAsTexture(uint id) tframeData.activeTextures.append(TransientFrameData::ActiveTexture::ActiveTexture(TransientFrameData::ActiveTexture::TypeRenderTarget, id)); } +void *QSGD3D12EnginePrivate::getResource(QSGRendererInterface::Resource resource) const +{ + switch (resource) { + case QSGRendererInterface::Device: + return device; + case QSGRendererInterface::CommandQueue: + return commandQueue.Get(); + case QSGRendererInterface::CommandList: + return commandList; + default: + break; + } + return nullptr; +} + QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h index 84bb5a554e..3b7dd7cdc6 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h @@ -55,6 +55,7 @@ #include <QImage> #include <QVector4D> #include <qsggeometry.h> +#include <qsgrendererinterface.h> #include <qt_windows.h> QT_BEGIN_NAMESPACE @@ -260,7 +261,7 @@ inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0) + key.topologyType; } -class QSGD3D12Engine +class QSGD3D12Engine : public QSGRendererInterface { public: QSGD3D12Engine(); @@ -278,6 +279,8 @@ public: void endFrame(); void beginLayer(); void endLayer(); + void invalidateCachedFrameState(); + void restoreFrameState(bool minimal = false); uint genBuffer(); void releaseBuffer(uint id); @@ -344,6 +347,10 @@ public: void releaseRenderTarget(uint id); void activateRenderTargetAsTexture(uint id); + // QSGRendererInterface + GraphicsAPI graphicsAPI() const override; + void *getResource(Resource resource) const override; + private: QSGD3D12EnginePrivate *d; Q_DISABLE_COPY(QSGD3D12Engine) diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h index 40d1fdb510..047036b52a 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p_p.h @@ -142,6 +142,8 @@ public: void endFrame(); void beginLayer(); void endLayer(); + void invalidateCachedFrameState(); + void restoreFrameState(bool minimal = false); uint genBuffer(); void releaseBuffer(uint id); @@ -176,6 +178,8 @@ public: void releaseRenderTarget(uint id); void activateRenderTargetAsTexture(uint id); + void *getResource(QSGRendererInterface::Resource resource) const; + // the device is intentionally hidden here. all resources have to go // through the engine and, unlike with GL, cannot just be created in random // places due to the need for proper tracking, managing and releasing. diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp index af3e8e36ee..ab590b95c5 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp @@ -56,6 +56,14 @@ QSGD3D12RenderContext::QSGD3D12RenderContext(QSGContext *ctx) { } +bool QSGD3D12RenderContext::isValid() const +{ + // The render thread sets an engine when it starts up and resets when it + // quits. The rc is initialized and functional between those two points, + // regardless of any calls to invalidate(). See setEngine(). + return m_engine != nullptr; +} + void QSGD3D12RenderContext::invalidate() { if (Q_UNLIKELY(debug_render())) @@ -98,4 +106,15 @@ void QSGD3D12RenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo) static_cast<QSGD3D12Renderer *>(renderer)->renderScene(fbo); } +void QSGD3D12RenderContext::setEngine(QSGD3D12Engine *engine) +{ + if (m_engine == engine) + return; + + m_engine = engine; + + if (m_engine) + emit initialized(); +} + QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h index 1acb7e4205..e2cd6e3182 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h @@ -61,12 +61,13 @@ class QSGD3D12RenderContext : public QSGRenderContext { public: QSGD3D12RenderContext(QSGContext *ctx); + bool isValid() const override; void invalidate() override; void renderNextFrame(QSGRenderer *renderer, uint fbo) override; QSGTexture *createTexture(const QImage &image, uint flags) const override; QSGRenderer *createRenderer() override; - void setEngine(QSGD3D12Engine *engine) { m_engine = engine; } + void setEngine(QSGD3D12Engine *engine); QSGD3D12Engine *engine() { return m_engine; } private: diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp index 7f8b10f003..f76927c0bd 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderer.cpp @@ -40,6 +40,7 @@ #include "qsgd3d12renderer_p.h" #include "qsgd3d12rendercontext_p.h" #include <private/qsgnodeupdater_p.h> +#include <private/qsgrendernode_p.h> #include "vs_stencilclip.hlslh" #include "ps_stencilclip.hlslh" @@ -206,6 +207,11 @@ void QSGD3D12Renderer::buildRenderList(QSGNode *node, QSGClipNode *clip) gn->setClipList(clip); if (node->type() == QSGNode::ClipNodeType) clip = static_cast<QSGClipNode *>(node); + } else if (node->type() == QSGNode::RenderNodeType) { + QSGRenderNode *rn = static_cast<QSGRenderNode *>(node); + Element e; + e.node = rn; + m_renderList.add(e); } QSGNODE_TRAVERSE(node) @@ -316,6 +322,7 @@ void QSGD3D12Renderer::render() if (gn->inheritedOpacity() > 0.999f && ((gn->activeMaterial()->flags() & QSGMaterial::Blending) == 0)) m_opaqueElements.setBit(i); } + // QSGRenderNodes are always treated as non-opaque } } @@ -432,15 +439,36 @@ void QSGD3D12Renderer::renderElements() // ...then the alpha ones for (int i = 0; i < m_renderList.size(); ++i) { - if (m_renderList.at(i).node->type() == QSGNode::GeometryNodeType && !m_opaqueElements.testBit(i)) + if ((m_renderList.at(i).node->type() == QSGNode::GeometryNodeType && !m_opaqueElements.testBit(i)) + || m_renderList.at(i).node->type() == QSGNode::RenderNodeType) renderElement(i); } } +struct RenderNodeState : public QSGRenderNode::RenderState +{ + const QMatrix4x4 *projectionMatrix() const override { return m_projectionMatrix; } + QRect scissorRect() const { return m_scissorRect; } + bool scissorEnabled() const { return m_scissorEnabled; } + int stencilValue() const { return m_stencilValue; } + bool stencilEnabled() const { return m_stencilEnabled; } + + const QMatrix4x4 *m_projectionMatrix; + QRect m_scissorRect; + bool m_scissorEnabled; + int m_stencilValue; + bool m_stencilEnabled; +}; + void QSGD3D12Renderer::renderElement(int elementIndex) { Element &e = m_renderList.at(elementIndex); - Q_ASSERT(e.node->type() == QSGNode::GeometryNodeType); + Q_ASSERT(e.node->type() == QSGNode::GeometryNodeType || e.node->type() == QSGNode::RenderNodeType); + + if (e.node->type() == QSGNode::RenderNodeType) { + renderRenderNode(static_cast<QSGRenderNode *>(e.node), elementIndex); + return; + } if (e.vboOffset < 0) return; @@ -508,7 +536,7 @@ void QSGD3D12Renderer::renderElement(int elementIndex) m_lastMaterialType = m->type(); - setupClipping(gn, elementIndex); + setupClipping(gn->clipList(), elementIndex); // ### Lines and points with sizes other than 1 have to be implemented in some other way. Just ignore for now. if (g->drawingMode() == QSGGeometry::DrawLineStrip || g->drawingMode() == QSGGeometry::DrawLines) { @@ -575,16 +603,10 @@ void QSGD3D12Renderer::queueDrawCall(const QSGGeometry *g, const QSGD3D12Rendere m_engine->queueDraw(dp); } -void QSGD3D12Renderer::setupClipping(const QSGGeometryNode *gn, int elementIndex) +void QSGD3D12Renderer::setupClipping(const QSGClipNode *clip, int elementIndex) { - const QSGClipNode *clip = gn->clipList(); - const QRect devRect = deviceRect(); QRect scissorRect; - enum ClipType { - ClipScissor = 0x1, - ClipStencil = 0x2 - }; int clipTypes = 0; quint32 stencilValue = 0; @@ -647,9 +669,13 @@ void QSGD3D12Renderer::setupClipping(const QSGGeometryNode *gn, int elementIndex if (clipTypes & ClipStencil) { m_pipelineState.stencilEnable = true; m_engine->queueSetStencilRef(stencilValue); + m_currentStencilValue = stencilValue; } else { m_pipelineState.stencilEnable = false; + m_currentStencilValue = 0; } + + m_currentClipTypes = clipTypes; } void QSGD3D12Renderer::setScissor(const QRect &r) @@ -707,4 +733,52 @@ void QSGD3D12Renderer::renderStencilClip(const QSGClipNode *clip, int elementInd ++stencilValue; } +void QSGD3D12Renderer::renderRenderNode(QSGRenderNode *node, int elementIndex) +{ + QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(node); + RenderNodeState state; + + setupClipping(rd->m_clip_list, elementIndex); + + QMatrix4x4 pm = projectionMatrix(); + state.m_projectionMatrix = ± + state.m_scissorEnabled = m_currentClipTypes & ClipScissor; + state.m_stencilEnabled = m_currentClipTypes & ClipStencil; + state.m_scissorRect = m_activeScissorRect; + state.m_stencilValue = m_currentStencilValue; + + // ### rendernodes do not have the QSGBasicGeometryNode infrastructure + // for storing combined matrices, opacity and such, but perhaps they should. + QSGNode *xform = node->parent(); + QSGNode *root = rootNode(); + QMatrix4x4 modelview; + while (xform != root) { + if (xform->type() == QSGNode::TransformNodeType) { + modelview *= static_cast<QSGTransformNode *>(xform)->combinedMatrix(); + break; + } + xform = xform->parent(); + } + rd->m_matrix = &modelview; + + QSGNode *opacity = node->parent(); + rd->m_opacity = 1.0; + while (opacity != rootNode()) { + if (opacity->type() == QSGNode::OpacityNodeType) { + rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity(); + break; + } + opacity = opacity->parent(); + } + + node->render(&state); + + m_engine->invalidateCachedFrameState(); + // For simplicity, reset viewport, scissor, blend factor, stencil ref when + // any of them got changed. This will likely be rare so skip these otherwise. + // Render target, pipeline state, draw call related stuff will be reset always. + const bool restoreMinimal = node->changedStates() == 0; + m_engine->restoreFrameState(restoreMinimal); +} + QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h index 0877c3699a..bed34df3a1 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderer_p.h @@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE +class QSGRenderNode; + class QSGD3D12Renderer : public QSGRenderer { public: @@ -78,12 +80,13 @@ private: void renderElements(); void renderElement(int elementIndex); void setInputLayout(const QSGGeometry *g, QSGD3D12PipelineState *pipelineState); - void setupClipping(const QSGGeometryNode *gn, int elementIndex); + void setupClipping(const QSGClipNode *clip, int elementIndex); void setScissor(const QRect &r); void renderStencilClip(const QSGClipNode *clip, int elementIndex, const QMatrix4x4 &m, quint32 &stencilValue); + void renderRenderNode(QSGRenderNode *node, int elementIndex); struct Element { - QSGBasicGeometryNode *node = nullptr; + QSGNode *node = nullptr; qint32 vboOffset = -1; qint32 iboOffset = -1; quint32 iboStride = 0; @@ -121,6 +124,12 @@ private: bool m_projectionChangedDueToDeviceSize; uint m_renderTarget = 0; + quint32 m_currentStencilValue; + enum ClipType { + ClipScissor = 0x1, + ClipStencil = 0x2 + }; + int m_currentClipTypes; }; QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp index 94bdf38819..2c05ce01c6 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp @@ -331,8 +331,12 @@ bool QSGD3D12RenderThread::event(QEvent *e) qDebug("RT - WM_TryRelease - invalidating rc"); if (wme->window) { QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window); - if (wme->destroying) + if (wme->destroying) { + // QSGNode destruction may release graphics resources in use so wait first. + engine->waitGPU(); + // Bye bye nodes... wd->cleanupNodesOnShutdown(); + } rc->invalidate(); QCoreApplication::processEvents(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index a932e7a508..2642daf19f 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4345,6 +4345,22 @@ qreal QQuickWindow::effectiveDevicePixelRatio() const return w ? w->devicePixelRatio() : devicePixelRatio(); } +/*! + Returns the current renderer interface if there is one. Otherwise null is returned. + + \sa QSGRenderNode, QSGRendererInterface + \since 5.8 + */ +QSGRendererInterface *QQuickWindow::rendererInterface() const +{ + Q_D(const QQuickWindow); + if (!isSceneGraphInitialized()) { + qWarning("The QSGRendererInterface cannot be queried before the scenegraph is initialized"); + return nullptr; + } + return d->context->sceneGraphContext()->rendererInterface(d->context); +} + #include "moc_qquickwindow.cpp" QT_END_NAMESPACE diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index a4060541c0..977b4956b2 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -60,6 +60,7 @@ class QQmlIncubationController; class QInputMethodEvent; class QQuickCloseEvent; class QQuickRenderControl; +class QSGRendererInterface; class Q_QUICK_EXPORT QQuickWindow : public QWindow { @@ -153,6 +154,8 @@ public: qreal effectiveDevicePixelRatio() const; + QSGRendererInterface *rendererInterface() const; + Q_SIGNALS: void frameSwapped(); Q_REVISION(2) void openglContextCreated(QOpenGLContext *context); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp index 04fc6da84e..2ed1da46f4 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp @@ -169,4 +169,15 @@ void QSGSoftwareRenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo) renderer->renderScene(fbo); } +QSGRendererInterface *QSGSoftwareContext::rendererInterface(QSGRenderContext *renderContext) +{ + Q_UNUSED(renderContext); + return this; +} + +QSGRendererInterface::GraphicsAPI QSGSoftwareContext::graphicsAPI() const +{ + return Software; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h index 086278b2f1..8f9daceb7e 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h @@ -53,6 +53,7 @@ #include <private/qsgcontext_p.h> #include <private/qsgadaptationlayer_p.h> +#include "qsgrendererinterface.h" Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_RENDERLOOP) Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_COMPILATION) @@ -79,7 +80,7 @@ public: bool m_initialized; }; -class QSGSoftwareContext : public QSGContext +class QSGSoftwareContext : public QSGContext, public QSGRendererInterface { Q_OBJECT public: @@ -93,6 +94,9 @@ public: QSGNinePatchNode *createNinePatchNode() override; QSGLayer *createLayer(QSGRenderContext *renderContext) override; QSurfaceFormat defaultSurfaceFormat() const override; + QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override; + + GraphicsAPI graphicsAPI() const override; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index a89dbc0ea2..f277475dbf 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -2763,6 +2763,21 @@ void Renderer::render() m_vao->release(); } +struct RenderNodeState : public QSGRenderNode::RenderState +{ + const QMatrix4x4 *projectionMatrix() const override { return m_projectionMatrix; } + QRect scissorRect() const { return m_scissorRect; } + bool scissorEnabled() const { return m_scissorEnabled; } + int stencilValue() const { return m_stencilValue; } + bool stencilEnabled() const { return m_stencilEnabled; } + + const QMatrix4x4 *m_projectionMatrix; + QRect m_scissorRect; + bool m_scissorEnabled; + int m_stencilValue; + bool m_stencilEnabled; +}; + void Renderer::renderRenderNode(Batch *batch) { if (Q_UNLIKELY(debug_render())) @@ -2774,24 +2789,25 @@ void Renderer::renderRenderNode(Batch *batch) setActiveShader(0, 0); QSGNode *clip = e->renderNode->parent(); - e->renderNode->m_clip_list = 0; + QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode); + rd->m_clip_list = 0; while (clip != rootNode()) { if (clip->type() == QSGNode::ClipNodeType) { - e->renderNode->m_clip_list = static_cast<QSGClipNode *>(clip); + rd->m_clip_list = static_cast<QSGClipNode *>(clip); break; } clip = clip->parent(); } - updateClip(e->renderNode->m_clip_list, batch); + updateClip(rd->m_clip_list, batch); - QSGRenderNode::RenderState state; + RenderNodeState state; QMatrix4x4 pm = projectionMatrix(); - state.projectionMatrix = ± - state.scissorEnabled = m_currentClipType & ScissorClip; - state.stencilEnabled = m_currentClipType & StencilClip; - state.scissorRect = m_currentScissorRect; - state.stencilValue = m_currentStencilValue; + state.m_projectionMatrix = ± + state.m_scissorEnabled = m_currentClipType & ScissorClip; + state.m_stencilEnabled = m_currentClipType & StencilClip; + state.m_scissorRect = m_currentScissorRect; + state.m_stencilValue = m_currentStencilValue; QSGNode *xform = e->renderNode->parent(); QMatrix4x4 matrix; @@ -2807,13 +2823,13 @@ void Renderer::renderRenderNode(Batch *batch) } xform = xform->parent(); } - e->renderNode->m_matrix = &matrix; + rd->m_matrix = &matrix; QSGNode *opacity = e->renderNode->parent(); - e->renderNode->m_opacity = 1.0; + rd->m_opacity = 1.0; while (opacity != rootNode()) { if (opacity->type() == QSGNode::OpacityNodeType) { - e->renderNode->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity(); + rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity(); break; } opacity = opacity->parent(); @@ -2825,12 +2841,17 @@ void Renderer::renderRenderNode(Batch *batch) glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - e->renderNode->render(state); + QSGRenderNode::StateFlags changes = e->renderNode->changedStates(); + + GLuint prevFbo = 0; + if (changes & QSGRenderNode::RenderTargetState) + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo); - e->renderNode->m_matrix = 0; - e->renderNode->m_clip_list = 0; + e->renderNode->render(&state); + + rd->m_matrix = 0; + rd->m_clip_list = 0; - QSGRenderNode::StateFlags changes = e->renderNode->changedStates(); if (changes & QSGRenderNode::ViewportState) { QRect r = viewportRect(); glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height()); @@ -2864,6 +2885,8 @@ void Renderer::renderRenderNode(Batch *batch) glDisable(GL_CULL_FACE); } + if (changes & QSGRenderNode::RenderTargetState) + glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); } class VisualizeShader : public QOpenGLShaderProgram diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index a84ac6d177..c56f15d655 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -56,9 +56,8 @@ #include <private/qsgrenderer_p.h> #include <private/qsgdefaultrendercontext_p.h> #include <private/qsgnodeupdater_p.h> -#include <private/qdatabuffer_p.h> - #include <private/qsgrendernode_p.h> +#include <private/qdatabuffer_p.h> #include <QtCore/QBitArray> diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index 349753a361..627fe6e27f 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -79,8 +79,8 @@ public: OpacityNodeType, #ifndef qdoc RootNodeType, - RenderNodeType #endif + RenderNodeType }; enum Flag { diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp index 372ffce9d6..d6d533307e 100644 --- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp +++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp @@ -175,9 +175,10 @@ void QSGNodeUpdater::enterRenderNode(QSGRenderNode *r) qDebug() << "enter render:" << r; #endif - r->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last(); - r->m_clip_list = m_current_clip; - r->setInheritedOpacity(m_opacity_stack.last()); + QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(r); + rd->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last(); + rd->m_clip_list = m_current_clip; + rd->m_opacity = m_opacity_stack.last(); } void QSGNodeUpdater::leaveRenderNode(QSGRenderNode *r) diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp new file mode 100644 index 0000000000..6a01fac212 --- /dev/null +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgrendererinterface.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QSGRendererInterface + \brief An interface providing access to some of the graphics API specific internals + of the scenegraph. + \inmodule QtQuick + \since 5.8 + + Renderer interfaces allow accessing graphics API specific functionality in + the scenegraph. Such internals are not typically exposed. However, when + integrating custom rendering via QSGRenderNode for example, it may become + necessary to query certain values, for instance the graphics device (e.g. + the Direct3D or Vulkan device) that is used by the scenegraph. + + \note QSGRendererInterface is only available after the scenegraph is + initialized. Additionally, there may be backend-specific limitations on + when the functions can be called. The only way that is guaranteed to + succeed is calling them when the rendering of a node (i.e. the preparation + of the command list for the next frame) is active. In practice this + typically means QSGRenderNode::render(). + */ + +/*! + \enum QSGRenderNode::GraphicsAPI + \value Unknown An unknown graphics API is in use + \value Software The Qt Quick 2D Renderer is in use + \value OpenGL OpenGL ES 2.0 or higher + \value Direct3D12 Direct3D 12 + \value Vulkan Vulkan + \value Metal Metal + */ + +/*! + \enum QSGRenderNode::Resource + \value Device The graphics device + \value CommandQueue The graphics command queue used by the scenergaph + \value CommandList The command list or buffer used by the scenegraph + */ + +QSGRendererInterface::~QSGRendererInterface() +{ +} + +/*! + \fn QSGRenderNode::GraphicsAPI QSGRenderNode::graphicsAPI() const + + Returns the graphics API that is in use by the Qt Quick scenegraph. + */ + +/*! + Queries a graphics \a resource. Returns null when the resource in question is + not supported or not available. + + When successful, the returned pointer is either a direct pointer to an + interface (and can be cast, for example, to \c{ID3D12Device *}) or a + pointer to an opaque handle that needs to be dereferenced first (for + example, \c{VkDevice dev = *static_cast<VkDevice *>(result)}). The latter + is necessary since such handles may have sizes different from a pointer. + */ +void *QSGRendererInterface::getResource(Resource resource) const +{ + Q_UNUSED(resource); + return nullptr; +} + +/*! + Queries a graphics resource. \a resource is a backend-specific key. This + allows supporting any future resources that are not listed in the + Resource enum. + */ +void *QSGRendererInterface::getResource(const char *resource) const +{ + Q_UNUSED(resource); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.h b/src/quick/scenegraph/coreapi/qsgrendererinterface.h new file mode 100644 index 0000000000..c4a145dd0f --- /dev/null +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGRENDERERINTERFACE_H +#define QSGRENDERERINTERFACE_H + +#include <QtQuick/qsgnode.h> + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGRendererInterface +{ +public: + enum GraphicsAPI { + Unknown, + Software, + OpenGL, + Direct3D12, + Vulkan, + Metal + }; + + enum Resource { + Device, + CommandQueue, + CommandList + }; + + virtual ~QSGRendererInterface(); + + virtual GraphicsAPI graphicsAPI() const = 0; + + virtual void *getResource(Resource resource) const; + virtual void *getResource(const char *resource) const; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index 1a38f6495e..8dc82a0d66 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -37,28 +37,51 @@ ** ****************************************************************************/ +#include "qsgrendernode.h" #include "qsgrendernode_p.h" QT_BEGIN_NAMESPACE +/*! + \class QSGRenderNode + \brief The QSGMaterialShader class represents a set of custom rendering commands + targeting the graphics API that is in use by the scenegraph. + \inmodule QtQuick + \since 5.8 + */ + QSGRenderNode::QSGRenderNode() - : QSGNode(RenderNodeType) - , m_matrix(0) - , m_clip_list(0) - , m_opacity(1) + : QSGNode(RenderNodeType), + d(new QSGRenderNodePrivate) { } -void QSGRenderNode::setInheritedOpacity(qreal opacity) +/*! + Destructs the render node. Derived classes are expected to perform cleanup + similar to releaseResources() in here. + + When a low-level graphics API is in use, the scenegraph will make sure + there is a CPU-side wait for the GPU to complete all work submitted to the + scenegraph's graphics command queue before the scenegraph's nodes are + deleted. Therefore there is no need to issue additional waits here, unless + the render() implementation is using additional command queues. + + \sa releaseResources() + */ +QSGRenderNode::~QSGRenderNode() { - Q_ASSERT(opacity >= 0 && opacity <= 1); - m_opacity = opacity; + delete d; } -/*! - \fn QSGRenderNode::StateFlags QSGRenderNode::changedStates() +QSGRenderNodePrivate::QSGRenderNodePrivate() + : m_matrix(0) + , m_clip_list(0) + , m_opacity(1) +{ +} - This function should return a mask where each bit represents OpenGL states changed by +/*! + This function should return a mask where each bit represents graphics states changed by the \l render() function: \list \li DepthState - depth write mask, depth test enabled, depth comparison function @@ -69,30 +92,72 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity) \li BlendState - blend enabled, blend function \li CullState - front face, cull face enabled \li ViewportState - viewport + \li RenderTargetState - render target \endlist - The function is called by the renderer so it can reset the OpenGL states after rendering this - node. + The function is called by the renderer so it can reset the states after + rendering this node. This makes the implementation of render() simpler + since it does not have to query and restore these states. - \internal + The default implementation returns 0, meaning no relevant state was changed + in render(). + + With APIs other than OpenGL the relevant states are only those that are set + via the command list (for example, OMSetRenderTargets, RSSetViewports, + RSSetScissorRects, OMSetBlendFactor, OMSetStencilRef in case of D3D12), and + only when such commands were added to the scenegraph's command list queried + via the QSGRendererInterface::CommandList resource enum. States set in + pipeline state objects do not need to be reported here. Similarly, draw + call related settings (root signature, descriptor heaps, etc.) are always + set again by the scenegraph so render() can freely change them. + + \note This function may be called before render(). */ +QSGRenderNode::StateFlags QSGRenderNode::changedStates() const +{ + return 0; +} /*! - \fn void QSGRenderNode::render(const RenderState &state) + \fn void QSGRenderNode::render(const RenderState *state) - This function is called by the renderer and should paint this node with OpenGL commands. + This function is called by the renderer and should paint this node with + directly invoking commands in the graphics API (OpenGL, Direct3D, etc.) + currently in use. - The states necessary for clipping has already been set before the function is called. - The clip is a combination of a stencil clip and scissor clip. Information about the clip is - found in \a state. + The states necessary for clipping has already been set before the function + is called. The clip is a combination of a stencil clip and scissor clip. + Information about the clip is found in \a state. + + \note This means that setting viewport, scissor rectangle, stencil + reference value, and similar is not necessary in render() since the + corresponding commands are on the command list (or, in case of OpenGL, the + context) already. However, for APIs other than OpenGL stencil-based + clipping will need enabling stencil testing in the pipeline state that is + used by render(). The effective opacity can be retrieved with \l inheritedOpacity(). - The projection matrix is available through \a state, while the model-view matrix can be - fetched with \l matrix(). The combined matrix is then the projection matrix times the - model-view matrix. + The projection matrix is available through \a state, while the model-view + matrix can be fetched with \l matrix(). The combined matrix is then the + projection matrix times the model-view matrix. The correct stacking of the + items in the scene is ensured by the projection matrix. + + When using the provided matrices, the coordinate system for vertex data + follows the usual QQuickItem conventions: top-left is (0, 0), bottom-right + is the corresponding QQuickItem's width() and height() minus one. For + example, assuming a two float (x-y) per vertex coordinate layout, a + triangle covering half of the item can be specified as (width - 1, height - 1), + (0, 0), (0, height - 1) using counter-clockwise direction. + + \note QSGRenderNode is provided as a means to implement custom 2D or 2.5D + Qt Quick items. It is not intended for integrating true 3D content into the + Qt Quick scene. That use case is better supported by + QQuickFramebufferObject, QQuickWindow::beforeRendering(), or the + equivalents of those for APIs other than OpenGL. - The following states are set before this function is called: + For OpenGL the following states are set on the render thread's context + before this function is called: \list \li glDepthMask(false) \li glDisable(GL_DEPTH_TEST) @@ -107,14 +172,128 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity) \li glDisable(GL_CULL_FACE) \endlist - States that are not listed above, but are included in \l StateFlags, can have arbitrary - values. + States that are not listed above, but are included in \l StateFlags, can + have arbitrary values. - \l changedStates() should return which states this function has changed. If a state is not - covered by \l StateFlags, the state should be set to the default value according to the - OpenGL specification. + \l changedStates() should return which states this function changes. If a + state is not covered by \l StateFlags, the state should be set to the + default value according to the OpenGL specification. For other APIs, see + the documentation for changedStates() for more information. - \internal + For APIs other than OpenGL, it will likely be necessary to query certain + API-specific resources (for example, the graphics device or the command + list/buffer to add the commands to). This is done via QSGRendererInterface. + + \sa QSGRendererInterface, QQuickWindow::rendererInterface() */ +/*! + \fn void QSGRenderNode::releaseResources() + + This function is called when all custom graphics resources allocated by + this node have to be freed immediately. In case the node does not directly + allocate graphics resources (buffers, textures, render targets, fences, + etc.) through the graphics API that is in use, there is nothing to do here. + + Failing to release all custom resources can lead to incorrect behavior in + graphics device loss scenarios on some systems since subsequent + reinitialization of the graphics system may fail. + + \note Some scenegraph backends may choose not to call this function. + Therefore it is expected that QSGRenderNode implementations perform cleanup + both in their destructor and in releaseResources(). + + Unlike with the destructor, it is expected that render() can reinitialize + all resources it needs when called after a call to releaseResources(). + + With OpenGL, the scenegraph's OpenGL context will be current both when + calling the destructor and this function. + */ + +/*! + \return pointer to the current model-view matrix. + */ +const QMatrix4x4 *QSGRenderNode::matrix() const +{ + return d->m_matrix; +} + +/*! + \return the current clip list. + */ +const QSGClipNode *QSGRenderNode::clipList() const +{ + return d->m_clip_list; +} + +/*! + \return the current effective opacity. + */ +qreal QSGRenderNode::inheritedOpacity() const +{ + return d->m_opacity; +} + +QSGRenderNode::RenderState::~RenderState() +{ +} + +/*! + \fn const QMatrix4x4 *QSGRenderNode::RenderState::projectionMatrix() const + + \return pointer to the current projection matrix. + + The model-view matrix can be retrieved with QSGRenderNode::matrix(). + Typically \c{projection * modelview} is the matrix that is then used in the + vertex shader to transform the vertices. + */ + +/*! + \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorRect() const + + \return the current scissor rectangle when clipping is active. + + \note Be aware of the differences between graphics APIs: for some the + scissor rect is only active when scissoring is enabled (for example, + OpenGL), while for others the scissor rect is equal to the viewport rect + when there is no need to scissor away anything (for example, Direct3D 12). + */ + +/*! + \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorEnabled() const + + \return the current state of scissoring. + + \note Only relevant for graphics APIs that have a dedicated on/off state of + scissoring. + */ + +/*! + \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilValue() const + + \return the current stencil reference value when clipping is active. + */ + +/*! + \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilEnabled() const + + \return the current state of stencil testing. + + \note With graphics APIs where stencil testing is enabled in pipeline state + objects, instead of individual state-setting commands, it is up to the + implementation of render() to enable stencil testing with operations + \c KEEP, comparison function \c EQUAL, and a read and write mask of \c 0xFF. + */ + +/*! + \return pointer to a \a state value. + + Reserved for future use. + */ +void *QSGRenderNode::RenderState::get(const char *state) const +{ + Q_UNUSED(state); + return nullptr; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h new file mode 100644 index 0000000000..5441b64fe4 --- /dev/null +++ b/src/quick/scenegraph/coreapi/qsgrendernode.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGRENDERNODE_H +#define QSGRENDERNODE_H + +#include <QtQuick/qsgnode.h> + +QT_BEGIN_NAMESPACE + +class QSGRenderNodePrivate; + +class Q_QUICK_EXPORT QSGRenderNode : public QSGNode +{ +public: + enum StateFlag { + DepthState = 0x01, + StencilState = 0x02, + ScissorState = 0x04, + ColorState = 0x08, + BlendState = 0x10, + CullState = 0x20, + ViewportState = 0x40, + RenderTargetState = 0x80 + }; + Q_DECLARE_FLAGS(StateFlags, StateFlag) + + struct Q_QUICK_EXPORT RenderState { + virtual ~RenderState(); + virtual const QMatrix4x4 *projectionMatrix() const = 0; + virtual QRect scissorRect() const = 0; + virtual bool scissorEnabled() const = 0; + virtual int stencilValue() const = 0; + virtual bool stencilEnabled() const = 0; + virtual void *get(const char *state) const; + }; + + QSGRenderNode(); + ~QSGRenderNode(); + + virtual StateFlags changedStates() const; + virtual void render(const RenderState *state) = 0; + virtual void releaseResources() = 0; + + const QMatrix4x4 *matrix() const; + const QSGClipNode *clipList() const; + qreal inheritedOpacity() const; + +private: + QSGRenderNodePrivate *d; + friend class QSGRenderNodePrivate; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags) + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/scenegraph/coreapi/qsgrendernode_p.h b/src/quick/scenegraph/coreapi/qsgrendernode_p.h index 8659b0e62c..5c42e55689 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode_p.h +++ b/src/quick/scenegraph/coreapi/qsgrendernode_p.h @@ -51,64 +51,23 @@ // We mean it. // -#include "qsgnode.h" -#include <private/qtquickglobal_p.h> +#include <QtQuick/qsgnode.h> +#include <QtQuick/qsgrendernode.h> QT_BEGIN_NAMESPACE -namespace QSGBatchRenderer { - class Renderer; -} - -class Q_QUICK_PRIVATE_EXPORT QSGRenderNode : public QSGNode +class QSGRenderNodePrivate { public: - enum StateFlag - { - DepthState = 0x01, // depth mask, depth test enable, depth func, clear depth - StencilState = 0x02, // stencil mask, stencil test enable, stencil op, stencil func, clear stencil - ScissorState = 0x04, // scissor enable, scissor test enable - ColorState = 0x08, // clear color, color mask - BlendState = 0x10, // blend enable, blend func - CullState = 0x20, // front face, cull face enable - ViewportState = 0x40 // viewport - }; - Q_DECLARE_FLAGS(StateFlags, StateFlag) - - struct RenderState - { - // The model-view matrix can be retrieved with matrix(). - // The opacity can be retrieved with inheritedOpacity(). - const QMatrix4x4 *projectionMatrix; - QRect scissorRect; - int stencilValue; - - bool stencilEnabled; - bool scissorEnabled; - }; - - QSGRenderNode(); + QSGRenderNodePrivate(); - virtual StateFlags changedStates() = 0; - virtual void render(const RenderState &state) = 0; - - const QMatrix4x4 *matrix() const { return m_matrix; } - const QSGClipNode *clipList() const { return m_clip_list; } - - void setInheritedOpacity(qreal opacity); - qreal inheritedOpacity() const { return m_opacity; } - -private: - friend class QSGNodeUpdater; - friend class QSGBatchRenderer::Renderer; + static QSGRenderNodePrivate *get(QSGRenderNode *node) { return node->d; } const QMatrix4x4 *m_matrix; const QSGClipNode *m_clip_list; qreal m_opacity; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags) - QT_END_NAMESPACE #endif diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index b0dd24af23..0f0a7be3b2 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -296,6 +296,13 @@ QSize QSGContext::minimumFBOSize() const return QSize(1, 1); } +QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext) +{ + Q_UNUSED(renderContext); + qWarning("QSGRendererInterface not implemented"); + return nullptr; +} + QSGRenderContext::QSGRenderContext(QSGContext *context) : m_sg(context) , m_distanceFieldCacheManager(0) diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 3893560142..19a8636f19 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -82,6 +82,7 @@ class QQuickTextureFactory; class QSGDistanceFieldGlyphCacheManager; class QSGContext; class QQuickPaintedItem; +class QSGRendererInterface; Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP) Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION) @@ -170,6 +171,8 @@ public: virtual QSize minimumFBOSize() const; virtual QSurfaceFormat defaultSurfaceFormat() const = 0; + virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext); + static QSGContext *createDefaultContext(); static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image); static QSGRenderLoop *createWindowManager(); diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index f969359e7c..4b05f64887 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -240,4 +240,15 @@ bool QSGDefaultContext::isDistanceFieldEnabled() const return !m_distanceFieldDisabled; } +QSGRendererInterface *QSGDefaultContext::rendererInterface(QSGRenderContext *renderContext) +{ + Q_UNUSED(renderContext); + return this; +} + +QSGRendererInterface::GraphicsAPI QSGDefaultContext::graphicsAPI() const +{ + return OpenGL; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultcontext_p.h b/src/quick/scenegraph/qsgdefaultcontext_p.h index 0569b7c321..923d1ee7ec 100644 --- a/src/quick/scenegraph/qsgdefaultcontext_p.h +++ b/src/quick/scenegraph/qsgdefaultcontext_p.h @@ -53,10 +53,11 @@ #include <QtQuick/private/qsgcontext_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> +#include "qsgrendererinterface.h" QT_BEGIN_NAMESPACE -class QSGDefaultContext : public QSGContext +class QSGDefaultContext : public QSGContext, public QSGRendererInterface { public: QSGDefaultContext(QObject *parent = 0); @@ -72,10 +73,13 @@ public: QSGNinePatchNode *createNinePatchNode() override; QSGLayer *createLayer(QSGRenderContext *renderContext) override; QSurfaceFormat defaultSurfaceFormat() const override; + QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override; void setDistanceFieldEnabled(bool enabled); bool isDistanceFieldEnabled() const; + GraphicsAPI graphicsAPI() const override; + private: QMutex m_mutex; QSGContext::AntialiasingMethod m_antialiasingMethod; diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 79971a2b0d..d8dfd01e7a 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -14,7 +14,9 @@ HEADERS += \ $$PWD/coreapi/qsgabstractrenderer.h \ $$PWD/coreapi/qsgabstractrenderer_p.h \ $$PWD/coreapi/qsgrenderer_p.h \ + $$PWD/coreapi/qsgrendernode.h \ $$PWD/coreapi/qsgrendernode_p.h \ + $$PWD/coreapi/qsgrendererinterface.h \ $$PWD/coreapi/qsggeometry_p.h SOURCES += \ @@ -24,7 +26,8 @@ SOURCES += \ $$PWD/coreapi/qsgnode.cpp \ $$PWD/coreapi/qsgnodeupdater.cpp \ $$PWD/coreapi/qsgrenderer.cpp \ - $$PWD/coreapi/qsgrendernode.cpp + $$PWD/coreapi/qsgrendernode.cpp \ + $$PWD/coreapi/qsgrendererinterface.cpp contains(QT_CONFIG, opengl(es1|es2)?) { HEADERS += \ diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index da7a65cfec..3f2c69d461 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -209,4 +209,20 @@ QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, CreateTex return 0; } +/*! + Returns the current renderer interface if there is one. Otherwise null is returned. + + \sa QSGRenderNode, QSGRendererInterface + \since 5.8 + */ +QSGRendererInterface *QSGEngine::rendererInterface() const +{ + Q_D(const QSGEngine); + if (!d->sgRenderContext->isValid()) { + qWarning("The QSGRendererInterface cannot be queried before the scenegraph is initialized"); + return nullptr; + } + return d->sgRenderContext->sceneGraphContext()->rendererInterface(d->sgRenderContext.data()); +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index 89af71fb47..9d27fb5525 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -49,6 +49,7 @@ class QOpenGLContext; class QSGAbstractRenderer; class QSGEnginePrivate; class QSGTexture; +class QSGRendererInterface; class Q_QUICK_EXPORT QSGEngine : public QObject { @@ -72,6 +73,7 @@ public: QSGAbstractRenderer *createRenderer() const; QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption()) const; QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; + QSGRendererInterface *rendererInterface() const; }; QT_END_NAMESPACE |