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
156QT_BEGIN_NAMESPACE
157
158
159namespace {
160
161QString 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
176QString 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
188QStringList 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}
234namespace Qt3DRender {
235
236using 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 */
257QRenderAspectPrivate::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 */
294QRenderAspectPrivate::~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
306QRenderAspectPrivate *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
317QRenderAspectPrivate *QRenderAspectPrivate::get(QRenderAspect *q)
318{
319 return q->d_func();
320}
321
322void QRenderAspectPrivate::jobsDone()
323{
324 m_renderer->jobsDone(manager: m_aspectManager);
325}
326
327void QRenderAspectPrivate::frameDone()
328{
329 m_renderer->setJobsInLastFrame(m_aspectManager->jobsInLastFrame());
330 if (m_renderAfterJobs)
331 m_renderer->render(swapBuffers: true);
332}
333
334void 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
352void 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
381void 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 */
393void 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 */
486void 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
561void 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 */
585QRenderAspect::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 */
597QRenderAspect::QRenderAspect(QRenderAspect::SubmissionType submissionType,
598 QObject *parent)
599 : Qt3DCore::QAbstractAspect(*new QRenderAspectPrivate(submissionType),
600 parent)
601{
602
603}
604
605/*! \internal */
606QRenderAspect::QRenderAspect(QRenderAspectPrivate &dd, QObject *parent)
607 : QAbstractAspect(dd, parent)
608{
609 setObjectName(QStringLiteral("Render Aspect"));
610}
611
612/*! \internal */
613QRenderAspect::~QRenderAspect()
614{
615}
616
617std::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
732QVariant 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
760void 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
768QStringList QRenderAspect::dependencies() const
769{
770 return { QLatin1String("core") };
771}
772
773void 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
816void 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
846std::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
865std::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
888void 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
899Render::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
920bool 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
933bool 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
943void 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
961QList<QString> QRenderAspectPrivate::m_pluginConfig;
962QMutex QRenderAspectPrivate::m_pluginLock;
963QList<QRenderAspectPrivate *> QRenderAspectPrivate::m_instances;
964
965void 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
978QT_END_NAMESPACE
979
980QT3D_REGISTER_NAMESPACED_ASPECT("render", QT_PREPEND_NAMESPACE(Qt3DRender), QRenderAspect)
981
982#include "moc_qrenderaspect.cpp"
983

source code of qt3d/src/render/frontend/qrenderaspect.cpp