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