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

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