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 "qrenderaspect.h" |
41 | #include "qrenderaspect_p.h" |
42 | |
43 | #include <Qt3DRender/private/nodemanagers_p.h> |
44 | #include <Qt3DRender/private/abstractrenderer_p.h> |
45 | #include <Qt3DRender/private/scenemanager_p.h> |
46 | #include <Qt3DRender/private/geometryrenderermanager_p.h> |
47 | |
48 | #include <Qt3DRender/qsceneloader.h> |
49 | #include <Qt3DRender/qcamera.h> |
50 | #include <Qt3DRender/qcameraselector.h> |
51 | #include <Qt3DRender/qlayer.h> |
52 | #include <Qt3DRender/qlayerfilter.h> |
53 | #include <Qt3DRender/qlevelofdetail.h> |
54 | #include <Qt3DRender/qlevelofdetailswitch.h> |
55 | #include <Qt3DRender/qmaterial.h> |
56 | #include <Qt3DRender/qmesh.h> |
57 | #include <Qt3DRender/qparameter.h> |
58 | #include <Qt3DRender/qrenderpassfilter.h> |
59 | #include <Qt3DRender/qrenderpass.h> |
60 | #include <Qt3DRender/qrendertargetselector.h> |
61 | #include <Qt3DRender/qtechniquefilter.h> |
62 | #include <Qt3DRender/qtechnique.h> |
63 | #include <Qt3DRender/qviewport.h> |
64 | #include <Qt3DRender/qrendertarget.h> |
65 | #include <Qt3DRender/qclearbuffers.h> |
66 | #include <Qt3DRender/qtexture.h> |
67 | #include <Qt3DRender/qeffect.h> |
68 | #include <Qt3DRender/qshaderdata.h> |
69 | #include <Qt3DRender/qrenderstateset.h> |
70 | #include <Qt3DRender/qnodraw.h> |
71 | #include <Qt3DRender/qnopicking.h> |
72 | #include <Qt3DRender/qcameralens.h> |
73 | #include <Qt3DRender/qattribute.h> |
74 | #include <Qt3DRender/qbuffer.h> |
75 | #include <Qt3DRender/qgeometry.h> |
76 | #include <Qt3DRender/qgeometryrenderer.h> |
77 | #include <Qt3DRender/qobjectpicker.h> |
78 | #include <Qt3DRender/qraycaster.h> |
79 | #include <Qt3DRender/qscreenraycaster.h> |
80 | #include <Qt3DRender/qfrustumculling.h> |
81 | #include <Qt3DRender/qabstractlight.h> |
82 | #include <Qt3DRender/qenvironmentlight.h> |
83 | #include <Qt3DRender/qdispatchcompute.h> |
84 | #include <Qt3DRender/qcomputecommand.h> |
85 | #include <Qt3DRender/qrendersurfaceselector.h> |
86 | #include <Qt3DRender/qrendersettings.h> |
87 | #include <Qt3DRender/qrendercapture.h> |
88 | #include <Qt3DRender/qbuffercapture.h> |
89 | #include <Qt3DRender/qmemorybarrier.h> |
90 | #include <Qt3DRender/qproximityfilter.h> |
91 | #include <Qt3DRender/qshaderprogrambuilder.h> |
92 | #include <Qt3DRender/qblitframebuffer.h> |
93 | #include <Qt3DRender/qsetfence.h> |
94 | #include <Qt3DRender/qwaitfence.h> |
95 | #include <Qt3DRender/qshaderimage.h> |
96 | #include <Qt3DRender/qsubtreeenabler.h> |
97 | #include <Qt3DRender/qdebugoverlay.h> |
98 | #include <Qt3DCore/qarmature.h> |
99 | #include <Qt3DCore/qjoint.h> |
100 | #include <Qt3DCore/qskeletonloader.h> |
101 | |
102 | #include <Qt3DRender/private/backendnode_p.h> |
103 | #include <Qt3DRender/private/cameraselectornode_p.h> |
104 | #include <Qt3DRender/private/layerfilternode_p.h> |
105 | #include <Qt3DRender/private/cameralens_p.h> |
106 | #include <Qt3DRender/private/filterkey_p.h> |
107 | #include <Qt3DRender/private/entity_p.h> |
108 | #include <Qt3DRender/private/abstractrenderer_p.h> |
109 | #include <Qt3DRender/private/shaderdata_p.h> |
110 | #include <Qt3DRender/private/renderpassfilternode_p.h> |
111 | #include <Qt3DRender/private/rendertargetselectornode_p.h> |
112 | #include <Qt3DRender/private/techniquefilternode_p.h> |
113 | #include <Qt3DRender/private/viewportnode_p.h> |
114 | #include <Qt3DRender/private/rendertarget_p.h> |
115 | #include <Qt3DRender/private/scenemanager_p.h> |
116 | #include <Qt3DRender/private/clearbuffers_p.h> |
117 | #include <Qt3DRender/private/sortpolicy_p.h> |
118 | #include <Qt3DRender/private/renderlogging_p.h> |
119 | #include <Qt3DRender/private/nodefunctor_p.h> |
120 | #include <Qt3DRender/private/framegraphnode_p.h> |
121 | #include <Qt3DRender/private/textureimage_p.h> |
122 | #include <Qt3DRender/private/statesetnode_p.h> |
123 | #include <Qt3DRender/private/nodraw_p.h> |
124 | #include <Qt3DRender/private/nopicking_p.h> |
125 | #include <Qt3DRender/private/vsyncframeadvanceservice_p.h> |
126 | #include <Qt3DRender/private/attribute_p.h> |
127 | #include <Qt3DRender/private/buffer_p.h> |
128 | #include <Qt3DRender/private/geometry_p.h> |
129 | #include <Qt3DRender/private/geometryrenderer_p.h> |
130 | #include <Qt3DRender/private/objectpicker_p.h> |
131 | #include <Qt3DRender/private/raycaster_p.h> |
132 | #include <Qt3DRender/private/boundingvolumedebug_p.h> |
133 | #include <Qt3DRender/private/nodemanagers_p.h> |
134 | #include <Qt3DRender/private/calcgeometrytrianglevolumes_p.h> |
135 | #include <Qt3DRender/private/handle_types_p.h> |
136 | #include <Qt3DRender/private/buffermanager_p.h> |
137 | #include <Qt3DRender/private/geometryrenderermanager_p.h> |
138 | #include <Qt3DRender/private/loadgeometryjob_p.h> |
139 | #include <Qt3DRender/private/qsceneimportfactory_p.h> |
140 | #include <Qt3DRender/private/qsceneimporter_p.h> |
141 | #include <Qt3DRender/private/frustumculling_p.h> |
142 | #include <Qt3DRender/private/light_p.h> |
143 | #include <Qt3DRender/private/environmentlight_p.h> |
144 | #include <Qt3DRender/private/dispatchcompute_p.h> |
145 | #include <Qt3DRender/private/computecommand_p.h> |
146 | #include <Qt3DRender/private/rendersurfaceselector_p.h> |
147 | #include <Qt3DRender/private/rendersettings_p.h> |
148 | #include <Qt3DRender/private/backendnode_p.h> |
149 | #include <Qt3DRender/private/rendercapture_p.h> |
150 | #include <Qt3DRender/private/buffercapture_p.h> |
151 | #include <Qt3DRender/private/technique_p.h> |
152 | #include <Qt3DRender/private/offscreensurfacehelper_p.h> |
153 | #include <Qt3DRender/private/memorybarrier_p.h> |
154 | #include <Qt3DRender/private/shaderbuilder_p.h> |
155 | #include <Qt3DRender/private/blitframebuffer_p.h> |
156 | #include <Qt3DRender/private/subtreeenabler_p.h> |
157 | #include <Qt3DRender/private/armature_p.h> |
158 | #include <Qt3DRender/private/skeleton_p.h> |
159 | #include <Qt3DRender/private/joint_p.h> |
160 | #include <Qt3DRender/private/loadskeletonjob_p.h> |
161 | #include <Qt3DRender/private/proximityfilter_p.h> |
162 | #include <Qt3DRender/private/setfence_p.h> |
163 | #include <Qt3DRender/private/waitfence_p.h> |
164 | #include <Qt3DRender/private/shaderimage_p.h> |
165 | #include <Qt3DRender/private/debugoverlay_p.h> |
166 | #include <Qt3DRender/private/qrendererpluginfactory_p.h> |
167 | #include <Qt3DRender/private/updatelevelofdetailjob_p.h> |
168 | #include <Qt3DRender/private/job_common_p.h> |
169 | #include <Qt3DRender/private/pickeventfilter_p.h> |
170 | #include <Qt3DRender/private/loadbufferjob_p.h> |
171 | #include <Qt3DRender/private/techniquemanager_p.h> |
172 | #include <Qt3DRender/private/qgraphicsapifilter_p.h> |
173 | |
174 | #include <private/qrenderpluginfactory_p.h> |
175 | #include <private/qrenderplugin_p.h> |
176 | |
177 | #include <Qt3DCore/qentity.h> |
178 | #include <Qt3DCore/qtransform.h> |
179 | |
180 | #include <Qt3DCore/qnode.h> |
181 | #include <Qt3DCore/QAspectEngine> |
182 | #include <Qt3DCore/private/qservicelocator_p.h> |
183 | #include <Qt3DCore/private/qscene_p.h> |
184 | #include <Qt3DCore/private/qentity_p.h> |
185 | #include <Qt3DCore/private/qaspectmanager_p.h> |
186 | #include <Qt3DCore/private/qeventfilterservice_p.h> |
187 | |
188 | #include <QThread> |
189 | #include <QOpenGLContext> |
190 | |
191 | QT_BEGIN_NAMESPACE |
192 | |
193 | using namespace Qt3DCore; |
194 | |
195 | namespace { |
196 | |
197 | QString dumpNode(const Qt3DCore::QEntity *n) { |
198 | auto formatNode = [](const Qt3DCore::QNode *n) { |
199 | QString res = QString(QLatin1String("%1{%2}" )) |
200 | .arg(a: QLatin1String(n->metaObject()->className())) |
201 | .arg(a: n->id().id()); |
202 | if (!n->objectName().isEmpty()) |
203 | res += QString(QLatin1String(" (%1)" )).arg(a: n->objectName()); |
204 | if (!n->isEnabled()) |
205 | res += QLatin1String(" [D]" ); |
206 | return res; |
207 | }; |
208 | |
209 | return formatNode(n); |
210 | } |
211 | |
212 | QString dumpNodeFilters(const QString &filterType, const QVector<Qt3DRender::QFilterKey*> &filters) { |
213 | QString res; |
214 | |
215 | QStringList kv; |
216 | for (auto filter: filters) |
217 | kv.push_back(t: QString(QLatin1String("%1: %2" )).arg(args: filter->name(), args: filter->value().toString())); |
218 | if (kv.size()) |
219 | res += QString(QLatin1String("%1 <%2>" )).arg(args: filterType, args: kv.join(sep: QLatin1String(", " ))); |
220 | |
221 | return res; |
222 | } |
223 | |
224 | QStringList dumpSGFilterState(Qt3DRender::Render::TechniqueManager *manager, |
225 | const Qt3DRender::GraphicsApiFilterData *contextData, |
226 | const Qt3DCore::QNode *n, int level = 0) |
227 | { |
228 | using namespace Qt3DRender; |
229 | |
230 | QStringList reply; |
231 | const auto *entity = qobject_cast<const Qt3DCore::QEntity *>(object: n); |
232 | if (entity != nullptr) { |
233 | QString res = dumpNode(n: entity); |
234 | auto materials = entity->componentsOfType<QMaterial>(); |
235 | if (materials.size() && materials.front()->effect()) { |
236 | auto m = materials.front(); |
237 | const auto techniques = m->effect()->techniques(); |
238 | for (auto t: m->effect()->techniques()) { |
239 | auto apiFilter = t->graphicsApiFilter(); |
240 | if (apiFilter) { |
241 | auto backendTechnique = manager->lookupResource(id: t->id()); |
242 | if (backendTechnique && |
243 | !(*contextData == *backendTechnique->graphicsApiFilter())) |
244 | continue; // skip technique that doesn't match current renderer |
245 | } |
246 | |
247 | QStringList filters; |
248 | filters += dumpNodeFilters(filterType: QLatin1String("T" ), filters: t->filterKeys()); |
249 | |
250 | const auto &renderPasses = t->renderPasses(); |
251 | for (auto r: renderPasses) |
252 | filters += dumpNodeFilters(filterType: QLatin1String("RP" ), filters: r->filterKeys()); |
253 | |
254 | if (filters.size()) |
255 | res += QLatin1String(" [ %1 ]" ).arg(args: filters.join(sep: QLatin1String(" " ))); |
256 | } |
257 | } |
258 | reply += res.rightJustified(width: res.length() + level * 2, fill: ' '); |
259 | level++; |
260 | } |
261 | |
262 | const auto children = n->childNodes(); |
263 | for (auto *child: children) |
264 | reply += dumpSGFilterState(manager, contextData, n: child, level); |
265 | |
266 | return reply; |
267 | } |
268 | |
269 | } |
270 | namespace Qt3DRender { |
271 | |
272 | #define CreateSynchronizerJobPtr(lambda, type) \ |
273 | Render::SynchronizerJobPtr::create(lambda, type, #type) |
274 | |
275 | /*! |
276 | * \class Qt3DRender::QRenderAspect |
277 | * \inheaderfile Qt3DRender/QRenderAspect |
278 | * \brief The QRenderAspect class. |
279 | * \since 5.7 |
280 | * \inmodule Qt3DRender |
281 | */ |
282 | |
283 | /*! |
284 | \namespace Qt3DRender::Render |
285 | \inmodule Qt3DRender |
286 | |
287 | \brief Namespace used for accessing the classes |
288 | Renderer and QRenderPlugin. |
289 | */ |
290 | /*! \internal */ |
291 | QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) |
292 | : QAbstractAspectPrivate() |
293 | , m_nodeManagers(nullptr) |
294 | , m_renderer(nullptr) |
295 | , m_initialized(false) |
296 | , m_renderAfterJobs(false) |
297 | , m_renderType(type) |
298 | , m_offscreenHelper(nullptr) |
299 | , m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create()) |
300 | , m_worldTransformJob(Render::UpdateWorldTransformJobPtr::create()) |
301 | , m_expandBoundingVolumeJob(Render::ExpandBoundingVolumeJobPtr::create()) |
302 | , m_calculateBoundingVolumeJob(Render::CalculateBoundingVolumeJobPtr::create()) |
303 | , m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create()) |
304 | , m_updateSkinningPaletteJob(Render::UpdateSkinningPaletteJobPtr::create()) |
305 | , m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create()) |
306 | , m_updateEntityLayersJob(Render::UpdateEntityLayersJobPtr::create()) |
307 | , m_syncLoadingJobs(CreateSynchronizerJobPtr([] {}, Render::JobTypes::SyncLoadingJobs)) |
308 | , m_pickBoundingVolumeJob(Render::PickBoundingVolumeJobPtr::create()) |
309 | , m_rayCastingJob(Render::RayCastingJobPtr::create()) |
310 | , m_pickEventFilter(new Render::PickEventFilter()) |
311 | { |
312 | m_instances.append(t: this); |
313 | loadSceneParsers(); |
314 | if (m_renderType == QRenderAspect::Threaded && !QOpenGLContext::supportsThreadedOpenGL()) { |
315 | m_renderType = QRenderAspect::Synchronous; |
316 | m_renderAfterJobs = true; |
317 | } |
318 | |
319 | m_updateWorldBoundingVolumeJob->addDependency(dependency: m_worldTransformJob); |
320 | m_updateWorldBoundingVolumeJob->addDependency(dependency: m_calculateBoundingVolumeJob); |
321 | m_calculateBoundingVolumeJob->addDependency(dependency: m_updateTreeEnabledJob); |
322 | m_expandBoundingVolumeJob->addDependency(dependency: m_updateWorldBoundingVolumeJob); |
323 | m_updateLevelOfDetailJob->addDependency(dependency: m_expandBoundingVolumeJob); |
324 | m_pickBoundingVolumeJob->addDependency(dependency: m_expandBoundingVolumeJob); |
325 | m_pickBoundingVolumeJob->addDependency(dependency: m_updateEntityLayersJob); |
326 | m_rayCastingJob->addDependency(dependency: m_expandBoundingVolumeJob); |
327 | m_rayCastingJob->addDependency(dependency: m_updateEntityLayersJob); |
328 | } |
329 | |
330 | /*! \internal */ |
331 | QRenderAspectPrivate::~QRenderAspectPrivate() |
332 | { |
333 | // The renderer should have been shutdown as part of onUnregistered(). |
334 | // If it still exists then this aspect is being deleted before the aspect |
335 | // engine is finished with it. |
336 | if (m_renderer != nullptr) |
337 | qWarning() << Q_FUNC_INFO << "The renderer should have been deleted when reaching this point (this warning may be normal when running tests)" ; |
338 | delete m_nodeManagers; |
339 | m_instances.removeAll(t: this); |
340 | qDeleteAll(c: m_sceneImporter); |
341 | } |
342 | |
343 | QRenderAspectPrivate *QRenderAspectPrivate::findPrivate(Qt3DCore::QAspectEngine *engine) |
344 | { |
345 | const QVector<QAbstractAspect*> aspects = engine->aspects(); |
346 | for (QAbstractAspect* aspect : aspects) { |
347 | QRenderAspect *renderAspect = qobject_cast<QRenderAspect *>(object: aspect); |
348 | if (renderAspect) |
349 | return static_cast<QRenderAspectPrivate *>(renderAspect->d_ptr.data()); |
350 | } |
351 | return nullptr; |
352 | } |
353 | |
354 | QRenderAspectPrivate *QRenderAspectPrivate::get(QRenderAspect *q) |
355 | { |
356 | return q->d_func(); |
357 | } |
358 | |
359 | void QRenderAspectPrivate::syncDirtyFrontEndNode(QNode *node, QBackendNode *backend, bool firstTime) const |
360 | { |
361 | Render::BackendNode *renderBackend = static_cast<Render::BackendNode *>(backend); |
362 | renderBackend->syncFromFrontEnd(frontEnd: node, firstTime); |
363 | } |
364 | |
365 | void QRenderAspectPrivate::jobsDone() |
366 | { |
367 | m_renderer->jobsDone(manager: m_aspectManager); |
368 | } |
369 | |
370 | void QRenderAspectPrivate::frameDone() |
371 | { |
372 | m_renderer->setJobsInLastFrame(m_aspectManager->jobsInLastFrame()); |
373 | if (m_renderAfterJobs) |
374 | m_renderer->doRender(swapBuffers: true); |
375 | } |
376 | |
377 | void QRenderAspectPrivate::createNodeManagers() |
378 | { |
379 | m_nodeManagers = new Render::NodeManagers(); |
380 | |
381 | m_updateTreeEnabledJob->setManagers(m_nodeManagers); |
382 | m_worldTransformJob->setManagers(m_nodeManagers); |
383 | m_expandBoundingVolumeJob->setManagers(m_nodeManagers); |
384 | m_calculateBoundingVolumeJob->setManagers(m_nodeManagers); |
385 | m_updateWorldBoundingVolumeJob->setManager(m_nodeManagers->renderNodesManager()); |
386 | m_updateSkinningPaletteJob->setManagers(m_nodeManagers); |
387 | m_updateLevelOfDetailJob->setManagers(m_nodeManagers); |
388 | m_updateEntityLayersJob->setManager(m_nodeManagers); |
389 | m_pickBoundingVolumeJob->setManagers(m_nodeManagers); |
390 | m_rayCastingJob->setManagers(m_nodeManagers); |
391 | } |
392 | |
393 | void QRenderAspectPrivate::onEngineStartup() |
394 | { |
395 | Render::Entity *rootEntity = m_nodeManagers->lookupResource<Render::Entity, Render::EntityManager>(id: m_rootId); |
396 | Q_ASSERT(rootEntity); |
397 | m_renderer->setSceneRoot(rootEntity); |
398 | |
399 | m_worldTransformJob->setRoot(rootEntity); |
400 | m_expandBoundingVolumeJob->setRoot(rootEntity); |
401 | m_calculateBoundingVolumeJob->setRoot(rootEntity); |
402 | m_updateLevelOfDetailJob->setRoot(rootEntity); |
403 | m_updateSkinningPaletteJob->setRoot(rootEntity); |
404 | m_updateTreeEnabledJob->setRoot(rootEntity); |
405 | m_pickBoundingVolumeJob->setRoot(rootEntity); |
406 | m_rayCastingJob->setRoot(rootEntity); |
407 | |
408 | // Ensures all skeletons are loaded before we try to update them |
409 | m_updateSkinningPaletteJob->addDependency(dependency: m_syncLoadingJobs); |
410 | } |
411 | |
412 | /*! \internal */ |
413 | void QRenderAspectPrivate::registerBackendTypes() |
414 | { |
415 | Q_Q(QRenderAspect); |
416 | |
417 | qRegisterMetaType<Qt3DRender::QBuffer*>(); |
418 | qRegisterMetaType<Qt3DRender::QEffect*>(); |
419 | qRegisterMetaType<Qt3DRender::QFrameGraphNode *>(); |
420 | qRegisterMetaType<Qt3DRender::QCamera*>(); |
421 | qRegisterMetaType<Qt3DRender::QShaderProgram*>(); |
422 | qRegisterMetaType<Qt3DRender::QViewport*>(); |
423 | qRegisterMetaType<Qt3DCore::QJoint*>(); |
424 | |
425 | q->registerBackendType<Qt3DCore::QEntity, true>(functor: QSharedPointer<Render::RenderEntityFunctor>::create(arguments&: m_renderer, arguments&: m_nodeManagers)); |
426 | q->registerBackendType<Qt3DCore::QTransform, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Transform, Render::TransformManager> >::create(arguments&: m_renderer)); |
427 | |
428 | q->registerBackendType<Qt3DRender::QCameraLens, true>(functor: QSharedPointer<Render::CameraLensFunctor>::create(arguments&: m_renderer, arguments: q)); |
429 | q->registerBackendType<QLayer, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Layer, Render::LayerManager> >::create(arguments&: m_renderer)); |
430 | q->registerBackendType<QLevelOfDetail, true>(functor: QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(arguments&: m_renderer)); |
431 | q->registerBackendType<QLevelOfDetailSwitch, true>(functor: QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(arguments&: m_renderer)); |
432 | q->registerBackendType<QSceneLoader, true>(functor: QSharedPointer<Render::RenderSceneFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->sceneManager())); |
433 | q->registerBackendType<QRenderTarget, true>(functor: QSharedPointer<Render::RenderTargetFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->renderTargetManager())); |
434 | q->registerBackendType<QRenderTargetOutput, true>(functor: QSharedPointer<Render::NodeFunctor<Render::RenderTargetOutput, Render::AttachmentManager> >::create(arguments&: m_renderer)); |
435 | q->registerBackendType<QRenderSettings, true>(functor: QSharedPointer<Render::RenderSettingsFunctor>::create(arguments&: m_renderer)); |
436 | q->registerBackendType<QRenderState, true>(functor: QSharedPointer<Render::NodeFunctor<Render::RenderStateNode, Render::RenderStateManager> >::create(arguments&: m_renderer)); |
437 | |
438 | // Geometry + Compute |
439 | q->registerBackendType<QAttribute, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Attribute, Render::AttributeManager> >::create(arguments&: m_renderer)); |
440 | q->registerBackendType<QBuffer, true>(functor: QSharedPointer<Render::BufferFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->bufferManager())); |
441 | q->registerBackendType<QComputeCommand, true>(functor: QSharedPointer<Render::NodeFunctor<Render::ComputeCommand, Render::ComputeCommandManager> >::create(arguments&: m_renderer)); |
442 | q->registerBackendType<QGeometry, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Geometry, Render::GeometryManager> >::create(arguments&: m_renderer)); |
443 | q->registerBackendType<QGeometryRenderer, true>(functor: QSharedPointer<Render::GeometryRendererFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->geometryRendererManager())); |
444 | q->registerBackendType<Qt3DCore::QArmature, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Armature, Render::ArmatureManager>>::create(arguments&: m_renderer)); |
445 | q->registerBackendType<Qt3DCore::QAbstractSkeleton, true>(functor: QSharedPointer<Render::SkeletonFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->skeletonManager(), arguments: m_nodeManagers->jointManager())); |
446 | q->registerBackendType<Qt3DCore::QJoint, true>(functor: QSharedPointer<Render::JointFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->jointManager(), arguments: m_nodeManagers->skeletonManager())); |
447 | |
448 | // Textures |
449 | q->registerBackendType<QAbstractTexture, true>(functor: QSharedPointer<Render::TextureFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->textureManager())); |
450 | q->registerBackendType<QAbstractTextureImage, true>(functor: QSharedPointer<Render::TextureImageFunctor>::create(arguments&: m_renderer, |
451 | arguments: m_nodeManagers->textureImageManager())); |
452 | |
453 | // Material system |
454 | q->registerBackendType<QEffect, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Effect, Render::EffectManager> >::create(arguments&: m_renderer)); |
455 | q->registerBackendType<QFilterKey, true>(functor: QSharedPointer<Render::NodeFunctor<Render::FilterKey, Render::FilterKeyManager> >::create(arguments&: m_renderer)); |
456 | q->registerBackendType<QAbstractLight, true>(functor: QSharedPointer<Render::RenderLightFunctor>::create(arguments&: m_renderer, arguments&: m_nodeManagers)); |
457 | q->registerBackendType<QEnvironmentLight, true>(functor: QSharedPointer<Render::NodeFunctor<Render::EnvironmentLight, Render::EnvironmentLightManager> >::create(arguments&: m_renderer)); |
458 | q->registerBackendType<QMaterial, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Material, Render::MaterialManager> >::create(arguments&: m_renderer)); |
459 | q->registerBackendType<QParameter, true>(functor: QSharedPointer<Render::NodeFunctor<Render::Parameter, Render::ParameterManager> >::create(arguments&: m_renderer)); |
460 | q->registerBackendType<QRenderPass, true>(functor: QSharedPointer<Render::NodeFunctor<Render::RenderPass, Render::RenderPassManager> >::create(arguments&: m_renderer)); |
461 | q->registerBackendType<QShaderData, true>(functor: QSharedPointer<Render::RenderShaderDataFunctor>::create(arguments&: m_renderer, arguments&: m_nodeManagers)); |
462 | q->registerBackendType<QShaderProgram, true>(functor: QSharedPointer<Render::ShaderFunctor>::create(arguments&: m_renderer, arguments: m_nodeManagers->shaderManager())); |
463 | q->registerBackendType<QShaderProgramBuilder, true>(functor: QSharedPointer<Render::NodeFunctor<Render::ShaderBuilder, Render::ShaderBuilderManager> >::create(arguments&: m_renderer)); |
464 | q->registerBackendType<QTechnique, true>(functor: QSharedPointer<Render::TechniqueFunctor>::create(arguments&: m_renderer, arguments&: m_nodeManagers)); |
465 | q->registerBackendType<QShaderImage, true>(functor: QSharedPointer<Render::NodeFunctor<Render::ShaderImage, Render::ShaderImageManager>>::create(arguments&: m_renderer)); |
466 | |
467 | // Framegraph |
468 | q->registerBackendType<QFrameGraphNode, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrameGraphNode, QFrameGraphNode> >::create(arguments&: m_renderer)); |
469 | q->registerBackendType<QCameraSelector, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::CameraSelector, QCameraSelector> >::create(arguments&: m_renderer)); |
470 | q->registerBackendType<QClearBuffers, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::ClearBuffers, QClearBuffers> >::create(arguments&: m_renderer)); |
471 | q->registerBackendType<QDispatchCompute, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::DispatchCompute, QDispatchCompute> >::create(arguments&: m_renderer)); |
472 | q->registerBackendType<QFrustumCulling, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrustumCulling, QFrustumCulling> >::create(arguments&: m_renderer)); |
473 | q->registerBackendType<QLayerFilter, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::LayerFilterNode, QLayerFilter> >::create(arguments&: m_renderer)); |
474 | q->registerBackendType<QNoDraw, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::NoDraw, QNoDraw> >::create(arguments&: m_renderer)); |
475 | q->registerBackendType<QRenderPassFilter, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderPassFilter, QRenderPassFilter> >::create(arguments&: m_renderer)); |
476 | q->registerBackendType<QRenderStateSet, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::StateSetNode, QRenderStateSet> >::create(arguments&: m_renderer)); |
477 | q->registerBackendType<QRenderSurfaceSelector, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderSurfaceSelector, QRenderSurfaceSelector> >::create(arguments&: m_renderer)); |
478 | q->registerBackendType<QRenderTargetSelector, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderTargetSelector, QRenderTargetSelector> >::create(arguments&: m_renderer)); |
479 | q->registerBackendType<QSortPolicy, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::SortPolicy, QSortPolicy> >::create(arguments&: m_renderer)); |
480 | q->registerBackendType<QTechniqueFilter, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::TechniqueFilter, QTechniqueFilter> >::create(arguments&: m_renderer)); |
481 | q->registerBackendType<QViewport, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::ViewportNode, QViewport> >::create(arguments&: m_renderer)); |
482 | q->registerBackendType<QRenderCapture, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderCapture, QRenderCapture> >::create(arguments&: m_renderer)); |
483 | q->registerBackendType<QBufferCapture, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::BufferCapture, QBufferCapture> >::create(arguments&: m_renderer)); |
484 | q->registerBackendType<QMemoryBarrier, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::MemoryBarrier, QMemoryBarrier> >::create(arguments&: m_renderer)); |
485 | q->registerBackendType<QProximityFilter, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::ProximityFilter, QProximityFilter> >::create(arguments&: m_renderer)); |
486 | q->registerBackendType<QBlitFramebuffer, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::BlitFramebuffer, QBlitFramebuffer> >::create(arguments&: m_renderer)); |
487 | q->registerBackendType<QSetFence, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::SetFence, QSetFence> >::create(arguments&: m_renderer)); |
488 | q->registerBackendType<QWaitFence, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::WaitFence, QWaitFence> >::create(arguments&: m_renderer)); |
489 | q->registerBackendType<QNoPicking, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::NoPicking, QNoPicking> >::create(arguments&: m_renderer)); |
490 | q->registerBackendType<QSubtreeEnabler, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::SubtreeEnabler, QSubtreeEnabler> >::create(arguments&: m_renderer)); |
491 | q->registerBackendType<QDebugOverlay, true>(functor: QSharedPointer<Render::FrameGraphNodeFunctor<Render::DebugOverlay, QDebugOverlay> >::create(arguments&: m_renderer)); |
492 | |
493 | // Picking |
494 | q->registerBackendType<QObjectPicker, true>(functor: QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(arguments&: m_renderer)); |
495 | q->registerBackendType<QRayCaster, true>(functor: QSharedPointer<Render::NodeFunctor<Render::RayCaster, Render::RayCasterManager> >::create(arguments&: m_renderer)); |
496 | q->registerBackendType<QScreenRayCaster, true>(functor: QSharedPointer<Render::NodeFunctor<Render::RayCaster, Render::RayCasterManager> >::create(arguments&: m_renderer)); |
497 | |
498 | // Plugins |
499 | for (const QString &plugin : qAsConst(t&: m_pluginConfig)) |
500 | loadRenderPlugin(pluginName: plugin); |
501 | } |
502 | |
503 | /*! \internal */ |
504 | void QRenderAspectPrivate::unregisterBackendTypes() |
505 | { |
506 | Q_Q(QRenderAspect); |
507 | unregisterBackendType<Qt3DCore::QEntity>(); |
508 | unregisterBackendType<Qt3DCore::QTransform>(); |
509 | |
510 | unregisterBackendType<Qt3DRender::QCameraLens>(); |
511 | unregisterBackendType<QLayer>(); |
512 | unregisterBackendType<QSceneLoader>(); |
513 | unregisterBackendType<QRenderTarget>(); |
514 | unregisterBackendType<QRenderTargetOutput>(); |
515 | unregisterBackendType<QRenderSettings>(); |
516 | unregisterBackendType<QRenderState>(); |
517 | |
518 | // Geometry + Compute |
519 | unregisterBackendType<QAttribute>(); |
520 | unregisterBackendType<QBuffer>(); |
521 | unregisterBackendType<QComputeCommand>(); |
522 | unregisterBackendType<QGeometry>(); |
523 | unregisterBackendType<QGeometryRenderer>(); |
524 | unregisterBackendType<Qt3DCore::QArmature>(); |
525 | unregisterBackendType<Qt3DCore::QAbstractSkeleton>(); |
526 | unregisterBackendType<Qt3DCore::QJoint>(); |
527 | |
528 | // Textures |
529 | unregisterBackendType<QAbstractTexture>(); |
530 | unregisterBackendType<QAbstractTextureImage>(); |
531 | |
532 | // Material system |
533 | unregisterBackendType<QEffect>(); |
534 | unregisterBackendType<QFilterKey>(); |
535 | unregisterBackendType<QAbstractLight>(); |
536 | unregisterBackendType<QEnvironmentLight>(); |
537 | unregisterBackendType<QMaterial>(); |
538 | unregisterBackendType<QParameter>(); |
539 | unregisterBackendType<QRenderPass>(); |
540 | unregisterBackendType<QShaderData>(); |
541 | unregisterBackendType<QShaderProgram>(); |
542 | unregisterBackendType<QShaderProgramBuilder>(); |
543 | unregisterBackendType<QTechnique>(); |
544 | unregisterBackendType<QShaderImage>(); |
545 | |
546 | // Framegraph |
547 | unregisterBackendType<QCameraSelector>(); |
548 | unregisterBackendType<QClearBuffers>(); |
549 | unregisterBackendType<QDispatchCompute>(); |
550 | unregisterBackendType<QFrustumCulling>(); |
551 | unregisterBackendType<QLayerFilter>(); |
552 | unregisterBackendType<QNoDraw>(); |
553 | unregisterBackendType<QRenderPassFilter>(); |
554 | unregisterBackendType<QRenderStateSet>(); |
555 | unregisterBackendType<QRenderSurfaceSelector>(); |
556 | unregisterBackendType<QRenderTargetSelector>(); |
557 | unregisterBackendType<QSortPolicy>(); |
558 | unregisterBackendType<QTechniqueFilter>(); |
559 | unregisterBackendType<QViewport>(); |
560 | unregisterBackendType<QRenderCapture>(); |
561 | unregisterBackendType<QBufferCapture>(); |
562 | unregisterBackendType<QMemoryBarrier>(); |
563 | unregisterBackendType<QSetFence>(); |
564 | unregisterBackendType<QWaitFence>(); |
565 | unregisterBackendType<QSubtreeEnabler>(); |
566 | unregisterBackendType<QDebugOverlay>(); |
567 | |
568 | // Picking |
569 | unregisterBackendType<QObjectPicker>(); |
570 | unregisterBackendType<QRayCaster>(); |
571 | unregisterBackendType<QScreenRayCaster>(); |
572 | |
573 | // Plugins |
574 | for (Render::QRenderPlugin *plugin : qAsConst(t&: m_renderPlugins)) |
575 | plugin->unregisterBackendTypes(aspect: q); |
576 | } |
577 | |
578 | void QRenderAspectPrivate::registerBackendType(const QMetaObject &obj, |
579 | const QBackendNodeMapperPtr &functor) |
580 | { |
581 | Q_Q(QRenderAspect); |
582 | q->registerBackendType(obj, functor); |
583 | } |
584 | |
585 | /*! |
586 | * The constructor creates a new QRenderAspect::QRenderAspect instance with the |
587 | * specified \a parent. |
588 | * \param parent |
589 | */ |
590 | QRenderAspect::QRenderAspect(QObject *parent) |
591 | : QRenderAspect(Threaded, parent) {} |
592 | |
593 | /*! |
594 | * The constructor creates a new QRenderAspect::QRenderAspect instance with the |
595 | * specified \a type and \a parent. |
596 | * \param type |
597 | * \param parent |
598 | */ |
599 | QRenderAspect::QRenderAspect(QRenderAspect::RenderType type, QObject *parent) |
600 | : QRenderAspect(*new QRenderAspectPrivate(type), parent) {} |
601 | |
602 | /*! \internal */ |
603 | QRenderAspect::QRenderAspect(QRenderAspectPrivate &dd, QObject *parent) |
604 | : QAbstractAspect(dd, parent) |
605 | { |
606 | setObjectName(QStringLiteral("Render Aspect" )); |
607 | } |
608 | |
609 | /*! \internal */ |
610 | QRenderAspect::~QRenderAspect() |
611 | { |
612 | } |
613 | |
614 | // Called by Scene3DRenderer only |
615 | void QRenderAspectPrivate::renderInitialize(QOpenGLContext *context) |
616 | { |
617 | if (m_renderer->api() == API::OpenGL) |
618 | m_renderer->setOpenGLContext(context); |
619 | m_renderer->initialize(); |
620 | } |
621 | |
622 | /*! \internal */ |
623 | void QRenderAspectPrivate::renderSynchronous(bool swapBuffers) |
624 | { |
625 | m_renderer->doRender(swapBuffers); |
626 | } |
627 | |
628 | /* |
629 | * \internal |
630 | * Only called when rendering with QtQuick 2 and a Scene3D item |
631 | */ |
632 | void QRenderAspectPrivate::renderShutdown() |
633 | { |
634 | if (m_renderer != nullptr) |
635 | m_renderer->shutdown(); |
636 | } |
637 | |
638 | QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) |
639 | { |
640 | using namespace Render; |
641 | |
642 | Q_D(QRenderAspect); |
643 | d->m_renderer->setTime(time); |
644 | |
645 | #if defined(QT3D_RENDER_DUMP_BACKEND_NODES) |
646 | d->m_renderer->dumpInfo(); |
647 | #endif |
648 | |
649 | // Create jobs that will get executed by the threadpool |
650 | QVector<QAspectJobPtr> jobs; |
651 | |
652 | // 1 LoadBufferJobs, GeometryJobs, SceneLoaderJobs, LoadTextureJobs |
653 | // 2 CalculateBoundingVolumeJob (depends on LoadBuffer) |
654 | // 3 WorldTransformJob |
655 | // 4 UpdateBoundingVolume, FramePreparationJob (depend on WorlTransformJob) |
656 | // 5 CalcGeometryTriangleVolumes (frame preparation job), RenderViewJobs |
657 | // 6 PickBoundingVolumeJob |
658 | // 7 Cleanup Job (depends on RV) |
659 | |
660 | // Ensure we have a settings object. It may get deleted by the call to |
661 | // QChangeArbiter::syncChanges() that happens just before the render aspect is |
662 | // asked for jobs to execute (this function). If that is the case, the RenderSettings will |
663 | // be null and we should not generate any jobs. |
664 | if (d->m_renderer->isRunning() && d->m_renderer->settings()) { |
665 | NodeManagers *manager = d->m_nodeManagers; |
666 | d->m_syncLoadingJobs->removeDependency(dependency: QWeakPointer<QAspectJob>()); |
667 | d->m_calculateBoundingVolumeJob->removeDependency(dependency: QWeakPointer<QAspectJob>()); |
668 | d->m_updateLevelOfDetailJob->setFrameGraphRoot(d->m_renderer->frameGraphRoot()); |
669 | |
670 | // Launch skeleton loader jobs once all loading jobs have completed. |
671 | const QVector<Render::HSkeleton> skeletonsToLoad = |
672 | manager->skeletonManager()->takeDirtySkeletons(dirtyFlag: Render::SkeletonManager::SkeletonDataDirty); |
673 | for (const auto &skeletonHandle : skeletonsToLoad) { |
674 | auto loadSkeletonJob = Render::LoadSkeletonJobPtr::create(arguments: skeletonHandle); |
675 | loadSkeletonJob->setNodeManagers(manager); |
676 | d->m_syncLoadingJobs->addDependency(dependency: loadSkeletonJob); |
677 | jobs.append(t: loadSkeletonJob); |
678 | } |
679 | |
680 | // TO DO: Have 2 jobs queue |
681 | // One for urgent jobs that are mandatory for the rendering of a frame |
682 | // Another for jobs that can span across multiple frames (Scene/Mesh loading) |
683 | const QVector<Render::LoadSceneJobPtr> sceneJobs = manager->sceneManager()->takePendingSceneLoaderJobs(); |
684 | for (const Render::LoadSceneJobPtr &job : sceneJobs) { |
685 | job->setNodeManagers(d->m_nodeManagers); |
686 | job->setSceneImporters(d->m_sceneImporter); |
687 | jobs.append(t: job); |
688 | } |
689 | |
690 | const QVector<QAspectJobPtr> geometryJobs = d->createGeometryRendererJobs(); |
691 | jobs.append(l: geometryJobs); |
692 | |
693 | const QVector<QAspectJobPtr> preRenderingJobs = d->createPreRendererJobs(); |
694 | jobs.append(l: preRenderingJobs); |
695 | |
696 | // Don't spawn any rendering jobs, if the renderer decides to skip this frame |
697 | // Note: this only affects rendering jobs (jobs that load buffers, |
698 | // perform picking,... must still be run) |
699 | if (!d->m_renderer->shouldRender()) { |
700 | d->m_renderer->skipNextFrame(); |
701 | QThread::msleep(1); |
702 | return jobs; |
703 | } |
704 | |
705 | // Traverse the current framegraph and create jobs to populate |
706 | // RenderBins with RenderCommands |
707 | // All jobs needed to create the frame and their dependencies are set by |
708 | // renderBinJobs() |
709 | |
710 | const AbstractRenderer::BackendNodeDirtySet dirtyBitsForFrame = d->m_renderer->dirtyBits(); |
711 | |
712 | // Create the jobs to build the frame |
713 | const QVector<QAspectJobPtr> bufferJobs = d->createRenderBufferJobs(); |
714 | for (const QAspectJobPtr &bufferJob : bufferJobs) |
715 | d->m_calculateBoundingVolumeJob->addDependency(dependency: bufferJob); |
716 | jobs.append(l: bufferJobs); |
717 | |
718 | const bool entitiesEnabledDirty = dirtyBitsForFrame & AbstractRenderer::EntityEnabledDirty; |
719 | if (entitiesEnabledDirty) |
720 | jobs.push_back(t: d->m_updateTreeEnabledJob); |
721 | |
722 | if (entitiesEnabledDirty || |
723 | dirtyBitsForFrame & AbstractRenderer::TransformDirty) { |
724 | jobs.push_back(t: d->m_worldTransformJob); |
725 | jobs.push_back(t: d->m_updateWorldBoundingVolumeJob); |
726 | } |
727 | |
728 | if (entitiesEnabledDirty || |
729 | dirtyBitsForFrame & AbstractRenderer::GeometryDirty || |
730 | dirtyBitsForFrame & AbstractRenderer::BuffersDirty) { |
731 | jobs.push_back(t: d->m_calculateBoundingVolumeJob); |
732 | } |
733 | |
734 | if (entitiesEnabledDirty || |
735 | dirtyBitsForFrame & AbstractRenderer::GeometryDirty || |
736 | dirtyBitsForFrame & AbstractRenderer::TransformDirty) { |
737 | jobs.push_back(t: d->m_expandBoundingVolumeJob); |
738 | } |
739 | |
740 | // TO DO: Conditionally add if skeletons dirty |
741 | jobs.push_back(t: d->m_syncLoadingJobs); |
742 | d->m_updateSkinningPaletteJob->setDirtyJoints(manager->jointManager()->dirtyJoints()); |
743 | jobs.push_back(t: d->m_updateSkinningPaletteJob); |
744 | jobs.push_back(t: d->m_updateLevelOfDetailJob); |
745 | |
746 | // Rebuild Entity Layers list if layers are dirty |
747 | const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty; |
748 | if (layersDirty) |
749 | jobs.push_back(t: d->m_updateEntityLayersJob); |
750 | |
751 | const QVector<QAspectJobPtr> renderBinJobs = d->m_renderer->renderBinJobs(); |
752 | jobs.append(l: renderBinJobs); |
753 | } |
754 | |
755 | return jobs; |
756 | } |
757 | |
758 | QVariant QRenderAspect::executeCommand(const QStringList &args) |
759 | { |
760 | Q_D(QRenderAspect); |
761 | |
762 | if (args.size() == 1) { |
763 | Render::RenderSettings *settings = d->m_renderer->settings(); |
764 | auto *droot = static_cast<Qt3DCore::QEntityPrivate *>(Qt3DCore::QNodePrivate::get(q: d->m_root)); |
765 | auto *fg = qobject_cast<Qt3DRender::QFrameGraphNode *>(object: droot->m_scene->lookupNode(id: settings->activeFrameGraphID())); |
766 | if (fg) { |
767 | if (args.front() == QLatin1String("framegraph" )) |
768 | return Qt3DRender::QFrameGraphNodePrivate::get(node: fg)->dumpFrameGraph(); |
769 | if (args.front() == QLatin1String("framepaths" )) |
770 | return Qt3DRender::QFrameGraphNodePrivate::get(node: fg)->dumpFrameGraphPaths().join(sep: QLatin1String("\n" )); |
771 | if (args.front() == QLatin1String("filterstates" )) { |
772 | const auto activeContextInfo = d->m_renderer->contextInfo(); |
773 | QString res = QLatin1String("Active Graphics API: " ) + activeContextInfo->toString() + QLatin1String("\n" ); |
774 | res += QLatin1String("Render Views:\n " ) + Qt3DRender::QFrameGraphNodePrivate::get(node: fg)->dumpFrameGraphFilterState().join(sep: QLatin1String("\n " )) + QLatin1String("\n" ); |
775 | res += QLatin1String("Scene Graph:\n " ) + dumpSGFilterState(manager: d->m_nodeManagers->techniqueManager(), contextData: activeContextInfo, n: d->m_root).join(sep: QLatin1String("\n " )); |
776 | return res; |
777 | } |
778 | } |
779 | if (args.front() == QLatin1String("scenegraph" )) |
780 | return droot->dumpSceneGraph(); |
781 | } |
782 | |
783 | return d->m_renderer->executeCommand(args); |
784 | } |
785 | |
786 | void QRenderAspect::onEngineStartup() |
787 | { |
788 | Q_D(QRenderAspect); |
789 | if (d->m_renderAfterJobs) // synchronous rendering but using QWindow |
790 | d->m_renderer->initialize(); |
791 | d->onEngineStartup(); |
792 | } |
793 | |
794 | void QRenderAspect::onRegistered() |
795 | { |
796 | // Create a renderer each time as this is destroyed in onUnregistered below. If |
797 | // using a threaded renderer, this blocks until the render thread has been created |
798 | // and started. |
799 | Q_D(QRenderAspect); |
800 | d->createNodeManagers(); |
801 | |
802 | // Load proper Renderer class based on Qt configuration preferences |
803 | d->m_renderer = d->loadRendererPlugin(); |
804 | Q_ASSERT(d->m_renderer); |
805 | d->m_renderer->setScreen(d->m_screen); |
806 | d->m_renderer->setAspect(this); |
807 | d->m_renderer->setNodeManagers(d->m_nodeManagers); |
808 | |
809 | // Create a helper for deferring creation of an offscreen surface used during cleanup |
810 | // to the main thread, after we know what the surface format in use is. |
811 | d->m_offscreenHelper = new Render::OffscreenSurfaceHelper(d->m_renderer); |
812 | d->m_offscreenHelper->moveToThread(thread: QCoreApplication::instance()->thread()); |
813 | d->m_renderer->setOffscreenSurfaceHelper(d->m_offscreenHelper); |
814 | |
815 | // Register backend types now that we have a renderer |
816 | d->registerBackendTypes(); |
817 | |
818 | if (!d->m_initialized) { |
819 | // Register the VSyncFrameAdvanceService to drive the aspect manager loop |
820 | // depending on the vsync |
821 | if (d->m_aspectManager) { |
822 | QAbstractFrameAdvanceService *advanceService = d->m_renderer->frameAdvanceService(); |
823 | if (advanceService) |
824 | d->services()->registerServiceProvider(serviceType: Qt3DCore::QServiceLocator::FrameAdvanceService, |
825 | provider: advanceService); |
826 | } |
827 | |
828 | if (d->services()) |
829 | d->m_renderer->setServices(d->services()); |
830 | d->m_initialized = true; |
831 | } |
832 | |
833 | if (d->m_aspectManager) |
834 | d->services()->eventFilterService()->registerEventFilter(eventFilter: d->m_pickEventFilter.data(), priority: 1024); |
835 | } |
836 | |
837 | void QRenderAspect::onUnregistered() |
838 | { |
839 | Q_D(QRenderAspect); |
840 | if (d->m_renderer) { |
841 | // Request the renderer shuts down. In the threaded renderer case, the |
842 | // Renderer destructor is the synchronization point where we wait for the |
843 | // thread to join (see below). |
844 | d->m_renderer->shutdown(); |
845 | } |
846 | |
847 | d->unregisterBackendTypes(); |
848 | |
849 | d->m_renderer->releaseGraphicsResources(); |
850 | |
851 | if (d->m_aspectManager) |
852 | d->services()->eventFilterService()->unregisterEventFilter(eventFilter: d->m_pickEventFilter.data()); |
853 | |
854 | delete d->m_nodeManagers; |
855 | d->m_nodeManagers = nullptr; |
856 | |
857 | // Waits for the render thread to join (if using threaded renderer) |
858 | delete d->m_renderer; |
859 | d->m_renderer = nullptr; |
860 | |
861 | // Queue the offscreen surface helper for deletion on the main thread. |
862 | // That will take care of deleting the offscreen surface itself. |
863 | d->m_offscreenHelper->deleteLater(); |
864 | d->m_offscreenHelper = nullptr; |
865 | } |
866 | |
867 | QVector<Qt3DCore::QAspectJobPtr> QRenderAspectPrivate::createGeometryRendererJobs() const |
868 | { |
869 | Render::GeometryRendererManager *geomRendererManager = m_nodeManagers->geometryRendererManager(); |
870 | const QVector<QNodeId> dirtyGeometryRenderers = geomRendererManager->dirtyGeometryRenderers(); |
871 | QVector<QAspectJobPtr> dirtyGeometryRendererJobs; |
872 | dirtyGeometryRendererJobs.reserve(asize: dirtyGeometryRenderers.size()); |
873 | |
874 | for (const QNodeId &geoRendererId : dirtyGeometryRenderers) { |
875 | Render::HGeometryRenderer geometryRendererHandle = geomRendererManager->lookupHandle(id: geoRendererId); |
876 | if (!geometryRendererHandle.isNull()) { |
877 | auto job = Render::LoadGeometryJobPtr::create(arguments&: geometryRendererHandle); |
878 | job->setNodeManagers(m_nodeManagers); |
879 | dirtyGeometryRendererJobs.push_back(t: job); |
880 | } |
881 | } |
882 | |
883 | return dirtyGeometryRendererJobs; |
884 | } |
885 | |
886 | QVector<QAspectJobPtr> QRenderAspectPrivate::createPreRendererJobs() const |
887 | { |
888 | if (!m_renderer) |
889 | return {}; |
890 | |
891 | const auto frameMouseEvents = m_pickEventFilter->pendingMouseEvents(); |
892 | const auto frameKeyEvents = m_pickEventFilter->pendingKeyEvents(); |
893 | m_renderer->setPendingEvents(mouseEvents: frameMouseEvents, keyEvents: frameKeyEvents); |
894 | |
895 | auto jobs = m_renderer->preRenderingJobs(); |
896 | |
897 | // Set values on picking jobs |
898 | Render::RenderSettings *renderSetting = m_renderer->settings(); |
899 | if (renderSetting != nullptr) { |
900 | m_pickBoundingVolumeJob->setRenderSettings(renderSetting); |
901 | m_pickBoundingVolumeJob->setFrameGraphRoot(m_renderer->frameGraphRoot()); |
902 | m_pickBoundingVolumeJob->setMouseEvents(frameMouseEvents); |
903 | m_pickBoundingVolumeJob->setKeyEvents(frameKeyEvents); |
904 | |
905 | m_rayCastingJob->setRenderSettings(renderSetting); |
906 | m_rayCastingJob->setFrameGraphRoot(m_renderer->frameGraphRoot()); |
907 | } |
908 | |
909 | jobs.append(t: m_pickBoundingVolumeJob); |
910 | jobs.append(t: m_rayCastingJob); |
911 | |
912 | return jobs; |
913 | } |
914 | |
915 | // Returns a vector of jobs to be performed for dirty buffers |
916 | // 1 dirty buffer == 1 job, all job can be performed in parallel |
917 | QVector<Qt3DCore::QAspectJobPtr> QRenderAspectPrivate::createRenderBufferJobs() const |
918 | { |
919 | const QVector<QNodeId> dirtyBuffers = m_nodeManagers->bufferManager()->takeDirtyBuffers(); |
920 | QVector<QAspectJobPtr> dirtyBuffersJobs; |
921 | dirtyBuffersJobs.reserve(asize: dirtyBuffers.size()); |
922 | |
923 | for (const QNodeId &bufId : dirtyBuffers) { |
924 | Render::HBuffer bufferHandle = m_nodeManagers->lookupHandle<Render::Buffer, Render::BufferManager, Render::HBuffer>(id: bufId); |
925 | if (!bufferHandle.isNull()) { |
926 | // Create new buffer job |
927 | auto job = Render::LoadBufferJobPtr::create(arguments&: bufferHandle); |
928 | job->setNodeManager(m_nodeManagers); |
929 | dirtyBuffersJobs.push_back(t: job); |
930 | } |
931 | } |
932 | |
933 | return dirtyBuffersJobs; |
934 | } |
935 | |
936 | void QRenderAspectPrivate::loadSceneParsers() |
937 | { |
938 | const QStringList keys = QSceneImportFactory::keys(); |
939 | for (const QString &key : keys) { |
940 | QSceneImporter *sceneIOHandler = QSceneImportFactory::create(name: key, args: QStringList()); |
941 | if (sceneIOHandler != nullptr) |
942 | m_sceneImporter.append(t: sceneIOHandler); |
943 | } |
944 | } |
945 | |
946 | Render::AbstractRenderer *QRenderAspectPrivate::loadRendererPlugin() |
947 | { |
948 | // Note: for now we load the first renderer plugin that is successfully loaded |
949 | // In the future we might want to offer the user a way to hint at which renderer |
950 | // plugin would best be loaded |
951 | |
952 | const QByteArray envTarget = qgetenv(varName: "QT3D_RENDERER" ); |
953 | const QString targetKey = !envTarget.isEmpty() ? QString::fromLatin1(str: envTarget) : QStringLiteral("opengl" ); |
954 | const QStringList keys = Render::QRendererPluginFactory::keys(); |
955 | for (const QString &key : keys) { |
956 | if (key != targetKey) |
957 | continue; |
958 | Render::AbstractRenderer *renderer = Render::QRendererPluginFactory::create(name: key, renderMode: m_renderType); |
959 | if (renderer) |
960 | return renderer; |
961 | } |
962 | const QByteArray targetKeyName = targetKey.toLatin1(); |
963 | qFatal(msg: "Unable to find renderer plugin for %s" , targetKeyName.constData()); |
964 | return nullptr; |
965 | } |
966 | |
967 | void QRenderAspectPrivate::loadRenderPlugin(const QString &pluginName) |
968 | { |
969 | Q_Q(QRenderAspect); |
970 | const QStringList keys = Render::QRenderPluginFactory::keys(); |
971 | if (!keys.contains(str: pluginName)) |
972 | return; |
973 | |
974 | if (m_pluginConfig.contains(t: pluginName) && !m_loadedPlugins.contains(t: pluginName)) { |
975 | Render::QRenderPlugin *plugin |
976 | = Render::QRenderPluginFactory::create(name: pluginName, args: QStringList()); |
977 | if (plugin != nullptr) { |
978 | m_loadedPlugins.append(t: pluginName); |
979 | m_renderPlugins.append(t: plugin); |
980 | plugin->registerBackendTypes(aspect: q, renderer: m_renderer); |
981 | } |
982 | } |
983 | } |
984 | |
985 | QVector<QString> QRenderAspectPrivate::m_pluginConfig; |
986 | QMutex QRenderAspectPrivate::m_pluginLock; |
987 | QVector<QRenderAspectPrivate *> QRenderAspectPrivate::m_instances; |
988 | |
989 | void QRenderAspectPrivate::configurePlugin(const QString &plugin) |
990 | { |
991 | QMutexLocker lock(&m_pluginLock); |
992 | if (!m_pluginConfig.contains(t: plugin)) { |
993 | m_pluginConfig.append(t: plugin); |
994 | |
995 | for (QRenderAspectPrivate *instance : qAsConst(t&: m_instances)) |
996 | instance->loadRenderPlugin(pluginName: plugin); |
997 | } |
998 | } |
999 | |
1000 | } // namespace Qt3DRender |
1001 | |
1002 | QT_END_NAMESPACE |
1003 | |
1004 | QT3D_REGISTER_NAMESPACED_ASPECT("render" , QT_PREPEND_NAMESPACE(Qt3DRender), QRenderAspect) |
1005 | |