1/****************************************************************************
2**
3** Copyright (C) 2016 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
30#include <QtTest/QTest>
31#include <Qt3DCore/private/qaspectjobmanager_p.h>
32#include <Qt3DCore/private/qnodevisitor_p.h>
33#include <Qt3DCore/private/qnode_p.h>
34#include <Qt3DCore/qentity.h>
35#include <Qt3DRender/qtechnique.h>
36#include <Qt3DRender/qviewport.h>
37#include <Qt3DRender/private/technique_p.h>
38#include <Qt3DRender/private/nodemanagers_p.h>
39#include <Qt3DRender/private/qrenderaspect_p.h>
40#include <Qt3DRender/private/techniquemanager_p.h>
41#include <renderer_p.h>
42#include <submissioncontext_p.h>
43#include <filtercompatibletechniquejob_p.h>
44
45QT_BEGIN_NAMESPACE
46
47namespace Qt3DRender {
48
49class TestAspect : public Qt3DRender::QRenderAspect
50{
51public:
52 TestAspect(Qt3DCore::QNode *root)
53 : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
54 , m_jobManager(new Qt3DCore::QAspectJobManager())
55 , m_window(new QWindow())
56 , m_contextCreationSuccessful(false)
57 {
58 m_window->setSurfaceType(QWindow::OpenGLSurface);
59 m_window->setGeometry(posx: 0, posy: 0, w: 10, h: 10);
60 m_window->create();
61
62 if (!m_glContext.create()) {
63 qWarning() << "Failed to create OpenGL context";
64 return;
65 }
66
67 if (!m_glContext.makeCurrent(surface: m_window.data())) {
68 qWarning() << "Failed to make OpenGL context current";
69 return;
70 }
71
72 m_contextCreationSuccessful = true;
73
74 Qt3DCore::QAbstractAspectPrivate::get(aspect: this)->m_jobManager = m_jobManager.data();
75 QRenderAspect::onRegistered();
76
77 QVector<Qt3DCore::QNode *> nodes;
78 Qt3DCore::QNodeVisitor v;
79 v.traverse(rootNode_: root, fN: [&nodes](Qt3DCore::QNode *node) {
80 Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(q: node);
81 d->m_typeInfo = const_cast<QMetaObject*>(Qt3DCore::QNodePrivate::findStaticMetaObject(metaObject: node->metaObject()));
82 d->m_hasBackendNode = true;
83 nodes << node;
84 });
85
86 for (const auto node: nodes)
87 d_func()->createBackendNode(change: {
88 .id: node->id(),
89 .metaObj: Qt3DCore::QNodePrivate::get(q: node)->m_typeInfo,
90 .type: Qt3DCore::NodeTreeChange::Added,
91 .node: node
92 });
93 }
94
95 ~TestAspect()
96 {
97 if (m_contextCreationSuccessful)
98 QRenderAspect::onUnregistered();
99 }
100
101 Qt3DRender::Render::NodeManagers *nodeManagers() const
102 {
103 return d_func()->m_renderer
104 ? d_func()->m_renderer->nodeManagers() : nullptr;
105 }
106
107 bool contextCreationSuccessful() const
108 {
109 return m_contextCreationSuccessful;
110 }
111
112 void initializeRenderer()
113 {
114 renderer()->setOpenGLContext(&m_glContext);
115 d_func()->m_renderer->initialize();
116 renderer()->submissionContext()->beginDrawing(surface: m_window.data());
117 }
118
119 Render::OpenGL::Renderer *renderer() const
120 {
121 return static_cast<Render::OpenGL::Renderer *>(d_func()->m_renderer);
122 }
123
124 void onRegistered() { QRenderAspect::onRegistered(); }
125 void onUnregistered() { QRenderAspect::onUnregistered(); }
126
127private:
128 QScopedPointer<Qt3DCore::QAspectJobManager> m_jobManager;
129 QScopedPointer<QWindow> m_window;
130 QOpenGLContext m_glContext;
131 bool m_contextCreationSuccessful;
132};
133
134} // namespace Qt3DRender
135
136QT_END_NAMESPACE
137
138namespace {
139
140Qt3DCore::QEntity *buildTestScene()
141{
142 Qt3DCore::QEntity *root = new Qt3DCore::QEntity();
143
144 // FrameGraph
145 Qt3DRender::QRenderSettings* renderSettings = new Qt3DRender::QRenderSettings();
146 renderSettings->setActiveFrameGraph(new Qt3DRender::QViewport());
147 root->addComponent(comp: renderSettings);
148
149 // Scene
150 Qt3DRender::QTechnique *gl2Technique = new Qt3DRender::QTechnique(root);
151 gl2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
152 gl2Technique->graphicsApiFilter()->setMajorVersion(2);
153 gl2Technique->graphicsApiFilter()->setMinorVersion(0);
154 gl2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile);
155
156 Qt3DRender::QTechnique *gl3Technique = new Qt3DRender::QTechnique(root);
157 gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
158 gl3Technique->graphicsApiFilter()->setMajorVersion(3);
159 gl3Technique->graphicsApiFilter()->setMinorVersion(2);
160 gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);
161
162 Qt3DRender::QTechnique *es2Technique = new Qt3DRender::QTechnique(root);
163 es2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGLES);
164 es2Technique->graphicsApiFilter()->setMajorVersion(2);
165 es2Technique->graphicsApiFilter()->setMinorVersion(0);
166 es2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile);
167
168 return root;
169}
170
171} // anonymous
172
173class tst_FilterCompatibleTechniqueJob : public QObject
174{
175 Q_OBJECT
176
177private Q_SLOTS:
178
179 void initTestCase()
180 {
181 QSurfaceFormat format;
182#ifdef QT_OPENGL_ES_2
183 format.setRenderableType(QSurfaceFormat::OpenGLES);
184#else
185 if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
186 format.setVersion(major: 4, minor: 3);
187 format.setProfile(QSurfaceFormat::CoreProfile);
188 }
189#endif
190 format.setDepthBufferSize(24);
191 format.setSamples(4);
192 format.setStencilBufferSize(8);
193 QSurfaceFormat::setDefaultFormat(format);
194 }
195
196 void checkInitialState()
197 {
198 // GIVEN
199 Qt3DRender::Render::OpenGL::FilterCompatibleTechniqueJob backendFilterCompatibleTechniqueJob;
200
201 // THEN
202 QVERIFY(backendFilterCompatibleTechniqueJob.manager() == nullptr);
203 QVERIFY(backendFilterCompatibleTechniqueJob.renderer() == nullptr);
204
205 // WHEN
206 Qt3DRender::Render::TechniqueManager techniqueManager;
207 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
208 backendFilterCompatibleTechniqueJob.setManager(&techniqueManager);
209 backendFilterCompatibleTechniqueJob.setRenderer(&renderer);
210
211 // THEN
212 QCOMPARE(backendFilterCompatibleTechniqueJob.manager(), &techniqueManager);
213 QCOMPARE(backendFilterCompatibleTechniqueJob.renderer(), &renderer);
214
215 renderer.shutdown();
216 }
217
218 void checkRunRendererRunning()
219 {
220 // GIVEN
221 Qt3DRender::Render::OpenGL::FilterCompatibleTechniqueJob backendFilterCompatibleTechniqueJob;
222 Qt3DRender::TestAspect testAspect(buildTestScene());
223
224 const bool unableToCreateContext = !testAspect.contextCreationSuccessful();
225
226 if (unableToCreateContext)
227 QSKIP("Initialization failed, unable to create GL context");
228
229 // WHEN
230 Qt3DRender::Render::NodeManagers *nodeManagers = testAspect.nodeManagers();
231 QVERIFY(nodeManagers);
232 Qt3DRender::Render::TechniqueManager *techniqueManager = nodeManagers->techniqueManager();
233 QVERIFY(techniqueManager);
234 backendFilterCompatibleTechniqueJob.setManager(techniqueManager);
235 backendFilterCompatibleTechniqueJob.setRenderer(testAspect.renderer());
236 testAspect.initializeRenderer();
237
238 // THEN
239 QCOMPARE(testAspect.renderer()->isRunning(), true);
240 QCOMPARE(testAspect.renderer()->submissionContext()->isInitialized(), true);
241 const std::vector<Qt3DRender::Render::HTechnique> &handles = testAspect.nodeManagers()->techniqueManager()->activeHandles();
242 QCOMPARE(handles.size(), 3);
243
244 // WHEN
245 backendFilterCompatibleTechniqueJob.run();
246
247 // THEN -> empty if job ran properly
248 const QVector<Qt3DCore::QNodeId> dirtyTechniquesId = testAspect.nodeManagers()->techniqueManager()->takeDirtyTechniques();
249 QCOMPARE(dirtyTechniquesId.size(), 0);
250
251 // Check at least one technique is valid
252 bool foundValid = false;
253 for (const auto handle: handles) {
254 Qt3DRender::Render::Technique *technique = testAspect.nodeManagers()->techniqueManager()->data(handle);
255 foundValid |= technique->isCompatibleWithRenderer();
256 }
257 QCOMPARE(foundValid, true);
258 }
259};
260
261QTEST_MAIN(tst_FilterCompatibleTechniqueJob)
262
263#include "tst_filtercompatibletechniquejob.moc"
264

source code of qt3d/tests/auto/render/opengl/filtercompatibletechniquejob/tst_filtercompatibletechniquejob.cpp