| 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 | |
| 191 | QT_BEGIN_NAMESPACE |
| 192 | |
| 193 | using namespace Qt3DCore; |
| 194 | |
| 195 | namespace { |
| 196 | |
| 197 | QString 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 | |
| 212 | QString 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 | |
| 224 | QStringList 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 | } |
| 270 | namespace 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 */ |
| 291 | QRenderAspectPrivate::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 */ |
| 331 | QRenderAspectPrivate::~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 | |
| 343 | QRenderAspectPrivate *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 | |
| 354 | QRenderAspectPrivate *QRenderAspectPrivate::get(QRenderAspect *q) |
| 355 | { |
| 356 | return q->d_func(); |
| 357 | } |
| 358 | |
| 359 | void 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 | |
| 365 | void QRenderAspectPrivate::jobsDone() |
| 366 | { |
| 367 | m_renderer->jobsDone(manager: m_aspectManager); |
| 368 | } |
| 369 | |
| 370 | void QRenderAspectPrivate::frameDone() |
| 371 | { |
| 372 | m_renderer->setJobsInLastFrame(m_aspectManager->jobsInLastFrame()); |
| 373 | if (m_renderAfterJobs) |
| 374 | m_renderer->doRender(swapBuffers: true); |
| 375 | } |
| 376 | |
| 377 | void 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 | |
| 393 | void 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 */ |
| 413 | void 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 */ |
| 504 | void 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 | |
| 578 | void 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 | */ |
| 590 | QRenderAspect::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 | */ |
| 599 | QRenderAspect::QRenderAspect(QRenderAspect::RenderType type, QObject *parent) |
| 600 | : QRenderAspect(*new QRenderAspectPrivate(type), parent) {} |
| 601 | |
| 602 | /*! \internal */ |
| 603 | QRenderAspect::QRenderAspect(QRenderAspectPrivate &dd, QObject *parent) |
| 604 | : QAbstractAspect(dd, parent) |
| 605 | { |
| 606 | setObjectName(QStringLiteral("Render Aspect" )); |
| 607 | } |
| 608 | |
| 609 | /*! \internal */ |
| 610 | QRenderAspect::~QRenderAspect() |
| 611 | { |
| 612 | } |
| 613 | |
| 614 | // Called by Scene3DRenderer only |
| 615 | void 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 */ |
| 623 | void 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 | */ |
| 632 | void QRenderAspectPrivate::renderShutdown() |
| 633 | { |
| 634 | if (m_renderer != nullptr) |
| 635 | m_renderer->shutdown(); |
| 636 | } |
| 637 | |
| 638 | QVector<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 | |
| 758 | QVariant 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 | |
| 786 | void 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 | |
| 794 | void 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 | |
| 837 | void 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 | |
| 867 | QVector<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 | |
| 886 | QVector<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 |
| 917 | QVector<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 | |
| 936 | void 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 | |
| 946 | Render::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 | |
| 967 | void 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 | |
| 985 | QVector<QString> QRenderAspectPrivate::m_pluginConfig; |
| 986 | QMutex QRenderAspectPrivate::m_pluginLock; |
| 987 | QVector<QRenderAspectPrivate *> QRenderAspectPrivate::m_instances; |
| 988 | |
| 989 | void 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 | |
| 1002 | QT_END_NAMESPACE |
| 1003 | |
| 1004 | QT3D_REGISTER_NAMESPACED_ASPECT("render" , QT_PREPEND_NAMESPACE(Qt3DRender), QRenderAspect) |
| 1005 | |