1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the Qt3D module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qrenderpass.h"
42#include "qrenderpass_p.h"
43#include "qparameter.h"
44#include "qfilterkey.h"
45#include "qrenderstate.h"
46#include <Qt3DCore/qpropertyupdatedchange.h>
47#include <Qt3DCore/qpropertynodeaddedchange.h>
48#include <Qt3DCore/qpropertynoderemovedchange.h>
49#include <Qt3DCore/private/qnode_p.h>
50
51QT_BEGIN_NAMESPACE
52
53using namespace Qt3DCore;
54
55namespace Qt3DRender {
56
57QRenderPassPrivate::QRenderPassPrivate()
58 : QNodePrivate()
59 , m_shader(nullptr)
60{
61}
62/*!
63 \qmltype RenderPass
64 \instantiates Qt3DRender::QRenderPass
65 \inqmlmodule Qt3D.Render
66 \inherits Node
67 \since 5.7
68 \brief Encapsulates a Render Pass.
69
70 A RenderPass specifies a single rendering pass - an instance of shader program
71 execution - used by Technique. A Render pass consists of a ShaderProgram and
72 a list of FilterKey objects, a list of RenderState objects and a list
73 of \l Parameter objects.
74
75 RenderPass executes the ShaderProgram using the given RenderState and
76 Parameter nodes when at least one of FilterKey nodes being referenced
77 matches any of the FilterKey nodes in RenderPassFilter or when no FilterKey
78 nodes are specified and no RenderPassFilter is present in the FrameGraph.
79
80 If the RenderPass defines a Parameter, it will be overridden by a Parameter
81 with the same name if it exists in any of the Technique, Effect, Material,
82 TechniqueFilter, RenderPassFilter associated with the pass at runtime. This
83 still can be useful to define sane default values.
84
85 At render time, for each leaf node of the FrameGraph a base render state is
86 recorded by accumulating states defined by all RenderStateSet nodes in the
87 FrameGraph branch. Each RenderPass can overload this base render state by
88 specifying its own RenderState nodes.
89
90 \qml
91 Technique {
92 filterKeys: [
93 FilterKey { name: "renderingStyle"; value: "forward" }
94 ]
95 graphicsApiFilter: {
96 api: GraphicsApiFilter.OpenGL
97 profile: GraphicsApiFilter.CoreProfile
98 majorVersion: 3
99 minorVersion: 1
100 }
101 renderPasses: [
102 RenderPass {
103 id: pass
104 shaderProgram: ShaderProgram {
105 // ...
106 }
107 parameters: [
108 Parameter { name: "color"; value: "red" }
109 ]
110 renderStates: [
111 DepthTest {}
112 ]
113 }
114 ]
115 }
116 \endqml
117
118 \sa RenderPassFilter, FilterKey, Parameter, RenderState, Effect, Technique
119 */
120
121/*!
122 \class Qt3DRender::QRenderPass
123 \inmodule Qt3DRender
124 \since 5.7
125 \brief Encapsulates a Render Pass.
126
127 A Qt3DRender::QRenderPass specifies a single rendering pass - an instance of shader
128 program execution - used by Qt3DRender::QTechnique. Render pass consists
129 of a Qt3DRender::QShaderProgram and a list of Qt3DRender::QFilterKey objects,
130 a list of Qt3DRender::QRenderState objects and a list of Qt3DRender::QParameter objects.
131
132 QRenderPass executes the QShaderProgram using the given QRenderState and
133 QParameter nodes when at least one of QFilterKey nodes being referenced
134 matches any of the QFilterKey nodes in QRenderPassFilter or when no
135 QFilterKey nodes are specified and no QRenderPassFilter is present in the
136 FrameGraph.
137
138 If the QRenderPass defines a QParameter, it will be overridden by a
139 QParameter with the same name if it exists in any of the QTechnique,
140 QEffect, QMaterial, QTechniqueFilter, QRenderPassFilter associated with the
141 pass at runtime. This still can be useful to define sane default values.
142
143 At render time, for each leaf node of the FrameGraph a base render state is
144 recorded by accumulating states defined by all QRenderStateSet nodes in the
145 FrameGraph branch. Each QRenderPass can overload this base render state by
146 specifying its own QRenderState nodes.
147
148 \code
149 // Create the render passes
150 QRenderPass *pass = new QRenderPass();
151
152 // Create shader program
153 QShaderProgram *glShader = new QShaderProgram();
154
155 // Set the shader on the render pass
156 pass->setShaderProgram(glShader);
157
158 // Create a FilterKey
159 QFilterKey *filterKey = new QFilterKey();
160 filterKey->setName(QStringLiteral("name"));
161 fitlerKey->setValue(QStringLiteral("zFillPass"));
162
163 // Add the FilterKey to the pass
164 pass->addFilterKey(filterKey);
165
166 // Create a QParameter
167 QParameter *colorParameter = new QParameter(QStringLiteral("color"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
168
169 // Add parameter to pass
170 pass->addParameter(colorParameter);
171
172 // Create a QRenderState
173 QDepthTest *depthTest = new QDepthTest();
174
175 // Add the render state to the pass
176 pass->addRenderState(depthTest);
177 \endcode
178
179 \sa QRenderPassFilter, QFilterKey, QParameter, QRenderState, QEffect, QTechnique
180 */
181/*!
182 \typedef ParameterList
183 \relates Qt3DRender::QRenderPass
184
185 A list of Qt3DRender::QParameter parameters.
186*/
187/*!
188 \qmlproperty ShaderProgram Qt3D.Render::RenderPass::shaderProgram
189 Holds the shader program to be used for this render pass.
190*/
191/*!
192 \qmlproperty list<FilterKey> Qt3D.Render::RenderPass::filterKeys
193 Holds the filter keys enabling the use of this render pass.
194*/
195/*!
196 \qmlproperty list<RenderState> Qt3D.Render::RenderPass::renderStates
197 Holds the render states used by the render pass.
198*/
199/*!
200 \qmlproperty list<Parameter> Qt3D.Render::RenderPass::parameters
201 Holds the shader parameter values used by the render pass.
202*/
203
204/*!
205 \property Qt3DRender::QRenderPass::shaderProgram
206 Specifies the shader program to be used for this render pass.
207 */
208
209/*!
210 \fn Qt3DRender::QRenderPass::QRenderPass(Qt3DCore::QNode *parent)
211 Constructs a new QRenderPass with the specified \a parent.
212 */
213QRenderPass::QRenderPass(QNode *parent)
214 : QNode(*new QRenderPassPrivate, parent)
215{
216}
217
218/*! \internal */
219QRenderPass::~QRenderPass()
220{
221}
222
223/*! \internal */
224QRenderPass::QRenderPass(QRenderPassPrivate &dd, QNode *parent)
225 : QNode(dd, parent)
226{
227}
228
229void QRenderPass::setShaderProgram(QShaderProgram *shaderProgram)
230{
231 Q_D(QRenderPass);
232 if (d->m_shader != shaderProgram) {
233
234 if (d->m_shader != nullptr && d->m_changeArbiter != nullptr) {
235 const auto change = QPropertyNodeRemovedChangePtr::create(id(), d->m_shader);
236 change->setPropertyName("shaderProgram");
237 d->notifyObservers(change);
238 }
239
240 if (d->m_shader)
241 d->unregisterDestructionHelper(d->m_shader);
242
243 // We need to add it as a child of the current node if it has been declared inline
244 // Or not previously added as a child of the current node so that
245 // 1) The backend gets notified about it's creation
246 // 2) When the current node is destroyed, it gets destroyed as well
247 if (shaderProgram && !shaderProgram->parent())
248 shaderProgram->setParent(this);
249
250 d->m_shader = shaderProgram;
251
252 // Ensures proper bookkeeping
253 if (d->m_shader)
254 d->registerDestructionHelper(d->m_shader, &QRenderPass::setShaderProgram, d->m_shader);
255
256 emit shaderProgramChanged(shaderProgram);
257 }
258}
259
260QShaderProgram *QRenderPass::shaderProgram() const
261{
262 Q_D(const QRenderPass);
263 return d->m_shader;
264}
265
266/*!
267 Adds \a filterKey to the Qt3DRender::QRenderPass local filter keys.
268 */
269void QRenderPass::addFilterKey(QFilterKey *filterKey)
270{
271 Q_ASSERT(filterKey);
272 Q_D(QRenderPass);
273 if (!d->m_filterKeyList.contains(filterKey)) {
274 d->m_filterKeyList.append(filterKey);
275
276 // Ensures proper bookkeeping
277 d->registerDestructionHelper(filterKey, &QRenderPass::removeFilterKey, d->m_filterKeyList);
278
279 // We need to add it as a child of the current node if it has been declared inline
280 // Or not previously added as a child of the current node so that
281 // 1) The backend gets notified about it's creation
282 // 2) When the current node is destroyed, it gets destroyed as well
283 if (!filterKey->parent())
284 filterKey->setParent(this);
285
286 if (d->m_changeArbiter != nullptr) {
287 const auto change = QPropertyNodeAddedChangePtr::create(id(), filterKey);
288 change->setPropertyName("filterKeys");
289 d->notifyObservers(change);
290 }
291 }
292}
293
294/*!
295 Removes \a filterKey from the Qt3DRender::QRenderPass local filter keys.
296 */
297void QRenderPass::removeFilterKey(QFilterKey *filterKey)
298{
299 Q_ASSERT(filterKey);
300 Q_D(QRenderPass);
301 if (d->m_changeArbiter != nullptr) {
302 const auto change = QPropertyNodeRemovedChangePtr::create(id(), filterKey);
303 change->setPropertyName("filterKeys");
304 d->notifyObservers(change);
305 }
306 d->m_filterKeyList.removeOne(filterKey);
307 // Remove bookkeeping connection
308 d->unregisterDestructionHelper(filterKey);
309}
310
311/*!
312 Returns the list of Qt3DRender::QFilterKey key objects making up the filter keys
313 of the Qt3DRender::QRenderPass.
314 */
315QVector<QFilterKey *> QRenderPass::filterKeys() const
316{
317 Q_D(const QRenderPass);
318 return d->m_filterKeyList;
319}
320
321/*!
322 Adds a render \a state to the rendering pass. That implies that
323 when the pass is executed at render time, the globally set render state will
324 be modified by the states defined locally by the Qt3DRender::QRenderPass.
325
326 \note not defining any Qt3DRender::QRenderState in a pass will result in the pass using
327 the globally set render state for a given FrameGraph branch execution path.
328 */
329void QRenderPass::addRenderState(QRenderState *state)
330{
331 Q_ASSERT(state);
332 Q_D(QRenderPass);
333 if (!d->m_renderStates.contains(state)) {
334 d->m_renderStates.append(state);
335
336 // Ensures proper bookkeeping
337 d->registerDestructionHelper(state, &QRenderPass::removeRenderState, d->m_renderStates);
338
339 if (!state->parent())
340 state->setParent(this);
341
342 if (d->m_changeArbiter != nullptr) {
343 const auto change = QPropertyNodeAddedChangePtr::create(id(), state);
344 change->setPropertyName("renderState");
345 d->notifyObservers(change);
346 }
347 }
348}
349
350/*!
351 Removes \a state from the Qt3DRender::QRenderPass local render state.
352 */
353void QRenderPass::removeRenderState(QRenderState *state)
354{
355 Q_ASSERT(state);
356 Q_D(QRenderPass);
357 if (d->m_changeArbiter != nullptr) {
358 const auto change = QPropertyNodeRemovedChangePtr::create(id(), state);
359 change->setPropertyName("renderState");
360 d->notifyObservers(change);
361 }
362 d->m_renderStates.removeOne(state);
363 // Remove bookkeeping connection
364 d->unregisterDestructionHelper(state);
365}
366
367/*!
368 Returns the list of Qt3DRender::QRenderState state objects making up the render
369 state of the Qt3DRender::QRenderPass.
370 */
371QVector<QRenderState *> QRenderPass::renderStates() const
372{
373 Q_D(const QRenderPass);
374 return d->m_renderStates;
375}
376
377/*!
378 Add \a parameter to the render pass' parameters.
379 */
380void QRenderPass::addParameter(QParameter *parameter)
381{
382 Q_ASSERT(parameter);
383 Q_D(QRenderPass);
384 if (!d->m_parameters.contains(parameter)) {
385 d->m_parameters.append(parameter);
386
387 // Ensures proper bookkeeping
388 d->registerDestructionHelper(parameter, &QRenderPass::removeParameter, d->m_parameters);
389
390 // We need to add it as a child of the current node if it has been declared inline
391 // Or not previously added as a child of the current node so that
392 // 1) The backend gets notified about it's creation
393 // 2) When the current node is destroyed, the child parameters get destroyed as well
394 if (!parameter->parent())
395 parameter->setParent(this);
396
397 if (d->m_changeArbiter != nullptr) {
398 const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
399 change->setPropertyName("parameter");
400 d->notifyObservers(change);
401 }
402 }
403}
404
405/*!
406 Remove \a parameter from the render pass' parameters.
407 */
408void QRenderPass::removeParameter(QParameter *parameter)
409{
410 Q_ASSERT(parameter);
411 Q_D(QRenderPass);
412 if (d->m_changeArbiter != nullptr) {
413 const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
414 change->setPropertyName("parameter");
415 d->notifyObservers(change);
416 }
417 d->m_parameters.removeOne(parameter);
418 // Remove bookkeeping connection
419 d->unregisterDestructionHelper(parameter);
420}
421
422/*!
423 Returns a vector of the render pass' current parameters
424 */
425ParameterList QRenderPass::parameters() const
426{
427 Q_D(const QRenderPass);
428 return d->m_parameters;
429}
430
431Qt3DCore::QNodeCreatedChangeBasePtr QRenderPass::createNodeCreationChange() const
432{
433 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QRenderPassData>::create(this);
434 auto &data = creationChange->data;
435 Q_D(const QRenderPass);
436 data.filterKeyIds = qIdsForNodes(d->m_filterKeyList);
437 data.parameterIds = qIdsForNodes(d->m_parameters);
438 data.renderStateIds = qIdsForNodes(d->m_renderStates);
439 data.shaderId = qIdForNode(d->m_shader);
440 return creationChange;
441}
442
443} // namespace Qt3DRender
444
445QT_END_NAMESPACE
446