Merge remote-tracking branch 'origin/wip/scenegraphng' into dev

Change-Id: Id0f9774dba13ccf10facc7da91b6791a96e0d778
This commit is contained in:
Laszlo Agocs 2016-06-01 15:37:02 +02:00
commit 272b9a8ad6
262 changed files with 27354 additions and 3730 deletions

2
.gitignore vendored
View File

@ -282,3 +282,5 @@ src/qml/RegExpJitTables.h
src/qml/udis86_itab.c
src/qml/udis86_itab.h
# Generated HLSL bytecode headers
*.hlslh

View File

@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <d3d12.h>
#include <dxgi1_4.h>
#include <wrl/client.h>
using namespace Microsoft::WRL;
int main(int, char **)
{
ID3D12Device *dev = 0;
return 0;
}

View File

@ -0,0 +1,4 @@
SOURCES = d3d12.cpp
CONFIG -= qt dylib
CONFIG += console
LIBS += -ldxgi -ld3d12

View File

@ -25,8 +25,12 @@ SUBDIRS = quick-accessibility \
imageresponseprovider \
window \
particles \
demos \
rendercontrol
demos
#OpenGL Support Required
contains(QT_CONFIG, opengl(es1|es2)?) {
SUBDIRS += rendercontrol
}
# Widget dependent examples
qtHaveModule(widgets) {

View File

@ -135,7 +135,7 @@ QSGNode *BezierCurve::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
//! [4] //! [5]
geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), m_segmentCount);
geometry->setLineWidth(2);
geometry->setDrawingMode(GL_LINE_STRIP);
geometry->setDrawingMode(QSGGeometry::DrawLineStrip);
node->setGeometry(geometry);
node->setFlag(QSGNode::OwnsGeometry);
//! [5] //! [6]

View File

@ -0,0 +1,79 @@
/****************************************************************************
**
** 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"
CustomRenderItem::CustomRenderItem(QQuickItem *parent)
: QQuickItem(parent)
{
// Our item shows something so set the flag.
setFlag(ItemHasContents);
}
QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{
QSGRenderNode *n = static_cast<QSGRenderNode *>(node);
if (!n) {
QSGRendererInterface *ri = window()->rendererInterface();
if (!ri)
return nullptr;
switch (ri->graphicsApi()) {
case QSGRendererInterface::OpenGL:
#ifndef QT_NO_OPENGL
n = new OpenGLRenderNode(this);
break;
#endif
case QSGRendererInterface::Direct3D12:
#ifdef HAS_D3D12
n = new D3D12RenderNode(this);
break;
#endif
default:
return nullptr;
}
}
return n;
}

View File

@ -0,0 +1,55 @@
/****************************************************************************
**
** 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>
class CustomRenderItem : public QQuickItem
{
Q_OBJECT
public:
CustomRenderItem(QQuickItem *parent = nullptr);
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override;
};
#endif

View File

@ -0,0 +1,244 @@
/****************************************************************************
**
** 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 <QQuickItem>
#include <QQuickWindow>
#include <QSGRendererInterface>
#ifdef HAS_D3D12
#include "vs_shader.hlslh"
#include "ps_shader.hlslh"
D3D12RenderNode::D3D12RenderNode(QQuickItem *item)
: m_item(item)
{
}
D3D12RenderNode::~D3D12RenderNode()
{
releaseResources();
}
void D3D12RenderNode::releaseResources()
{
if (vbPtr) {
vertexBuffer->Unmap(0, nullptr);
vbPtr = nullptr;
}
if (cbPtr) {
constantBuffer->Unmap(0, nullptr);
cbPtr = nullptr;
}
constantBuffer = nullptr;
vertexBuffer = nullptr;
rootSignature = nullptr;
pipelineState = nullptr;
m_device = nullptr;
}
void D3D12RenderNode::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;
}
}
void D3D12RenderNode::render(const RenderState *state)
{
if (!m_device)
init();
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, 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

View File

@ -0,0 +1,80 @@
/****************************************************************************
**
** 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 <qsgrendernode.h>
#ifdef HAS_D3D12
class QQuickItem;
#include <d3d12.h>
#include <wrl/client.h>
using namespace Microsoft::WRL;
class D3D12RenderNode : public QSGRenderNode
{
public:
D3D12RenderNode(QQuickItem *item);
~D3D12RenderNode();
void render(const RenderState *state) override;
void releaseResources() override;
private:
void init();
QQuickItem *m_item;
ID3D12Device *m_device = nullptr;
ComPtr<ID3D12PipelineState> pipelineState;
ComPtr<ID3D12RootSignature> rootSignature;
ComPtr<ID3D12Resource> vertexBuffer;
ComPtr<ID3D12Resource> constantBuffer;
D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
quint8 *vbPtr = nullptr;
quint8 *cbPtr = nullptr;
};
#endif // HAS_D3D12
#endif

View File

@ -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();
}

View File

@ -0,0 +1,97 @@
/****************************************************************************
**
** 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.8
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
property int api: GraphicsInfo.api
text: "Custom rendering via the graphics API " + (api === GraphicsInfo.OpenGL ? "OpenGL" : (api === GraphicsInfo.Direct3D12 ? "Direct3D 12" : ""))
color: "yellow"
}
}
}

View File

@ -0,0 +1,146 @@
/****************************************************************************
**
** 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"
#include <QQuickItem>
#ifndef QT_NO_OPENGL
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLFunctions>
OpenGLRenderNode::OpenGLRenderNode(QQuickItem *item)
: m_item(item)
{
}
OpenGLRenderNode::~OpenGLRenderNode()
{
releaseResources();
}
// No need to reimplement changedStates() since our rendering is so simple,
// without involving any state changes.
void OpenGLRenderNode::releaseResources()
{
delete m_program;
m_program = nullptr;
delete m_vbo;
m_vbo = nullptr;
}
void OpenGLRenderNode::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();
}
void OpenGLRenderNode::render(const RenderState *state)
{
if (!m_program)
init();
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
m_program->bind();
m_program->setUniformValue(m_matrixUniform, *state->projectionMatrix() * *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

View File

@ -0,0 +1,72 @@
/****************************************************************************
**
** 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 <qsgrendernode.h>
#ifndef QT_NO_OPENGL
class QQuickItem;
class QOpenGLShaderProgram;
class QOpenGLBuffer;
class OpenGLRenderNode : public QSGRenderNode
{
public:
OpenGLRenderNode(QQuickItem *item);
~OpenGLRenderNode();
void render(const RenderState *state) override;
void releaseResources() override;
private:
void init();
QQuickItem *m_item;
QOpenGLShaderProgram *m_program = nullptr;
int m_matrixUniform;
QOpenGLBuffer *m_vbo = nullptr;
};
#endif // QT_NO_OPENGL
#endif

View File

@ -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)
}

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/scenegraph/rendernode">
<file>main.qml</file>
</qresource>
</RCC>

View File

@ -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;
}

View File

@ -1,14 +1,21 @@
TEMPLATE = subdirs
contains(QT_CONFIG, opengl(es1|es2)?) {
SUBDIRS += \
graph \
simplematerial \
sgengine \
textureinsgnode \
openglunderqml \
textureinsgnode \
textureinthread \
twotextureproviders
}
SUBDIRS += \
customgeometry \
graph \
openglunderqml \
sgengine \
simplematerial \
textureinsgnode \
textureinthread \
threadedanimation \
twotextureproviders
rendernode \
threadedanimation
EXAMPLE_FILES += \
shared

View File

@ -0,0 +1,10 @@
for (SHADER, HLSL_SHADERS) {
INPUT = $$eval($${SHADER}.input)
fxc_$${SHADER}.input = $$INPUT
fxc_$${SHADER}.commands = fxc.exe /nologo /E $$eval($${SHADER}.entry) /T $$eval($${SHADER}.type) /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
fxc_$${SHADER}.output = $$eval($${SHADER}.header)
fxc_$${SHADER}.dependency_type = TYPE_C
fxc_$${SHADER}.variable_out = HEADERS
fxc_$${SHADER}.CONFIG += target_predeps
QMAKE_EXTRA_COMPILERS += fxc_$${SHADER}
}

View File

@ -1,3 +1,6 @@
load(configure)
qtCompileTest(d3d12)
CONFIG += tests_need_tools examples_need_tools
load(qt_parts)

View File

@ -13,9 +13,13 @@ qtHaveModule(quick) {
SUBDIRS += \
layouts \
qtquick2 \
particles \
window \
testlib
contains(QT_CONFIG, opengl(es1|es2)?) {
SUBDIRS += \
particles
}
}
qtHaveModule(xmlpatterns) : SUBDIRS += xmllistmodel

View File

@ -94,6 +94,7 @@ struct PlainVertices {
QQuickCustomParticle::QQuickCustomParticle(QQuickItem* parent)
: QQuickParticlePainter(parent)
, m_common(this)
, m_dirtyUniforms(true)
, m_dirtyUniformValues(true)
, m_dirtyTextureProviders(true)
@ -237,7 +238,7 @@ void QQuickCustomParticle::reset()
QSGNode *QQuickCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
QQuickShaderEffectNode *rootNode = static_cast<QQuickShaderEffectNode *>(oldNode);
QQuickOpenGLShaderEffectNode *rootNode = static_cast<QQuickOpenGLShaderEffectNode *>(oldNode);
if (m_pleaseReset){
delete rootNode;//Automatically deletes children
rootNode = 0;
@ -258,7 +259,7 @@ QSGNode *QQuickCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNode
return rootNode;
}
QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffectNode *rootNode)
QQuickOpenGLShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickOpenGLShaderEffectNode *rootNode)
{
if (!rootNode)
rootNode = buildCustomNodes();
@ -269,7 +270,7 @@ QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffec
if (m_dirtyProgram) {
const bool isES = QOpenGLContext::currentContext()->isOpenGLES();
QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(rootNode->material());
QQuickOpenGLShaderEffectMaterial *material = static_cast<QQuickOpenGLShaderEffectMaterial *>(rootNode->material());
Q_ASSERT(material);
Key s = m_common.source;
@ -292,7 +293,7 @@ QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffec
material->setProgramSource(s);
material->attributes = m_common.attributes;
foreach (QQuickShaderEffectNode* node, m_nodes)
foreach (QQuickOpenGLShaderEffectNode* node, m_nodes)
node->markDirty(QSGNode::DirtyMaterial);
m_dirtyProgram = false;
@ -305,9 +306,9 @@ QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffec
return rootNode;
}
QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
QQuickOpenGLShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
{
typedef QHash<int, QQuickShaderEffectNode*>::const_iterator NodeHashConstIt;
typedef QHash<int, QQuickOpenGLShaderEffectNode*>::const_iterator NodeHashConstIt;
if (!QOpenGLContext::currentContext())
return 0;
@ -325,14 +326,14 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
if (groups().isEmpty())
return 0;
QQuickShaderEffectNode *rootNode = 0;
QQuickShaderEffectMaterial *material = new QQuickShaderEffectMaterial;
QQuickOpenGLShaderEffectNode *rootNode = 0;
QQuickOpenGLShaderEffectMaterial *material = new QQuickOpenGLShaderEffectMaterial;
m_dirtyProgram = true;
for (auto groupId : groupIds()) {
int count = m_system->groupData[groupId]->size();
QQuickShaderEffectNode* node = new QQuickShaderEffectNode();
QQuickOpenGLShaderEffectNode* node = new QQuickOpenGLShaderEffectNode();
m_nodes.insert(groupId, node);
node->setMaterial(material);
@ -398,7 +399,7 @@ void QQuickCustomParticle::propertyChanged(int mappedId)
}
void QQuickCustomParticle::buildData(QQuickShaderEffectNode *rootNode)
void QQuickCustomParticle::buildData(QQuickOpenGLShaderEffectNode *rootNode)
{
if (!rootNode)
return;
@ -408,9 +409,9 @@ void QQuickCustomParticle::buildData(QQuickShaderEffectNode *rootNode)
m_common.uniformData[shaderType][i].value = qVariantFromValue(m_lastTime);
}
}
m_common.updateMaterial(rootNode, static_cast<QQuickShaderEffectMaterial *>(rootNode->material()),
m_common.updateMaterial(rootNode, static_cast<QQuickOpenGLShaderEffectMaterial *>(rootNode->material()),
m_dirtyUniforms, true, m_dirtyTextureProviders);
foreach (QQuickShaderEffectNode* node, m_nodes)
foreach (QQuickOpenGLShaderEffectNode* node, m_nodes)
node->markDirty(QSGNode::DirtyMaterial);
m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
}

View File

@ -51,8 +51,8 @@
// We mean it.
//
#include "qquickparticlepainter_p.h"
#include <private/qquickshadereffectnode_p.h>
#include <private/qquickshadereffect_p.h>
#include <private/qquickopenglshadereffectnode_p.h>
#include <private/qquickopenglshadereffect_p.h>
#include <QSignalMapper>
QT_BEGIN_NAMESPACE
@ -88,11 +88,11 @@ protected:
virtual void commit(int gIdx, int pIdx);
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
QQuickShaderEffectNode *prepareNextFrame(QQuickShaderEffectNode *rootNode);
QQuickOpenGLShaderEffectNode *prepareNextFrame(QQuickOpenGLShaderEffectNode *rootNode);
void reset();
void resize(int oldCount, int newCount);
virtual void componentComplete();
QQuickShaderEffectNode *buildCustomNodes();
QQuickOpenGLShaderEffectNode *buildCustomNodes();
void sceneGraphInvalidated();
void itemChange(ItemChange change, const ItemChangeData &value);
@ -102,15 +102,15 @@ private Q_SLOTS:
void propertyChanged(int mappedId);
private:
typedef QQuickShaderEffectMaterialKey Key;
typedef QQuickShaderEffectMaterial::UniformData UniformData;
typedef QQuickOpenGLShaderEffectMaterialKey Key;
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
void buildData(QQuickShaderEffectNode *rootNode);
void buildData(QQuickOpenGLShaderEffectNode *rootNode);
void updateVertexShader();
QQuickShaderEffectCommon m_common;
QQuickOpenGLShaderEffectCommon m_common;
QHash<int, QQuickShaderEffectNode*> m_nodes;
QHash<int, QQuickOpenGLShaderEffectNode*> m_nodes;
qreal m_lastTime;
uint m_dirtyUniforms : 1;

View File

@ -1,2 +1,4 @@
TEMPLATE = subdirs
!contains(QT_CONFIG, no-qml-debug):SUBDIRS += qmltooling
SUBDIRS += scenegraph

View File

@ -0,0 +1,3 @@
{
"Keys": ["d3d12"]
}

View File

@ -0,0 +1,55 @@
TARGET = qsgd3d12backend
QT += core-private gui-private qml-private quick-private
PLUGIN_TYPE = scenegraph
PLUGIN_CLASS_NAME = QSGD3D12Adaptation
load(qt_plugin)
QMAKE_TARGET_PRODUCT = "Qt Quick D3D12 Renderer (Qt $$QT_VERSION)"
QMAKE_TARGET_DESCRIPTION = "Quick D3D12 Renderer for Qt."
SOURCES += \
$$PWD/qsgd3d12adaptation.cpp \
$$PWD/qsgd3d12renderloop.cpp \
$$PWD/qsgd3d12renderer.cpp \
$$PWD/qsgd3d12context.cpp \
$$PWD/qsgd3d12rendercontext.cpp \
$$PWD/qsgd3d12rectanglenode.cpp \
$$PWD/qsgd3d12material.cpp \
$$PWD/qsgd3d12builtinmaterials.cpp \
$$PWD/qsgd3d12texture.cpp \
$$PWD/qsgd3d12imagenode.cpp \
$$PWD/qsgd3d12glyphnode.cpp \
$$PWD/qsgd3d12glyphcache.cpp \
$$PWD/qsgd3d12layer.cpp \
$$PWD/qsgd3d12shadereffectnode.cpp \
$$PWD/qsgd3d12painternode.cpp
NO_PCH_SOURCES += \
$$PWD/qsgd3d12engine.cpp
HEADERS += \
$$PWD/qsgd3d12adaptation_p.h \
$$PWD/qsgd3d12renderloop_p.h \
$$PWD/qsgd3d12renderer_p.h \
$$PWD/qsgd3d12context_p.h \
$$PWD/qsgd3d12rendercontext_p.h \
$$PWD/qsgd3d12engine_p.h \
$$PWD/qsgd3d12engine_p_p.h \
$$PWD/qsgd3d12rectanglenode_p.h \
$$PWD/qsgd3d12material_p.h \
$$PWD/qsgd3d12builtinmaterials_p.h \
$$PWD/qsgd3d12texture_p.h \
$$PWD/qsgd3d12imagenode_p.h \
$$PWD/qsgd3d12glyphnode_p.h \
$$PWD/qsgd3d12glyphcache_p.h \
$$PWD/qsgd3d12layer_p.h \
$$PWD/qsgd3d12shadereffectnode_p.h \
$$PWD/qsgd3d12painternode_p.h
LIBS += -ldxgi -ld3d12 -ld3dcompiler
include($$PWD/shaders/shaders.pri)
OTHER_FILES += $$PWD/d3d12.json

View File

@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgd3d12adaptation_p.h"
#include "qsgd3d12renderloop_p.h"
#include "qsgd3d12context_p.h"
QT_BEGIN_NAMESPACE
QSGD3D12Adaptation::QSGD3D12Adaptation(QObject *parent)
: QSGContextPlugin(parent)
{
}
QStringList QSGD3D12Adaptation::keys() const
{
return QStringList() << QLatin1String("d3d12");
}
QSGContext *QSGD3D12Adaptation::create(const QString &) const
{
if (!contextInstance)
contextInstance = new QSGD3D12Context;
return contextInstance;
}
QSGContextFactoryInterface::Flags QSGD3D12Adaptation::flags(const QString &) const
{
return QSGContextFactoryInterface::SupportsShaderEffectNode;
}
QSGRenderLoop *QSGD3D12Adaptation::createWindowManager()
{
return new QSGD3D12RenderLoop;
}
QSGD3D12Context *QSGD3D12Adaptation::contextInstance = nullptr;
QT_END_NAMESPACE

View File

@ -0,0 +1,81 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12ADAPTATION_P_H
#define QSGD3D12ADAPTATION_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgcontextplugin_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Context;
class QSGContext;
class QSGRenderLoop;
class QSGD3D12Adaptation : public QSGContextPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSGContextFactoryInterface" FILE "d3d12.json")
public:
QSGD3D12Adaptation(QObject *parent = 0);
QStringList keys() const override;
QSGContext *create(const QString &key) const override;
QSGContextFactoryInterface::Flags flags(const QString &key) const override;
QSGRenderLoop *createWindowManager() override;
private:
static QSGD3D12Context *contextInstance;
};
QT_END_NAMESPACE
#endif // QSGD3D12ADAPTATION_P_H

View File

@ -0,0 +1,651 @@
/****************************************************************************
**
** 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 "qsgd3d12builtinmaterials_p.h"
#include "qsgd3d12rendercontext_p.h"
#include <QQuickWindow>
#include <QtCore/qmath.h>
#include <QtGui/private/qfixed_p.h>
#include "vs_vertexcolor.hlslh"
#include "ps_vertexcolor.hlslh"
#include "vs_smoothcolor.hlslh"
#include "ps_smoothcolor.hlslh"
#include "vs_texture.hlslh"
#include "ps_texture.hlslh"
#include "vs_smoothtexture.hlslh"
#include "ps_smoothtexture.hlslh"
#include "vs_textmask.hlslh"
#include "ps_textmask24.hlslh"
#include "ps_textmask32.hlslh"
#include "ps_textmask8.hlslh"
#include "vs_styledtext.hlslh"
#include "ps_styledtext.hlslh"
#include "vs_outlinedtext.hlslh"
#include "ps_outlinedtext.hlslh"
QT_BEGIN_NAMESPACE
// NB! In HLSL constant buffer data is packed into 4-byte boundaries and, more
// importantly, it is packed so that it does not cross a 16-byte (float4)
// boundary. Hence the need for padding in some cases.
QSGMaterialType QSGD3D12VertexColorMaterial::mtype;
QSGMaterialType *QSGD3D12VertexColorMaterial::type() const
{
return &QSGD3D12VertexColorMaterial::mtype;
}
int QSGD3D12VertexColorMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
// As the vertex color material has all its state in the vertex attributes
// defined by the geometry, all such materials will be equal.
return 0;
}
static const int VERTEX_COLOR_CB_SIZE_0 = 16 * sizeof(float); // float4x4
static const int VERTEX_COLOR_CB_SIZE_1 = sizeof(float); // float
static const int VERTEX_COLOR_CB_SIZE = VERTEX_COLOR_CB_SIZE_0 + VERTEX_COLOR_CB_SIZE_1;
int QSGD3D12VertexColorMaterial::constantBufferSize() const
{
return QSGD3D12Engine::alignedConstantBufferSize(VERTEX_COLOR_CB_SIZE);
}
void QSGD3D12VertexColorMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
pipelineState->shaders.vs = g_VS_VertexColor;
pipelineState->shaders.vsSize = sizeof(g_VS_VertexColor);
pipelineState->shaders.ps = g_PS_VertexColor;
pipelineState->shaders.psSize = sizeof(g_PS_VertexColor);
}
QSGD3D12Material::UpdateResults QSGD3D12VertexColorMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *,
ExtraState *,
quint8 *constantBuffer)
{
QSGD3D12Material::UpdateResults r = 0;
quint8 *p = constantBuffer;
if (state.isMatrixDirty()) {
memcpy(p, state.combinedMatrix().constData(), VERTEX_COLOR_CB_SIZE_0);
r |= UpdatedConstantBuffer;
}
p += VERTEX_COLOR_CB_SIZE_0;
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
memcpy(p, &opacity, VERTEX_COLOR_CB_SIZE_1);
r |= UpdatedConstantBuffer;
}
return r;
}
QSGD3D12SmoothColorMaterial::QSGD3D12SmoothColorMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
setFlag(Blending, true);
}
QSGMaterialType QSGD3D12SmoothColorMaterial::mtype;
QSGMaterialType *QSGD3D12SmoothColorMaterial::type() const
{
return &QSGD3D12SmoothColorMaterial::mtype;
}
int QSGD3D12SmoothColorMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
return 0;
}
static const int SMOOTH_COLOR_CB_SIZE_0 = 16 * sizeof(float); // float4x4
static const int SMOOTH_COLOR_CB_SIZE_1 = sizeof(float); // float
static const int SMOOTH_COLOR_CB_SIZE_2 = 2 * sizeof(float); // float2
static const int SMOOTH_COLOR_CB_SIZE = SMOOTH_COLOR_CB_SIZE_0 + SMOOTH_COLOR_CB_SIZE_1 + SMOOTH_COLOR_CB_SIZE_2;
int QSGD3D12SmoothColorMaterial::constantBufferSize() const
{
return QSGD3D12Engine::alignedConstantBufferSize(SMOOTH_COLOR_CB_SIZE);
}
void QSGD3D12SmoothColorMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
pipelineState->shaders.vs = g_VS_SmoothColor;
pipelineState->shaders.vsSize = sizeof(g_VS_SmoothColor);
pipelineState->shaders.ps = g_PS_SmoothColor;
pipelineState->shaders.psSize = sizeof(g_PS_SmoothColor);
}
QSGD3D12Material::UpdateResults QSGD3D12SmoothColorMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *,
ExtraState *,
quint8 *constantBuffer)
{
QSGD3D12Material::UpdateResults r = 0;
quint8 *p = constantBuffer;
if (state.isMatrixDirty()) {
memcpy(p, state.combinedMatrix().constData(), SMOOTH_COLOR_CB_SIZE_0);
r |= UpdatedConstantBuffer;
}
p += SMOOTH_COLOR_CB_SIZE_0;
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
memcpy(p, &opacity, SMOOTH_COLOR_CB_SIZE_1);
r |= UpdatedConstantBuffer;
}
p += SMOOTH_COLOR_CB_SIZE_1;
if (state.isMatrixDirty()) {
const QRect viewport = state.viewportRect();
const float v[] = { 2.0f / viewport.width(), 2.0f / viewport.height() };
memcpy(p, v, SMOOTH_COLOR_CB_SIZE_2);
r |= UpdatedConstantBuffer;
}
return r;
}
QSGMaterialType QSGD3D12TextureMaterial::mtype;
QSGMaterialType *QSGD3D12TextureMaterial::type() const
{
return &QSGD3D12TextureMaterial::mtype;
}
int QSGD3D12TextureMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
const QSGD3D12TextureMaterial *o = static_cast<const QSGD3D12TextureMaterial *>(other);
if (int diff = m_texture->textureId() - o->texture()->textureId())
return diff;
return int(m_filtering) - int(o->m_filtering);
}
static const int TEXTURE_CB_SIZE_0 = 16 * sizeof(float); // float4x4
static const int TEXTURE_CB_SIZE_1 = sizeof(float); // float
static const int TEXTURE_CB_SIZE = TEXTURE_CB_SIZE_0 + TEXTURE_CB_SIZE_1;
int QSGD3D12TextureMaterial::constantBufferSize() const
{
return QSGD3D12Engine::alignedConstantBufferSize(TEXTURE_CB_SIZE);
}
void QSGD3D12TextureMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
pipelineState->shaders.vs = g_VS_Texture;
pipelineState->shaders.vsSize = sizeof(g_VS_Texture);
pipelineState->shaders.ps = g_PS_Texture;
pipelineState->shaders.psSize = sizeof(g_PS_Texture);
pipelineState->shaders.rootSig.textureViewCount = 1;
}
QSGD3D12Material::UpdateResults QSGD3D12TextureMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *,
quint8 *constantBuffer)
{
QSGD3D12Material::UpdateResults r = 0;
quint8 *p = constantBuffer;
if (state.isMatrixDirty()) {
memcpy(p, state.combinedMatrix().constData(), TEXTURE_CB_SIZE_0);
r |= UpdatedConstantBuffer;
}
p += TEXTURE_CB_SIZE_0;
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
memcpy(p, &opacity, TEXTURE_CB_SIZE_1);
r |= UpdatedConstantBuffer;
}
Q_ASSERT(m_texture);
m_texture->setFiltering(m_filtering);
m_texture->setMipmapFiltering(m_mipmap_filtering);
m_texture->setHorizontalWrapMode(m_horizontal_wrap);
m_texture->setVerticalWrapMode(m_vertical_wrap);
QSGD3D12TextureView &tv(pipelineState->shaders.rootSig.textureViews[0]);
if (m_filtering == QSGTexture::Linear)
tv.filter = m_mipmap_filtering == QSGTexture::Linear
? QSGD3D12TextureView::FilterLinear : QSGD3D12TextureView::FilterMinMagLinearMipNearest;
else
tv.filter = m_mipmap_filtering == QSGTexture::Linear
? QSGD3D12TextureView::FilterMinMagNearestMipLinear : QSGD3D12TextureView::FilterNearest;
tv.addressModeHoriz = m_horizontal_wrap == QSGTexture::ClampToEdge ? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap;
tv.addressModeVert = m_vertical_wrap == QSGTexture::ClampToEdge ? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap;
m_texture->bind();
return r;
}
QSGD3D12SmoothTextureMaterial::QSGD3D12SmoothTextureMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
setFlag(Blending, true);
}
QSGMaterialType QSGD3D12SmoothTextureMaterial::mtype;
QSGMaterialType *QSGD3D12SmoothTextureMaterial::type() const
{
return &QSGD3D12SmoothTextureMaterial::mtype;
}
int QSGD3D12SmoothTextureMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
const QSGD3D12SmoothTextureMaterial *o = static_cast<const QSGD3D12SmoothTextureMaterial *>(other);
if (int diff = m_texture->textureId() - o->texture()->textureId())
return diff;
return int(m_filtering) - int(o->m_filtering);
}
static const int SMOOTH_TEXTURE_CB_SIZE_0 = 16 * sizeof(float); // float4x4
static const int SMOOTH_TEXTURE_CB_SIZE_1 = sizeof(float); // float
static const int SMOOTH_TEXTURE_CB_SIZE_2 = 2 * sizeof(float); // float2
static const int SMOOTH_TEXTURE_CB_SIZE = SMOOTH_TEXTURE_CB_SIZE_0 + SMOOTH_TEXTURE_CB_SIZE_1 + SMOOTH_TEXTURE_CB_SIZE_2;
int QSGD3D12SmoothTextureMaterial::constantBufferSize() const
{
return QSGD3D12Engine::alignedConstantBufferSize(SMOOTH_TEXTURE_CB_SIZE);
}
void QSGD3D12SmoothTextureMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
pipelineState->shaders.vs = g_VS_SmoothTexture;
pipelineState->shaders.vsSize = sizeof(g_VS_SmoothTexture);
pipelineState->shaders.ps = g_PS_SmoothTexture;
pipelineState->shaders.psSize = sizeof(g_PS_SmoothTexture);
pipelineState->shaders.rootSig.textureViewCount = 1;
}
QSGD3D12Material::UpdateResults QSGD3D12SmoothTextureMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *,
quint8 *constantBuffer)
{
QSGD3D12Material::UpdateResults r = 0;
quint8 *p = constantBuffer;
if (state.isMatrixDirty()) {
memcpy(p, state.combinedMatrix().constData(), SMOOTH_TEXTURE_CB_SIZE_0);
r |= UpdatedConstantBuffer;
}
p += SMOOTH_TEXTURE_CB_SIZE_0;
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
memcpy(p, &opacity, SMOOTH_TEXTURE_CB_SIZE_1);
r |= UpdatedConstantBuffer;
}
p += SMOOTH_TEXTURE_CB_SIZE_1;
if (state.isMatrixDirty()) {
const QRect viewport = state.viewportRect();
const float v[] = { 2.0f / viewport.width(), 2.0f / viewport.height() };
memcpy(p, v, SMOOTH_TEXTURE_CB_SIZE_2);
r |= UpdatedConstantBuffer;
}
Q_ASSERT(m_texture);
m_texture->setFiltering(m_filtering);
m_texture->setMipmapFiltering(m_mipmap_filtering);
m_texture->setHorizontalWrapMode(m_horizontal_wrap);
m_texture->setVerticalWrapMode(m_vertical_wrap);
QSGD3D12TextureView &tv(pipelineState->shaders.rootSig.textureViews[0]);
if (m_filtering == QSGTexture::Linear)
tv.filter = m_mipmap_filtering == QSGTexture::Linear
? QSGD3D12TextureView::FilterLinear : QSGD3D12TextureView::FilterMinMagLinearMipNearest;
else
tv.filter = m_mipmap_filtering == QSGTexture::Linear
? QSGD3D12TextureView::FilterMinMagNearestMipLinear : QSGD3D12TextureView::FilterNearest;
tv.addressModeHoriz = m_horizontal_wrap == QSGTexture::ClampToEdge ? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap;
tv.addressModeVert = m_vertical_wrap == QSGTexture::ClampToEdge ? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap;
m_texture->bind();
return r;
}
static inline QVector4D qsg_premultiply(const QVector4D &c, float globalOpacity)
{
float o = c.w() * globalOpacity;
return QVector4D(c.x() * o, c.y() * o, c.z() * o, o);
}
static inline int qsg_colorDiff(const QVector4D &a, const QVector4D &b)
{
if (a.x() != b.x())
return a.x() > b.x() ? 1 : -1;
if (a.y() != b.y())
return a.y() > b.y() ? 1 : -1;
if (a.z() != b.z())
return a.z() > b.z() ? 1 : -1;
if (a.w() != b.w())
return a.w() > b.w() ? 1 : -1;
return 0;
}
QSGD3D12TextMaterial::QSGD3D12TextMaterial(StyleType styleType, QSGD3D12RenderContext *rc,
const QRawFont &font, QFontEngine::GlyphFormat glyphFormat)
: m_styleType(styleType),
m_font(font),
m_rc(rc)
{
setFlag(Blending, true);
QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
if (QFontEngine *fontEngine = fontD->fontEngine) {
if (glyphFormat == QFontEngine::Format_None)
glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None
? fontEngine->glyphFormat : QFontEngine::Format_A32;
QSGD3D12Engine *d3dengine = rc->engine();
const float devicePixelRatio = d3dengine->windowDevicePixelRatio();
QTransform glyphCacheTransform = QTransform::fromScale(devicePixelRatio, devicePixelRatio);
if (!fontEngine->supportsTransformation(glyphCacheTransform))
glyphCacheTransform = QTransform();
m_glyphCache = fontEngine->glyphCache(d3dengine, glyphFormat, glyphCacheTransform);
if (!m_glyphCache || int(m_glyphCache->glyphFormat()) != glyphFormat) {
m_glyphCache = new QSGD3D12GlyphCache(d3dengine, glyphFormat, glyphCacheTransform);
fontEngine->setGlyphCache(d3dengine, m_glyphCache.data());
rc->registerFontengineForCleanup(fontEngine);
}
}
}
QSGMaterialType QSGD3D12TextMaterial::mtype[QSGD3D12TextMaterial::NTextMaterialTypes];
QSGMaterialType *QSGD3D12TextMaterial::type() const
{
// Format_A32 has special blend settings and therefore two materials with
// the same style but different formats where one is A32 are treated as
// different. This way the renderer can manage the pipeline state properly.
const int matStyle = m_styleType * 2;
const int matFormat = glyphCache()->glyphFormat() != QFontEngine::Format_A32 ? 0 : 1;
return &QSGD3D12TextMaterial::mtype[matStyle + matFormat];
}
int QSGD3D12TextMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
const QSGD3D12TextMaterial *o = static_cast<const QSGD3D12TextMaterial *>(other);
if (m_styleType != o->m_styleType)
return m_styleType - o->m_styleType;
if (m_glyphCache != o->m_glyphCache)
return m_glyphCache.data() < o->m_glyphCache.data() ? -1 : 1;
if (m_styleShift != o->m_styleShift)
return m_styleShift.y() - o->m_styleShift.y();
int styleColorDiff = qsg_colorDiff(m_styleColor, o->m_styleColor);
if (styleColorDiff)
return styleColorDiff;
return qsg_colorDiff(m_color, o->m_color);
}
static const int TEXT_CB_SIZE_0 = 16 * sizeof(float); // float4x4 mvp
static const int TEXT_CB_SIZE_1 = 2 * sizeof(float); // float2 textureScale
static const int TEXT_CB_SIZE_2 = sizeof(float); // float dpr
static const int TEXT_CB_SIZE_3 = sizeof(float); // float color
static const int TEXT_CB_SIZE_4 = 4 * sizeof(float); // float4 colorVec
static const int TEXT_CB_SIZE_5 = 2 * sizeof(float); // float2 shift
static const int TEXT_CB_SIZE_5_PADDING = 2 * sizeof(float); // float2 padding (the next float4 would cross the 16-byte boundary)
static const int TEXT_CB_SIZE_6 = 4 * sizeof(float); // float4 styleColor
static const int TEXT_CB_SIZE = TEXT_CB_SIZE_0 + TEXT_CB_SIZE_1 + TEXT_CB_SIZE_2 + TEXT_CB_SIZE_3
+ TEXT_CB_SIZE_4 + TEXT_CB_SIZE_5 + TEXT_CB_SIZE_5_PADDING + TEXT_CB_SIZE_6;
int QSGD3D12TextMaterial::constantBufferSize() const
{
return QSGD3D12Engine::alignedConstantBufferSize(TEXT_CB_SIZE);
}
void QSGD3D12TextMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
if (m_styleType == Normal) {
pipelineState->shaders.vs = g_VS_TextMask;
pipelineState->shaders.vsSize = sizeof(g_VS_TextMask);
switch (glyphCache()->glyphFormat()) {
case QFontEngine::Format_A32:
pipelineState->shaders.ps = g_PS_TextMask24;
pipelineState->shaders.psSize = sizeof(g_PS_TextMask24);
break;
case QFontEngine::Format_ARGB:
pipelineState->shaders.ps = g_PS_TextMask32;
pipelineState->shaders.psSize = sizeof(g_PS_TextMask32);
break;
default:
pipelineState->shaders.ps = g_PS_TextMask8;
pipelineState->shaders.psSize = sizeof(g_PS_TextMask8);
break;
}
} else if (m_styleType == Outlined) {
pipelineState->shaders.vs = g_VS_OutlinedText;
pipelineState->shaders.vsSize = sizeof(g_VS_OutlinedText);
pipelineState->shaders.ps = g_PS_OutlinedText;
pipelineState->shaders.psSize = sizeof(g_PS_OutlinedText);
} else {
pipelineState->shaders.vs = g_VS_StyledText;
pipelineState->shaders.vsSize = sizeof(g_VS_StyledText);
pipelineState->shaders.ps = g_PS_StyledText;
pipelineState->shaders.psSize = sizeof(g_PS_StyledText);
}
pipelineState->shaders.rootSig.textureViewCount = 1;
}
QSGD3D12Material::UpdateResults QSGD3D12TextMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer)
{
QSGD3D12Material::UpdateResults r = 0;
quint8 *p = constantBuffer;
if (glyphCache()->glyphFormat() == QFontEngine::Format_A32) {
// can freely change the state due to the way type() works
pipelineState->blend = QSGD3D12PipelineState::BlendColor;
extraState->blendFactor = m_color;
r |= UpdatedBlendFactor; // must be set always as this affects the command list
}
if (state.isMatrixDirty()) {
memcpy(p, state.combinedMatrix().constData(), TEXT_CB_SIZE_0);
r |= UpdatedConstantBuffer;
}
p += TEXT_CB_SIZE_0;
if (state.isCachedMaterialDataDirty() || m_lastGlyphCacheSize != glyphCache()->currentSize()) {
m_lastGlyphCacheSize = glyphCache()->currentSize();
const float textureScale[2] = { 1.0f / m_lastGlyphCacheSize.width(),
1.0f / m_lastGlyphCacheSize.height() };
memcpy(p, textureScale, TEXT_CB_SIZE_1);
r |= UpdatedConstantBuffer;
}
p += TEXT_CB_SIZE_1;
const float dpr = m_rc->engine()->windowDevicePixelRatio();
if (state.isCachedMaterialDataDirty() || m_lastDpr != dpr) {
m_lastDpr = dpr;
memcpy(p, &dpr, TEXT_CB_SIZE_2);
r |= UpdatedConstantBuffer;
}
p += TEXT_CB_SIZE_2;
if (state.isOpacityDirty() || m_lastColor != m_color) {
m_lastColor = m_color;
if (glyphCache()->glyphFormat() == QFontEngine::Format_A32) {
const QVector4D color = qsg_premultiply(m_color, state.opacity());
const float alpha = color.w();
memcpy(p, &alpha, TEXT_CB_SIZE_3);
} else if (glyphCache()->glyphFormat() == QFontEngine::Format_ARGB) {
const float opacity = m_color.w() * state.opacity();
memcpy(p, &opacity, TEXT_CB_SIZE_3);
} else {
const QVector4D color = qsg_premultiply(m_color, state.opacity());
const float f[4] = { color.x(), color.y(), color.z(), color.w() };
memcpy(p + TEXT_CB_SIZE_3, f, TEXT_CB_SIZE_4);
}
r |= UpdatedConstantBuffer;
}
p += TEXT_CB_SIZE_3 + TEXT_CB_SIZE_4;
if (m_styleType == Styled && (state.isCachedMaterialDataDirty() || m_lastStyleShift != m_styleShift)) {
m_lastStyleShift = m_styleShift;
const float f[2] = { m_styleShift.x(), m_styleShift.y() };
memcpy(p, f, TEXT_CB_SIZE_5);
r |= UpdatedConstantBuffer;
}
p += TEXT_CB_SIZE_5 + TEXT_CB_SIZE_5_PADDING;
if ((m_styleType == Styled || m_styleType == Outlined)
&& (state.isOpacityDirty() || m_lastStyleColor != m_styleColor)) {
m_lastStyleColor = m_styleColor;
const QVector4D color = qsg_premultiply(m_styleColor, state.opacity());
const float f[4] = { color.x(), color.y(), color.z(), color.w() };
memcpy(p, f, TEXT_CB_SIZE_6);
r |= UpdatedConstantBuffer;
}
QSGD3D12TextureView &tv(pipelineState->shaders.rootSig.textureViews[0]);
tv.filter = QSGD3D12TextureView::FilterNearest;
tv.addressModeHoriz = QSGD3D12TextureView::AddressClamp;
tv.addressModeVert = QSGD3D12TextureView::AddressClamp;
glyphCache()->useTexture();
return r;
}
void QSGD3D12TextMaterial::populate(const QPointF &p,
const QVector<quint32> &glyphIndexes,
const QVector<QPointF> &glyphPositions,
QSGGeometry *geometry,
QRectF *boundingRect,
QPointF *baseLine,
const QMargins &margins)
{
Q_ASSERT(m_font.isValid());
QVector<QFixedPoint> fixedPointPositions;
const int glyphPositionsSize = glyphPositions.size();
fixedPointPositions.reserve(glyphPositionsSize);
for (int i=0; i < glyphPositionsSize; ++i)
fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i)));
QSGD3D12GlyphCache *cache = glyphCache();
QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
fixedPointPositions.data());
cache->fillInPendingGlyphs();
int margin = fontD->fontEngine->glyphMargin(cache->glyphFormat());
float glyphCacheScaleX = cache->transform().m11();
float glyphCacheScaleY = cache->transform().m22();
float glyphCacheInverseScaleX = 1.0 / glyphCacheScaleX;
float glyphCacheInverseScaleY = 1.0 / glyphCacheScaleY;
Q_ASSERT(geometry->indexType() == QSGGeometry::TypeUnsignedShort);
geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
QVector4D *vp = reinterpret_cast<QVector4D *>(geometry->vertexDataAsTexturedPoint2D());
Q_ASSERT(geometry->sizeOfVertex() == sizeof(QVector4D));
ushort *ip = geometry->indexDataAsUShort();
QPointF position(p.x(), p.y() - m_font.ascent());
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
for (int i = 0; i < glyphIndexes.size(); ++i) {
QFixed subPixelPosition;
if (supportsSubPixelPositions)
subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x()));
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
QPointF glyphPosition = glyphPositions.at(i) + position;
float x = (qFloor(glyphPosition.x() * glyphCacheScaleX) * glyphCacheInverseScaleX)
+ (c.baseLineX * glyphCacheInverseScaleX) - margin;
float y = (qRound(glyphPosition.y() * glyphCacheScaleY) * glyphCacheInverseScaleY)
- (c.baseLineY * glyphCacheInverseScaleY) - margin;
float w = c.w * glyphCacheInverseScaleX;
float h = c.h * glyphCacheInverseScaleY;
*boundingRect |= QRectF(x + margin, y + margin, w, h);
float cx1 = x - margins.left();
float cx2 = x + w + margins.right();
float cy1 = y - margins.top();
float cy2 = y + h + margins.bottom();
float tx1 = c.x - margins.left();
float tx2 = c.x + c.w + margins.right();
float ty1 = c.y - margins.top();
float ty2 = c.y + c.h + margins.bottom();
if (baseLine->isNull())
*baseLine = glyphPosition;
vp[4 * i + 0] = QVector4D(cx1, cy1, tx1, ty1);
vp[4 * i + 1] = QVector4D(cx2, cy1, tx2, ty1);
vp[4 * i + 2] = QVector4D(cx1, cy2, tx1, ty2);
vp[4 * i + 3] = QVector4D(cx2, cy2, tx2, ty2);
int o = i * 4;
ip[6 * i + 0] = o + 0;
ip[6 * i + 1] = o + 2;
ip[6 * i + 2] = o + 3;
ip[6 * i + 3] = o + 3;
ip[6 * i + 4] = o + 1;
ip[6 * i + 5] = o + 0;
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,236 @@
/****************************************************************************
**
** 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 QSGD3D12BUILTINMATERIALS_P_H
#define QSGD3D12BUILTINMATERIALS_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qsgd3d12material_p.h"
#include "qsgd3d12glyphcache_p.h"
#include <private/qsgtexture_p.h>
#include <QRawFont>
QT_BEGIN_NAMESPACE
class QSGD3D12RenderContext;
class QSGD3D12VertexColorMaterial : public QSGD3D12Material
{
public:
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) override;
private:
static QSGMaterialType mtype;
};
class QSGD3D12SmoothColorMaterial : public QSGD3D12Material
{
public:
QSGD3D12SmoothColorMaterial();
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) override;
private:
static QSGMaterialType mtype;
};
class QSGD3D12TextureMaterial : public QSGD3D12Material
{
public:
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) override;
void setTexture(QSGTexture *texture) { m_texture = texture; }
QSGTexture *texture() const { return m_texture; }
void setMipmapFiltering(QSGTexture::Filtering filter) { m_mipmap_filtering = filter; }
QSGTexture::Filtering mipmapFiltering() const { return m_mipmap_filtering; }
void setFiltering(QSGTexture::Filtering filter) { m_filtering = filter; }
QSGTexture::Filtering filtering() const { return m_filtering; }
void setHorizontalWrapMode(QSGTexture::WrapMode hwrap) { m_horizontal_wrap = hwrap; }
QSGTexture::WrapMode horizontalWrapMode() const { return m_horizontal_wrap; }
void setVerticalWrapMode(QSGTexture::WrapMode vwrap) { m_vertical_wrap = vwrap; }
QSGTexture::WrapMode verticalWrapMode() const { return m_vertical_wrap; }
private:
static QSGMaterialType mtype;
QSGTexture *m_texture = nullptr;
QSGTexture::Filtering m_filtering = QSGTexture::Nearest;
QSGTexture::Filtering m_mipmap_filtering = QSGTexture::None;
QSGTexture::WrapMode m_horizontal_wrap = QSGTexture::ClampToEdge;
QSGTexture::WrapMode m_vertical_wrap = QSGTexture::ClampToEdge;
};
class QSGD3D12SmoothTextureMaterial : public QSGD3D12Material
{
public:
QSGD3D12SmoothTextureMaterial();
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) override;
void setTexture(QSGTexture *texture) { m_texture = texture; }
QSGTexture *texture() const { return m_texture; }
void setMipmapFiltering(QSGTexture::Filtering filter) { m_mipmap_filtering = filter; }
QSGTexture::Filtering mipmapFiltering() const { return m_mipmap_filtering; }
void setFiltering(QSGTexture::Filtering filter) { m_filtering = filter; }
QSGTexture::Filtering filtering() const { return m_filtering; }
void setHorizontalWrapMode(QSGTexture::WrapMode hwrap) { m_horizontal_wrap = hwrap; }
QSGTexture::WrapMode horizontalWrapMode() const { return m_horizontal_wrap; }
void setVerticalWrapMode(QSGTexture::WrapMode vwrap) { m_vertical_wrap = vwrap; }
QSGTexture::WrapMode verticalWrapMode() const { return m_vertical_wrap; }
private:
static QSGMaterialType mtype;
QSGTexture *m_texture = nullptr;
QSGTexture::Filtering m_filtering = QSGTexture::Nearest;
QSGTexture::Filtering m_mipmap_filtering = QSGTexture::None;
QSGTexture::WrapMode m_horizontal_wrap = QSGTexture::ClampToEdge;
QSGTexture::WrapMode m_vertical_wrap = QSGTexture::ClampToEdge;
};
class QSGD3D12TextMaterial : public QSGD3D12Material
{
public:
enum StyleType {
Normal,
Styled,
Outlined,
NStyleTypes
};
QSGD3D12TextMaterial(StyleType styleType, QSGD3D12RenderContext *rc, const QRawFont &font,
QFontEngine::GlyphFormat glyphFormat = QFontEngine::Format_None);
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) override;
void setColor(const QColor &c) { m_color = QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF()); }
void setColor(const QVector4D &color) { m_color = color; }
const QVector4D &color() const { return m_color; }
void setStyleShift(const QVector2D &shift) { m_styleShift = shift; }
const QVector2D &styleShift() const { return m_styleShift; }
void setStyleColor(const QColor &c) { m_styleColor = QVector4D(c.redF(), c.greenF(), c.blueF(), c.alphaF()); }
void setStyleColor(const QVector4D &color) { m_styleColor = color; }
const QVector4D &styleColor() const { return m_styleColor; }
void populate(const QPointF &position,
const QVector<quint32> &glyphIndexes, const QVector<QPointF> &glyphPositions,
QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine,
const QMargins &margins = QMargins(0, 0, 0, 0));
QSGD3D12GlyphCache *glyphCache() const { return static_cast<QSGD3D12GlyphCache *>(m_glyphCache.data()); }
private:
static const int NTextMaterialTypes = NStyleTypes * 2;
static QSGMaterialType mtype[NTextMaterialTypes];
StyleType m_styleType;
QSGD3D12RenderContext *m_rc;
QVector4D m_color;
QVector2D m_styleShift;
QVector4D m_styleColor;
QRawFont m_font;
QExplicitlySharedDataPointer<QFontEngineGlyphCache> m_glyphCache;
QSize m_lastGlyphCacheSize;
float m_lastDpr = 0;
QVector4D m_lastColor;
QVector2D m_lastStyleShift;
QVector4D m_lastStyleColor;
};
QT_END_NAMESPACE
#endif // QSGD3D12BUILTINMATERIALS_P_H

View File

@ -0,0 +1,124 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgd3d12context_p.h"
#include "qsgd3d12rendercontext_p.h"
#include "qsgd3d12rectanglenode_p.h"
#include "qsgd3d12imagenode_p.h"
#include "qsgd3d12glyphnode_p.h"
#include "qsgd3d12layer_p.h"
#include "qsgd3d12shadereffectnode_p.h"
#include "qsgd3d12painternode_p.h"
QT_BEGIN_NAMESPACE
QSGRenderContext *QSGD3D12Context::createRenderContext()
{
return new QSGD3D12RenderContext(this);
}
QSGRectangleNode *QSGD3D12Context::createRectangleNode()
{
return new QSGD3D12RectangleNode;
}
QSGImageNode *QSGD3D12Context::createImageNode()
{
return new QSGD3D12ImageNode;
}
QSGPainterNode *QSGD3D12Context::createPainterNode(QQuickPaintedItem *item)
{
return new QSGD3D12PainterNode(item);
}
QSGGlyphNode *QSGD3D12Context::createGlyphNode(QSGRenderContext *renderContext, bool preferNativeGlyphNode)
{
Q_UNUSED(preferNativeGlyphNode);
// ### distance field text rendering is not supported atm
QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext);
return new QSGD3D12GlyphNode(rc);
}
QSGNinePatchNode *QSGD3D12Context::createNinePatchNode()
{
return nullptr;
}
QSGLayer *QSGD3D12Context::createLayer(QSGRenderContext *renderContext)
{
QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext);
return new QSGD3D12Layer(rc);
}
QSGGuiThreadShaderEffectManager *QSGD3D12Context::createGuiThreadShaderEffectManager()
{
return new QSGD3D12GuiThreadShaderEffectManager;
}
QSGShaderEffectNode *QSGD3D12Context::createShaderEffectNode(QSGRenderContext *renderContext,
QSGGuiThreadShaderEffectManager *mgr)
{
QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext);
QSGD3D12GuiThreadShaderEffectManager *dmgr = static_cast<QSGD3D12GuiThreadShaderEffectManager *>(mgr);
return new QSGD3D12ShaderEffectNode(rc, dmgr);
}
QSize QSGD3D12Context::minimumFBOSize() const
{
return QSize(16, 16);
}
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

View File

@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12CONTEXT_P_H
#define QSGD3D12CONTEXT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgcontext_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Context : public QSGContext
{
public:
QSGD3D12Context(QObject *parent = 0) : QSGContext(parent) { }
QSGRenderContext *createRenderContext() override;
QSGRectangleNode *createRectangleNode() override;
QSGImageNode *createImageNode() override;
QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override;
QSGGlyphNode *createGlyphNode(QSGRenderContext *renderContext, bool preferNativeGlyphNode) override;
QSGNinePatchNode *createNinePatchNode() override;
QSGLayer *createLayer(QSGRenderContext *renderContext) override;
QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager() override;
QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
QSGGuiThreadShaderEffectManager *mgr) override;
QSize minimumFBOSize() const override;
QSurfaceFormat defaultSurfaceFormat() const override;
QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
};
QT_END_NAMESPACE
#endif // QSGD3D12CONTEXT_P_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,392 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12ENGINE_P_H
#define QSGD3D12ENGINE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QWindow>
#include <QImage>
#include <QVector4D>
#include <qsggeometry.h>
#include <qsgrendererinterface.h>
#include <qt_windows.h>
QT_BEGIN_NAMESPACE
// No D3D or COM headers must be pulled in here. All that has to be isolated
// to engine_p_p.h and engine.cpp.
class QSGD3D12EnginePrivate;
// Shader bytecode and other strings are expected to be static so that a
// different pointer means a different shader.
enum QSGD3D12Format {
FmtUnknown = 0,
FmtFloat4 = 2, // DXGI_FORMAT_R32G32B32A32_FLOAT
FmtFloat3 = 6, // DXGI_FORMAT_R32G32B32_FLOAT
FmtFloat2 = 16, // DXGI_FORMAT_R32G32_FLOAT
FmtFloat = 41, // DXGI_FORMAT_R32_FLOAT
// glVertexAttribPointer with GL_UNSIGNED_BYTE and normalized == true maps to the UNORM formats below
FmtUNormByte4 = 28, // DXGI_FORMAT_R8G8B8A8_UNORM
FmtUNormByte2 = 49, // DXGI_FORMAT_R8G8_UNORM
FmtUNormByte = 61, // DXGI_FORMAT_R8_UNORM
// Index data types
FmtUnsignedShort = 57, // DXGI_FORMAT_R16_UINT
FmtUnsignedInt = 42 // DXGI_FORMAT_R32_UINT
};
struct QSGD3D12InputElement
{
const char *semanticName = nullptr;
int semanticIndex = 0;
QSGD3D12Format format = FmtFloat4;
quint32 slot = 0;
quint32 offset = 0;
bool operator==(const QSGD3D12InputElement &other) const {
return semanticName == other.semanticName && semanticIndex == other.semanticIndex
&& format == other.format && slot == other.slot && offset == other.offset;
}
};
inline uint qHash(const QSGD3D12InputElement &key, uint seed = 0)
{
return qHash(key.semanticName, seed) + key.semanticIndex + key.format + key.offset;
}
struct QSGD3D12TextureView
{
enum Filter {
FilterNearest = 0,
FilterLinear = 0x15,
FilterMinMagNearestMipLinear = 0x1,
FilterMinMagLinearMipNearest = 0x14
};
enum AddressMode {
AddressWrap = 1,
AddressClamp = 3
};
Filter filter = FilterLinear;
AddressMode addressModeHoriz = AddressClamp;
AddressMode addressModeVert = AddressClamp;
bool operator==(const QSGD3D12TextureView &other) const {
return filter == other.filter
&& addressModeHoriz == other.addressModeHoriz
&& addressModeVert == other.addressModeVert;
}
};
inline uint qHash(const QSGD3D12TextureView &key, uint seed = 0)
{
Q_UNUSED(seed);
return key.filter + key.addressModeHoriz + key.addressModeVert;
}
const int QSGD3D12_MAX_TEXTURE_VIEWS = 8;
struct QSGD3D12RootSignature
{
int textureViewCount = 0;
QSGD3D12TextureView textureViews[QSGD3D12_MAX_TEXTURE_VIEWS];
bool operator==(const QSGD3D12RootSignature &other) const {
if (textureViewCount != other.textureViewCount)
return false;
for (int i = 0; i < textureViewCount; ++i)
if (!(textureViews[i] == other.textureViews[i]))
return false;
return true;
}
};
inline uint qHash(const QSGD3D12RootSignature &key, uint seed = 0)
{
return key.textureViewCount + (key.textureViewCount > 0 ? qHash(key.textureViews[0], seed) : 0);
}
// Shader bytecode blobs and root signature-related data.
struct QSGD3D12ShaderState
{
const quint8 *vs = nullptr;
quint32 vsSize = 0;
const quint8 *ps = nullptr;
quint32 psSize = 0;
QSGD3D12RootSignature rootSig;
bool operator==(const QSGD3D12ShaderState &other) const {
return vs == other.vs && vsSize == other.vsSize
&& ps == other.ps && psSize == other.psSize
&& rootSig == other.rootSig;
}
};
inline uint qHash(const QSGD3D12ShaderState &key, uint seed = 0)
{
return qHash(key.vs, seed) + key.vsSize + qHash(key.ps, seed) + key.psSize + qHash(key.rootSig, seed);
}
const int QSGD3D12_MAX_INPUT_ELEMENTS = 8;
struct QSGD3D12PipelineState
{
enum CullMode {
CullNone = 1,
CullFront,
CullBack
};
enum CompareFunc {
CompareNever = 1,
CompareLess,
CompareEqual,
CompareLessEqual,
CompareGreater,
CompareNotEqual,
CompareGreaterEqual,
CompareAlways
};
enum StencilOp {
StencilKeep = 1,
StencilZero,
StencilReplace,
StencilIncrSat,
StencilDecrSat,
StencilInvert,
StencilIncr,
StencilDescr
};
enum TopologyType {
TopologyTypePoint = 1,
TopologyTypeLine,
TopologyTypeTriangle
};
enum BlendType {
BlendNone,
BlendPremul, // == GL_ONE, GL_ONE_MINUS_SRC_ALPHA
BlendColor // == GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR
};
QSGD3D12ShaderState shaders;
int inputElementCount = 0;
QSGD3D12InputElement inputElements[QSGD3D12_MAX_INPUT_ELEMENTS];
CullMode cullMode = CullNone;
bool frontCCW = true;
bool colorWrite = true;
BlendType blend = BlendNone;
bool depthEnable = true;
CompareFunc depthFunc = CompareLess;
bool depthWrite = true;
bool stencilEnable = false;
CompareFunc stencilFunc = CompareEqual;
StencilOp stencilFailOp = StencilKeep;
StencilOp stencilDepthFailOp = StencilKeep;
StencilOp stencilPassOp = StencilKeep;
TopologyType topologyType = TopologyTypeTriangle;
bool operator==(const QSGD3D12PipelineState &other) const {
bool eq = shaders == other.shaders
&& inputElementCount == other.inputElementCount
&& cullMode == other.cullMode
&& frontCCW == other.frontCCW
&& colorWrite == other.colorWrite
&& blend == other.blend
&& depthEnable == other.depthEnable
&& (!depthEnable || depthFunc == other.depthFunc)
&& depthWrite == other.depthWrite
&& stencilEnable == other.stencilEnable
&& (!stencilEnable || stencilFunc == other.stencilFunc)
&& (!stencilEnable || stencilFailOp == other.stencilFailOp)
&& (!stencilEnable || stencilDepthFailOp == other.stencilDepthFailOp)
&& (!stencilEnable || stencilPassOp == other.stencilPassOp)
&& topologyType == other.topologyType;
if (eq) {
for (int i = 0; i < inputElementCount; ++i) {
if (!(inputElements[i] == other.inputElements[i])) {
eq = false;
break;
}
}
}
return eq;
}
};
inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0)
{
return qHash(key.shaders, seed) + key.inputElementCount
+ key.cullMode + key.frontCCW
+ key.colorWrite + key.blend
+ key.depthEnable + key.depthWrite
+ key.stencilEnable
+ key.topologyType;
}
class QSGD3D12Engine : public QSGRendererInterface
{
public:
QSGD3D12Engine();
~QSGD3D12Engine();
bool attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples);
void releaseResources();
bool hasResources() const;
void setWindowSize(const QSize &size, float dpr);
WId window() const;
QSize windowSize() const;
float windowDevicePixelRatio() const;
uint windowSamples() const;
void beginFrame();
void endFrame();
void beginLayer();
void endLayer();
void invalidateCachedFrameState();
void restoreFrameState(bool minimal = false);
uint genBuffer();
void releaseBuffer(uint id);
void resetBuffer(uint id, const quint8 *data, int size);
void markBufferDirty(uint id, int offset, int size);
enum ClearFlag {
ClearDepth = 0x1,
ClearStencil = 0x2
};
Q_DECLARE_FLAGS(ClearFlags, ClearFlag)
void queueViewport(const QRect &rect);
void queueScissor(const QRect &rect);
void queueSetRenderTarget(uint id = 0);
void queueClearRenderTarget(const QColor &color);
void queueClearDepthStencil(float depthValue, quint8 stencilValue, ClearFlags which);
void queueSetBlendFactor(const QVector4D &factor);
void queueSetStencilRef(quint32 ref);
void finalizePipeline(const QSGD3D12PipelineState &pipelineState);
struct DrawParams {
QSGGeometry::DrawingMode mode = QSGGeometry::DrawTriangles;
int count = 0;
uint vertexBuf = 0;
uint indexBuf = 0;
uint constantBuf = 0;
int vboOffset = 0;
int vboSize = 0;
int vboStride = 0;
int cboOffset = 0;
int startIndexIndex = -1;
QSGD3D12Format indexFormat = FmtUnsignedShort;
};
void queueDraw(const DrawParams &params);
void present();
void waitGPU();
static quint32 alignedConstantBufferSize(quint32 size);
static QSGD3D12Format toDXGIFormat(QSGGeometry::Type sgtype, int tupleSize = 1, int *size = nullptr);
static int mipMapLevels(const QSize &size);
static QSize mipMapAdjustedSourceSize(const QSize &size);
enum TextureCreateFlag {
TextureWithAlpha = 0x1,
TextureWithMipMaps = 0x2
};
Q_DECLARE_FLAGS(TextureCreateFlags, TextureCreateFlag)
uint genTexture();
void createTexture(uint id, const QSize &size, QImage::Format format, TextureCreateFlags flags);
void queueTextureResize(uint id, const QSize &size);
void queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos = QPoint());
void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos);
void releaseTexture(uint id);
void useTexture(uint id);
uint genRenderTarget();
void createRenderTarget(uint id, const QSize &size, const QVector4D &clearColor, uint samples);
void releaseRenderTarget(uint id);
void useRenderTargetAsTexture(uint id);
uint activeRenderTarget() const;
QImage executeAndWaitReadbackRenderTarget(uint id = 0);
void simulateDeviceLoss();
// QSGRendererInterface
GraphicsApi graphicsApi() const override;
void *getResource(Resource resource) const override;
ShaderType shaderType() const override;
ShaderCompilationTypes shaderCompilationType() const override;
ShaderSourceTypes shaderSourceType() const override;
private:
QSGD3D12EnginePrivate *d;
Q_DISABLE_COPY(QSGD3D12Engine)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::ClearFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::TextureCreateFlags)
QT_END_NAMESPACE
#endif // QSGD3D12ENGINE_P_H

View File

@ -0,0 +1,445 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12ENGINE_P_P_H
#define QSGD3D12ENGINE_P_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qsgd3d12engine_p.h"
#include <QCache>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <wrl/client.h>
using namespace Microsoft::WRL;
// No moc-related features (Q_OBJECT, signals, etc.) can be used here to due
// moc-generated code failing to compile when combined with COM stuff.
// Recommended reading before moving further: https://github.com/Microsoft/DirectXTK/wiki/ComPtr
// Note esp. operator= vs. Attach and operator& vs. GetAddressOf
// ID3D12* is never passed to Qt containers directly. Always use ComPtr and put it into a struct.
QT_BEGIN_NAMESPACE
class QSGD3D12CPUDescriptorHeapManager
{
public:
void initialize(ID3D12Device *device);
void releaseResources();
D3D12_CPU_DESCRIPTOR_HANDLE allocate(D3D12_DESCRIPTOR_HEAP_TYPE type);
void release(D3D12_CPU_DESCRIPTOR_HANDLE handle, D3D12_DESCRIPTOR_HEAP_TYPE type);
quint32 handleSize(D3D12_DESCRIPTOR_HEAP_TYPE type) const { return m_handleSizes[type]; }
private:
ID3D12Device *m_device = nullptr;
struct Heap {
D3D12_DESCRIPTOR_HEAP_TYPE type;
ComPtr<ID3D12DescriptorHeap> heap;
D3D12_CPU_DESCRIPTOR_HANDLE start;
quint32 handleSize;
quint32 freeMap[8];
};
QVector<Heap> m_heaps;
quint32 m_handleSizes[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
};
class QSGD3D12DeviceManager
{
public:
ID3D12Device *ref();
void unref();
void deviceLossDetected();
IDXGIFactory4 *dxgi();
struct DeviceLossObserver {
virtual void deviceLost() = 0;
};
void registerDeviceLossObserver(DeviceLossObserver *observer);
private:
void ensureCreated();
ComPtr<ID3D12Device> m_device;
ComPtr<IDXGIFactory4> m_factory;
QAtomicInt m_ref;
QVector<DeviceLossObserver *> m_observers;
};
struct QSGD3D12CPUWaitableFence
{
~QSGD3D12CPUWaitableFence() {
if (event)
CloseHandle(event);
}
ComPtr<ID3D12Fence> fence;
HANDLE event = nullptr;
QAtomicInt value;
};
class QSGD3D12EnginePrivate : public QSGD3D12DeviceManager::DeviceLossObserver
{
public:
void initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples);
bool isInitialized() const { return initialized; }
void releaseResources();
void setWindowSize(const QSize &size, float dpr);
WId currentWindow() const { return window; }
QSize currentWindowSize() const { return windowSize; }
float currentWindowDpr() const { return windowDpr; }
uint currentWindowSamples() const { return windowSamples; }
void beginFrame();
void endFrame();
void beginLayer();
void endLayer();
void invalidateCachedFrameState();
void restoreFrameState(bool minimal = false);
uint genBuffer();
void releaseBuffer(uint id);
void resetBuffer(uint id, const quint8 *data, int size);
void markBufferDirty(uint id, int offset, int size);
void queueViewport(const QRect &rect);
void queueScissor(const QRect &rect);
void queueSetRenderTarget(uint id);
void queueClearRenderTarget(const QColor &color);
void queueClearDepthStencil(float depthValue, quint8 stencilValue, QSGD3D12Engine::ClearFlags which);
void queueSetBlendFactor(const QVector4D &factor);
void queueSetStencilRef(quint32 ref);
void finalizePipeline(const QSGD3D12PipelineState &pipelineState);
void queueDraw(const QSGD3D12Engine::DrawParams &params);
void present();
void waitGPU();
uint genTexture();
void createTexture(uint id, const QSize &size, QImage::Format format, QSGD3D12Engine::TextureCreateFlags flags);
void queueTextureResize(uint id, const QSize &size);
void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos);
void releaseTexture(uint id);
void useTexture(uint id);
uint genRenderTarget();
void createRenderTarget(uint id, const QSize &size, const QVector4D &clearColor, uint samples);
void releaseRenderTarget(uint id);
void useRenderTargetAsTexture(uint id);
uint activeRenderTarget() const { return currentRenderTarget; }
QImage executeAndWaitReadbackRenderTarget(uint id);
void simulateDeviceLoss();
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.
private:
void ensureDevice();
void setupDefaultRenderTargets();
void deviceLost() override;
bool createCbvSrvUavHeap(int pframeIndex, int descriptorCount);
void setDescriptorHeaps(bool force = false);
void ensureGPUDescriptorHeap(int cbvSrvUavDescriptorCount);
DXGI_SAMPLE_DESC makeSampleDesc(DXGI_FORMAT format, uint samples);
ID3D12Resource *createColorBuffer(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size,
const QVector4D &clearColor, uint samples);
ID3D12Resource *createDepthStencil(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, uint samples);
QSGD3D12CPUWaitableFence *createCPUWaitableFence() const;
void waitForGPU(QSGD3D12CPUWaitableFence *f) const;
void transitionResource(ID3D12Resource *resource, ID3D12GraphicsCommandList *commandList,
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after) const;
void resolveMultisampledTarget(ID3D12Resource *msaa, ID3D12Resource *resolve, D3D12_RESOURCE_STATES resolveUsage,
ID3D12GraphicsCommandList *commandList) const;
void uavBarrier(ID3D12Resource *resource, ID3D12GraphicsCommandList *commandList) const;
ID3D12Resource *createBuffer(int size);
typedef QVector<QPair<int, int> > DirtyList;
void addDirtyRange(DirtyList *dirty, int offset, int size, int bufferSize);
struct PersistentFrameData {
ComPtr<ID3D12DescriptorHeap> gpuCbvSrvUavHeap;
int gpuCbvSrvUavHeapSize;
int cbvSrvUavNextFreeDescriptorIndex;
QSet<uint> pendingTextureUploads;
QSet<uint> pendingTextureMipMap;
struct DeleteQueueEntry {
ComPtr<ID3D12Resource> res;
ComPtr<ID3D12DescriptorHeap> descHeap;
SIZE_T cpuDescriptorPtr = 0;
D3D12_DESCRIPTOR_HEAP_TYPE descHeapType = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
};
QVector<DeleteQueueEntry> deleteQueue;
QVector<DeleteQueueEntry> outOfFrameDeleteQueue;
QSet<uint> buffersUsedInDrawCallSet;
QSet<uint> buffersUsedInFrame;
struct PendingRelease {
enum Type {
TypeTexture,
TypeBuffer
};
Type type = TypeTexture;
uint id = 0;
PendingRelease(Type type, uint id) : type(type), id(id) { }
PendingRelease() { }
bool operator==(const PendingRelease &other) const { return type == other.type && id == other.id; }
};
QSet<PendingRelease> pendingReleases;
QSet<PendingRelease> outOfFramePendingReleases;
};
friend uint qHash(const PersistentFrameData::PendingRelease &pr, uint seed);
void deferredDelete(ComPtr<ID3D12Resource> res);
void deferredDelete(ComPtr<ID3D12DescriptorHeap> dh);
void deferredDelete(D3D12_CPU_DESCRIPTOR_HANDLE h, D3D12_DESCRIPTOR_HEAP_TYPE type);
struct Buffer;
void ensureBuffer(Buffer *buf);
void updateBuffer(Buffer *buf);
void beginDrawCalls();
void beginFrameDraw();
void endDrawCalls(bool lastInFrame = false);
static const int MAX_SWAP_CHAIN_BUFFER_COUNT = 4;
static const int MAX_FRAME_IN_FLIGHT_COUNT = 4;
bool initialized = false;
bool inFrame = false;
WId window = 0;
QSize windowSize;
float windowDpr;
uint windowSamples;
int swapChainBufferCount;
int frameInFlightCount;
int waitableSwapChainMaxLatency;
ID3D12Device *device;
ComPtr<ID3D12CommandQueue> commandQueue;
ComPtr<ID3D12CommandQueue> copyCommandQueue;
ComPtr<IDXGISwapChain3> swapChain;
HANDLE swapEvent;
ComPtr<ID3D12Resource> backBufferRT[MAX_SWAP_CHAIN_BUFFER_COUNT];
ComPtr<ID3D12Resource> defaultRT[MAX_SWAP_CHAIN_BUFFER_COUNT];
D3D12_CPU_DESCRIPTOR_HANDLE defaultRTV[MAX_SWAP_CHAIN_BUFFER_COUNT];
ComPtr<ID3D12Resource> defaultDS;
D3D12_CPU_DESCRIPTOR_HANDLE defaultDSV;
ComPtr<ID3D12CommandAllocator> frameCommandAllocator[MAX_FRAME_IN_FLIGHT_COUNT];
ComPtr<ID3D12CommandAllocator> copyCommandAllocator;
ComPtr<ID3D12GraphicsCommandList> frameCommandList;
ComPtr<ID3D12GraphicsCommandList> copyCommandList;
QSGD3D12CPUDescriptorHeapManager cpuDescHeapManager;
quint64 presentFrameIndex;
quint64 frameIndex;
QSGD3D12CPUWaitableFence *presentFence = nullptr;
QSGD3D12CPUWaitableFence *frameFence[MAX_FRAME_IN_FLIGHT_COUNT];
PersistentFrameData pframeData[MAX_FRAME_IN_FLIGHT_COUNT];
int currentPFrameIndex;
ID3D12GraphicsCommandList *commandList = nullptr;
int activeLayers = 0;
int currentLayerDepth = 0;
struct PSOCacheEntry {
ComPtr<ID3D12PipelineState> pso;
};
QCache<QSGD3D12PipelineState, PSOCacheEntry> psoCache;
struct RootSigCacheEntry {
ComPtr<ID3D12RootSignature> rootSig;
};
QCache<QSGD3D12RootSignature, RootSigCacheEntry> rootSigCache;
struct Texture {
enum Flag {
EntryInUse = 0x01,
Alpha = 0x02,
MipMap = 0x04
};
int flags = 0;
bool entryInUse() const { return flags & EntryInUse; }
bool alpha() const { return flags & Alpha; }
bool mipmap() const { return flags & MipMap; }
ComPtr<ID3D12Resource> texture;
D3D12_CPU_DESCRIPTOR_HANDLE srv;
quint64 fenceValue = 0;
quint64 lastWaitFenceValue = 0;
struct StagingHeap {
ComPtr<ID3D12Heap> heap;
};
QVector<StagingHeap> stagingHeaps;
struct StagingBuffer {
ComPtr<ID3D12Resource> buffer;
};
QVector<StagingBuffer> stagingBuffers;
QVector<D3D12_CPU_DESCRIPTOR_HANDLE> mipUAVs;
};
QVector<Texture> textures;
ComPtr<ID3D12Fence> textureUploadFence;
QAtomicInt nextTextureUploadFenceValue;
struct TransientFrameData {
QSGGeometry::DrawingMode drawingMode;
uint currentIndexBuffer;
struct ActiveTexture {
enum Type {
TypeTexture,
TypeRenderTarget
};
Type type = TypeTexture;
uint id = 0;
ActiveTexture(Type type, uint id) : type(type), id(id) { }
ActiveTexture() { }
};
int activeTextureCount;
ActiveTexture activeTextures[QSGD3D12_MAX_TEXTURE_VIEWS];
int drawCount;
ID3D12PipelineState *lastPso;
ID3D12RootSignature *lastRootSig;
bool descHeapSet;
QRect viewport;
QRect scissor;
QVector4D blendFactor = QVector4D(1, 1, 1, 1);
quint32 stencilRef = 1;
QSGD3D12PipelineState pipelineState;
};
TransientFrameData tframeData;
struct MipMapGen {
bool initialize(QSGD3D12EnginePrivate *enginePriv);
void releaseResources();
void queueGenerate(const Texture &t);
QSGD3D12EnginePrivate *engine;
ComPtr<ID3D12RootSignature> rootSig;
ComPtr<ID3D12PipelineState> pipelineState;
};
MipMapGen mipmapper;
struct RenderTarget {
enum Flag {
EntryInUse = 0x01,
NeedsReadBarrier = 0x02,
Multisample = 0x04
};
int flags = 0;
bool entryInUse() const { return flags & EntryInUse; }
ComPtr<ID3D12Resource> color;
ComPtr<ID3D12Resource> colorResolve;
D3D12_CPU_DESCRIPTOR_HANDLE rtv;
ComPtr<ID3D12Resource> ds;
D3D12_CPU_DESCRIPTOR_HANDLE dsv;
D3D12_CPU_DESCRIPTOR_HANDLE srv;
};
QVector<RenderTarget> renderTargets;
uint currentRenderTarget;
struct CPUBufferRef {
const quint8 *p = nullptr;
quint32 size = 0;
DirtyList dirty;
CPUBufferRef() { dirty.reserve(16); }
};
struct Buffer {
enum Flag {
EntryInUse = 0x01
};
int flags = 0;
bool entryInUse() const { return flags & EntryInUse; }
struct InFlightData {
ComPtr<ID3D12Resource> buffer;
DirtyList dirty;
quint32 dataSize = 0;
quint32 resourceSize = 0;
InFlightData() { dirty.reserve(16); }
};
InFlightData d[MAX_FRAME_IN_FLIGHT_COUNT];
CPUBufferRef cpuDataRef;
};
QVector<Buffer> buffers;
struct DeviceLossTester {
bool initialize(QSGD3D12EnginePrivate *enginePriv);
void releaseResources();
void killDevice();
QSGD3D12EnginePrivate *engine;
ComPtr<ID3D12PipelineState> computeState;
ComPtr<ID3D12RootSignature> computeRootSignature;
};
DeviceLossTester devLossTest;
};
inline uint qHash(const QSGD3D12EnginePrivate::PersistentFrameData::PendingRelease &pr, uint seed = 0)
{
Q_UNUSED(seed);
return pr.id + pr.type;
}
QT_END_NAMESPACE
#endif

View File

@ -0,0 +1,184 @@
/****************************************************************************
**
** 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 "qsgd3d12glyphcache_p.h"
#include "qsgd3d12engine_p.h"
QT_BEGIN_NAMESPACE
// NOTE: Avoid categorized logging. It is slow.
#define DECLARE_DEBUG_VAR(variable) \
static bool debug_ ## variable() \
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(render)
QSGD3D12GlyphCache::QSGD3D12GlyphCache(QSGD3D12Engine *engine, QFontEngine::GlyphFormat format, const QTransform &matrix)
: QTextureGlyphCache(format, matrix),
m_engine(engine)
{
}
QSGD3D12GlyphCache::~QSGD3D12GlyphCache()
{
if (m_id)
m_engine->releaseTexture(m_id);
}
void QSGD3D12GlyphCache::createTextureData(int width, int height)
{
width = qMax(128, width);
height = qMax(32, height);
m_id = m_engine->genTexture();
Q_ASSERT(m_id);
if (Q_UNLIKELY(debug_render()))
qDebug("new glyph cache texture %u of size %dx%d, fontengine format %d", m_id, width, height, m_format);
m_size = QSize(width, height);
const QImage::Format imageFormat =
m_format == QFontEngine::Format_A8 ? QImage::Format_Alpha8 : QImage::Format_ARGB32_Premultiplied;
m_engine->createTexture(m_id, m_size, imageFormat, QSGD3D12Engine::TextureWithAlpha);
}
void QSGD3D12GlyphCache::resizeTextureData(int width, int height)
{
width = qMax(128, width);
height = qMax(32, height);
if (m_size.width() >= width && m_size.height() >= height)
return;
if (Q_UNLIKELY(debug_render()))
qDebug("glyph cache texture %u resize to %dx%d", m_id, width, height);
m_size = QSize(width, height);
m_engine->queueTextureResize(m_id, m_size);
}
void QSGD3D12GlyphCache::beginFillTexture()
{
Q_ASSERT(m_glyphImages.isEmpty() && m_glyphPos.isEmpty());
}
void QSGD3D12GlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
{
QImage mask = textureMapForGlyph(glyph, subPixelPosition);
const int maskWidth = mask.width();
const int maskHeight = mask.height();
if (mask.format() == QImage::Format_Mono) {
mask = mask.convertToFormat(QImage::Format_Indexed8);
for (int y = 0; y < maskHeight; ++y) {
uchar *src = mask.scanLine(y);
for (int x = 0; x < maskWidth; ++x)
src[x] = -src[x]; // convert 0 and 1 into 0 and 255
}
} else if (mask.depth() == 32) {
if (mask.format() == QImage::Format_RGB32) {
// We need to make the alpha component equal to the average of the RGB values.
// This is needed when drawing sub-pixel antialiased text on translucent targets.
for (int y = 0; y < maskHeight; ++y) {
QRgb *src = reinterpret_cast<QRgb *>(mask.scanLine(y));
for (int x = 0; x < maskWidth; ++x) {
const int r = qRed(src[x]);
const int g = qGreen(src[x]);
const int b = qBlue(src[x]);
int avg;
if (mask.format() == QImage::Format_RGB32)
avg = (r + g + b + 1) / 3; // "+1" for rounding.
else // Format_ARGB32_Premultiplied
avg = qAlpha(src[x]);
src[x] = qRgba(r, g, b, avg);
}
}
}
}
m_glyphImages.append(mask);
m_glyphPos.append(QPoint(c.x, c.y));
}
void QSGD3D12GlyphCache::endFillTexture()
{
if (m_glyphImages.isEmpty())
return;
Q_ASSERT(m_id);
m_engine->queueTextureUpload(m_id, m_glyphImages, m_glyphPos);
// Nothing else left to do, it is up to the text material to call
// useTexture() which will then add the texture dependency to the frame.
m_glyphImages.clear();
m_glyphPos.clear();
}
int QSGD3D12GlyphCache::glyphPadding() const
{
return 1;
}
int QSGD3D12GlyphCache::maxTextureWidth() const
{
return 16384;
}
int QSGD3D12GlyphCache::maxTextureHeight() const
{
return 16384;
}
void QSGD3D12GlyphCache::useTexture()
{
if (m_id)
m_engine->useTexture(m_id);
}
QSize QSGD3D12GlyphCache::currentSize() const
{
return m_size;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,88 @@
/****************************************************************************
**
** 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 QSGD3D12GLYPHCACHE_P_H
#define QSGD3D12GLYPHCACHE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtGui/private/qtextureglyphcache_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
class QSGD3D12GlyphCache : public QTextureGlyphCache
{
public:
QSGD3D12GlyphCache(QSGD3D12Engine *engine, QFontEngine::GlyphFormat format, const QTransform &matrix);
~QSGD3D12GlyphCache();
void createTextureData(int width, int height) override;
void resizeTextureData(int width, int height) override;
void beginFillTexture() override;
void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition) override;
void endFillTexture() override;
int glyphPadding() const override;
int maxTextureWidth() const override;
int maxTextureHeight() const override;
void useTexture();
QSize currentSize() const;
private:
QSGD3D12Engine *m_engine;
uint m_id = 0;
QVector<QImage> m_glyphImages;
QVector<QPoint> m_glyphPos;
QSize m_size;
};
QT_END_NAMESPACE
#endif // QSGD3D12GLYPHCACHE_P_H

View File

@ -0,0 +1,90 @@
/****************************************************************************
**
** 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 "qsgd3d12glyphnode_p.h"
#include "qsgd3d12builtinmaterials_p.h"
QT_BEGIN_NAMESPACE
void QSGD3D12GlyphNode::setMaterialColor(const QColor &color)
{
static_cast<QSGD3D12TextMaterial *>(m_material)->setColor(color);
}
void QSGD3D12GlyphNode::update()
{
QRawFont font = m_glyphs.rawFont();
QMargins margins(0, 0, 0, 0);
if (m_style == QQuickText::Normal) {
// QSGBasicGlyphNode dtor will delete
m_material = new QSGD3D12TextMaterial(QSGD3D12TextMaterial::Normal, m_rc, font);
} else if (m_style == QQuickText::Outline) {
QSGD3D12TextMaterial *material = new QSGD3D12TextMaterial(QSGD3D12TextMaterial::Outlined,
m_rc, font, QFontEngine::Format_A8);
material->setStyleColor(m_styleColor);
m_material = material;
margins = QMargins(1, 1, 1, 1);
} else {
QSGD3D12TextMaterial *material = new QSGD3D12TextMaterial(QSGD3D12TextMaterial::Styled,
m_rc, font, QFontEngine::Format_A8);
if (m_style == QQuickText::Sunken) {
material->setStyleShift(QVector2D(0, -1));
margins.setTop(1);
} else if (m_style == QQuickText::Raised) {
material->setStyleShift(QVector2D(0, 1));
margins.setBottom(1);
}
material->setStyleColor(m_styleColor);
m_material = material;
}
QSGD3D12TextMaterial *textMaterial = static_cast<QSGD3D12TextMaterial *>(m_material);
textMaterial->setColor(m_color);
QRectF boundingRect;
textMaterial->populate(m_position, m_glyphs.glyphIndexes(), m_glyphs.positions(), geometry(),
&boundingRect, &m_baseLine, margins);
setBoundingRect(boundingRect);
setMaterial(m_material);
markDirty(DirtyGeometry);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12GLYPHNODE_P_H
#define QSGD3D12GLYPHNODE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgbasicglyphnode_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12RenderContext;
class QSGD3D12GlyphNode : public QSGBasicGlyphNode
{
public:
QSGD3D12GlyphNode(QSGD3D12RenderContext *rc) : m_rc(rc) { }
void setMaterialColor(const QColor &color) override;
void update() override;
private:
QSGD3D12RenderContext *m_rc;
};
QT_END_NAMESPACE
#endif // QSGD3D12GLYPHNODE_P_H

View File

@ -0,0 +1,123 @@
/****************************************************************************
**
** 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 "qsgd3d12imagenode_p.h"
QT_BEGIN_NAMESPACE
QSGD3D12ImageNode::QSGD3D12ImageNode()
{
setMaterial(&m_material);
}
void QSGD3D12ImageNode::setFiltering(QSGTexture::Filtering filtering)
{
if (m_material.filtering() == filtering)
return;
m_material.setFiltering(filtering);
m_smoothMaterial.setFiltering(filtering);
markDirty(DirtyMaterial);
}
void QSGD3D12ImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
{
if (m_material.mipmapFiltering() == filtering)
return;
m_material.setMipmapFiltering(filtering);
m_smoothMaterial.setMipmapFiltering(filtering);
markDirty(DirtyMaterial);
}
void QSGD3D12ImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
{
if (m_material.verticalWrapMode() == wrapMode)
return;
m_material.setVerticalWrapMode(wrapMode);
m_smoothMaterial.setVerticalWrapMode(wrapMode);
markDirty(DirtyMaterial);
}
void QSGD3D12ImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
{
if (m_material.horizontalWrapMode() == wrapMode)
return;
m_material.setHorizontalWrapMode(wrapMode);
m_smoothMaterial.setHorizontalWrapMode(wrapMode);
markDirty(DirtyMaterial);
}
void QSGD3D12ImageNode::updateMaterialAntialiasing()
{
if (m_antialiasing)
setMaterial(&m_smoothMaterial);
else
setMaterial(&m_material);
}
void QSGD3D12ImageNode::setMaterialTexture(QSGTexture *texture)
{
m_material.setTexture(texture);
m_smoothMaterial.setTexture(texture);
}
QSGTexture *QSGD3D12ImageNode::materialTexture() const
{
return m_material.texture();
}
bool QSGD3D12ImageNode::updateMaterialBlending()
{
const bool alpha = m_material.flags() & QSGMaterial::Blending;
if (materialTexture() && alpha != materialTexture()->hasAlphaChannel()) {
m_material.setFlag(QSGMaterial::Blending, !alpha);
return true;
}
return false;
}
bool QSGD3D12ImageNode::supportsWrap(const QSize &) const
{
return true;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,82 @@
/****************************************************************************
**
** 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 QSGD3D12IMAGENODE_P_H
#define QSGD3D12IMAGENODE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgbasicimagenode_p.h>
#include "qsgd3d12builtinmaterials_p.h"
QT_BEGIN_NAMESPACE
class QSGD3D12ImageNode : public QSGBasicImageNode
{
public:
QSGD3D12ImageNode();
void setMipmapFiltering(QSGTexture::Filtering filtering) override;
void setFiltering(QSGTexture::Filtering filtering) override;
void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) override;
void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) override;
void updateMaterialAntialiasing() override;
void setMaterialTexture(QSGTexture *texture) override;
QSGTexture *materialTexture() const override;
bool updateMaterialBlending() override;
bool supportsWrap(const QSize &size) const override;
private:
QSGD3D12TextureMaterial m_material;
QSGD3D12SmoothTextureMaterial m_smoothMaterial;
};
QT_END_NAMESPACE
#endif // QSGD3D12IMAGENODE_P_H

View File

@ -0,0 +1,363 @@
/****************************************************************************
**
** 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 "qsgd3d12layer_p.h"
#include "qsgd3d12rendercontext_p.h"
#include "qsgd3d12engine_p.h"
#include "qsgd3d12renderer_p.h"
QT_BEGIN_NAMESPACE
// NOTE: Avoid categorized logging. It is slow.
#define DECLARE_DEBUG_VAR(variable) \
static bool debug_ ## variable() \
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(render)
QSGD3D12Layer::QSGD3D12Layer(QSGD3D12RenderContext *rc)
: m_rc(rc)
{
if (Q_UNLIKELY(debug_render()))
qDebug("new layer %p", this);
}
QSGD3D12Layer::~QSGD3D12Layer()
{
if (Q_UNLIKELY(debug_render()))
qDebug("destroying layer %p", this);
cleanup();
}
// QSGTexture
int QSGD3D12Layer::textureId() const
{
return m_rt; // not a texture id per se but will do
}
QSize QSGD3D12Layer::textureSize() const
{
return m_size;
}
bool QSGD3D12Layer::hasAlphaChannel() const
{
return true;
}
bool QSGD3D12Layer::hasMipmaps() const
{
// mipmapped layers are not supported for now
return false;
}
QRectF QSGD3D12Layer::normalizedTextureSubRect() const
{
return QRectF(m_mirrorHorizontal ? 1 : 0,
m_mirrorVertical ? 0 : 1,
m_mirrorHorizontal ? -1 : 1,
m_mirrorVertical ? 1 : -1);
}
void QSGD3D12Layer::bind()
{
if (Q_UNLIKELY(debug_render()))
qDebug("layer %p bind rt=%u", this, m_rt);
QSGD3D12Engine *engine = m_rc->engine();
Q_ASSERT(m_rt);
#ifndef QT_NO_DEBUG
// Should not use the color buffer as a texture while it is the current render target.
if (!m_recursive && engine->activeRenderTarget() == m_rt && engine->windowSamples() == 1)
qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively.");
#endif
engine->useRenderTargetAsTexture(m_rt);
}
// QSGDynamicTexture
bool QSGD3D12Layer::updateTexture()
{
if (Q_UNLIKELY(debug_render()))
qDebug("layer %p updateTexture", this);
const bool doUpdate = (m_live || m_updateContentPending) && m_dirtyTexture;
if (doUpdate)
updateContent();
if (m_updateContentPending) {
m_updateContentPending = false;
emit scheduledUpdateCompleted();
}
return doUpdate;
}
// QSGLayer
void QSGD3D12Layer::setItem(QSGNode *item)
{
if (m_item == item)
return;
if (m_live && !item)
resetRenderTarget();
m_item = item;
markDirtyTexture();
}
void QSGD3D12Layer::setRect(const QRectF &rect)
{
if (m_rect == rect)
return;
m_rect = rect;
markDirtyTexture();
}
void QSGD3D12Layer::setSize(const QSize &size)
{
if (m_size == size)
return;
if (m_live && size.isNull())
resetRenderTarget();
m_size = size;
markDirtyTexture();
}
void QSGD3D12Layer::scheduleUpdate()
{
if (m_updateContentPending)
return;
if (Q_UNLIKELY(debug_render()))
qDebug("layer %p scheduleUpdate", this);
m_updateContentPending = true;
if (m_dirtyTexture)
emit updateRequested();
}
QImage QSGD3D12Layer::toImage() const
{
return m_rc->engine()->executeAndWaitReadbackRenderTarget(m_rt);
}
void QSGD3D12Layer::setLive(bool live)
{
if (m_live == live)
return;
if (live && (!m_item || m_size.isNull()))
resetRenderTarget();
m_live = live;
markDirtyTexture();
}
void QSGD3D12Layer::setRecursive(bool recursive)
{
m_recursive = recursive;
}
void QSGD3D12Layer::setFormat(uint format)
{
Q_UNUSED(format);
}
void QSGD3D12Layer::setHasMipmaps(bool mipmap)
{
// mipmapped layers are not supported for now
Q_UNUSED(mipmap);
}
void QSGD3D12Layer::setDevicePixelRatio(qreal ratio)
{
m_dpr = ratio;
}
void QSGD3D12Layer::setMirrorHorizontal(bool mirror)
{
m_mirrorHorizontal = mirror;
}
void QSGD3D12Layer::setMirrorVertical(bool mirror)
{
m_mirrorVertical = mirror;
}
void QSGD3D12Layer::markDirtyTexture()
{
if (Q_UNLIKELY(debug_render()))
qDebug("layer %p markDirtyTexture", this);
m_dirtyTexture = true;
if (m_live || m_updateContentPending)
emit updateRequested();
}
void QSGD3D12Layer::invalidated()
{
cleanup();
}
void QSGD3D12Layer::cleanup()
{
if (!m_renderer && !m_rt)
return;
if (Q_UNLIKELY(debug_render()))
qDebug("layer %p cleanup renderer=%p rt=%u", this, m_renderer, m_rt);
delete m_renderer;
m_renderer = nullptr;
resetRenderTarget();
}
void QSGD3D12Layer::resetRenderTarget()
{
if (!m_rt)
return;
if (Q_UNLIKELY(debug_render()))
qDebug("layer %p resetRenderTarget rt=%u", this, m_rt);
m_rc->engine()->releaseRenderTarget(m_rt);
m_rt = 0;
if (m_secondaryRT) {
m_rc->engine()->releaseRenderTarget(m_secondaryRT);
m_secondaryRT = 0;
}
}
void QSGD3D12Layer::updateContent()
{
if (Q_UNLIKELY(debug_render()))
qDebug("layer %p updateContent", this);
if (!m_item || m_size.isNull()) {
resetRenderTarget();
m_dirtyTexture = false;
return;
}
QSGNode *root = m_item;
while (root->firstChild() && root->type() != QSGNode::RootNodeType)
root = root->firstChild();
if (root->type() != QSGNode::RootNodeType)
return;
if (!m_renderer) {
m_renderer = m_rc->createRenderer();
static_cast<QSGD3D12Renderer *>(m_renderer)->turnToLayerRenderer();
connect(m_renderer, &QSGRenderer::sceneGraphChanged, this, &QSGD3D12Layer::markDirtyTexture);
}
m_renderer->setDevicePixelRatio(m_dpr);
m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
QSGD3D12Engine *engine = m_rc->engine();
const uint sampleCount = engine->windowSamples();
const QVector4D clearColor;
if (!m_rt || m_rtSize != m_size) {
if (m_rt)
resetRenderTarget();
m_rt = engine->genRenderTarget();
m_rtSize = m_size;
if (Q_UNLIKELY(debug_render()))
qDebug("new render target for layer %p, size=%dx%d, samples=%d",
this, m_size.width(), m_size.height(), sampleCount);
engine->createRenderTarget(m_rt, m_rtSize, clearColor, sampleCount);
// For multisampling the resolving via an extra non-ms color buffer is
// handled internally in the engine, no need to worry about it here.
}
if (m_recursive && !m_secondaryRT && sampleCount == 1) {
m_secondaryRT = engine->genRenderTarget();
engine->createRenderTarget(m_secondaryRT, m_rtSize, clearColor, sampleCount);
}
m_dirtyTexture = false;
m_renderer->setDeviceRect(m_size);
m_renderer->setViewportRect(m_size);
// Note that the handling of vertical mirroring differs from OpenGL here
// due to y running top-bottom with D3D as opposed to bottom-top with GL.
// The common parts of Quick follow OpenGL so vertical mirroring is
// typically enabled.
QRectF mirrored(m_mirrorHorizontal ? m_rect.right() : m_rect.left(),
m_mirrorVertical ? m_rect.top() : m_rect.bottom(),
m_mirrorHorizontal ? -m_rect.width() : m_rect.width(),
m_mirrorVertical ? m_rect.height() : -m_rect.height());
m_renderer->setProjectionMatrixToRect(mirrored);
m_renderer->setClearColor(Qt::transparent);
if (!m_recursive || sampleCount > 1) {
m_renderer->renderScene(m_rt);
} else {
m_renderer->renderScene(m_secondaryRT);
qSwap(m_rt, m_secondaryRT);
}
if (m_recursive)
markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
}
QT_END_NAMESPACE

View File

@ -0,0 +1,118 @@
/****************************************************************************
**
** 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 QSGD3D12LAYER_P_H
#define QSGD3D12LAYER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgadaptationlayer_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12RenderContext;
class QSGD3D12Layer : public QSGLayer
{
Q_OBJECT
public:
QSGD3D12Layer(QSGD3D12RenderContext *rc);
~QSGD3D12Layer();
int textureId() const override;
QSize textureSize() const override;
bool hasAlphaChannel() const override;
bool hasMipmaps() const override;
QRectF normalizedTextureSubRect() const override;
void bind() override;
bool updateTexture() override;
void setItem(QSGNode *item) override;
void setRect(const QRectF &rect) override;
void setSize(const QSize &size) override;
void scheduleUpdate() override;
QImage toImage() const override;
void setLive(bool live) override;
void setRecursive(bool recursive) override;
void setFormat(uint format) override;
void setHasMipmaps(bool mipmap) override;
void setDevicePixelRatio(qreal ratio) override;
void setMirrorHorizontal(bool mirror) override;
void setMirrorVertical(bool mirror) override;
public Q_SLOTS:
void markDirtyTexture() override;
void invalidated() override;
private:
void cleanup();
void resetRenderTarget();
void updateContent();
QSGD3D12RenderContext *m_rc;
uint m_rt = 0;
uint m_secondaryRT = 0;
QSize m_rtSize;
QSize m_size;
QRectF m_rect;
QSGNode *m_item = nullptr;
QSGRenderer *m_renderer = nullptr;
float m_dpr = 1;
bool m_mirrorHorizontal = false;
bool m_mirrorVertical = true;
bool m_live = true;
bool m_recursive = false;
bool m_dirtyTexture = true;
bool m_updateContentPending = false;
};
QT_END_NAMESPACE
#endif // QSGD3D12LAYER_P_H

View File

@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgd3d12material_p.h"
QT_BEGIN_NAMESPACE
QSGMaterialShader *QSGD3D12Material::createShader() const
{
return nullptr;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12MATERIAL_P_H
#define QSGD3D12MATERIAL_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtQuick/qsgmaterial.h>
#include "qsgd3d12engine_p.h"
QT_BEGIN_NAMESPACE
class QSGRenderer;
// The D3D renderer works with QSGD3D12Material as the "base" class since
// QSGMaterial and its GL program related bits are not suitable. Also, there is
// no split like with QSGMaterialShader.
typedef QSGMaterialShader::RenderState QSGD3D12MaterialRenderState;
class QSGD3D12Material : public QSGMaterial
{
public:
struct ExtraState {
QVector4D blendFactor;
};
enum UpdateResult {
UpdatedShaders = 0x0001,
UpdatedConstantBuffer = 0x0002,
UpdatedBlendFactor = 0x0004
};
Q_DECLARE_FLAGS(UpdateResults, UpdateResult)
virtual int constantBufferSize() const = 0;
virtual void preparePipeline(QSGD3D12PipelineState *pipelineState) = 0;
virtual UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) = 0;
private:
QSGMaterialShader *createShader() const override; // dummy, QSGMaterialShader is too GL dependent
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Material::UpdateResults)
QT_END_NAMESPACE
#endif // QSGD3D12MATERIAL_P_H

View File

@ -0,0 +1,256 @@
/****************************************************************************
**
** 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 "qsgd3d12painternode_p.h"
#include "qsgd3d12rendercontext_p.h"
#include "qsgd3d12engine_p.h"
#include <private/qquickitem_p.h>
#include <qmath.h>
QT_BEGIN_NAMESPACE
QSGD3D12PainterTexture::QSGD3D12PainterTexture(QSGD3D12Engine *engine)
: QSGD3D12Texture(engine)
{
}
void QSGD3D12PainterTexture::bind()
{
if (m_image.isNull()) {
if (!m_id) {
m_id = m_engine->genTexture();
m_engine->createTexture(m_id, QSize(16, 16), QImage::Format_RGB32, 0);
}
} else if (m_image.size() != lastSize) {
lastSize = m_image.size();
if (m_id)
m_engine->releaseTexture(m_id);
m_id = m_engine->genTexture();
m_engine->createTexture(m_id, m_image.size(), m_image.format(), QSGD3D12Engine::TextureWithAlpha);
m_engine->queueTextureUpload(m_id, m_image);
} else if (!dirty.isEmpty()) {
const int bpl = m_image.bytesPerLine();
const uchar *p = m_image.constBits() + dirty.y() * bpl + dirty.x() * 4;
QImage subImg(p, dirty.width(), dirty.height(), bpl, QImage::Format_ARGB32_Premultiplied);
m_engine->queueTextureUpload(m_id, subImg, dirty.topLeft());
}
dirty = QRect();
m_engine->useTexture(m_id);
}
QSGD3D12PainterNode::QSGD3D12PainterNode(QQuickPaintedItem *item)
: m_item(item),
m_engine(static_cast<QSGD3D12RenderContext *>(QQuickItemPrivate::get(item)->sceneGraphRenderContext())->engine()),
m_texture(new QSGD3D12PainterTexture(m_engine)),
m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4),
m_dirtyGeometry(false),
m_dirtyContents(false)
{
m_material.setFlag(QSGMaterial::Blending);
m_material.setTexture(m_texture);
setMaterial(&m_material);
setGeometry(&m_geometry);
}
QSGD3D12PainterNode::~QSGD3D12PainterNode()
{
delete m_texture;
}
void QSGD3D12PainterNode::setPreferredRenderTarget(QQuickPaintedItem::RenderTarget)
{
// always QImage-based
}
void QSGD3D12PainterNode::setSize(const QSize &size)
{
if (m_size == size)
return;
m_size = size;
m_dirtyGeometry = true;
}
void QSGD3D12PainterNode::setDirty(const QRect &dirtyRect)
{
m_dirtyRect = dirtyRect;
m_dirtyContents = true;
markDirty(DirtyMaterial);
}
void QSGD3D12PainterNode::setOpaquePainting(bool)
{
// ignored
}
void QSGD3D12PainterNode::setLinearFiltering(bool linearFiltering)
{
m_material.setFiltering(linearFiltering ? QSGTexture::Linear : QSGTexture::Nearest);
markDirty(DirtyMaterial);
}
void QSGD3D12PainterNode::setMipmapping(bool)
{
// ### not yet
}
void QSGD3D12PainterNode::setSmoothPainting(bool s)
{
if (m_smoothPainting == s)
return;
m_smoothPainting = s;
m_dirtyContents = true;
markDirty(DirtyMaterial);
}
void QSGD3D12PainterNode::setFillColor(const QColor &c)
{
if (m_fillColor == c)
return;
m_fillColor = c;
m_dirtyContents = true;
markDirty(DirtyMaterial);
}
void QSGD3D12PainterNode::setContentsScale(qreal s)
{
if (m_contentsScale == s)
return;
m_contentsScale = s;
m_dirtyContents = true;
markDirty(DirtyMaterial);
}
void QSGD3D12PainterNode::setFastFBOResizing(bool)
{
// nope
}
void QSGD3D12PainterNode::setTextureSize(const QSize &size)
{
if (m_textureSize == size)
return;
m_textureSize = size;
m_dirtyGeometry = true;
}
QImage QSGD3D12PainterNode::toImage() const
{
return *m_texture->image();
}
void QSGD3D12PainterNode::update()
{
if (m_dirtyGeometry) {
m_dirtyGeometry = false;
QRectF src(0, 0, 1, 1);
QRectF dst(QPointF(0, 0), m_size);
QSGGeometry::updateTexturedRectGeometry(&m_geometry, dst, src);
markDirty(DirtyGeometry);
}
QImage *img = m_texture->image();
if (img->size() != m_textureSize) {
*img = QImage(m_textureSize, QImage::Format_ARGB32_Premultiplied);
img->fill(Qt::transparent);
m_dirtyContents = true;
}
if (m_dirtyContents) {
m_dirtyContents = false;
if (!img->isNull()) {
QRect dirtyRect = m_dirtyRect.isNull() ? QRect(QPoint(0, 0), m_size) : m_dirtyRect;
QPainter painter;
painter.begin(img);
if (m_smoothPainting)
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
QRect clipRect;
QRect dirtyTextureRect;
if (m_contentsScale == 1) {
float scaleX = m_textureSize.width() / (float) m_size.width();
float scaleY = m_textureSize.height() / (float) m_size.height();
painter.scale(scaleX, scaleY);
clipRect = dirtyRect;
dirtyTextureRect = QRectF(dirtyRect.x() * scaleX,
dirtyRect.y() * scaleY,
dirtyRect.width() * scaleX,
dirtyRect.height() * scaleY).toAlignedRect();
} else {
painter.scale(m_contentsScale, m_contentsScale);
QRect sclip(qFloor(dirtyRect.x() / m_contentsScale),
qFloor(dirtyRect.y() / m_contentsScale),
qCeil(dirtyRect.width() / m_contentsScale + dirtyRect.x() / m_contentsScale
- qFloor(dirtyRect.x() / m_contentsScale)),
qCeil(dirtyRect.height() / m_contentsScale + dirtyRect.y() / m_contentsScale
- qFloor(dirtyRect.y() / m_contentsScale)));
clipRect = sclip;
dirtyTextureRect = dirtyRect;
}
// only clip if we were originally updating only a subrect
if (!m_dirtyRect.isNull())
painter.setClipRect(clipRect);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.fillRect(clipRect, m_fillColor);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
m_item->paint(&painter);
painter.end();
m_texture->dirty = dirtyTextureRect;
}
m_dirtyRect = QRect();
}
}
QSGTexture *QSGD3D12PainterNode::texture() const
{
return m_texture;
}
QT_END_NAMESPACE

View File

@ -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$
**
****************************************************************************/
#ifndef QSGD3D12PAINTERNODE_P_H
#define QSGD3D12PAINTERNODE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgadaptationlayer_p.h>
#include "qsgd3d12texture_p.h"
#include "qsgd3d12builtinmaterials_p.h"
QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
class QSGD3D12PainterTexture : public QSGD3D12Texture
{
public:
QSGD3D12PainterTexture(QSGD3D12Engine *engine);
void bind() override;
QImage *image() { return &m_image; }
QRect dirty;
private:
QSize lastSize;
};
class QSGD3D12PainterNode : public QSGPainterNode
{
public:
QSGD3D12PainterNode(QQuickPaintedItem *item);
~QSGD3D12PainterNode();
void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target) override;
void setSize(const QSize &size) override;
void setDirty(const QRect &dirtyRect = QRect()) override;
void setOpaquePainting(bool opaque) override;
void setLinearFiltering(bool linearFiltering) override;
void setMipmapping(bool mipmapping) override;
void setSmoothPainting(bool s) override;
void setFillColor(const QColor &c) override;
void setContentsScale(qreal s) override;
void setFastFBOResizing(bool dynamic) override;
void setTextureSize(const QSize &size) override;
QImage toImage() const override;
void update() override;
QSGTexture *texture() const override;
private:
QQuickPaintedItem *m_item;
QSGD3D12Engine *m_engine;
QSGD3D12PainterTexture *m_texture;
QSize m_size;
QSize m_textureSize;
float m_contentsScale = 1;
bool m_smoothPainting = false;
QColor m_fillColor = Qt::transparent;
QRect m_dirtyRect;
QSGGeometry m_geometry;
QSGD3D12TextureMaterial m_material;
uint m_dirtyGeometry : 1;
uint m_dirtyContents : 1;
};
QT_END_NAMESPACE
#endif // QSGD3D12PAINTERNODE_P_H

View File

@ -0,0 +1,72 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgd3d12rectanglenode_p.h"
QT_BEGIN_NAMESPACE
QSGD3D12RectangleNode::QSGD3D12RectangleNode()
{
setMaterial(&m_material);
}
void QSGD3D12RectangleNode::updateMaterialAntialiasing()
{
if (m_antialiasing)
setMaterial(&m_smoothMaterial);
else
setMaterial(&m_material);
}
void QSGD3D12RectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
{
// smoothed material is always blended, so no change in material state
if (material() == &m_material) {
bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
|| (m_color.alpha() < 255 && m_color.alpha() != 0)
|| (m_pen_width > 0 && m_border_color.alpha() < 255);
if (wasBlending != isBlending) {
m_material.setFlag(QSGMaterial::Blending, isBlending);
*state |= QSGNode::DirtyMaterial;
}
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12RECTANGLENODE_P_H
#define QSGD3D12RECTANGLENODE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgbasicrectanglenode_p.h>
#include "qsgd3d12builtinmaterials_p.h"
QT_BEGIN_NAMESPACE
class QSGD3D12RectangleNode : public QSGBasicRectangleNode
{
public:
QSGD3D12RectangleNode();
private:
void updateMaterialAntialiasing() override;
void updateMaterialBlending(QSGNode::DirtyState *state) override;
QSGD3D12VertexColorMaterial m_material;
QSGD3D12SmoothColorMaterial m_smoothMaterial;
};
QT_END_NAMESPACE
#endif // QSGD3D12RECTANGLENODE_P_H

View File

@ -0,0 +1,129 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgd3d12rendercontext_p.h"
#include "qsgd3d12renderer_p.h"
#include "qsgd3d12texture_p.h"
QT_BEGIN_NAMESPACE
// NOTE: Avoid categorized logging. It is slow.
#define DECLARE_DEBUG_VAR(variable) \
static bool debug_ ## variable() \
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(render)
QSGD3D12RenderContext::QSGD3D12RenderContext(QSGContext *ctx)
: QSGRenderContext(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()))
qDebug("rendercontext invalidate engine %p, %d/%d/%d", m_engine,
m_texturesToDelete.count(), m_textures.count(), m_fontEnginesToClean.count());
qDeleteAll(m_texturesToDelete);
m_texturesToDelete.clear();
qDeleteAll(m_textures);
m_textures.clear();
for (QSet<QFontEngine *>::const_iterator it = m_fontEnginesToClean.constBegin(),
end = m_fontEnginesToClean.constEnd(); it != end; ++it) {
(*it)->clearGlyphCache(m_engine);
if (!(*it)->ref.deref())
delete *it;
}
m_fontEnginesToClean.clear();
m_sg->renderContextInvalidated(this);
emit invalidated();
}
QSGTexture *QSGD3D12RenderContext::createTexture(const QImage &image, uint flags) const
{
Q_ASSERT(m_engine);
QSGD3D12Texture *t = new QSGD3D12Texture(m_engine);
t->create(image, flags);
return t;
}
QSGRenderer *QSGD3D12RenderContext::createRenderer()
{
return new QSGD3D12Renderer(this);
}
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();
}
void QSGD3D12RenderContext::ensureInitializedEmitted()
{
if (!m_pendingInitialized)
return;
m_pendingInitialized = false;
emit initialized();
}
QT_END_NAMESPACE

View File

@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12RENDERCONTEXT_P_H
#define QSGD3D12RENDERCONTEXT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgcontext_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
class QSGD3D12RenderContext : public QSGRenderContext
{
public:
QSGD3D12RenderContext(QSGContext *ctx);
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);
QSGD3D12Engine *engine() { return m_engine; }
void ensureInitializedEmitted();
void setInitializedPending() { m_pendingInitialized = true; }
private:
QSGD3D12Engine *m_engine = nullptr;
bool m_pendingInitialized = false;
};
QT_END_NAMESPACE
#endif // QSGD3D12RENDERCONTEXT_P_H

View File

@ -0,0 +1,783 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsgd3d12renderer_p.h"
#include "qsgd3d12rendercontext_p.h"
#include <private/qsgnodeupdater_p.h>
#include <private/qsgrendernode_p.h>
#include "vs_stencilclip.hlslh"
#include "ps_stencilclip.hlslh"
//#define I_LIKE_STENCIL
QT_BEGIN_NAMESPACE
#define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling())
// NOTE: Avoid categorized logging. It is slow.
#define DECLARE_DEBUG_VAR(variable) \
static bool debug_ ## variable() \
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(build)
DECLARE_DEBUG_VAR(change)
DECLARE_DEBUG_VAR(render)
class DummyUpdater : public QSGNodeUpdater
{
public:
void updateState(QSGNode *) { };
};
QSGD3D12Renderer::QSGD3D12Renderer(QSGRenderContext *context)
: QSGRenderer(context),
m_renderList(16),
m_vboData(1024),
m_iboData(256),
m_cboData(4096)
{
setNodeUpdater(new DummyUpdater);
}
QSGD3D12Renderer::~QSGD3D12Renderer()
{
if (m_engine) {
m_engine->releaseBuffer(m_vertexBuf);
m_engine->releaseBuffer(m_indexBuf);
m_engine->releaseBuffer(m_constantBuf);
}
}
void QSGD3D12Renderer::renderScene(GLuint fboId)
{
m_renderTarget = fboId;
struct DummyBindable : public QSGBindable {
void bind() const { }
} bindable;
QSGRenderer::renderScene(bindable); // calls back render()
}
// Search through the node set and remove nodes that are descendants of other
// nodes in the same set.
static QSet<QSGNode *> qsg_removeDescendants(const QSet<QSGNode *> &nodes, QSGRootNode *root)
{
QSet<QSGNode *> result = nodes;
for (QSGNode *node : nodes) {
QSGNode *n = node;
while (n != root) {
if (n != node && result.contains(n)) {
result.remove(node);
break;
}
n = n->parent();
}
}
return result;
}
void QSGD3D12Renderer::updateMatrices(QSGNode *node, QSGTransformNode *xform)
{
if (node->isSubtreeBlocked())
return;
if (node->type() == QSGNode::TransformNodeType) {
QSGTransformNode *tn = static_cast<QSGTransformNode *>(node);
if (xform)
tn->setCombinedMatrix(xform->combinedMatrix() * tn->matrix());
else
tn->setCombinedMatrix(tn->matrix());
QSGNODE_TRAVERSE(node)
updateMatrices(child, tn);
} else {
if (node->type() == QSGNode::GeometryNodeType || node->type() == QSGNode::ClipNodeType) {
m_nodeDirtyMap[node] |= QSGD3D12MaterialRenderState::DirtyMatrix;
QSGBasicGeometryNode *gnode = static_cast<QSGBasicGeometryNode *>(node);
const QMatrix4x4 *newMatrix = xform ? &xform->combinedMatrix() : nullptr;
// NB the newMatrix ptr is usually the same as before as it just
// references the transform node's own matrix.
gnode->setRendererMatrix(newMatrix);
}
QSGNODE_TRAVERSE(node)
updateMatrices(child, xform);
}
}
void QSGD3D12Renderer::updateOpacities(QSGNode *node, float inheritedOpacity)
{
if (node->isSubtreeBlocked())
return;
if (node->type() == QSGNode::OpacityNodeType) {
QSGOpacityNode *on = static_cast<QSGOpacityNode *>(node);
float combined = inheritedOpacity * on->opacity();
on->setCombinedOpacity(combined);
QSGNODE_TRAVERSE(node)
updateOpacities(child, combined);
} else {
if (node->type() == QSGNode::GeometryNodeType) {
m_nodeDirtyMap[node] |= QSGD3D12MaterialRenderState::DirtyOpacity;
QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(node);
gn->setInheritedOpacity(inheritedOpacity);
}
QSGNODE_TRAVERSE(node)
updateOpacities(child, inheritedOpacity);
}
}
void QSGD3D12Renderer::buildRenderList(QSGNode *node, QSGClipNode *clip)
{
if (node->isSubtreeBlocked())
return;
if (node->type() == QSGNode::GeometryNodeType || node->type() == QSGNode::ClipNodeType) {
QSGBasicGeometryNode *gn = static_cast<QSGBasicGeometryNode *>(node);
QSGGeometry *g = gn->geometry();
Element e;
e.node = gn;
if (g->vertexCount() > 0) {
e.vboOffset = m_vboData.size();
const int vertexSize = g->sizeOfVertex() * g->vertexCount();
m_vboData.resize(m_vboData.size() + vertexSize);
memcpy(m_vboData.data() + e.vboOffset, g->vertexData(), vertexSize);
}
if (g->indexCount() > 0) {
e.iboOffset = m_iboData.size();
e.iboStride = g->sizeOfIndex();
const int indexSize = e.iboStride * g->indexCount();
m_iboData.resize(m_iboData.size() + indexSize);
memcpy(m_iboData.data() + e.iboOffset, g->indexData(), indexSize);
}
e.cboOffset = m_cboData.size();
if (node->type() == QSGNode::GeometryNodeType) {
QSGD3D12Material *m = static_cast<QSGD3D12Material *>(static_cast<QSGGeometryNode *>(node)->activeMaterial());
e.cboSize = m->constantBufferSize();
} else {
// Stencil-based clipping needs a 4x4 matrix.
e.cboSize = QSGD3D12Engine::alignedConstantBufferSize(16 * sizeof(float));
}
m_cboData.resize(m_cboData.size() + e.cboSize);
m_renderList.add(e);
gn->setRendererClipList(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)
buildRenderList(child, clip);
}
void QSGD3D12Renderer::render()
{
QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(context());
m_engine = rc->engine();
if (!m_layerRenderer)
m_engine->beginFrame();
else
m_engine->beginLayer();
m_activeScissorRect = QRect();
if (m_rebuild) {
m_rebuild = false;
m_dirtyTransformNodes.clear();
m_dirtyTransformNodes.insert(rootNode());
m_dirtyOpacityNodes.clear();
m_dirtyOpacityNodes.insert(rootNode());
m_renderList.reset();
m_vboData.reset();
m_iboData.reset();
m_cboData.reset();
buildRenderList(rootNode(), nullptr);
if (!m_vertexBuf)
m_vertexBuf = m_engine->genBuffer();
m_engine->resetBuffer(m_vertexBuf, m_vboData.data(), m_vboData.size());
if (!m_constantBuf)
m_constantBuf = m_engine->genBuffer();
m_engine->resetBuffer(m_constantBuf, m_cboData.data(), m_cboData.size());
if (m_iboData.size()) {
if (!m_indexBuf)
m_indexBuf = m_engine->genBuffer();
m_engine->resetBuffer(m_indexBuf, m_iboData.data(), m_iboData.size());
} else if (m_indexBuf) {
m_engine->releaseBuffer(m_indexBuf);
m_indexBuf = 0;
}
if (Q_UNLIKELY(debug_build())) {
qDebug("renderList: %d elements in total", m_renderList.size());
for (int i = 0; i < m_renderList.size(); ++i) {
const Element &e = m_renderList.at(i);
qDebug() << " - " << e.vboOffset << e.iboOffset << e.cboOffset << e.cboSize << e.node;
}
}
}
const QRect devRect = deviceRect();
m_projectionChangedDueToDeviceSize = devRect != m_lastDeviceRect;
if (m_projectionChangedDueToDeviceSize)
m_lastDeviceRect = devRect;
if (m_dirtyTransformNodes.size()) {
const QSet<QSGNode *> subTreeRoots = qsg_removeDescendants(m_dirtyTransformNodes, rootNode());
for (QSGNode *node : subTreeRoots) {
// First find the parent transform so we have the accumulated
// matrix up until this point.
QSGTransformNode *xform = 0;
QSGNode *n = node;
if (n->type() == QSGNode::TransformNodeType)
n = node->parent();
while (n != rootNode() && n->type() != QSGNode::TransformNodeType)
n = n->parent();
if (n != rootNode())
xform = static_cast<QSGTransformNode *>(n);
// Then update in the subtree
updateMatrices(node, xform);
}
}
if (m_dirtyOpacityNodes.size()) {
const QSet<QSGNode *> subTreeRoots = qsg_removeDescendants(m_dirtyOpacityNodes, rootNode());
for (QSGNode *node : subTreeRoots) {
float opacity = 1.0f;
QSGNode *n = node;
if (n->type() == QSGNode::OpacityNodeType)
n = node->parent();
while (n != rootNode() && n->type() != QSGNode::OpacityNodeType)
n = n->parent();
if (n != rootNode())
opacity = static_cast<QSGOpacityNode *>(n)->combinedOpacity();
updateOpacities(node, opacity);
}
m_dirtyOpaqueElements = true;
}
if (m_dirtyOpaqueElements) {
m_dirtyOpaqueElements = false;
m_opaqueElements.clear();
m_opaqueElements.resize(m_renderList.size());
for (int i = 0; i < m_renderList.size(); ++i) {
const Element &e = m_renderList.at(i);
if (e.node->type() == QSGNode::GeometryNodeType) {
const QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(e.node);
if (gn->inheritedOpacity() > 0.999f && ((gn->activeMaterial()->flags() & QSGMaterial::Blending) == 0))
m_opaqueElements.setBit(i);
}
// QSGRenderNodes are always treated as non-opaque
}
}
// Build pipeline state and draw calls.
renderElements();
m_dirtyTransformNodes.clear();
m_dirtyOpacityNodes.clear();
m_dirtyOpaqueElements = false;
m_nodeDirtyMap.clear();
// Finalize buffers and execute commands.
if (!m_layerRenderer)
m_engine->endFrame();
else
m_engine->endLayer();
}
void QSGD3D12Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
{
// note that with DirtyNodeRemoved the window and all the graphics engine may already be gone
if (Q_UNLIKELY(debug_change())) {
QDebug debug = qDebug();
debug << "dirty:";
if (state & QSGNode::DirtyGeometry)
debug << "Geometry";
if (state & QSGNode::DirtyMaterial)
debug << "Material";
if (state & QSGNode::DirtyMatrix)
debug << "Matrix";
if (state & QSGNode::DirtyNodeAdded)
debug << "Added";
if (state & QSGNode::DirtyNodeRemoved)
debug << "Removed";
if (state & QSGNode::DirtyOpacity)
debug << "Opacity";
if (state & QSGNode::DirtySubtreeBlocked)
debug << "SubtreeBlocked";
if (state & QSGNode::DirtyForceUpdate)
debug << "ForceUpdate";
// when removed, some parts of the node could already have been destroyed
// so don't debug it out.
if (state & QSGNode::DirtyNodeRemoved)
debug << (void *) node << node->type();
else
debug << node;
}
if (state & (QSGNode::DirtyNodeAdded
| QSGNode::DirtyNodeRemoved
| QSGNode::DirtySubtreeBlocked
| QSGNode::DirtyGeometry
| QSGNode::DirtyForceUpdate))
m_rebuild = true;
if (state & QSGNode::DirtyMatrix)
m_dirtyTransformNodes << node;
if (state & QSGNode::DirtyOpacity)
m_dirtyOpacityNodes << node;
if (state & QSGNode::DirtyMaterial)
m_dirtyOpaqueElements = true;
QSGRenderer::nodeChanged(node, state);
}
void QSGD3D12Renderer::renderElements()
{
m_engine->queueSetRenderTarget(m_renderTarget);
m_engine->queueViewport(viewportRect());
m_engine->queueClearRenderTarget(clearColor());
m_engine->queueClearDepthStencil(1, 0, QSGD3D12Engine::ClearDepth | QSGD3D12Engine::ClearStencil);
m_pipelineState.blend = m_freshPipelineState.blend = QSGD3D12PipelineState::BlendNone;
m_pipelineState.depthEnable = m_freshPipelineState.depthEnable = true;
m_pipelineState.depthWrite = m_freshPipelineState.depthWrite = true;
// First do opaque...
// The algorithm is quite simple. We traverse the list back-to-front, and
// for every item we start a second traversal and draw all elements which
// have identical material. Then we clear the bit for this in the rendered
// list so we don't draw it again when we come to that index.
QBitArray rendered = m_opaqueElements;
for (int i = m_renderList.size() - 1; i >= 0; --i) {
if (rendered.testBit(i)) {
renderElement(i);
for (int j = i - 1; j >= 0; --j) {
if (rendered.testBit(j)) {
const QSGGeometryNode *gni = static_cast<QSGGeometryNode *>(m_renderList.at(i).node);
const QSGGeometryNode *gnj = static_cast<QSGGeometryNode *>(m_renderList.at(j).node);
if (gni->clipList() == gnj->clipList()
&& gni->inheritedOpacity() == gnj->inheritedOpacity()
&& gni->geometry()->drawingMode() == gnj->geometry()->drawingMode()
&& gni->geometry()->attributes() == gnj->geometry()->attributes()) {
const QSGMaterial *ami = gni->activeMaterial();
const QSGMaterial *amj = gnj->activeMaterial();
if (ami->type() == amj->type()
&& ami->flags() == amj->flags()
&& ami->compare(amj) == 0) {
renderElement(j);
rendered.clearBit(j);
}
}
}
}
}
}
m_pipelineState.blend = m_freshPipelineState.blend = QSGD3D12PipelineState::BlendPremul;
m_pipelineState.depthWrite = m_freshPipelineState.depthWrite = false;
// ...then the alpha ones
for (int i = 0; i < m_renderList.size(); ++i) {
if ((m_renderList.at(i).node->type() == QSGNode::GeometryNodeType && !m_opaqueElements.testBit(i))
|| 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 || e.node->type() == QSGNode::RenderNodeType);
if (e.node->type() == QSGNode::RenderNodeType) {
renderRenderNode(static_cast<QSGRenderNode *>(e.node), elementIndex);
return;
}
if (e.vboOffset < 0)
return;
Q_ASSERT(e.cboOffset >= 0);
const QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(e.node);
if (Q_UNLIKELY(debug_render()))
qDebug() << "renderElement:" << elementIndex << gn << e.vboOffset << e.iboOffset << gn->inheritedOpacity() << gn->clipList();
if (gn->inheritedOpacity() < 0.001f) // pretty much invisible, don't draw it
return;
// Update the QSGRenderer members which the materials will access.
m_current_projection_matrix = projectionMatrix();
const float scale = 1.0 / m_renderList.size();
m_current_projection_matrix(2, 2) = scale;
m_current_projection_matrix(2, 3) = 1.0f - (elementIndex + 1) * scale;
m_current_model_view_matrix = gn->matrix() ? *gn->matrix() : QMatrix4x4();
m_current_determinant = m_current_model_view_matrix.determinant();
m_current_opacity = gn->inheritedOpacity();
const QSGGeometry *g = gn->geometry();
QSGD3D12Material *m = static_cast<QSGD3D12Material *>(gn->activeMaterial());
if (m->type() != m_lastMaterialType) {
m_pipelineState = m_freshPipelineState;
m->preparePipeline(&m_pipelineState);
}
QSGD3D12MaterialRenderState::DirtyStates dirtyState = m_nodeDirtyMap.value(e.node);
// After a rebuild everything in the cbuffer has to be updated.
if (!e.cboPrepared) {
e.cboPrepared = true;
dirtyState = QSGD3D12MaterialRenderState::DirtyAll;
}
// DirtyMatrix does not include projection matrix changes that can arise
// due to changing the render target's size (and there is no rebuild).
// Accommodate for this.
if (m_projectionChangedDueToDeviceSize)
dirtyState |= QSGD3D12MaterialRenderState::DirtyMatrix;
quint8 *cboPtr = nullptr;
if (e.cboSize > 0)
cboPtr = m_cboData.data() + e.cboOffset;
if (Q_UNLIKELY(debug_render()))
qDebug() << "dirty state for" << e.node << "is" << dirtyState;
QSGD3D12Material::ExtraState extraState;
QSGD3D12Material::UpdateResults updRes = m->updatePipeline(state(dirtyState),
&m_pipelineState,
&extraState,
cboPtr);
if (updRes.testFlag(QSGD3D12Material::UpdatedConstantBuffer))
m_engine->markBufferDirty(m_constantBuf, e.cboOffset, e.cboSize);
if (updRes.testFlag(QSGD3D12Material::UpdatedBlendFactor))
m_engine->queueSetBlendFactor(extraState.blendFactor);
setInputLayout(g, &m_pipelineState);
m_lastMaterialType = m->type();
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) {
if (g->lineWidth() != 1.0f)
qWarning("QSGD3D12Renderer: Line widths other than 1 are not supported by this renderer");
} else if (g->drawingMode() == QSGGeometry::DrawPoints) {
if (g->lineWidth() != 1.0f)
qWarning("QSGD3D12Renderer: Point sprites are not supported by this renderer");
}
m_engine->finalizePipeline(m_pipelineState);
queueDrawCall(g, e);
}
void QSGD3D12Renderer::setInputLayout(const QSGGeometry *g, QSGD3D12PipelineState *pipelineState)
{
pipelineState->inputElementCount = g->attributeCount();
const QSGGeometry::Attribute *attrs = g->attributes();
quint32 offset = 0;
for (int i = 0; i < g->attributeCount(); ++i) {
QSGD3D12InputElement &ie(pipelineState->inputElements[i]);
static const char *semanticNames[] = { "UNKNOWN", "POSITION", "COLOR", "TEXCOORD", "TEXCOORD", "TEXCOORD" };
static const int semanticIndices[] = { 0, 0, 0, 0, 1, 2 };
Q_ASSERT(attrs[i].semantic >= 1 && attrs[i].semantic < _countof(semanticNames));
const int tupleSize = attrs[i].tupleSize;
ie.semanticName = semanticNames[attrs[i].semantic];
ie.semanticIndex = semanticIndices[attrs[i].semantic];
ie.offset = offset;
int bytesPerTuple = 0;
ie.format = QSGD3D12Engine::toDXGIFormat(QSGGeometry::Type(attrs[i].type), tupleSize, &bytesPerTuple);
if (ie.format == FmtUnknown)
qFatal("QSGD3D12Renderer: unsupported tuple size for attribute type 0x%x", attrs[i].type);
offset += bytesPerTuple;
// There is one buffer with interleaved data so the slot is always 0.
ie.slot = 0;
}
}
void QSGD3D12Renderer::queueDrawCall(const QSGGeometry *g, const QSGD3D12Renderer::Element &e)
{
QSGD3D12Engine::DrawParams dp;
dp.mode = QSGGeometry::DrawingMode(g->drawingMode());
dp.vertexBuf = m_vertexBuf;
dp.constantBuf = m_constantBuf;
dp.vboOffset = e.vboOffset;
dp.vboSize = g->vertexCount() * g->sizeOfVertex();
dp.vboStride = g->sizeOfVertex();
dp.cboOffset = e.cboOffset;
if (e.iboOffset >= 0) {
const QSGGeometry::Type indexType = QSGGeometry::Type(g->indexType());
const QSGD3D12Format indexFormat = QSGD3D12Engine::toDXGIFormat(indexType);
if (indexFormat == FmtUnknown)
qFatal("QSGD3D12Renderer: unsupported index type 0x%x", indexType);
dp.count = g->indexCount();
dp.indexBuf = m_indexBuf;
dp.startIndexIndex = e.iboOffset / e.iboStride;
dp.indexFormat = indexFormat;
} else {
dp.count = g->vertexCount();
}
m_engine->queueDraw(dp);
}
void QSGD3D12Renderer::setupClipping(const QSGClipNode *clip, int elementIndex)
{
const QRect devRect = deviceRect();
QRect scissorRect;
int clipTypes = 0;
quint32 stencilValue = 0;
while (clip) {
QMatrix4x4 m = projectionMatrix();
if (clip->matrix())
m *= *clip->matrix();
#ifndef I_LIKE_STENCIL
const bool isRectangleWithNoPerspective = clip->isRectangular()
&& qFuzzyIsNull(m(3, 0)) && qFuzzyIsNull(m(3, 1));
const bool noRotate = qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(1, 0));
const bool isRotate90 = qFuzzyIsNull(m(0, 0)) && qFuzzyIsNull(m(1, 1));
if (isRectangleWithNoPerspective && (noRotate || isRotate90)) {
QRectF bbox = clip->clipRect();
float invW = 1.0f / m(3, 3);
float fx1, fy1, fx2, fy2;
if (noRotate) {
fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
} else {
Q_ASSERT(isRotate90);
fx1 = (bbox.bottom() * m(0, 1) + m(0, 3)) * invW;
fy1 = (bbox.left() * m(1, 0) + m(1, 3)) * invW;
fx2 = (bbox.top() * m(0, 1) + m(0, 3)) * invW;
fy2 = (bbox.right() * m(1, 0) + m(1, 3)) * invW;
}
if (fx1 > fx2)
qSwap(fx1, fx2);
if (fy1 > fy2)
qSwap(fy1, fy2);
int ix1 = qRound((fx1 + 1) * devRect.width() * 0.5f);
int iy1 = qRound((fy1 + 1) * devRect.height() * 0.5f);
int ix2 = qRound((fx2 + 1) * devRect.width() * 0.5f);
int iy2 = qRound((fy2 + 1) * devRect.height() * 0.5f);
if (!(clipTypes & ClipScissor)) {
scissorRect = QRect(ix1, devRect.height() - iy2, ix2 - ix1, iy2 - iy1);
clipTypes |= ClipScissor;
} else {
scissorRect &= QRect(ix1, devRect.height() - iy2, ix2 - ix1, iy2 - iy1);
}
} else
#endif
{
clipTypes |= ClipStencil;
renderStencilClip(clip, elementIndex, m, stencilValue);
}
clip = clip->clipList();
}
setScissor((clipTypes & ClipScissor) ? scissorRect : viewportRect());
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)
{
if (m_activeScissorRect == r)
return;
m_activeScissorRect = r;
m_engine->queueScissor(r);
}
void QSGD3D12Renderer::renderStencilClip(const QSGClipNode *clip, int elementIndex,
const QMatrix4x4 &m, quint32 &stencilValue)
{
QSGD3D12PipelineState sps;
sps.shaders.vs = g_VS_StencilClip;
sps.shaders.vsSize = sizeof(g_VS_StencilClip);
sps.shaders.ps = g_PS_StencilClip;
sps.shaders.psSize = sizeof(g_PS_StencilClip);
m_engine->queueClearDepthStencil(1, 0, QSGD3D12Engine::ClearStencil);
sps.stencilEnable = true;
sps.colorWrite = false;
sps.depthWrite = false;
sps.stencilFunc = QSGD3D12PipelineState::CompareEqual;
sps.stencilFailOp = QSGD3D12PipelineState::StencilKeep;
sps.stencilDepthFailOp = QSGD3D12PipelineState::StencilKeep;
sps.stencilPassOp = QSGD3D12PipelineState::StencilIncr;
m_engine->queueSetStencilRef(stencilValue);
int clipIndex = elementIndex;
while (m_renderList.at(--clipIndex).node != clip) {
Q_ASSERT(clipIndex >= 0);
}
const Element &ce = m_renderList.at(clipIndex);
Q_ASSERT(ce.node == clip);
const QSGGeometry *g = clip->geometry();
Q_ASSERT(g->attributeCount() == 1);
Q_ASSERT(g->attributes()[0].tupleSize == 2);
Q_ASSERT(g->attributes()[0].type == QSGGeometry::TypeFloat);
setInputLayout(g, &sps);
m_engine->finalizePipeline(sps);
Q_ASSERT(ce.cboSize > 0);
quint8 *p = m_cboData.data() + ce.cboOffset;
memcpy(p, m.constData(), 16 * sizeof(float));
m_engine->markBufferDirty(m_constantBuf, ce.cboOffset, ce.cboSize);
queueDrawCall(g, ce);
++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 = &pm;
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

View File

@ -0,0 +1,137 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12RENDERER_P_H
#define QSGD3D12RENDERER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgrenderer_p.h>
#include <QtGui/private/qdatabuffer_p.h>
#include <QtCore/qbitarray.h>
#include "qsgd3d12engine_p.h"
#include "qsgd3d12material_p.h"
QT_BEGIN_NAMESPACE
class QSGRenderNode;
class QSGD3D12Renderer : public QSGRenderer
{
public:
QSGD3D12Renderer(QSGRenderContext *context);
~QSGD3D12Renderer();
void renderScene(GLuint fboId) override;
void render() override;
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override;
void turnToLayerRenderer() { m_layerRenderer = true; }
private:
void updateMatrices(QSGNode *node, QSGTransformNode *xform);
void updateOpacities(QSGNode *node, float inheritedOpacity);
void buildRenderList(QSGNode *node, QSGClipNode *clip);
void renderElements();
void renderElement(int elementIndex);
void setInputLayout(const QSGGeometry *g, QSGD3D12PipelineState *pipelineState);
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 {
QSGNode *node = nullptr;
qint32 vboOffset = -1;
qint32 iboOffset = -1;
quint32 iboStride = 0;
qint32 cboOffset = -1;
quint32 cboSize = 0;
bool cboPrepared = false;
};
void queueDrawCall(const QSGGeometry *g, const Element &e);
bool m_layerRenderer = false;
QSet<QSGNode *> m_dirtyTransformNodes;
QSet<QSGNode *> m_dirtyOpacityNodes;
QBitArray m_opaqueElements;
bool m_rebuild = true;
bool m_dirtyOpaqueElements = true;
QDataBuffer<quint8> m_vboData;
QDataBuffer<quint8> m_iboData;
QDataBuffer<quint8> m_cboData;
QDataBuffer<Element> m_renderList;
uint m_vertexBuf = 0;
uint m_indexBuf = 0;
uint m_constantBuf = 0;
QSGD3D12Engine *m_engine = nullptr;
QSGMaterialType *m_lastMaterialType = nullptr;
QSGD3D12PipelineState m_pipelineState;
QSGD3D12PipelineState m_freshPipelineState;
typedef QHash<QSGNode *, QSGD3D12MaterialRenderState::DirtyStates> NodeDirtyMap;
NodeDirtyMap m_nodeDirtyMap;
QRect m_activeScissorRect;
QRect m_lastDeviceRect;
bool m_projectionChangedDueToDeviceSize;
uint m_renderTarget = 0;
quint32 m_currentStencilValue;
enum ClipType {
ClipScissor = 0x1,
ClipStencil = 0x2
};
int m_currentClipTypes;
};
QT_END_NAMESPACE
#endif // QSGD3D12RENDERER_P_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSGD3D12RENDERLOOP_P_H
#define QSGD3D12RENDERLOOP_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgrenderloop_p.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
class QSGD3D12Context;
class QSGD3D12RenderContext;
class QSGD3D12RenderThread;
class QSGD3D12RenderLoop : public QSGRenderLoop
{
Q_OBJECT
public:
QSGD3D12RenderLoop();
~QSGD3D12RenderLoop();
void show(QQuickWindow *window) override;
void hide(QQuickWindow *window) override;
void resize(QQuickWindow *window) override;
void windowDestroyed(QQuickWindow *window) override;
void exposureChanged(QQuickWindow *window) override;
QImage grab(QQuickWindow *window) override;
void update(QQuickWindow *window) override;
void maybeUpdate(QQuickWindow *window) override;
void handleUpdateRequest(QQuickWindow *window) override;
QAnimationDriver *animationDriver() const override;
QSGContext *sceneGraphContext() const override;
QSGRenderContext *createRenderContext(QSGContext *) const override;
void releaseResources(QQuickWindow *window) override;
void postJob(QQuickWindow *window, QRunnable *job) override;
QSurface::SurfaceType windowSurfaceType() const override;
bool interleaveIncubation() const override;
int flags() const override;
bool event(QEvent *e) override;
public Q_SLOTS:
void onAnimationStarted();
void onAnimationStopped();
private:
struct WindowData {
QQuickWindow *window;
QSGD3D12RenderThread *thread;
uint updateDuringSync : 1;
uint forceRenderPass : 1;
};
void startOrStopAnimationTimer();
void handleExposure(QQuickWindow *window);
void handleObscurity(WindowData *w);
void scheduleUpdate(WindowData *w);
void handleResourceRelease(WindowData *w, bool destroying);
void polishAndSync(WindowData *w, bool inExpose);
QSGD3D12Context *sg;
QAnimationDriver *anim;
int animationTimer = 0;
bool lockedForSync = false;
QVector<WindowData> windows;
friend class QSGD3D12RenderThread;
};
QT_END_NAMESPACE
#endif // QSGD3D12RENDERLOOP_P_H

View File

@ -0,0 +1,962 @@
/****************************************************************************
**
** 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 "qsgd3d12shadereffectnode_p.h"
#include "qsgd3d12rendercontext_p.h"
#include "qsgd3d12texture_p.h"
#include "qsgd3d12engine_p.h"
#include <QtCore/qfile.h>
#include <QtQml/qqmlfile.h>
#include <qsgtextureprovider.h>
#include <d3d12shader.h>
#include <d3dcompiler.h>
#include "vs_shadereffectdefault.hlslh"
#include "ps_shadereffectdefault.hlslh"
QT_BEGIN_NAMESPACE
// NOTE: Avoid categorized logging. It is slow.
#define DECLARE_DEBUG_VAR(variable) \
static bool debug_ ## variable() \
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(render)
void QSGD3D12ShaderLinker::reset(const QByteArray &vertBlob, const QByteArray &fragBlob)
{
Q_ASSERT(!vertBlob.isEmpty() && !fragBlob.isEmpty());
vs = vertBlob;
fs = fragBlob;
error = false;
constantBufferSize = 0;
constants.clear();
samplers.clear();
textures.clear();
textureNameMap.clear();
}
void QSGD3D12ShaderLinker::feedVertexInput(const QSGShaderEffectNode::ShaderData &shader)
{
bool foundPos = false, foundTexCoord = false;
for (const auto &ip : qAsConst(shader.shaderInfo.inputParameters)) {
if (ip.semanticName == QByteArrayLiteral("POSITION"))
foundPos = true;
else if (ip.semanticName == QByteArrayLiteral("TEXCOORD"))
foundTexCoord = true;
}
if (!foundPos) {
qWarning("ShaderEffect: No POSITION input found.");
error = true;
}
if (!foundTexCoord) {
qWarning("ShaderEffect: No TEXCOORD input found.");
error = true;
}
// Nothing else to do here, the QSGGeometry::AttributeSet decides anyway
// and that is already generated by QQuickShaderEffectMesh via
// QSGGeometry::defaultAttributes_TexturedPoint2D() and has the semantics
// so it will just work.
}
void QSGD3D12ShaderLinker::feedConstants(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices)
{
Q_ASSERT(shader.shaderInfo.variables.count() == shader.varData.count());
if (!dirtyIndices) {
constantBufferSize = qMax(constantBufferSize, shader.shaderInfo.constantDataSize);
for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
const auto &var(shader.shaderInfo.variables.at(i));
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Constant) {
const auto &vd(shader.varData.at(i));
Constant c;
c.size = var.size;
c.specialType = vd.specialType;
if (c.specialType != QSGShaderEffectNode::VariableData::SubRect) {
c.value = vd.value;
} else {
Q_ASSERT(var.name.startsWith(QByteArrayLiteral("qt_SubRect_")));
c.value = var.name.mid(11);
}
constants[var.offset] = c;
}
}
} else {
for (int idx : *dirtyIndices)
constants[shader.shaderInfo.variables.at(idx).offset].value = shader.varData.at(idx).value;
}
}
void QSGD3D12ShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &shader)
{
for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
const auto &var(shader.shaderInfo.variables.at(i));
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
const auto &vd(shader.varData.at(i));
Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Unused);
samplers.insert(var.bindPoint);
}
}
}
void QSGD3D12ShaderLinker::feedTextures(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices)
{
if (!dirtyIndices) {
for (int i = 0; i < shader.shaderInfo.variables.count(); ++i) {
const auto &var(shader.shaderInfo.variables.at(i));
const auto &vd(shader.varData.at(i));
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Source);
textures.insert(var.bindPoint, vd.value);
textureNameMap.insert(var.name, var.bindPoint);
}
}
} else {
for (int idx : *dirtyIndices) {
const auto &var(shader.shaderInfo.variables.at(idx));
const auto &vd(shader.varData.at(idx));
textures.insert(var.bindPoint, vd.value);
textureNameMap.insert(var.name, var.bindPoint);
}
}
}
void QSGD3D12ShaderLinker::linkTextureSubRects()
{
// feedConstants stores <name> in Constant::value for subrect entries. Now
// that both constants and textures are known, replace the name with the
// texture bind point.
for (Constant &c : constants) {
if (c.specialType == QSGShaderEffectNode::VariableData::SubRect) {
if (c.value.type() == QMetaType::QByteArray) {
const QByteArray name = c.value.toByteArray();
if (!textureNameMap.contains(name))
qWarning("ShaderEffect: qt_SubRect_%s refers to unknown source texture", qPrintable(name));
c.value = textureNameMap[name];
}
}
}
}
void QSGD3D12ShaderLinker::dump()
{
if (error) {
qDebug() << "Failed to generate program data";
return;
}
qDebug() << "Combined shader data" << vs.size() << fs.size() << "cbuffer size" << constantBufferSize;
qDebug() << " - constants" << constants;
qDebug() << " - samplers" << samplers;
qDebug() << " - textures" << textures;
}
QDebug operator<<(QDebug debug, const QSGD3D12ShaderLinker::Constant &c)
{
QDebugStateSaver saver(debug);
debug.space();
debug << "size" << c.size;
if (c.specialType != QSGShaderEffectNode::VariableData::None)
debug << "special" << c.specialType;
else
debug << "value" << c.value;
return debug;
}
QSGD3D12ShaderEffectMaterial::QSGD3D12ShaderEffectMaterial(QSGD3D12ShaderEffectNode *node)
: node(node)
{
setFlag(Blending | RequiresFullMatrix, true); // may be changed in sync()
}
QSGD3D12ShaderEffectMaterial::~QSGD3D12ShaderEffectMaterial()
{
delete dummy;
}
struct QSGD3D12ShaderMaterialTypeCache
{
QSGMaterialType *get(const QByteArray &vs, const QByteArray &fs);
void reset() { qDeleteAll(m_types); m_types.clear(); }
struct Key {
QByteArray blob[2];
Key() { }
Key(const QByteArray &vs, const QByteArray &fs) { blob[0] = vs; blob[1] = fs; }
bool operator==(const Key &other) const {
return blob[0] == other.blob[0] && blob[1] == other.blob[1];
}
};
QHash<Key, QSGMaterialType *> m_types;
};
uint qHash(const QSGD3D12ShaderMaterialTypeCache::Key &key, uint seed = 0)
{
uint hash = seed;
for (int i = 0; i < 2; ++i)
hash = hash * 31337 + qHash(key.blob[i]);
return hash;
}
QSGMaterialType *QSGD3D12ShaderMaterialTypeCache::get(const QByteArray &vs, const QByteArray &fs)
{
const Key k(vs, fs);
if (m_types.contains(k))
return m_types.value(k);
QSGMaterialType *t = new QSGMaterialType;
m_types.insert(k, t);
return t;
}
Q_GLOBAL_STATIC(QSGD3D12ShaderMaterialTypeCache, shaderMaterialTypeCache)
void QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache()
{
shaderMaterialTypeCache()->reset();
}
QSGMaterialType *QSGD3D12ShaderEffectMaterial::type() const
{
return mtype;
}
static bool hasAtlasTexture(const QVector<QSGTextureProvider *> &textureProviders)
{
for (int i = 0; i < textureProviders.count(); ++i) {
QSGTextureProvider *t = textureProviders.at(i);
if (t && t->texture() && t->texture()->isAtlasTexture())
return true;
}
return false;
}
int QSGD3D12ShaderEffectMaterial::compare(const QSGMaterial *other) const
{
Q_ASSERT(other && type() == other->type());
const QSGD3D12ShaderEffectMaterial *o = static_cast<const QSGD3D12ShaderEffectMaterial *>(other);
if (int diff = cullMode - o->cullMode)
return diff;
if (int diff = textureProviders.count() - o->textureProviders.count())
return diff;
if (linker.constants != o->linker.constants)
return 1;
if ((hasAtlasTexture(textureProviders) && !geometryUsesTextureSubRect)
|| (hasAtlasTexture(o->textureProviders) && !o->geometryUsesTextureSubRect))
return 1;
for (int i = 0; i < textureProviders.count(); ++i) {
QSGTextureProvider *tp1 = textureProviders.at(i);
QSGTextureProvider *tp2 = o->textureProviders.at(i);
if (!tp1 || !tp2)
return tp1 == tp2 ? 0 : 1;
QSGTexture *t1 = tp1->texture();
QSGTexture *t2 = tp2->texture();
if (!t1 || !t2)
return t1 == t2 ? 0 : 1;
if (int diff = t1->textureId() - t2->textureId())
return diff;
}
return 0;
}
int QSGD3D12ShaderEffectMaterial::constantBufferSize() const
{
return QSGD3D12Engine::alignedConstantBufferSize(linker.constantBufferSize);
}
void QSGD3D12ShaderEffectMaterial::preparePipeline(QSGD3D12PipelineState *pipelineState)
{
pipelineState->shaders.vs = reinterpret_cast<const quint8 *>(linker.vs.constData());
pipelineState->shaders.vsSize = linker.vs.size();
pipelineState->shaders.ps = reinterpret_cast<const quint8 *>(linker.fs.constData());
pipelineState->shaders.psSize = linker.fs.size();
pipelineState->shaders.rootSig.textureViewCount = textureProviders.count();
}
static inline QColor qsg_premultiply_color(const QColor &c)
{
return QColor::fromRgbF(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF());
}
QSGD3D12Material::UpdateResults QSGD3D12ShaderEffectMaterial::updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *,
quint8 *constantBuffer)
{
QSGD3D12Material::UpdateResults r = 0;
quint8 *p = constantBuffer;
for (auto it = linker.constants.constBegin(), itEnd = linker.constants.constEnd(); it != itEnd; ++it) {
quint8 *dst = p + it.key();
const QSGD3D12ShaderLinker::Constant &c(it.value());
if (c.specialType == QSGShaderEffectNode::VariableData::Opacity) {
if (state.isOpacityDirty()) {
const float f = state.opacity();
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, &f, sizeof(f));
r |= UpdatedConstantBuffer;
}
} else if (c.specialType == QSGShaderEffectNode::VariableData::Matrix) {
if (state.isMatrixDirty()) {
const int sz = 16 * sizeof(float);
Q_ASSERT(sz == c.size);
memcpy(dst, state.combinedMatrix().constData(), sz);
r |= UpdatedConstantBuffer;
}
} else if (c.specialType == QSGShaderEffectNode::VariableData::SubRect) {
// float4
QRectF subRect(0, 0, 1, 1);
int srcBindPoint = c.value.toInt(); // filled in by linkTextureSubRects
if (QSGTexture *t = textureProviders.at(srcBindPoint)->texture())
subRect = t->normalizedTextureSubRect();
const float f[4] = { float(subRect.x()), float(subRect.y()),
float(subRect.width()), float(subRect.height()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
} else if (c.specialType == QSGShaderEffectNode::VariableData::None) {
r |= UpdatedConstantBuffer;
switch (c.value.type()) {
case QMetaType::QColor: {
const QColor v = qsg_premultiply_color(qvariant_cast<QColor>(c.value));
const float f[4] = { float(v.redF()), float(v.greenF()), float(v.blueF()), float(v.alphaF()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::Float: {
const float f = qvariant_cast<float>(c.value);
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, &f, sizeof(f));
break;
}
case QMetaType::Double: {
const float f = float(qvariant_cast<double>(c.value));
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, &f, sizeof(f));
break;
}
case QMetaType::Int: {
const int i = c.value.toInt();
Q_ASSERT(sizeof(i) == c.size);
memcpy(dst, &i, sizeof(i));
break;
}
case QMetaType::Bool: {
const bool b = c.value.toBool();
Q_ASSERT(sizeof(b) == c.size);
memcpy(dst, &b, sizeof(b));
break;
}
case QMetaType::QTransform: { // float3x3
const QTransform v = qvariant_cast<QTransform>(c.value);
const float m[3][3] = {
{ float(v.m11()), float(v.m12()), float(v.m13()) },
{ float(v.m21()), float(v.m22()), float(v.m23()) },
{ float(v.m31()), float(v.m32()), float(v.m33()) }
};
Q_ASSERT(sizeof(m) == c.size);
memcpy(dst, m[0], sizeof(m));
break;
}
case QMetaType::QSize:
case QMetaType::QSizeF: { // float2
const QSizeF v = c.value.toSizeF();
const float f[2] = { float(v.width()), float(v.height()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::QPoint:
case QMetaType::QPointF: { // float2
const QPointF v = c.value.toPointF();
const float f[2] = { float(v.x()), float(v.y()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::QRect:
case QMetaType::QRectF: { // float4
const QRectF v = c.value.toRectF();
const float f[4] = { float(v.x()), float(v.y()), float(v.width()), float(v.height()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::QVector2D: { // float2
const QVector2D v = qvariant_cast<QVector2D>(c.value);
const float f[2] = { float(v.x()), float(v.y()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::QVector3D: { // float3
const QVector3D v = qvariant_cast<QVector3D>(c.value);
const float f[3] = { float(v.x()), float(v.y()), float(v.z()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::QVector4D: { // float4
const QVector4D v = qvariant_cast<QVector4D>(c.value);
const float f[4] = { float(v.x()), float(v.y()), float(v.z()), float(v.w()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::QQuaternion: { // float4
const QQuaternion v = qvariant_cast<QQuaternion>(c.value);
const float f[4] = { float(v.x()), float(v.y()), float(v.z()), float(v.scalar()) };
Q_ASSERT(sizeof(f) == c.size);
memcpy(dst, f, sizeof(f));
break;
}
case QMetaType::QMatrix4x4: { // float4x4
const QMatrix4x4 v = qvariant_cast<QMatrix4x4>(c.value);
const int sz = 16 * sizeof(float);
Q_ASSERT(sz == c.size);
memcpy(dst, v.constData(), sz);
break;
}
default:
break;
}
}
}
for (int i = 0; i < textureProviders.count(); ++i) {
QSGTextureProvider *tp = textureProviders[i];
QSGD3D12TextureView &tv(pipelineState->shaders.rootSig.textureViews[i]);
if (tp) {
if (QSGTexture *t = tp->texture()) {
if (t->isAtlasTexture() && !geometryUsesTextureSubRect) {
QSGTexture *newTexture = t->removedFromAtlas();
if (newTexture)
t = newTexture;
}
tv.filter = t->filtering() == QSGTexture::Linear
? QSGD3D12TextureView::FilterLinear : QSGD3D12TextureView::FilterNearest;
tv.addressModeHoriz = t->horizontalWrapMode() == QSGTexture::ClampToEdge
? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap;
tv.addressModeVert = t->verticalWrapMode() == QSGTexture::ClampToEdge
? QSGD3D12TextureView::AddressClamp : QSGD3D12TextureView::AddressWrap;
t->bind();
continue;
}
}
if (!dummy) {
dummy = new QSGD3D12Texture(node->renderContext()->engine());
QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
img.fill(0);
dummy->create(img, QSGRenderContext::CreateTexture_Alpha);
}
tv.filter = QSGD3D12TextureView::FilterNearest;
tv.addressModeHoriz = QSGD3D12TextureView::AddressWrap;
tv.addressModeVert = QSGD3D12TextureView::AddressWrap;
dummy->bind();
}
switch (cullMode) {
case QSGShaderEffectNode::FrontFaceCulling:
pipelineState->cullMode = QSGD3D12PipelineState::CullFront;
break;
case QSGShaderEffectNode::BackFaceCulling:
pipelineState->cullMode = QSGD3D12PipelineState::CullBack;
break;
default:
pipelineState->cullMode = QSGD3D12PipelineState::CullNone;
break;
}
return r;
}
void QSGD3D12ShaderEffectMaterial::updateTextureProviders(bool layoutChange)
{
if (layoutChange) {
for (QSGTextureProvider *tp : textureProviders) {
if (tp) {
QObject::disconnect(tp, SIGNAL(textureChanged()), node,
SLOT(handleTextureChange()));
QObject::disconnect(tp, SIGNAL(destroyed(QObject*)), node,
SLOT(handleTextureProviderDestroyed(QObject*)));
}
}
textureProviders.fill(nullptr, linker.textures.count());
}
for (auto it = linker.textures.constBegin(), itEnd = linker.textures.constEnd(); it != itEnd; ++it) {
const int bindPoint = it.key();
// Now that the linker has merged the textures, we can switch over to a
// simple vector indexed by the binding point for textureProviders.
Q_ASSERT(bindPoint >= 0 && bindPoint < textureProviders.count());
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(it.value()));
QSGTextureProvider *newProvider = source && source->isTextureProvider() ? source->textureProvider() : nullptr;
QSGTextureProvider *&activeProvider(textureProviders[bindPoint]);
if (newProvider != activeProvider) {
if (activeProvider) {
QObject::disconnect(activeProvider, SIGNAL(textureChanged()), node,
SLOT(handleTextureChange()));
QObject::disconnect(activeProvider, SIGNAL(destroyed(QObject*)), node,
SLOT(handleTextureProviderDestroyed(QObject*)));
}
if (newProvider) {
Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
"QSGD3D12ShaderEffectMaterial::updateTextureProviders",
"Texture provider must belong to the rendering thread");
QObject::connect(newProvider, SIGNAL(textureChanged()), node, SLOT(handleTextureChange()));
QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), node,
SLOT(handleTextureProviderDestroyed(QObject*)));
} else {
const char *typeName = source ? source->metaObject()->className() : it.value().typeName();
qWarning("ShaderEffect: Texture t%d is not assigned a valid texture provider (%s).",
bindPoint, typeName);
}
activeProvider = newProvider;
}
}
}
QSGD3D12ShaderEffectNode::QSGD3D12ShaderEffectNode(QSGD3D12RenderContext *rc, QSGD3D12GuiThreadShaderEffectManager *mgr)
: QSGShaderEffectNode(mgr),
m_rc(rc),
m_mgr(mgr),
m_material(this)
{
setFlag(UsePreprocess, true);
setMaterial(&m_material);
}
QRectF QSGD3D12ShaderEffectNode::updateNormalizedTextureSubRect(bool supportsAtlasTextures)
{
QRectF srcRect(0, 0, 1, 1);
bool geometryUsesTextureSubRect = false;
if (supportsAtlasTextures && m_material.textureProviders.count() == 1) {
QSGTextureProvider *provider = m_material.textureProviders.at(0);
if (provider->texture()) {
srcRect = provider->texture()->normalizedTextureSubRect();
geometryUsesTextureSubRect = true;
}
}
if (m_material.geometryUsesTextureSubRect != geometryUsesTextureSubRect) {
m_material.geometryUsesTextureSubRect = geometryUsesTextureSubRect;
markDirty(QSGNode::DirtyMaterial);
}
return srcRect;
}
void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData)
{
if (Q_UNLIKELY(debug_render()))
qDebug() << "shadereffect node sync" << syncData->dirty;
if (bool(m_material.flags() & QSGMaterial::Blending) != syncData->blending) {
m_material.setFlag(QSGMaterial::Blending, syncData->blending);
markDirty(QSGNode::DirtyMaterial);
}
if (m_material.cullMode != syncData->cullMode) {
m_material.cullMode = syncData->cullMode;
markDirty(QSGNode::DirtyMaterial);
}
if (syncData->dirty & QSGShaderEffectNode::DirtyShaders) {
QByteArray vertBlob, fragBlob;
m_material.hasCustomVertexShader = syncData->vertex.shader->hasShaderCode;
if (m_material.hasCustomVertexShader) {
vertBlob = syncData->vertex.shader->shaderInfo.blob;
} else {
vertBlob = QByteArray::fromRawData(reinterpret_cast<const char *>(g_VS_DefaultShaderEffect),
sizeof(g_VS_DefaultShaderEffect));
}
m_material.hasCustomFragmentShader = syncData->fragment.shader->hasShaderCode;
if (m_material.hasCustomFragmentShader) {
fragBlob = syncData->fragment.shader->shaderInfo.blob;
} else {
fragBlob = QByteArray::fromRawData(reinterpret_cast<const char *>(g_PS_DefaultShaderEffect),
sizeof(g_PS_DefaultShaderEffect));
}
m_material.mtype = shaderMaterialTypeCache()->get(vertBlob, fragBlob);
m_material.linker.reset(vertBlob, fragBlob);
if (m_material.hasCustomVertexShader) {
m_material.linker.feedVertexInput(*syncData->vertex.shader);
m_material.linker.feedConstants(*syncData->vertex.shader);
} else {
QSGShaderEffectNode::ShaderData defaultSD;
defaultSD.shaderInfo.blob = vertBlob;
defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex;
QSGGuiThreadShaderEffectManager::ShaderInfo::InputParameter ip;
ip.semanticName = QByteArrayLiteral("POSITION");
defaultSD.shaderInfo.inputParameters.append(ip);
ip.semanticName = QByteArrayLiteral("TEXCOORD");
defaultSD.shaderInfo.inputParameters.append(ip);
// { float4x4 qt_Matrix; float qt_Opacity; } where only the matrix is used
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("qt_Matrix");
v.offset = 0;
v.size = 16 * sizeof(float);
defaultSD.shaderInfo.variables.append(v);
QSGShaderEffectNode::VariableData vd;
vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
defaultSD.varData.append(vd);
defaultSD.shaderInfo.constantDataSize = (16 + 1) * sizeof(float);
m_material.linker.feedVertexInput(defaultSD);
m_material.linker.feedConstants(defaultSD);
}
m_material.linker.feedSamplers(*syncData->vertex.shader);
m_material.linker.feedTextures(*syncData->vertex.shader);
if (m_material.hasCustomFragmentShader) {
m_material.linker.feedConstants(*syncData->fragment.shader);
} else {
QSGShaderEffectNode::ShaderData defaultSD;
defaultSD.shaderInfo.blob = fragBlob;
defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
// { float4x4 qt_Matrix; float qt_Opacity; } where only the opacity is used
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("qt_Opacity");
v.offset = 16 * sizeof(float);
v.size = sizeof(float);
defaultSD.shaderInfo.variables.append(v);
QSGShaderEffectNode::VariableData vd;
vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
defaultSD.varData.append(vd);
v.name = QByteArrayLiteral("source");
v.bindPoint = 0;
v.type = QSGGuiThreadShaderEffectManager::ShaderInfo::Texture;
defaultSD.shaderInfo.variables.append(v);
vd.specialType = QSGShaderEffectNode::VariableData::Source;
defaultSD.varData.append(vd);
v.name = QByteArrayLiteral("sourceSampler");
v.bindPoint = 0;
v.type = QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
defaultSD.shaderInfo.variables.append(v);
vd.specialType = QSGShaderEffectNode::VariableData::Unused;
defaultSD.varData.append(vd);
defaultSD.shaderInfo.constantDataSize = (16 + 1) * sizeof(float);
m_material.linker.feedConstants(defaultSD);
m_material.linker.feedSamplers(defaultSD);
m_material.linker.feedTextures(defaultSD);
}
// While this may seem unnecessary for the built-in shaders, the value
// of 'source' is still in there and we have to process it.
m_material.linker.feedSamplers(*syncData->fragment.shader);
m_material.linker.feedTextures(*syncData->fragment.shader);
m_material.linker.linkTextureSubRects();
m_material.updateTextureProviders(true);
markDirty(QSGNode::DirtyMaterial);
if (Q_UNLIKELY(debug_render()))
m_material.linker.dump();
} else {
if (syncData->dirty & QSGShaderEffectNode::DirtyShaderConstant) {
if (!syncData->vertex.dirtyConstants->isEmpty())
m_material.linker.feedConstants(*syncData->vertex.shader, syncData->vertex.dirtyConstants);
if (!syncData->fragment.dirtyConstants->isEmpty())
m_material.linker.feedConstants(*syncData->fragment.shader, syncData->fragment.dirtyConstants);
markDirty(QSGNode::DirtyMaterial);
if (Q_UNLIKELY(debug_render()))
m_material.linker.dump();
}
if (syncData->dirty & QSGShaderEffectNode::DirtyShaderTexture) {
if (!syncData->vertex.dirtyTextures->isEmpty())
m_material.linker.feedTextures(*syncData->vertex.shader, syncData->vertex.dirtyTextures);
if (!syncData->fragment.dirtyTextures->isEmpty())
m_material.linker.feedTextures(*syncData->fragment.shader, syncData->fragment.dirtyTextures);
m_material.linker.linkTextureSubRects();
m_material.updateTextureProviders(false);
markDirty(QSGNode::DirtyMaterial);
if (Q_UNLIKELY(debug_render()))
m_material.linker.dump();
}
}
if (bool(m_material.flags() & QSGMaterial::RequiresFullMatrix) != m_material.hasCustomVertexShader) {
m_material.setFlag(QSGMaterial::RequiresFullMatrix, m_material.hasCustomVertexShader);
markDirty(QSGNode::DirtyMaterial);
}
}
void QSGD3D12ShaderEffectNode::handleTextureChange()
{
markDirty(QSGNode::DirtyMaterial);
emit m_mgr->textureChanged();
}
void QSGD3D12ShaderEffectNode::handleTextureProviderDestroyed(QObject *object)
{
for (QSGTextureProvider *&tp : m_material.textureProviders) {
if (tp == object)
tp = nullptr;
}
}
void QSGD3D12ShaderEffectNode::preprocess()
{
for (QSGTextureProvider *tp : m_material.textureProviders) {
if (tp) {
if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(tp->texture()))
texture->updateTexture();
}
}
}
bool QSGD3D12GuiThreadShaderEffectManager::hasSeparateSamplerAndTextureObjects() const
{
return true;
}
QString QSGD3D12GuiThreadShaderEffectManager::log() const
{
return QString();
}
QSGGuiThreadShaderEffectManager::Status QSGD3D12GuiThreadShaderEffectManager::status() const
{
return Compiled;
}
struct RefGuard {
RefGuard(IUnknown *p) : p(p) { }
~RefGuard() { p->Release(); }
IUnknown *p;
};
bool QSGD3D12GuiThreadShaderEffectManager::reflect(const QByteArray &src, ShaderInfo *result)
{
const QString fn = QQmlFile::urlToLocalFileOrQrc(src);
QFile f(fn);
if (!f.open(QIODevice::ReadOnly)) {
qWarning("ShaderEffect: Failed to read %s", qPrintable(fn));
return false;
}
result->blob = f.readAll();
f.close();
ID3D12ShaderReflection *reflector;
HRESULT hr = D3DReflect(result->blob.constData(), result->blob.size(), IID_PPV_ARGS(&reflector));
if (FAILED(hr)) {
qWarning("D3D shader reflection failed: 0x%x", hr);
return false;
}
RefGuard rg(reflector);
D3D12_SHADER_DESC shaderDesc;
reflector->GetDesc(&shaderDesc);
const uint progType = (shaderDesc.Version & 0xFFFF0000) >> 16;
const uint major = (shaderDesc.Version & 0x000000F0) >> 4;
const uint minor = (shaderDesc.Version & 0x0000000F);
switch (progType) {
case D3D12_SHVER_VERTEX_SHADER:
result->type = ShaderInfo::TypeVertex;
break;
case D3D12_SHVER_PIXEL_SHADER:
result->type = ShaderInfo::TypeFragment;
break;
default:
result->type = ShaderInfo::TypeOther;
qWarning("D3D shader is of unknown type 0x%x", shaderDesc.Version);
return false;
}
if (major < 5) {
qWarning("D3D shader model version %u.%u is too low", major, minor);
return false;
}
const int ieCount = shaderDesc.InputParameters;
const int cbufferCount = shaderDesc.ConstantBuffers;
const int boundResCount = shaderDesc.BoundResources;
result->constantDataSize = 0;
if (ieCount < 1) {
qWarning("Invalid shader: Not enough input parameters (%d)", ieCount);
return false;
}
if (cbufferCount < 1) {
qWarning("Invalid shader: Shader has no constant buffers");
return false;
}
if (boundResCount < 1) {
qWarning("Invalid shader: No resources bound. Expected to have at least a constant buffer bound.");
return false;
}
if (Q_UNLIKELY(debug_render()))
qDebug("Shader reflection size %d type %d v%u.%u input elems %d cbuffers %d boundres %d",
result->blob.size(), result->type, major, minor, ieCount, cbufferCount, boundResCount);
for (int i = 0; i < ieCount; ++i) {
D3D12_SIGNATURE_PARAMETER_DESC desc;
if (FAILED(reflector->GetInputParameterDesc(i, &desc))) {
qWarning("D3D reflection: Failed to query input parameter %d", i);
return false;
}
if (desc.SystemValueType != D3D_NAME_UNDEFINED)
continue;
ShaderInfo::InputParameter param;
param.semanticName = QByteArray(desc.SemanticName);
param.semanticIndex = desc.SemanticIndex;
result->inputParameters.append(param);
}
for (int i = 0; i < boundResCount; ++i) {
D3D12_SHADER_INPUT_BIND_DESC desc;
if (FAILED(reflector->GetResourceBindingDesc(i, &desc))) {
qWarning("D3D reflection: Failed to query resource binding %d", i);
continue;
}
bool gotCBuffer = false;
if (desc.Type == D3D_SIT_CBUFFER) {
ID3D12ShaderReflectionConstantBuffer *cbuf = reflector->GetConstantBufferByName(desc.Name);
D3D12_SHADER_BUFFER_DESC bufDesc;
if (FAILED(cbuf->GetDesc(&bufDesc))) {
qWarning("D3D reflection: Failed to query constant buffer description");
continue;
}
if (gotCBuffer) {
qWarning("D3D reflection: Found more than one constant buffers. Only the first one is used.");
continue;
}
gotCBuffer = true;
result->constantDataSize = bufDesc.Size;
for (uint cbIdx = 0; cbIdx < bufDesc.Variables; ++cbIdx) {
ID3D12ShaderReflectionVariable *cvar = cbuf->GetVariableByIndex(cbIdx);
D3D12_SHADER_VARIABLE_DESC varDesc;
if (FAILED(cvar->GetDesc(&varDesc))) {
qWarning("D3D reflection: Failed to query constant buffer variable %d", cbIdx);
return false;
}
// we report the full size of the buffer but only return variables that are actually used by this shader
if (!(varDesc.uFlags & D3D_SVF_USED))
continue;
ShaderInfo::Variable v;
v.type = ShaderInfo::Constant;
v.name = QByteArray(varDesc.Name);
v.offset = varDesc.StartOffset;
v.size = varDesc.Size;
result->variables.append(v);
}
} else if (desc.Type == D3D_SIT_TEXTURE) {
if (desc.Dimension != D3D_SRV_DIMENSION_TEXTURE2D) {
qWarning("D3D reflection: Texture %s is not a 2D texture, ignoring.", qPrintable(desc.Name));
continue;
}
if (desc.NumSamples != (UINT) -1) {
qWarning("D3D reflection: Texture %s is multisample (%u), ignoring.", qPrintable(desc.Name), desc.NumSamples);
continue;
}
if (desc.BindCount != 1) {
qWarning("D3D reflection: Texture %s is an array, ignoring.", qPrintable(desc.Name));
continue;
}
if (desc.Space != 0) {
qWarning("D3D reflection: Texture %s is not using register space 0, ignoring.", qPrintable(desc.Name));
continue;
}
ShaderInfo::Variable v;
v.type = ShaderInfo::Texture;
v.name = QByteArray(desc.Name);
v.bindPoint = desc.BindPoint;
result->variables.append(v);
} else if (desc.Type == D3D_SIT_SAMPLER) {
if (desc.BindCount != 1) {
qWarning("D3D reflection: Sampler %s is an array, ignoring.", qPrintable(desc.Name));
continue;
}
if (desc.Space != 0) {
qWarning("D3D reflection: Sampler %s is not using register space 0, ignoring.", qPrintable(desc.Name));
continue;
}
ShaderInfo::Variable v;
v.type = ShaderInfo::Sampler;
v.name = QByteArray(desc.Name);
v.bindPoint = desc.BindPoint;
result->variables.append(v);
} else {
qWarning("D3D reflection: Resource binding %d has an unknown type of %d and will be ignored.", i, desc.Type);
continue;
}
}
if (Q_UNLIKELY(debug_render())) {
qDebug() << "Input:" << result->inputParameters;
qDebug() << "Variables:" << result->variables << "cbuffer size" << result->constantDataSize;
}
return true;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,168 @@
/****************************************************************************
**
** 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 QSGD3D12SHADEREFFECTNODE_P_H
#define QSGD3D12SHADEREFFECTNODE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qsgadaptationlayer_p.h>
#include "qsgd3d12material_p.h"
QT_BEGIN_NAMESPACE
class QSGD3D12RenderContext;
class QSGD3D12GuiThreadShaderEffectManager;
class QSGD3D12ShaderEffectNode;
class QSGD3D12Texture;
class QSGD3D12ShaderLinker
{
public:
void reset(const QByteArray &vertBlob, const QByteArray &fragBlob);
void feedVertexInput(const QSGShaderEffectNode::ShaderData &shader);
void feedConstants(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices = nullptr);
void feedSamplers(const QSGShaderEffectNode::ShaderData &shader);
void feedTextures(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices = nullptr);
void linkTextureSubRects();
void dump();
struct Constant {
uint size;
QSGShaderEffectNode::VariableData::SpecialType specialType;
QVariant value;
bool operator==(const Constant &other) const {
return size == other.size && specialType == other.specialType
&& (specialType == QSGShaderEffectNode::VariableData::None ? value == other.value : true);
}
};
bool error;
QByteArray vs;
QByteArray fs;
uint constantBufferSize;
QHash<uint, Constant> constants; // offset -> Constant
QSet<int> samplers; // bindpoint
QHash<int, QVariant> textures; // bindpoint -> value (source ref)
QHash<QByteArray, int> textureNameMap; // name -> bindpoint
};
QDebug operator<<(QDebug debug, const QSGD3D12ShaderLinker::Constant &c);
class QSGD3D12ShaderEffectMaterial : public QSGD3D12Material
{
public:
QSGD3D12ShaderEffectMaterial(QSGD3D12ShaderEffectNode *node);
~QSGD3D12ShaderEffectMaterial();
QSGMaterialType *type() const override;
int compare(const QSGMaterial *other) const override;
int constantBufferSize() const override;
void preparePipeline(QSGD3D12PipelineState *pipelineState) override;
UpdateResults updatePipeline(const QSGD3D12MaterialRenderState &state,
QSGD3D12PipelineState *pipelineState,
ExtraState *extraState,
quint8 *constantBuffer) override;
void updateTextureProviders(bool layoutChange);
QSGD3D12ShaderEffectNode *node;
bool valid = false;
QSGShaderEffectNode::CullMode cullMode = QSGShaderEffectNode::NoCulling;
bool hasCustomVertexShader = false;
bool hasCustomFragmentShader = false;
QSGD3D12ShaderLinker linker;
QSGMaterialType *mtype = nullptr;
QVector<QSGTextureProvider *> textureProviders;
QSGD3D12Texture *dummy = nullptr;
bool geometryUsesTextureSubRect = false;
};
class QSGD3D12ShaderEffectNode : public QObject, public QSGShaderEffectNode
{
Q_OBJECT
public:
QSGD3D12ShaderEffectNode(QSGD3D12RenderContext *rc, QSGD3D12GuiThreadShaderEffectManager *mgr);
QRectF updateNormalizedTextureSubRect(bool supportsAtlasTextures) override;
void syncMaterial(SyncData *syncData) override;
static void cleanupMaterialTypeCache();
void preprocess() override;
QSGD3D12RenderContext *renderContext() { return m_rc; }
private Q_SLOTS:
void handleTextureChange();
void handleTextureProviderDestroyed(QObject *object);
private:
QSGD3D12RenderContext *m_rc;
QSGD3D12GuiThreadShaderEffectManager *m_mgr;
QSGD3D12ShaderEffectMaterial m_material;
};
class QSGD3D12GuiThreadShaderEffectManager : public QSGGuiThreadShaderEffectManager
{
public:
bool hasSeparateSamplerAndTextureObjects() const override;
QString log() const override;
Status status() const override;
bool reflect(const QByteArray &src, ShaderInfo *result) override;
};
QT_END_NAMESPACE
#endif // QSGD3D12SHADEREFFECTNODE_P_H

View File

@ -0,0 +1,139 @@
/****************************************************************************
**
** 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 "qsgd3d12texture_p.h"
#include "qsgd3d12engine_p.h"
#include <private/qsgcontext_p.h>
QT_BEGIN_NAMESPACE
#define RETAIN_IMAGE
void QSGD3D12Texture::create(const QImage &image, uint flags)
{
// ### atlas?
const bool alphaRequest = flags & QSGRenderContext::CreateTexture_Alpha;
m_alphaWanted = alphaRequest && image.hasAlphaChannel();
m_image = image;
m_id = m_engine->genTexture();
Q_ASSERT(m_id);
// We could kick off the texture creation and the async upload right here.
// Unfortunately we cannot tell at this stage if mipmaps will be enabled
// via an Image element's mipmap property...so defer to bind().
m_createPending = true;
}
QSGD3D12Texture::~QSGD3D12Texture()
{
if (m_id)
m_engine->releaseTexture(m_id);
}
int QSGD3D12Texture::textureId() const
{
return m_id;
}
QSize QSGD3D12Texture::textureSize() const
{
return m_image.size();
}
bool QSGD3D12Texture::hasAlphaChannel() const
{
return m_alphaWanted;
}
bool QSGD3D12Texture::hasMipmaps() const
{
return mipmapFiltering() != QSGTexture::None;
}
QRectF QSGD3D12Texture::normalizedTextureSubRect() const
{
return QRectF(0, 0, 1, 1);
}
void QSGD3D12Texture::bind()
{
// Called when the texture material updates the pipeline state.
if (!m_createPending && hasMipmaps() != m_createdWithMipMaps) {
#ifdef RETAIN_IMAGE
m_engine->releaseTexture(m_id);
m_id = m_engine->genTexture();
Q_ASSERT(m_id);
m_createPending = true;
#else
// ### this can be made working some day (something similar to
// queueTextureResize) but skip for now
qWarning("D3D12: mipmap property cannot be changed once the texture is created");
#endif
}
if (m_createPending) {
m_createPending = false;
QSGD3D12Engine::TextureCreateFlags createFlags = 0;
if (m_alphaWanted)
createFlags |= QSGD3D12Engine::TextureWithAlpha;
m_createdWithMipMaps = hasMipmaps();
if (m_createdWithMipMaps)
createFlags |= QSGD3D12Engine::TextureWithMipMaps;
m_engine->createTexture(m_id, m_image.size(), m_image.format(), createFlags);
m_engine->queueTextureUpload(m_id, m_image);
#ifndef RETAIN_IMAGE
m_image = QImage();
#endif
}
// Here we know that the texture is going to be used in the current frame
// by the next draw call. Notify the engine so that it can wait for
// possible pending uploads and set up the pipeline accordingly.
m_engine->useTexture(m_id);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,87 @@
/****************************************************************************
**
** 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 QSGD3D12TEXTURE_P_H
#define QSGD3D12TEXTURE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <qsgtexture.h>
#include <basetsd.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
class QSGD3D12Texture : public QSGTexture
{
public:
QSGD3D12Texture(QSGD3D12Engine *engine) : m_engine(engine) { }
~QSGD3D12Texture();
void create(const QImage &image, uint flags);
int textureId() const override;
QSize textureSize() const override;
bool hasAlphaChannel() const override;
bool hasMipmaps() const override;
QRectF normalizedTextureSubRect() const override;
void bind() override;
protected:
QSGD3D12Engine *m_engine;
QImage m_image;
bool m_createPending = false;
bool m_createdWithMipMaps = false;
uint m_id = 0;
bool m_alphaWanted = false;
};
QT_END_NAMESPACE
#endif

View File

@ -0,0 +1,60 @@
static const uint GROUP_DIM = 8; // 2 ^ (out_mip_count - 1)
Texture2D tex : register(t0);
SamplerState samp : register(s0);
cbuffer ConstantBuffer : register(b0)
{
uint2 mip1Size;
uint sampleLevel;
uint totalMips;
}
RWTexture2D<float4> mip1 : register(u0);
RWTexture2D<float4> mip2 : register(u1);
RWTexture2D<float4> mip3 : register(u2);
RWTexture2D<float4> mip4 : register(u3);
groupshared float4 groupColor[GROUP_DIM][GROUP_DIM];
[numthreads(GROUP_DIM, GROUP_DIM, 1)]
void CS_Generate4MipMaps(uint3 localId: SV_GroupThreadId, uint3 globalId: SV_DispatchThreadID)
{
const float2 coord = float2(1.0f / float(mip1Size.x), 1.0f / float(mip1Size.y)) * (globalId.xy + 0.5);
float4 c = tex.SampleLevel(samp, coord, sampleLevel);
mip1[globalId.xy] = c;
groupColor[localId.y][localId.x] = c;
if (sampleLevel + 1 >= totalMips)
return;
GroupMemoryBarrierWithGroupSync();
if ((localId.x & 1) == 0 && (localId.y & 1) == 0) {
c = (c + groupColor[localId.y][localId.x + 1] + groupColor[localId.y + 1][localId.x] + groupColor[localId.y + 1][localId.x + 1]) / 4.0;
mip2[globalId.xy / 2] = c;
groupColor[localId.y][localId.x] = c;
}
if (sampleLevel + 2 >= totalMips)
return;
GroupMemoryBarrierWithGroupSync();
if ((localId.x & 3) == 0 && (localId.y & 3) == 0) {
c = (c + groupColor[localId.y][localId.x + 2] + groupColor[localId.y + 2][localId.x] + groupColor[localId.y + 2][localId.x + 2]) / 4.0;
mip3[globalId.xy / 4] = c;
groupColor[localId.y][localId.x] = c;
}
if (sampleLevel + 3 >= totalMips)
return;
GroupMemoryBarrierWithGroupSync();
if ((localId.x & 7) == 0 && (localId.y & 7) == 0) {
c = (c + groupColor[localId.y][localId.x + 3] + groupColor[localId.y + 3][localId.x] + groupColor[localId.y + 3][localId.x + 3]) / 4.0;
mip4[globalId.xy / 8] = c;
}
}

View File

@ -0,0 +1,27 @@
cbuffer ConstantBuffer : register(b0)
{
float4x4 qt_Matrix;
float qt_Opacity;
};
struct PSInput
{
float4 position : SV_POSITION;
float2 coord : TEXCOORD0;
};
Texture2D source : register(t0);
SamplerState sourceSampler : register(s0);
PSInput VS_DefaultShaderEffect(float4 position : POSITION, float2 coord : TEXCOORD0)
{
PSInput result;
result.position = mul(qt_Matrix, position);
result.coord = coord;
return result;
}
float4 PS_DefaultShaderEffect(PSInput input) : SV_TARGET
{
return source.Sample(sourceSampler, input.coord) * qt_Opacity;
}

View File

@ -0,0 +1,119 @@
vertexcolor_VSPS = $$PWD/vertexcolor.hlsl
vertexcolor_vshader.input = vertexcolor_VSPS
vertexcolor_vshader.header = vs_vertexcolor.hlslh
vertexcolor_vshader.entry = VS_VertexColor
vertexcolor_vshader.type = vs_5_0
vertexcolor_pshader.input = vertexcolor_VSPS
vertexcolor_pshader.header = ps_vertexcolor.hlslh
vertexcolor_pshader.entry = PS_VertexColor
vertexcolor_pshader.type = ps_5_0
stencilclip_VSPS = $$PWD/stencilclip.hlsl
stencilclip_vshader.input = stencilclip_VSPS
stencilclip_vshader.header = vs_stencilclip.hlslh
stencilclip_vshader.entry = VS_StencilClip
stencilclip_vshader.type = vs_5_0
stencilclip_pshader.input = stencilclip_VSPS
stencilclip_pshader.header = ps_stencilclip.hlslh
stencilclip_pshader.entry = PS_StencilClip
stencilclip_pshader.type = ps_5_0
smoothcolor_VSPS = $$PWD/smoothcolor.hlsl
smoothcolor_vshader.input = smoothcolor_VSPS
smoothcolor_vshader.header = vs_smoothcolor.hlslh
smoothcolor_vshader.entry = VS_SmoothColor
smoothcolor_vshader.type = vs_5_0
smoothcolor_pshader.input = smoothcolor_VSPS
smoothcolor_pshader.header = ps_smoothcolor.hlslh
smoothcolor_pshader.entry = PS_SmoothColor
smoothcolor_pshader.type = ps_5_0
texture_VSPS = $$PWD/texture.hlsl
texture_vshader.input = texture_VSPS
texture_vshader.header = vs_texture.hlslh
texture_vshader.entry = VS_Texture
texture_vshader.type = vs_5_0
texture_pshader.input = texture_VSPS
texture_pshader.header = ps_texture.hlslh
texture_pshader.entry = PS_Texture
texture_pshader.type = ps_5_0
smoothtexture_VSPS = $$PWD/smoothtexture.hlsl
smoothtexture_vshader.input = smoothtexture_VSPS
smoothtexture_vshader.header = vs_smoothtexture.hlslh
smoothtexture_vshader.entry = VS_SmoothTexture
smoothtexture_vshader.type = vs_5_0
smoothtexture_pshader.input = smoothtexture_VSPS
smoothtexture_pshader.header = ps_smoothtexture.hlslh
smoothtexture_pshader.entry = PS_SmoothTexture
smoothtexture_pshader.type = ps_5_0
mipmapgen_CS = $$PWD/mipmapgen.hlsl
mipmapgen_cshader.input = mipmapgen_CS
mipmapgen_cshader.header = cs_mipmapgen.hlslh
mipmapgen_cshader.entry = CS_Generate4MipMaps
mipmapgen_cshader.type = cs_5_0
textmask_VSPS = $$PWD/textmask.hlsl
textmask_vshader.input = textmask_VSPS
textmask_vshader.header = vs_textmask.hlslh
textmask_vshader.entry = VS_TextMask
textmask_vshader.type = vs_5_0
textmask_pshader24.input = textmask_VSPS
textmask_pshader24.header = ps_textmask24.hlslh
textmask_pshader24.entry = PS_TextMask24
textmask_pshader24.type = ps_5_0
textmask_pshader32.input = textmask_VSPS
textmask_pshader32.header = ps_textmask32.hlslh
textmask_pshader32.entry = PS_TextMask32
textmask_pshader32.type = ps_5_0
textmask_pshader8.input = textmask_VSPS
textmask_pshader8.header = ps_textmask8.hlslh
textmask_pshader8.entry = PS_TextMask8
textmask_pshader8.type = ps_5_0
styledtext_vshader.input = textmask_VSPS
styledtext_vshader.header = vs_styledtext.hlslh
styledtext_vshader.entry = VS_StyledText
styledtext_vshader.type = vs_5_0
styledtext_pshader.input = textmask_VSPS
styledtext_pshader.header = ps_styledtext.hlslh
styledtext_pshader.entry = PS_StyledText
styledtext_pshader.type = ps_5_0
outlinedtext_vshader.input = textmask_VSPS
outlinedtext_vshader.header = vs_outlinedtext.hlslh
outlinedtext_vshader.entry = VS_OutlinedText
outlinedtext_vshader.type = vs_5_0
outlinedtext_pshader.input = textmask_VSPS
outlinedtext_pshader.header = ps_outlinedtext.hlslh
outlinedtext_pshader.entry = PS_OutlinedText
outlinedtext_pshader.type = ps_5_0
shadereffectdefault_VSPS = $$PWD/shadereffectdefault.hlsl
shadereffectdefault_vshader.input = shadereffectdefault_VSPS
shadereffectdefault_vshader.header = vs_shadereffectdefault.hlslh
shadereffectdefault_vshader.entry = VS_DefaultShaderEffect
shadereffectdefault_vshader.type = vs_5_0
shadereffectdefault_pshader.input = shadereffectdefault_VSPS
shadereffectdefault_pshader.header = ps_shadereffectdefault.hlslh
shadereffectdefault_pshader.entry = PS_DefaultShaderEffect
shadereffectdefault_pshader.type = ps_5_0
tdr_CS = $$PWD/tdr.hlsl
tdr_cshader.input = tdr_CS
tdr_cshader.header = cs_tdr.hlslh
tdr_cshader.entry = timeout
tdr_cshader.type = cs_5_0
HLSL_SHADERS = \
vertexcolor_vshader vertexcolor_pshader \
stencilclip_vshader stencilclip_pshader \
smoothcolor_vshader smoothcolor_pshader \
texture_vshader texture_pshader \
smoothtexture_vshader smoothtexture_pshader \
mipmapgen_cshader \
textmask_vshader textmask_pshader24 textmask_pshader32 textmask_pshader8 \
styledtext_vshader styledtext_pshader outlinedtext_vshader outlinedtext_pshader \
shadereffectdefault_vshader shadereffectdefault_pshader \
tdr_cshader
load(hlsl_bytecode_header)

View File

@ -0,0 +1,64 @@
struct VSInput
{
float4 position : POSITION;
float4 color : COLOR;
float2 offset : TEXCOORD0;
};
cbuffer ConstantBuffer : register(b0)
{
float4x4 mvp;
float opacity;
float2 pixelSize;
};
struct PSInput
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
PSInput VS_SmoothColor(VSInput input)
{
PSInput result;
float4 pos = mul(mvp, input.position);
if (input.offset.x != 0.0) {
// In HLSL matrix packing is column-major by default (which is good) but the math is row-major (unlike GLSL).
float4 delta = float4(mvp._11, mvp._21, mvp._31, mvp._41) * input.offset.x;
float2 dir = delta.xy * pos.w - pos.xy * delta.w;
float2 ndir = 0.5 * pixelSize * normalize(dir / pixelSize);
dir -= ndir * delta.w * pos.w;
float numerator = dot(dir, ndir * pos.w * pos.w);
float scale = 0.0;
if (numerator < 0.0)
scale = 1.0;
else
scale = min(1.0, numerator / dot(dir, dir));
pos += scale * delta;
}
if (input.offset.y != 0.0) {
float4 delta = float4(mvp._12, mvp._22, mvp._32, mvp._42) * input.offset.y;
float2 dir = delta.xy * pos.w - pos.xy * delta.w;
float2 ndir = 0.5 * pixelSize * normalize(dir / pixelSize);
dir -= ndir * delta.w * pos.w;
float numerator = dot(dir, ndir * pos.w * pos.w);
float scale = 0.0;
if (numerator < 0.0)
scale = 1.0;
else
scale = min(1.0, numerator / dot(dir, dir));
pos += scale * delta;
}
result.position = pos;
result.color = input.color * opacity;
return result;
}
float4 PS_SmoothColor(PSInput input) : SV_TARGET
{
return input.color;
}

View File

@ -0,0 +1,77 @@
struct VSInput
{
float4 position : POSITION;
float2 coord : TEXCOORD0;
float2 offset : TEXCOORD1;
float2 coordOffset : TEXCOORD2;
};
cbuffer ConstantBuffer : register(b0)
{
float4x4 mvp;
float opacity;
float2 pixelSize;
};
struct PSInput
{
float4 position : SV_POSITION;
float2 coord : TEXCOORD0;
float vertexOpacity : TEXCOORD3;
};
Texture2D tex : register(t0);
SamplerState samp : register(s0);
PSInput VS_SmoothTexture(VSInput input)
{
PSInput result;
float4 pos = mul(mvp, input.position);
float2 coord = input.coord;
if (input.offset.x != 0.0) {
// In HLSL matrix packing is column-major by default (which is good) but the math is row-major (unlike GLSL).
float4 delta = float4(mvp._11, mvp._21, mvp._31, mvp._41) * input.offset.x;
float2 dir = delta.xy * pos.w - pos.xy * delta.w;
float2 ndir = 0.5 * pixelSize * normalize(dir / pixelSize);
dir -= ndir * delta.w * pos.w;
float numerator = dot(dir, ndir * pos.w * pos.w);
float scale = 0.0;
if (numerator < 0.0)
scale = 1.0;
else
scale = min(1.0, numerator / dot(dir, dir));
pos += scale * delta;
coord.x += scale * input.coordOffset.x;
}
if (input.offset.y != 0.0) {
float4 delta = float4(mvp._12, mvp._22, mvp._32, mvp._42) * input.offset.y;
float2 dir = delta.xy * pos.w - pos.xy * delta.w;
float2 ndir = 0.5 * pixelSize * normalize(dir / pixelSize);
dir -= ndir * delta.w * pos.w;
float numerator = dot(dir, ndir * pos.w * pos.w);
float scale = 0.0;
if (numerator < 0.0)
scale = 1.0;
else
scale = min(1.0, numerator / dot(dir, dir));
pos += scale * delta;
coord.y += scale * input.coordOffset.y;
}
if ((input.offset.x != 0.0 || input.offset.y != 0.0) && (input.coordOffset.x == 0.0 && input.coordOffset.y == 0.0))
result.vertexOpacity = 0.0;
else
result.vertexOpacity = opacity;
result.position = pos;
result.coord = coord;
return result;
}
float4 PS_SmoothTexture(PSInput input) : SV_TARGET
{
return tex.Sample(samp, input.coord) * input.vertexOpacity;
}

View File

@ -0,0 +1,26 @@
struct VSInput
{
float4 position : POSITION;
};
cbuffer ConstantBuffer : register(b0)
{
float4x4 mvp;
};
struct PSInput
{
float4 position : SV_POSITION;
};
PSInput VS_StencilClip(VSInput input)
{
PSInput result;
result.position = mul(mvp, input.position);
return result;
}
float4 PS_StencilClip(PSInput input) : SV_TARGET
{
return float4(0.81, 0.83, 0.12, 1.0); // Trolltech green ftw!
}

View File

@ -0,0 +1,11 @@
// http://gamedev.stackexchange.com/questions/108141/how-can-i-test-dxgi-error-device-removed-error-handling
RWBuffer<uint> uav;
cbuffer ConstantBuffer { uint zero; }
[numthreads(256, 1, 1)]
void timeout(uint3 id: SV_DispatchThreadID)
{
while (zero == 0)
uav[id.x] = zero;
}

View File

@ -0,0 +1,104 @@
struct VSInput
{
float4 position : POSITION;
float2 coord : TEXCOORD0;
};
cbuffer ConstantBuffer : register(b0)
{
float4x4 mvp;
float2 textureScale;
float dpr;
float color; // for TextMask24 and 32
float4 colorVec; // for TextMask8 and Styled and Outlined
float2 shift; // for Styled
float4 styleColor; // for Styled and Outlined
};
struct PSInput
{
float4 position : SV_POSITION;
float2 coord : TEXCOORD0;
};
Texture2D tex : register(t0);
SamplerState samp : register(s0);
PSInput VS_TextMask(VSInput input)
{
PSInput result;
result.position = mul(mvp, floor(input.position * dpr + 0.5) / dpr);
result.coord = input.coord * textureScale;
return result;
}
float4 PS_TextMask24(PSInput input) : SV_TARGET
{
float4 glyph = tex.Sample(samp, input.coord);
return float4(glyph.rgb * color, glyph.a);
}
float4 PS_TextMask32(PSInput input) : SV_TARGET
{
return tex.Sample(samp, input.coord) * color;
}
float4 PS_TextMask8(PSInput input) : SV_TARGET
{
return colorVec * tex.Sample(samp, input.coord).r;
}
struct StyledPSInput
{
float4 position : SV_POSITION;
float2 coord : TEXCOORD0;
float2 shiftedCoord : TEXCOORD1;
};
StyledPSInput VS_StyledText(VSInput input)
{
StyledPSInput result;
result.position = mul(mvp, floor(input.position * dpr + 0.5) / dpr);
result.coord = input.coord * textureScale;
result.shiftedCoord = (input.coord - shift) * textureScale;
return result;
}
float4 PS_StyledText(StyledPSInput input) : SV_TARGET
{
float glyph = tex.Sample(samp, input.coord).r;
float style = clamp(tex.Sample(samp, input.shiftedCoord).r - glyph, 0.0, 1.0);
return style * styleColor + glyph * colorVec;
}
struct OutlinedPSInput
{
float4 position : SV_POSITION;
float2 coord : TEXCOORD0;
float2 coordUp : TEXCOORD1;
float2 coordDown : TEXCOORD2;
float2 coordLeft : TEXCOORD3;
float2 coordRight : TEXCOORD4;
};
OutlinedPSInput VS_OutlinedText(VSInput input)
{
OutlinedPSInput result;
result.position = mul(mvp, floor(input.position * dpr + 0.5) / dpr);
result.coord = input.coord * textureScale;
result.coordUp = (input.coord - float2(0.0, -1.0)) * textureScale;
result.coordDown = (input.coord - float2(0.0, 1.0)) * textureScale;
result.coordLeft = (input.coord - float2(-1.0, 0.0)) * textureScale;
result.coordRight = (input.coord - float2(1.0, 0.0)) * textureScale;
return result;
}
float4 PS_OutlinedText(OutlinedPSInput input) : SV_TARGET
{
float glyph = tex.Sample(samp, input.coord).r;
float outline = clamp(clamp(tex.Sample(samp, input.coordUp).r
+ tex.Sample(samp, input.coordDown).r
+ tex.Sample(samp, input.coordLeft).r
+ tex.Sample(samp, input.coordRight).r, 0.0, 1.0) - glyph, 0.0, 1.0);
return outline * styleColor + glyph * colorVec;
}

View File

@ -0,0 +1,33 @@
struct VSInput
{
float4 position : POSITION;
float2 coord : TEXCOORD0;
};
cbuffer ConstantBuffer : register(b0)
{
float4x4 mvp;
float opacity;
};
struct PSInput
{
float4 position : SV_POSITION;
float2 coord : TEXCOORD0;
};
Texture2D tex : register(t0);
SamplerState samp : register(s0);
PSInput VS_Texture(VSInput input)
{
PSInput result;
result.position = mul(mvp, input.position);
result.coord = input.coord;
return result;
}
float4 PS_Texture(PSInput input) : SV_TARGET
{
return tex.Sample(samp, input.coord) * opacity;
}

View File

@ -0,0 +1,32 @@
struct VSInput
{
float4 position : POSITION;
float4 color : COLOR;
};
cbuffer ConstantBuffer : register(b0)
{
float4x4 mvp;
float opacity;
};
struct PSInput
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
PSInput VS_VertexColor(VSInput input)
{
PSInput result;
result.position = mul(mvp, input.position);
result.color = input.color * opacity;
return result;
}
float4 PS_VertexColor(PSInput input) : SV_TARGET
{
return input.color;
}

View File

@ -0,0 +1,2 @@
TEMPLATE = subdirs
config_d3d12: SUBDIRS += d3d12

View File

@ -92,6 +92,7 @@ void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool h
texture->setRect(referencedItem->boundingRect());
texture->setSize(referencedItem->boundingRect().size().toSize());
texture->setRecursive(true);
#ifndef QT_NO_OPENGL
#ifndef QT_OPENGL_ES
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
texture->setFormat(GL_RGBA8);
@ -99,6 +100,7 @@ void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool h
texture->setFormat(GL_RGBA);
#else
texture->setFormat(GL_RGBA);
#endif
#endif
texture->setHasMipmaps(false);

View File

@ -39,8 +39,9 @@
#include "qquickdesignerwindowmanager_p.h"
#include "private/qquickwindow_p.h"
#include <QtGui/QOpenGLContext>
#ifndef QT_NO_OPENGL
# include <QtQuick/private/qsgdefaultrendercontext_p.h>
#endif
#include <QtQuick/QQuickWindow>
QT_BEGIN_NAMESPACE
@ -48,7 +49,7 @@ QT_BEGIN_NAMESPACE
QQuickDesignerWindowManager::QQuickDesignerWindowManager()
: m_sgContext(QSGContext::createDefaultContext())
{
m_renderContext.reset(new QSGRenderContext(m_sgContext.data()));
m_renderContext.reset(m_sgContext.data()->createRenderContext());
}
void QQuickDesignerWindowManager::show(QQuickWindow *window)
@ -66,6 +67,7 @@ void QQuickDesignerWindowManager::windowDestroyed(QQuickWindow *)
void QQuickDesignerWindowManager::makeOpenGLContext(QQuickWindow *window)
{
#ifndef QT_NO_OPENGL
if (!m_openGlContext) {
m_openGlContext.reset(new QOpenGLContext());
m_openGlContext->setFormat(window->requestedFormat());
@ -76,6 +78,9 @@ void QQuickDesignerWindowManager::makeOpenGLContext(QQuickWindow *window)
} else {
m_openGlContext->makeCurrent(window);
}
#else
Q_UNUSED(window)
#endif
}
void QQuickDesignerWindowManager::exposureChanged(QQuickWindow *)

View File

@ -57,6 +57,10 @@
#include <private/qtquickglobal_p.h>
#include <QtQuick/private/qsgcontext_p.h>
#ifndef QT_NO_OPENGL
# include <QtGui/QOpenGLContext>
#endif
QT_BEGIN_NAMESPACE
@ -64,7 +68,6 @@ class QQuickWindow;
class QSGContext;
class QSGRenderContext;
class QAnimationDriver;
class QOpenGLContext;
class QQuickDesignerWindowManager : public QSGRenderLoop
{
@ -94,7 +97,9 @@ public:
static void createOpenGLContext(QQuickWindow *window);
private:
#ifndef QT_NO_OPENGL
QScopedPointer<QOpenGLContext> m_openGlContext;
#endif
QScopedPointer<QSGContext> m_sgContext;
QScopedPointer<QSGRenderContext> m_renderContext;
};

View File

@ -0,0 +1,86 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://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: http://www.gnu.org/copyleft/fdl.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\title Scene Graph Adaptations
\page qtquick-visualcanvas-adaptations.html
\section1 Scene Graph Adaptations in Qt Quick
Originally Qt Quick only had one available renderer for parsing the
scene graph and rendering the results to a render target. This renderer
is now the default OpenGL Renderer which supports rendering either using
the OpenGL ES 2.0 or OpenGL 2.0 APIs. The Qt Quick APIs are designed
with the assumption that these two APIs are always available. It is
however possible now to use other graphics API's to render Qt Quick
scenes using the scene graph APIs.
\section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation
The default adaptation capable of providing the full Qt Quick 2 feature
set is the OpenGL adaptation. All of the details of the OpenGL
adpatation can are available here
\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}
\section1 Software Adaptation
The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that uses the Raster
paint engine to render the contents of the scene graph instead of OpenGL.
As a result of not using OpenGL to render the scene graph, some features
and optimizations are no longer available. Most Qt Quick 2 applications
will run without modification though any attempts to use unsupported
features will be ignored. By using the Software adpatation it is possible to run Qt
Quick 2 applications on hardware and platforms that do not have OpenGL
support.
The Software adaptation was previously known as the Qt Quick 2D Renderer.
\section2 Shader Effects
ShaderEffect components in QtQuick 2 can not be rendered by the Software adptation.
\section2 Qt Graphical Effects Module
\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use
graphical effects from this module, then you should not hide the source
item so that the original item can still be rendered.
\section2 Particle Effects
It is not possible to render particle effects with the Software adaptation. Whenever
possible, remove particles completely from the scene. Otherwise they will still
require some processing, even though they are not visible.
\section2 Sprites
The Sprite item depends on OpenGL functions and will not be visible.
\section2 Rendering Text
The text rendering with the Software adaptation is based on software
rasterization and does not respond as well to transformations such as scaling
as when using OpenGL. The quality is similar to choosing \l [QML] {Text::renderType}
{Text.NativeRendering} with \l [QML] {Text} items.
\section1 Direct3D 12 (experimental)
*/

View File

@ -31,9 +31,10 @@
\section1 The Scene Graph in Qt Quick
Qt Quick 2 makes use of a dedicated scene graph based on OpenGL ES 2.0
or OpenGL 2.0 for its rendering. Using a scene graph for graphics
rather than the traditional imperative painting systems (QPainter and
Qt Quick 2 makes use of a dedicated scene graph based and a series of
adpatations of which the default uses OpenGL ES 2.0 or OpenGL 2.0 for
its rendering. Using a scene graph for graphics rather than the
traditional imperative painting systems (QPainter and
similar), means the scene to be rendered can be retained between
frames and the complete set of primitives to render is known before
rendering starts. This opens up for a number of optimizations, such as
@ -62,6 +63,11 @@ independently of the state of the items. On many platforms, the scene
graph will even be rendered on a dedicated render thread while the GUI
thread is preparing the next frame's state.
\note Much of the information listed on this page is specific to the
default OpenGL adaptation of the Qt Quick Scene graph. For more information
about the different scene graph adaptations see
\l{qtquick-visualcanvas-adaptations.html}{Scene Graph Adaptations}.
\section1 Qt Quick Scene Graph Structure

View File

@ -55,12 +55,13 @@ See the documentation about the \l{qtquick-visualcanvas-visualparent.html}
\section1 Scene Graph
Modern computer systems and devices use OpenGL to draw graphics. Qt Quick
requires OpenGL and it is used to display applications developed with
Qt Quick in QML. In particular, Qt Quick defines a scene graph which is then
rendered. See the documentation about the
\l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth
information about the concept of a scene graph and why it is beneficial, and
about the scene graph implementation provided by Qt Quick.
Modern computer systems and devices use graphics processing units or GPUs to
render graphics. Qt Quick can leverage this graphics hardware by using graphics
APIs like OpenGL. The default graphics adpatation for Qt Quick requires OpenGL and
it is used to display applications developed with Qt Quick in QML. In particular,
Qt Quick defines a scene graph which is then rendered. See the documentation about the
\l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth information about
the concept of a scene graph and why it is beneficial, and about the scene graph
adaptations provided by Qt Quick.
*/

View File

@ -43,7 +43,7 @@
#include <private/qquickcanvascontext_p.h>
#include <private/qquickcontext2d_p.h>
#include <private/qquickcontext2dtexture_p.h>
#include <qsgsimpletexturenode.h>
#include <private/qsgadaptationlayer_p.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QtGui/QGuiApplication>
@ -59,24 +59,11 @@
QT_BEGIN_NAMESPACE
class QQuickCanvasNode : public QSGSimpleTextureNode
{
public:
QQuickCanvasNode() {
qsgnode_set_description(this, QStringLiteral("canvasnode"));
setOwnsTexture(false);
}
~QQuickCanvasNode() {
delete texture();
}
};
class QQuickCanvasTextureProvider : public QSGTextureProvider
{
public:
QQuickCanvasNode *node;
QSGTexture *texture() const Q_DECL_OVERRIDE { return node ? node->texture() : 0; }
QSGTexture *tex;
QSGTexture *texture() const Q_DECL_OVERRIDE { return tex; }
void fireTextureChanged() { emit textureChanged(); }
};
@ -187,7 +174,8 @@ public:
QUrl baseUrl;
QMap<int, QV4::PersistentValue> animationCallbacks;
mutable QQuickCanvasTextureProvider *textureProvider;
QQuickCanvasNode *node;
QSGImageNode *node;
QSGTexture *nodeTexture;
};
QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
@ -203,6 +191,7 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, renderStrategy(QQuickCanvasItem::Immediate)
, textureProvider(0)
, node(0)
, nodeTexture(0)
{
implicitAntialiasing = true;
}
@ -256,17 +245,18 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
The Canvas item supports two render targets: \c Canvas.Image and
\c Canvas.FramebufferObject.
The \c Canvas.Image render target is a \a QImage object. This render
target supports background thread rendering, allowing complex or long
running painting to be executed without blocking the UI.
The \c Canvas.Image render target is a \a QImage object. This render target
supports background thread rendering, allowing complex or long running
painting to be executed without blocking the UI. This is the only render
target that is supported by all Qt Quick backends.
The Canvas.FramebufferObject render target utilizes OpenGL hardware
acceleration rather than rendering into system memory, which in many cases
results in faster rendering. Canvas.FramebufferObject relies on the
OpenGL extensions \c GL_EXT_framebuffer_multisample and
\c GL_EXT_framebuffer_blit for antialiasing. It will also use more
graphics memory when rendering strategy is anything other than
Canvas.Cooperative.
results in faster rendering. Canvas.FramebufferObject relies on the OpenGL
extensions \c GL_EXT_framebuffer_multisample and \c GL_EXT_framebuffer_blit
for antialiasing. It will also use more graphics memory when rendering
strategy is anything other than Canvas.Cooperative. Framebuffer objects may
not be available with Qt Quick backends other than OpenGL.
The default render target is Canvas.Image and the default renderStrategy is
Canvas.Immediate.
@ -301,7 +291,14 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
and can be used directly in \l {ShaderEffect}{ShaderEffects} and other
classes that consume texture providers.
\sa Context2D
\note In general large canvases, frequent updates, and animation should be
avoided with the Canvas.Image render target. This is because with
accelerated graphics APIs each update will lead to a texture upload. Also,
if possible, prefer QQuickPaintedItem and implement drawing in C++ via
QPainter instead of the more expensive and likely less performing
JavaScript and Context2D approach.
\sa Context2D QQuickPaintedItem
*/
QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
@ -735,16 +732,16 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (!d->context || d->canvasWindow.size().isEmpty()) {
if (d->textureProvider) {
d->textureProvider->node = 0;
d->textureProvider->tex = 0;
d->textureProvider->fireTextureChanged();
}
delete oldNode;
return 0;
}
QQuickCanvasNode *node = static_cast<QQuickCanvasNode*>(oldNode);
QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
if (!node) {
node = new QQuickCanvasNode();
node = QQuickWindowPrivate::get(window())->context->sceneGraphContext()->createImageNode();
d->node = node;
}
@ -761,22 +758,27 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
QQuickContext2DTexture *factory = ctx->texture();
QSGTexture *texture = factory->textureForNextFrame(node->texture(), window());
QSGTexture *texture = factory->textureForNextFrame(d->nodeTexture, window());
if (!texture) {
delete node;
d->node = 0;
delete d->nodeTexture;
d->nodeTexture = 0;
if (d->textureProvider) {
d->textureProvider->node = 0;
d->textureProvider->tex = 0;
d->textureProvider->fireTextureChanged();
}
return 0;
}
d->nodeTexture = texture;
node->setTexture(texture);
node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
node->setTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
node->setInnerTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
node->update();
if (d->textureProvider) {
d->textureProvider->node = node;
d->textureProvider->tex = d->nodeTexture;
d->textureProvider->fireTextureChanged();
}
return node;
@ -796,14 +798,17 @@ QSGTextureProvider *QQuickCanvasItem::textureProvider() const
return QQuickItem::textureProvider();
Q_D(const QQuickCanvasItem);
#ifndef QT_NO_OPENGL
QQuickWindow *w = window();
if (!w || !w->openglContext() || QThread::currentThread() != w->openglContext()->thread()) {
if (!w || !w->isSceneGraphInitialized()
|| QThread::currentThread() != QQuickWindowPrivate::get(w)->context->thread()) {
qWarning("QQuickCanvasItem::textureProvider: can only be queried on the rendering thread of an exposed window");
return 0;
}
#endif
if (!d->textureProvider)
d->textureProvider = new QQuickCanvasTextureProvider;
d->textureProvider->node = d->node;
d->textureProvider->tex = d->nodeTexture;
return d->textureProvider;
}

View File

@ -43,6 +43,7 @@
#include <private/qquickcontext2dtexture_p.h>
#include <private/qquickitem_p.h>
#include <QtQuick/private/qquickshadereffectsource_p.h>
#include <qsgrendererinterface.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquicksvgparser_p.h>
@ -74,6 +75,10 @@
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#ifndef QT_NO_OPENGL
# include <private/qsgdefaultrendercontext_p.h>
#endif
#include <cmath>
#if defined(Q_OS_QNX) || defined(Q_OS_ANDROID)
#include <ctype.h>
@ -3980,10 +3985,12 @@ public:
~QQuickContext2DThreadCleanup()
{
#ifndef QT_NO_OPENGL
context->makeCurrent(surface);
delete texture;
context->doneCurrent();
delete context;
#endif
surface->deleteLater();
}
@ -4019,6 +4026,7 @@ QQuickContext2D::~QQuickContext2D()
delete m_buffer;
if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
#ifndef QT_NO_OPENGL
if (m_renderStrategy == QQuickCanvasItem::Immediate && m_glContext) {
Q_ASSERT(QThread::currentThread() == m_glContext->thread());
m_glContext->makeCurrent(m_surface.data());
@ -4039,6 +4047,7 @@ QQuickContext2D::~QQuickContext2D()
m_texture->deleteLater();
}
}
#endif
} else {
// Image based does not have GL resources, but must still be deleted
// on its designated thread after it has completed whatever it might
@ -4064,8 +4073,6 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_canvas = canvasItem;
m_renderTarget = canvasItem->renderTarget();
QQuickWindow *window = canvasItem->window();
m_renderStrategy = canvasItem->renderStrategy();
#ifdef Q_OS_WIN
@ -4084,12 +4091,24 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_renderTarget = QQuickCanvasItem::Image;
}
// Disable Framebuffer Object based rendering when not running with OpenGL
if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
QSGRendererInterface *rif = canvasItem->window()->rendererInterface();
if (rif && rif->graphicsApi() != QSGRendererInterface::OpenGL)
m_renderTarget = QQuickCanvasItem::Image;
}
switch (m_renderTarget) {
case QQuickCanvasItem::Image:
m_texture = new QQuickContext2DImageTexture;
break;
case QQuickCanvasItem::FramebufferObject:
#ifndef QT_NO_OPENGL
m_texture = new QQuickContext2DFBOTexture;
#else
// It shouldn't be possible to use a FramebufferObject without OpenGL
m_texture = nullptr;
#endif
break;
}
@ -4103,18 +4122,27 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_thread = QThread::currentThread();
QThread *renderThread = m_thread;
QThread *sceneGraphThread = window->openglContext() ? window->openglContext()->thread() : 0;
#ifndef QT_NO_OPENGL
QQuickWindow *window = canvasItem->window();
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
QThread *sceneGraphThread = wd->context->thread();
if (m_renderStrategy == QQuickCanvasItem::Threaded)
renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
else if (m_renderStrategy == QQuickCanvasItem::Cooperative)
renderThread = sceneGraphThread;
#else
if (m_renderStrategy == QQuickCanvasItem::Threaded)
renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
#endif
if (renderThread && renderThread != QThread::currentThread())
m_texture->moveToThread(renderThread);
#ifndef QT_NO_OPENGL
if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->openglContext();
auto openglRenderContext = static_cast<const QSGDefaultRenderContext *>(QQuickWindowPrivate::get(window)->context);
QOpenGLContext *cc = openglRenderContext->openglContext();
m_surface.reset(new QOffscreenSurface);
m_surface->setFormat(window->format());
m_surface->create();
@ -4125,7 +4153,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_glContext->moveToThread(renderThread);
m_texture->initializeOpenGL(m_glContext, m_surface.data());
}
#endif
connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
reset();
@ -4172,6 +4200,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
flush();
m_texture->grabImage(bounds);
} else {
#ifndef QT_NO_OPENGL
QQuickWindow *window = m_canvas->window();
QOpenGLContext *ctx = window ? window->openglContext() : 0;
if (ctx && ctx->isValid()) {
@ -4187,6 +4216,10 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
qWarning() << "Cannot read pixels from canvas before opengl context is valid";
return QImage();
}
#else
flush();
m_texture->grabImage(bounds);
#endif
}
} else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";

View File

@ -42,9 +42,11 @@
#include <qqml.h>
#include <QtCore/QMutex>
#include <QtQuick/qsgtexture.h>
#include <QtGui/QOpenGLContext>
#include <QtGui/QPaintEngine>
#include <QtGui/private/qopenglpaintengine_p.h>
#ifndef QT_NO_OPENGL
# include <QtGui/QOpenGLContext>
# include <QtGui/private/qopenglpaintengine_p.h>
#endif
#define HAS_SHADOW(offsetX, offsetY, blur, color) (color.isValid() && color.alpha() && (blur || offsetX || offsetY))

View File

@ -44,14 +44,16 @@
#include <QtQuick/private/qsgtexture_p.h>
#include "qquickcontext2dcommandbuffer_p.h"
#include <QOpenGLPaintDevice>
#ifndef QT_NO_OPENGL
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QOpenGLFunctions>
#endif
#include <QtCore/QThread>
#include <QtGui/QGuiApplication>
QT_BEGIN_NAMESPACE
#ifndef QT_NO_OPENGL
#define QT_MINIMUM_FBO_SIZE 64
static inline int qt_next_power_of_two(int v)
@ -85,10 +87,12 @@ struct GLAcquireContext {
}
QOpenGLContext *ctx;
};
#endif
QQuickContext2DTexture::QQuickContext2DTexture()
: m_context(0)
#ifndef QT_NO_OPENGL
, m_gl(0)
#endif
, m_surface(0)
, m_item(0)
, m_canvasWindowChanged(false)
@ -250,9 +254,9 @@ void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb)
return;
}
QQuickContext2D::mutex.unlock();
#ifndef QT_NO_OPENGL
GLAcquireContext currentContext(m_gl, m_surface);
#endif
if (!m_tiledCanvas) {
paintWithoutTiles(ccb);
delete ccb;
@ -379,7 +383,7 @@ bool QQuickContext2DTexture::event(QEvent *e)
}
return QObject::event(e);
}
#ifndef QT_NO_OPENGL
static inline QSize npotAdjustedSize(const QSize &size)
{
static bool checked = false;
@ -646,6 +650,7 @@ void QQuickContext2DFBOTexture::endPainting()
m_fbo->bindDefault();
}
#endif
QQuickContext2DImageTexture::QQuickContext2DImageTexture()
: QQuickContext2DTexture()

View File

@ -54,10 +54,10 @@
#include <QtQuick/qsgtexture.h>
#include "qquickcanvasitem_p.h"
#include "qquickcontext2d_p.h"
#include <QOpenGLContext>
#include <QOpenGLFramebufferObject>
#ifndef QT_NO_OPENGL
# include <QOpenGLContext>
# include <QOpenGLFramebufferObject>
#endif
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QThread>
@ -121,11 +121,12 @@ public:
// Called during sync() on the scene graph thread while GUI is blocked.
virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window) = 0;
bool event(QEvent *e);
#ifndef QT_NO_OPENGL
void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) {
m_gl = gl;
m_surface = s;
}
#endif
Q_SIGNALS:
void textureChanged();
@ -152,8 +153,9 @@ protected:
QList<QQuickContext2DTile*> m_tiles;
QQuickContext2D *m_context;
#ifndef QT_NO_OPENGL
QOpenGLContext *m_gl;
#endif
QSurface *m_surface;
QQuickContext2D::State m_state;
@ -174,7 +176,7 @@ protected:
uint m_painting : 1;
uint m_onCustomThread : 1; // Not GUI and not SGRender
};
#ifndef QT_NO_OPENGL
class QQuickContext2DFBOTexture : public QQuickContext2DTexture
{
Q_OBJECT
@ -209,7 +211,7 @@ private:
GLuint m_displayTextures[2];
int m_displayTexture;
};
#endif
class QSGPlainTexture;
class QQuickContext2DImageTexture : public QQuickContext2DTexture
{

View File

@ -38,10 +38,11 @@
****************************************************************************/
#include "qquickcontext2dtile_p.h"
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QOpenGLPaintDevice>
#ifndef QT_NO_OPENGL
# include <QOpenGLFramebufferObject>
# include <QOpenGLFramebufferObjectFormat>
# include <QOpenGLPaintDevice>
#endif
QT_BEGIN_NAMESPACE
@ -96,7 +97,7 @@ QPainter* QQuickContext2DTile::createPainter(bool smooth, bool antialiasing)
return 0;
}
#ifndef QT_NO_OPENGL
QQuickContext2DFBOTile::QQuickContext2DFBOTile()
: QQuickContext2DTile()
, m_fbo(0)
@ -146,7 +147,7 @@ void QQuickContext2DFBOTile::setRect(const QRect& r)
m_fbo = new QOpenGLFramebufferObject(r.size(), format);
}
}
#endif
QQuickContext2DImageTile::QQuickContext2DImageTile()
: QQuickContext2DTile()

View File

@ -52,8 +52,9 @@
//
#include "qquickcontext2d_p.h"
#include <QOpenGLFramebufferObject>
#ifndef QT_NO_OPENGL
# include <QOpenGLFramebufferObject>
#endif
QT_BEGIN_NAMESPACE
class QQuickContext2DTexture;
@ -82,7 +83,7 @@ protected:
QPainter m_painter;
};
#ifndef QT_NO_OPENGL
class QQuickContext2DFBOTile : public QQuickContext2DTile
{
public:
@ -99,7 +100,7 @@ private:
QOpenGLFramebufferObject *m_fbo;
};
#endif
class QQuickContext2DImageTile : public QQuickContext2DTile
{
public:

View File

@ -63,10 +63,6 @@ HEADERS += \
$$PWD/qquickstateoperations_p.h \
$$PWD/qquickimplicitsizeitem_p.h \
$$PWD/qquickimplicitsizeitem_p_p.h \
$$PWD/qquickspriteengine_p.h \
$$PWD/qquicksprite_p.h \
$$PWD/qquickspritesequence_p.h \
$$PWD/qquickanimatedsprite_p.h \
$$PWD/qquickdrag_p.h \
$$PWD/qquickdroparea_p.h \
$$PWD/qquickmultipointtoucharea_p.h \
@ -76,11 +72,14 @@ HEADERS += \
$$PWD/qquickscreen_p.h \
$$PWD/qquickwindowattached_p.h \
$$PWD/qquickwindowmodule_p.h \
$$PWD/qquickframebufferobject.h \
$$PWD/qquickitemgrabresult.h \
$$PWD/qquickshadereffectsource_p.h \
$$PWD/qquickshadereffectmesh_p.h \
$$PWD/qquickshadereffect_p.h \
$$PWD/qquickgenericshadereffect_p.h \
$$PWD/qquickrendercontrol.h \
$$PWD/qquickrendercontrol_p.h \
$$PWD/qquickopenglinfo_p.h
$$PWD/qquickgraphicsinfo_p.h \
$$PWD/qquickitemgrabresult.h
SOURCES += \
$$PWD/qquickevents.cpp \
@ -120,10 +119,6 @@ SOURCES += \
$$PWD/qquickitemanimation.cpp \
$$PWD/qquickstateoperations.cpp \
$$PWD/qquickimplicitsizeitem.cpp \
$$PWD/qquickspriteengine.cpp \
$$PWD/qquicksprite.cpp \
$$PWD/qquickspritesequence.cpp \
$$PWD/qquickanimatedsprite.cpp \
$$PWD/qquickaccessibleattached.cpp \
$$PWD/qquickdrag.cpp \
$$PWD/qquickdroparea.cpp \
@ -133,36 +128,50 @@ SOURCES += \
$$PWD/qquickwindowmodule.cpp \
$$PWD/qquickscreen.cpp \
$$PWD/qquickwindowattached.cpp \
$$PWD/qquickframebufferobject.cpp \
$$PWD/qquickitemgrabresult.cpp \
$$PWD/qquickrendercontrol.cpp \
$$PWD/qquickopenglinfo.cpp
SOURCES += \
$$PWD/qquickshadereffect.cpp \
$$PWD/qquickshadereffectmesh.cpp \
$$PWD/qquickshadereffectnode.cpp \
$$PWD/qquickshadereffectsource.cpp \
$$PWD/qquickshadereffectmesh.cpp \
$$PWD/qquickshadereffect.cpp \
$$PWD/qquickgenericshadereffect.cpp \
$$PWD/qquickrendercontrol.cpp \
$$PWD/qquickgraphicsinfo.cpp \
$$PWD/qquickitemgrabresult.cpp
HEADERS += \
$$PWD/qquickshadereffect_p.h \
$$PWD/qquickshadereffectmesh_p.h \
$$PWD/qquickshadereffectnode_p.h \
$$PWD/qquickshadereffectsource_p.h \
# Items that depend on OpenGL Renderer
contains(QT_CONFIG, opengl(es1|es2)?) {
SOURCES += \
$$PWD/qquickopenglinfo.cpp \
$$PWD/qquickopenglshadereffect.cpp \
$$PWD/qquickopenglshadereffectnode.cpp \
$$PWD/qquickframebufferobject.cpp \
$$PWD/qquickspriteengine.cpp \
$$PWD/qquicksprite.cpp \
$$PWD/qquickspritesequence.cpp \
$$PWD/qquickanimatedsprite.cpp
OTHER_FILES += \
$$PWD/shaders/sprite.vert \
$$PWD/shaders/sprite.frag \
$$PWD/shaders/shadereffect.vert \
$$PWD/shaders/shadereffect.frag \
$$PWD/shaders/shadereffectfallback.vert \
$$PWD/shaders/shadereffectfallback.frag \
$$PWD/shaders/sprite_core.vert \
$$PWD/shaders/sprite_core.frag \
$$PWD/shaders/shadereffect_core.vert \
$$PWD/shaders/shadereffect_core.frag \
$$PWD/shaders/shadereffectfallback_core.vert \
$$PWD/shaders/shadereffectfallback_core.frag
HEADERS += \
$$PWD/qquickopenglinfo_p.h \
$$PWD/qquickspriteengine_p.h \
$$PWD/qquicksprite_p.h \
$$PWD/qquickspritesequence_p.h \
$$PWD/qquickanimatedsprite_p.h \
$$PWD/qquickopenglshadereffect_p.h \
$$PWD/qquickopenglshadereffectnode_p.h \
$$PWD/qquickframebufferobject.h
OTHER_FILES += \
$$PWD/shaders/sprite.vert \
$$PWD/shaders/sprite.frag \
$$PWD/shaders/shadereffect.vert \
$$PWD/shaders/shadereffect.frag \
$$PWD/shaders/shadereffectfallback.vert \
$$PWD/shaders/shadereffectfallback.frag \
$$PWD/shaders/sprite_core.vert \
$$PWD/shaders/sprite_core.frag \
$$PWD/shaders/shadereffect_core.vert \
$$PWD/shaders/shadereffect_core.frag \
$$PWD/shaders/shadereffectfallback_core.vert \
$$PWD/shaders/shadereffectfallback_core.frag
}
RESOURCES += \
$$PWD/items.qrc

View File

@ -40,7 +40,7 @@
#include "qquickframebufferobject.h"
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
#include <private/qquickitem_p.h>
#include <QSGSimpleTextureNode>

View File

@ -0,0 +1,609 @@
/****************************************************************************
**
** 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 <private/qquickgenericshadereffect_p.h>
#include <private/qquickwindow_p.h>
#include <private/qquickitem_p.h>
#include <QSignalMapper>
QT_BEGIN_NAMESPACE
// The generic shader effect is used when the scenegraph backend indicates
// SupportsShaderEffectNode. This, unlike the monolithic and interconnected (e.g.
// with particles) OpenGL variant, passes most of the work to a scenegraph node
// created via the adaptation layer, thus allowing different implementation in
// the backends.
QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent)
: QObject(parent)
, m_item(item)
, m_meshResolution(1, 1)
, m_mesh(nullptr)
, m_cullMode(QQuickShaderEffect::NoCulling)
, m_blending(true)
, m_supportsAtlasTextures(false)
, m_mgr(nullptr)
, m_dirty(0)
{
connect(m_item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(itemWindowChanged(QQuickWindow*)));
}
QQuickGenericShaderEffect::~QQuickGenericShaderEffect()
{
for (int i = 0; i < NShader; ++i) {
disconnectSignals(Shader(i));
for (const auto &sm : qAsConst(m_signalMappers[i]))
delete sm.mapper;
}
delete m_mgr;
}
void QQuickGenericShaderEffect::setFragmentShader(const QByteArray &src)
{
// Compare the actual values since they are often just filenames.
// Optimizing by comparing constData() is a bad idea since seemingly static
// strings in QML may in fact have different addresses when a binding
// triggers assigning the "same" value to the property.
if (m_fragShader == src)
return;
m_fragShader = src;
m_dirty |= QSGShaderEffectNode::DirtyShaders;
if (m_item->isComponentComplete())
updateShader(Fragment, src);
m_item->update();
emit m_item->fragmentShaderChanged();
}
void QQuickGenericShaderEffect::setVertexShader(const QByteArray &src)
{
if (m_vertShader == src)
return;
m_vertShader = src;
m_dirty |= QSGShaderEffectNode::DirtyShaders;
if (m_item->isComponentComplete())
updateShader(Vertex, src);
m_item->update();
emit m_item->vertexShaderChanged();
}
void QQuickGenericShaderEffect::setBlending(bool enable)
{
if (m_blending == enable)
return;
m_blending = enable;
m_item->update();
emit m_item->blendingChanged();
}
QVariant QQuickGenericShaderEffect::mesh() const
{
return m_mesh ? qVariantFromValue(static_cast<QObject *>(m_mesh))
: qVariantFromValue(m_meshResolution);
}
void QQuickGenericShaderEffect::setMesh(const QVariant &mesh)
{
QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
if (newMesh && newMesh == m_mesh)
return;
if (m_mesh)
disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
m_mesh = newMesh;
if (m_mesh) {
connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(markGeometryDirtyAndUpdate()));
} else {
if (mesh.canConvert<QSize>()) {
m_meshResolution = mesh.toSize();
} else {
QList<QByteArray> res = mesh.toByteArray().split('x');
bool ok = res.size() == 2;
if (ok) {
int w = res.at(0).toInt(&ok);
if (ok) {
int h = res.at(1).toInt(&ok);
if (ok)
m_meshResolution = QSize(w, h);
}
}
if (!ok)
qWarning("ShaderEffect: mesh property must be a size or an object deriving from QQuickShaderEffectMesh");
}
m_defaultMesh.setResolution(m_meshResolution);
}
m_dirty |= QSGShaderEffectNode::DirtyShaderMesh;
m_item->update();
emit m_item->meshChanged();
}
void QQuickGenericShaderEffect::setCullMode(QQuickShaderEffect::CullMode face)
{
if (m_cullMode == face)
return;
m_cullMode = face;
m_item->update();
emit m_item->cullModeChanged();
}
void QQuickGenericShaderEffect::setSupportsAtlasTextures(bool supports)
{
if (m_supportsAtlasTextures == supports)
return;
m_supportsAtlasTextures = supports;
markGeometryDirtyAndUpdate();
emit m_item->supportsAtlasTexturesChanged();
}
QString QQuickGenericShaderEffect::log() const
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr)
return QString();
return mgr->log();
}
QQuickShaderEffect::Status QQuickGenericShaderEffect::status() const
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr)
return QQuickShaderEffect::Uncompiled;
return QQuickShaderEffect::Status(mgr->status());
}
void QQuickGenericShaderEffect::handleEvent(QEvent *event)
{
if (event->type() == QEvent::DynamicPropertyChange) {
QDynamicPropertyChangeEvent *e = static_cast<QDynamicPropertyChangeEvent *>(event);
for (int shaderType = 0; shaderType < NShader; ++shaderType) {
const auto &vars(m_shaders[shaderType].shaderInfo.variables);
for (int idx = 0; idx < vars.count(); ++idx) {
if (vars[idx].name == e->propertyName()) {
propertyChanged((shaderType << 16) | idx);
break;
}
}
}
}
}
void QQuickGenericShaderEffect::handleGeometryChanged(const QRectF &, const QRectF &)
{
m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
}
QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
{
QSGShaderEffectNode *node = static_cast<QSGShaderEffectNode *>(oldNode);
if (m_item->width() <= 0 || m_item->height() <= 0) {
delete node;
return nullptr;
}
// The manager should be already created on the gui thread. Just take that instance.
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr) {
delete node;
return nullptr;
}
if (!node) {
QSGRenderContext *rc = QQuickWindowPrivate::get(m_item->window())->context;
node = rc->sceneGraphContext()->createShaderEffectNode(rc, mgr);
m_dirty = QSGShaderEffectNode::DirtyShaderAll;
}
QSGShaderEffectNode::SyncData sd;
sd.dirty = m_dirty;
sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
sd.blending = m_blending;
sd.vertex.shader = &m_shaders[Vertex];
sd.vertex.dirtyConstants = &m_dirtyConstants[Vertex];
sd.vertex.dirtyTextures = &m_dirtyTextures[Vertex];
sd.fragment.shader = &m_shaders[Fragment];
sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
node->syncMaterial(&sd);
if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
node->setGeometry(nullptr);
m_dirty &= ~QSGShaderEffectNode::DirtyShaderMesh;
m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
}
if (m_dirty & QSGShaderEffectNode::DirtyShaderGeometry) {
const QRectF rect(0, 0, m_item->width(), m_item->height());
QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
QSGGeometry *geometry = node->geometry();
const QRectF srcRect = node->updateNormalizedTextureSubRect(m_supportsAtlasTextures);
geometry = mesh->updateGeometry(geometry, 2, 0, srcRect, rect);
node->setFlag(QSGNode::OwnsGeometry, false);
node->setGeometry(geometry);
node->setFlag(QSGNode::OwnsGeometry, true);
m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
}
m_dirty = 0;
for (int i = 0; i < NShader; ++i) {
m_dirtyConstants[i].clear();
m_dirtyTextures[i].clear();
}
return node;
}
void QQuickGenericShaderEffect::handleComponentComplete()
{
updateShader(Vertex, m_vertShader);
updateShader(Fragment, m_fragShader);
}
void QQuickGenericShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
{
// Move the window ref.
if (change == QQuickItem::ItemSceneChange) {
for (int shaderType = 0; shaderType < NShader; ++shaderType) {
for (const auto &vd : qAsConst(m_shaders[shaderType].varData)) {
if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
if (source) {
if (value.window)
QQuickItemPrivate::get(source)->refWindow(value.window);
else
QQuickItemPrivate::get(source)->derefWindow();
}
}
}
}
}
}
QSGGuiThreadShaderEffectManager *QQuickGenericShaderEffect::shaderEffectManager() const
{
if (!m_mgr) {
// return null if this is not the gui thread and not already created
if (QThread::currentThread() != m_item->thread())
return m_mgr;
// need a window and a rendercontext (i.e. the scenegraph backend is ready)
QQuickWindow *w = m_item->window();
if (w && w->isSceneGraphInitialized()) {
m_mgr = QQuickWindowPrivate::get(w)->context->sceneGraphContext()->createGuiThreadShaderEffectManager();
if (m_mgr) {
connect(m_mgr, SIGNAL(logAndStatusChanged()), m_item, SIGNAL(logChanged()));
connect(m_mgr, SIGNAL(logAndStatusChanged()), m_item, SIGNAL(statusChanged()));
connect(m_mgr, SIGNAL(textureChanged()), this, SLOT(markGeometryDirtyAndUpdateIfSupportsAtlas()));
}
} else if (!w) {
// Wait until itemWindowChanged() gets called. Return null for now.
} else {
// Have window, but no scenegraph -> ensure the signal is connected. Return null for now.
const_cast<QQuickGenericShaderEffect *>(this)->itemWindowChanged(w);
}
}
return m_mgr;
}
void QQuickGenericShaderEffect::itemWindowChanged(QQuickWindow *w)
{
if (w) {
if (w->isSceneGraphInitialized())
backendChanged();
else
connect(w, SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()), Qt::UniqueConnection);
}
}
void QQuickGenericShaderEffect::backendChanged()
{
disconnect(m_item->window(), SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()));
emit m_item->logChanged();
emit m_item->statusChanged();
}
void QQuickGenericShaderEffect::disconnectSignals(Shader shaderType)
{
for (auto &sm : m_signalMappers[shaderType]) {
if (sm.active) {
sm.active = false;
QObject::disconnect(m_item, nullptr, sm.mapper, SLOT(map()));
QObject::disconnect(sm.mapper, SIGNAL(mapped(int)), this, SLOT(propertyChanged(int)));
}
}
for (const auto &vd : qAsConst(m_shaders[shaderType].varData)) {
if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
if (source) {
if (m_item->window())
QQuickItemPrivate::get(source)->derefWindow();
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
}
}
}
}
struct ReflectCache
{
bool contains(const QByteArray &key) const
{
return m_reflectCache.contains(key);
}
QSGGuiThreadShaderEffectManager::ShaderInfo value(const QByteArray &key) const
{
return m_reflectCache.value(key);
}
void insert(const QByteArray &key, const QSGGuiThreadShaderEffectManager::ShaderInfo &value)
{
m_reflectCache.insert(key, value);
}
QHash<QByteArray, QSGGuiThreadShaderEffectManager::ShaderInfo> m_reflectCache;
};
Q_GLOBAL_STATIC(ReflectCache, reflectCache)
void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray &src)
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr)
return;
const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
disconnectSignals(shaderType);
m_shaders[shaderType].shaderInfo = QSGGuiThreadShaderEffectManager::ShaderInfo();
m_shaders[shaderType].varData.clear();
if (!src.isEmpty()) {
// Figure out what input parameters and variables are used in the shader.
// For file-based shader source/bytecode this is where the data is pulled
// in from the file.
if (reflectCache()->contains(src)) {
m_shaders[shaderType].shaderInfo = reflectCache()->value(src);
} else {
QSGGuiThreadShaderEffectManager::ShaderInfo shaderInfo;
if (!mgr->reflect(src, &shaderInfo)) {
qWarning("ShaderEffect: shader reflection failed for %s", src.constData());
m_shaders[shaderType].hasShaderCode = false;
return;
}
m_shaders[shaderType].shaderInfo = shaderInfo;
reflectCache()->insert(src, shaderInfo);
}
m_shaders[shaderType].hasShaderCode = true;
} else {
m_shaders[shaderType].hasShaderCode = false;
if (shaderType == Fragment) {
// With built-in shaders hasShaderCode is set to false and all
// metadata is empty, as it is left up to the node to provide a
// built-in default shader and its metadata. However, in case of
// the built-in fragment shader the value for 'source' has to be
// provided and monitored like with an application-provided shader.
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("source");
v.bindPoint = 0;
v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
: QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
m_shaders[shaderType].shaderInfo.variables.append(v);
}
}
const int varCount = m_shaders[shaderType].shaderInfo.variables.count();
m_shaders[shaderType].varData.resize(varCount);
// Reuse signal mappers as much as possible since the mapping is based on
// the index and shader type which are both constant.
if (m_signalMappers[shaderType].count() < varCount)
m_signalMappers[shaderType].resize(varCount);
// Hook up the signals to get notified about changes for properties that
// correspond to variables in the shader. Store also the values.
for (int i = 0; i < varCount; ++i) {
const auto &v(m_shaders[shaderType].shaderInfo.variables.at(i));
QSGShaderEffectNode::VariableData &vd(m_shaders[shaderType].varData[i]);
const bool isSpecial = v.name.startsWith("qt_"); // special names not mapped to properties
if (isSpecial) {
if (v.name == QByteArrayLiteral("qt_Opacity"))
vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
else if (v.name == QByteArrayLiteral("qt_Matrix"))
vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
else if (v.name.startsWith("qt_SubRect_"))
vd.specialType = QSGShaderEffectNode::VariableData::SubRect;
continue;
}
// The value of a property corresponding to a sampler is the source
// item ref, unless there are separate texture objects in which case
// the sampler is ignored (here).
if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
if (texturesSeparate) {
vd.specialType = QSGShaderEffectNode::VariableData::Unused;
continue;
} else {
vd.specialType = QSGShaderEffectNode::VariableData::Source;
}
} else if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
Q_ASSERT(texturesSeparate);
vd.specialType = QSGShaderEffectNode::VariableData::Source;
} else {
vd.specialType = QSGShaderEffectNode::VariableData::None;
}
// Find the property on the ShaderEffect item.
const int propIdx = m_item->metaObject()->indexOfProperty(v.name.constData());
if (propIdx >= 0) {
QMetaProperty mp = m_item->metaObject()->property(propIdx);
if (!mp.hasNotifySignal())
qWarning("ShaderEffect: property '%s' does not have notification method", v.name.constData());
// Have a QSignalMapper that emits mapped() with an index+type on each property change notify signal.
auto &sm(m_signalMappers[shaderType][i]);
if (!sm.mapper) {
sm.mapper = new QSignalMapper;
sm.mapper->setMapping(m_item, i | (shaderType << 16));
}
sm.active = true;
const QByteArray signalName = '2' + mp.notifySignal().methodSignature();
QObject::connect(m_item, signalName, sm.mapper, SLOT(map()));
QObject::connect(sm.mapper, SIGNAL(mapped(int)), this, SLOT(propertyChanged(int)));
} else {
// Do not warn for dynamic properties.
if (!m_item->property(v.name.constData()).isValid())
qWarning("ShaderEffect: '%s' does not have a matching property!", v.name.constData());
}
vd.value = m_item->property(v.name.constData());
if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
if (source) {
if (m_item->window())
QQuickItemPrivate::get(source)->refWindow(m_item->window());
QObject::connect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
}
}
}
}
bool QQuickGenericShaderEffect::sourceIsUnique(QQuickItem *source, Shader typeToSkip, int indexToSkip) const
{
for (int shaderType = 0; shaderType < NShader; ++shaderType) {
for (int idx = 0; idx < m_shaders[shaderType].varData.count(); ++idx) {
if (shaderType != typeToSkip || idx != indexToSkip) {
const auto &vd(m_shaders[shaderType].varData[idx]);
if (vd.specialType == QSGShaderEffectNode::VariableData::Source && qvariant_cast<QObject *>(vd.value) == source)
return false;
}
}
}
return true;
}
void QQuickGenericShaderEffect::propertyChanged(int mappedId)
{
const Shader type = Shader(mappedId >> 16);
const int idx = mappedId & 0xFFFF;
const auto &v(m_shaders[type].shaderInfo.variables[idx]);
auto &vd(m_shaders[type].varData[idx]);
if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
if (source) {
if (m_item->window())
QQuickItemPrivate::get(source)->derefWindow();
// QObject::disconnect() will disconnect all matching connections.
// If the same source has been attached to two separate
// textures/samplers, then changing one of them would trigger both
// to be disconnected. So check first.
if (sourceIsUnique(source, type, idx))
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
}
vd.value = m_item->property(v.name.constData());
source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
if (source) {
// 'source' needs a window to get a scene graph node. It usually gets one through its
// parent, but if the source item is "inline" rather than a reference -- i.e.
// "property variant source: Image { }" instead of "property variant source: foo" -- it
// will not get a parent. In those cases, 'source' should get the window from 'item'.
if (m_item->window())
QQuickItemPrivate::get(source)->refWindow(m_item->window());
QObject::connect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
}
m_dirty |= QSGShaderEffectNode::DirtyShaderTexture;
m_dirtyTextures[type].insert(idx);
} else {
vd.value = m_item->property(v.name.constData());
m_dirty |= QSGShaderEffectNode::DirtyShaderConstant;
m_dirtyConstants[type].insert(idx);
}
m_item->update();
}
void QQuickGenericShaderEffect::sourceDestroyed(QObject *object)
{
for (int shaderType = 0; shaderType < NShader; ++shaderType) {
for (auto &vd : m_shaders[shaderType].varData) {
if (vd.specialType == QSGShaderEffectNode::VariableData::Source && vd.value.canConvert<QObject *>()) {
if (qvariant_cast<QObject *>(vd.value) == object)
vd.value = QVariant();
}
}
}
}
void QQuickGenericShaderEffect::markGeometryDirtyAndUpdate()
{
m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
m_item->update();
}
void QQuickGenericShaderEffect::markGeometryDirtyAndUpdateIfSupportsAtlas()
{
if (m_supportsAtlasTextures)
markGeometryDirtyAndUpdate();
}
QT_END_NAMESPACE

View File

@ -0,0 +1,146 @@
/****************************************************************************
**
** 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 QQUICKGENERICSHADEREFFECT_P_H
#define QQUICKGENERICSHADEREFFECT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtQuick/qquickitem.h>
#include <private/qtquickglobal_p.h>
#include <private/qsgadaptationlayer_p.h>
#include "qquickshadereffect_p.h"
#include "qquickshadereffectmesh_p.h"
QT_BEGIN_NAMESPACE
class QSignalMapper;
class Q_QUICK_PRIVATE_EXPORT QQuickGenericShaderEffect : public QObject
{
Q_OBJECT
public:
QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent = 0);
~QQuickGenericShaderEffect();
QByteArray fragmentShader() const { return m_fragShader; }
void setFragmentShader(const QByteArray &src);
QByteArray vertexShader() const { return m_vertShader; }
void setVertexShader(const QByteArray &src);
bool blending() const { return m_blending; }
void setBlending(bool enable);
QVariant mesh() const;
void setMesh(const QVariant &mesh);
QQuickShaderEffect::CullMode cullMode() const { return m_cullMode; }
void setCullMode(QQuickShaderEffect::CullMode face);
QString log() const;
QQuickShaderEffect::Status status() const;
bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
void setSupportsAtlasTextures(bool supports);
void handleEvent(QEvent *);
void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
void handleComponentComplete();
void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
private slots:
void propertyChanged(int mappedId);
void sourceDestroyed(QObject *object);
void markGeometryDirtyAndUpdate();
void markGeometryDirtyAndUpdateIfSupportsAtlas();
void itemWindowChanged(QQuickWindow *w);
void backendChanged();
private:
QSGGuiThreadShaderEffectManager *shaderEffectManager() const;
enum Shader {
Vertex,
Fragment,
NShader
};
void updateShader(Shader which, const QByteArray &src);
void disconnectSignals(Shader which);
bool sourceIsUnique(QQuickItem *source, Shader typeToSkip, int indexToSkip) const;
QQuickShaderEffect *m_item;
QSize m_meshResolution;
QQuickShaderEffectMesh *m_mesh;
QQuickGridMesh m_defaultMesh;
QQuickShaderEffect::CullMode m_cullMode;
bool m_blending;
bool m_supportsAtlasTextures;
mutable QSGGuiThreadShaderEffectManager *m_mgr;
QByteArray m_fragShader;
QByteArray m_vertShader;
QSGShaderEffectNode::ShaderData m_shaders[NShader];
QSGShaderEffectNode::DirtyShaderFlags m_dirty;
QSet<int> m_dirtyConstants[NShader];
QSet<int> m_dirtyTextures[NShader];
struct SignalMapper {
SignalMapper() : mapper(nullptr), active(false) { }
QSignalMapper *mapper;
bool active;
};
QVector<SignalMapper> m_signalMappers[NShader];
};
QT_END_NAMESPACE
#endif // QQUICKGENERICSHADEREFFECT_P_H

View File

@ -0,0 +1,306 @@
/****************************************************************************
**
** 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 "qquickgraphicsinfo_p.h"
#include "qquickwindow.h"
#include "qquickitem.h"
#include <QtGui/qopenglcontext.h>
QT_BEGIN_NAMESPACE
/*!
\qmltype GraphicsInfo
\instantiates QQuickGraphicsInfo
\inqmlmodule QtQuick
\ingroup qtquick-visual
\since 5.8
\since QtQuick 2.8
\brief Provides information about the used Qt Quick backend
The GraphicsInfo attached type provides information about the scenegraph
backend used to render the contents of the associated window.
If the item to which the properties are attached is not currently
associated with any window, the properties are set to default values. When
the associated window changes, the properties will update.
*/
QQuickGraphicsInfo::QQuickGraphicsInfo(QQuickItem *item)
: QObject(item)
, m_window(0)
, m_api(Unknown)
, m_shaderType(UnknownShadingLanguage)
, m_shaderCompilationType(ShaderCompilationType(0))
, m_shaderSourceType(ShaderSourceType(0))
, m_majorVersion(2)
, m_minorVersion(0)
, m_profile(NoProfile)
, m_renderableType(SurfaceFormatUnspecified)
{
connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(setWindow(QQuickWindow*)));
setWindow(item->window());
}
QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
{
if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
return new QQuickGraphicsInfo(item);
return nullptr;
}
/*!
\qmlproperty enumeration QtQuick::GraphicsInfo::api
This property describes the graphics API that is currently in use.
The possible values are:
\list
\li GraphicsInfo.Unknown - the default value when no active scenegraph is associated with the item
\li GraphicsInfo.Software - Qt Quick's software renderer based on QPainter with the raster paint engine
\li GraphicsInfo.OpenGL - OpenGL or OpenGL ES
\li GraphicsInfo.Direct3D12 - Direct3D 12
\endlist
*/
/*!
\qmlproperty enumeration QtQuick::GraphicsInfo::shaderType
This property contains the shading language supported by the Qt Quick
backend the application is using.
\list
\li GraphicsInfo.UnknownShadingLanguage - Not yet known due to no window and scenegraph associated
\li GraphicsInfo.GLSL - GLSL or GLSL ES
\li GraphicsInfo.HLSL - HLSL
\endlist
\note The value is only up-to-date once the item is associated with a
window and the window's scenegraph has initialized. Bindings relying on the
value have to keep this in mind since the value may change from
GraphicsInfo.UnknownShadingLanguage to the actual value after component
initialization is complete. This is particularly relevant for ShaderEffect
items inside ShaderEffectSource items set as property values.
\since 5.8
\since QtQuick 2.8
\sa shaderCompilationType, shaderSourceType
*/
/*!
\qmlproperty enumeration QtQuick::GraphicsInfo::shaderCompilationType
This property contains a bitmask of the shader compilation approaches
supported by the Qt Quick backend the application is using.
\list
\li GraphicsInfo.RuntimeCompilation
\li GraphicsInfo.OfflineCompilation
\endlist
With OpenGL the value is GraphicsInfo.RuntimeCompilation, which corresponds
to the traditional way of using ShaderEffect. Non-OpenGL backends are
expected to focus more on GraphicsInfo.OfflineCompilation, however.
\note The value is only up-to-date once the item is associated with a
window and the window's scenegraph has initialized. Bindings relying on the
value have to keep this in mind since the value may change from \c 0 to the
actual bitmask after component initialization is complete. This is
particularly relevant for ShaderEffect items inside ShaderEffectSource
items set as property values.
\since 5.8
\since QtQuick 2.8
\sa shaderType, shaderSourceType
*/
/*!
\qmlproperty enumeration QtQuick::GraphicsInfo::shaderSourceType
This property contains a bitmask of the supported ways of providing shader
sources.
\list
\li GraphicsInfo.ShaderSourceString
\li GraphicsInfo.ShaderSourceFile
\li GraphicsInfo.ShaderByteCode
\endlist
With OpenGL the value is GraphicsInfo.ShaderSourceString, which corresponds
to the traditional way of inlining GLSL source code into QML. Other,
non-OpenGL Qt Quick backends may however decide not to support inlined
shader sources, or even shader sources at all. In this case shaders are
expected to be pre-compiled into formats like SPIR-V or D3D shader
bytecode.
\note The value is only up-to-date once the item is associated with a
window and the window's scenegraph has initialized. Bindings relying on the
value have to keep this in mind since the value may change from \c 0 to the
actual bitmask after component initialization is complete. This is
particularly relevant for ShaderEffect items inside ShaderEffectSource
items set as property values.
\since 5.8
\since QtQuick 2.8
\sa shaderType, shaderCompilationType
*/
/*!
\qmlproperty int QtQuick::GraphicsInfo::majorVersion
This property holds the major version of the graphics API in use.
With OpenGL the default version is \c 2.0.
\sa minorVersion, profile
*/
/*!
\qmlproperty int QtQuick::GraphicsInfo::minorVersion
This property holds the minor version of the graphics API in use.
With OpenGL the default version is \c 2.0.
\sa majorVersion, profile
*/
/*!
\qmlproperty enumeration QtQuick::GraphicsInfo::profile
This property holds the configured OpenGL context profile.
The possible values are:
\list
\li GraphicsInfo.NoProfile (default) - OpenGL version is lower than 3.2 or OpenGL is not in use.
\li GraphicsInfo.CoreProfile - Functionality deprecated in OpenGL version 3.0 is not available.
\li GraphicsInfo.CompatibilityProfile - Functionality from earlier OpenGL versions is available.
\endlist
Reusable QML components will typically use this property in bindings in order to
choose between core and non core profile compatible shader sources.
\sa majorVersion, minorVersion, QSurfaceFormat
*/
/*!
\qmlproperty enumeration QtQuick::GraphicsInfo::renderableType
This property holds the renderable type. The value has no meaning for APIs
other than OpenGL.
The possible values are:
\list
\li GraphicsInfo.SurfaceFormatUnspecified (default) - Unspecified rendering method
\li GraphicsInfo.SurfaceFormatOpenGL - Desktop OpenGL or other graphics API
\li GraphicsInfo.SurfaceFormatOpenGLES - OpenGL ES
\endlist
\sa QSurfaceFormat
*/
void QQuickGraphicsInfo::updateInfo()
{
const bool sgReady = m_window && m_window->isSceneGraphInitialized();
if (sgReady) {
QSGRendererInterface *rif = m_window->rendererInterface();
if (rif) {
GraphicsApi newAPI = GraphicsApi(rif->graphicsApi());
if (m_api != newAPI) {
m_api = newAPI;
emit apiChanged();
m_shaderType = ShaderType(rif->shaderType());
emit shaderTypeChanged();
m_shaderCompilationType = ShaderCompilationType(int(rif->shaderCompilationType()));
emit shaderCompilationTypeChanged();
m_shaderSourceType = ShaderSourceType(int(rif->shaderSourceType()));
emit shaderSourceTypeChanged();
}
}
}
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
#ifndef QT_NO_OPENGL
if (sgReady) {
QOpenGLContext *context = m_window->openglContext();
if (context)
format = context->format();
}
#endif
if (m_majorVersion != format.majorVersion()) {
m_majorVersion = format.majorVersion();
emit majorVersionChanged();
}
if (m_minorVersion != format.minorVersion()) {
m_minorVersion = format.minorVersion();
emit minorVersionChanged();
}
ContextProfile profile = static_cast<ContextProfile>(format.profile());
if (m_profile != profile) {
m_profile = profile;
emit profileChanged();
}
RenderableType renderableType = static_cast<RenderableType>(format.renderableType());
if (m_renderableType != renderableType) {
m_renderableType = renderableType;
emit renderableTypeChanged();
}
}
void QQuickGraphicsInfo::setWindow(QQuickWindow *window)
{
if (m_window != window) {
if (m_window) {
disconnect(m_window, SIGNAL(sceneGraphInitialized()), this, SLOT(updateInfo()));
disconnect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(updateInfo()));
}
if (window) {
connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(updateInfo()));
connect(window, SIGNAL(sceneGraphInvalidated()), this, SLOT(updateInfo()));
}
m_window = window;
}
updateInfo();
}
QT_END_NAMESPACE

View File

@ -0,0 +1,166 @@
/****************************************************************************
**
** 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 QQUICKGRAPHICSINFO_P_H
#define QQUICKGRAPHICSINFO_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtQml/qqml.h>
#include <QtGui/qsurfaceformat.h>
#include <QtQuick/qsgrendererinterface.h>
QT_BEGIN_NAMESPACE
class QQuickItem;
class QQuickWindow;
class QQuickGraphicsInfo : public QObject
{
Q_OBJECT
Q_PROPERTY(GraphicsApi api READ api NOTIFY apiChanged FINAL)
Q_PROPERTY(ShaderType shaderType READ shaderType NOTIFY shaderTypeChanged FINAL)
Q_PROPERTY(ShaderCompilationType shaderCompilationType READ shaderCompilationType NOTIFY shaderCompilationTypeChanged FINAL)
Q_PROPERTY(ShaderSourceType shaderSourceType READ shaderSourceType NOTIFY shaderSourceTypeChanged FINAL)
Q_PROPERTY(int majorVersion READ majorVersion NOTIFY majorVersionChanged FINAL)
Q_PROPERTY(int minorVersion READ minorVersion NOTIFY minorVersionChanged FINAL)
Q_PROPERTY(ContextProfile profile READ profile NOTIFY profileChanged FINAL)
Q_PROPERTY(RenderableType renderableType READ renderableType NOTIFY renderableTypeChanged FINAL)
public:
enum GraphicsApi {
Unknown = QSGRendererInterface::Unknown,
Software = QSGRendererInterface::Software,
OpenGL = QSGRendererInterface::OpenGL,
Direct3D12 = QSGRendererInterface::Direct3D12
};
Q_ENUM(GraphicsApi)
enum ShaderType {
UnknownShadingLanguage = QSGRendererInterface::UnknownShadingLanguage,
GLSL = QSGRendererInterface::GLSL,
HLSL = QSGRendererInterface::HLSL
};
Q_ENUM(ShaderType)
enum ShaderCompilationType {
RuntimeCompilation = QSGRendererInterface::RuntimeCompilation,
OfflineCompilation = QSGRendererInterface::OfflineCompilation
};
Q_ENUM(ShaderCompilationType)
enum ShaderSourceType {
ShaderSourceString = QSGRendererInterface::ShaderSourceString,
ShaderSourceFile = QSGRendererInterface::ShaderSourceFile,
ShaderByteCode = QSGRendererInterface::ShaderByteCode
};
Q_ENUM(ShaderSourceType)
enum ContextProfile {
NoProfile = QSurfaceFormat::NoProfile,
CoreProfile = QSurfaceFormat::CoreProfile,
CompatibilityProfile = QSurfaceFormat::CompatibilityProfile
};
Q_ENUM(ContextProfile)
enum RenderableType {
SurfaceFormatUnspecified = QSurfaceFormat::DefaultRenderableType,
SurfaceFormatOpenGL = QSurfaceFormat::OpenGL,
SurfaceFormatOpenGLES = QSurfaceFormat::OpenGLES
};
Q_ENUM(RenderableType)
QQuickGraphicsInfo(QQuickItem *item = 0);
static QQuickGraphicsInfo *qmlAttachedProperties(QObject *object);
GraphicsApi api() const { return m_api; }
ShaderType shaderType() const { return m_shaderType; }
ShaderCompilationType shaderCompilationType() const { return m_shaderCompilationType; }
ShaderSourceType shaderSourceType() const { return m_shaderSourceType; }
int majorVersion() const { return m_majorVersion; }
int minorVersion() const { return m_minorVersion; }
ContextProfile profile() const { return m_profile; }
RenderableType renderableType() const { return m_renderableType; }
Q_SIGNALS:
void apiChanged();
void shaderTypeChanged();
void shaderCompilationTypeChanged();
void shaderSourceTypeChanged();
void majorVersionChanged();
void minorVersionChanged();
void profileChanged();
void renderableTypeChanged();
private Q_SLOTS:
void updateInfo();
void setWindow(QQuickWindow *window);
private:
QPointer<QQuickWindow> m_window;
GraphicsApi m_api;
ShaderType m_shaderType;
ShaderCompilationType m_shaderCompilationType;
ShaderSourceType m_shaderSourceType;
int m_majorVersion;
int m_minorVersion;
ContextProfile m_profile;
RenderableType m_renderableType;
};
QT_END_NAMESPACE
QML_DECLARE_TYPEINFO(QQuickGraphicsInfo, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKGRAPHICSINFO_P_H

View File

@ -78,7 +78,6 @@
#include <QtCore/qelapsedtimer.h>
#include <QtQuick/private/qquickshadereffectsource_p.h>
#include <QtQuick/private/qquickshadereffect_p.h>
QT_BEGIN_NAMESPACE

View File

@ -240,8 +240,7 @@ void QQuickItemGrabResult::render()
return;
d->texture->setRect(QRectF(0, d->itemSize.height(), d->itemSize.width(), -d->itemSize.height()));
QSGContext *sg = QSGRenderContext::from(QOpenGLContext::currentContext())->sceneGraphContext();
const QSize minSize = sg->minimumFBOSize();
const QSize minSize = QQuickWindowPrivate::get(d->window.data())->context->sceneGraphContext()->minimumFBOSize();
d->texture->setSize(QSize(qMax(minSize.width(), d->textureSize.width()),
qMax(minSize.height(), d->textureSize.height())));
d->texture->scheduleUpdate();

View File

@ -41,7 +41,6 @@
#include "qquickitem.h"
#include "qquickitem_p.h"
#include "qquickitemgrabresult.h"
#include "qquickevents_p_p.h"
#include "qquickrectangle_p.h"
#include "qquickfocusscope_p.h"
@ -70,18 +69,23 @@
#include "qquicktranslate_p.h"
#include "qquickstateoperations_p.h"
#include "qquickitemanimation_p.h"
#include <private/qquickshadereffect_p.h>
#include <QtQuick/private/qquickshadereffectsource_p.h>
//#include <private/qquickpincharea_p.h>
#include <QtQuick/private/qquickcanvasitem_p.h>
#include <QtQuick/private/qquickcontext2d_p.h>
#include "qquicksprite_p.h"
#include "qquickspritesequence_p.h"
#include "qquickanimatedsprite_p.h"
# include "qquickitemgrabresult.h"
#ifndef QT_NO_OPENGL
# include "qquicksprite_p.h"
# include "qquickspritesequence_p.h"
# include "qquickanimatedsprite_p.h"
# include "qquickopenglinfo_p.h"
#endif
#include "qquickgraphicsinfo_p.h"
#include "qquickshadereffect_p.h"
#include "qquickshadereffectmesh_p.h"
#include "qquickdrag_p.h"
#include "qquickdroparea_p.h"
#include "qquickmultipointtoucharea_p.h"
#include "qquickopenglinfo_p.h"
#include <private/qqmlmetatype_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
@ -178,7 +182,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTextInput,2>(uri,2,2,"TextInput");
qmlRegisterType<QQuickTextInput,3>(uri,2,4,"TextInput");
qmlRegisterType<QQuickViewSection>(uri,major,minor,"ViewSection");
qmlRegisterType<QQuickItemGrabResult>();
qmlRegisterType<QQuickItemLayer>();
qmlRegisterType<QQuickAnchors>();
@ -207,20 +210,19 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPinch>(uri,major,minor,"Pinch");
qmlRegisterType<QQuickPinchEvent>();
qmlRegisterType<QQuickShaderEffect>("QtQuick", 2, 0, "ShaderEffect");
qmlRegisterType<QQuickShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource");
qmlRegisterUncreatableType<QQuickShaderEffectMesh>("QtQuick", 2, 0, "ShaderEffectMesh", QQuickShaderEffectMesh::tr("Cannot create instance of abstract class ShaderEffectMesh."));
qmlRegisterType<QQuickGridMesh>("QtQuick", 2, 0, "GridMesh");
qmlRegisterType<QQuickBorderImageMesh>("QtQuick", 2, 8, "BorderImageMesh");
qmlRegisterType<QQuickShaderEffect>("QtQuick", 2, 0, "ShaderEffect");
qmlRegisterUncreatableType<QQuickPaintedItem>("QtQuick", 2, 0, "PaintedItem", QQuickPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
qmlRegisterType<QQuickCanvasItem>("QtQuick", 2, 0, "Canvas");
#ifndef QT_NO_OPENGL
qmlRegisterType<QQuickSprite>("QtQuick", 2, 0, "Sprite");
qmlRegisterType<QQuickAnimatedSprite>("QtQuick", 2, 0, "AnimatedSprite");
qmlRegisterType<QQuickSpriteSequence>("QtQuick", 2, 0, "SpriteSequence");
#endif
qmlRegisterType<QQuickParentChange>(uri, major, minor,"ParentChange");
qmlRegisterType<QQuickAnchorChanges>(uri, major, minor,"AnchorChanges");
qmlRegisterType<QQuickAnchorSet>();
@ -263,8 +265,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickListView, 2>(uri, 2, 4, "ListView");
qmlRegisterType<QQuickMouseArea, 1>(uri, 2, 4, "MouseArea");
qmlRegisterType<QQuickShaderEffect, 1>(uri, 2, 4, "ShaderEffect");
qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
#ifndef QT_NO_OPENGL
qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
#endif
qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea");
qmlRegisterType<QQuickImage, 2>(uri, 2, 5,"Image");
qmlRegisterType<QQuickMouseArea, 2>(uri, 2, 5, "MouseArea");
@ -289,6 +293,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPathView, 7>(uri, 2, 7, "PathView");
qmlRegisterUncreatableType<QQuickMouseEvent, 7>(uri, 2, 7, nullptr, QQuickMouseEvent::tr("MouseEvent is only available within handlers in MouseArea"));
qmlRegisterUncreatableType<QQuickGraphicsInfo>(uri, 2, 8,"GraphicsInfo", QQuickGraphicsInfo::tr("GraphicsInfo is only available via attached properties"));
qmlRegisterType<QQuickBorderImageMesh>("QtQuick", 2, 8, "BorderImageMesh");
}
static void initResources()

View File

@ -61,6 +61,10 @@ QT_BEGIN_NAMESPACE
format. When it becomes associated with a surface, all properties
will update.
\deprecated
\warning This type is deprecated. Use GraphicsInfo instead.
\sa ShaderEffect
*/
QQuickOpenGLInfo::QQuickOpenGLInfo(QQuickItem *item)

View File

@ -0,0 +1,862 @@
/****************************************************************************
**
** 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 <private/qquickopenglshadereffect_p.h>
#include <QtQuick/qsgmaterial.h>
#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include "qquickitem_p.h"
#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/qsgtextureprovider.h>
#include "qquickwindow.h"
#include "qquickimage_p.h"
#include "qquickshadereffectsource_p.h"
#include "qquickshadereffectmesh_p.h"
#include <QtCore/qsignalmapper.h>
QT_BEGIN_NAMESPACE
namespace {
enum VariableQualifier {
AttributeQualifier,
UniformQualifier
};
inline bool qt_isalpha(char c)
{
char ch = c | 0x20;
return (ch >= 'a' && ch <= 'z') || c == '_';
}
inline bool qt_isalnum(char c)
{
return qt_isalpha(c) || (c >= '0' && c <= '9');
}
inline bool qt_isspace(char c)
{
return c == ' ' || (c >= 0x09 && c <= 0x0d);
}
// Returns -1 if not found, returns index to first character after the name if found.
int qt_search_for_variable(const char *s, int length, int index, VariableQualifier &decl,
int &typeIndex, int &typeLength,
int &nameIndex, int &nameLength,
QQuickOpenGLShaderEffectCommon::Key::ShaderType shaderType)
{
enum Identifier {
QualifierIdentifier, // Base state
PrecisionIdentifier,
TypeIdentifier,
NameIdentifier
};
Identifier expected = QualifierIdentifier;
bool compilerDirectiveExpected = index == 0;
while (index < length) {
// Skip whitespace.
while (qt_isspace(s[index])) {
compilerDirectiveExpected |= s[index] == '\n';
++index;
}
if (qt_isalpha(s[index])) {
// Read identifier.
int idIndex = index;
++index;
while (qt_isalnum(s[index]))
++index;
int idLength = index - idIndex;
const int attrLen = sizeof("attribute") - 1;
const int inLen = sizeof("in") - 1;
const int uniLen = sizeof("uniform") - 1;
const int loLen = sizeof("lowp") - 1;
const int medLen = sizeof("mediump") - 1;
const int hiLen = sizeof("highp") - 1;
switch (expected) {
case QualifierIdentifier:
if (idLength == attrLen && qstrncmp("attribute", s + idIndex, attrLen) == 0) {
decl = AttributeQualifier;
expected = PrecisionIdentifier;
} else if (shaderType == QQuickOpenGLShaderEffectCommon::Key::VertexShader
&& idLength == inLen && qstrncmp("in", s + idIndex, inLen) == 0) {
decl = AttributeQualifier;
expected = PrecisionIdentifier;
} else if (idLength == uniLen && qstrncmp("uniform", s + idIndex, uniLen) == 0) {
decl = UniformQualifier;
expected = PrecisionIdentifier;
}
break;
case PrecisionIdentifier:
if ((idLength == loLen && qstrncmp("lowp", s + idIndex, loLen) == 0)
|| (idLength == medLen && qstrncmp("mediump", s + idIndex, medLen) == 0)
|| (idLength == hiLen && qstrncmp("highp", s + idIndex, hiLen) == 0))
{
expected = TypeIdentifier;
break;
}
// Fall through.
case TypeIdentifier:
typeIndex = idIndex;
typeLength = idLength;
expected = NameIdentifier;
break;
case NameIdentifier:
nameIndex = idIndex;
nameLength = idLength;
return index; // Attribute or uniform declaration found. Return result.
default:
break;
}
} else if (s[index] == '#' && compilerDirectiveExpected) {
// Skip compiler directives.
++index;
while (index < length && (s[index] != '\n' || s[index - 1] == '\\'))
++index;
} else if (s[index] == '/' && s[index + 1] == '/') {
// Skip comments.
index += 2;
while (index < length && s[index] != '\n')
++index;
} else if (s[index] == '/' && s[index + 1] == '*') {
// Skip comments.
index += 2;
while (index < length && (s[index] != '*' || s[index + 1] != '/'))
++index;
if (index < length)
index += 2; // Skip star-slash.
} else {
expected = QualifierIdentifier;
++index;
}
compilerDirectiveExpected = false;
}
return -1;
}
}
QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
{
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
qDeleteAll(signalMappers[shaderType]);
}
void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
{
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (signalMappers[shaderType].at(i) == 0)
continue;
const UniformData &d = uniformData[shaderType].at(i);
QSignalMapper *mapper = signalMappers[shaderType].at(i);
QObject::disconnect(item, 0, mapper, SLOT(map()));
QObject::disconnect(mapper, SIGNAL(mapped(int)), host, SLOT(propertyChanged(int)));
if (d.specialType == UniformData::Sampler) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
if (item->window())
QQuickItemPrivate::get(source)->derefWindow();
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
}
}
}
void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
{
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (signalMappers[shaderType].at(i) == 0)
continue;
const UniformData &d = uniformData[shaderType].at(i);
int pi = item->metaObject()->indexOfProperty(d.name.constData());
if (pi >= 0) {
QMetaProperty mp = item->metaObject()->property(pi);
if (!mp.hasNotifySignal())
qWarning("QQuickOpenGLShaderEffect: property '%s' does not have notification method!", d.name.constData());
const QByteArray signalName = '2' + mp.notifySignal().methodSignature();
QSignalMapper *mapper = signalMappers[shaderType].at(i);
QObject::connect(item, signalName, mapper, SLOT(map()));
QObject::connect(mapper, SIGNAL(mapped(int)), host, SLOT(propertyChanged(int)));
} else {
// If the source is set via a dynamic property, like the layer is, then we need this
// check to disable the warning.
if (!item->property(d.name.constData()).isValid())
qWarning("QQuickOpenGLShaderEffect: '%s' does not have a matching property!", d.name.constData());
}
if (d.specialType == UniformData::Sampler) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
if (item->window())
QQuickItemPrivate::get(source)->refWindow(item->window());
QObject::connect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
}
}
}
void QQuickOpenGLShaderEffectCommon::updateParseLog(bool ignoreAttributes)
{
parseLog.clear();
if (!ignoreAttributes) {
if (!attributes.contains(qtPositionAttributeName())) {
parseLog += QLatin1String("Warning: Missing reference to \'");
parseLog += QLatin1String(qtPositionAttributeName());
parseLog += QLatin1String("\'.\n");
}
if (!attributes.contains(qtTexCoordAttributeName())) {
parseLog += QLatin1String("Warning: Missing reference to \'");
parseLog += QLatin1String(qtTexCoordAttributeName());
parseLog += QLatin1String("\'.\n");
}
}
bool respectsMatrix = false;
bool respectsOpacity = false;
for (int i = 0; i < uniformData[Key::VertexShader].size(); ++i)
respectsMatrix |= uniformData[Key::VertexShader].at(i).specialType == UniformData::Matrix;
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i)
respectsOpacity |= uniformData[shaderType].at(i).specialType == UniformData::Opacity;
}
if (!respectsMatrix)
parseLog += QLatin1String("Warning: Vertex shader is missing reference to \'qt_Matrix\'.\n");
if (!respectsOpacity)
parseLog += QLatin1String("Warning: Shaders are missing reference to \'qt_Opacity\'.\n");
}
void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code)
{
int index = 0;
int typeIndex = -1;
int typeLength = 0;
int nameIndex = -1;
int nameLength = 0;
const char *s = code.constData();
VariableQualifier decl = AttributeQualifier;
while ((index = qt_search_for_variable(s, code.size(), index, decl, typeIndex, typeLength,
nameIndex, nameLength, shaderType)) != -1)
{
if (decl == AttributeQualifier) {
if (shaderType == Key::VertexShader)
attributes.append(QByteArray(s + nameIndex, nameLength));
} else {
Q_ASSERT(decl == UniformQualifier);
const int sampLen = sizeof("sampler2D") - 1;
const int opLen = sizeof("qt_Opacity") - 1;
const int matLen = sizeof("qt_Matrix") - 1;
const int srLen = sizeof("qt_SubRect_") - 1;
UniformData d;
QSignalMapper *mapper = 0;
d.name = QByteArray(s + nameIndex, nameLength);
if (nameLength == opLen && qstrncmp("qt_Opacity", s + nameIndex, opLen) == 0) {
d.specialType = UniformData::Opacity;
} else if (nameLength == matLen && qstrncmp("qt_Matrix", s + nameIndex, matLen) == 0) {
d.specialType = UniformData::Matrix;
} else if (nameLength > srLen && qstrncmp("qt_SubRect_", s + nameIndex, srLen) == 0) {
d.specialType = UniformData::SubRect;
} else {
mapper = new QSignalMapper;
mapper->setMapping(item, uniformData[shaderType].size() | (shaderType << 16));
d.value = item->property(d.name.constData());
bool sampler = typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0;
d.specialType = sampler ? UniformData::Sampler : UniformData::None;
}
uniformData[shaderType].append(d);
signalMappers[shaderType].append(mapper);
}
}
}
void QQuickOpenGLShaderEffectCommon::updateShader(QQuickItem *item, Key::ShaderType shaderType)
{
disconnectPropertySignals(item, shaderType);
qDeleteAll(signalMappers[shaderType]);
uniformData[shaderType].clear();
signalMappers[shaderType].clear();
if (shaderType == Key::VertexShader)
attributes.clear();
const QByteArray &code = source.sourceCode[shaderType];
if (code.isEmpty()) {
// Optimize for default code.
if (shaderType == Key::VertexShader) {
attributes.append(QByteArray(qtPositionAttributeName()));
attributes.append(QByteArray(qtTexCoordAttributeName()));
UniformData d;
d.name = "qt_Matrix";
d.specialType = UniformData::Matrix;
uniformData[Key::VertexShader].append(d);
signalMappers[Key::VertexShader].append(0);
} else if (shaderType == Key::FragmentShader) {
UniformData d;
d.name = "qt_Opacity";
d.specialType = UniformData::Opacity;
uniformData[Key::FragmentShader].append(d);
signalMappers[Key::FragmentShader].append(0);
QSignalMapper *mapper = new QSignalMapper;
mapper->setMapping(item, 1 | (Key::FragmentShader << 16));
const char *sourceName = "source";
d.name = sourceName;
d.value = item->property(sourceName);
d.specialType = UniformData::Sampler;
uniformData[Key::FragmentShader].append(d);
signalMappers[Key::FragmentShader].append(mapper);
}
} else {
lookThroughShaderCode(item, shaderType, code);
}
connectPropertySignals(item, shaderType);
}
void QQuickOpenGLShaderEffectCommon::updateMaterial(QQuickOpenGLShaderEffectNode *node,
QQuickOpenGLShaderEffectMaterial *material,
bool updateUniforms, bool updateUniformValues,
bool updateTextureProviders)
{
if (updateUniforms) {
for (int i = 0; i < material->textureProviders.size(); ++i) {
QSGTextureProvider *t = material->textureProviders.at(i);
if (t) {
QObject::disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
QObject::disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
}
}
// First make room in the textureProviders array. Set to proper value further down.
int textureProviderCount = 0;
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (uniformData[shaderType].at(i).specialType == UniformData::Sampler)
++textureProviderCount;
}
material->uniforms[shaderType] = uniformData[shaderType];
}
material->textureProviders.fill(0, textureProviderCount);
updateUniformValues = false;
updateTextureProviders = true;
}
if (updateUniformValues) {
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
Q_ASSERT(uniformData[shaderType].size() == material->uniforms[shaderType].size());
for (int i = 0; i < uniformData[shaderType].size(); ++i)
material->uniforms[shaderType][i].value = uniformData[shaderType].at(i).value;
}
}
if (updateTextureProviders) {
int index = 0;
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
const UniformData &d = uniformData[shaderType].at(i);
if (d.specialType != UniformData::Sampler)
continue;
QSGTextureProvider *oldProvider = material->textureProviders.at(index);
QSGTextureProvider *newProvider = 0;
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source && source->isTextureProvider())
newProvider = source->textureProvider();
if (newProvider != oldProvider) {
if (oldProvider) {
QObject::disconnect(oldProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
QObject::disconnect(oldProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
}
if (newProvider) {
Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
"QQuickOpenGLShaderEffect::updatePaintNode",
"Texture provider must belong to the rendering thread");
QObject::connect(newProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
} else {
const char *typeName = source ? source->metaObject()->className() : d.value.typeName();
qWarning("ShaderEffect: Property '%s' is not assigned a valid texture provider (%s).",
d.name.constData(), typeName);
}
material->textureProviders[index] = newProvider;
}
++index;
}
}
Q_ASSERT(index == material->textureProviders.size());
}
}
void QQuickOpenGLShaderEffectCommon::updateWindow(QQuickWindow *window)
{
// See comment in QQuickOpenGLShaderEffectCommon::propertyChanged().
if (window) {
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
const UniformData &d = uniformData[shaderType].at(i);
if (d.specialType == UniformData::Sampler) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source)
QQuickItemPrivate::get(source)->refWindow(window);
}
}
}
} else {
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
const UniformData &d = uniformData[shaderType].at(i);
if (d.specialType == UniformData::Sampler) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source)
QQuickItemPrivate::get(source)->derefWindow();
}
}
}
}
}
void QQuickOpenGLShaderEffectCommon::sourceDestroyed(QObject *object)
{
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
UniformData &d = uniformData[shaderType][i];
if (d.specialType == UniformData::Sampler && d.value.canConvert<QObject *>()) {
if (qvariant_cast<QObject *>(d.value) == object)
d.value = QVariant();
}
}
}
}
static bool qquick_uniqueInUniformData(QQuickItem *source, const QVector<QQuickOpenGLShaderEffectMaterial::UniformData> *uniformData, int typeToSkip, int indexToSkip)
{
for (int s=0; s<QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++s) {
for (int i=0; i<uniformData[s].size(); ++i) {
if (s == typeToSkip && i == indexToSkip)
continue;
const QQuickOpenGLShaderEffectMaterial::UniformData &d = uniformData[s][i];
if (d.specialType == QQuickOpenGLShaderEffectMaterial::UniformData::Sampler && qvariant_cast<QObject *>(d.value) == source)
return false;
}
}
return true;
}
void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
bool *textureProviderChanged)
{
Key::ShaderType shaderType = Key::ShaderType(mappedId >> 16);
int index = mappedId & 0xffff;
UniformData &d = uniformData[shaderType][index];
if (d.specialType == UniformData::Sampler) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
if (item->window())
QQuickItemPrivate::get(source)->derefWindow();
// QObject::disconnect() will disconnect all matching connections. If the same
// source has been attached to two separate samplers, then changing one of them
// would trigger both to be disconnected. Without the connection we'll end up
// with a dangling pointer in the uniformData.
if (qquick_uniqueInUniformData(source, uniformData, shaderType, index))
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
d.value = item->property(d.name.constData());
source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
// 'source' needs a window to get a scene graph node. It usually gets one through its
// parent, but if the source item is "inline" rather than a reference -- i.e.
// "property variant source: Image { }" instead of "property variant source: foo" -- it
// will not get a parent. In those cases, 'source' should get the window from 'item'.
if (item->window())
QQuickItemPrivate::get(source)->refWindow(item->window());
QObject::connect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
if (textureProviderChanged)
*textureProviderChanged = true;
} else {
d.value = item->property(d.name.constData());
if (textureProviderChanged)
*textureProviderChanged = false;
}
}
QQuickOpenGLShaderEffect::QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent)
: QObject(parent)
, m_item(item)
, m_meshResolution(1, 1)
, m_mesh(0)
, m_cullMode(QQuickShaderEffect::NoCulling)
, m_status(QQuickShaderEffect::Uncompiled)
, m_common(this)
, m_blending(true)
, m_dirtyUniforms(true)
, m_dirtyUniformValues(true)
, m_dirtyTextureProviders(true)
, m_dirtyProgram(true)
, m_dirtyParseLog(true)
, m_dirtyMesh(true)
, m_dirtyGeometry(true)
, m_customVertexShader(false)
, m_supportsAtlasTextures(false)
{
}
QQuickOpenGLShaderEffect::~QQuickOpenGLShaderEffect()
{
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
m_common.disconnectPropertySignals(m_item, Key::ShaderType(shaderType));
}
void QQuickOpenGLShaderEffect::setFragmentShader(const QByteArray &code)
{
if (m_common.source.sourceCode[Key::FragmentShader].constData() == code.constData())
return;
m_common.source.sourceCode[Key::FragmentShader] = code;
m_dirtyProgram = true;
m_dirtyParseLog = true;
if (m_item->isComponentComplete())
m_common.updateShader(m_item, Key::FragmentShader);
m_item->update();
if (m_status != QQuickShaderEffect::Uncompiled) {
m_status = QQuickShaderEffect::Uncompiled;
emit m_item->statusChanged();
}
emit m_item->fragmentShaderChanged();
}
void QQuickOpenGLShaderEffect::setVertexShader(const QByteArray &code)
{
if (m_common.source.sourceCode[Key::VertexShader].constData() == code.constData())
return;
m_common.source.sourceCode[Key::VertexShader] = code;
m_dirtyProgram = true;
m_dirtyParseLog = true;
m_customVertexShader = true;
if (m_item->isComponentComplete())
m_common.updateShader(m_item, Key::VertexShader);
m_item->update();
if (m_status != QQuickShaderEffect::Uncompiled) {
m_status = QQuickShaderEffect::Uncompiled;
emit m_item->statusChanged();
}
emit m_item->vertexShaderChanged();
}
void QQuickOpenGLShaderEffect::setBlending(bool enable)
{
if (blending() == enable)
return;
m_blending = enable;
m_item->update();
emit m_item->blendingChanged();
}
QVariant QQuickOpenGLShaderEffect::mesh() const
{
return m_mesh ? qVariantFromValue(static_cast<QObject *>(m_mesh))
: qVariantFromValue(m_meshResolution);
}
void QQuickOpenGLShaderEffect::setMesh(const QVariant &mesh)
{
QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
if (newMesh && newMesh == m_mesh)
return;
if (m_mesh)
disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
m_mesh = newMesh;
if (m_mesh) {
connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(updateGeometry()));
} else {
if (mesh.canConvert<QSize>()) {
m_meshResolution = mesh.toSize();
} else {
QList<QByteArray> res = mesh.toByteArray().split('x');
bool ok = res.size() == 2;
if (ok) {
int w = res.at(0).toInt(&ok);
if (ok) {
int h = res.at(1).toInt(&ok);
if (ok)
m_meshResolution = QSize(w, h);
}
}
if (!ok)
qWarning("ShaderEffect: mesh property must be size or object deriving from QQuickShaderEffectMesh.");
}
m_defaultMesh.setResolution(m_meshResolution);
}
m_dirtyMesh = true;
m_dirtyParseLog = true;
m_item->update();
emit m_item->meshChanged();
}
void QQuickOpenGLShaderEffect::setCullMode(QQuickShaderEffect::CullMode face)
{
if (face == m_cullMode)
return;
m_cullMode = face;
m_item->update();
emit m_item->cullModeChanged();
}
void QQuickOpenGLShaderEffect::setSupportsAtlasTextures(bool supports)
{
if (supports == m_supportsAtlasTextures)
return;
m_supportsAtlasTextures = supports;
updateGeometry();
emit m_item->supportsAtlasTexturesChanged();
}
QString QQuickOpenGLShaderEffect::parseLog()
{
if (m_dirtyParseLog) {
m_common.updateParseLog(m_mesh != 0);
m_dirtyParseLog = false;
}
return m_common.parseLog;
}
void QQuickOpenGLShaderEffect::handleEvent(QEvent *event)
{
if (event->type() == QEvent::DynamicPropertyChange) {
QDynamicPropertyChangeEvent *e = static_cast<QDynamicPropertyChangeEvent *>(event);
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < m_common.uniformData[shaderType].size(); ++i) {
if (m_common.uniformData[shaderType].at(i).name == e->propertyName()) {
bool textureProviderChanged;
m_common.propertyChanged(m_item, (shaderType << 16) | i, &textureProviderChanged);
m_dirtyTextureProviders |= textureProviderChanged;
m_dirtyUniformValues = true;
m_item->update();
}
}
}
}
}
void QQuickOpenGLShaderEffect::updateGeometry()
{
m_dirtyGeometry = true;
m_item->update();
}
void QQuickOpenGLShaderEffect::updateGeometryIfAtlased()
{
if (m_supportsAtlasTextures)
updateGeometry();
}
void QQuickOpenGLShaderEffect::updateLogAndStatus(const QString &log, int status)
{
m_log = parseLog() + log;
m_status = QQuickShaderEffect::Status(status);
emit m_item->logChanged();
emit m_item->statusChanged();
}
void QQuickOpenGLShaderEffect::sourceDestroyed(QObject *object)
{
m_common.sourceDestroyed(object);
}
void QQuickOpenGLShaderEffect::propertyChanged(int mappedId)
{
bool textureProviderChanged;
m_common.propertyChanged(m_item, mappedId, &textureProviderChanged);
m_dirtyTextureProviders |= textureProviderChanged;
m_dirtyUniformValues = true;
m_item->update();
}
void QQuickOpenGLShaderEffect::handleGeometryChanged(const QRectF &, const QRectF &)
{
m_dirtyGeometry = true;
}
QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
{
QQuickOpenGLShaderEffectNode *node = static_cast<QQuickOpenGLShaderEffectNode *>(oldNode);
// In the case of zero-size or a bad vertex shader, don't try to create a node...
if (m_common.attributes.isEmpty() || m_item->width() <= 0 || m_item->height() <= 0) {
if (node)
delete node;
return 0;
}
if (!node) {
node = new QQuickOpenGLShaderEffectNode;
node->setMaterial(new QQuickOpenGLShaderEffectMaterial(node));
node->setFlag(QSGNode::OwnsMaterial, true);
m_dirtyProgram = true;
m_dirtyUniforms = true;
m_dirtyGeometry = true;
connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int)));
connect(node, &QQuickOpenGLShaderEffectNode::dirtyTexture,
this, &QQuickOpenGLShaderEffect::updateGeometryIfAtlased);
}
QQuickOpenGLShaderEffectMaterial *material = static_cast<QQuickOpenGLShaderEffectMaterial *>(node->material());
// Update blending
if (bool(material->flags() & QSGMaterial::Blending) != m_blending) {
material->setFlag(QSGMaterial::Blending, m_blending);
node->markDirty(QSGNode::DirtyMaterial);
}
if (int(material->cullMode) != int(m_cullMode)) {
material->cullMode = QQuickShaderEffect::CullMode(m_cullMode);
node->markDirty(QSGNode::DirtyMaterial);
}
if (m_dirtyProgram) {
Key s = m_common.source;
QSGShaderSourceBuilder builder;
if (s.sourceCode[Key::FragmentShader].isEmpty()) {
builder.appendSourceFile(QStringLiteral(":/qt-project.org/items/shaders/shadereffect.frag"));
s.sourceCode[Key::FragmentShader] = builder.source();
builder.clear();
}
if (s.sourceCode[Key::VertexShader].isEmpty()) {
builder.appendSourceFile(QStringLiteral(":/qt-project.org/items/shaders/shadereffect.vert"));
s.sourceCode[Key::VertexShader] = builder.source();
}
material->setProgramSource(s);
material->attributes = m_common.attributes;
node->markDirty(QSGNode::DirtyMaterial);
m_dirtyProgram = false;
m_dirtyUniforms = true;
}
if (m_dirtyUniforms || m_dirtyUniformValues || m_dirtyTextureProviders) {
m_common.updateMaterial(node, material, m_dirtyUniforms, m_dirtyUniformValues,
m_dirtyTextureProviders);
node->markDirty(QSGNode::DirtyMaterial);
m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
}
QRectF srcRect(0, 0, 1, 1);
bool geometryUsesTextureSubRect = false;
if (m_supportsAtlasTextures && material->textureProviders.size() == 1) {
QSGTextureProvider *provider = material->textureProviders.at(0);
if (provider->texture()) {
srcRect = provider->texture()->normalizedTextureSubRect();
geometryUsesTextureSubRect = true;
}
}
if (bool(material->flags() & QSGMaterial::RequiresFullMatrix) != m_customVertexShader) {
material->setFlag(QSGMaterial::RequiresFullMatrix, m_customVertexShader);
node->markDirty(QSGNode::DirtyMaterial);
}
if (material->geometryUsesTextureSubRect != geometryUsesTextureSubRect) {
material->geometryUsesTextureSubRect = geometryUsesTextureSubRect;
node->markDirty(QSGNode::DirtyMaterial);
}
if (m_dirtyMesh) {
node->setGeometry(0);
m_dirtyMesh = false;
m_dirtyGeometry = true;
}
if (m_dirtyGeometry) {
node->setFlag(QSGNode::OwnsGeometry, false);
QSGGeometry *geometry = node->geometry();
QRectF rect(0, 0, m_item->width(), m_item->height());
QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
int posIndex = 0;
if (!mesh->validateAttributes(m_common.attributes, &posIndex)) {
QString log = mesh->log();
if (!log.isNull()) {
m_log = parseLog();
m_log += QLatin1String("*** Mesh ***\n");
m_log += log;
m_status = QQuickShaderEffect::Error;
emit m_item->logChanged();
emit m_item->statusChanged();
}
delete node;
return 0;
}
geometry = mesh->updateGeometry(geometry, m_common.attributes.count(), posIndex, srcRect, rect);
node->setGeometry(geometry);
node->setFlag(QSGNode::OwnsGeometry, true);
m_dirtyGeometry = false;
}
return node;
}
void QQuickOpenGLShaderEffect::handleComponentComplete()
{
m_common.updateShader(m_item, Key::VertexShader);
m_common.updateShader(m_item, Key::FragmentShader);
}
void QQuickOpenGLShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
{
if (change == QQuickItem::ItemSceneChange)
m_common.updateWindow(value.window);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,176 @@
/****************************************************************************
**
** 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 QQUICKOPENGLSHADEREFFECT_P_H
#define QQUICKOPENGLSHADEREFFECT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtQuick/qquickitem.h>
#include <QtQuick/qsgmaterial.h>
#include <private/qtquickglobal_p.h>
#include <private/qsgadaptationlayer_p.h>
#include <private/qquickopenglshadereffectnode_p.h>
#include "qquickshadereffect_p.h"
#include "qquickshadereffectmesh_p.h"
#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
class QSGContext;
class QSignalMapper;
class QQuickOpenGLCustomMaterialShader;
// Common class for QQuickOpenGLShaderEffect and QQuickCustomParticle.
struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
{
typedef QQuickOpenGLShaderEffectMaterialKey Key;
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
QQuickOpenGLShaderEffectCommon(QObject *host) : host(host) { }
~QQuickOpenGLShaderEffectCommon();
void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void updateParseLog(bool ignoreAttributes);
void lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code);
void updateShader(QQuickItem *item, Key::ShaderType shaderType);
void updateMaterial(QQuickOpenGLShaderEffectNode *node, QQuickOpenGLShaderEffectMaterial *material,
bool updateUniforms, bool updateUniformValues, bool updateTextureProviders);
void updateWindow(QQuickWindow *window);
// Called by slots in QQuickOpenGLShaderEffect:
void sourceDestroyed(QObject *object);
void propertyChanged(QQuickItem *item, int mappedId, bool *textureProviderChanged);
QObject *host;
Key source;
QVector<QByteArray> attributes;
QVector<UniformData> uniformData[Key::ShaderTypeCount];
QVector<QSignalMapper *> signalMappers[Key::ShaderTypeCount];
QString parseLog;
};
class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffect : public QObject
{
Q_OBJECT
public:
QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent = 0);
~QQuickOpenGLShaderEffect();
QByteArray fragmentShader() const { return m_common.source.sourceCode[Key::FragmentShader]; }
void setFragmentShader(const QByteArray &code);
QByteArray vertexShader() const { return m_common.source.sourceCode[Key::VertexShader]; }
void setVertexShader(const QByteArray &code);
bool blending() const { return m_blending; }
void setBlending(bool enable);
QVariant mesh() const;
void setMesh(const QVariant &mesh);
QQuickShaderEffect::CullMode cullMode() const { return m_cullMode; }
void setCullMode(QQuickShaderEffect::CullMode face);
QString log() const { return m_log; }
QQuickShaderEffect::Status status() const { return m_status; }
bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
void setSupportsAtlasTextures(bool supports);
QString parseLog();
void handleEvent(QEvent *);
void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
void handleComponentComplete();
void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
private Q_SLOTS:
void updateGeometry();
void updateGeometryIfAtlased();
void updateLogAndStatus(const QString &log, int status);
void sourceDestroyed(QObject *object);
void propertyChanged(int mappedId);
private:
friend class QQuickCustomMaterialShader;
friend class QQuickOpenGLShaderEffectNode;
typedef QQuickOpenGLShaderEffectMaterialKey Key;
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
QQuickShaderEffect *m_item;
QSize m_meshResolution;
QQuickShaderEffectMesh *m_mesh;
QQuickGridMesh m_defaultMesh;
QQuickShaderEffect::CullMode m_cullMode;
QString m_log;
QQuickShaderEffect::Status m_status;
QQuickOpenGLShaderEffectCommon m_common;
uint m_blending : 1;
uint m_dirtyUniforms : 1;
uint m_dirtyUniformValues : 1;
uint m_dirtyTextureProviders : 1;
uint m_dirtyProgram : 1;
uint m_dirtyParseLog : 1;
uint m_dirtyMesh : 1;
uint m_dirtyGeometry : 1;
uint m_customVertexShader : 1;
uint m_supportsAtlasTextures : 1;
};
QT_END_NAMESPACE
#endif // QQUICKOPENGLSHADEREFFECT_P_H

View File

@ -37,14 +37,15 @@
**
****************************************************************************/
#include <private/qquickshadereffectnode_p.h>
#include <private/qquickopenglshadereffectnode_p.h>
#include "qquickshadereffect_p.h"
#include "qquickopenglshadereffect_p.h"
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include <QtQuick/private/qsgtexture_p.h>
#include <QtCore/qmutex.h>
#include <QtGui/qopenglfunctions.h>
QT_BEGIN_NAMESPACE
@ -61,29 +62,29 @@ static bool hasAtlasTexture(const QVector<QSGTextureProvider *> &textureProvider
class QQuickCustomMaterialShader : public QSGMaterialShader
{
public:
QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes);
QQuickCustomMaterialShader(const QQuickOpenGLShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes);
void deactivate() Q_DECL_OVERRIDE;
void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) Q_DECL_OVERRIDE;
char const *const *attributeNames() const Q_DECL_OVERRIDE;
protected:
friend class QQuickShaderEffectNode;
friend class QQuickOpenGLShaderEffectNode;
void compile() Q_DECL_OVERRIDE;
const char *vertexShader() const Q_DECL_OVERRIDE;
const char *fragmentShader() const Q_DECL_OVERRIDE;
const QQuickShaderEffectMaterialKey m_key;
const QQuickOpenGLShaderEffectMaterialKey m_key;
QVector<QByteArray> m_attributes;
QVector<const char *> m_attributeNames;
QString m_log;
bool m_compiled;
QVector<int> m_uniformLocs[QQuickShaderEffectMaterialKey::ShaderTypeCount];
QVector<int> m_uniformLocs[QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount];
uint m_initialized : 1;
};
QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickOpenGLShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
: m_key(key)
, m_attributes(attributes)
, m_compiled(false)
@ -104,11 +105,11 @@ void QQuickCustomMaterialShader::deactivate()
void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
typedef QQuickShaderEffectMaterial::UniformData UniformData;
typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
Q_ASSERT(newEffect != 0);
QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(newEffect);
QQuickOpenGLShaderEffectMaterial *material = static_cast<QQuickOpenGLShaderEffectMaterial *>(newEffect);
if (!material->m_emittedLogChanged && material->m_node) {
material->m_emittedLogChanged = true;
emit material->m_node->logAndStatusChanged(m_log, m_compiled ? QQuickShaderEffect::Compiled
@ -117,7 +118,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
int textureProviderIndex = 0;
if (!m_initialized) {
for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
Q_ASSERT(m_uniformLocs[shaderType].isEmpty());
m_uniformLocs[shaderType].reserve(material->uniforms[shaderType].size());
for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
@ -138,7 +139,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
}
QOpenGLFunctions *functions = state.context()->functions();
for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
const UniformData &d = material->uniforms[shaderType].at(i);
int loc = m_uniformLocs[shaderType].at(i);
@ -230,14 +231,14 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
}
functions->glActiveTexture(GL_TEXTURE0);
const QQuickShaderEffectMaterial *oldMaterial = static_cast<const QQuickShaderEffectMaterial *>(oldEffect);
const QQuickOpenGLShaderEffectMaterial *oldMaterial = static_cast<const QQuickOpenGLShaderEffectMaterial *>(oldEffect);
if (oldEffect == 0 || material->cullMode != oldMaterial->cullMode) {
switch (material->cullMode) {
case QQuickShaderEffectMaterial::FrontFaceCulling:
case QQuickShaderEffect::FrontFaceCulling:
functions->glEnable(GL_CULL_FACE);
functions->glCullFace(GL_FRONT);
break;
case QQuickShaderEffectMaterial::BackFaceCulling:
case QQuickShaderEffect::BackFaceCulling:
functions->glEnable(GL_CULL_FACE);
functions->glCullFace(GL_BACK);
break;
@ -322,16 +323,16 @@ void QQuickCustomMaterialShader::compile()
const char *QQuickCustomMaterialShader::vertexShader() const
{
return m_key.sourceCode[QQuickShaderEffectMaterialKey::VertexShader].constData();
return m_key.sourceCode[QQuickOpenGLShaderEffectMaterialKey::VertexShader].constData();
}
const char *QQuickCustomMaterialShader::fragmentShader() const
{
return m_key.sourceCode[QQuickShaderEffectMaterialKey::FragmentShader].constData();
return m_key.sourceCode[QQuickOpenGLShaderEffectMaterialKey::FragmentShader].constData();
}
bool QQuickShaderEffectMaterialKey::operator == (const QQuickShaderEffectMaterialKey &other) const
bool QQuickOpenGLShaderEffectMaterialKey::operator == (const QQuickOpenGLShaderEffectMaterialKey &other) const
{
for (int shaderType = 0; shaderType < ShaderTypeCount; ++shaderType) {
if (sourceCode[shaderType] != other.sourceCode[shaderType])
@ -340,39 +341,39 @@ bool QQuickShaderEffectMaterialKey::operator == (const QQuickShaderEffectMateria
return true;
}
bool QQuickShaderEffectMaterialKey::operator != (const QQuickShaderEffectMaterialKey &other) const
bool QQuickOpenGLShaderEffectMaterialKey::operator != (const QQuickOpenGLShaderEffectMaterialKey &other) const
{
return !(*this == other);
}
uint qHash(const QQuickShaderEffectMaterialKey &key)
uint qHash(const QQuickOpenGLShaderEffectMaterialKey &key)
{
uint hash = 1;
typedef QQuickShaderEffectMaterialKey Key;
typedef QQuickOpenGLShaderEffectMaterialKey Key;
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
hash = hash * 31337 + qHash(key.sourceCode[shaderType]);
return hash;
}
class QQuickShaderEffectMaterialCache : public QObject
class QQuickOpenGLShaderEffectMaterialCache : public QObject
{
Q_OBJECT
public:
static QQuickShaderEffectMaterialCache *get(bool create = true) {
static QQuickOpenGLShaderEffectMaterialCache *get(bool create = true) {
QOpenGLContext *ctx = QOpenGLContext::currentContext();
QQuickShaderEffectMaterialCache *me = ctx->findChild<QQuickShaderEffectMaterialCache *>(QStringLiteral("__qt_ShaderEffectCache"), Qt::FindDirectChildrenOnly);
QQuickOpenGLShaderEffectMaterialCache *me = ctx->findChild<QQuickOpenGLShaderEffectMaterialCache *>(QStringLiteral("__qt_ShaderEffectCache"), Qt::FindDirectChildrenOnly);
if (!me && create) {
me = new QQuickShaderEffectMaterialCache();
me = new QQuickOpenGLShaderEffectMaterialCache();
me->setObjectName(QStringLiteral("__qt_ShaderEffectCache"));
me->setParent(ctx);
}
return me;
}
QHash<QQuickShaderEffectMaterialKey, QSGMaterialType *> cache;
QHash<QQuickOpenGLShaderEffectMaterialKey, QSGMaterialType *> cache;
};
QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *node)
: cullMode(NoCulling)
QQuickOpenGLShaderEffectMaterial::QQuickOpenGLShaderEffectMaterial(QQuickOpenGLShaderEffectNode *node)
: cullMode(QQuickShaderEffect::NoCulling)
, geometryUsesTextureSubRect(false)
, m_node(node)
, m_emittedLogChanged(false)
@ -380,17 +381,17 @@ QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *n
setFlag(Blending | RequiresFullMatrix, true);
}
QSGMaterialType *QQuickShaderEffectMaterial::type() const
QSGMaterialType *QQuickOpenGLShaderEffectMaterial::type() const
{
return m_type;
}
QSGMaterialShader *QQuickShaderEffectMaterial::createShader() const
QSGMaterialShader *QQuickOpenGLShaderEffectMaterial::createShader() const
{
return new QQuickCustomMaterialShader(m_source, attributes);
}
bool QQuickShaderEffectMaterial::UniformData::operator == (const UniformData &other) const
bool QQuickOpenGLShaderEffectMaterial::UniformData::operator == (const UniformData &other) const
{
if (specialType != other.specialType)
return false;
@ -407,14 +408,14 @@ bool QQuickShaderEffectMaterial::UniformData::operator == (const UniformData &ot
}
}
int QQuickShaderEffectMaterial::compare(const QSGMaterial *o) const
int QQuickOpenGLShaderEffectMaterial::compare(const QSGMaterial *o) const
{
const QQuickShaderEffectMaterial *other = static_cast<const QQuickShaderEffectMaterial *>(o);
const QQuickOpenGLShaderEffectMaterial *other = static_cast<const QQuickOpenGLShaderEffectMaterial *>(o);
if ((hasAtlasTexture(textureProviders) && !geometryUsesTextureSubRect) || (hasAtlasTexture(other->textureProviders) && !other->geometryUsesTextureSubRect))
return 1;
if (cullMode != other->cullMode)
return 1;
for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
if (uniforms[shaderType] != other->uniforms[shaderType])
return 1;
}
@ -438,12 +439,12 @@ int QQuickShaderEffectMaterial::compare(const QSGMaterial *o) const
return 0;
}
void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMaterialKey &source)
void QQuickOpenGLShaderEffectMaterial::setProgramSource(const QQuickOpenGLShaderEffectMaterialKey &source)
{
m_source = source;
m_emittedLogChanged = false;
QQuickShaderEffectMaterialCache *cache = QQuickShaderEffectMaterialCache::get();
QQuickOpenGLShaderEffectMaterialCache *cache = QQuickOpenGLShaderEffectMaterialCache::get();
m_type = cache->cache.value(m_source);
if (!m_type) {
m_type = new QSGMaterialType();
@ -451,16 +452,16 @@ void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMateri
}
}
void QQuickShaderEffectMaterial::cleanupMaterialCache()
void QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache()
{
QQuickShaderEffectMaterialCache *cache = QQuickShaderEffectMaterialCache::get(false);
QQuickOpenGLShaderEffectMaterialCache *cache = QQuickOpenGLShaderEffectMaterialCache::get(false);
if (cache) {
qDeleteAll(cache->cache);
delete cache;
}
}
void QQuickShaderEffectMaterial::updateTextures() const
void QQuickOpenGLShaderEffectMaterial::updateTextures() const
{
for (int i = 0; i < textureProviders.size(); ++i) {
if (QSGTextureProvider *provider = textureProviders.at(i)) {
@ -470,7 +471,7 @@ void QQuickShaderEffectMaterial::updateTextures() const
}
}
void QQuickShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider)
void QQuickOpenGLShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider)
{
for (int i = 0; i < textureProviders.size(); ++i) {
if (provider == textureProviders.at(i))
@ -479,7 +480,7 @@ void QQuickShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *p
}
QQuickShaderEffectNode::QQuickShaderEffectNode()
QQuickOpenGLShaderEffectNode::QQuickOpenGLShaderEffectNode()
{
QSGNode::setFlag(UsePreprocess, true);
@ -488,28 +489,28 @@ QQuickShaderEffectNode::QQuickShaderEffectNode()
#endif
}
QQuickShaderEffectNode::~QQuickShaderEffectNode()
QQuickOpenGLShaderEffectNode::~QQuickOpenGLShaderEffectNode()
{
}
void QQuickShaderEffectNode::markDirtyTexture()
void QQuickOpenGLShaderEffectNode::markDirtyTexture()
{
markDirty(DirtyMaterial);
Q_EMIT dirtyTexture();
}
void QQuickShaderEffectNode::textureProviderDestroyed(QObject *object)
void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(QObject *object)
{
Q_ASSERT(material());
static_cast<QQuickShaderEffectMaterial *>(material())->invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
}
void QQuickShaderEffectNode::preprocess()
void QQuickOpenGLShaderEffectNode::preprocess()
{
Q_ASSERT(material());
static_cast<QQuickShaderEffectMaterial *>(material())->updateTextures();
static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->updateTextures();
}
#include "qquickshadereffectnode.moc"
#include "qquickopenglshadereffectnode.moc"
QT_END_NAMESPACE

View File

@ -37,8 +37,8 @@
**
****************************************************************************/
#ifndef QQUICKSHADEREFFECTNODE_P_H
#define QQUICKSHADEREFFECTNODE_P_H
#ifndef QQUICKOPENGLSHADEREFFECTNODE_P_H
#define QQUICKOPENGLSHADEREFFECTNODE_P_H
//
// W A R N I N G
@ -56,13 +56,14 @@
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/qquickitem.h>
#include <private/qtquickglobal_p.h>
#include <private/qquickshadereffect_p.h>
#include <QtCore/qsharedpointer.h>
#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
struct QQuickShaderEffectMaterialKey {
struct QQuickOpenGLShaderEffectMaterialKey {
enum ShaderType
{
VertexShader,
@ -72,15 +73,15 @@ struct QQuickShaderEffectMaterialKey {
QByteArray sourceCode[ShaderTypeCount];
bool operator == (const QQuickShaderEffectMaterialKey &other) const;
bool operator != (const QQuickShaderEffectMaterialKey &other) const;
bool operator == (const QQuickOpenGLShaderEffectMaterialKey &other) const;
bool operator != (const QQuickOpenGLShaderEffectMaterialKey &other) const;
};
uint qHash(const QQuickShaderEffectMaterialKey &key);
uint qHash(const QQuickOpenGLShaderEffectMaterialKey &key);
class QQuickCustomMaterialShader;
class QQuickShaderEffectNode;
class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectMaterial : public QSGMaterial
class QQuickOpenGLShaderEffectNode;
class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectMaterial : public QSGMaterial
{
public:
struct UniformData
@ -94,25 +95,18 @@ public:
bool operator == (const UniformData &other) const;
};
enum CullMode
{
NoCulling,
BackFaceCulling,
FrontFaceCulling
};
explicit QQuickShaderEffectMaterial(QQuickShaderEffectNode *node = 0);
explicit QQuickOpenGLShaderEffectMaterial(QQuickOpenGLShaderEffectNode *node = 0);
QSGMaterialType *type() const Q_DECL_OVERRIDE;
QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;
int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE;
QVector<QByteArray> attributes;
QVector<UniformData> uniforms[QQuickShaderEffectMaterialKey::ShaderTypeCount];
QVector<UniformData> uniforms[QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount];
QVector<QSGTextureProvider *> textureProviders;
CullMode cullMode;
QQuickShaderEffect::CullMode cullMode;
bool geometryUsesTextureSubRect;
void setProgramSource(const QQuickShaderEffectMaterialKey &source);
void setProgramSource(const QQuickOpenGLShaderEffectMaterialKey &source);
void updateTextures() const;
void invalidateTextureProvider(QSGTextureProvider *provider);
@ -127,21 +121,21 @@ protected:
// type. The type is cleaned up in cleanupMaterialCache() which is called
// when the GL context is shut down.
QSGMaterialType *m_type;
QQuickShaderEffectMaterialKey m_source;
QQuickOpenGLShaderEffectMaterialKey m_source;
QQuickShaderEffectNode *m_node;
QQuickOpenGLShaderEffectNode *m_node;
bool m_emittedLogChanged;
};
class QSGShaderEffectMesh;
class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectNode : public QObject, public QSGGeometryNode
class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectNode : public QObject, public QSGGeometryNode
{
Q_OBJECT
public:
QQuickShaderEffectNode();
virtual ~QQuickShaderEffectNode();
QQuickOpenGLShaderEffectNode();
virtual ~QQuickOpenGLShaderEffectNode();
void preprocess() Q_DECL_OVERRIDE;
@ -156,4 +150,4 @@ private Q_SLOTS:
QT_END_NAMESPACE
#endif // QQUICKSHADEREFFECTNODE_P_H
#endif // QQUICKOPENGLSHADEREFFECTNODE_P_H

View File

@ -63,13 +63,14 @@ public:
\inmodule QtQuick
The QQuickPaintedItem makes it possible to use the QPainter API with the QML Scene Graph.
It sets up a textured rectangle in the Scene Graph and uses a QPainter to paint
onto the texture. The render target can be either a QImage or a QOpenGLFramebufferObject.
When the render target is a QImage, QPainter first renders into the image then
the content is uploaded to the texture.
When a QOpenGLFramebufferObject is used, QPainter paints directly onto the texture.
Call update() to trigger a repaint.
The QQuickPaintedItem makes it possible to use the QPainter API with the
QML Scene Graph. It sets up a textured rectangle in the Scene Graph and
uses a QPainter to paint onto the texture. The render target can be either
a QImage or, when OpenGL is in use, a QOpenGLFramebufferObject. When the
render target is a QImage, QPainter first renders into the image then the
content is uploaded to the texture. When a QOpenGLFramebufferObject is
used, QPainter paints directly onto the texture. Call update() to trigger a
repaint.
To enable QPainter to do anti-aliased rendering, use setAntialiasing().
@ -78,6 +79,10 @@ public:
public function: paint(), which implements the actual painting. The
painting will be inside the rectangle spanning from 0,0 to
width(),height().
\note It important to understand the performance implications such items
can incur. See QQuickPaintedItem::RenderTarget and
QQuickPaintedItem::renderTarget.
*/
/*!
@ -172,8 +177,6 @@ QQuickPaintedItem::~QQuickPaintedItem()
is processed by the QML Scene Graph when the next frame is rendered. The item will only be
redrawn if it is visible.
Note that calling this function will trigger a repaint of the whole scene.
\sa paint()
*/
void QQuickPaintedItem::update(const QRect &rect)
@ -499,6 +502,12 @@ void QQuickPaintedItem::setFillColor(const QColor &c)
the QQuickPaintedItem::FramebufferObject render target if the item gets resized often.
By default, the render target is QQuickPaintedItem::Image.
\note Some Qt Quick backends may not support all render target options. For
example, it is likely that non-OpenGL backends will lack support for
QQuickPaintedItem::FramebufferObject and
QQuickPaintedItem::InvertedYFramebufferObject. Requesting these will then
be ignored.
*/
QQuickPaintedItem::RenderTarget QQuickPaintedItem::renderTarget() const
{
@ -652,11 +661,13 @@ QSGTextureProvider *QQuickPaintedItem::textureProvider() const
return QQuickItem::textureProvider();
Q_D(const QQuickPaintedItem);
#ifndef QT_NO_OPENGL
QQuickWindow *w = window();
if (!w || !w->openglContext() || QThread::currentThread() != w->openglContext()->thread()) {
qWarning("QQuickPaintedItem::textureProvider: can only be queried on the rendering thread of an exposed window");
return 0;
}
#endif
if (!d->textureProvider)
d->textureProvider = new QQuickPaintedItemTextureProvider();
d->textureProvider->node = d->node;

View File

@ -44,7 +44,11 @@
#include <QtCore/QTime>
#include <QtQuick/private/qquickanimatorcontroller_p.h>
#include <QtGui/QOpenGLContext>
#ifndef QT_NO_OPENGL
# include <QtGui/QOpenGLContext>
# include <QtQuick/private/qsgdefaultrendercontext_p.h>
# include <QtQuick/private/qquickopenglshadereffectnode_p.h>
#endif
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@ -54,12 +58,11 @@
#include <QtQuick/private/qquickwindow_p.h>
#include <QtCore/private/qobject_p.h>
#include <private/qquickshadereffectnode_p.h>
QT_BEGIN_NAMESPACE
#ifndef QT_NO_OPENGL
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
#endif
/*!
\class QQuickRenderControl
@ -134,7 +137,7 @@ QQuickRenderControlPrivate::QQuickRenderControlPrivate()
qAddPostRoutine(cleanup);
sg = QSGContext::createDefaultContext();
}
rc = new QSGRenderContext(sg);
rc = sg->createRenderContext();
}
void QQuickRenderControlPrivate::cleanup()
@ -183,7 +186,9 @@ void QQuickRenderControlPrivate::windowDestroyed()
delete QQuickWindowPrivate::get(window)->animationController;
QQuickWindowPrivate::get(window)->animationController = 0;
QQuickShaderEffectMaterial::cleanupMaterialCache();
#ifndef QT_NO_OPENGL
QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
#endif
window = 0;
}
@ -213,8 +218,9 @@ void QQuickRenderControl::prepareThread(QThread *targetThread)
*/
void QQuickRenderControl::initialize(QOpenGLContext *gl)
{
Q_D(QQuickRenderControl);
Q_D(QQuickRenderControl);
#ifndef QT_NO_OPENGL
if (!d->window) {
qWarning("QQuickRenderControl::initialize called with no associated window");
return;
@ -229,9 +235,10 @@ void QQuickRenderControl::initialize(QOpenGLContext *gl)
// It cannot be done here since the surface to use may not be the
// surface belonging to window. In fact window may not have a native
// window/surface at all.
d->rc->initialize(gl);
#else
Q_UNUSED(gl)
#endif
d->initialized = true;
}
@ -363,7 +370,11 @@ QImage QQuickRenderControl::grab()
return QImage();
render();
#ifndef QT_NO_OPENGL
QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
#else
QImage grabContent = d->window->grabWindow();
#endif
return grabContent;
}

File diff suppressed because it is too large Load Diff

View File

@ -52,51 +52,12 @@
//
#include <QtQuick/qquickitem.h>
#include <QtQuick/qsgmaterial.h>
#include <private/qtquickglobal_p.h>
#include <private/qsgadaptationlayer_p.h>
#include <private/qquickshadereffectnode_p.h>
#include "qquickshadereffectmesh_p.h"
#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
const char *qtPositionAttributeName();
const char *qtTexCoordAttributeName();
class QSGContext;
class QSignalMapper;
class QQuickCustomMaterialShader;
// Common class for QQuickShaderEffect and QQuickCustomParticle.
struct Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectCommon
{
typedef QQuickShaderEffectMaterialKey Key;
typedef QQuickShaderEffectMaterial::UniformData UniformData;
~QQuickShaderEffectCommon();
void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void updateParseLog(bool ignoreAttributes);
void lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code);
void updateShader(QQuickItem *item, Key::ShaderType shaderType);
void updateMaterial(QQuickShaderEffectNode *node, QQuickShaderEffectMaterial *material,
bool updateUniforms, bool updateUniformValues, bool updateTextureProviders);
void updateWindow(QQuickWindow *window);
// Called by slots in QQuickShaderEffect:
void sourceDestroyed(QObject *object);
void propertyChanged(QQuickItem *item, int mappedId, bool *textureProviderChanged);
Key source;
QVector<QByteArray> attributes;
QVector<UniformData> uniformData[Key::ShaderTypeCount];
QVector<QSignalMapper *> signalMappers[Key::ShaderTypeCount];
QString parseLog;
};
class QQuickOpenGLShaderEffect;
class QQuickGenericShaderEffect;
class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
{
@ -111,16 +72,14 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1)
public:
enum CullMode
{
NoCulling = QQuickShaderEffectMaterial::NoCulling,
BackFaceCulling = QQuickShaderEffectMaterial::BackFaceCulling,
FrontFaceCulling = QQuickShaderEffectMaterial::FrontFaceCulling
enum CullMode {
NoCulling,
BackFaceCulling,
FrontFaceCulling
};
Q_ENUM(CullMode)
enum Status
{
enum Status {
Compiled,
Uncompiled,
Error
@ -128,32 +87,30 @@ public:
Q_ENUM(Status)
QQuickShaderEffect(QQuickItem *parent = 0);
~QQuickShaderEffect();
QByteArray fragmentShader() const { return m_common.source.sourceCode[Key::FragmentShader]; }
QByteArray fragmentShader() const;
void setFragmentShader(const QByteArray &code);
QByteArray vertexShader() const { return m_common.source.sourceCode[Key::VertexShader]; }
QByteArray vertexShader() const;
void setVertexShader(const QByteArray &code);
bool blending() const { return m_blending; }
bool blending() const;
void setBlending(bool enable);
QVariant mesh() const;
void setMesh(const QVariant &mesh);
CullMode cullMode() const { return m_cullMode; }
CullMode cullMode() const;
void setCullMode(CullMode face);
QString log() const { return m_log; }
Status status() const { return m_status; }
bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
bool supportsAtlasTextures() const;
void setSupportsAtlasTextures(bool supports);
QString parseLog();
QString log() const;
Status status() const;
bool event(QEvent *) Q_DECL_OVERRIDE;
bool isComponentComplete() const;
QString parseLog();
Q_SIGNALS:
void fragmentShaderChanged();
@ -166,44 +123,17 @@ Q_SIGNALS:
void supportsAtlasTexturesChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
void componentComplete() Q_DECL_OVERRIDE;
void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
private Q_SLOTS:
void updateGeometry();
void updateGeometryIfAtlased();
void updateLogAndStatus(const QString &log, int status);
void sourceDestroyed(QObject *object);
void propertyChanged(int mappedId);
bool event(QEvent *e) override;
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override;
void componentComplete() override;
void itemChange(ItemChange change, const ItemChangeData &value) override;
private:
friend class QQuickCustomMaterialShader;
friend class QQuickShaderEffectNode;
typedef QQuickShaderEffectMaterialKey Key;
typedef QQuickShaderEffectMaterial::UniformData UniformData;
QSize m_meshResolution;
QQuickShaderEffectMesh *m_mesh;
QQuickGridMesh m_defaultMesh;
CullMode m_cullMode;
QString m_log;
Status m_status;
QQuickShaderEffectCommon m_common;
uint m_blending : 1;
uint m_dirtyUniforms : 1;
uint m_dirtyUniformValues : 1;
uint m_dirtyTextureProviders : 1;
uint m_dirtyProgram : 1;
uint m_dirtyParseLog : 1;
uint m_dirtyMesh : 1;
uint m_dirtyGeometry : 1;
uint m_customVertexShader : 1;
uint m_supportsAtlasTextures : 1;
#ifndef QT_NO_OPENGL
QQuickOpenGLShaderEffect *m_glImpl;
#endif
QQuickGenericShaderEffect *m_impl;
};
QT_END_NAMESPACE

Some files were not shown because too many files have changed in this diff Show More