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