1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "technique_p.h"
41
42#include <Qt3DRender/qrenderpass.h>
43#include <Qt3DRender/qparameter.h>
44#include <Qt3DRender/qtechnique.h>
45#include <Qt3DRender/qgraphicsapifilter.h>
46#include <Qt3DRender/private/filterkey_p.h>
47#include <Qt3DRender/private/qtechnique_p.h>
48#include <Qt3DRender/private/shader_p.h>
49#include <Qt3DCore/private/qchangearbiter_p.h>
50#include <Qt3DRender/private/managers_p.h>
51#include <Qt3DRender/private/techniquemanager_p.h>
52#include <Qt3DRender/private/nodemanagers_p.h>
53
54#include <QDebug>
55
56QT_BEGIN_NAMESPACE
57
58using namespace Qt3DCore;
59
60namespace Qt3DRender {
61namespace Render {
62
63Technique::Technique()
64 : BackendNode()
65 , m_isCompatibleWithRenderer(false)
66 , m_nodeManager(nullptr)
67{
68}
69
70Technique::~Technique()
71{
72 cleanup();
73}
74
75void Technique::cleanup()
76{
77 QBackendNode::setEnabled(false);
78 m_parameterPack.clear();
79 m_renderPasses.clear();
80 m_filterKeyList.clear();
81 m_isCompatibleWithRenderer = false;
82}
83
84void Technique::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
85{
86 const QTechnique *node = qobject_cast<const QTechnique *>(object: frontEnd);
87
88 if (!node)
89 return;
90
91 bool dirty = isEnabled() != frontEnd->isEnabled();
92 BackendNode::syncFromFrontEnd(frontEnd, firstTime);
93
94 auto renderPasses = qIdsForNodes(nodes: node->renderPasses());
95 std::sort(first: std::begin(cont&: renderPasses), last: std::end(cont&: renderPasses));
96 if (m_renderPasses != renderPasses) {
97 m_renderPasses = renderPasses;
98 dirty = true;
99 }
100
101 auto parameters = qIdsForNodes(nodes: node->parameters());
102 std::sort(first: std::begin(cont&: parameters), last: std::end(cont&: parameters));
103 if (m_parameterPack.parameters() != parameters) {
104 m_parameterPack.setParameters(parameters);
105 dirty = true;
106 }
107
108 auto filterKeys = qIdsForNodes(nodes: node->filterKeys());
109 std::sort(first: std::begin(cont&: filterKeys), last: std::end(cont&: filterKeys));
110 if (m_filterKeyList != filterKeys) {
111 m_filterKeyList = filterKeys;
112 dirty = true;
113 }
114
115 auto graphicsApiFilterData = QGraphicsApiFilterPrivate::get(q: node->graphicsApiFilter())->m_data;
116 if (m_graphicsApiFilterData != graphicsApiFilterData) {
117 m_graphicsApiFilterData = graphicsApiFilterData;
118 m_isCompatibleWithRenderer = false;
119 dirty = true;
120 }
121
122 if (dirty) {
123 m_nodeManager->techniqueManager()->addDirtyTechnique(techniqueId: peerId());
124 markDirty(changes: AbstractRenderer::TechniquesDirty);
125 }
126}
127
128QVector<Qt3DCore::QNodeId> Technique::parameters() const
129{
130 return m_parameterPack.parameters();
131}
132
133void Technique::appendRenderPass(Qt3DCore::QNodeId renderPassId)
134{
135 if (!m_renderPasses.contains(t: renderPassId))
136 m_renderPasses.append(t: renderPassId);
137}
138
139void Technique::removeRenderPass(Qt3DCore::QNodeId renderPassId)
140{
141 m_renderPasses.removeOne(t: renderPassId);
142}
143
144QVector<Qt3DCore::QNodeId> Technique::filterKeys() const
145{
146 return m_filterKeyList;
147}
148
149QVector<Qt3DCore::QNodeId> Technique::renderPasses() const
150{
151 return m_renderPasses;
152}
153
154const GraphicsApiFilterData *Technique::graphicsApiFilter() const
155{
156 return &m_graphicsApiFilterData;
157}
158
159bool Technique::isCompatibleWithRenderer() const
160{
161 return m_isCompatibleWithRenderer;
162}
163
164void Technique::setCompatibleWithRenderer(bool compatible)
165{
166 m_isCompatibleWithRenderer = compatible;
167}
168
169bool Technique::isCompatibleWithFilters(const QNodeIdVector &filterKeyIds)
170{
171 // There is a technique filter so we need to check for a technique with suitable criteria.
172 // Check for early bail out if the technique doesn't have sufficient number of criteria and
173 // can therefore never satisfy the filter
174 if (m_filterKeyList.size() < filterKeyIds.size())
175 return false;
176
177 // Iterate through the filter criteria and for each one search for a criteria on the
178 // technique that satisfies it
179 for (const QNodeId filterKeyId : filterKeyIds) {
180 FilterKey *filterKey = m_nodeManager->filterKeyManager()->lookupResource(id: filterKeyId);
181
182 bool foundMatch = false;
183
184 for (const QNodeId techniqueFilterKeyId : qAsConst(t&: m_filterKeyList)) {
185 FilterKey *techniqueFilterKey = m_nodeManager->filterKeyManager()->lookupResource(id: techniqueFilterKeyId);
186 if ((foundMatch = (*techniqueFilterKey == *filterKey)))
187 break;
188 }
189
190 // No match for TechniqueFilter criterion in any of the technique's criteria.
191 // So no way this can match. Don't bother checking the rest of the criteria.
192 if (!foundMatch)
193 return false;
194 }
195 return true;
196}
197
198void Technique::setNodeManager(NodeManagers *nodeManager)
199{
200 m_nodeManager = nodeManager;
201}
202
203NodeManagers *Technique::nodeManager() const
204{
205 return m_nodeManager;
206}
207
208void Technique::appendFilterKey(Qt3DCore::QNodeId criterionId)
209{
210 if (!m_filterKeyList.contains(t: criterionId))
211 m_filterKeyList.append(t: criterionId);
212}
213
214void Technique::removeFilterKey(Qt3DCore::QNodeId criterionId)
215{
216 m_filterKeyList.removeOne(t: criterionId);
217}
218
219TechniqueFunctor::TechniqueFunctor(AbstractRenderer *renderer, NodeManagers *manager)
220 : m_manager(manager)
221 , m_renderer(renderer)
222{
223}
224
225QBackendNode *TechniqueFunctor::create(const QNodeCreatedChangeBasePtr &change) const
226{
227 Technique *technique = m_manager->techniqueManager()->getOrCreateResource(id: change->subjectId());
228 technique->setNodeManager(m_manager);
229 technique->setRenderer(m_renderer);
230 return technique;
231}
232
233QBackendNode *TechniqueFunctor::get(QNodeId id) const
234{
235 return m_manager->techniqueManager()->lookupResource(id);
236}
237
238void TechniqueFunctor::destroy(QNodeId id) const
239{
240 m_manager->techniqueManager()->releaseResource(id);
241
242}
243
244} // namespace Render
245} // namespace Qt3DRender
246
247QT_END_NAMESPACE
248

source code of qt3d/src/render/materialsystem/technique.cpp