1/****************************************************************************
2**
3** Copyright (C) 2015 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:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30#include <qbackendnodetester.h>
31#include <Qt3DRender/private/renderpass_p.h>
32
33#include <Qt3DCore/QPropertyUpdatedChange>
34#include <Qt3DCore/QPropertyNodeAddedChange>
35#include <Qt3DCore/QPropertyNodeRemovedChange>
36
37#include <Qt3DRender/QFilterKey>
38#include <Qt3DRender/QRenderPass>
39#include <Qt3DRender/QShaderProgram>
40#include <Qt3DRender/QParameter>
41
42#include <Qt3DRender/QAlphaCoverage>
43#include <Qt3DRender/QAlphaTest>
44#include <Qt3DRender/QBlendEquation>
45#include <Qt3DRender/QBlendEquationArguments>
46#include <Qt3DRender/QColorMask>
47#include <Qt3DRender/QCullFace>
48#include <Qt3DRender/QNoDepthMask>
49#include <Qt3DRender/QDepthTest>
50#include <Qt3DRender/QDithering>
51#include <Qt3DRender/QFrontFace>
52#include <Qt3DRender/QPolygonOffset>
53#include <Qt3DRender/QScissorTest>
54#include <Qt3DRender/QStencilTest>
55#include <Qt3DRender/QStencilTestArguments>
56#include <Qt3DRender/QStencilMask>
57#include <Qt3DRender/QStencilOperation>
58#include <Qt3DRender/QStencilOperationArguments>
59#include <Qt3DRender/QClipPlane>
60
61#include <Qt3DRender/private/renderstates_p.h>
62#include <Qt3DRender/private/managers_p.h>
63
64#include "testrenderer.h"
65
66using namespace Qt3DCore;
67using namespace Qt3DRender;
68using namespace Qt3DRender::Render;
69
70class tst_RenderRenderPass : public Qt3DCore::QBackendNodeTester
71{
72 Q_OBJECT
73public:
74 tst_RenderRenderPass()
75 : m_renderStateManager(new RenderStateManager())
76 {
77 qRegisterMetaType<Qt3DCore::QNode *>();
78 }
79 ~tst_RenderRenderPass() {}
80
81private slots:
82 void shouldHaveInitialState()
83 {
84 // GIVEN
85 RenderPass backend;
86
87 // THEN
88 QVERIFY(!backend.isEnabled());
89 QVERIFY(backend.shaderProgram().isNull());
90 QVERIFY(backend.filterKeys().isEmpty());
91 QVERIFY(backend.renderStates().isEmpty());
92 QVERIFY(backend.parameters().isEmpty());
93 }
94
95 void checkCleanupState()
96 {
97 // GIVEN
98 RenderPass backend;
99
100 // WHEN
101 backend.setEnabled(true);
102
103 {
104 QRenderPass frontend;
105 QShaderProgram program;
106 QBlendEquationArguments state;
107 QParameter parameter;
108 QFilterKey filterKey;
109
110 frontend.addFilterKey(&filterKey);
111 frontend.addParameter(&parameter);
112 frontend.addRenderState(&state);
113 frontend.setShaderProgram(&program);
114
115 simulateInitialization(&frontend, &backend);
116 }
117
118 backend.cleanup();
119
120 // THEN
121 QVERIFY(!backend.isEnabled());
122 QVERIFY(backend.shaderProgram().isNull());
123 QVERIFY(backend.filterKeys().isEmpty());
124 QVERIFY(backend.renderStates().isEmpty());
125 QVERIFY(backend.parameters().isEmpty());
126 QVERIFY(!backend.hasRenderStates());
127 }
128
129 void shouldHavePropertiesMirroringItsPeer()
130 {
131 // GIVEN
132 QRenderPass frontend;
133 frontend.setShaderProgram(new QShaderProgram(&frontend));
134
135 frontend.addFilterKey(new QFilterKey(&frontend));
136
137 frontend.addParameter(new QParameter(&frontend));
138
139 QRenderState *frontendState = new QBlendEquationArguments();
140 frontendState->setParent(&frontend);
141 frontend.addRenderState(frontendState);
142
143 RenderPass backend;
144
145 RenderStateNode *backendState = m_renderStateManager->getOrCreateResource(frontendState->id());
146 simulateInitialization(frontendState, backendState);
147
148 // WHEN
149 simulateInitialization(&frontend, &backend);
150
151 // THEN
152 QCOMPARE(backend.shaderProgram(), frontend.shaderProgram()->id());
153
154 QCOMPARE(backend.filterKeys().size(), 1);
155 QCOMPARE(backend.filterKeys().first(), frontend.filterKeys().first()->id());
156
157 QCOMPARE(backend.parameters().size(), 1);
158 QCOMPARE(backend.parameters().first(), frontend.parameters().first()->id());
159
160 QCOMPARE(backend.renderStates().size(), 1);
161 QCOMPARE(backend.renderStates().first(), backendState->peerId());
162 QVERIFY(backend.hasRenderStates());
163 }
164
165 void shouldHandleShaderPropertyChangeEvents()
166 {
167 // GIVEN
168 QScopedPointer<QShaderProgram> shader(new QShaderProgram);
169
170 RenderPass backend;
171 TestRenderer renderer;
172 backend.setRenderer(&renderer);
173
174 // WHEN
175 const auto addChange = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), shader.data());
176 addChange->setPropertyName("shaderProgram");
177 backend.sceneChangeEvent(addChange);
178
179 // THEN
180 QCOMPARE(backend.shaderProgram(), shader->id());
181 QVERIFY(renderer.dirtyBits() != 0);
182
183 // WHEN
184 const auto removeChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), shader.data());
185 removeChange->setPropertyName("shaderProgram");
186 backend.sceneChangeEvent(removeChange);
187
188 // THEN
189 QVERIFY(backend.shaderProgram().isNull());
190 }
191
192 void shouldHandleAnnotationsPropertyChangeEvents()
193 {
194 // GIVEN
195 QScopedPointer<QFilterKey> annotation(new QFilterKey);
196
197 RenderPass backend;
198 TestRenderer renderer;
199 backend.setRenderer(&renderer);
200
201 // WHEN
202 const auto addChange = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), annotation.data());
203 addChange->setPropertyName("filterKeys");
204 backend.sceneChangeEvent(addChange);
205
206 // THEN
207 QCOMPARE(backend.filterKeys().size(), 1);
208 QCOMPARE(backend.filterKeys().first(), annotation->id());
209 QVERIFY(renderer.dirtyBits() != 0);
210
211 // WHEN
212 const auto removeChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), annotation.data());
213 removeChange->setPropertyName("filterKeys");
214 backend.sceneChangeEvent(removeChange);
215
216 // THEN
217 QVERIFY(backend.filterKeys().isEmpty());
218 }
219
220 void shouldHandleParametersPropertyChangeEvents()
221 {
222 // GIVEN
223 QScopedPointer<QParameter> parameter(new QParameter);
224
225 RenderPass backend;
226 TestRenderer renderer;
227 backend.setRenderer(&renderer);
228
229 // WHEN
230 const auto addChange = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), parameter.data());
231 addChange->setPropertyName("parameter");
232 backend.sceneChangeEvent(addChange);
233
234 // THEN
235 QCOMPARE(backend.parameters().size(), 1);
236 QCOMPARE(backend.parameters().first(), parameter->id());
237 QVERIFY(renderer.dirtyBits() != 0);
238
239 // WHEN
240 const auto removeChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), parameter.data());
241 removeChange->setPropertyName("parameter");
242 backend.sceneChangeEvent(removeChange);
243
244 // THEN
245 QVERIFY(backend.parameters().isEmpty());
246 }
247
248 void shouldHandleRenderStatePropertyChangeEvents()
249 {
250 QRenderState *frontendState = new QBlendEquationArguments();
251
252 RenderPass backend;
253 TestRenderer renderer;
254 backend.setRenderer(&renderer);
255
256 RenderStateNode *backendState = m_renderStateManager->getOrCreateResource(frontendState->id());
257 simulateInitialization(frontendState, backendState);
258
259 // WHEN
260 const auto addChange = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), frontendState);
261 addChange->setPropertyName("renderState");
262 backend.sceneChangeEvent(addChange);
263
264 // THEN
265 QCOMPARE(backend.renderStates().size(), 1);
266 QCOMPARE(backend.renderStates().first(), backendState->peerId());
267 QVERIFY(renderer.dirtyBits() != 0);
268
269 // WHEN
270 const auto removeChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), frontendState);
271 removeChange->setPropertyName("renderState");
272 backend.sceneChangeEvent(removeChange);
273
274 // THEN
275 QVERIFY(backend.renderStates().isEmpty());
276 }
277
278 void shouldHandleShaderProgramPropertyChangeEvents()
279 {
280 // GIVEN
281 RenderPass backend;
282 TestRenderer renderer;
283 backend.setRenderer(&renderer);
284
285 // WHEN
286 Qt3DCore::QNodeId shaderId = Qt3DCore::QNodeId::createId();
287 const auto shaderChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
288 shaderChange->setPropertyName("shaderProgram");
289 shaderChange->setValue(QVariant::fromValue(shaderId));
290 backend.sceneChangeEvent(shaderChange);
291
292 // THEN
293 QCOMPARE(backend.shaderProgram(), shaderId);
294 }
295
296private:
297 RenderStateManager *m_renderStateManager;
298};
299
300QTEST_APPLESS_MAIN(tst_RenderRenderPass)
301
302#include "tst_renderpass.moc"
303