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