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 "qtechnique.h"
41 #include "qtechnique_p.h"
42 #include "qparameter.h"
43 #include "qgraphicsapifilter.h"
44 
45 QT_BEGIN_NAMESPACE
46 
47 using namespace Qt3DCore;
48 
49 namespace Qt3DRender {
50 
QTechniquePrivate()51 QTechniquePrivate::QTechniquePrivate()
52     : QNodePrivate()
53 {
54 }
55 
~QTechniquePrivate()56 QTechniquePrivate::~QTechniquePrivate()
57 {
58 }
59 
60 /*!
61     \qmltype Technique
62     \instantiates Qt3DRender::QTechnique
63     \inqmlmodule Qt3D.Render
64     \inherits Qt3DCore::QNode
65     \since 5.7
66     \brief Encapsulates a Technique.
67 
68     A Technique specifies a set of RenderPass objects, FilterKey objects,
69     Parameter objects and a GraphicsApiFilter, which together define a
70     rendering technique the given graphics API can render. The filter keys are
71     used by TechniqueFilter to select specific techniques at specific parts of
72     the FrameGraph. A Parameter defined on a Technique overrides parameter
73     (of the same name) defined in RenderPass, but are overridden by
74     parameter in RenderPassFilter, TechniqueFilter, Material and Effect.
75 
76     When creating an Effect that targets several versions of a graphics API, it
77     is useful to create several Technique nodes each with a graphicsApiFilter
78     set to match one of the targeted versions. At runtime, the Qt3D renderer
79     will select the most appropriate Technique based on which graphics API
80     versions are supported and (if specified) the FilterKey nodes that satisfy
81     a given TechniqueFilter in the FrameGraph.
82 
83     \note When using OpenGL as the graphics API for rendering, Qt3D relies on
84     the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
85     to decide what is the most appropriate GL version available. If you need to
86     customize the QSurfaceFormat, do not forget to apply it with
87     QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
88     will likely have no effect on Qt3D related rendering.
89 
90     \note Technique node can not be disabled.
91 
92     \qml
93     Technique {
94         id: gl3Technique
95         parameters: [
96             Parameter { name: "color"; value: "orange" }
97         ]
98         filterKeys: [
99             FilterKey { name: "renderingStyle"; value: "forward" }
100         ]
101         graphicsApiFilter: {
102             api: GraphicsApiFilter.OpenGL
103             profile: GraphicsApiFilter.CoreProfile
104             majorVersion: 3
105             minorVersion: 1
106         }
107         renderPasses: [
108             RenderPass {
109                 id: firstPass
110                 shaderProgram: ShaderProgram {
111                     // ...
112                 }
113             },
114             RenderPass {
115                 id: secondPass
116                 shaderProgram: ShaderProgram {
117                     // ...
118                 }
119             }
120         ]
121     }
122     \endqml
123 
124     \sa Effect, RenderPass, TechniqueFilter
125  */
126 
127 /*!
128     \class Qt3DRender::QTechnique
129     \inmodule Qt3DRender
130     \inherits Node
131     \since 5.7
132     \brief Encapsulates a Technique.
133 
134     A Qt3DRender::QTechnique specifies a set of Qt3DRender::QRenderPass
135     objects, Qt3DRender::QFilterKey objects, Qt3DRender::QParameter objects and
136     a Qt3DRender::QGraphicsApiFilter, which together define a rendering
137     technique the given graphics API can render. The filter keys are used by
138     Qt3DRender::QTechniqueFilter to select specific techniques at specific
139     parts of the FrameGraph. A QParameter defined on a QTechnique overrides parameter
140     (of the same name) defined in QRenderPass, but are overridden by
141     parameter in QRenderPassFilter, QTechniqueFilter, QMaterial and QEffect.
142 
143     When creating an QEffect that targets several versions of a graphics API,
144     it is useful to create several QTechnique nodes each with a
145     graphicsApiFilter set to match one of the targeted GL versions. At runtime,
146     the Qt3D renderer will select the most appropriate QTechnique based on
147     which graphics API versions are supported and (if specified) the QFilterKey
148     nodes that satisfy a given QTechniqueFilter in the FrameGraph.
149 
150     \note When using OpenGL as the graphics API for rendering, Qt3D relies on
151     the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
152     to decide what is the most appropriate GL version available. If you need to
153     customize the QSurfaceFormat, do not forget to apply it with
154     QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
155     will likely have no effect on Qt3D related rendering.
156 
157     \note QTechnique node can not be disabled.
158 
159     \code
160     QTechnique *gl3Technique = new QTechnique();
161 
162     // Create the render passes
163     QRenderPass *firstPass = new QRenderPass();
164     QRenderPass *secondPass = new QRenderPass();
165 
166     // Add the passes to the technique
167     gl3Technique->addRenderPass(firstPass);
168     gl3Technique->addRenderPass(secondPass);
169 
170     // Set the targeted GL version for the technique
171     gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
172     gl3Technique->graphicsApiFilter()->setMajorVersion(3);
173     gl3Technique->graphicsApiFilter()->setMinorVersion(1);
174     gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
175 
176     // Create a FilterKey
177     QFilterKey *filterKey = new QFilterKey();
178     filterKey->setName(QStringLiteral("name"));
179     fitlerKey->setValue(QStringLiteral("zFillPass"));
180 
181     // Add the FilterKey to the Technique
182     gl3Technique->addFilterKey(filterKey);
183 
184     // Create a QParameter
185     QParameter *colorParameter = new QParameter(QStringLiteral("color"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
186 
187     // Add parameter to technique
188     gl3Technique->addParameter(colorParameter);
189     \endcode
190 
191     \sa QEffect, QRenderPass, QTechniqueFilter
192  */
193 
194 /*!
195     \qmlproperty GraphicsApiFilter Qt3D.Render::Technique::graphicsApiFilter
196     Specifies the graphics API filter being used
197 */
198 /*!
199     \qmlproperty list<FilterKey> Qt3D.Render::Technique::filterKeys
200     Specifies the list of filter keys enabling this technique
201 */
202 /*!
203     \qmlproperty list<RenderPass> Qt3D.Render::Technique::renderPasses
204     Specifies the render passes used by the tehcnique
205 */
206 /*!
207     \qmlproperty list<Parameter> Qt3D.Render::Technique::parameters
208     Specifies the parameters used by the technique
209 */
210 /*!
211     \property Qt3DRender::QTechnique::graphicsApiFilter
212     Specifies the graphics API filter being used
213  */
214 
QTechnique(QNode * parent)215 QTechnique::QTechnique(QNode *parent)
216     : QNode(*new QTechniquePrivate, parent)
217 {
218     Q_D(QTechnique);
219     QObject::connect(&d->m_graphicsApiFilter, SIGNAL(graphicsApiFilterChanged()), this, SLOT(_q_graphicsApiFilterChanged()));
220 }
221 
222 /*! \internal */
~QTechnique()223 QTechnique::~QTechnique()
224 {
225 }
226 
227 /*! \internal */
QTechnique(QTechniquePrivate & dd,QNode * parent)228 QTechnique::QTechnique(QTechniquePrivate &dd, QNode *parent)
229     : QNode(dd, parent)
230 {
231     Q_D(QTechnique);
232     QObject::connect(&d->m_graphicsApiFilter, SIGNAL(graphicsApiFilterChanged()), this, SLOT(_q_graphicsApiFilterChanged()));
233 }
234 
235 /*! \internal */
_q_graphicsApiFilterChanged()236 void QTechniquePrivate::_q_graphicsApiFilterChanged()
237 {
238     update();
239 }
240 
241 /*!
242     Add \a filterKey to the Qt3DRender::QTechnique local filter keys.
243  */
addFilterKey(QFilterKey * filterKey)244 void QTechnique::addFilterKey(QFilterKey *filterKey)
245 {
246     Q_ASSERT(filterKey);
247     Q_D(QTechnique);
248     if (!d->m_filterKeys.contains(filterKey)) {
249         d->m_filterKeys.append(filterKey);
250 
251         // Ensures proper bookkeeping
252         d->registerDestructionHelper(filterKey, &QTechnique::removeFilterKey, d->m_filterKeys);
253 
254         // We need to add it as a child of the current node if it has been declared inline
255         // Or not previously added as a child of the current node so that
256         // 1) The backend gets notified about it's creation
257         // 2) When the current node is destroyed, it gets destroyed as well
258         if (!filterKey->parent())
259             filterKey->setParent(this);
260 
261         d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueAdded);
262     }
263 }
264 
265 /*!
266     Removes \a filterKey from the Qt3DRender::QTechnique local filter keys.
267  */
removeFilterKey(QFilterKey * filterKey)268 void QTechnique::removeFilterKey(QFilterKey *filterKey)
269 {
270     Q_ASSERT(filterKey);
271     Q_D(QTechnique);
272     if (!d->m_filterKeys.removeOne(filterKey))
273         return;
274     d->updateNode(filterKey, "filterKeys", Qt3DCore::PropertyValueRemoved);
275     // Remove bookkeeping connection
276     d->unregisterDestructionHelper(filterKey);
277 }
278 
279 /*!
280     Returns the list of Qt3DCore::QFilterKey key objects making up the filter keys
281     of the Qt3DRender::QTechnique.
282  */
filterKeys() const283 QVector<QFilterKey *> QTechnique::filterKeys() const
284 {
285     Q_D(const QTechnique);
286     return d->m_filterKeys;
287 }
288 
289 /*!
290     Add \a parameter to the technique's parameters.
291  */
addParameter(QParameter * parameter)292 void QTechnique::addParameter(QParameter *parameter)
293 {
294     Q_ASSERT(parameter);
295     Q_D(QTechnique);
296     if (!d->m_parameters.contains(parameter)) {
297         d->m_parameters.append(parameter);
298 
299         // Ensures proper bookkeeping
300         d->registerDestructionHelper(parameter, &QTechnique::removeParameter, d->m_parameters);
301 
302         // We need to add it as a child of the current node if it has been declared inline
303         // Or not previously added as a child of the current node so that
304         // 1) The backend gets notified about it's creation
305         // 2) When the current node is destroyed, the child parameters get destroyed as well
306         if (!parameter->parent())
307             parameter->setParent(this);
308 
309         d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueAdded);
310     }
311 }
312 
313 /*!
314     Remove \a parameter from the technique's parameters.
315  */
removeParameter(QParameter * parameter)316 void QTechnique::removeParameter(QParameter *parameter)
317 {
318     Q_ASSERT(parameter);
319     Q_D(QTechnique);
320     if (!d->m_parameters.removeOne(parameter))
321         return;
322     d->updateNode(parameter, "parameter", Qt3DCore::PropertyValueRemoved);
323     // Remove bookkeeping connection
324     d->unregisterDestructionHelper(parameter);
325 }
326 
327 /*!
328     Appends a \a pass to the technique.
329  */
addRenderPass(QRenderPass * pass)330 void QTechnique::addRenderPass(QRenderPass *pass)
331 {
332     Q_ASSERT(pass);
333     Q_D(QTechnique);
334     if (!d->m_renderPasses.contains(pass)) {
335         d->m_renderPasses.append(pass);
336 
337         // Ensures proper bookkeeping
338         d->registerDestructionHelper(pass, &QTechnique::removeRenderPass, d->m_renderPasses);
339 
340         // We need to add it as a child of the current node if it has been declared inline
341         // Or not previously added as a child of the current node so that
342         // 1) The backend gets notified about it's creation
343         // 2) When the current node is destroyed, it gets destroyed as well
344         if (!pass->parent())
345             pass->setParent(this);
346 
347         d->updateNode(pass, "pass", Qt3DCore::PropertyValueAdded);
348     }
349 }
350 
351 /*!
352     Removes a \a pass from the technique.
353  */
removeRenderPass(QRenderPass * pass)354 void QTechnique::removeRenderPass(QRenderPass *pass)
355 {
356     Q_ASSERT(pass);
357     Q_D(QTechnique);
358     if (!d->m_renderPasses.removeOne(pass))
359         return;
360     d->updateNode(pass, "pass", Qt3DCore::PropertyValueAdded);
361     // Remove bookkeeping connection
362     d->unregisterDestructionHelper(pass);
363 }
364 
365 /*!
366     Returns the list of render passes contained in the technique.
367  */
renderPasses() const368 QVector<QRenderPass *> QTechnique::renderPasses() const
369 {
370     Q_D(const QTechnique);
371     return d->m_renderPasses;
372 }
373 
374 /*!
375     Returns a vector of the techniques current parameters
376  */
parameters() const377 QVector<QParameter *> QTechnique::parameters() const
378 {
379     Q_D(const QTechnique);
380     return d->m_parameters;
381 }
382 
graphicsApiFilter()383 QGraphicsApiFilter *QTechnique::graphicsApiFilter()
384 {
385     Q_D(QTechnique);
386     return &d->m_graphicsApiFilter;
387 }
388 
graphicsApiFilter() const389 const QGraphicsApiFilter *QTechnique::graphicsApiFilter() const
390 {
391     Q_D(const QTechnique);
392     return &d->m_graphicsApiFilter;
393 }
394 
createNodeCreationChange() const395 Qt3DCore::QNodeCreatedChangeBasePtr QTechnique::createNodeCreationChange() const
396 {
397     auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QTechniqueData>::create(this);
398     QTechniqueData &data = creationChange->data;
399 
400     Q_D(const QTechnique);
401     data.graphicsApiFilterData = QGraphicsApiFilterPrivate::get(const_cast<QGraphicsApiFilter *>(&d->m_graphicsApiFilter))->m_data;
402     data.filterKeyIds = qIdsForNodes(d->m_filterKeys);
403     data.parameterIds = qIdsForNodes(d->m_parameters);
404     data.renderPassIds = qIdsForNodes(d->m_renderPasses);
405 
406     return creationChange;
407 }
408 
409 } // of namespace Qt3DRender
410 
411 QT_END_NAMESPACE
412 
413 #include "moc_qtechnique.cpp"
414