/**************************************************************************** ** ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qrenderaspect.h" #include "qrenderaspect_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE using namespace Qt3DCore; namespace Qt3DRender { /*! * \class Qt3DRender::QRenderAspect * \brief The QRenderAspect class * \since 5.7 * \inmodule Qt3DRender */ /*! \internal */ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) : QAbstractAspectPrivate() , m_nodeManagers(new Render::NodeManagers()) , m_renderer(nullptr) , m_initialized(false) , m_renderType(type) { // Load the scene parsers loadSceneParsers(); } /*! \internal */ QRenderAspectPrivate::~QRenderAspectPrivate() { // The renderer should have been shutdown as part of onUnregistered(). // If it still exists then this aspect is being deleted before the aspect // engine is finished with it. if (m_renderer != nullptr) qWarning() << Q_FUNC_INFO << "The renderer should have been deleted when reaching this point (this warning may be normal when running tests)"; delete m_nodeManagers; } /*! \internal */ void QRenderAspectPrivate::registerBackendTypes() { Q_Q(QRenderAspect); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers)); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->transformManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->cameraManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->layerManager())); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers->sceneManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->renderTargetManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->attachmentManager())); q->registerBackendType(QSharedPointer::create(m_renderer)); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->renderStateManager())); // Geometry + Compute q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->attributeManager())); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers->bufferManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->computeJobManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->geometryManager())); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers->geometryRendererManager())); // Textures q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager(), m_nodeManagers->textureDataManager())); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager(), m_nodeManagers->textureDataManager())); // Material system q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->effectManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->filterKeyManager())); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers)); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->materialManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->parameterManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->renderPassManager())); q->registerBackendType(QSharedPointer::create(m_renderer, m_nodeManagers)); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->shaderManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->techniqueManager())); // Framegraph q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->frameGraphManager())); // Picking q->registerBackendType(QSharedPointer >::create(m_renderer, m_nodeManagers->objectPickerManager())); } /*! \internal */ void QRenderAspectPrivate::unregisterBackendTypes() { unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); // Geometry + Compute unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); // Textures unregisterBackendType(); unregisterBackendType(); // Material system unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); // Framegraph unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); unregisterBackendType(); // Picking unregisterBackendType(); } /*! * The constructor creates a new QRenderAspect::QRenderAspect instance with the * specified \a parent. * \param parent */ QRenderAspect::QRenderAspect(QObject *parent) : QRenderAspect(Threaded, parent) {} /*! * The constructor creates a new QRenderAspect::QRenderAspect instance with the * specified \a type and \a parent. * \param type * \param parent */ QRenderAspect::QRenderAspect(QRenderAspect::RenderType type, QObject *parent) : QRenderAspect(*new QRenderAspectPrivate(type), parent) {} /*! \internal */ QRenderAspect::QRenderAspect(QRenderAspectPrivate &dd, QObject *parent) : QAbstractAspect(dd, parent) { setObjectName(QStringLiteral("Render Aspect")); } /*! \internal */ QRenderAspect::~QRenderAspect() { } void QRenderAspectPrivate::renderInitialize(QOpenGLContext *context) { if (m_renderer->api() == Render::AbstractRenderer::OpenGL) static_cast(m_renderer)->setOpenGLContext(context); m_renderer->initialize(); } /*! \internal */ void QRenderAspectPrivate::renderSynchronous() { m_renderer->doRender(); } /*! * Only called when rendering with QtQuick 2 and a Scene3D item */ void QRenderAspectPrivate::renderShutdown() { m_renderer->shutdown(); } QVector QRenderAspect::jobsToExecute(qint64 time) { Q_D(QRenderAspect); d->m_renderer->setTime(time); #if defined(QT3D_RENDER_DUMP_BACKEND_NODES) d->m_renderer->dumpInfo(); #endif // Create jobs that will get exectued by the threadpool QVector jobs; // 1 LoadBufferJobs, GeometryJobs, SceneLoaderJobs // 2 CalculateBoundingVolumeJob (depends on LoadBuffer) // 3 WorldTransformJob // 4 UpdateBoundingVolume, FramePreparationJob (depend on WorlTransformJob) // 5 CalcGeometryTriangleVolumes (frame preparation job), RenderViewJobs // 6 PickBoundingVolumeJob // 7 Cleanup Job (depends on RV) // Ensure we have a settings object. It may get deleted by the call to // QChangeArbiter::syncChanges() that happens just before the render aspect is // asked for jobs to execute (this function). If that is the case, the RenderSettings will // be null and we should not generate any jobs. if (d->m_renderer->isRunning() && d->m_renderer->settings()) { // don't spawn any jobs, if the renderer decides to skip this frame if (!d->m_renderer->shouldRender()) { d->m_renderer->skipNextFrame(); return jobs; } Render::NodeManagers *manager = d->m_renderer->nodeManagers(); const QVector texturesPending = std::move(manager->textureDataManager()->texturesPending()); for (const QNodeId textureId : texturesPending) { auto loadTextureJob = Render::LoadTextureDataJobPtr::create(textureId); loadTextureJob->setNodeManagers(manager); jobs.append(loadTextureJob); } // TO DO: Have 2 jobs queue // One for urgent jobs that are mandatory for the rendering of a frame // Another for jobs that can span across multiple frames (Scene/Mesh loading) const QVector sceneJobs = manager->sceneManager()->pendingSceneLoaderJobs(); for (const Render::LoadSceneJobPtr &job : sceneJobs) { job->setNodeManagers(d->m_nodeManagers); job->setSceneIOHandlers(d->m_sceneIOHandler); jobs.append(job); } const QVector geometryJobs = d->createGeometryRendererJobs(); jobs.append(geometryJobs); // Add all jobs to queue const Qt3DCore::QAspectJobPtr pickBoundingVolumeJob = d->m_renderer->pickBoundingVolumeJob(); jobs.append(pickBoundingVolumeJob); // Traverse the current framegraph and create jobs to populate // RenderBins with RenderCommands // All jobs needed to create the frame and their dependencies are set by // renderBinJobs() const QVector renderBinJobs = d->m_renderer->renderBinJobs(); jobs.append(renderBinJobs); } return jobs; } QVariant QRenderAspect::executeCommand(const QStringList &args) { Q_D(QRenderAspect); return d->m_renderer->executeCommand(args); } void QRenderAspect::onEngineStartup() { Q_D(QRenderAspect); Render::NodeManagers *managers = d->m_renderer->nodeManagers(); Render::Entity *rootEntity = managers->lookupResource(rootEntityId()); Q_ASSERT(rootEntity); d->m_renderer->setSceneRoot(d, rootEntity); } void QRenderAspect::onRegistered() { // Create a renderer each time as this is destroyed in onUnregistered below. If // using a threaded renderer, this blocks until the render thread has been created // and started. Q_D(QRenderAspect); d->m_renderer = new Render::Renderer(d->m_renderType); d->m_renderer->setNodeManagers(d->m_nodeManagers); // Register backend types now that we have a renderer d->registerBackendTypes(); if (!d->m_initialized) { // Register the VSyncFrameAdvanceService to drive the aspect manager loop // depending on the vsync if (d->m_aspectManager) { QAbstractFrameAdvanceService *advanceService = d->m_renderer->frameAdvanceService(); if (advanceService) d->services()->registerServiceProvider(Qt3DCore::QServiceLocator::FrameAdvanceService, advanceService); } d->m_renderer->setServices(d->services()); d->m_initialized = true; } if (d->m_aspectManager) d->m_renderer->registerEventFilter(d->services()->eventFilterService()); } void QRenderAspect::onUnregistered() { Q_D(QRenderAspect); if (d->m_renderer) { // Request the renderer shuts down. In the threaded renderer case, the // Renderer destructor is the synchronization point where we wait for the // thread to join (see below). d->m_renderer->shutdown(); } d->unregisterBackendTypes(); // Waits for the render thread to join (if using threaded renderer) delete d->m_renderer; d->m_renderer = nullptr; } QVector QRenderAspectPrivate::createGeometryRendererJobs() { Render::GeometryRendererManager *geomRendererManager = m_nodeManagers->geometryRendererManager(); const QVector dirtyGeometryRenderers = geomRendererManager->dirtyGeometryRenderers(); QVector dirtyGeometryRendererJobs; dirtyGeometryRendererJobs.reserve(dirtyGeometryRenderers.size()); for (const QNodeId geoRendererId : dirtyGeometryRenderers) { Render::HGeometryRenderer geometryRendererHandle = geomRendererManager->lookupHandle(geoRendererId); if (!geometryRendererHandle.isNull()) { auto job = Render::LoadGeometryJobPtr::create(geometryRendererHandle); job->setNodeManagers(m_nodeManagers); dirtyGeometryRendererJobs.push_back(job); } } return dirtyGeometryRendererJobs; } void QRenderAspectPrivate::loadSceneParsers() { const QStringList keys = QSceneIOFactory::keys(); for (const QString &key : keys) { QSceneIOHandler *sceneIOHandler = QSceneIOFactory::create(key, QStringList()); if (sceneIOHandler != nullptr) m_sceneIOHandler.append(sceneIOHandler); } } } // namespace Qt3DRender QT_END_NAMESPACE QT3D_REGISTER_NAMESPACED_ASPECT("render", QT_PREPEND_NAMESPACE(Qt3DRender), QRenderAspect)