diff options
Diffstat (limited to 'src/render')
127 files changed, 2136 insertions, 1619 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h index b618eda55..8bbfcd548 100644 --- a/src/render/backend/abstractrenderer_p.h +++ b/src/render/backend/abstractrenderer_p.h @@ -71,6 +71,7 @@ class QAbstractFrameAdvanceService; class QEventFilterService; class QAbstractAspectJobManager; class QServiceLocator; +class QAspectManager; } namespace Qt3DRender { @@ -151,8 +152,9 @@ public: #if defined(QT_BUILD_INTERNAL) virtual void clearDirtyBits(BackendNodeDirtySet changes) = 0; #endif - virtual bool shouldRender() = 0; + virtual bool shouldRender() const = 0; virtual void skipNextFrame() = 0; + virtual void jobsDone(Qt3DCore::QAspectManager *manager) = 0; virtual QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() = 0; virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0; diff --git a/src/render/backend/bufferutils_p.h b/src/render/backend/bufferutils_p.h index 2bb35fac6..ea783df0d 100644 --- a/src/render/backend/bufferutils_p.h +++ b/src/render/backend/bufferutils_p.h @@ -74,6 +74,8 @@ struct BufferInfo , count(0) , byteStride(0) , byteOffset(0) + , restartEnabled(false) + , restartIndexValue(-1) {} QByteArray data; @@ -82,6 +84,8 @@ struct BufferInfo uint count; uint byteStride; uint byteOffset; + bool restartEnabled; + int restartIndexValue; }; diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp index 85c5e9656..e1d72efda 100644 --- a/src/render/backend/cameralens.cpp +++ b/src/render/backend/cameralens.cpp @@ -46,8 +46,10 @@ #include <Qt3DRender/private/entity_p.h> #include <Qt3DRender/private/sphere_p.h> #include <Qt3DRender/private/computefilteredboundingvolumejob_p.h> +#include <Qt3DRender/private/renderlogging_p.h> #include <Qt3DCore/qentity.h> #include <Qt3DCore/qtransform.h> +#include <Qt3DCore/private/qaspectmanager_p.h> QT_BEGIN_NAMESPACE @@ -62,21 +64,21 @@ namespace { class GetBoundingVolumeWithoutCameraJob : public ComputeFilteredBoundingVolumeJob { public: - GetBoundingVolumeWithoutCameraJob(CameraLens *lens, - QNodeCommand::CommandId commandId) - : m_lens(lens), m_commandId(commandId) + GetBoundingVolumeWithoutCameraJob(CameraLens *lens, QNodeId commandId) + : m_lens(lens), m_requestId(commandId) { } protected: - void finished(const Sphere &sphere) override + // called in main thread + void finished(Qt3DCore::QAspectManager *aspectManager, const Sphere &sphere) override { - m_lens->notifySceneBoundingVolume(sphere, m_commandId); + m_lens->processViewAllResult(aspectManager, sphere, m_requestId); } private: CameraLens *m_lens; - QNodeCommand::CommandId m_commandId; + QNodeId m_requestId; }; } // namespace @@ -114,6 +116,9 @@ Matrix4x4 CameraLens::viewMatrix(const Matrix4x4 &worldTransform) m.lookAt(convertToQVector3D(Vector3D(position)), convertToQVector3D(Vector3D(position + viewDirection)), convertToQVector3D(Vector3D(upVector))); + + qDebug(Jobs) << Q_FUNC_INFO << "Transform Matrix" << worldTransform << "View Matrix" << m; + return Matrix4x4(m); } @@ -131,34 +136,23 @@ void CameraLens::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTim markDirty(AbstractRenderer::AllDirty); } - if (node->exposure() != m_exposure) { + if (!qFuzzyCompare(node->exposure(), m_exposure)) { m_exposure = node->exposure(); markDirty(AbstractRenderer::AllDirty); } const QCameraLensPrivate *d = static_cast<const QCameraLensPrivate *>(QNodePrivate::get(node)); - if (d->m_pendingViewAllCommand != m_pendingViewAllCommand) { - m_pendingViewAllCommand = d->m_pendingViewAllCommand; - - if (m_pendingViewAllCommand) { - const QVariant v = m_pendingViewAllCommand.data; - const QNodeCommand::CommandId commandId = m_pendingViewAllCommand.commandId; - - if (m_pendingViewAllCommand.name == QLatin1String("QueryRootBoundingVolume")) { - const QNodeId id = v.value<QNodeId>(); - computeSceneBoundingVolume({}, id, commandId); - } else if (m_pendingViewAllCommand.name == QLatin1String("QueryEntityBoundingVolume")) { - const QVector<QNodeId> ids = v.value<QVector<QNodeId>>(); - if (ids.size() == 2) - computeSceneBoundingVolume(ids[0], ids[1], commandId); - } - } + if (d->m_pendingViewAllRequest != m_pendingViewAllRequest) { + m_pendingViewAllRequest = d->m_pendingViewAllRequest; + + if (m_pendingViewAllRequest) + computeSceneBoundingVolume(m_pendingViewAllRequest.entityId, m_pendingViewAllRequest.cameraId, m_pendingViewAllRequest.requestId); } } void CameraLens::computeSceneBoundingVolume(QNodeId entityId, QNodeId cameraId, - QNodeCommand::CommandId commandId) + QNodeId requestId) { if (!m_renderer || !m_renderAspect) return; @@ -171,7 +165,7 @@ void CameraLens::computeSceneBoundingVolume(QNodeId entityId, return; Entity *camNode = nodeManagers->renderNodesManager()->lookupResource(cameraId); - ComputeFilteredBoundingVolumeJobPtr job(new GetBoundingVolumeWithoutCameraJob(this, commandId)); + ComputeFilteredBoundingVolumeJobPtr job(new GetBoundingVolumeWithoutCameraJob(this, requestId)); job->addDependency(m_renderer->expandBoundingVolumeJob()); job->setRoot(root); job->setManagers(nodeManagers); @@ -179,18 +173,18 @@ void CameraLens::computeSceneBoundingVolume(QNodeId entityId, m_renderAspect->scheduleSingleShotJob(job); } -void CameraLens::notifySceneBoundingVolume(const Sphere &sphere, QNodeCommand::CommandId commandId) +void CameraLens::processViewAllResult(QAspectManager *aspectManager, const Sphere &sphere, QNodeId commandId) { - if (!m_pendingViewAllCommand || m_pendingViewAllCommand.commandId != commandId) + if (!m_pendingViewAllRequest || m_pendingViewAllRequest.requestId != commandId) return; if (sphere.radius() > 0.f) { - QVector<float> data = { sphere.center().x(), sphere.center().y(), sphere.center().z(), - sphere.radius() }; - QVariant v; - v.setValue(data); - sendCommand(QLatin1String("ViewAll"), v, m_pendingViewAllCommand.commandId); + QCameraLens *lens = qobject_cast<QCameraLens *>(aspectManager->lookupNode(peerId())); + if (lens) { + QCameraLensPrivate *dlens = static_cast<QCameraLensPrivate *>(QCameraLensPrivate::get(lens)); + dlens->processViewAllResult(m_pendingViewAllRequest.requestId, { sphere.center().x(), sphere.center().y(), sphere.center().z() }, sphere.radius()); + } } - m_pendingViewAllCommand = {}; + m_pendingViewAllRequest = {}; } void CameraLens::setProjection(const Matrix4x4 &projection) diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h index bd721d5e9..4afa38620 100644 --- a/src/render/backend/cameralens_p.h +++ b/src/render/backend/cameralens_p.h @@ -52,7 +52,6 @@ // #include <Qt3DRender/private/backendnode_p.h> -#include <Qt3DCore/private/qnodecommand_p.h> #include <Qt3DCore/private/matrix4x4_p.h> #include <Qt3DRender/private/qcameralens_p.h> #include <QRectF> @@ -99,7 +98,7 @@ public: inline float exposure() const { return m_exposure; } void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override; - void notifySceneBoundingVolume(const Sphere &sphere, Qt3DCore::QNodeCommand::CommandId commandId); + void processViewAllResult(Qt3DCore::QAspectManager *aspectManager, const Sphere &sphere, Qt3DCore::QNodeId commandId); static bool viewMatrixForCamera(EntityManager *manager, Qt3DCore::QNodeId cameraId, Matrix4x4 &viewMatrix, Matrix4x4 &projectionMatrix); @@ -107,10 +106,10 @@ public: private: void computeSceneBoundingVolume(Qt3DCore::QNodeId entityId, Qt3DCore::QNodeId cameraId, - Qt3DCore::QNodeCommand::CommandId commandId); + Qt3DCore::QNodeId requestId); QRenderAspect *m_renderAspect; - CameraLensCommand m_pendingViewAllCommand; + CameraLensRequest m_pendingViewAllRequest; Matrix4x4 m_projection; float m_exposure; }; diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp index 8bccb1437..5ed0c970d 100644 --- a/src/render/backend/commandexecuter.cpp +++ b/src/render/backend/commandexecuter.cpp @@ -248,10 +248,10 @@ QJsonObject parameterPackToJson(const Render::ShaderParameterPack &pack) const Render::PackUniformHash &uniforms = pack.uniforms(); QJsonArray uniformsArray; - for (auto it = uniforms.cbegin(), end = uniforms.cend(); it != end; ++it) { + for (int i = 0, m = uniforms.keys.size(); i < m; ++i) { QJsonObject uniformObj; - uniformObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(it.key())); - const Render::UniformValue::ValueType type = it.value().valueType(); + uniformObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(uniforms.keys.at(i))); + const Render::UniformValue::ValueType type = uniforms.values.at(i).valueType(); uniformObj.insert(QLatin1String("type"), type == Render::UniformValue::ScalarValue ? QLatin1String("value") @@ -346,15 +346,15 @@ void CommandExecuter::performAsynchronousCommandExecution(const QVector<Render:: viewObj.insert(QLatin1String("clearStencilValue"), v->clearStencilValue()); QJsonArray renderCommandsArray; - for (Render::RenderCommand *c : v->commands()) { + for (const Render::RenderCommand &c : v->commands()) { QJsonObject commandObj; Render::NodeManagers *nodeManagers = m_renderer->nodeManagers(); - commandObj.insert(QLatin1String("shader"), backendNodeToJSon(c->m_shader, nodeManagers->shaderManager())); - commandObj.insert(QLatin1String("vao"), double(c->m_vao.handle())); - commandObj.insert(QLatin1String("instanceCount"), c->m_instanceCount); - commandObj.insert(QLatin1String("geometry"), backendNodeToJSon(c->m_geometry, nodeManagers->geometryManager())); - commandObj.insert(QLatin1String("geometryRenderer"), backendNodeToJSon(c->m_geometryRenderer, nodeManagers->geometryRendererManager())); - commandObj.insert(QLatin1String("shaderParameterPack"), parameterPackToJson(c->m_parameterPack)); + commandObj.insert(QLatin1String("shader"), backendNodeToJSon(c.m_shader, nodeManagers->shaderManager())); + commandObj.insert(QLatin1String("vao"), double(c.m_vao.handle())); + commandObj.insert(QLatin1String("instanceCount"), c.m_instanceCount); + commandObj.insert(QLatin1String("geometry"), backendNodeToJSon(c.m_geometry, nodeManagers->geometryManager())); + commandObj.insert(QLatin1String("geometryRenderer"), backendNodeToJSon(c.m_geometryRenderer, nodeManagers->geometryRendererManager())); + commandObj.insert(QLatin1String("shaderParameterPack"), parameterPackToJson(c.m_parameterPack)); renderCommandsArray.push_back(commandObj); } diff --git a/src/render/backend/computecommand.cpp b/src/render/backend/computecommand.cpp index df79dcbe8..bc82291f0 100644 --- a/src/render/backend/computecommand.cpp +++ b/src/render/backend/computecommand.cpp @@ -53,6 +53,7 @@ ComputeCommand::ComputeCommand() : BackendNode(ReadWrite) , m_frameCount(0) , m_runType(QComputeCommand::Continuous) + , m_hasReachedFrameCount(false) { m_workGroups[0] = 1; m_workGroups[1] = 1; @@ -71,6 +72,7 @@ void ComputeCommand::cleanup() m_workGroups[2] = 1; m_frameCount = 0; m_runType = QComputeCommand::Continuous; + m_hasReachedFrameCount = false; } void ComputeCommand::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) @@ -98,8 +100,12 @@ void ComputeCommand::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firs markDirty(AbstractRenderer::ComputeDirty); } const QComputeCommandPrivate *d = static_cast<const QComputeCommandPrivate *>(Qt3DCore::QNodePrivate::get(node)); - if (d->m_frameCount != m_frameCount) { + // Check frame count only if frontend is enabled + // If disabled that means we might have disabled the frontend because + // framecount reached 0 + if (d->m_enabled && d->m_frameCount != m_frameCount) { m_frameCount = d->m_frameCount; + m_hasReachedFrameCount = m_frameCount <= 0; markDirty(AbstractRenderer::ComputeDirty); } @@ -112,14 +118,19 @@ void ComputeCommand::updateFrameCount() { // Disable frontend node when reaching 0 --m_frameCount; - if (m_frameCount <= 0) { - setEnabled(false); - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("enabled"); - e->setValue(false); - notifyObservers(e); - } + if (m_frameCount <= 0) + m_hasReachedFrameCount = true; + // Backend will be disabled on the next sync +} + +void ComputeCommand::resetHasReachedFrameCount() +{ + m_hasReachedFrameCount = false; +} + +bool ComputeCommand::hasReachedFrameCount() const +{ + return m_hasReachedFrameCount; } } // Render diff --git a/src/render/backend/computecommand_p.h b/src/render/backend/computecommand_p.h index dc2069928..5012930ae 100644 --- a/src/render/backend/computecommand_p.h +++ b/src/render/backend/computecommand_p.h @@ -79,11 +79,14 @@ public: // Called from a job void updateFrameCount(); + bool hasReachedFrameCount() const; + void resetHasReachedFrameCount(); private: int m_workGroups[3]; int m_frameCount; QComputeCommand::RunType m_runType; + bool m_hasReachedFrameCount; }; } // Render diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri index 9510b9530..c910adfe4 100644 --- a/src/render/backend/render-backend.pri +++ b/src/render/backend/render-backend.pri @@ -37,7 +37,8 @@ HEADERS += \ $$PWD/resourceaccessor_p.h \ $$PWD/visitorutils_p.h \ $$PWD/segmentsvisitor_p.h \ - $$PWD/pointsvisitor_p.h + $$PWD/pointsvisitor_p.h \ + $$PWD/commandexecuter_p.h SOURCES += \ $$PWD/renderthread.cpp \ @@ -67,11 +68,5 @@ SOURCES += \ $$PWD/offscreensurfacehelper.cpp \ $$PWD/resourceaccessor.cpp \ $$PWD/segmentsvisitor.cpp \ - $$PWD/pointsvisitor.cpp - -include($$QT3D_BUILD_ROOT/src/core/qt3dcore-config.pri) -QT_FOR_CONFIG += 3dcore-private -qtConfig(qt3d-profile-jobs): { - HEADERS += $$PWD/commandexecuter_p.h - SOURCES += $$PWD/commandexecuter.cpp -} + $$PWD/pointsvisitor.cpp \ + $$PWD/commandexecuter.cpp diff --git a/src/render/backend/rendersettings.cpp b/src/render/backend/rendersettings.cpp index 487f6e11a..5aeaa2563 100644 --- a/src/render/backend/rendersettings.cpp +++ b/src/render/backend/rendersettings.cpp @@ -42,7 +42,6 @@ #include <Qt3DRender/QFrameGraphNode> #include <Qt3DRender/private/abstractrenderer_p.h> #include <Qt3DRender/private/qrendersettings_p.h> -#include <Qt3DCore/qnodecommand.h> QT_BEGIN_NAMESPACE @@ -79,20 +78,21 @@ void RenderSettings::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firs m_renderPolicy = node->renderPolicy(); } - if (node->pickingSettings()->pickMethod() != m_pickMethod) { - m_pickMethod = node->pickingSettings()->pickMethod(); + auto ncnode = const_cast<QRenderSettings *>(node); + if (ncnode->pickingSettings()->pickMethod() != m_pickMethod) { + m_pickMethod = ncnode->pickingSettings()->pickMethod(); } - if (node->pickingSettings()->pickResultMode() != m_pickResultMode) { - m_pickResultMode = node->pickingSettings()->pickResultMode(); + if (ncnode->pickingSettings()->pickResultMode() != m_pickResultMode) { + m_pickResultMode = ncnode->pickingSettings()->pickResultMode(); } - if (node->pickingSettings()->worldSpaceTolerance() != m_pickWorldSpaceTolerance) { - m_pickWorldSpaceTolerance = node->pickingSettings()->worldSpaceTolerance(); + if (ncnode->pickingSettings()->worldSpaceTolerance() != m_pickWorldSpaceTolerance) { + m_pickWorldSpaceTolerance = ncnode->pickingSettings()->worldSpaceTolerance(); } - if (node->pickingSettings()->faceOrientationPickingMode() != m_faceOrientationPickingMode) { - m_faceOrientationPickingMode = node->pickingSettings()->faceOrientationPickingMode(); + if (ncnode->pickingSettings()->faceOrientationPickingMode() != m_faceOrientationPickingMode) { + m_faceOrientationPickingMode = ncnode->pickingSettings()->faceOrientationPickingMode(); } // Either because something above as changed or if QRenderSettingsPrivate::invalidFrame() diff --git a/src/render/backend/segmentsvisitor.cpp b/src/render/backend/segmentsvisitor.cpp index a3a5d059c..d9f2d79ec 100644 --- a/src/render/backend/segmentsvisitor.cpp +++ b/src/render/backend/segmentsvisitor.cpp @@ -135,34 +135,44 @@ void traverseSegmentStripIndexed(Index *indices, bool loop) { uint i = 0; + uint stripStartIndex = 0; + const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex); const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U); uint ndx[2]; Vector3D abc[2]; - ndx[0] = indices[0]; - uint idx = ndx[0] * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) - abc[0][j] = vertices[idx + j]; - while (i < indexInfo.count - 1) { - ndx[1] = indices[i + 1]; - if (ndx[0] != ndx[1]) { - idx = ndx[1] * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) - abc[1][j] = vertices[idx + j]; - visitor->visit(ndx[0], abc[0], ndx[1], abc[1]); + while (i < indexInfo.count) { + if (indexInfo.restartEnabled && indexInfo.restartIndexValue == static_cast<int>(indices[i])) { + ++i; + continue; } + stripStartIndex = i; + ndx[0] = indices[stripStartIndex]; + uint idx = ndx[0] * verticesStride; + for (uint j = 0; j < maxVerticesDataSize; ++j) + abc[0][j] = vertices[idx + j]; ++i; - ndx[0] = ndx[1]; - abc[0] = abc[1]; - } - if (loop) { - ndx[1] = indices[0]; - if (ndx[0] != ndx[1]) { - idx = ndx[1] * verticesStride; - for (uint j = 0; j < maxVerticesDataSize; ++j) - abc[1][j] = vertices[idx + j]; - visitor->visit(ndx[0], abc[0], ndx[1], abc[1]); + while (i < indexInfo.count && (!indexInfo.restartEnabled || indexInfo.restartIndexValue != static_cast<int>(indices[i]))) { + ndx[1] = indices[i]; + if (ndx[0] != ndx[1]) { + idx = ndx[1] * verticesStride; + for (uint j = 0; j < maxVerticesDataSize; ++j) + abc[1][j] = vertices[idx + j]; + visitor->visit(ndx[0], abc[0], ndx[1], abc[1]); + } + ++i; + ndx[0] = ndx[1]; + abc[0] = abc[1]; + } + if (loop) { + ndx[1] = indices[stripStartIndex]; + if (ndx[0] != ndx[1]) { + idx = ndx[1] * verticesStride; + for (uint j = 0; j < maxVerticesDataSize; ++j) + abc[1][j] = vertices[idx + j]; + visitor->visit(ndx[0], abc[0], ndx[1], abc[1]); + } } } } diff --git a/src/render/backend/stringtoint.cpp b/src/render/backend/stringtoint.cpp index 5659da394..0e0d38c9c 100644 --- a/src/render/backend/stringtoint.cpp +++ b/src/render/backend/stringtoint.cpp @@ -50,9 +50,18 @@ namespace Render { namespace { -QReadWriteLock lock; -QHash<QString, int> map = QHash<QString, int>(); -QVector<QString> reverseMap = QVector<QString>(); +struct StringToIntCache +{ + QReadWriteLock lock; + QHash<QString, int> map = QHash<QString, int>(); + QVector<QString> reverseMap = QVector<QString>(); + + static StringToIntCache& instance() + { + static StringToIntCache c; + return c; + } +}; } // anonymous @@ -64,20 +73,21 @@ int StringToInt::lookupId(QLatin1String str) int StringToInt::lookupId(const QString &str) { + auto& cache = StringToIntCache::instance(); int idx; { - QReadLocker readLocker(&lock); - idx = map.value(str, -1); + QReadLocker readLocker(&cache.lock); + idx = cache.map.value(str, -1); } if (Q_UNLIKELY(idx < 0)) { - QWriteLocker writeLocker(&lock); - idx = map.value(str, -1); + QWriteLocker writeLocker(&cache.lock); + idx = cache.map.value(str, -1); if (idx < 0) { - idx = reverseMap.size(); - Q_ASSERT(map.size() == reverseMap.size()); - map.insert(str, idx); - reverseMap.append(str); + idx = cache.reverseMap.size(); + Q_ASSERT(cache.map.size() == cache.reverseMap.size()); + cache.map.insert(str, idx); + cache.reverseMap.append(str); } } return idx; @@ -85,9 +95,10 @@ int StringToInt::lookupId(const QString &str) QString StringToInt::lookupString(int idx) { - QReadLocker readLocker(&lock); - if (Q_LIKELY(reverseMap.size() > idx)) - return reverseMap.at(idx); + auto& cache = StringToIntCache::instance(); + QReadLocker readLocker(&cache.lock); + if (Q_LIKELY(cache.reverseMap.size() > idx)) + return cache.reverseMap.at(idx); return QString(); } diff --git a/src/render/backend/transform.cpp b/src/render/backend/transform.cpp index 8e98801b7..9e78bc96f 100644 --- a/src/render/backend/transform.cpp +++ b/src/render/backend/transform.cpp @@ -39,7 +39,6 @@ #include "transform_p.h" -#include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/private/qchangearbiter_p.h> #include <Qt3DCore/qtransform.h> #include <Qt3DCore/private/qtransform_p.h> diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp index 87ba7bde9..a58f2d20b 100644 --- a/src/render/backend/trianglesvisitor.cpp +++ b/src/render/backend/trianglesvisitor.cpp @@ -153,6 +153,10 @@ void traverseTriangleStripIndexed(index *indices, uint ndx[3]; Vector3D abc[3]; while (i < indexInfo.count - 2) { + if (indexInfo.restartEnabled && indexInfo.restartIndexValue == static_cast<int>(indices[i + 2])) { + i += 3; + continue; + } bool degenerate = false; for (uint u = 0; u < 3; ++u) { ndx[u] = indices[i + u]; @@ -216,6 +220,11 @@ void traverseTriangleFanIndexed(index *indices, ndx[0] = indices[0]; uint i = 1; while (i < indexInfo.count - 1) { + if (indexInfo.restartEnabled && indexInfo.restartIndexValue == static_cast<int>(indices[i + 1])) { + ndx[0] = indices[i + 2]; + i += 3; + continue; + } for (uint u = 0; u < 2; ++u) { ndx[u + 1] = indices[i + u]; uint idx = ndx[u + 1] * verticesStride; @@ -224,7 +233,7 @@ void traverseTriangleFanIndexed(index *indices, } } visitor->visit(ndx[2], abc[2], ndx[1], abc[1], ndx[0], abc[0]); - i += 1; + ++i; } } diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h index 09575a077..c8731637c 100644 --- a/src/render/backend/uniform_p.h +++ b/src/render/backend/uniform_p.h @@ -227,9 +227,9 @@ public: return !(*this == other); } private: - // Allocate 4 floats on stack + // Allocate 16 floats on stack // For larger elements, heap allocation will be used - QVarLengthArray<float, 4> m_data; + QVarLengthArray<float, 16> m_data; ValueType m_valueType = ScalarValue; diff --git a/src/render/backend/visitorutils_p.h b/src/render/backend/visitorutils_p.h index 6a5c7b4ff..14183e11b 100644 --- a/src/render/backend/visitorutils_p.h +++ b/src/render/backend/visitorutils_p.h @@ -149,6 +149,8 @@ void visitPrimitives(NodeManagers *manager, const GeometryRenderer *renderer, Vi indexBufferInfo.byteOffset = indexAttribute->byteOffset(); indexBufferInfo.byteStride = indexAttribute->byteStride(); indexBufferInfo.count = indexAttribute->count(); + indexBufferInfo.restartEnabled = renderer->primitiveRestartEnabled(); + indexBufferInfo.restartIndexValue = renderer->restartIndexValue(); IndexExecutor executor; executor.m_vertexBufferInfo = vertexBufferInfo; diff --git a/src/render/framegraph/qblitframebuffer.cpp b/src/render/framegraph/qblitframebuffer.cpp index 3a26e3d56..252758af4 100644 --- a/src/render/framegraph/qblitframebuffer.cpp +++ b/src/render/framegraph/qblitframebuffer.cpp @@ -70,6 +70,10 @@ namespace Qt3DRender { Specifies the interpolation applied if the image is stretched. + \value Nearest + Nearest-neighbor interpolation. + \value Linear + Linear interpolation. */ /*! \property Qt3DRender::QBlitFramebuffer::destination diff --git a/src/render/framegraph/qbuffercapture.cpp b/src/render/framegraph/qbuffercapture.cpp index 0c12a3aff..3eaa5dfd2 100644 --- a/src/render/framegraph/qbuffercapture.cpp +++ b/src/render/framegraph/qbuffercapture.cpp @@ -39,8 +39,8 @@ #include <Qt3DRender/qbuffercapture.h> #include <Qt3DRender/private/qbuffercapture_p.h> -#include <Qt3DCore/QSceneChange> -#include <Qt3DRender/QFrameGraphNodeCreatedChange> +#include <Qt3DCore/qscenechange.h> +#include <Qt3DRender/qframegraphnodecreatedchange.h> QT_BEGIN_NAMESPACE @@ -62,6 +62,14 @@ QBufferCapturePrivate::QBufferCapturePrivate() \inmodule Qt3DRender \brief Exchanges buffer data between GPU and CPU. */ + +/*! + \qmltype BufferCapture + \inqmlmodule Qt3D.Render + \instantiates Qt3DRender::QBufferCapture + \brief Exchanges buffer data between GPU and CPU. +*/ + QBufferCapture::QBufferCapture(Qt3DCore::QNode *parent) : QFrameGraphNode(*new QBufferCapturePrivate, parent) { diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp index cc74553b2..a10083374 100644 --- a/src/render/framegraph/qrendercapture.cpp +++ b/src/render/framegraph/qrendercapture.cpp @@ -36,8 +36,8 @@ #include <Qt3DRender/qrendercapture.h> #include <Qt3DRender/private/qrendercapture_p.h> -#include <Qt3DCore/QSceneChange> -#include <Qt3DCore/QPropertyUpdatedChange> +#include <Qt3DCore/qscenechange.h> +#include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DRender/qframegraphnodecreatedchange.h> #include <QPointer> diff --git a/src/render/framegraph/qsetfence.cpp b/src/render/framegraph/qsetfence.cpp index 5cb82f3db..262dbd4ad 100644 --- a/src/render/framegraph/qsetfence.cpp +++ b/src/render/framegraph/qsetfence.cpp @@ -54,7 +54,8 @@ QSetFencePrivate::QSetFencePrivate() } /*! - \class QSetFence + \class Qt3DRender::QSetFence + \inmodule Qt3DRender \brief FrameGraphNode used to insert a fence in the graphics command stream. Fence allow to synchronosize GPU and CPU workloads. GPU commands usually @@ -100,7 +101,7 @@ QSetFence::QSetFence(QSetFencePrivate &dd, Qt3DCore::QNode *parent) are supported. */ /*! - \property QSetFence::handleType + \property Qt3DRender::QSetFence::handleType Specifies the type of handle being used. Currently only OpenGL Fence ids are supported. @@ -123,12 +124,12 @@ void QSetFencePrivate::setHandleType(QSetFence::HandleType type) } /*! - \qmlproperty variant AbstractFence::handle + \qmlproperty variant SetFence::handle Holds the underlying fence handle wrapped in a variant. */ /*! - \property QAbstractFence::handle + \property Qt3DRender::QSetFence::handle Holds the underlying fence handle wrapped in a QVariant. */ diff --git a/src/render/framegraph/qwaitfence.cpp b/src/render/framegraph/qwaitfence.cpp index 5195653ce..737f4e54d 100644 --- a/src/render/framegraph/qwaitfence.cpp +++ b/src/render/framegraph/qwaitfence.cpp @@ -56,8 +56,8 @@ QWaitFencePrivate::QWaitFencePrivate() } /*! - \class QWaitFence - + \class Qt3DRender::QWaitFence + \inmodule Qt3DRender \brief FrameGraphNode used to wait for a fence in the graphics command stream to become signaled. @@ -98,7 +98,7 @@ QWaitFence::~QWaitFence() become signaled. This is false by default. */ /*! - \property QWaitFence::waitOnCPU + \property Qt3DRender::QWaitFence::waitOnCPU Specifies whether the CPU should be block while waiting for the fence to become signaled. This is false by default. @@ -125,7 +125,7 @@ void QWaitFence::setWaitOnCPU(bool waitOnCPU) to become signaled. */ /*! - \property QWaitFence::timeout + \property Qt3DRender::QWaitFence::timeout Specifies the maximum amount of time in nanoseconds to wait for the fence to become signaled. @@ -157,7 +157,7 @@ QWaitFence::QWaitFence(QWaitFencePrivate &dd, Qt3DCore::QNode *parent) are supported. */ /*! - \property QWaitFence::handleType + \property Qt3DRender::QWaitFence::handleType Specifies the type of handle being used. Currently only OpenGL Fence ids are supported. @@ -183,7 +183,7 @@ void QWaitFence::setHandleType(QWaitFence::HandleType type) Holds the underlying fence handle wrapped in a variant. */ /*! - \property QWaitFence::handle + \property Qt3DRender::QWaitFence::handle Holds the underlying fence handle wrapped in a QVariant. */ diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp index 68d62b6a5..73d8770a7 100644 --- a/src/render/framegraph/rendercapture.cpp +++ b/src/render/framegraph/rendercapture.cpp @@ -37,6 +37,8 @@ #include <Qt3DRender/private/qrendercapture_p.h> #include <Qt3DRender/private/rendercapture_p.h> #include <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DCore/private/qaspectmanager_p.h> +#include <Qt3DCore/private/qaspectjobmanager_p.h> QT_BEGIN_NAMESPACE @@ -99,17 +101,25 @@ void RenderCapture::addRenderCapture(int captureId, const QImage &image) m_renderCaptureData.push_back(data); } -// called by send render capture job thread -void RenderCapture::sendRenderCaptures() +// called to send render capture in main thread +void RenderCapture::syncRenderCapturesToFrontend(Qt3DCore::QAspectManager *manager) { - QMutexLocker lock(&m_mutex); + auto *frontend = manager->lookupNode(peerId()); + if (!frontend) + return; + QRenderCapturePrivate *dfrontend = static_cast<QRenderCapturePrivate *>(Qt3DCore::QNodePrivate::get(frontend)); + QMutexLocker lock(&m_mutex); for (const RenderCaptureDataPtr &data : qAsConst(m_renderCaptureData)) { - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("renderCaptureData"); - e->setValue(QVariant::fromValue(data)); - notifyObservers(e); + QPointer<QRenderCaptureReply> reply = dfrontend->takeReply(data.data()->captureId); + if (reply) { + dfrontend->setImage(reply, data.data()->image); + emit reply->completed(); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + emit reply->completeChanged(true); +QT_WARNING_POP + } } m_renderCaptureData.clear(); } diff --git a/src/render/framegraph/rendercapture_p.h b/src/render/framegraph/rendercapture_p.h index 4560c525d..5714fb44d 100644 --- a/src/render/framegraph/rendercapture_p.h +++ b/src/render/framegraph/rendercapture_p.h @@ -66,9 +66,9 @@ public: bool wasCaptureRequested() const; QRenderCaptureRequest takeCaptureRequest(); void addRenderCapture(int captureId, const QImage &image); - void sendRenderCaptures(); void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override; + void syncRenderCapturesToFrontend(Qt3DCore::QAspectManager *manager); private: diff --git a/src/render/framegraph/subtreeenabler.cpp b/src/render/framegraph/subtreeenabler.cpp index 160e1a5b5..4d912dc1d 100644 --- a/src/render/framegraph/subtreeenabler.cpp +++ b/src/render/framegraph/subtreeenabler.cpp @@ -52,30 +52,12 @@ SubtreeEnabler::SubtreeEnabler() { } -void SubtreeEnabler::sendDisableToFrontend() -{ - if (m_enablement != QSubtreeEnabler::SingleShot) - return; - - if (isEnabled()) - return; - - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("enabled"); - e->setValue(false); - notifyObservers(e); -} - void SubtreeEnabler::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) { const QSubtreeEnabler *node = qobject_cast<const QSubtreeEnabler *>(frontEnd); if (!node) return; - if (node->isEnabled() != isEnabled()) - markDirty(AbstractRenderer::AllDirty); - FrameGraphNode::syncFromFrontEnd(frontEnd, firstTime); const auto enablement = node->enablement(); diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp index 2dcec7ed6..b0fd16182 100644 --- a/src/render/frontend/qcamera.cpp +++ b/src/render/frontend/qcamera.cpp @@ -235,7 +235,7 @@ void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) * \qmlmethod void Qt3D.Render::Camera::viewEntity(Entity entity) * * Rotates and moves the camera so that it's viewCenter is the center of the entity's bounding volume - * and the entire entity fits in the view port. + * and the entire \a entity fits in the view port. * * \note Only works if the lens is in perspective projection mode. * \sa Qt3D.Render::Camera::projectionType diff --git a/src/render/frontend/qcameralens.cpp b/src/render/frontend/qcameralens.cpp index cf30b714a..1d8059f45 100644 --- a/src/render/frontend/qcameralens.cpp +++ b/src/render/frontend/qcameralens.cpp @@ -233,11 +233,7 @@ void QCameraLens::viewAll(Qt3DCore::QNodeId cameraId) { Q_D(QCameraLens); if (d->m_projectionType == PerspectiveProjection) { - QVariant v; - v.setValue(cameraId); - d->m_pendingViewAllCommand = {QLatin1String("QueryRootBoundingVolume"), - v, - id()}; + d->m_pendingViewAllRequest = {Qt3DCore::QNodeId::createId(), cameraId, {}}; d->update(); } } @@ -246,30 +242,19 @@ void QCameraLens::viewEntity(Qt3DCore::QNodeId entityId, Qt3DCore::QNodeId camer { Q_D(QCameraLens); if (d->m_projectionType == PerspectiveProjection) { - QVector<Qt3DCore::QNodeId> ids = {entityId, cameraId}; - QVariant v; - v.setValue(ids); - d->m_pendingViewAllCommand = {QLatin1String("QueryEntityBoundingVolume"), - v, - id()}; + d->m_pendingViewAllRequest = {Qt3DCore::QNodeId::createId(), cameraId, entityId}; d->update(); } } -void QCameraLensPrivate::processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId, - const QVariant &data) +void QCameraLensPrivate::processViewAllResult(Qt3DCore::QNodeId requestId, const QVector3D ¢er, float radius) { Q_Q(QCameraLens); - if (!m_pendingViewAllCommand || m_pendingViewAllCommand.commandId != commandId) + if (!m_pendingViewAllRequest || m_pendingViewAllRequest.requestId != requestId) return; - QVector<float> boundingVolumeData = data.value< QVector<float> >(); - if (boundingVolumeData.size() != 4) - return; - QVector3D center(boundingVolumeData[0], boundingVolumeData[1], boundingVolumeData[2]); - float radius = boundingVolumeData[3]; Q_EMIT q->viewSphere(center, radius); - m_pendingViewAllCommand = {}; + m_pendingViewAllRequest = {}; } /*! @@ -643,18 +628,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QCameraLens::createNodeCreationChange() cons void QCameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) { - Q_D(QCameraLens); - switch (change->type()) { - case Qt3DCore::CommandRequested: { - Qt3DCore::QNodeCommandPtr command = qSharedPointerCast<Qt3DCore::QNodeCommand>(change); - - if (command->name() == QLatin1String("ViewAll")) - d->processViewAllCommand(command->inReplyTo(), command->data()); - } - break; - default: - break; - } + Q_UNUSED(change) } } // Qt3DRender diff --git a/src/render/frontend/qcameralens_p.h b/src/render/frontend/qcameralens_p.h index 5c5a6a42a..eca01b890 100644 --- a/src/render/frontend/qcameralens_p.h +++ b/src/render/frontend/qcameralens_p.h @@ -53,7 +53,6 @@ #include <Qt3DRender/private/qt3drender_global_p.h> #include <Qt3DCore/private/qcomponent_p.h> -#include <Qt3DCore/private/qnodecommand_p.h> #include "qcameralens.h" @@ -63,21 +62,21 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { -struct CameraLensCommand +struct CameraLensRequest { - QString name; - QVariant data; - Qt3DCore::QNodeCommand::CommandId commandId; + Qt3DCore::QNodeId requestId; + Qt3DCore::QNodeId cameraId; + Qt3DCore::QNodeId entityId; - inline operator bool() const { return !name.isEmpty(); } + inline operator bool() const { return !requestId.isNull(); } }; -inline bool operator ==(const CameraLensCommand &a, const CameraLensCommand &b) noexcept +inline bool operator ==(const CameraLensRequest &a, const CameraLensRequest &b) noexcept { - return a.name == b.name && a.data == b.data && a.commandId == b.commandId; + return a.cameraId == b.cameraId && a.entityId == b.entityId && a.requestId == b.requestId; } -inline bool operator !=(const CameraLensCommand &a, const CameraLensCommand &b) noexcept +inline bool operator !=(const CameraLensRequest &a, const CameraLensRequest &b) noexcept { return !(a == b); } @@ -123,8 +122,8 @@ public: float m_exposure; - CameraLensCommand m_pendingViewAllCommand; - void processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId, const QVariant &data); + CameraLensRequest m_pendingViewAllRequest; + void processViewAllResult(Qt3DCore::QNodeId requestId, const QVector3D ¢er, float radius); private: inline void updatePerpectiveProjection() diff --git a/src/render/frontend/qcomputecommand.cpp b/src/render/frontend/qcomputecommand.cpp index d0c9f5805..dfd9c2033 100644 --- a/src/render/frontend/qcomputecommand.cpp +++ b/src/render/frontend/qcomputecommand.cpp @@ -92,15 +92,15 @@ namespace Qt3DRender { */ /*! - \qmlproperty QComputeCommand::runType + \qmlproperty enumeration ComputeCommand::runType Specifies whether the compute command should be performed every frame or manually triggered. - \value Continuous Compute command is executed everyframe. This is the + \value ComputeCommand.Continuous Compute command is executed everyframe. This is the default. - \value Manual CompouteCommand is executed for a given number of frames and + \value ComputeCommand.Manual CompouteCommand is executed for a given number of frames and then the component disables itself. */ diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp index 3d0cb9553..ced0604c7 100644 --- a/src/render/frontend/qlevelofdetail.cpp +++ b/src/render/frontend/qlevelofdetail.cpp @@ -325,6 +325,11 @@ Qt3DCore::QNodeCreatedChangeBasePtr QLevelOfDetail::createNodeCreationChange() c return creationChange; } +// TODO Unused remove in Qt6 +void QLevelOfDetail::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) +{ +} + QCamera *QLevelOfDetail::camera() const { Q_D(const QLevelOfDetail); diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h index f6c09a287..81fcf3235 100644 --- a/src/render/frontend/qlevelofdetail.h +++ b/src/render/frontend/qlevelofdetail.h @@ -97,6 +97,8 @@ Q_SIGNALS: protected: explicit QLevelOfDetail(QLevelOfDetailPrivate &dd, Qt3DCore::QNode *parent = nullptr); Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override; + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; private: Q_DECLARE_PRIVATE(QLevelOfDetail) diff --git a/src/render/frontend/qlevelofdetailswitch.cpp b/src/render/frontend/qlevelofdetailswitch.cpp index 7b888fe98..c07d4c4b1 100644 --- a/src/render/frontend/qlevelofdetailswitch.cpp +++ b/src/render/frontend/qlevelofdetailswitch.cpp @@ -42,7 +42,6 @@ #include "qlevelofdetail_p.h" #include "qglobal.h" #include <Qt3DCore/QEntity> -#include <Qt3DCore/qpropertyupdatedchange.h> QT_BEGIN_NAMESPACE @@ -134,6 +133,11 @@ QLevelOfDetailSwitch::QLevelOfDetailSwitch(QLevelOfDetailPrivate &dd, QNode *par { } +// TODO Unused remove in Qt6 +void QLevelOfDetailSwitch::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) +{ +} + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/frontend/qlevelofdetailswitch.h b/src/render/frontend/qlevelofdetailswitch.h index 90f4ee3e2..325b885ed 100644 --- a/src/render/frontend/qlevelofdetailswitch.h +++ b/src/render/frontend/qlevelofdetailswitch.h @@ -57,6 +57,8 @@ public: protected: explicit QLevelOfDetailSwitch(QLevelOfDetailPrivate &dd, Qt3DCore::QNode *parent = nullptr); + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; private: Q_DECLARE_PRIVATE(QLevelOfDetailSwitch) diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 271eb9c11..7a51fa0e7 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -170,10 +170,8 @@ #include <Qt3DCore/QAspectEngine> #include <Qt3DCore/private/qservicelocator_p.h> -#include <QDebug> -#include <QOffscreenSurface> #include <QThread> -#include <QWindow> +#include <QOpenGLContext> QT_BEGIN_NAMESPACE @@ -202,11 +200,16 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) , m_nodeManagers(nullptr) , m_renderer(nullptr) , m_initialized(false) + , m_renderAfterJobs(false) , m_renderType(type) , m_offscreenHelper(nullptr) { m_instances.append(this); loadSceneParsers(); + if (m_renderType == QRenderAspect::Threaded && !QOpenGLContext::supportsThreadedOpenGL()) { + m_renderType = QRenderAspect::Synchronous; + m_renderAfterJobs = true; + } } /*! \internal */ @@ -239,6 +242,13 @@ void QRenderAspectPrivate::syncDirtyFrontEndNode(QNode *node, QBackendNode *back renderBackend->syncFromFrontEnd(node, firstTime); } +void QRenderAspectPrivate::jobsDone(QAspectManager *manager) +{ + m_renderer->jobsDone(manager); + if (m_renderAfterJobs) + m_renderer->doRender(true); +} + /*! \internal */ void QRenderAspectPrivate::registerBackendTypes() { @@ -546,6 +556,8 @@ QVariant QRenderAspect::executeCommand(const QStringList &args) void QRenderAspect::onEngineStartup() { Q_D(QRenderAspect); + if (d->m_renderAfterJobs) // synchronous rendering but using QWindow + d->m_renderer->initialize(); Render::NodeManagers *managers = d->m_renderer->nodeManagers(); Render::Entity *rootEntity = managers->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId()); Q_ASSERT(rootEntity); diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index 62e373b11..8723180ab 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -87,6 +87,7 @@ public: static QRenderAspectPrivate* findPrivate(Qt3DCore::QAspectEngine *engine); void syncDirtyFrontEndNode(Qt3DCore::QNode *node, Qt3DCore::QBackendNode *backend, bool firstTime) const override; + void jobsDone(Qt3DCore::QAspectManager *manager) override; void registerBackendTypes(); void unregisterBackendTypes(); @@ -102,6 +103,7 @@ public: Render::AbstractRenderer *m_renderer; bool m_initialized; + bool m_renderAfterJobs; QList<QSceneImporter *> m_sceneImporter; QVector<QString> m_loadedPlugins; QVector<Render::QRenderPlugin *> m_renderPlugins; diff --git a/src/render/frontend/qrendersettings.cpp b/src/render/frontend/qrendersettings.cpp index d106e4205..491d3e442 100644 --- a/src/render/frontend/qrendersettings.cpp +++ b/src/render/frontend/qrendersettings.cpp @@ -104,25 +104,25 @@ void QRenderSettingsPrivate::invalidateFrame() /*! \internal */ void QRenderSettingsPrivate::_q_onPickingMethodChanged(QPickingSettings::PickMethod pickMethod) { - notifyPropertyChange("pickMethod", pickMethod);// TODOSYNC + notifyPropertyChange("pickMethod", pickMethod); } /*! \internal */ void QRenderSettingsPrivate::_q_onPickResultModeChanged(QPickingSettings::PickResultMode pickResultMode) { - notifyPropertyChange("pickResultMode", pickResultMode);// TODOSYNC + notifyPropertyChange("pickResultMode", pickResultMode); } /*! \internal */ void QRenderSettingsPrivate::_q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode) { - notifyPropertyChange("faceOrientationPickingMode", faceOrientationPickingMode);// TODOSYNC + notifyPropertyChange("faceOrientationPickingMode", faceOrientationPickingMode); } /*! \internal */ void QRenderSettingsPrivate::_q_onWorldSpaceToleranceChanged(float worldSpaceTolerance) { - notifyPropertyChange("pickWorldSpaceTolerance", worldSpaceTolerance);// TODOSYNC + notifyPropertyChange("pickWorldSpaceTolerance", worldSpaceTolerance); } QRenderSettings::QRenderSettings(Qt3DCore::QNode *parent) @@ -161,12 +161,6 @@ QPickingSettings *QRenderSettings::pickingSettings() return &(d->m_pickingSettings); } -const QPickingSettings *QRenderSettings::pickingSettings() const -{ - Q_D(const QRenderSettings); - return &(d->m_pickingSettings); -} - /*! \qmlproperty FrameGraphNode RenderSettings::activeFrameGraph diff --git a/src/render/frontend/qrendersettings.h b/src/render/frontend/qrendersettings.h index c8771a8fa..9d2baa58b 100644 --- a/src/render/frontend/qrendersettings.h +++ b/src/render/frontend/qrendersettings.h @@ -71,7 +71,6 @@ public: Q_ENUM(RenderPolicy) // LCOV_EXCL_LINE QPickingSettings* pickingSettings(); - const QPickingSettings* pickingSettings() const; QFrameGraphNode *activeFrameGraph() const; RenderPolicy renderPolicy() const; diff --git a/src/render/frontend/sphere.cpp b/src/render/frontend/sphere.cpp index 470dbfe59..0caeed9f1 100644 --- a/src/render/frontend/sphere.cpp +++ b/src/render/frontend/sphere.cpp @@ -93,54 +93,6 @@ bool intersectRaySphere(const Qt3DRender::RayCasting::QRay3D &ray, const Qt3DRen return true; } -inline QPair<int, int> findExtremePoints(const QVector<Vector3D> &points) -{ - // Find indices of extreme points along x, y, and z axes - int xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0; - for (int i = 1; i < points.size(); ++i) { - const Vector3D &p = points.at(i); - if (p.x() < points[xMin].x()) - xMin = i; - if (p.x() > points[xMax].x()) - xMax = i; - if (p.y() < points[yMin].y()) - yMin = i; - if (p.y() > points[yMax].y()) - yMax = i; - if (p.z() < points[zMin].z()) - zMin = i; - if (p.z() > points[zMax].z()) - zMax = i; - } - - // Calculate squared distance for the pairs of points - const float xDist2 = (points.at(xMax) - points.at(xMin)).lengthSquared(); - const float yDist2 = (points.at(yMax) - points.at(yMin)).lengthSquared(); - const float zDist2 = (points.at(zMax) - points.at(zMin)).lengthSquared(); - - // Select most distant pair - QPair<int, int> extremeIndices(xMin, xMax); - if (yDist2 > xDist2 && yDist2 > zDist2) - extremeIndices = qMakePair(yMin, yMax); - if (zDist2 > xDist2 && zDist2 > yDist2) - extremeIndices = qMakePair(zMin, zMax); - - return extremeIndices; -} - -inline void sphereFromExtremePoints(Qt3DRender::Render::Sphere &s, const QVector<Vector3D> &points) -{ - // Find two most separated points on any of the basis vectors - QPair<int, int> extremeIndices = findExtremePoints(points); - - // Construct sphere to contain these two points - const Vector3D &p = points.at(extremeIndices.first); - const Vector3D &q = points.at(extremeIndices.second); - const Vector3D c = 0.5f * (p + q); - s.setCenter(c); - s.setRadius((q - c).length()); -} - inline void constructRitterSphere(Qt3DRender::Render::Sphere &s, const QVector<Vector3D> &points) { //def bounding_sphere(points): diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp index 0ce81efc1..6db3bab44 100644 --- a/src/render/geometry/buffer.cpp +++ b/src/render/geometry/buffer.cpp @@ -88,15 +88,6 @@ void Buffer::executeFunctor() m_data = (*m_functor)(); // Request data to be loaded forceDataUpload(); - - if (m_syncData) { - // Send data back to the frontend - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("data"); - e->setValue(QVariant::fromValue(m_data)); - notifyObservers(e); - } } //Called from th sendBufferJob @@ -105,12 +96,6 @@ void Buffer::updateDataFromGPUToCPU(QByteArray data) // Note: when this is called, data is what's currently in GPU memory // so m_data shouldn't be reuploaded m_data = data; - // Send data back to the frontend - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); - e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); - e->setPropertyName("downloadedData"); - e->setValue(QVariant::fromValue(m_data)); - notifyObservers(e); } void Buffer::forceDataUpload() @@ -152,20 +137,31 @@ void Buffer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) m_manager->addDirtyBuffer(peerId()); } { - QVariant v = node->property("QT3D_updateData"); - if (v.isValid()) { + const QVariant v = node->property("QT3D_updateData"); + + // Make sure we record data if it's the first time we are called + // or if we have no partial updates + if (firstTime || !v.isValid()){ + const QByteArray newData = node->data(); + const bool dirty = m_data != newData; + m_bufferDirty |= dirty; + m_data = newData; + + // Since frontend applies partial updates to its m_data + // if we enter this code block, there's no problem in actually + // ignoring the partial updates + if (v.isValid()) + const_cast<QBuffer *>(node)->setProperty("QT3D_updateData", {}); + + if (dirty && !m_data.isEmpty()) + forceDataUpload(); + } else if (v.isValid()) { + // Apply partial updates and record them to allow partial upload to the GPU Qt3DRender::QBufferUpdate updateData = v.value<Qt3DRender::QBufferUpdate>(); m_data.replace(updateData.offset, updateData.data.size(), updateData.data); m_bufferUpdates.push_back(updateData); m_bufferDirty = true; const_cast<QBuffer *>(node)->setProperty("QT3D_updateData", {}); - } else { - QByteArray newData = node->data(); - bool dirty = m_data != newData; - m_bufferDirty |= dirty; - m_data = newData; - if (dirty && !m_data.isEmpty()) - forceDataUpload(); } } markDirty(AbstractRenderer::BuffersDirty); diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp index 3b460f48c..881c0f66b 100644 --- a/src/render/geometry/geometryrenderer.cpp +++ b/src/render/geometry/geometryrenderer.cpp @@ -139,8 +139,16 @@ void GeometryRenderer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) if (functorDirty) { m_dirty = true; m_geometryFactory = newFunctor; - if (m_geometryFactory && m_manager != nullptr) + if (m_geometryFactory && m_manager != nullptr) { m_manager->addDirtyGeometryRenderer(peerId()); + + const bool isQMeshFunctor = m_geometryFactory->id() == Qt3DRender::functorTypeId<MeshLoaderFunctor>(); + if (isQMeshFunctor) { + const QMesh *meshNode = static_cast<const QMesh *>(node); + QMeshPrivate *dmeshNode = QMeshPrivate::get(const_cast<QMesh *>(meshNode)); + dmeshNode->setStatus(QMesh::Loading); + } + } } markDirty(AbstractRenderer::GeometryDirty); diff --git a/src/render/geometry/gltfskeletonloader.cpp b/src/render/geometry/gltfskeletonloader.cpp index 56144747c..07789cd84 100644 --- a/src/render/geometry/gltfskeletonloader.cpp +++ b/src/render/geometry/gltfskeletonloader.cpp @@ -48,6 +48,7 @@ #include <Qt3DRender/private/renderlogging_p.h> #include <Qt3DCore/private/qmath3d_p.h> +#include <Qt3DCore/private/qloadgltf_p.h> QT_BEGIN_NAMESPACE @@ -316,12 +317,7 @@ GLTFSkeletonLoader::GLTFSkeletonLoader() bool GLTFSkeletonLoader::load(QIODevice *ioDev) { - QByteArray jsonData = ioDev->readAll(); - QJsonDocument sceneDocument = QJsonDocument::fromBinaryData(jsonData); - if (sceneDocument.isNull()) - sceneDocument = QJsonDocument::fromJson(jsonData); - - if (Q_UNLIKELY(!setJSON(sceneDocument))) { + if (Q_UNLIKELY(!setJSON(qLoadGLTF(ioDev->readAll())))) { qCWarning(Jobs, "not a JSON document"); return false; } diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp index d27da25c7..8399bdd7c 100644 --- a/src/render/geometry/qbuffer.cpp +++ b/src/render/geometry/qbuffer.cpp @@ -58,6 +58,15 @@ QBufferPrivate::QBufferPrivate() { } +void QBufferPrivate::setData(const QByteArray &data) +{ + Q_Q(QBuffer); + const bool blocked = q->blockNotifications(true); + m_data = data; + emit q->dataChanged(data); + q->blockNotifications(blocked); +} + /*! * \qmltype Buffer * \instantiates Qt3DRender::QBuffer @@ -301,36 +310,14 @@ QBuffer::~QBuffer() } /*! - * \internal - */ -void QBuffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) -{ - if (change->type() == PropertyUpdated) { - QPropertyUpdatedChangePtr e = qSharedPointerCast<QPropertyUpdatedChange>(change); - const QByteArray propertyName = e->propertyName(); - if (propertyName == QByteArrayLiteral("data")) { - const bool blocked = blockNotifications(true); - setData(e->value().toByteArray()); - blockNotifications(blocked); - } else if (propertyName == QByteArrayLiteral("downloadedData")) { - const bool blocked = blockNotifications(true); - setData(e->value().toByteArray()); - blockNotifications(blocked); - Q_EMIT dataAvailable(); - } - } -} - -/*! * Sets \a bytes as data. */ void QBuffer::setData(const QByteArray &bytes) { Q_D(QBuffer); if (bytes != d->m_data) { - d->m_data = bytes; + d->setData(bytes); d->update(); - emit dataChanged(bytes); } } @@ -446,6 +433,13 @@ void QBuffer::setAccessType(QBuffer::AccessType access) } } +/*! \internal */ +void QBuffer::sceneChangeEvent(const QSceneChangePtr &change) +{ + // TODO Unused remove in Qt6 + Q_UNUSED(change) +} + bool QBuffer::isSyncData() const { Q_D(const QBuffer); diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h index 1bd1aa8fd..aa6ebca66 100644 --- a/src/render/geometry/qbuffer.h +++ b/src/render/geometry/qbuffer.h @@ -118,9 +118,6 @@ public Q_SLOTS: void setSyncData(bool syncData); void setAccessType(AccessType access); -protected: - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; - Q_SIGNALS: void dataChanged(const QByteArray &bytes); void typeChanged(BufferType type); @@ -129,6 +126,10 @@ Q_SIGNALS: void accessTypeChanged(AccessType access); void dataAvailable(); +protected: + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; + private: Q_DECLARE_PRIVATE(QBuffer) Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override; diff --git a/src/render/geometry/qbuffer_p.h b/src/render/geometry/qbuffer_p.h index 7a0ffdfb9..6da28e88b 100644 --- a/src/render/geometry/qbuffer_p.h +++ b/src/render/geometry/qbuffer_p.h @@ -75,6 +75,8 @@ public: QBufferDataGeneratorPtr m_functor; bool m_syncData; QBuffer::AccessType m_access; + + void setData(const QByteArray &data); }; struct QBufferData diff --git a/src/render/geometry/qgeometryrenderer.cpp b/src/render/geometry/qgeometryrenderer.cpp index 6e0a24f61..64f3e058e 100644 --- a/src/render/geometry/qgeometryrenderer.cpp +++ b/src/render/geometry/qgeometryrenderer.cpp @@ -218,6 +218,11 @@ QGeometryRenderer::QGeometryRenderer(QGeometryRendererPrivate &dd, QNode *parent { } +// TODO Unused remove in Qt6 +void QGeometryRenderer::sceneChangeEvent(const QSceneChangePtr &) +{ +} + /*! \property QGeometryRenderer::instanceCount diff --git a/src/render/geometry/qgeometryrenderer.h b/src/render/geometry/qgeometryrenderer.h index eceeb9173..14de40d0b 100644 --- a/src/render/geometry/qgeometryrenderer.h +++ b/src/render/geometry/qgeometryrenderer.h @@ -134,6 +134,8 @@ Q_SIGNALS: protected: explicit QGeometryRenderer(QGeometryRendererPrivate &dd, Qt3DCore::QNode *parent = nullptr); + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; private: Q_DECLARE_PRIVATE(QGeometryRenderer) diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp index 1d7d33f9a..1f05a71f6 100644 --- a/src/render/geometry/qmesh.cpp +++ b/src/render/geometry/qmesh.cpp @@ -148,17 +148,6 @@ void QMeshPrivate::setStatus(QMesh::Status status) */ /*! - \enum QMesh::Status - - This enum identifies the status of shader used. - - \value None A source mesh hasn't been assigned a source yet - \value Loading The mesh geometry is loading - \value Ready The mesh geometry was successfully loaded - \value Error An error occurred while loading the mesh -*/ - -/*! \qmlproperty enumeration Mesh::status Holds the status of the mesh loading. @@ -197,6 +186,17 @@ void QMeshPrivate::setStatus(QMesh::Status status) */ /*! + \enum Qt3DRender::QMesh::Status + + This enum identifies the status of shader used. + + \value None A source mesh hasn't been assigned a source yet + \value Loading The mesh geometry is loading + \value Ready The mesh geometry was successfully loaded + \value Error An error occurred while loading the mesh +*/ + +/*! * Constructs a new QMesh with \a parent. */ QMesh::QMesh(QNode *parent) @@ -215,6 +215,11 @@ QMesh::QMesh(QMeshPrivate &dd, QNode *parent) { } +// TODO Unused remove in Qt6 +void QMesh::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) +{ +} + void QMesh::setSource(const QUrl& source) { Q_D(QMesh); diff --git a/src/render/geometry/qmesh.h b/src/render/geometry/qmesh.h index 04fdedc20..e8ff52b35 100644 --- a/src/render/geometry/qmesh.h +++ b/src/render/geometry/qmesh.h @@ -88,6 +88,8 @@ Q_SIGNALS: protected: explicit QMesh(QMeshPrivate &dd, Qt3DCore::QNode *parent = nullptr); + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; private: Q_DECLARE_PRIVATE(QMesh) diff --git a/src/render/geometry/skeleton.cpp b/src/render/geometry/skeleton.cpp index 839a1a056..0452c020b 100644 --- a/src/render/geometry/skeleton.cpp +++ b/src/render/geometry/skeleton.cpp @@ -60,6 +60,8 @@ namespace Render { Skeleton::Skeleton() : BackendNode(Qt3DCore::QBackendNode::ReadWrite) , m_status(Qt3DCore::QSkeletonLoader::NotReady) + , m_createJoints(false) + , m_dataType(Unknown) , m_skeletonManager(nullptr) , m_jointManager(nullptr) { diff --git a/src/render/io/qsceneloader.cpp b/src/render/io/qsceneloader.cpp index cf1e45355..2d53702f6 100644 --- a/src/render/io/qsceneloader.cpp +++ b/src/render/io/qsceneloader.cpp @@ -41,7 +41,6 @@ #include "qsceneloader_p.h" #include <Qt3DCore/private/qscene_p.h> -#include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/qentity.h> #include <Qt3DCore/qtransform.h> #include <Qt3DRender/qgeometryrenderer.h> @@ -253,6 +252,11 @@ QSceneLoader::~QSceneLoader() { } +// TODO Unused remove in Qt6 +void QSceneLoader::sceneChangeEvent(const QSceneChangePtr &) +{ +} + /*! \internal */ QSceneLoader::QSceneLoader(QSceneLoaderPrivate &dd, QNode *parent) : Qt3DCore::QComponent(dd, parent) @@ -313,7 +317,7 @@ QStringList QSceneLoader::entityNames() const /*! \qmlmethod Entity SceneLoader::component(string entityName, enumeration componentType) - Returns a component matching \a componentType of a loaded entity with an \a objectName matching + Returns a component matching \a componentType of a loaded entity with an \e objectName matching the \a entityName. If the entity has multiple matching components, the first match in the component list of the entity is returned. diff --git a/src/render/io/qsceneloader.h b/src/render/io/qsceneloader.h index 6842a6926..51ba42de7 100644 --- a/src/render/io/qsceneloader.h +++ b/src/render/io/qsceneloader.h @@ -60,6 +60,8 @@ public: explicit QSceneLoader(Qt3DCore::QNode *parent = nullptr); ~QSceneLoader(); + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; enum Status { None = 0, Loading, diff --git a/src/render/io/scene.cpp b/src/render/io/scene.cpp index 089091701..1a2000bbb 100644 --- a/src/render/io/scene.cpp +++ b/src/render/io/scene.cpp @@ -39,7 +39,6 @@ #include "scene_p.h" #include <Qt3DCore/qentity.h> -#include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/private/qnode_p.h> #include <Qt3DCore/private/qscene_p.h> #include <Qt3DCore/private/qdownloadhelperservice_p.h> @@ -80,6 +79,9 @@ void Scene::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) m_sceneManager->addSceneData(m_source, peerId()); else m_sceneManager->startSceneDownload(m_source, peerId()); + + const auto d = static_cast<const QSceneLoaderPrivate *>(Qt3DCore::QNodePrivate::get(node)); + const_cast<QSceneLoaderPrivate *>(d)->setStatus(QSceneLoader::Loading); } markDirty(AbstractRenderer::AllDirty); } diff --git a/src/render/jobs/abstractpickingjob.cpp b/src/render/jobs/abstractpickingjob.cpp index 35e658535..092ab7d3b 100644 --- a/src/render/jobs/abstractpickingjob.cpp +++ b/src/render/jobs/abstractpickingjob.cpp @@ -63,6 +63,7 @@ AbstractPickingJob::AbstractPickingJob() , m_node(nullptr) , m_frameGraphRoot(nullptr) , m_renderSettings(nullptr) + , m_oneEnabledAtLeast(false) { } @@ -72,6 +73,7 @@ AbstractPickingJob::AbstractPickingJob(Qt3DCore::QAspectJobPrivate &dd) , m_node(nullptr) , m_frameGraphRoot(nullptr) , m_renderSettings(nullptr) + , m_oneEnabledAtLeast(false) { } diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp index 9af2f4f38..172c4ddca 100644 --- a/src/render/jobs/calcboundingvolumejob.cpp +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -354,7 +354,7 @@ CalculateBoundingVolumeJob::CalculateBoundingVolumeJob() : m_manager(nullptr) , m_node(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcBoundingVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcBoundingVolume, 0) } void CalculateBoundingVolumeJob::run() diff --git a/src/render/jobs/calcgeometrytrianglevolumes.cpp b/src/render/jobs/calcgeometrytrianglevolumes.cpp index d2b12e09c..eb31a25a6 100644 --- a/src/render/jobs/calcgeometrytrianglevolumes.cpp +++ b/src/render/jobs/calcgeometrytrianglevolumes.cpp @@ -53,7 +53,7 @@ CalcGeometryTriangleVolumes::CalcGeometryTriangleVolumes(const Qt3DCore::QNodeId , m_geometryRendererId(geometryRendererId) , m_manager(manager) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcTriangleVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcTriangleVolume, 0) } void CalcGeometryTriangleVolumes::run() diff --git a/src/render/jobs/computefilteredboundingvolumejob.cpp b/src/render/jobs/computefilteredboundingvolumejob.cpp index 02852685c..0cdbc8b6d 100644 --- a/src/render/jobs/computefilteredboundingvolumejob.cpp +++ b/src/render/jobs/computefilteredboundingvolumejob.cpp @@ -74,12 +74,25 @@ void expandWorldBoundingVolume(NodeManagers *manager, } // namespace +class ComputeFilteredBoundingVolumeJobPrivate : public Qt3DCore::QAspectJobPrivate +{ +public: + ComputeFilteredBoundingVolumeJobPrivate(ComputeFilteredBoundingVolumeJob *job) : Qt3DCore::QAspectJobPrivate(), m_job(job) {} + ~ComputeFilteredBoundingVolumeJobPrivate() {} + + void postFrame(Qt3DCore::QAspectManager *aspectManager) override; + + ComputeFilteredBoundingVolumeJob *m_job; + Qt3DRender::Render::Sphere m_sphere; +}; + ComputeFilteredBoundingVolumeJob::ComputeFilteredBoundingVolumeJob() - : m_root(nullptr) + : Qt3DCore::QAspectJob(*new ComputeFilteredBoundingVolumeJobPrivate(this)) + , m_root(nullptr) , m_ignoreSubTree(nullptr) , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0) } void ComputeFilteredBoundingVolumeJob::setRoot(Entity *root) @@ -100,11 +113,13 @@ void ComputeFilteredBoundingVolumeJob::ignoreSubTree(Entity *node) void ComputeFilteredBoundingVolumeJob::run() { qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread(); + Q_D(ComputeFilteredBoundingVolumeJob); + d->m_sphere = {}; if (!m_root) return; if (!m_ignoreSubTree) { - finished(*m_root->worldBoundingVolumeWithChildren()); + d->m_sphere = *m_root->worldBoundingVolumeWithChildren(); return; } @@ -118,20 +133,24 @@ void ComputeFilteredBoundingVolumeJob::run() parent = parent->parent(); } if (!isFilterChildOfRoot) { - finished(*m_root->worldBoundingVolumeWithChildren()); + d->m_sphere = *m_root->worldBoundingVolumeWithChildren(); return; } - Qt3DRender::Render::Sphere sphere; - expandWorldBoundingVolume(m_manager, &sphere, m_root, m_ignoreSubTree); - finished(sphere); + expandWorldBoundingVolume(m_manager, &d->m_sphere, m_root, m_ignoreSubTree); qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); } -void ComputeFilteredBoundingVolumeJob::finished(const Qt3DRender::Render::Sphere &sphere) +void ComputeFilteredBoundingVolumeJob::finished(Qt3DCore::QAspectManager *aspectManager, const Qt3DRender::Render::Sphere &sphere) +{ + Q_UNUSED(aspectManager) + Q_UNUSED(sphere) +} + +void ComputeFilteredBoundingVolumeJobPrivate::postFrame(Qt3DCore::QAspectManager *aspectManager) { - Q_UNUSED(sphere); + m_job->finished(aspectManager, m_sphere); } } // namespace Render diff --git a/src/render/jobs/computefilteredboundingvolumejob_p.h b/src/render/jobs/computefilteredboundingvolumejob_p.h index d2aca575c..0f804e647 100644 --- a/src/render/jobs/computefilteredboundingvolumejob_p.h +++ b/src/render/jobs/computefilteredboundingvolumejob_p.h @@ -64,6 +64,7 @@ namespace Render { class Entity; class NodeManagers; class Sphere; +class ComputeFilteredBoundingVolumeJobPrivate; class Q_3DRENDERSHARED_PRIVATE_EXPORT ComputeFilteredBoundingVolumeJob : public Qt3DCore::QAspectJob { @@ -76,9 +77,10 @@ public: void run() override; protected: - virtual void finished(const Qt3DRender::Render::Sphere &sphere); + virtual void finished(Qt3DCore::QAspectManager *aspectManager, const Qt3DRender::Render::Sphere &sphere); // called in main thread private: + Q_DECLARE_PRIVATE(ComputeFilteredBoundingVolumeJob) Entity *m_root; Entity *m_ignoreSubTree; NodeManagers *m_manager; diff --git a/src/render/jobs/expandboundingvolumejob.cpp b/src/render/jobs/expandboundingvolumejob.cpp index d63934b54..8587634cb 100644 --- a/src/render/jobs/expandboundingvolumejob.cpp +++ b/src/render/jobs/expandboundingvolumejob.cpp @@ -62,7 +62,7 @@ void expandWorldBoundingVolume(NodeManagers *manager, Entity *node) const auto childrenHandles = node->childrenHandles(); for (const HEntity &handle : childrenHandles) { Entity *c = manager->renderNodesManager()->data(handle); - if (c) + if (c && c->isEnabled()) expandWorldBoundingVolume(manager, c); } @@ -72,7 +72,7 @@ void expandWorldBoundingVolume(NodeManagers *manager, Entity *node) Qt3DRender::Render::Sphere *parentBoundingVolume = node->worldBoundingVolumeWithChildren(); for (const HEntity &handle : childrenHandles) { Entity *c = manager->renderNodesManager()->data(handle); - if (c) + if (c && c->isEnabled()) parentBoundingVolume->expandToContain(*c->worldBoundingVolumeWithChildren()); } } @@ -84,7 +84,7 @@ ExpandBoundingVolumeJob::ExpandBoundingVolumeJob() : m_node(nullptr) , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0) } void ExpandBoundingVolumeJob::setRoot(Entity *root) diff --git a/src/render/jobs/filterentitybycomponentjob_p.h b/src/render/jobs/filterentitybycomponentjob_p.h index dd64e50a7..cefcdd296 100644 --- a/src/render/jobs/filterentitybycomponentjob_p.h +++ b/src/render/jobs/filterentitybycomponentjob_p.h @@ -74,7 +74,7 @@ public: : Qt3DCore::QAspectJob() , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::EntityComponentTypeFiltering, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::EntityComponentTypeFiltering, 0) } inline void setManager(EntityManager *manager) Q_DECL_NOTHROW { m_manager = manager; } @@ -97,10 +97,6 @@ private: QVector<Entity *> m_filteredEntities; }; -template<typename T, typename ... Ts> -using FilterEntityByComponentJobPtr = QSharedPointer<FilterEntityByComponentJob<T, Ts...>>; - - } // Render } // Qt3DRender diff --git a/src/render/jobs/filterlayerentityjob.cpp b/src/render/jobs/filterlayerentityjob.cpp index e206ef968..032004422 100644 --- a/src/render/jobs/filterlayerentityjob.cpp +++ b/src/render/jobs/filterlayerentityjob.cpp @@ -58,7 +58,7 @@ FilterLayerEntityJob::FilterLayerEntityJob() : Qt3DCore::QAspectJob() , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LayerFiltering, layerFilterJobCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LayerFiltering, layerFilterJobCounter++) } diff --git a/src/render/jobs/filterproximitydistancejob.cpp b/src/render/jobs/filterproximitydistancejob.cpp index a25e88508..02b712fc2 100644 --- a/src/render/jobs/filterproximitydistancejob.cpp +++ b/src/render/jobs/filterproximitydistancejob.cpp @@ -43,8 +43,10 @@ namespace Render { FilterProximityDistanceJob::FilterProximityDistanceJob() : m_manager(nullptr) + , m_targetEntity(nullptr) + , m_distanceThresholdSquared(0.) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::ProximityFiltering, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::ProximityFiltering, 0) } void FilterProximityDistanceJob::run() @@ -55,9 +57,9 @@ void FilterProximityDistanceJob::run() // Fill m_filteredEntities // If no filtering needs to be done, this will be the output value // otherwise it will be used as the base list of entities to filter - selectAllEntities(); if (hasProximityFilter()) { + selectAllEntities(); QVector<Entity *> entitiesToFilter = std::move(m_filteredEntities); FrameGraphManager *frameGraphManager = m_manager->frameGraphManager(); EntityManager *entityManager = m_manager->renderNodesManager(); diff --git a/src/render/jobs/framecleanupjob.cpp b/src/render/jobs/framecleanupjob.cpp index 17ca60bff..fb63f005b 100644 --- a/src/render/jobs/framecleanupjob.cpp +++ b/src/render/jobs/framecleanupjob.cpp @@ -55,7 +55,7 @@ FrameCleanupJob::FrameCleanupJob() : m_managers(nullptr) , m_root(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrameCleanup, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrameCleanup, 0) } FrameCleanupJob::~FrameCleanupJob() diff --git a/src/render/jobs/frustumcullingjob.cpp b/src/render/jobs/frustumcullingjob.cpp index 0922fb0cb..e22d625df 100644 --- a/src/render/jobs/frustumcullingjob.cpp +++ b/src/render/jobs/frustumcullingjob.cpp @@ -58,7 +58,7 @@ FrustumCullingJob::FrustumCullingJob() , m_manager(nullptr) , m_active(false) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrustumCulling, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrustumCulling, 0) } void FrustumCullingJob::run() diff --git a/src/render/jobs/genericlambdajob_p.h b/src/render/jobs/genericlambdajob_p.h index 4d93f0f8d..8cf4276f6 100644 --- a/src/render/jobs/genericlambdajob_p.h +++ b/src/render/jobs/genericlambdajob_p.h @@ -68,7 +68,7 @@ public: : Qt3DCore::QAspectJob() , m_callable(callable) { - SET_JOB_RUN_STAT_TYPE(this, type, 0); + SET_JOB_RUN_STAT_TYPE(this, type, 0) } // QAspectJob interface @@ -111,7 +111,7 @@ public: : Qt3DCore::QAspectJob(*new GenericLambdaJobAndPostFramePrivate<T, U>(postFrameCallable)) , m_runCallable(runCallable) { - SET_JOB_RUN_STAT_TYPE(this, type, 0); + SET_JOB_RUN_STAT_TYPE(this, type, 0) } // QAspectJob interface diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h index 7aa6f64ba..c3b581277 100644 --- a/src/render/jobs/job_common_p.h +++ b/src/render/jobs/job_common_p.h @@ -80,7 +80,7 @@ namespace JobTypes { LayerFiltering, EntityComponentTypeFiltering, MaterialParameterGathering, - RenderViewBuilder, + RenderCommandUpdater, GenericLambda, FrustumCulling, LightGathering, @@ -92,9 +92,9 @@ namespace JobTypes { DirtyShaderGathering, SendRenderCapture, SendBufferCapture, - SyncRenderViewCommandBuilding, + SyncRenderViewPreCommandUpdate, SyncRenderViewInitialization, - SyncRenderViewCommandBuilder, + SyncRenderViewPostCommandUpdate, SyncFrustumCulling, ClearBufferDrawIndex, UpdateMeshTriangleList, @@ -109,7 +109,9 @@ namespace JobTypes { UpdateLayerEntity, SendTextureChangesToFrontend, SendSetFenceHandlesToFrontend, - SendDisablesToFrontend + SendDisablesToFrontend, + RenderViewCommandBuilder, + SyncRenderViewPreCommandBuilding }; } // JobTypes diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri index 2181e4a95..eb89ab35e 100644 --- a/src/render/jobs/jobs.pri +++ b/src/render/jobs/jobs.pri @@ -18,7 +18,6 @@ HEADERS += \ $$PWD/lightgatherer_p.h \ $$PWD/expandboundingvolumejob_p.h \ $$PWD/updateworldboundingvolumejob_p.h \ - $$PWD/sendrendercapturejob_p.h \ $$PWD/updateshaderdatatransformjob_p.h \ $$PWD/updatelevelofdetailjob_p.h \ $$PWD/updatemeshtrianglelistjob_p.h \ @@ -47,7 +46,6 @@ SOURCES += \ $$PWD/lightgatherer.cpp \ $$PWD/expandboundingvolumejob.cpp \ $$PWD/updateworldboundingvolumejob.cpp \ - $$PWD/sendrendercapturejob.cpp \ $$PWD/updateshaderdatatransformjob.cpp \ $$PWD/updatemeshtrianglelistjob.cpp \ $$PWD/updatelevelofdetailjob.cpp \ diff --git a/src/render/jobs/lightgatherer.cpp b/src/render/jobs/lightgatherer.cpp index b76cd4d73..b79976aef 100644 --- a/src/render/jobs/lightgatherer.cpp +++ b/src/render/jobs/lightgatherer.cpp @@ -53,11 +53,14 @@ LightGatherer::LightGatherer() , m_manager(nullptr) , m_environmentLight(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LightGathering, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LightGathering, 0) } void LightGatherer::run() { + m_lights.clear(); + m_environmentLight = nullptr; + const QVector<HEntity> handles = m_manager->activeHandles(); int envLightCount = 0; diff --git a/src/render/jobs/loadbufferjob.cpp b/src/render/jobs/loadbufferjob.cpp index 49f271df5..0f4feb5d4 100644 --- a/src/render/jobs/loadbufferjob.cpp +++ b/src/render/jobs/loadbufferjob.cpp @@ -39,9 +39,11 @@ #include "loadbufferjob_p.h" #include <Qt3DRender/private/buffer_p.h> +#include <Qt3DRender/private/qbuffer_p.h> #include <Qt3DRender/private/buffermanager_p.h> #include <Qt3DRender/private/renderer_p.h> #include <Qt3DRender/private/job_common_p.h> +#include <Qt3DCore/private/qaspectmanager_p.h> QT_BEGIN_NAMESPACE @@ -49,13 +51,24 @@ namespace Qt3DRender { namespace Render { +class LoadBufferJobPrivate : public Qt3DCore::QAspectJobPrivate +{ +public: + LoadBufferJobPrivate() {} + ~LoadBufferJobPrivate() {} + + void postFrame(Qt3DCore::QAspectManager *aspectManager) override; + + Buffer *m_bufferToUpdate = nullptr; +}; + LoadBufferJob::LoadBufferJob(const HBuffer &handle) - : QAspectJob() + : QAspectJob(*new LoadBufferJobPrivate) , m_handle(handle) , m_nodeManagers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadBuffer, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadBuffer, 0) } LoadBufferJob::~LoadBufferJob() @@ -64,10 +77,25 @@ LoadBufferJob::~LoadBufferJob() void LoadBufferJob::run() { + Q_D(LoadBufferJob); // Let's leave it for the moment until this has been properly tested qCDebug(Jobs) << Q_FUNC_INFO; Buffer *buffer = m_nodeManagers->data<Buffer, BufferManager>(m_handle); buffer->executeFunctor(); + if (buffer->isSyncData()) + d->m_bufferToUpdate = buffer; +} + +void LoadBufferJobPrivate::postFrame(Qt3DCore::QAspectManager *aspectManager) +{ + if (m_bufferToUpdate == nullptr) + return; + QBuffer *frontendBuffer = static_cast<decltype(frontendBuffer)>(aspectManager->lookupNode(m_bufferToUpdate->peerId())); + QBufferPrivate *dFrontend = static_cast<decltype(dFrontend)>(Qt3DCore::QNodePrivate::get(frontendBuffer)); + // Calling frontendBuffer->setData would result in forcing a sync against the backend + // which isn't necessary + dFrontend->setData(m_bufferToUpdate->data()); + m_bufferToUpdate = nullptr; } } // namespace Render diff --git a/src/render/jobs/loadbufferjob_p.h b/src/render/jobs/loadbufferjob_p.h index 6a221c7e0..e86e4f835 100644 --- a/src/render/jobs/loadbufferjob_p.h +++ b/src/render/jobs/loadbufferjob_p.h @@ -63,6 +63,7 @@ namespace Qt3DRender { namespace Render { class NodeManagers; +class LoadBufferJobPrivate; class Q_AUTOTEST_EXPORT LoadBufferJob : public Qt3DCore::QAspectJob { @@ -76,6 +77,9 @@ public: protected: HBuffer m_handle; NodeManagers *m_nodeManagers; + +private: + Q_DECLARE_PRIVATE(LoadBufferJob) }; typedef QSharedPointer<LoadBufferJob> LoadBufferJobPtr; diff --git a/src/render/jobs/loadgeometryjob.cpp b/src/render/jobs/loadgeometryjob.cpp index 88930038a..2069336cd 100644 --- a/src/render/jobs/loadgeometryjob.cpp +++ b/src/render/jobs/loadgeometryjob.cpp @@ -66,7 +66,7 @@ LoadGeometryJob::LoadGeometryJob(const HGeometryRenderer &handle) , m_handle(handle) , m_nodeManagers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadGeometry, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadGeometry, 0) } LoadGeometryJob::~LoadGeometryJob() diff --git a/src/render/jobs/loadscenejob.cpp b/src/render/jobs/loadscenejob.cpp index f858f82e3..be855c608 100644 --- a/src/render/jobs/loadscenejob.cpp +++ b/src/render/jobs/loadscenejob.cpp @@ -63,7 +63,7 @@ LoadSceneJob::LoadSceneJob(const QUrl &source, Qt3DCore::QNodeId sceneComponent) , m_sceneComponent(sceneComponent) , m_managers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadScene, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadScene, 0) } void LoadSceneJob::setData(const QByteArray &data) diff --git a/src/render/jobs/loadskeletonjob.cpp b/src/render/jobs/loadskeletonjob.cpp index 8d0d47fb9..e696cc434 100644 --- a/src/render/jobs/loadskeletonjob.cpp +++ b/src/render/jobs/loadskeletonjob.cpp @@ -288,7 +288,7 @@ void LoadSkeletonJobPrivate::postFrame(Qt3DCore::QAspectManager *manager) dloaderNode->setStatus(m_backendSkeleton->status()); if (m_loadedRootJoint) { - dloaderNode->m_rootJoint = m_loadedRootJoint; + dloaderNode->setRootJoint(m_loadedRootJoint); m_loadedRootJoint = nullptr; } } diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp index 8683ea9f2..2ccb72337 100644 --- a/src/render/jobs/sendbuffercapturejob.cpp +++ b/src/render/jobs/sendbuffercapturejob.cpp @@ -39,11 +39,12 @@ #include "sendbuffercapturejob_p.h" - -#include "Qt3DRender/private/renderer_p.h" -#include "Qt3DRender/private/nodemanagers_p.h" +#include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/job_common_p.h> #include <Qt3DRender/private/buffer_p.h> +#include <Qt3DRender/private/buffermanager_p.h> +#include <Qt3DCore/private/qaspectmanager_p.h> +#include <Qt3DRender/private/qbuffer_p.h> QT_BEGIN_NAMESPACE @@ -51,36 +52,75 @@ namespace Qt3DRender { namespace Render { +class SendBufferCaptureJobPrivate : public Qt3DCore::QAspectJobPrivate +{ +public: + SendBufferCaptureJobPrivate() {} + ~SendBufferCaptureJobPrivate() {} + + void postFrame(Qt3DCore::QAspectManager *aspectManager) override; + + mutable QMutex m_mutex; + QVector<QPair<Qt3DCore::QNodeId, QByteArray>> m_buffersToCapture; + QVector<QPair<Qt3DCore::QNodeId, QByteArray>> m_buffersToNotify; +}; + SendBufferCaptureJob::SendBufferCaptureJob() - : Qt3DCore::QAspectJob() + : Qt3DCore::QAspectJob(*new SendBufferCaptureJobPrivate) + , m_nodeManagers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0) } SendBufferCaptureJob::~SendBufferCaptureJob() { } -void SendBufferCaptureJob::addRequest(QPair<Buffer *, QByteArray> request) +// Called from SubmitRenderView while rendering +void SendBufferCaptureJob::addRequest(QPair<Qt3DCore::QNodeId, QByteArray> request) { - QMutexLocker locker(&m_mutex); - m_pendingSendBufferCaptures.push_back(request); + Q_D(SendBufferCaptureJob); + QMutexLocker locker(&d->m_mutex); + d->m_buffersToCapture.push_back(request); } -// Called by aspect thread jobs to execute (no concurrency at that point) +// Called by aspect thread jobs to execute (we may still be rendering at this point) bool SendBufferCaptureJob::hasRequests() const { - return m_pendingSendBufferCaptures.size() > 0; + Q_D(const SendBufferCaptureJob); + QMutexLocker locker(&d->m_mutex); + return d->m_buffersToCapture.size() > 0; } void SendBufferCaptureJob::run() { - QMutexLocker locker(&m_mutex); - for (const QPair<Buffer*, QByteArray> &pendingCapture : qAsConst(m_pendingSendBufferCaptures)) { - pendingCapture.first->updateDataFromGPUToCPU(pendingCapture.second); + Q_ASSERT(m_nodeManagers); + Q_D(SendBufferCaptureJob); + QMutexLocker locker(&d->m_mutex); + for (const QPair<Qt3DCore::QNodeId, QByteArray> &pendingCapture : qAsConst(d->m_buffersToCapture)) { + Buffer *buffer = m_nodeManagers->bufferManager()->lookupResource(pendingCapture.first); + // Buffer might have been destroyed between the time addRequest is made and this job gets run + // If it exists however, it cannot be destroyed before this job is done running + if (buffer != nullptr) + buffer->updateDataFromGPUToCPU(pendingCapture.second); } + d->m_buffersToNotify = std::move(d->m_buffersToCapture); +} - m_pendingSendBufferCaptures.clear(); +void SendBufferCaptureJobPrivate::postFrame(Qt3DCore::QAspectManager *aspectManager) +{ + QMutexLocker locker(&m_mutex); + const QVector<QPair<Qt3DCore::QNodeId, QByteArray>> pendingSendBufferCaptures = std::move(m_buffersToNotify); + for (const auto &bufferDataPair : pendingSendBufferCaptures) { + QBuffer *frontendBuffer = static_cast<decltype(frontendBuffer)>(aspectManager->lookupNode(bufferDataPair.first)); + if (!frontendBuffer) + continue; + QBufferPrivate *dFrontend = static_cast<decltype(dFrontend)>(Qt3DCore::QNodePrivate::get(frontendBuffer)); + // Calling frontendBuffer->setData would result in forcing a sync against the backend + // which isn't necessary + dFrontend->setData(bufferDataPair.second); + Q_EMIT frontendBuffer->dataAvailable(); + } } } // Render diff --git a/src/render/jobs/sendbuffercapturejob_p.h b/src/render/jobs/sendbuffercapturejob_p.h index f47c556df..3b9f5d12b 100644 --- a/src/render/jobs/sendbuffercapturejob_p.h +++ b/src/render/jobs/sendbuffercapturejob_p.h @@ -52,6 +52,7 @@ // #include <Qt3DCore/qaspectjob.h> +#include <Qt3DCore/qnodeid.h> #include <Qt3DRender/qt3drender_global.h> #include <Qt3DRender/private/qt3drender_global_p.h> #include <QMutex> @@ -67,6 +68,7 @@ class NodeManagers; class Entity; class Renderer; class Buffer; +class SendBufferCaptureJobPrivate; class Q_3DRENDERSHARED_PRIVATE_EXPORT SendBufferCaptureJob : public Qt3DCore::QAspectJob { @@ -74,15 +76,15 @@ public: explicit SendBufferCaptureJob(); ~SendBufferCaptureJob(); - void addRequest(QPair<Buffer*, QByteArray> request); + void setManagers(NodeManagers *nodeManagers) { m_nodeManagers = nodeManagers; } + void addRequest(QPair<Qt3DCore::QNodeId, QByteArray> request); bool hasRequests() const; void run() final; private: - QMutex m_mutex; - - QVector<QPair<Buffer*, QByteArray> > m_pendingSendBufferCaptures; + Q_DECLARE_PRIVATE(SendBufferCaptureJob) + NodeManagers *m_nodeManagers; }; typedef QSharedPointer<SendBufferCaptureJob> SendBufferCaptureJobPtr; diff --git a/src/render/jobs/sendrendercapturejob.cpp b/src/render/jobs/sendrendercapturejob.cpp deleted file mode 100644 index f622c347a..000000000 --- a/src/render/jobs/sendrendercapturejob.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "sendrendercapturejob_p.h" - -#include "Qt3DRender/private/renderer_p.h" -#include "Qt3DRender/private/nodemanagers_p.h" -#include "Qt3DRender/private/rendercapture_p.h" -#include <Qt3DRender/private/job_common_p.h> - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - -SendRenderCaptureJob::SendRenderCaptureJob() - : Qt3DCore::QAspectJob() - , m_managers(nullptr) -{ - SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendRenderCapture, 0); -} - -SendRenderCaptureJob::~SendRenderCaptureJob() -{ - -} - -void SendRenderCaptureJob::setPendingCaptureRequests(const QVector<Qt3DCore::QNodeId> &requests) -{ - m_pendingCaptures = requests; -} - -void SendRenderCaptureJob::setManagers(NodeManagers *managers) -{ - m_managers = managers; -} - -void SendRenderCaptureJob::run() -{ - for (const Qt3DCore::QNodeId id : qAsConst(m_pendingCaptures)) { - auto *node = static_cast<Qt3DRender::Render::RenderCapture *> - (m_managers->frameGraphManager()->lookupNode(id)); - node->sendRenderCaptures(); - } - m_pendingCaptures.clear(); -} - -} // Render - -} // Qt3DRender - -QT_END_NAMESPACE diff --git a/src/render/jobs/sendrendercapturejob_p.h b/src/render/jobs/sendrendercapturejob_p.h deleted file mode 100644 index 8bc1e2fb0..000000000 --- a/src/render/jobs/sendrendercapturejob_p.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SENDRENDERCAPTUREJOB_P_H -#define SENDRENDERCAPTUREJOB_P_H - - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <Qt3DCore/qaspectjob.h> -#include <Qt3DCore/qnodeid.h> -#include <Qt3DRender/qt3drender_global.h> -#include <Qt3DRender/private/qt3drender_global_p.h> - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -namespace Render { - -class NodeManagers; -class Entity; - -class Q_3DRENDERSHARED_PRIVATE_EXPORT SendRenderCaptureJob : public Qt3DCore::QAspectJob -{ -public: - SendRenderCaptureJob(); - ~SendRenderCaptureJob(); - - void setPendingCaptureRequests(const QVector<Qt3DCore::QNodeId> &requests); - void setManagers(NodeManagers *managers); - - void run() final; - -private: - NodeManagers *m_managers; - QVector<Qt3DCore::QNodeId> m_pendingCaptures; -}; - -typedef QSharedPointer<SendRenderCaptureJob> SendRenderCaptureJobPtr; - -} // namespace Render - -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // SENDRENDERCAPTUREJOB_P_H diff --git a/src/render/jobs/updateentitylayersjob.cpp b/src/render/jobs/updateentitylayersjob.cpp index 2c5e38364..b8c50c179 100644 --- a/src/render/jobs/updateentitylayersjob.cpp +++ b/src/render/jobs/updateentitylayersjob.cpp @@ -52,7 +52,7 @@ namespace Render { UpdateEntityLayersJob::UpdateEntityLayersJob() : m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateLayerEntity, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateLayerEntity, 0) } diff --git a/src/render/jobs/updatemeshtrianglelistjob.cpp b/src/render/jobs/updatemeshtrianglelistjob.cpp index 1c61d1c90..4837dcad6 100644 --- a/src/render/jobs/updatemeshtrianglelistjob.cpp +++ b/src/render/jobs/updatemeshtrianglelistjob.cpp @@ -60,7 +60,7 @@ namespace Render { UpdateMeshTriangleListJob::UpdateMeshTriangleListJob() : m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateMeshTriangleList, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateMeshTriangleList, 0) } UpdateMeshTriangleListJob::~UpdateMeshTriangleListJob() diff --git a/src/render/jobs/updateshaderdatatransformjob.cpp b/src/render/jobs/updateshaderdatatransformjob.cpp index c29a827e3..11fe91932 100644 --- a/src/render/jobs/updateshaderdatatransformjob.cpp +++ b/src/render/jobs/updateshaderdatatransformjob.cpp @@ -61,7 +61,7 @@ namespace Render { UpdateShaderDataTransformJob::UpdateShaderDataTransformJob() : m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateShaderDataTransform, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateShaderDataTransform, 0) } UpdateShaderDataTransformJob::~UpdateShaderDataTransformJob() diff --git a/src/render/jobs/updateskinningpalettejob.cpp b/src/render/jobs/updateskinningpalettejob.cpp index 0f5d3d6d6..b77707f15 100644 --- a/src/render/jobs/updateskinningpalettejob.cpp +++ b/src/render/jobs/updateskinningpalettejob.cpp @@ -50,7 +50,7 @@ UpdateSkinningPaletteJob::UpdateSkinningPaletteJob() , m_nodeManagers(nullptr) , m_root() { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateSkinningPalette, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateSkinningPalette, 0) } UpdateSkinningPaletteJob::~UpdateSkinningPaletteJob() diff --git a/src/render/jobs/updatetreeenabledjob.cpp b/src/render/jobs/updatetreeenabledjob.cpp index e97fc6414..22d6f6083 100644 --- a/src/render/jobs/updatetreeenabledjob.cpp +++ b/src/render/jobs/updatetreeenabledjob.cpp @@ -71,8 +71,9 @@ void updateTreeEnabled(NodeManagers *manager, Entity *node, bool parentEnabled) UpdateTreeEnabledJob::UpdateTreeEnabledJob() : Qt3DCore::QAspectJob() , m_node(nullptr) + , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTreeEnabled, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTreeEnabled, 0) } void UpdateTreeEnabledJob::setRoot(Entity *root) diff --git a/src/render/jobs/updateworldboundingvolumejob.cpp b/src/render/jobs/updateworldboundingvolumejob.cpp index 40dd919bc..65a3ec75d 100644 --- a/src/render/jobs/updateworldboundingvolumejob.cpp +++ b/src/render/jobs/updateworldboundingvolumejob.cpp @@ -52,7 +52,7 @@ UpdateWorldBoundingVolumeJob::UpdateWorldBoundingVolumeJob() : Qt3DCore::QAspectJob() , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateWorldBoundingVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateWorldBoundingVolume, 0) } void UpdateWorldBoundingVolumeJob::run() @@ -61,6 +61,8 @@ void UpdateWorldBoundingVolumeJob::run() for (const HEntity &handle : handles) { Entity *node = m_manager->data(handle); + if (!node->isEnabled()) + continue; *(node->worldBoundingVolume()) = node->localBoundingVolume()->transformed(*(node->worldTransform())); *(node->worldBoundingVolumeWithChildren()) = *(node->worldBoundingVolume()); // expanded in UpdateBoundingVolumeJob } diff --git a/src/render/jobs/updateworldtransformjob.cpp b/src/render/jobs/updateworldtransformjob.cpp index 13e14442f..e3c8077f4 100644 --- a/src/render/jobs/updateworldtransformjob.cpp +++ b/src/render/jobs/updateworldtransformjob.cpp @@ -65,11 +65,13 @@ struct TransformUpdate QMatrix4x4 worldTransformMatrix; }; -QVector<TransformUpdate> updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform) +void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform, QVector<TransformUpdate> &updatedTransforms) { + if (!node->isEnabled()) + return; + Matrix4x4 worldTransform(parentTransform); Transform *nodeTransform = node->renderComponent<Transform>(); - QVector<TransformUpdate> updatedTransforms; const bool hasTransformComponent = nodeTransform != nullptr && nodeTransform->isEnabled(); if (hasTransformComponent) @@ -85,9 +87,8 @@ QVector<TransformUpdate> updateWorldTransformAndBounds(NodeManagers *manager, En for (const HEntity &handle : childrenHandles) { Entity *child = manager->renderNodesManager()->data(handle); if (child) - updatedTransforms += updateWorldTransformAndBounds(manager, child, worldTransform); + updateWorldTransformAndBounds(manager, child, worldTransform, updatedTransforms); } - return updatedTransforms; } } @@ -108,7 +109,7 @@ UpdateWorldTransformJob::UpdateWorldTransformJob() , m_node(nullptr) , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTransform, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTransform, 0) } void UpdateWorldTransformJob::setRoot(Entity *root) @@ -137,7 +138,7 @@ void UpdateWorldTransformJob::run() Entity *parent = m_node->parent(); if (parent != nullptr) parentTransform = *(parent->worldTransform()); - d->m_updatedTransforms = updateWorldTransformAndBounds(m_manager, m_node, parentTransform); + updateWorldTransformAndBounds(m_manager, m_node, parentTransform, d->m_updatedTransforms); qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); } diff --git a/src/render/lights/qdirectionallight.cpp b/src/render/lights/qdirectionallight.cpp index 13fb78843..51827b644 100644 --- a/src/render/lights/qdirectionallight.cpp +++ b/src/render/lights/qdirectionallight.cpp @@ -115,12 +115,18 @@ QDirectionalLight::QDirectionalLight(QDirectionalLightPrivate &dd, QNode *parent /*! \qmlproperty vector3d Qt3D.Render::DirectionalLight::worldDirection - Specifies the world direction of the directional light + Specifies the world direction of the directional light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QDirectionalLight::worldDirection - Specifies the world direction of the directional light + Specifies the world direction of the directional light. + + \note The exact meaning and use of this property is up to the + material implementation. */ void QDirectionalLight::setWorldDirection(const QVector3D &direction) { diff --git a/src/render/lights/qenvironmentlight.cpp b/src/render/lights/qenvironmentlight.cpp index 86ef04f95..977e117db 100644 --- a/src/render/lights/qenvironmentlight.cpp +++ b/src/render/lights/qenvironmentlight.cpp @@ -158,6 +158,9 @@ QEnvironmentLight::~QEnvironmentLight() Holds the current environment irradiance map texture. By default, the environment irradiance texture is null. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! @@ -166,6 +169,9 @@ QEnvironmentLight::~QEnvironmentLight() Holds the current environment irradiance map texture. By default, the environment irradiance texture is null. + + \note The exact meaning and use of this property is up to the + material implementation. */ QAbstractTexture *QEnvironmentLight::irradiance() const { @@ -179,6 +185,9 @@ QAbstractTexture *QEnvironmentLight::irradiance() const Holds the current environment specular map texture. By default, the environment specular texture is null. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! @@ -187,6 +196,9 @@ QAbstractTexture *QEnvironmentLight::irradiance() const Holds the current environment specular map texture. By default, the environment specular texture is null. + + \note The exact meaning and use of this property is up to the + material implementation. */ QAbstractTexture *QEnvironmentLight::specular() const { diff --git a/src/render/lights/qpointlight.cpp b/src/render/lights/qpointlight.cpp index 2b042c91d..c16291709 100644 --- a/src/render/lights/qpointlight.cpp +++ b/src/render/lights/qpointlight.cpp @@ -135,12 +135,18 @@ QPointLight::QPointLight(QPointLightPrivate &dd, QNode *parent) /*! \qmlproperty float Qt3D.Render::PointLight::constantAttenuation - Specifies the constant attenuation of the point light + Specifies the constant attenuation of the point light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QPointLight::constantAttenuation - Specifies the constant attenuation of the point light + Specifies the constant attenuation of the point light. + + \note The exact meaning and use of this property is up to the + material implementation. */ float QPointLight::constantAttenuation() const { @@ -159,12 +165,18 @@ void QPointLight::setConstantAttenuation(float value) /*! \qmlproperty float Qt3D.Render::PointLight::linearAttenuation - Specifies the linear attenuation of the point light + Specifies the linear attenuation of the point light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QPointLight::linearAttenuation - Specifies the linear attenuation of the point light + Specifies the linear attenuation of the point light. + + \note The exact meaning and use of this property is up to the + material implementation. */ float QPointLight::linearAttenuation() const { @@ -183,12 +195,18 @@ void QPointLight::setLinearAttenuation(float value) /*! \qmlproperty float Qt3D.Render::PointLight::quadraticAttenuation - Specifies the quadratic attenuation of the point light + Specifies the quadratic attenuation of the point light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QPointLight::quadraticAttenuation - Specifies the quadratic attenuation of the point light + Specifies the quadratic attenuation of the point light. + + \note The exact meaning and use of this property is up to the + material implementation. */ float QPointLight::quadraticAttenuation() const { diff --git a/src/render/lights/qspotlight.cpp b/src/render/lights/qspotlight.cpp index eddafbe61..c725a6baf 100644 --- a/src/render/lights/qspotlight.cpp +++ b/src/render/lights/qspotlight.cpp @@ -140,12 +140,18 @@ QSpotLight::QSpotLight(QSpotLightPrivate &dd, QNode *parent) /*! \qmlproperty float Qt3D.Render::SpotLight::constantAttenuation - Specifies the constant attenuation of the spot light + Specifies the constant attenuation of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QSpotLight::constantAttenuation - Specifies the constant attenuation of the spot light + Specifies the constant attenuation of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ float QSpotLight::constantAttenuation() const { @@ -164,12 +170,18 @@ void QSpotLight::setConstantAttenuation(float value) /*! \qmlproperty float Qt3D.Render::SpotLight::linearAttenuation - Specifies the linear attenuation of the spot light + Specifies the linear attenuation of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QSpotLight::linearAttenuation - Specifies the linear attenuation of the spot light + Specifies the linear attenuation of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ float QSpotLight::linearAttenuation() const { @@ -188,12 +200,18 @@ void QSpotLight::setLinearAttenuation(float value) /*! \qmlproperty float Qt3D.Render::SpotLight::quadraticAttenuation - Specifies the quadratic attenuation of the spot light + Specifies the quadratic attenuation of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QSpotLight::quadraticAttenuation - Specifies the quadratic attenuation of the spot light + Specifies the quadratic attenuation of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ float QSpotLight::quadraticAttenuation() const { @@ -212,12 +230,18 @@ void QSpotLight::setQuadraticAttenuation(float value) /*! \qmlproperty vector3d Qt3D.Render::SpotLight::localDirection - Specifies the local direction of the spot light + Specifies the local direction of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QSpotLight::localDirection - Specifies the local direction of the spot light + Specifies the local direction of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ QVector3D QSpotLight::localDirection() const { @@ -227,12 +251,18 @@ QVector3D QSpotLight::localDirection() const /*! \qmlproperty float Qt3D.Render::SpotLight::cutOffAngle - Specifies the cut off angle of the spot light + Specifies the cut off angle of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ /*! \property Qt3DRender::QSpotLight::cutOffAngle - Specifies the cut off angle of the spot light + Specifies the cut off angle of the spot light. + + \note The exact meaning and use of this property is up to the + material implementation. */ float QSpotLight::cutOffAngle() const { diff --git a/src/render/materialsystem/qshaderimage.cpp b/src/render/materialsystem/qshaderimage.cpp index f2ce04c3d..508cf44f2 100644 --- a/src/render/materialsystem/qshaderimage.cpp +++ b/src/render/materialsystem/qshaderimage.cpp @@ -342,7 +342,7 @@ QShaderImagePrivate::~QShaderImagePrivate() */ /*! - \qmlproperty Qt3DRender::QShaderImage::mipLevel + \qmlproperty int Qt3D.Render::ShaderImage::mipLevel Holds which mipLevel out of the referenced texture should be used for the ShaderImage. @@ -351,7 +351,7 @@ QShaderImagePrivate::~QShaderImagePrivate() */ /*! - \qmlproperty Qt3DRender::QShaderImage::layer + \qmlproperty int Qt3D.Render::ShaderImage::layer Holds which layer out of the referenced texture should be used for the ShaderImage. This property does nothing if \a layered is set to true or if @@ -365,11 +365,11 @@ QShaderImagePrivate::~QShaderImagePrivate() cubeMapFace = layer - (cubeMapLayer * 6) \endcode - \default 0 + Default value is 0. */ /*! - * \qmlproperty Qt3DRender::QShaderImage::layered + * \qmlproperty bool Qt3D.Render::ShaderImage::layered If set to true, if the referenced texture is a one-dimensional array, two-dimensional array, three-dimensional, cube map, cube map array, or @@ -377,21 +377,28 @@ QShaderImagePrivate::~QShaderImagePrivate() for all layers. If set to false, only the single layer specified by the \a layer property will be bound. - \default false + Default value is \c false. */ /*! - \qmlproperty Qt3DRender::QShaderImage::access + \qmlproperty enumeration Qt3D.Render::ShaderImage::access Specifies the type of access we want to allow from our shader instances to the image. If a shader tries to write or read from an image that has incompatible access, the behavior is undefined. - \default ShaderImage.ReadWrite + \value ShaderImage.ReadOnly + Read-only access. + \value ShaderImage.WriteOnly + Write-only access. + \value ShaderImage.ReadWrite + Read-write access. + + Default value is ShaderImage.ReadWrite. */ /*! - \qmlproperty Qt3DRender::QShaderImage::format + \qmlproperty enumeration Qt3D.Render::ShaderImage::format Specifies the image format, which is essentially important when storing values in the ShaderImage from a shader. @@ -407,7 +414,7 @@ QShaderImagePrivate::~QShaderImagePrivate() By default Qt3D will try to set the image format to match that of the referenced texture. - \default ShaderImage.Automatic + Default value is ShaderImage.Automatic. */ /*! diff --git a/src/render/materialsystem/qshaderprogrambuilder.cpp b/src/render/materialsystem/qshaderprogrambuilder.cpp index 6613661d1..7f98fbf5e 100644 --- a/src/render/materialsystem/qshaderprogrambuilder.cpp +++ b/src/render/materialsystem/qshaderprogrambuilder.cpp @@ -135,6 +135,11 @@ QShaderProgramBuilder::QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, Q { } +// TODO Unused remove in Qt6 +void QShaderProgramBuilder::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) +{ +} + /*! \qmlproperty string ShaderProgramBuilder::shaderProgram diff --git a/src/render/materialsystem/qshaderprogrambuilder.h b/src/render/materialsystem/qshaderprogrambuilder.h index 5dc6b54ff..48e189c8c 100644 --- a/src/render/materialsystem/qshaderprogrambuilder.h +++ b/src/render/materialsystem/qshaderprogrambuilder.h @@ -117,6 +117,8 @@ Q_SIGNALS: protected: explicit QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, Qt3DCore::QNode *parent = nullptr); + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; private: Q_DECLARE_PRIVATE(QShaderProgramBuilder) diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp index 58709b37e..0d4b5edba 100644 --- a/src/render/materialsystem/shader.cpp +++ b/src/render/materialsystem/shader.cpp @@ -57,11 +57,35 @@ using namespace Qt3DCore; namespace Qt3DRender { namespace Render { +const int Shader::modelMatrixNameId = StringToInt::lookupId(QLatin1String("modelMatrix")); +const int Shader::viewMatrixNameId = StringToInt::lookupId(QLatin1String("viewMatrix")); +const int Shader::projectionMatrixNameId = StringToInt::lookupId(QLatin1String("projectionMatrix")); +const int Shader::modelViewMatrixNameId = StringToInt::lookupId(QLatin1String("modelView")); +const int Shader::viewProjectionMatrixNameId = StringToInt::lookupId(QLatin1String("viewProjectionMatrix")); +const int Shader::modelViewProjectionNameId = StringToInt::lookupId(QLatin1String("modelViewProjection")); +const int Shader::mvpNameId = StringToInt::lookupId(QLatin1String("mvp")); +const int Shader::inverseModelMatrixNameId = StringToInt::lookupId(QLatin1String("inverseModelMatrix")); +const int Shader::inverseViewMatrixNameId = StringToInt::lookupId(QLatin1String("inverseViewMatrix")); +const int Shader::inverseProjectionMatrixNameId = StringToInt::lookupId(QLatin1String("inverseProjectionMatrix")); +const int Shader::inverseModelViewNameId = StringToInt::lookupId(QLatin1String("inverseModelView")); +const int Shader::inverseViewProjectionMatrixNameId = StringToInt::lookupId(QLatin1String("inverseViewProjectionMatrix")); +const int Shader::inverseModelViewProjectionNameId = StringToInt::lookupId(QLatin1String("inverseModelViewProjection")); +const int Shader::modelNormalMatrixNameId = StringToInt::lookupId(QLatin1String("modelNormalMatrix")); +const int Shader::modelViewNormalNameId = StringToInt::lookupId(QLatin1String("modelViewNormal")); +const int Shader::viewportMatrixNameId = StringToInt::lookupId(QLatin1String("viewportMatrix")); +const int Shader::inverseViewportMatrixNameId = StringToInt::lookupId(QLatin1String("inverseViewportMatrix")); +const int Shader::aspectRatioNameId = StringToInt::lookupId(QLatin1String("aspectRatio")); +const int Shader::exposureNameId = StringToInt::lookupId(QLatin1String("exposure")); +const int Shader::gammaNameId = StringToInt::lookupId(QLatin1String("gamma")); +const int Shader::timeNameId = StringToInt::lookupId(QLatin1String("time")); +const int Shader::eyePositionNameId = StringToInt::lookupId(QLatin1String("eyePosition")); +const int Shader::skinningPaletteNameId = StringToInt::lookupId(QLatin1String("skinningPalette[0]")); Shader::Shader() : BackendNode(ReadWrite) , m_isLoaded(false) , m_dna(0) + , m_oldDna(0) , m_graphicsContext(nullptr) , m_status(QShaderProgram::NotReady) , m_requiresFrontendSync(false) @@ -243,13 +267,13 @@ void Shader::prepareUniforms(ShaderParameterPack &pack) { const PackUniformHash &values = pack.uniforms(); - auto it = values.cbegin(); - const auto end = values.cend(); + auto it = values.keys.cbegin(); + const auto end = values.keys.cend(); while (it != end) { // Find if there's a uniform with the same name id for (const ShaderUniform &uniform : qAsConst(m_uniforms)) { - if (uniform.m_nameId == it.key()) { + if (uniform.m_nameId == *it) { pack.setSubmissionUniform(uniform); break; } @@ -307,13 +331,47 @@ void Shader::initializeUniforms(const QVector<ShaderUniform> &uniformsDescriptio { m_uniforms = uniformsDescription; m_uniformsNames.resize(uniformsDescription.size()); - m_uniformsNamesIds.resize(uniformsDescription.size()); + m_uniformsNamesIds.reserve(uniformsDescription.size()); + m_standardUniformNamesIds.reserve(5); QHash<QString, ShaderUniform> activeUniformsInDefaultBlock; + static const QVector<int> standardUniformNameIds = { + modelMatrixNameId, + viewMatrixNameId, + projectionMatrixNameId, + modelViewMatrixNameId, + viewProjectionMatrixNameId, + modelViewProjectionNameId, + mvpNameId, + inverseModelMatrixNameId, + inverseViewMatrixNameId, + inverseProjectionMatrixNameId, + inverseModelViewNameId, + inverseViewProjectionMatrixNameId, + inverseModelViewProjectionNameId, + modelNormalMatrixNameId, + modelViewNormalNameId, + viewportMatrixNameId, + inverseViewportMatrixNameId, + aspectRatioNameId, + exposureNameId, + gammaNameId, + timeNameId, + eyePositionNameId, + skinningPaletteNameId, + }; + for (int i = 0, m = uniformsDescription.size(); i < m; i++) { m_uniformsNames[i] = m_uniforms[i].m_name; - m_uniforms[i].m_nameId = StringToInt::lookupId(m_uniformsNames[i]); - m_uniformsNamesIds[i] = m_uniforms[i].m_nameId; + const int nameId = StringToInt::lookupId(m_uniformsNames[i]); + m_uniforms[i].m_nameId = nameId; + + // Is the uniform a Qt3D "Standard" uniform or a user defined one? + if (standardUniformNameIds.contains(nameId)) + m_standardUniformNamesIds.push_back(nameId); + else + m_uniformsNamesIds.push_back(nameId); + if (uniformsDescription[i].m_blockIndex == -1) { // Uniform is in default block qCDebug(Shaders) << "Active Uniform in Default Block " << uniformsDescription[i].m_name << uniformsDescription[i].m_blockIndex; activeUniformsInDefaultBlock.insert(uniformsDescription[i].m_name, uniformsDescription[i]); @@ -393,6 +451,7 @@ void Shader::initializeFromReference(const Shader &other) { Q_ASSERT(m_dna == other.m_dna); m_uniformsNamesIds = other.m_uniformsNamesIds; + m_standardUniformNamesIds = other.m_standardUniformNamesIds; m_uniformsNames = other.m_uniformsNames; m_uniforms = other.m_uniforms; m_attributesNames = other.m_attributesNames; diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h index 1c9731e50..4c5bc5ea1 100644 --- a/src/render/materialsystem/shader_p.h +++ b/src/render/materialsystem/shader_p.h @@ -75,6 +75,30 @@ typedef uint ProgramDNA; class Q_AUTOTEST_EXPORT Shader : public BackendNode { public: + static const int modelMatrixNameId; + static const int viewMatrixNameId; + static const int projectionMatrixNameId; + static const int modelViewMatrixNameId; + static const int viewProjectionMatrixNameId; + static const int modelViewProjectionNameId; + static const int mvpNameId; + static const int inverseModelMatrixNameId; + static const int inverseViewMatrixNameId; + static const int inverseProjectionMatrixNameId; + static const int inverseModelViewNameId; + static const int inverseViewProjectionMatrixNameId; + static const int inverseModelViewProjectionNameId; + static const int modelNormalMatrixNameId; + static const int modelViewNormalNameId; + static const int viewportMatrixNameId; + static const int inverseViewportMatrixNameId; + static const int aspectRatioNameId; + static const int exposureNameId; + static const int gammaNameId; + static const int timeNameId; + static const int eyePositionNameId; + static const int skinningPaletteNameId; + Shader(); ~Shader(); @@ -88,6 +112,7 @@ public: const QHash<QString, int> fragOutputs() const; inline QVector<int> uniformsNamesIds() const { return m_uniformsNamesIds; } + inline QVector<int> standardUniformNameIds() const { return m_standardUniformNamesIds; } inline QVector<int> uniformBlockNamesIds() const { return m_uniformBlockNamesIds; } inline QVector<int> storageBlockNamesIds() const { return m_shaderStorageBlockNamesIds; } inline QVector<int> attributeNamesIds() const { return m_attributeNamesIds; } @@ -128,6 +153,7 @@ public: private: QVector<QString> m_uniformsNames; QVector<int> m_uniformsNamesIds; + QVector<int> m_standardUniformNamesIds; QVector<ShaderUniform> m_uniforms; QVector<QString> m_attributesNames; diff --git a/src/render/picking/qabstractraycaster.cpp b/src/render/picking/qabstractraycaster.cpp index ab0916401..5f4c4c490 100644 --- a/src/render/picking/qabstractraycaster.cpp +++ b/src/render/picking/qabstractraycaster.cpp @@ -58,10 +58,6 @@ QAbstractRayCasterPrivate::QAbstractRayCasterPrivate() m_shareable = false; } -/*! - \property Qt3DRender::QAbstractRayCaster::Hits -*/ - QAbstractRayCasterPrivate *QAbstractRayCasterPrivate::get(QAbstractRayCaster *obj) { return obj->d_func(); diff --git a/src/render/picking/qobjectpicker.cpp b/src/render/picking/qobjectpicker.cpp index 7d9741f21..4f039b361 100644 --- a/src/render/picking/qobjectpicker.cpp +++ b/src/render/picking/qobjectpicker.cpp @@ -152,7 +152,7 @@ namespace Qt3DRender { This signal is emitted when the bounding volume defined by the pickAttribute property intersects with a ray on a mouse click. Intersection - information are accessible through the pick \a parameter. + information are accessible through the \a pick parameter. */ /*! @@ -292,6 +292,11 @@ void QObjectPicker::setPriority(int priority) } } +// TODO Unused remove in Qt6 +void QObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) +{ +} + /*! \qmlproperty bool Qt3D.Render::ObjectPicker::dragEnabled */ diff --git a/src/render/picking/qobjectpicker.h b/src/render/picking/qobjectpicker.h index ee63c9418..ea65040ba 100644 --- a/src/render/picking/qobjectpicker.h +++ b/src/render/picking/qobjectpicker.h @@ -77,6 +77,10 @@ public Q_SLOTS: void setDragEnabled(bool dragEnabled); Q_REVISION(13) void setPriority(int priority); +protected: + // TODO Unused remove in Qt6 + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override; + Q_SIGNALS: void pressed(Qt3DRender::QPickEvent *pick); void released(Qt3DRender::QPickEvent *pick); diff --git a/src/render/picking/qobjectpicker_p.h b/src/render/picking/qobjectpicker_p.h index 69cee529d..61f8a3d94 100644 --- a/src/render/picking/qobjectpicker_p.h +++ b/src/render/picking/qobjectpicker_p.h @@ -50,7 +50,6 @@ #include <Qt3DCore/private/qcomponent_p.h> #include <Qt3DCore/qnodeid.h> -#include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DRender/private/qt3drender_global_p.h> #include <Qt3DRender/private/objectpicker_p.h> diff --git a/src/render/picking/raycaster.cpp b/src/render/picking/raycaster.cpp index 3a79204c7..8d3456595 100644 --- a/src/render/picking/raycaster.cpp +++ b/src/render/picking/raycaster.cpp @@ -44,7 +44,6 @@ #include <Qt3DRender/qlayer.h> #include <Qt3DRender/private/qabstractraycaster_p.h> #include <Qt3DRender/private/raycastingjob_p.h> -#include <Qt3DCore/qpropertyupdatedchange.h> QT_BEGIN_NAMESPACE diff --git a/src/render/raycasting/qcollisionqueryresult.cpp b/src/render/raycasting/qcollisionqueryresult.cpp index 9d1e484b6..d2a443691 100644 --- a/src/render/raycasting/qcollisionqueryresult.cpp +++ b/src/render/raycasting/qcollisionqueryresult.cpp @@ -46,6 +46,7 @@ namespace RayCasting { QCollisionQueryResultPrivate::QCollisionQueryResultPrivate() : QSharedData() + , m_handle(0) { } diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h index 67f6a34d0..d8e2056eb 100644 --- a/src/render/raycasting/qcollisionqueryresult_p.h +++ b/src/render/raycasting/qcollisionqueryresult_p.h @@ -86,8 +86,10 @@ public: Hit(Qt3DCore::QNodeId entity, const Vector3D &intersection, float distance, const Vector3D &uvw) : m_entityId(entity) + , m_type(Entity) , m_intersection(intersection) , m_distance(distance) + , m_primitiveIndex(0U) , m_uvw(uvw) { } diff --git a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp index 333453ac7..71edc1c74 100644 --- a/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/graphicscontext.cpp @@ -265,17 +265,15 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode) return shaderProgram.take(); } -// Called by GL Command Thread (can't use global glHelpers) // That assumes that the shaderProgram in Shader stays the same void GraphicsContext::introspectShaderInterface(Shader *shader, QOpenGLShaderProgram *shaderProgram) { - QScopedPointer<GraphicsHelperInterface> glHelper(resolveHighestOpenGLFunctions()); - shader->initializeUniforms(glHelper->programUniformsAndLocations(shaderProgram->programId())); - shader->initializeAttributes(glHelper->programAttributesAndLocations(shaderProgram->programId())); + shader->initializeUniforms(m_glHelper->programUniformsAndLocations(shaderProgram->programId())); + shader->initializeAttributes(m_glHelper->programAttributesAndLocations(shaderProgram->programId())); if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject)) - shader->initializeUniformBlocks(glHelper->programUniformBlocks(shaderProgram->programId())); + shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId())); if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject)) - shader->initializeShaderStorageBlocks(glHelper->programShaderStorageBlocks(shaderProgram->programId())); + shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId())); } diff --git a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp index 4b4199820..47779dded 100644 --- a/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp +++ b/src/render/renderers/opengl/graphicshelpers/submissioncontext.cpp @@ -538,9 +538,9 @@ GLuint SubmissionContext::updateRenderTarget(Qt3DCore::QNodeId renderTargetNodeI // ### TODO QTBUG-64757 this check is insufficient since the // texture may have changed to another one with the same size. That // case is not handled atm. - needsResize |= (rTex != nullptr && rTex->size() != s); - if (isActiveRenderTarget) { - if (attachment.m_point == QRenderTargetOutput::Color0) + if (rTex) { + needsResize |= rTex->size() != s; + if (isActiveRenderTarget && attachment.m_point == QRenderTargetOutput::Color0) m_renderTargetFormat = rTex->properties().format; } } @@ -687,8 +687,8 @@ QImage SubmissionContext::readFramebuffer(const QRect &rect) GLint samples = 0; m_gl->functions()->glGetIntegerv(GL_SAMPLES, &samples); if (samples > 0 && !m_glHelper->supportsFeature(GraphicsHelperInterface::BlitFramebuffer)) { - qWarning () << Q_FUNC_INFO << "Unable to capture multisampled framebuffer; " - "Required feature BlitFramebuffer is missing."; + qCWarning(Backend) << Q_FUNC_INFO << "Unable to capture multisampled framebuffer; " + "Required feature BlitFramebuffer is missing."; return img; } @@ -711,7 +711,7 @@ QImage SubmissionContext::readFramebuffer(const QRect &rect) if (status != GL_FRAMEBUFFER_COMPLETE) { gl->glDeleteRenderbuffers(1, &rb); gl->glDeleteFramebuffers(1, &fbo); - qWarning () << Q_FUNC_INFO << "Copy-framebuffer not complete: " << status; + qCWarning(Backend) << Q_FUNC_INFO << "Copy-framebuffer not complete: " << status; return img; } @@ -797,7 +797,7 @@ bool SubmissionContext::activateShader(ProgramDNA shaderDNA) m_activeShaderDNA = shaderDNA; } else { m_glHelper->useProgram(0); - qWarning() << "No shader program found for DNA"; + qCWarning(Backend) << "No shader program found for DNA"; m_activeShaderDNA = 0; return false; } @@ -855,7 +855,7 @@ void SubmissionContext::activateDrawBuffers(const AttachmentPack &attachments) } } } else { - qWarning() << "FBO incomplete"; + qCWarning(Backend) << "FBO incomplete"; } } @@ -1171,7 +1171,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) if (uniformValues.contains(namedTex.glslNameId)) { GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.nodeId); if (t != nullptr) { - UniformValue &texUniform = uniformValues[namedTex.glslNameId]; + UniformValue &texUniform = uniformValues.value(namedTex.glslNameId); if (texUniform.valueType() == UniformValue::TextureValue) { const int texUnit = m_textureContext.activateTexture(TextureSubmissionContext::TextureScopeMaterial, m_gl, t); texUniform.data<int>()[namedTex.uniformArrayIndex] = texUnit; @@ -1179,7 +1179,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) if (namedTex.glslNameId != irradianceId && namedTex.glslNameId != specularId) { // Only return false if we are not dealing with env light textures - qWarning() << "Unable to find suitable Texture Unit"; + qCWarning(Backend) << "Unable to find suitable Texture Unit"; return false; } } @@ -1198,15 +1198,15 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) if (img != nullptr) { GLTexture *t = manager->glTextureManager()->lookupResource(img->textureId()); if (t == nullptr) { - qWarning() << "Shader Image referencing invalid texture"; + qCWarning(Backend) << "Shader Image referencing invalid texture"; continue; } else { - UniformValue &imgUniform = uniformValues[namedTex.glslNameId]; + UniformValue &imgUniform = uniformValues.value(namedTex.glslNameId); if (imgUniform.valueType() == UniformValue::ShaderImageValue) { const int imgUnit = m_imageContext.activateImage(img, t); imgUniform.data<int>()[namedTex.uniformArrayIndex] = imgUnit; if (imgUnit == -1) { - qWarning() << "Unable to bind Image to Texture"; + qCWarning(Backend) << "Unable to bind Image to Texture"; return false; } } @@ -1260,7 +1260,7 @@ bool SubmissionContext::setParameters(ShaderParameterPack ¶meterPack) for (const ShaderUniform &uniform : activeUniforms) { // We can use [] as we are sure the the uniform wouldn't // be un activeUniforms if there wasn't a matching value - const UniformValue &v = values[uniform.m_nameId]; + const UniformValue &v = values.value(uniform.m_nameId); // skip invalid textures/images if ((v.valueType() == UniformValue::TextureValue || diff --git a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp index 342fd3dad..d2a01eef4 100644 --- a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp +++ b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp @@ -53,7 +53,7 @@ FilterCompatibleTechniqueJob::FilterCompatibleTechniqueJob() : m_manager(nullptr) , m_renderer(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::FilterCompatibleTechniques, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::FilterCompatibleTechniques, 0) } void FilterCompatibleTechniqueJob::setManager(TechniqueManager *manager) diff --git a/src/render/renderers/opengl/jobs/jobs.pri b/src/render/renderers/opengl/jobs/jobs.pri index 021cd3242..d80b8bfd9 100644 --- a/src/render/renderers/opengl/jobs/jobs.pri +++ b/src/render/renderers/opengl/jobs/jobs.pri @@ -3,13 +3,15 @@ INCLUDEPATH += $$PWD SOURCES += \ $$PWD/filtercompatibletechniquejob.cpp \ $$PWD/materialparametergathererjob.cpp \ - $$PWD/renderviewbuilderjob.cpp \ + $$PWD/renderviewcommandbuilderjob.cpp \ + $$PWD/renderviewcommandupdaterjob.cpp \ $$PWD/renderviewinitializerjob.cpp \ $$PWD/renderviewjobutils.cpp HEADERS += \ $$PWD/filtercompatibletechniquejob_p.h \ $$PWD/materialparametergathererjob_p.h \ - $$PWD/renderviewbuilderjob_p.h \ + $$PWD/renderviewcommandbuilderjob_p.h \ + $$PWD/renderviewcommandupdaterjob_p.h \ $$PWD/renderviewinitializerjob_p.h \ $$PWD/renderviewjobutils_p.h diff --git a/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp b/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp index 5e56e817f..e1f8aa403 100644 --- a/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp +++ b/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp @@ -63,7 +63,7 @@ MaterialParameterGathererJob::MaterialParameterGathererJob() , m_techniqueFilter(nullptr) , m_renderPassFilter(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::MaterialParameterGathering, materialParameterGathererCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::MaterialParameterGathering, materialParameterGathererCounter++) } // TechniqueFilter / RenderPassFilter diff --git a/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob.cpp b/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob.cpp new file mode 100644 index 000000000..091d49ef5 --- /dev/null +++ b/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 "renderviewcommandbuilderjob_p.h" +#include <Qt3DRender/private/job_common_p.h> +#include <Qt3DRender/private/renderview_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +namespace { +int renderViewInstanceCounter = 0; +} // anonymous + +RenderViewCommandBuilderJob::RenderViewCommandBuilderJob() + : Qt3DCore::QAspectJob() + , m_offset(0) + , m_count(0) + , m_renderView(nullptr) +{ + SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderViewCommandBuilder, renderViewInstanceCounter++) +} + +void RenderViewCommandBuilderJob::run() +{ + if (!m_renderView->noDraw()) { + if (m_count == 0) + return; + + const bool isDraw = !m_renderView->isCompute(); + if (isDraw) + m_commandData = m_renderView->buildDrawRenderCommands(m_entities, m_offset, m_count); + else + m_commandData = m_renderView->buildComputeRenderCommands(m_entities, m_offset, m_count); + } +} + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/renderers/opengl/jobs/renderviewbuilderjob_p.h b/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob_p.h index c38f788b0..556c7f241 100644 --- a/src/render/renderers/opengl/jobs/renderviewbuilderjob_p.h +++ b/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 Paul Lemire +** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QT3DRENDER_RENDER_RENDERVIEWBUILDERJOB_P_H -#define QT3DRENDER_RENDER_RENDERVIEWBUILDERJOB_P_H +#ifndef QT3DRENDER_RENDER_RENDERVIEWCOMMANDBUILDERJOB_P_H +#define QT3DRENDER_RENDER_RENDERVIEWCOMMANDBUILDERJOB_P_H // // W A R N I N G @@ -53,6 +53,7 @@ #include <Qt3DCore/qaspectjob.h> #include <Qt3DRender/private/handle_types_p.h> +#include <Qt3DRender/private/rendercommand_p.h> QT_BEGIN_NAMESPACE @@ -60,32 +61,31 @@ namespace Qt3DRender { namespace Render { -class RenderView; -class Renderer; -class RenderCommand; - -class Q_AUTOTEST_EXPORT RenderViewBuilderJob : public Qt3DCore::QAspectJob +class Q_AUTOTEST_EXPORT RenderViewCommandBuilderJob : public Qt3DCore::QAspectJob { public: - RenderViewBuilderJob(); + RenderViewCommandBuilderJob(); inline void setRenderView(RenderView *rv) Q_DECL_NOTHROW { m_renderView = rv; } - inline void setRenderer(Renderer *renderer) Q_DECL_NOTHROW { m_renderer = renderer; } - inline void setIndex(int index) Q_DECL_NOTHROW { m_index = index; } - inline void setRenderables(const QVector<Entity *> &renderables) Q_DECL_NOTHROW { m_renderables = renderables; } - QVector<RenderCommand *> &commands() Q_DECL_NOTHROW { return m_commands; } + inline void setEntities(const QVector<Entity *> &entities, int offset, int count) + { + m_offset = offset; + m_count = count; + m_entities = entities; + } + inline EntityRenderCommandData &commandData() { return m_commandData; } void run() final; private: + int m_offset; + int m_count; RenderView *m_renderView; - Renderer *m_renderer; - int m_index; - QVector<Entity *> m_renderables; - QVector<RenderCommand *> m_commands; + QVector<Entity *> m_entities; + EntityRenderCommandData m_commandData; }; -typedef QSharedPointer<RenderViewBuilderJob> RenderViewBuilderJobPtr; +typedef QSharedPointer<RenderViewCommandBuilderJob> RenderViewCommandBuilderJobPtr; } // Render @@ -93,4 +93,4 @@ typedef QSharedPointer<RenderViewBuilderJob> RenderViewBuilderJobPtr; QT_END_NAMESPACE -#endif // QT3DRENDER_RENDER_RENDERVIEWBUILDERJOB_P_H +#endif // QT3DRENDER_RENDER_RENDERVIEWCOMMANDBUILDERJOB_P_H diff --git a/src/render/renderers/opengl/jobs/renderviewbuilderjob.cpp b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp index 15154641e..6772279d7 100644 --- a/src/render/renderers/opengl/jobs/renderviewbuilderjob.cpp +++ b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "renderviewbuilderjob_p.h" +#include "renderviewcommandupdaterjob_p.h" #include <Qt3DRender/private/job_common_p.h> #include <Qt3DRender/private/renderer_p.h> #include <Qt3DRender/private/renderview_p.h> @@ -52,22 +52,26 @@ namespace { int renderViewInstanceCounter = 0; } // anonymous -RenderViewBuilderJob::RenderViewBuilderJob() - : Qt3DCore::QAspectJob(), - m_renderView(nullptr) +RenderViewCommandUpdaterJob::RenderViewCommandUpdaterJob() + : Qt3DCore::QAspectJob() + , m_offset(0) + , m_count(0) + , m_renderView(nullptr) + , m_renderer(nullptr) + , m_renderables() { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderViewBuilder, renderViewInstanceCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderCommandUpdater, renderViewInstanceCounter++) } -void RenderViewBuilderJob::run() +void RenderViewCommandUpdaterJob::run() { // Build RenderCommand should perform the culling as we have no way to determine // if a child has a mesh in the view frustum while its parent isn't contained in it. if (!m_renderView->noDraw()) { - if (!m_renderView->isCompute()) - m_commands = m_renderView->buildDrawRenderCommands(m_renderables); - else - m_commands = m_renderView->buildComputeRenderCommands(m_renderables); + if (m_count == 0) + return; + // Update Render Commands (Uniform Change, Depth Change) + m_renderView->updateRenderCommand(m_renderables.data(), m_offset, m_count); } } diff --git a/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob_p.h b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob_p.h new file mode 100644 index 000000000..d7f424966 --- /dev/null +++ b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Paul Lemire +** 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$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_RENDERVIEWCOMMANDUPDATEJOB_P_H +#define QT3DRENDER_RENDER_RENDERVIEWCOMMANDUPDATEJOB_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DCore/qaspectjob.h> +#include <Qt3DRender/private/handle_types_p.h> +#include <Qt3DRender/private/rendercommand_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +namespace Render { + +class RenderView; +class Renderer; + +class Q_AUTOTEST_EXPORT RenderViewCommandUpdaterJob : public Qt3DCore::QAspectJob +{ +public: + RenderViewCommandUpdaterJob(); + + inline void setRenderView(RenderView *rv) Q_DECL_NOTHROW { m_renderView = rv; } + inline void setRenderer(Renderer *renderer) Q_DECL_NOTHROW { m_renderer = renderer; } + inline void setRenderables(const EntityRenderCommandDataPtr &renderables, int offset, int count) Q_DECL_NOTHROW + { + m_offset = offset; + m_count = count; + m_renderables = renderables; + } + EntityRenderCommandDataPtr renderables() const { return m_renderables; } + + QVector<RenderCommand> &commands() Q_DECL_NOTHROW { return m_commands; } + + void run() final; + +private: + int m_offset; + int m_count; + RenderView *m_renderView; + Renderer *m_renderer; + EntityRenderCommandDataPtr m_renderables; + QVector<RenderCommand> m_commands; +}; + +typedef QSharedPointer<RenderViewCommandUpdaterJob> RenderViewCommandUpdaterJobPtr; + +} // Render + +} // Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_RENDERVIEWCOMMANDUPDATEJOB_P_H diff --git a/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp b/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp index 7bf55be40..f0f72803c 100644 --- a/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp +++ b/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp @@ -65,7 +65,7 @@ RenderViewInitializerJob::RenderViewInitializerJob() , m_index(0) , m_renderView(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderView, renderViewInstanceCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderView, renderViewInstanceCounter++) } RenderViewInitializerJob::~RenderViewInitializerJob() diff --git a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp index cc211ba68..39917fb58 100644 --- a/src/render/renderers/opengl/jobs/renderviewjobutils.cpp +++ b/src/render/renderers/opengl/jobs/renderviewjobutils.cpp @@ -232,6 +232,7 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN = static_cast<const Render::RenderSurfaceSelector *>(node); rv->setSurface(surfaceSelector->surface()); rv->setSurfaceSize(surfaceSelector->renderTargetSize() * surfaceSelector->devicePixelRatio()); + rv->setDevicePixelRatio(surfaceSelector->devicePixelRatio()); } break; } @@ -487,7 +488,12 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData * } } } else { // Array of scalar/vec qmlPropertyName[0] - QString varName = blockName + QLatin1String(".") + qmlPropertyName + QLatin1String("[0]"); + QString varName; + varName.reserve(blockName.length() + 1 + qmlPropertyName.length() + 3); + varName.append(blockName); + varName.append(QLatin1String(".")); + varName.append(qmlPropertyName); + varName.append(QLatin1String("[0]")); if (uniforms.contains(varName)) { qCDebug(Shaders) << "UBO array member " << varName << " set for update"; activeUniformNamesToValue.insert(StringToInt::lookupId(varName), value); @@ -505,7 +511,11 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData * activeUniformNamesToValue.insert(varId, value); } } else { // Scalar / Vec - QString varName = blockName + QLatin1Char('.') + qmlPropertyName; + QString varName; + varName.reserve(blockName.length() + 1 + qmlPropertyName.length()); + varName.append(blockName); + varName.append(QLatin1String(".")); + varName.append(qmlPropertyName); if (uniforms.contains(varName)) { qCDebug(Shaders) << "UBO scalar member " << varName << " set for update"; @@ -525,11 +535,15 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapStructHelper(Shader const auto end = properties.end(); while (it != end) { - const auto prefix = qmlPropertyName.isEmpty() ? QLatin1String("") : QLatin1String("."); - buildActiveUniformNameValueMapHelper(rShaderData, - blockName + prefix + qmlPropertyName, - it.key(), - it.value().value); + QString fullBlockName; + fullBlockName.reserve(blockName.length() + 1 + qmlPropertyName.length()); + fullBlockName.append(blockName); + if (!qmlPropertyName.isEmpty()) { + fullBlockName.append(QLatin1String(".")); + fullBlockName.append(qmlPropertyName); + } + buildActiveUniformNameValueMapHelper(rShaderData, fullBlockName, + it.key(), it.value().value); ++it; } } diff --git a/src/render/renderers/opengl/renderer/rendercommand.cpp b/src/render/renderers/opengl/renderer/rendercommand.cpp index e60b17668..072127391 100644 --- a/src/render/renderers/opengl/renderer/rendercommand.cpp +++ b/src/render/renderers/opengl/renderer/rendercommand.cpp @@ -48,6 +48,7 @@ RenderCommand::RenderCommand() : m_stateSet(nullptr) , m_depth(0.0f) , m_changeCost(0) + , m_shaderDna(0) , m_type(RenderCommand::Draw) , m_primitiveCount(0) , m_primitiveType(QGeometryRenderer::Triangles) @@ -70,6 +71,20 @@ RenderCommand::RenderCommand() m_workGroups[2] = 0; } +bool operator==(const RenderCommand &a, const RenderCommand &b) noexcept +{ + return (a.m_vao == b.m_vao && a.m_shader == b.m_shader && a.m_material == b.m_material && + a.m_stateSet == b.m_stateSet && a.m_geometry == b.m_geometry && a.m_geometryRenderer == b.m_geometryRenderer && + a.m_indirectDrawBuffer == b.m_indirectDrawBuffer && a.m_activeAttributes == b.m_activeAttributes && + a.m_depth == b.m_depth && a.m_changeCost == b.m_changeCost && a.m_shaderDna == b.m_shaderDna && + a.m_workGroups[0] == b.m_workGroups[0] && a.m_workGroups[1] == b.m_workGroups[1] && a.m_workGroups[2] == b.m_workGroups[2] && + a.m_primitiveCount == b.m_primitiveCount && a.m_primitiveType == b.m_primitiveType && a.m_restartIndexValue == b.m_restartIndexValue && + a.m_firstInstance == b.m_firstInstance && a.m_firstVertex == b.m_firstVertex && a.m_verticesPerPatch == b.m_verticesPerPatch && + a.m_instanceCount == b.m_instanceCount && a.m_indexOffset == b.m_indexOffset && a.m_indexAttributeByteOffset == b.m_indexAttributeByteOffset && + a.m_drawIndexed == b.m_drawIndexed && a.m_drawIndirect == b.m_drawIndirect && a.m_primitiveRestartEnabled == b.m_primitiveRestartEnabled && + a.m_isValid == b.m_isValid && a.m_computeCommand == b.m_computeCommand); +} + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/renderers/opengl/renderer/rendercommand_p.h b/src/render/renderers/opengl/renderer/rendercommand_p.h index 61cc6d17d..be00fb753 100644 --- a/src/render/renderers/opengl/renderer/rendercommand_p.h +++ b/src/render/renderers/opengl/renderer/rendercommand_p.h @@ -55,6 +55,7 @@ #include <qglobal.h> #include <Qt3DRender/private/shaderparameterpack_p.h> #include <Qt3DRender/private/handle_types_p.h> +#include <Qt3DRender/private/renderviewjobutils_p.h> #include <Qt3DRender/qgeometryrenderer.h> #include <QOpenGLShaderProgram> #include <QOpenGLTexture> @@ -69,6 +70,7 @@ namespace Qt3DRender { namespace Render { class RenderStateSet; +using RenderStateSetPtr = QSharedPointer<RenderStateSet>; class Q_AUTOTEST_EXPORT RenderCommand { @@ -80,12 +82,13 @@ public: HMaterial m_material; // Purely used to ease sorting (minimize stage changes, binding changes ....) ShaderParameterPack m_parameterPack; // Might need to be reworked so as to be able to destroy the // Texture while submission is happening. - RenderStateSet *m_stateSet; + RenderStateSetPtr m_stateSet; HGeometry m_geometry; HGeometryRenderer m_geometryRenderer; HBuffer m_indirectDrawBuffer; // Reference to indirect draw buffer (valid only m_drawIndirect == true) + HComputeCommand m_computeCommand; // A QAttribute pack might be interesting // This is a temporary fix in the meantime, to remove the hacked methods in Technique @@ -121,6 +124,53 @@ public: bool m_isValid; }; +Q_AUTOTEST_EXPORT bool operator==(const RenderCommand &a, const RenderCommand &b) noexcept; + +inline bool operator!=(const RenderCommand &lhs, const RenderCommand &rhs) noexcept +{ return !operator==(lhs, rhs); } + +struct EntityRenderCommandData +{ + QVector<Entity *> entities; + QVector<RenderCommand> commands; + QVector<RenderPassParameterData> passesData; + + void reserve(int size) + { + entities.reserve(size); + commands.reserve(size); + passesData.reserve(size); + } + + inline int size() const { return entities.size(); } + + inline void push_back(Entity *e, const RenderCommand &c, const RenderPassParameterData &p) + { + entities.push_back(e); + commands.push_back(c); + passesData.push_back(p); + } + + inline void push_back(Entity *e, RenderCommand &&c, RenderPassParameterData &&p) + { + entities.push_back(e); + commands.push_back(std::move(c)); + passesData.push_back(std::move(p)); + } + + EntityRenderCommandData &operator+=(EntityRenderCommandData &&t) + { + entities += std::move(t.entities); + commands += std::move(t.commands); + passesData += std::move(t.passesData); + return *this; + } + +}; + +using EntityRenderCommandDataPtr = QSharedPointer<EntityRenderCommandData>; + + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 121a6aa8f..ddf57f4fe 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -93,15 +93,15 @@ #include <Qt3DRender/private/subtreeenabler_p.h> #include <Qt3DRender/private/qshaderprogrambuilder_p.h> #include <Qt3DRender/private/qshaderprogram_p.h> +#include <Qt3DRender/private/filterentitybycomponentjob_p.h> +#include <Qt3DRender/private/commandexecuter_p.h> #include <Qt3DRender/qcameralens.h> #include <Qt3DCore/private/qeventfilterservice_p.h> #include <Qt3DCore/private/qabstractaspectjobmanager_p.h> #include <Qt3DCore/private/qaspectmanager_p.h> - -#if QT_CONFIG(qt3d_profile_jobs) -#include <Qt3DCore/private/aspectcommanddebugger_p.h> -#endif +#include <Qt3DCore/private/qsysteminformationservice_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p_p.h> #include <QStack> #include <QOffscreenSurface> @@ -114,19 +114,9 @@ #include <QUrl> #include <QOffscreenSurface> #include <QWindow> - -#include <QtGui/private/qopenglcontext_p.h> - -// For Debug purposes only #include <QThread> - -#if QT_CONFIG(qt3d_profile_jobs) -#include <Qt3DCore/private/qthreadpooler_p.h> -#include <Qt3DRender/private/job_common_p.h> -#include <Qt3DRender/private/commandexecuter_p.h> -#endif - +#include <QtGui/private/qopenglcontext_p.h> #include <Qt3DRender/private/frameprofiler_p.h> QT_BEGIN_NAMESPACE @@ -138,6 +128,82 @@ using namespace Qt3DCore; namespace Qt3DRender { namespace Render { + +namespace { + +class SyncLightsGatherer +{ +public: + explicit SyncLightsGatherer(LightGathererPtr gatherJob, + RendererCache *cache) + : m_gatherJob(gatherJob) + , m_cache(cache) + { + } + + void operator()() + { + QMutexLocker lock(m_cache->mutex()); + m_cache->gatheredLights = m_gatherJob->lights(); + m_cache->environmentLight = m_gatherJob->takeEnvironmentLight(); + } + +private: + LightGathererPtr m_gatherJob; + RendererCache *m_cache; +}; + +class SyncRenderableEntities +{ +public: + explicit SyncRenderableEntities(RenderableEntityFilterPtr gatherJob, + RendererCache *cache) + : m_gatherJob(gatherJob) + , m_cache(cache) + { + } + + void operator()() + { + QVector<Entity *> selectedEntities = m_gatherJob->filteredEntities(); + std::sort(selectedEntities.begin(), selectedEntities.end()); + + QMutexLocker lock(m_cache->mutex()); + m_cache->renderableEntities = selectedEntities; + } + +private: + RenderableEntityFilterPtr m_gatherJob; + RendererCache *m_cache; +}; + +class SyncComputableEntities +{ +public: + explicit SyncComputableEntities(ComputableEntityFilterPtr gatherJob, + RendererCache *cache) + : m_gatherJob(gatherJob) + , m_cache(cache) + { + } + + void operator()() + { + QVector<Entity *> selectedEntities = m_gatherJob->filteredEntities(); + std::sort(selectedEntities.begin(), selectedEntities.end()); + + QMutexLocker lock(m_cache->mutex()); + m_cache->computeEntities = selectedEntities; + } + +private: + ComputableEntityFilterPtr m_gatherJob; + RendererCache *m_cache; +}; + +} // anonymous + + /*! \internal @@ -186,31 +252,33 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_calculateBoundingVolumeJob(Render::CalculateBoundingVolumeJobPtr::create()) , m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create()) , m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create()) - , m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create()) , m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create()) , m_updateSkinningPaletteJob(Render::UpdateSkinningPaletteJobPtr::create()) , m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create()) , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create()) , m_updateEntityLayersJob(Render::UpdateEntityLayersJobPtr::create()) + , m_lightGathererJob(Render::LightGathererPtr::create()) + , m_renderableEntityFilterJob(Render::RenderableEntityFilterPtr::create()) + , m_computableEntityFilterJob(Render::ComputableEntityFilterPtr::create()) , m_bufferGathererJob(SynchronizerJobPtr::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) , m_vaoGathererJob(SynchronizerJobPtr::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering)) , m_textureGathererJob(SynchronizerJobPtr::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) - , m_sendTextureChangesToFrontendJob(SynchronizerPostFramePtr::create([] {}, - [this] (Qt3DCore::QAspectManager *m) { sendTextureChangesToFrontend(m); }, - JobTypes::SendTextureChangesToFrontend)) , m_sendSetFenceHandlesToFrontendJob(SynchronizerJobPtr::create([this] { sendSetFenceHandlesToFrontend(); }, JobTypes::SendSetFenceHandlesToFrontend)) - , m_sendDisablesToFrontendJob(SynchronizerJobPtr::create([this] { sendDisablesToFrontend(); }, JobTypes::SendDisablesToFrontend)) , m_introspectShaderJob(SynchronizerPostFramePtr::create([this] { reloadDirtyShaders(); }, [this] (Qt3DCore::QAspectManager *m) { sendShaderChangesToFrontend(m); }, JobTypes::DirtyShaderGathering)) , m_syncLoadingJobs(SynchronizerJobPtr::create([] {}, JobTypes::SyncLoadingJobs)) + , m_cacheRenderableEntitiesJob(SynchronizerJobPtr::create(SyncRenderableEntities(m_renderableEntityFilterJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) + , m_cacheComputableEntitiesJob(SynchronizerJobPtr::create(SyncComputableEntities(m_computableEntityFilterJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) + , m_cacheLightsJob(SynchronizerJobPtr::create(SyncLightsGatherer(m_lightGathererJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) , m_ownedContext(false) , m_offscreenHelper(nullptr) - , m_shouldSwapBuffers(true) - #if QT_CONFIG(qt3d_profile_jobs) , m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this)) - #endif + , m_shouldSwapBuffers(true) { // Set renderer as running - it will wait in the context of the // RenderThread for RenderViews to be submitted @@ -238,6 +306,10 @@ Renderer::Renderer(QRenderAspect::RenderType type) m_introspectShaderJob->addDependency(m_filterCompatibleTechniqueJob); + m_cacheLightsJob->addDependency(m_lightGathererJob); + m_cacheRenderableEntitiesJob->addDependency(m_renderableEntityFilterJob); + m_cacheComputableEntitiesJob->addDependency(m_computableEntityFilterJob); + m_filterCompatibleTechniqueJob->setRenderer(this); m_defaultRenderStateSet = new RenderStateSet; @@ -299,13 +371,16 @@ void Renderer::setNodeManagers(NodeManagers *managers) m_pickBoundingVolumeJob->setManagers(m_nodesManager); m_rayCastingJob->setManagers(m_nodesManager); m_updateWorldBoundingVolumeJob->setManager(m_nodesManager->renderNodesManager()); - m_sendRenderCaptureJob->setManagers(m_nodesManager); m_updateLevelOfDetailJob->setManagers(m_nodesManager); m_updateSkinningPaletteJob->setManagers(m_nodesManager); m_updateMeshTriangleListJob->setManagers(m_nodesManager); m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager()); m_updateEntityLayersJob->setManager(m_nodesManager); m_updateTreeEnabledJob->setManagers(m_nodesManager); + m_sendBufferCaptureJob->setManagers(m_nodesManager); + m_lightGathererJob->setManager(m_nodesManager->renderNodesManager()); + m_renderableEntityFilterJob->setManager(m_nodesManager->renderNodesManager()); + m_computableEntityFilterJob->setManager(m_nodesManager->renderNodesManager()); } void Renderer::setServices(QServiceLocator *services) @@ -338,7 +413,7 @@ QOpenGLContext *Renderer::shareContext() const // Executed in the reloadDirtyShader job void Renderer::loadShader(Shader *shader, HShader shaderHandle) { - Q_UNUSED(shader); + Q_UNUSED(shader) m_dirtyShaders.push_back(shaderHandle); } @@ -432,6 +507,9 @@ void Renderer::initialize() m_waitForInitializationToBeCompleted.release(1); // Allow the aspect manager to proceed m_vsyncFrameAdvanceService->proceedToNextFrame(); + + // Force initial refresh + markDirty(AllDirty, nullptr); } /*! @@ -653,19 +731,12 @@ void Renderer::doRender(bool swapBuffers) // RenderQueue is complete (but that means it may be of size 0) if (canSubmit && (queueIsComplete && !queueIsEmpty)) { const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue(); - -#if QT_CONFIG(qt3d_profile_jobs) - // Save start of frame - JobRunStats submissionStatsPart1; - JobRunStats submissionStatsPart2; - submissionStatsPart1.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart1; - submissionStatsPart1.jobId.typeAndInstance[1] = 0; - submissionStatsPart1.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); - submissionStatsPart1.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - submissionStatsPart2.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart2; - submissionStatsPart2.jobId.typeAndInstance[1] = 0; - submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); -#endif + QTaskLogger submissionStatsPart1(m_services->systemInformation(), + {JobTypes::FrameSubmissionPart1, 0}, + QTaskLogger::Submission); + QTaskLogger submissionStatsPart2(m_services->systemInformation(), + {JobTypes::FrameSubmissionPart2, 0}, + QTaskLogger::Submission); if (canRender()) { { // Scoped to destroy surfaceLock @@ -698,15 +769,11 @@ void Renderer::doRender(bool swapBuffers) m_vsyncFrameAdvanceService->proceedToNextFrame(); hasCleanedQueueAndProceeded = true; -#if QT_CONFIG(qt3d_profile_jobs) - if (preprocessingComplete) { - submissionStatsPart2.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - submissionStatsPart1.endTime = submissionStatsPart2.startTime; - } -#endif // Only try to submit the RenderViews if the preprocessing was successful // This part of the submission is happening in parallel to the RV building for the next frame if (preprocessingComplete) { + submissionStatsPart1.end(submissionStatsPart2.restart()); + // 3) Submit the render commands for frame n (making sure we never reference something that could be changing) // Render using current device state and renderer configuration submissionData = submitRenderViews(renderViews); @@ -716,33 +783,18 @@ void Renderer::doRender(bool swapBuffers) } } -#if QT_CONFIG(qt3d_profile_jobs) // Execute the pending shell commands m_commandExecuter->performAsynchronousCommandExecution(renderViews); -#endif // Delete all the RenderViews which will clear the allocators // that were used for their allocation qDeleteAll(renderViews); - -#if QT_CONFIG(qt3d_profile_jobs) - if (preprocessingComplete) { - // Save submission elapsed time - submissionStatsPart2.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - // Note this is safe since proceedToNextFrame is the one going to trigger - // the write to the file, and this is performed after this step - Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart1); - Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart2); - Profiling::GLTimeRecorder::writeResults(); - } -#endif } // If hasCleanedQueueAndProceeded isn't true this implies that something went wrong // with the rendering and/or the renderqueue is incomplete from some reason // or alternatively it could be complete but empty (RenderQueue of size 0) - if (!hasCleanedQueueAndProceeded) { // RenderQueue was full but something bad happened when // trying to render it and therefore proceedToNextFrame was not called @@ -830,12 +882,7 @@ bool Renderer::isReadyToSubmit() // Main thread QVariant Renderer::executeCommand(const QStringList &args) { -#if QT_CONFIG(qt3d_profile_jobs) return m_commandExecuter->executeCommand(args); -#else - Q_UNUSED(args); -#endif - return QVariant(); } /*! @@ -860,13 +907,13 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView QHash<HVao, bool> updatedTable; for (RenderView *rv: renderViews) { - const QVector<RenderCommand *> commands = rv->commands(); - for (RenderCommand *command : commands) { + QVector<RenderCommand> &commands = rv->commands(); + for (RenderCommand &command : commands) { // Update/Create VAO - if (command->m_type == RenderCommand::Draw) { - Geometry *rGeometry = m_nodesManager->data<Geometry, GeometryManager>(command->m_geometry); - GeometryRenderer *rGeometryRenderer = m_nodesManager->data<GeometryRenderer, GeometryRendererManager>(command->m_geometryRenderer); - Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command->m_shader); + if (command.m_type == RenderCommand::Draw) { + Geometry *rGeometry = m_nodesManager->data<Geometry, GeometryManager>(command.m_geometry); + GeometryRenderer *rGeometryRenderer = m_nodesManager->data<GeometryRenderer, GeometryRendererManager>(command.m_geometryRenderer); + Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command.m_shader); // We should never have inserted a command for which these are null // in the first place @@ -879,15 +926,15 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView // Create VAO or return already created instance associated with command shader/geometry // (VAO is emulated if not supported) - createOrUpdateVAO(command, &vaoHandle, &vao); - command->m_vao = vaoHandle; + createOrUpdateVAO(&command, &vaoHandle, &vao); + command.m_vao = vaoHandle; // Avoids redoing the same thing for the same VAO if (!updatedTable.contains(vaoHandle)) { updatedTable.insert(vaoHandle, true); // Do we have any attributes that are dirty ? - const bool requiresPartialVAOUpdate = requiresVAOAttributeUpdate(rGeometry, command); + const bool requiresPartialVAOUpdate = requiresVAOAttributeUpdate(rGeometry, &command); // If true, we need to reupload all attributes to set the VAO // Otherwise only dirty attributes will be updates @@ -898,7 +945,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView if (rGeometry->isDirty()) m_dirtyGeometry.push_back(rGeometry); - if (!command->m_activeAttributes.isEmpty() && (requiresFullVAOUpdate || requiresPartialVAOUpdate)) { + if (!command.m_activeAttributes.isEmpty() && (requiresFullVAOUpdate || requiresPartialVAOUpdate)) { Profiling::GLTimeRecorder recorder(Profiling::VAOUpload); // Activate shader m_submissionContext->activateShader(shader->dna()); @@ -906,7 +953,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView vao->bind(); // Update or set Attributes and Buffers for the given rGeometry and Command // Note: this fills m_dirtyAttributes as well - if (updateVAOWithAttributes(rGeometry, command, shader, requiresFullVAOUpdate)) + if (updateVAOWithAttributes(rGeometry, &command, shader, requiresFullVAOUpdate)) vao->setSpecified(true); } } @@ -918,82 +965,14 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView rGeometryRenderer->unsetDirty(); // Prepare the ShaderParameterPack based on the active uniforms of the shader - shader->prepareUniforms(command->m_parameterPack); - - { // Scoped to show extent - command->m_isValid = !command->m_activeAttributes.empty(); - if (!command->m_isValid) - continue; - - // Update the draw command with what's going to be needed for the drawing - uint primitiveCount = rGeometryRenderer->vertexCount(); - uint estimatedCount = 0; - Attribute *indexAttribute = nullptr; - Attribute *indirectAttribute = nullptr; - - const QVector<Qt3DCore::QNodeId> attributeIds = rGeometry->attributes(); - for (Qt3DCore::QNodeId attributeId : attributeIds) { - Attribute *attribute = m_nodesManager->attributeManager()->lookupResource(attributeId); - switch (attribute->attributeType()) { - case QAttribute::IndexAttribute: - indexAttribute = attribute; - break; - case QAttribute::DrawIndirectAttribute: - indirectAttribute = attribute; - break; - case QAttribute::VertexAttribute: { - if (command->m_activeAttributes.contains(attribute->nameId())) - estimatedCount = qMax(attribute->count(), estimatedCount); - break; - } - default: - Q_UNREACHABLE(); - break; - } - } - - command->m_drawIndexed = (indexAttribute != nullptr); - command->m_drawIndirect = (indirectAttribute != nullptr); - - // Update the draw command with all the information required for the drawing - if (command->m_drawIndexed) { - command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType()); - command->m_indexAttributeByteOffset = indexAttribute->byteOffset() + rGeometryRenderer->indexBufferByteOffset(); - } - - // Note: we only care about the primitiveCount when using direct draw calls - // For indirect draw calls it is assumed the buffer was properly set already - if (command->m_drawIndirect) { - command->m_indirectAttributeByteOffset = indirectAttribute->byteOffset(); - command->m_indirectDrawBuffer = m_nodesManager->bufferManager()->lookupHandle(indirectAttribute->bufferId()); - } else { - // Use the count specified by the GeometryRender - // If not specify use the indexAttribute count if present - // Otherwise tries to use the count from the attribute with the highest count - if (primitiveCount == 0) { - if (indexAttribute) - primitiveCount = indexAttribute->count(); - else - primitiveCount = estimatedCount; - } - } + shader->prepareUniforms(command.m_parameterPack); - command->m_primitiveCount = primitiveCount; - command->m_primitiveType = rGeometryRenderer->primitiveType(); - command->m_primitiveRestartEnabled = rGeometryRenderer->primitiveRestartEnabled(); - command->m_restartIndexValue = rGeometryRenderer->restartIndexValue(); - command->m_firstInstance = rGeometryRenderer->firstInstance(); - command->m_instanceCount = rGeometryRenderer->instanceCount(); - command->m_firstVertex = rGeometryRenderer->firstVertex(); - command->m_indexOffset = rGeometryRenderer->indexOffset(); - command->m_verticesPerPatch = rGeometryRenderer->verticesPerPatch(); - } // scope - } else if (command->m_type == RenderCommand::Compute) { - Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command->m_shader); + } else if (command.m_type == RenderCommand::Compute) { + Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command.m_shader); Q_ASSERT(shader); // Prepare the ShaderParameterPack based on the active uniforms of the shader - shader->prepareUniforms(command->m_parameterPack); + shader->prepareUniforms(command.m_parameterPack); } } } @@ -1042,6 +1021,7 @@ void Renderer::lookForDirtyBuffers() } } +// Called in prepareSubmission void Renderer::lookForDownloadableBuffers() { m_downloadableBuffers.clear(); @@ -1049,7 +1029,7 @@ void Renderer::lookForDownloadableBuffers() for (const HBuffer &handle : activeBufferHandles) { Buffer *buffer = m_nodesManager->bufferManager()->data(handle); if (buffer->access() & QBuffer::Read) - m_downloadableBuffers.push_back(handle); + m_downloadableBuffers.push_back(buffer->peerId()); } } @@ -1106,7 +1086,7 @@ void Renderer::reloadDirtyShaders() // If api of the renderer matches the one from the technique if (technique->isCompatibleWithRenderer()) { const auto passIds = technique->renderPasses(); - for (const QNodeId passId : passIds) { + for (const QNodeId &passId : passIds) { RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId); HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram()); Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle); @@ -1146,7 +1126,7 @@ void Renderer::reloadDirtyShaders() } } -// Executed in job postFrame +// Executed in job (in main thread when jobs are done) void Renderer::sendShaderChangesToFrontend(Qt3DCore::QAspectManager *manager) { Q_ASSERT(isRunning()); @@ -1173,14 +1153,13 @@ void Renderer::sendShaderChangesToFrontend(Qt3DCore::QAspectManager *manager) } } -// Executed in a job (as postFrame) +// Executed in a job (in main thread when jobs are done) void Renderer::sendTextureChangesToFrontend(Qt3DCore::QAspectManager *manager) { const QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> updateTextureProperties = std::move(m_updatedTextureProperties); for (const auto &pair : updateTextureProperties) { const Qt3DCore::QNodeIdVector targetIds = pair.second; - for (const Qt3DCore::QNodeId targetId: targetIds) { - + for (const Qt3DCore::QNodeId &targetId: targetIds) { // Lookup texture Texture *t = m_nodesManager->textureManager()->lookupResource(targetId); // If backend texture is Dirty, some property has changed and the properties we are @@ -1226,17 +1205,24 @@ void Renderer::sendSetFenceHandlesToFrontend() } } -// Executed in a job -void Renderer::sendDisablesToFrontend() +// Executed in a job (in main thread when jobs done) +void Renderer::sendDisablesToFrontend(Qt3DCore::QAspectManager *manager) { - const auto updatedDisables = std::move(m_updatedDisables); - FrameGraphManager *fgManager = m_nodesManager->frameGraphManager(); + // SubtreeEnabled + const auto updatedDisables = std::move(m_updatedDisableSubtreeEnablers); for (const auto &nodeId : updatedDisables) { - FrameGraphNode *fgNode = fgManager->lookupNode(nodeId); - if (fgNode != nullptr) { // Node could have been deleted before we got a chance to notify it - Q_ASSERT(fgNode->nodeType() == FrameGraphNode::SubtreeEnabler); - SubtreeEnabler *enabler = static_cast<SubtreeEnabler *>(fgNode); - enabler->sendDisableToFrontend(); + QSubtreeEnabler *frontend = static_cast<decltype(frontend)>(manager->lookupNode(nodeId)); + frontend->setEnabled(false); + } + + // Compute Commands + const QVector<HComputeCommand> activeCommands = m_nodesManager->computeJobManager()->activeHandles(); + for (const HComputeCommand &handle :activeCommands) { + ComputeCommand *c = m_nodesManager->computeJobManager()->data(handle); + if (c->hasReachedFrameCount()) { + QComputeCommand *frontend = static_cast<decltype(frontend)>(manager->lookupNode(c->peerId())); + frontend->setEnabled(false); + c->resetHasReachedFrameCount(); } } } @@ -1355,6 +1341,9 @@ void Renderer::updateGLResources() // Record ids of texture to cleanup while we are still blocking the aspect thread m_textureIdsToCleanup += m_nodesManager->textureManager()->takeTexturesIdsToCleanup(); } + + // Record list of buffer that might need uploading + lookForDownloadableBuffers(); } // Render Thread @@ -1437,12 +1426,18 @@ void Renderer::cleanupTexture(Qt3DCore::QNodeId cleanedUpTextureId) // Called by SubmitRenderView void Renderer::downloadGLBuffers() { - lookForDownloadableBuffers(); - const QVector<HBuffer> downloadableHandles = std::move(m_downloadableBuffers); - for (const HBuffer &handle : downloadableHandles) { - Buffer *buffer = m_nodesManager->bufferManager()->data(handle); - QByteArray content = m_submissionContext->downloadBufferContent(buffer); - m_sendBufferCaptureJob->addRequest(QPair<Buffer*, QByteArray>(buffer, content)); + const QVector<Qt3DCore::QNodeId> downloadableHandles = std::move(m_downloadableBuffers); + for (const Qt3DCore::QNodeId &bufferId : downloadableHandles) { + BufferManager *bufferManager = m_nodesManager->bufferManager(); + BufferManager::ReadLocker locker(const_cast<const BufferManager *>(bufferManager)); + Buffer *buffer = bufferManager->lookupResource(bufferId); + // Buffer could have been destroyed at this point + if (!buffer) + continue; + // locker is protecting us from the buffer being destroy while we're looking + // up its content + const QByteArray content = m_submissionContext->downloadBufferContent(buffer); + m_sendBufferCaptureJob->addRequest(QPair<Qt3DCore::QNodeId, QByteArray>(bufferId, content)); } } @@ -1606,7 +1601,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren } // Set the Viewport - m_submissionContext->setViewport(renderView->viewport(), renderView->surfaceSize() * renderView->devicePixelRatio()); + m_submissionContext->setViewport(renderView->viewport(), renderView->surfaceSize()); // Execute the render commands if (!executeCommandsSubmission(renderView)) @@ -1617,7 +1612,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren // renderViewStateSet or m_defaultRenderStateSet) if (!renderView->renderCaptureNodeId().isNull()) { const QRenderCaptureRequest request = renderView->renderCaptureRequest(); - const QSize size = m_submissionContext->renderTargetSize(renderView->surfaceSize() * renderView->devicePixelRatio()); + const QSize size = m_submissionContext->renderTargetSize(renderView->surfaceSize()); QRect rect(QPoint(0, 0), size); if (!request.rect.isEmpty()) rect = rect.intersected(request.rect); @@ -1632,7 +1627,8 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren Render::RenderCapture *renderCapture = static_cast<Render::RenderCapture*>(m_nodesManager->frameGraphManager()->lookupNode(renderView->renderCaptureNodeId())); renderCapture->addRenderCapture(request.captureId, image); - addRenderCaptureSendRequest(renderView->renderCaptureNodeId()); + if (!m_pendingRenderCaptureSendRequests.contains(renderView->renderCaptureNodeId())) + m_pendingRenderCaptureSendRequests.push_back(renderView->renderCaptureNodeId()); } if (renderView->isDownloadBuffersEnable()) @@ -1688,7 +1684,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren void Renderer::markDirty(BackendNodeDirtySet changes, BackendNode *node) { - Q_UNUSED(node); + Q_UNUSED(node) m_dirtyBits.marked |= changes; } @@ -1705,12 +1701,11 @@ void Renderer::clearDirtyBits(BackendNodeDirtySet changes) } #endif -bool Renderer::shouldRender() +bool Renderer::shouldRender() const { // Only render if something changed during the last frame, or the last frame // was not rendered successfully (or render-on-demand is disabled) return (m_settings->renderPolicy() == QRenderSettings::Always - || m_renderThread == nullptr // <==> we use Scene3D || m_dirtyBits.marked != 0 || m_dirtyBits.remaining != 0 || !m_lastFrameCorrect.loadRelaxed()); @@ -1725,24 +1720,34 @@ void Renderer::skipNextFrame() m_submitRenderViewsSemaphore.release(1); } -// Jobs we may have to run even if no rendering will happen -QVector<QAspectJobPtr> Renderer::preRenderingJobs() +void Renderer::jobsDone(Qt3DCore::QAspectManager *manager) { - QVector<QAspectJobPtr> jobs; + // called in main thread once all jobs are done running + + // sync captured renders to frontend + const QVector<Qt3DCore::QNodeId> pendingCaptureIds = std::move(m_pendingRenderCaptureSendRequests); + for (const Qt3DCore::QNodeId &id : qAsConst(pendingCaptureIds)) { + auto *backend = static_cast<Qt3DRender::Render::RenderCapture *> + (m_nodesManager->frameGraphManager()->lookupNode(id)); + backend->syncRenderCapturesToFrontend(manager); + } // Do we need to notify any texture about property changes? if (m_updatedTextureProperties.size() > 0) - jobs.push_back(m_sendTextureChangesToFrontendJob); + sendTextureChangesToFrontend(manager); + + sendDisablesToFrontend(manager); +} + +// Jobs we may have to run even if no rendering will happen +QVector<QAspectJobPtr> Renderer::preRenderingJobs() +{ + QVector<QAspectJobPtr> jobs; // Do we need to notify frontend about fence change? if (m_updatedSetFences.size() > 0) jobs.push_back(m_sendSetFenceHandlesToFrontendJob); - const QVector<Qt3DCore::QNodeId> pendingCaptureIds = takePendingRenderCaptureSendRequests(); - if (pendingCaptureIds.size() > 0) { - m_sendRenderCaptureJob->setPendingCaptureRequests(pendingCaptureIds); - jobs.push_back(m_sendRenderCaptureJob); - } if (m_sendBufferCaptureJob->hasRequests()) jobs.push_back(m_sendBufferCaptureJob); @@ -1759,7 +1764,6 @@ QVector<QAspectJobPtr> Renderer::preRenderingJobs() QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() { QVector<QAspectJobPtr> renderBinJobs; - // Create the jobs to build the frame const QVector<QAspectJobPtr> bufferJobs = createRenderBufferJobs(); @@ -1774,9 +1778,9 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot()); const BackendNodeDirtySet dirtyBitsForFrame = m_dirtyBits.marked | m_dirtyBits.remaining; - m_dirtyBits.marked = 0; - m_dirtyBits.remaining = 0; - BackendNodeDirtySet notCleared = 0; + m_dirtyBits.marked = {}; + m_dirtyBits.remaining = {}; + BackendNodeDirtySet notCleared = {}; // Add jobs const bool entitiesEnabledDirty = dirtyBitsForFrame & AbstractRenderer::EntityEnabledDirty; @@ -1810,7 +1814,6 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() renderBinJobs.push_back(m_updateSkinningPaletteJob); renderBinJobs.push_back(m_updateLevelOfDetailJob); renderBinJobs.push_back(m_cleanupJob); - renderBinJobs.append(bufferJobs); // Jobs to prepare GL Resource upload @@ -1834,11 +1837,27 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() const bool computeableDirty = dirtyBitsForFrame & AbstractRenderer::ComputeDirty; const bool renderableDirty = dirtyBitsForFrame & AbstractRenderer::GeometryDirty; const bool materialCacheNeedsToBeRebuilt = shadersDirty || materialDirty || frameGraphDirty; + const bool renderCommandsDirty = materialCacheNeedsToBeRebuilt || renderableDirty || computeableDirty; // Rebuild Entity Layers list if layers are dirty if (layersDirty) renderBinJobs.push_back(m_updateEntityLayersJob); + if (renderableDirty) { + renderBinJobs.push_back(m_renderableEntityFilterJob); + renderBinJobs.push_back(m_cacheRenderableEntitiesJob); + } + + if (computeableDirty) { + renderBinJobs.push_back(m_computableEntityFilterJob); + renderBinJobs.push_back(m_cacheComputableEntitiesJob); + } + + if (lightsDirty) { + renderBinJobs.push_back(m_lightGathererJob); + renderBinJobs.push_back(m_cacheLightsJob); + } + QMutexLocker lock(m_renderQueue->mutex()); if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case) // Traverse the current framegraph. For each leaf node create a @@ -1859,20 +1878,18 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() // Handle single shot subtree enablers const auto subtreeEnablers = visitor.takeEnablersToDisable(); for (auto *node : subtreeEnablers) - m_updatedDisables.push_back(node->peerId()); - if (m_updatedDisables.size() > 0) - renderBinJobs.push_back(m_sendDisablesToFrontendJob); + m_updatedDisableSubtreeEnablers.push_back(node->peerId()); } const int fgBranchCount = m_frameGraphLeaves.size(); for (int i = 0; i < fgBranchCount; ++i) { - RenderViewBuilder builder(m_frameGraphLeaves.at(i), i, this); - builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt); - builder.setRenderableCacheNeedsToBeRebuilt(renderableDirty); - builder.setComputableCacheNeedsToBeRebuilt(computeableDirty); - builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty); - builder.setMaterialGathererCacheNeedsToBeRebuilt(materialCacheNeedsToBeRebuilt); - builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty); + FrameGraphNode *leaf = m_frameGraphLeaves.at(i); + RenderViewBuilder builder(leaf, i, this); + // If we have a new RV (wasn't in the cache before, then it contains no cached data) + const bool isNewRV = !m_cache.leafNodeCache.contains(leaf); + builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt || isNewRV); + builder.setMaterialGathererCacheNeedsToBeRebuilt(materialCacheNeedsToBeRebuilt || isNewRV); + builder.setRenderCommandCacheNeedsToBeRebuilt(renderCommandsDirty || isNewRV); builder.prepareJobs(); renderBinJobs.append(builder.buildJobHierachy()); @@ -2075,7 +2092,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) bool allCommandsIssued = true; // Render drawing commands - const QVector<RenderCommand *> commands = rv->commands(); + QVector<RenderCommand> commands = rv->commands(); // Use the graphicscontext to submit the commands to the underlying // graphics API (OpenGL) @@ -2084,18 +2101,18 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) RenderStateSet *globalState = m_submissionContext->currentStateSet(); OpenGLVertexArrayObject *vao = nullptr; - for (RenderCommand *command : qAsConst(commands)) { + for (RenderCommand &command : commands) { - if (command->m_type == RenderCommand::Compute) { // Compute Call - performCompute(rv, command); + if (command.m_type == RenderCommand::Compute) { // Compute Call + performCompute(rv, &command); } else { // Draw Command // Check if we have a valid command that can be drawn - if (!command->m_isValid) { + if (!command.m_isValid) { allCommandsIssued = false; continue; } - vao = m_nodesManager->vaoManager()->data(command->m_vao); + vao = m_nodesManager->vaoManager()->data(command.m_vao); // something may have went wrong when initializing the VAO if (!vao->isSpecified()) { @@ -2106,7 +2123,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) { Profiling::GLTimeRecorder recorder(Profiling::ShaderUpdate); //// We activate the shader here - if (!m_submissionContext->activateShader(command->m_shaderDna)) { + if (!m_submissionContext->activateShader(command.m_shaderDna)) { allCommandsIssued = false; continue; } @@ -2121,7 +2138,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) { Profiling::GLTimeRecorder recorder(Profiling::UniformUpdate); //// Update program uniforms - if (!m_submissionContext->setParameters(command->m_parameterPack)) { + if (!m_submissionContext->setParameters(command.m_parameterPack)) { allCommandsIssued = false; // If we have failed to set uniform (e.g unable to bind a texture) // we won't perform the draw call which could show invalid content @@ -2132,7 +2149,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) //// OpenGL State // TO DO: Make states not dependendent on their backend node for this step // Set state - RenderStateSet *localState = command->m_stateSet; + RenderStateSet *localState = command.m_stateSet.data(); { @@ -2140,8 +2157,8 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) // Merge the RenderCommand state with the globalState of the RenderView // Or restore the globalState if no stateSet for the RenderCommand if (localState != nullptr) { - command->m_stateSet->merge(globalState); - m_submissionContext->setCurrentStateSet(command->m_stateSet); + command.m_stateSet->merge(globalState); + m_submissionContext->setCurrentStateSet(localState); } else { m_submissionContext->setCurrentStateSet(globalState); } @@ -2151,7 +2168,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) // at that point //// Draw Calls - performDraw(command); + performDraw(&command); } } // end of RenderCommands loop @@ -2167,7 +2184,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) } bool Renderer::updateVAOWithAttributes(Geometry *geometry, - RenderCommand *command, + const RenderCommand *command, Shader *shader, bool forceUpdate) { @@ -2227,7 +2244,7 @@ bool Renderer::updateVAOWithAttributes(Geometry *geometry, } bool Renderer::requiresVAOAttributeUpdate(Geometry *geometry, - RenderCommand *command) const + const RenderCommand *command) const { const auto attributeIds = geometry->attributes(); @@ -2295,17 +2312,6 @@ SubmissionContext *Renderer::submissionContext() const return m_submissionContext.data(); } -void Renderer::addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId) -{ - if (!m_pendingRenderCaptureSendRequests.contains(nodeId)) - m_pendingRenderCaptureSendRequests.push_back(nodeId); -} - -const QVector<Qt3DCore::QNodeId> Renderer::takePendingRenderCaptureSendRequests() -{ - return std::move(m_pendingRenderCaptureSendRequests); -} - // Returns a vector of jobs to be performed for dirty buffers // 1 dirty buffer == 1 job, all job can be performed in parallel QVector<Qt3DCore::QAspectJobPtr> Renderer::createRenderBufferJobs() const diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h index b1cd4aac5..e770b8280 100644 --- a/src/render/renderers/opengl/renderer/renderer_p.h +++ b/src/render/renderers/opengl/renderer/renderer_p.h @@ -71,7 +71,6 @@ #include <Qt3DRender/private/updateworldboundingvolumejob_p.h> #include <Qt3DRender/private/updatetreeenabledjob_p.h> #include <Qt3DRender/private/platformsurfacefilter_p.h> -#include <Qt3DRender/private/sendrendercapturejob_p.h> #include <Qt3DRender/private/sendbuffercapturejob_p.h> #include <Qt3DRender/private/genericlambdajob_p.h> #include <Qt3DRender/private/updatemeshtrianglelistjob_p.h> @@ -82,6 +81,7 @@ #include <Qt3DRender/private/texture_p.h> #include <Qt3DRender/private/glfence_p.h> #include <Qt3DRender/private/shaderbuilder_p.h> +#include <Qt3DRender/private/lightgatherer_p.h> #include <QHash> #include <QMatrix4x4> @@ -125,11 +125,9 @@ class QAbstractShapeMesh; struct GraphicsApiFilterData; class QSceneImporter; -#if QT_CONFIG(qt3d_profile_jobs) namespace Debug { class CommandExecuter; } -#endif namespace Render { @@ -158,6 +156,13 @@ typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr; using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; using SynchronizerPostFramePtr = GenericLambdaJobAndPostFramePtr<std::function<void ()>, std::function<void (Qt3DCore::QAspectManager *)>>; +template<typename T, typename ... Ts> +class FilterEntityByComponentJob; +template<typename T, typename ... Ts> +using FilterEntityByComponentJobPtr = QSharedPointer<FilterEntityByComponentJob<T, Ts...>>; +using ComputableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>; +using RenderableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>; + class Q_3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer { public: @@ -199,8 +204,9 @@ public: #if defined(QT_BUILD_INTERNAL) void clearDirtyBits(BackendNodeDirtySet changes) override; #endif - bool shouldRender() override; + bool shouldRender() const override; void skipNextFrame() override; + void jobsDone(Qt3DCore::QAspectManager *manager) override; QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() override; QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() override; @@ -225,8 +231,13 @@ public: inline SynchronizerPostFramePtr introspectShadersJob() const { return m_introspectShaderJob; } inline Qt3DCore::QAspectJobPtr bufferGathererJob() const { return m_bufferGathererJob; } inline Qt3DCore::QAspectJobPtr textureGathererJob() const { return m_textureGathererJob; } - inline Qt3DCore::QAspectJobPtr sendTextureChangesToFrontendJob() const { return m_sendTextureChangesToFrontendJob; } inline UpdateEntityLayersJobPtr updateEntityLayersJob() const { return m_updateEntityLayersJob; } + inline LightGathererPtr lightGathererJob() const { return m_lightGathererJob; } + inline RenderableEntityFilterPtr renderableEntityFilterJob() const { return m_renderableEntityFilterJob; } + inline ComputableEntityFilterPtr computableEntityFilterJob() const { return m_computableEntityFilterJob; } + inline SynchronizerJobPtr cacheLightJob() const { return m_cacheLightsJob; } + inline SynchronizerJobPtr cacheRenderableEntitiesJob() const { return m_cacheRenderableEntitiesJob; } + inline SynchronizerJobPtr cacheComputableEntitiesJob() const { return m_cacheComputableEntitiesJob; } Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const override; @@ -254,12 +265,12 @@ public: void prepareCommandsSubmission(const QVector<RenderView *> &renderViews); bool executeCommandsSubmission(const RenderView *rv); bool updateVAOWithAttributes(Geometry *geometry, - RenderCommand *command, + const RenderCommand *command, Shader *shader, bool forceUpdate); bool requiresVAOAttributeUpdate(Geometry *geometry, - RenderCommand *command) const; + const RenderCommand *command) const; void setOpenGLContext(QOpenGLContext *context) override; const GraphicsApiFilterData *contextInfo() const; @@ -270,9 +281,6 @@ public: QList<QPair<QObject*, QMouseEvent>> pendingPickingEvents() const; QList<QKeyEvent> pendingKeyEvents() const; - void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId); - const QVector<Qt3DCore::QNodeId> takePendingRenderCaptureSendRequests(); - void enqueueRenderView(RenderView *renderView, int submitOrder); bool isReadyToSubmit(); @@ -338,8 +346,8 @@ private: QAtomicInt m_exposed; struct DirtyBits { - BackendNodeDirtySet marked = 0; // marked dirty since last job build - BackendNodeDirtySet remaining = 0; // remaining dirty after jobs have finished + BackendNodeDirtySet marked; // marked dirty since last job build + BackendNodeDirtySet remaining; // remaining dirty after jobs have finished }; DirtyBits m_dirtyBits; @@ -362,13 +370,15 @@ private: CalculateBoundingVolumeJobPtr m_calculateBoundingVolumeJob; UpdateWorldBoundingVolumeJobPtr m_updateWorldBoundingVolumeJob; UpdateTreeEnabledJobPtr m_updateTreeEnabledJob; - SendRenderCaptureJobPtr m_sendRenderCaptureJob; SendBufferCaptureJobPtr m_sendBufferCaptureJob; UpdateSkinningPaletteJobPtr m_updateSkinningPaletteJob; UpdateLevelOfDetailJobPtr m_updateLevelOfDetailJob; UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob; FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob; UpdateEntityLayersJobPtr m_updateEntityLayersJob; + LightGathererPtr m_lightGathererJob; + RenderableEntityFilterPtr m_renderableEntityFilterJob; + ComputableEntityFilterPtr m_computableEntityFilterJob; QVector<Qt3DCore::QNodeId> m_pendingRenderCaptureSendRequests; @@ -381,11 +391,12 @@ private: SynchronizerJobPtr m_bufferGathererJob; SynchronizerJobPtr m_vaoGathererJob; SynchronizerJobPtr m_textureGathererJob; - SynchronizerPostFramePtr m_sendTextureChangesToFrontendJob; SynchronizerJobPtr m_sendSetFenceHandlesToFrontendJob; - SynchronizerJobPtr m_sendDisablesToFrontendJob; SynchronizerPostFramePtr m_introspectShaderJob; SynchronizerJobPtr m_syncLoadingJobs; + SynchronizerJobPtr m_cacheRenderableEntitiesJob; + SynchronizerJobPtr m_cacheComputableEntitiesJob; + SynchronizerJobPtr m_cacheLightsJob; void lookForAbandonedVaos(); void lookForDirtyBuffers(); @@ -395,18 +406,18 @@ private: void sendShaderChangesToFrontend(Qt3DCore::QAspectManager *manager); void sendTextureChangesToFrontend(Qt3DCore::QAspectManager *manager); void sendSetFenceHandlesToFrontend(); - void sendDisablesToFrontend(); + void sendDisablesToFrontend(Qt3DCore::QAspectManager *manager); QMutex m_abandonedVaosMutex; QVector<HVao> m_abandonedVaos; QVector<HBuffer> m_dirtyBuffers; - QVector<HBuffer> m_downloadableBuffers; + QVector<Qt3DCore::QNodeId> m_downloadableBuffers; QVector<HShader> m_dirtyShaders; QVector<HTexture> m_dirtyTextures; QVector<QPair<Texture::TextureUpdateInfo, Qt3DCore::QNodeIdVector>> m_updatedTextureProperties; QVector<QPair<Qt3DCore::QNodeId, GLFence>> m_updatedSetFences; - QVector<Qt3DCore::QNodeId> m_updatedDisables; + QVector<Qt3DCore::QNodeId> m_updatedDisableSubtreeEnablers; Qt3DCore::QNodeIdVector m_textureIdsToCleanup; QVector<ShaderBuilderUpdate> m_shaderBuilderUpdates; @@ -415,10 +426,7 @@ private: OffscreenSurfaceHelper *m_offscreenHelper; QMutex m_offscreenSurfaceMutex; -#if QT_CONFIG(qt3d_profile_jobs) QScopedPointer<Qt3DRender::Debug::CommandExecuter> m_commandExecuter; - friend class Qt3DRender::Debug::CommandExecuter; -#endif #ifdef QT_BUILD_INTERNAL friend class ::tst_Renderer; diff --git a/src/render/renderers/opengl/renderer/renderercache_p.h b/src/render/renderers/opengl/renderer/renderercache_p.h index 0e9c5d3cd..02fe4ff41 100644 --- a/src/render/renderers/opengl/renderer/renderercache_p.h +++ b/src/render/renderers/opengl/renderer/renderercache_p.h @@ -56,6 +56,7 @@ #include <Qt3DRender/private/entity_p.h> #include <Qt3DRender/private/renderviewjobutils_p.h> #include <Qt3DRender/private/lightsource_p.h> +#include <Qt3DRender/private/rendercommand_p.h> QT_BEGIN_NAMESPACE @@ -69,12 +70,16 @@ struct RendererCache { QVector<Entity *> filterEntitiesByLayer; MaterialParameterGathererData materialParameterGatherer; - QVector<LightSource> gatheredLights; - QVector<Entity *> renderableEntities; - QVector<Entity *> computeEntities; - EnvironmentLight* environmentLight; + EntityRenderCommandData renderCommandData; }; + // Shared amongst all RV cache + QVector<Entity *> renderableEntities; + QVector<Entity *> computeEntities; + QVector<LightSource> gatheredLights; + EnvironmentLight* environmentLight; + + // Per RV cache QHash<FrameGraphNode *, LeafNodeData> leafNodeCache; QMutex *mutex() { return &m_mutex; } diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index aa9f4d1a5..c00a92629 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -119,29 +119,29 @@ RenderView::StandardUniformsNameToTypeHash RenderView::initializeStandardUniform { RenderView::StandardUniformsNameToTypeHash setters; - setters.insert(StringToInt::lookupId(QLatin1String("modelMatrix")), ModelMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("viewMatrix")), ViewMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("projectionMatrix")), ProjectionMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("modelView")), ModelViewMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("viewProjectionMatrix")), ViewProjectionMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("modelViewProjection")), ModelViewProjectionMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("mvp")), ModelViewProjectionMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("inverseModelMatrix")), InverseModelMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("inverseViewMatrix")), InverseViewMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("inverseProjectionMatrix")), InverseProjectionMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("inverseModelView")), InverseModelViewMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("inverseViewProjectionMatrix")), InverseViewProjectionMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("inverseModelViewProjection")), InverseModelViewProjectionMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("modelNormalMatrix")), ModelNormalMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("modelViewNormal")), ModelViewNormalMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("viewportMatrix")), ViewportMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("inverseViewportMatrix")), InverseViewportMatrix); - setters.insert(StringToInt::lookupId(QLatin1String("aspectRatio")), AspectRatio); - setters.insert(StringToInt::lookupId(QLatin1String("exposure")), Exposure); - setters.insert(StringToInt::lookupId(QLatin1String("gamma")), Gamma); - setters.insert(StringToInt::lookupId(QLatin1String("time")), Time); - setters.insert(StringToInt::lookupId(QLatin1String("eyePosition")), EyePosition); - setters.insert(StringToInt::lookupId(QLatin1String("skinningPalette[0]")), SkinningPalette); + setters.insert(Shader::modelMatrixNameId, ModelMatrix); + setters.insert(Shader::viewMatrixNameId, ViewMatrix); + setters.insert(Shader::projectionMatrixNameId, ProjectionMatrix); + setters.insert(Shader::modelViewMatrixNameId, ModelViewMatrix); + setters.insert(Shader::viewProjectionMatrixNameId, ViewProjectionMatrix); + setters.insert(Shader::modelViewProjectionNameId, ModelViewProjectionMatrix); + setters.insert(Shader::mvpNameId, ModelViewProjectionMatrix); + setters.insert(Shader::inverseModelMatrixNameId, InverseModelMatrix); + setters.insert(Shader::inverseViewMatrixNameId, InverseViewMatrix); + setters.insert(Shader::inverseProjectionMatrixNameId, InverseProjectionMatrix); + setters.insert(Shader::inverseModelViewNameId, InverseModelViewMatrix); + setters.insert(Shader::inverseViewProjectionMatrixNameId, InverseViewProjectionMatrix); + setters.insert(Shader::inverseModelViewProjectionNameId, InverseModelViewProjectionMatrix); + setters.insert(Shader::modelNormalMatrixNameId, ModelNormalMatrix); + setters.insert(Shader::modelViewNormalNameId, ModelViewNormalMatrix); + setters.insert(Shader::viewportMatrixNameId, ViewportMatrix); + setters.insert(Shader::inverseViewportMatrixNameId, InverseViewportMatrix); + setters.insert(Shader::aspectRatioNameId, AspectRatio); + setters.insert(Shader::exposureNameId, Exposure); + setters.insert(Shader::gammaNameId, Gamma); + setters.insert(Shader::timeNameId, Time); + setters.insert(Shader::eyePositionNameId, EyePosition); + setters.insert(Shader::skinningPaletteNameId, SkinningPalette); return setters; } @@ -211,7 +211,7 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa return UniformValue(Matrix4x4(viewportMatrix.inverted())); } case AspectRatio: - return float(m_surfaceSize.width()) / float(m_surfaceSize.height()); + return float(m_surfaceSize.width()) / std::max(1.f, float(m_surfaceSize.height())); case Exposure: return UniformValue(m_data.m_renderCameraLens ? m_data.m_renderCameraLens->exposure() : 0.0f); case Gamma: @@ -238,11 +238,14 @@ RenderView::RenderView() : m_isDownloadBuffersEnable(false) , m_hasBlitFramebufferInfo(false) , m_renderer(nullptr) + , m_manager(nullptr) , m_devicePixelRatio(1.) - , m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f)) + , m_viewport(QRectF(0., 0., 1., 1.)) , m_gamma(2.2f) , m_surface(nullptr) , m_clearBuffer(QClearBuffers::None) + , m_clearDepthValue(1.f) + , m_clearStencilValue(0) , m_stateSet(nullptr) , m_noDraw(false) , m_compute(false) @@ -280,10 +283,6 @@ RenderView::RenderView() RenderView::~RenderView() { delete m_stateSet; - for (RenderCommand *command : qAsConst(m_commands)) { - delete command->m_stateSet; - delete command; - } } namespace { @@ -291,7 +290,7 @@ namespace { template<int SortType> struct AdjacentSubRangeFinder { - static bool adjacentSubRange(RenderCommand *, RenderCommand *) + static bool adjacentSubRange(const RenderCommand &, const RenderCommand &) { Q_UNREACHABLE(); return false; @@ -301,47 +300,47 @@ struct AdjacentSubRangeFinder template<> struct AdjacentSubRangeFinder<QSortPolicy::StateChangeCost> { - static bool adjacentSubRange(RenderCommand *a, RenderCommand *b) + static bool adjacentSubRange(const RenderCommand &a, const RenderCommand &b) { - return a->m_changeCost == b->m_changeCost; + return a.m_changeCost == b.m_changeCost; } }; template<> struct AdjacentSubRangeFinder<QSortPolicy::BackToFront> { - static bool adjacentSubRange(RenderCommand *a, RenderCommand *b) + static bool adjacentSubRange(const RenderCommand &a, const RenderCommand &b) { - return a->m_depth == b->m_depth; + return a.m_depth == b.m_depth; } }; template<> struct AdjacentSubRangeFinder<QSortPolicy::Material> { - static bool adjacentSubRange(RenderCommand *a, RenderCommand *b) + static bool adjacentSubRange(const RenderCommand &a, const RenderCommand &b) { - return a->m_shaderDna == b->m_shaderDna; + return a.m_shaderDna == b.m_shaderDna; } }; template<> struct AdjacentSubRangeFinder<QSortPolicy::FrontToBack> { - static bool adjacentSubRange(RenderCommand *a, RenderCommand *b) + static bool adjacentSubRange(const RenderCommand &a, const RenderCommand &b) { - return a->m_depth == b->m_depth; + return a.m_depth == b.m_depth; } }; template<> struct AdjacentSubRangeFinder<QSortPolicy::Texture> { - static bool adjacentSubRange(RenderCommand *a, RenderCommand *b) + static bool adjacentSubRange(const RenderCommand &a, const RenderCommand &b) { // Two renderCommands are adjacent if one contains all the other command's textures - QVector<ShaderParameterPack::NamedResource> texturesA = a->m_parameterPack.textures(); - QVector<ShaderParameterPack::NamedResource> texturesB = b->m_parameterPack.textures(); + QVector<ShaderParameterPack::NamedResource> texturesA = a.m_parameterPack.textures(); + QVector<ShaderParameterPack::NamedResource> texturesB = b.m_parameterPack.textures(); if (texturesB.size() > texturesA.size()) qSwap(texturesA, texturesB); @@ -356,7 +355,7 @@ struct AdjacentSubRangeFinder<QSortPolicy::Texture> }; template<typename Predicate> -int advanceUntilNonAdjacent(const QVector<RenderCommand *> &commands, +int advanceUntilNonAdjacent(const QVector<RenderCommand> &commands, const int beg, const int end, Predicate pred) { int i = beg + 1; @@ -369,7 +368,7 @@ int advanceUntilNonAdjacent(const QVector<RenderCommand *> &commands, } -using CommandIt = QVector<RenderCommand *>::iterator; +using CommandIt = QVector<RenderCommand>::iterator; template<int SortType> struct SubRangeSorter @@ -387,8 +386,8 @@ struct SubRangeSorter<QSortPolicy::StateChangeCost> { static void sortSubRange(CommandIt begin, const CommandIt end) { - std::stable_sort(begin, end, [] (RenderCommand *a, RenderCommand *b) { - return a->m_changeCost > b->m_changeCost; + std::stable_sort(begin, end, [] (const RenderCommand &a, const RenderCommand &b) { + return a.m_changeCost > b.m_changeCost; }); } }; @@ -398,8 +397,8 @@ struct SubRangeSorter<QSortPolicy::BackToFront> { static void sortSubRange(CommandIt begin, const CommandIt end) { - std::stable_sort(begin, end, [] (RenderCommand *a, RenderCommand *b) { - return a->m_depth > b->m_depth; + std::stable_sort(begin, end, [] (const RenderCommand &a, const RenderCommand &b) { + return a.m_depth > b.m_depth; }); } }; @@ -410,8 +409,8 @@ struct SubRangeSorter<QSortPolicy::Material> static void sortSubRange(CommandIt begin, const CommandIt end) { // First we sort by shaderDNA - std::stable_sort(begin, end, [] (RenderCommand *a, RenderCommand *b) { - return a->m_shaderDna > b->m_shaderDna; + std::stable_sort(begin, end, [] (const RenderCommand &a, const RenderCommand &b) { + return a.m_shaderDna > b.m_shaderDna; }); } }; @@ -421,8 +420,8 @@ struct SubRangeSorter<QSortPolicy::FrontToBack> { static void sortSubRange(CommandIt begin, const CommandIt end) { - std::stable_sort(begin, end, [] (RenderCommand *a, RenderCommand *b) { - return a->m_depth < b->m_depth; + std::stable_sort(begin, end, [] (const RenderCommand &a, const RenderCommand &b) { + return a.m_depth < b.m_depth; }); } }; @@ -432,9 +431,9 @@ struct SubRangeSorter<QSortPolicy::Texture> { static void sortSubRange(CommandIt begin, const CommandIt end) { - std::stable_sort(begin, end, [] (RenderCommand *a, RenderCommand *b) { - QVector<ShaderParameterPack::NamedResource> texturesA = a->m_parameterPack.textures(); - QVector<ShaderParameterPack::NamedResource> texturesB = b->m_parameterPack.textures(); + std::stable_sort(begin, end, [] (const RenderCommand &a, const RenderCommand &b) { + QVector<ShaderParameterPack::NamedResource> texturesA = a.m_parameterPack.textures(); + QVector<ShaderParameterPack::NamedResource> texturesB = b.m_parameterPack.textures(); const int originalTextureASize = texturesA.size(); @@ -453,7 +452,7 @@ struct SubRangeSorter<QSortPolicy::Texture> } }; -int findSubRange(const QVector<RenderCommand *> &commands, +int findSubRange(const QVector<RenderCommand> &commands, const int begin, const int end, const QSortPolicy::SortType sortType) { @@ -474,14 +473,14 @@ int findSubRange(const QVector<RenderCommand *> &commands, } } -void sortByMaterial(QVector<RenderCommand *> &commands, int begin, const int end) +void sortByMaterial(QVector<RenderCommand> &commands, int begin, const int end) { // We try to arrange elements so that their rendering cost is minimized for a given shader int rangeEnd = advanceUntilNonAdjacent(commands, begin, end, AdjacentSubRangeFinder<QSortPolicy::Material>::adjacentSubRange); while (begin != end) { if (begin + 1 < rangeEnd) { - std::stable_sort(commands.begin() + begin + 1, commands.begin() + rangeEnd, [] (RenderCommand *a, RenderCommand *b){ - return a->m_material.handle() < b->m_material.handle(); + std::stable_sort(commands.begin() + begin + 1, commands.begin() + rangeEnd, [] (const RenderCommand &a, const RenderCommand &b){ + return a.m_material.handle() < b.m_material.handle(); }); } begin = rangeEnd; @@ -489,7 +488,7 @@ void sortByMaterial(QVector<RenderCommand *> &commands, int begin, const int end } } -void sortCommandRange(QVector<RenderCommand *> &commands, int begin, const int end, const int level, +void sortCommandRange(QVector<RenderCommand> &commands, int begin, const int end, const int level, const QVector<Qt3DRender::QSortPolicy::SortType> &sortingTypes) { if (level >= sortingTypes.size()) @@ -539,24 +538,23 @@ void RenderView::sort() // Minimize uniform changes int i = 0; - while (i < m_commands.size()) { + const int commandSize = m_commands.size(); + while (i < commandSize) { int j = i; // Advance while commands share the same shader - while (i < m_commands.size() && m_commands[j]->m_shaderDna == m_commands[i]->m_shaderDna) + while (i < commandSize && m_commands[j].m_shaderDna == m_commands[i].m_shaderDna) ++i; if (i - j > 0) { // Several commands have the same shader, so we minimize uniform changes - PackUniformHash cachedUniforms = m_commands[j++]->m_parameterPack.uniforms(); + PackUniformHash cachedUniforms = m_commands[j++].m_parameterPack.uniforms(); while (j < i) { // We need the reference here as we are modifying the original container // not the copy - PackUniformHash &uniforms = m_commands.at(j)->m_parameterPack.m_uniforms; - PackUniformHash::iterator it = uniforms.begin(); - const PackUniformHash::iterator end = uniforms.end(); + PackUniformHash &uniforms = m_commands[j].m_parameterPack.m_uniforms; - while (it != end) { + for (int u = 0; u < uniforms.keys.size();) { // We are comparing the values: // - raw uniform values // - the texture Node id if the uniform represents a texture @@ -564,12 +562,17 @@ void RenderView::sort() // sharing the same material (shader) are rendered, we can't have the case // where two uniforms, referencing the same texture eventually have 2 different // texture unit values - const UniformValue refValue = cachedUniforms.value(it.key()); - if (it.value() == refValue) { - it = uniforms.erase(it); + const int uniformNameId = uniforms.keys.at(u); + const UniformValue &refValue = cachedUniforms.value(uniformNameId); + const UniformValue &newValue = uniforms.values.at(u); + if (newValue == refValue) { + uniforms.erase(u); } else { - cachedUniforms.insert(it.key(), it.value()); - ++it; + // Record updated value so that subsequent comparison + // for the next command will be made againts latest + // uniform value + cachedUniforms.insert(uniformNameId, newValue); + ++u; } } ++j; @@ -619,20 +622,16 @@ void RenderView::addClearBuffers(const ClearBuffers *cb) { } // If we are there, we know that entity had a GeometryRenderer + Material -QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entity *> &entities) const +EntityRenderCommandData RenderView::buildDrawRenderCommands(const QVector<Entity *> &entities, + int offset, int count) const { - // Note: since many threads can be building render commands - // we need to ensure that the UniformBlockValueBuilder they are using - // is only accessed from the same thread - UniformBlockValueBuilder *builder = new UniformBlockValueBuilder(); - builder->shaderDataManager = m_manager->shaderDataManager(); - builder->textureManager = m_manager->textureManager(); - m_localData.setLocalData(builder); + EntityRenderCommandData commands; - QVector<RenderCommand *> commands; - commands.reserve(entities.size()); + commands.reserve(count); - for (Entity *entity : entities) { + for (int i = 0; i < count; ++i) { + const int idx = offset + i; + Entity *entity = entities.at(idx); GeometryRenderer *geometryRenderer = nullptr; HGeometryRenderer geometryRendererHandle = entity->componentHandle<GeometryRenderer>(); @@ -645,135 +644,226 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit const HMaterial materialHandle = entity->componentHandle<Material>(); const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId); + HGeometry geometryHandle = m_manager->geometryManager()->lookupHandle(geometryRenderer->geometryId()); + Geometry *geometry = m_manager->geometryManager()->data(geometryHandle); + // 1 RenderCommand per RenderPass pass on an Entity with a Mesh for (const RenderPassParameterData &passData : renderPassData) { // Add the RenderPass Parameters - RenderCommand *command = new RenderCommand(); - command->m_geometryRenderer = geometryRendererHandle; - command->m_geometry = m_manager->geometryManager()->lookupHandle(geometryRenderer->geometryId()); - - // Project the camera-to-object-center vector onto the camera - // view vector. This gives a depth value suitable as the key - // for BackToFront sorting. - command->m_depth = Vector3D::dotProduct(entity->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir); - command->m_material = materialHandle; + RenderCommand command = {}; + command.m_geometryRenderer = geometryRendererHandle; + command.m_geometry = geometryHandle; + + command.m_material = materialHandle; // For RenderPass based states we use the globally set RenderState // if no renderstates are defined as part of the pass. That means: // RenderPass { renderStates: [] } will use the states defined by // StateSet in the FrameGraph RenderPass *pass = passData.pass; if (pass->hasRenderStates()) { - command->m_stateSet = new RenderStateSet(); - addStatesToRenderStateSet(command->m_stateSet, pass->renderStates(), m_manager->renderStateManager()); + command.m_stateSet = RenderStateSetPtr::create(); + addStatesToRenderStateSet(command.m_stateSet.data(), pass->renderStates(), m_manager->renderStateManager()); if (m_stateSet != nullptr) - command->m_stateSet->merge(m_stateSet); - command->m_changeCost = m_renderer->defaultRenderState()->changeCost(command->m_stateSet); + command.m_stateSet->merge(m_stateSet); + command.m_changeCost = m_renderer->defaultRenderState()->changeCost(command.m_stateSet.data()); } + command.m_shader = m_manager->lookupHandle<Shader, ShaderManager, HShader>(pass->shaderProgram()); + + { // Scoped to show extent + + // Update the draw command with what's going to be needed for the drawing + int primitiveCount = geometryRenderer->vertexCount(); + int estimatedCount = 0; + Attribute *indexAttribute = nullptr; + Attribute *indirectAttribute = nullptr; + + const QVector<Qt3DCore::QNodeId> attributeIds = geometry->attributes(); + for (Qt3DCore::QNodeId attributeId : attributeIds) { + Attribute *attribute = m_manager->attributeManager()->lookupResource(attributeId); + switch (attribute->attributeType()) { + case QAttribute::IndexAttribute: + indexAttribute = attribute; + break; + case QAttribute::DrawIndirectAttribute: + indirectAttribute = attribute; + break; + case QAttribute::VertexAttribute: + estimatedCount = std::max(int(attribute->count()), estimatedCount); + break; + default: + Q_UNREACHABLE(); + break; + } + } - // Pick which lights to take in to account. - // For now decide based on the distance by taking the MAX_LIGHTS closest lights. - // Replace with more sophisticated mechanisms later. - // Copy vector so that we can sort it concurrently and we only want to sort the one for the current command - QVector<LightSource> lightSources = m_lightSources; - if (lightSources.size() > 1) { - const Vector3D entityCenter = entity->worldBoundingVolume()->center(); - std::sort(lightSources.begin(), lightSources.end(), - [&] (const LightSource &a, const LightSource &b) { - const float distA = entityCenter.distanceToPoint(a.entity->worldBoundingVolume()->center()); - const float distB = entityCenter.distanceToPoint(b.entity->worldBoundingVolume()->center()); - return distA < distB; - }); - } + command.m_drawIndexed = (indexAttribute != nullptr); + command.m_drawIndirect = (indirectAttribute != nullptr); + + // Update the draw command with all the information required for the drawing + if (command.m_drawIndexed) { + command.m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType()); + command.m_indexAttributeByteOffset = indexAttribute->byteOffset() + geometryRenderer->indexBufferByteOffset(); + } + + // Note: we only care about the primitiveCount when using direct draw calls + // For indirect draw calls it is assumed the buffer was properly set already + if (command.m_drawIndirect) { + command.m_indirectAttributeByteOffset = indirectAttribute->byteOffset(); + command.m_indirectDrawBuffer = m_manager->bufferManager()->lookupHandle(indirectAttribute->bufferId()); + } else { + // Use the count specified by the GeometryRender + // If not specify use the indexAttribute count if present + // Otherwise tries to use the count from the attribute with the highest count + if (primitiveCount == 0) { + if (indexAttribute) + primitiveCount = indexAttribute->count(); + else + primitiveCount = estimatedCount; + } + } - ParameterInfoList globalParameters = passData.parameterInfo; - // setShaderAndUniforms can initialize a localData - // make sure this is cleared before we leave this function - setShaderAndUniforms(command, - pass, - globalParameters, - entity, - lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)), - m_environmentLight); - - commands.append(command); + command.m_primitiveCount = primitiveCount; + command.m_primitiveType = geometryRenderer->primitiveType(); + command.m_primitiveRestartEnabled = geometryRenderer->primitiveRestartEnabled(); + command.m_restartIndexValue = geometryRenderer->restartIndexValue(); + command.m_firstInstance = geometryRenderer->firstInstance(); + command.m_instanceCount = geometryRenderer->instanceCount(); + command.m_firstVertex = geometryRenderer->firstVertex(); + command.m_indexOffset = geometryRenderer->indexOffset(); + command.m_verticesPerPatch = geometryRenderer->verticesPerPatch(); + } // scope + + + commands.push_back(entity, + std::move(command), + std::move(passData)); } } } - // We reset the local data once we are done with it - m_localData.setLocalData(nullptr); - return commands; } -QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<Entity *> &entities) const +EntityRenderCommandData RenderView::buildComputeRenderCommands(const QVector<Entity *> &entities, + int offset, int count) const { - // Note: since many threads can be building render commands - // we need to ensure that the UniformBlockValueBuilder they are using - // is only accessed from the same thread - UniformBlockValueBuilder *builder = new UniformBlockValueBuilder(); - builder->shaderDataManager = m_manager->shaderDataManager(); - builder->textureManager = m_manager->textureManager(); - m_localData.setLocalData(builder); - // If the RenderView contains only a ComputeDispatch then it cares about // A ComputeDispatch is also implicitely a NoDraw operation // enabled flag // layer component // material/effect/technique/parameters/filters/ - QVector<RenderCommand *> commands; - commands.reserve(entities.size()); - for (Entity *entity : entities) { + EntityRenderCommandData commands; + + commands.reserve(count); + + for (int i = 0; i < count; ++i) { + const int idx = offset + i; + Entity *entity = entities.at(idx); ComputeCommand *computeJob = nullptr; - if ((computeJob = entity->renderComponent<ComputeCommand>()) != nullptr + HComputeCommand computeCommandHandle = entity->componentHandle<ComputeCommand>(); + if ((computeJob = nodeManagers()->computeJobManager()->data(computeCommandHandle)) != nullptr && computeJob->isEnabled()) { - // Note: if frameCount has reached 0 in the previous frame, isEnabled - // would be false - if (computeJob->runType() == QComputeCommand::Manual) - computeJob->updateFrameCount(); - const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>(); const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId); // 1 RenderCommand per RenderPass pass on an Entity with a Mesh for (const RenderPassParameterData &passData : renderPassData) { // Add the RenderPass Parameters - RenderCommand *command = new RenderCommand(); + RenderCommand command = {}; RenderPass *pass = passData.pass; if (pass->hasRenderStates()) { - command->m_stateSet = new RenderStateSet(); - addStatesToRenderStateSet(command->m_stateSet, pass->renderStates(), m_manager->renderStateManager()); + command.m_stateSet = RenderStateSetPtr::create(); + addStatesToRenderStateSet(command.m_stateSet.data(), pass->renderStates(), m_manager->renderStateManager()); // Merge per pass stateset with global stateset // so that the local stateset only overrides if (m_stateSet != nullptr) - command->m_stateSet->merge(m_stateSet); - command->m_changeCost = m_renderer->defaultRenderState()->changeCost(command->m_stateSet); + command.m_stateSet->merge(m_stateSet); + command.m_changeCost = m_renderer->defaultRenderState()->changeCost(command.m_stateSet.data()); } + command.m_shader = m_manager->lookupHandle<Shader, ShaderManager, HShader>(pass->shaderProgram()); + command.m_computeCommand = computeCommandHandle; + command.m_type = RenderCommand::Compute; + command.m_workGroups[0] = std::max(m_workGroups[0], computeJob->x()); + command.m_workGroups[1] = std::max(m_workGroups[1], computeJob->y()); + command.m_workGroups[2] = std::max(m_workGroups[2], computeJob->z()); + + commands.push_back(entity, + std::move(command), + std::move(passData)); + } + } + } - command->m_type = RenderCommand::Compute; - command->m_workGroups[0] = std::max(m_workGroups[0], computeJob->x()); - command->m_workGroups[1] = std::max(m_workGroups[1], computeJob->y()); - command->m_workGroups[2] = std::max(m_workGroups[2], computeJob->z()); - - ParameterInfoList globalParameters = passData.parameterInfo; - setShaderAndUniforms(command, - pass, - globalParameters, - entity, - QVector<LightSource>(), - nullptr); - commands.append(command); + return commands; +} + +void RenderView::updateRenderCommand(EntityRenderCommandData *renderCommandData, + int offset, + int count) +{ + // Note: since many threads can be building render commands + // we need to ensure that the UniformBlockValueBuilder they are using + // is only accessed from the same thread + UniformBlockValueBuilder *builder = new UniformBlockValueBuilder(); + builder->shaderDataManager = m_manager->shaderDataManager(); + builder->textureManager = m_manager->textureManager(); + m_localData.setLocalData(builder); + + for (int i = 0, m = count; i < m; ++i) { + const int idx = offset + i; + Entity *entity = renderCommandData->entities.at(idx); + const RenderPassParameterData passData = renderCommandData->passesData.at(idx); + RenderCommand &command = renderCommandData->commands[idx]; + + // Pick which lights to take in to account. + // For now decide based on the distance by taking the MAX_LIGHTS closest lights. + // Replace with more sophisticated mechanisms later. + // Copy vector so that we can sort it concurrently and we only want to sort the one for the current command + QVector<LightSource> lightSources; + EnvironmentLight *environmentLight = nullptr; + + if (command.m_type == RenderCommand::Draw) { + // Project the camera-to-object-center vector onto the camera + // view vector. This gives a depth value suitable as the key + // for BackToFront sorting. + command.m_depth = Vector3D::dotProduct(entity->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir); + + environmentLight = m_environmentLight; + lightSources = m_lightSources; + + if (lightSources.size() > 1) { + const Vector3D entityCenter = entity->worldBoundingVolume()->center(); + std::sort(lightSources.begin(), lightSources.end(), + [&] (const LightSource &a, const LightSource &b) { + const float distA = entityCenter.distanceToPoint(a.entity->worldBoundingVolume()->center()); + const float distB = entityCenter.distanceToPoint(b.entity->worldBoundingVolume()->center()); + return distA < distB; + }); } + lightSources = lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)); + } else { // Compute + // Note: if frameCount has reached 0 in the previous frame, isEnabled + // would be false + ComputeCommand *computeJob = m_manager->computeJobManager()->data(command.m_computeCommand); + if (computeJob->runType() == QComputeCommand::Manual) + computeJob->updateFrameCount(); } + + ParameterInfoList globalParameters = passData.parameterInfo; + // setShaderAndUniforms can initialize a localData + // make sure this is cleared before we leave this function + setShaderAndUniforms(&command, + globalParameters, + entity, + lightSources, + environmentLight); } // We reset the local data once we are done with it m_localData.setLocalData(nullptr); - - return commands; } void RenderView::updateMatrices() @@ -908,7 +998,6 @@ void RenderView::setDefaultUniformBlockShaderDataValue(ShaderParameterPack &unif } void RenderView::setShaderAndUniforms(RenderCommand *command, - RenderPass *rPass, ParameterInfoList ¶meters, Entity *entity, const QVector<LightSource> &activeLightSources, @@ -924,163 +1013,163 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, // For each ParameterBinder in the RenderPass -> create a QUniformPack // Once that works, improve that to try and minimize QUniformPack updates - if (rPass != nullptr) { - // Index Shader by Shader UUID - command->m_shader = m_manager->lookupHandle<Shader, ShaderManager, HShader>(rPass->shaderProgram()); - Shader *shader = m_manager->data<Shader, ShaderManager>(command->m_shader); - if (shader != nullptr && shader->isLoaded()) { - command->m_shaderDna = shader->dna(); - - // Builds the QUniformPack, sets shader standard uniforms and store attributes name / glname bindings - // If a parameter is defined and not found in the bindings it is assumed to be a binding of Uniform type with the glsl name - // equals to the parameter name - const QVector<int> uniformNamesIds = shader->uniformsNamesIds(); - const QVector<int> uniformBlockNamesIds = shader->uniformBlockNamesIds(); - const QVector<int> shaderStorageBlockNamesIds = shader->storageBlockNamesIds(); - const QVector<int> attributeNamesIds = shader->attributeNamesIds(); - - // Set fragData Name and index - // Later on we might want to relink the shader if attachments have changed - // But for now we set them once and for all + // Index Shader by Shader UUID + Shader *shader = m_manager->data<Shader, ShaderManager>(command->m_shader); + if (shader != nullptr && shader->isLoaded()) { + command->m_shaderDna = shader->dna(); + + // Builds the QUniformPack, sets shader standard uniforms and store attributes name / glname bindings + // If a parameter is defined and not found in the bindings it is assumed to be a binding of Uniform type with the glsl name + // equals to the parameter name + const QVector<int> uniformNamesIds = shader->uniformsNamesIds(); + const QVector<int> standardUniformNamesIds = shader->standardUniformNameIds(); + const QVector<int> uniformBlockNamesIds = shader->uniformBlockNamesIds(); + const QVector<int> shaderStorageBlockNamesIds = shader->storageBlockNamesIds(); + const QVector<int> attributeNamesIds = shader->attributeNamesIds(); + + // Set fragData Name and index + // Later on we might want to relink the shader if attachments have changed + // But for now we set them once and for all + if (!m_renderTarget.isNull() && !shader->isLoaded()) { QHash<QString, int> fragOutputs; - if (!m_renderTarget.isNull() && !shader->isLoaded()) { - const auto atts = m_attachmentPack.attachments(); - for (const Attachment &att : atts) { - if (att.m_point <= QRenderTargetOutput::Color15) - fragOutputs.insert(att.m_name, att.m_point); - } + const auto atts = m_attachmentPack.attachments(); + for (const Attachment &att : atts) { + if (att.m_point <= QRenderTargetOutput::Color15) + fragOutputs.insert(att.m_name, att.m_point); } + // Set frag outputs in the shaders if hash not empty + if (!fragOutputs.isEmpty()) + shader->setFragOutputs(fragOutputs); + } - if (!uniformNamesIds.isEmpty() || !attributeNamesIds.isEmpty() || - !shaderStorageBlockNamesIds.isEmpty() || !attributeNamesIds.isEmpty()) { - - // Set default standard uniforms without bindings - const Matrix4x4 worldTransform = *(entity->worldTransform()); - for (const int uniformNameId : uniformNamesIds) { - if (ms_standardUniformSetters.contains(uniformNameId)) - setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, entity, worldTransform); - } - - // Set default attributes - for (const int attributeNameId : attributeNamesIds) - command->m_activeAttributes.push_back(attributeNameId); - - // Parameters remaining could be - // -> uniform scalar / vector - // -> uniform struct / arrays - // -> uniform block / array (4.3) - // -> ssbo block / array (4.3) - - ParameterInfoList::const_iterator it = parameters.cbegin(); - const ParameterInfoList::const_iterator parametersEnd = parameters.cend(); - - while (it != parametersEnd) { - Parameter *param = m_manager->data<Parameter, ParameterManager>(it->handle); - const UniformValue &uniformValue = param->uniformValue(); - if (uniformNamesIds.contains(it->nameId)) { // Parameter is a regular uniform - setUniformValue(command->m_parameterPack, it->nameId, uniformValue); - } else if (uniformBlockNamesIds.indexOf(it->nameId) != -1) { // Parameter is a uniform block - setUniformBlockValue(command->m_parameterPack, shader, shader->uniformBlockForBlockNameId(it->nameId), uniformValue); - } else if (shaderStorageBlockNamesIds.indexOf(it->nameId) != -1) { // Parameters is a SSBO - setShaderStorageValue(command->m_parameterPack, shader, shader->storageBlockForBlockNameId(it->nameId), uniformValue); - } else { // Parameter is a struct - ShaderData *shaderData = nullptr; - if (uniformValue.valueType() == UniformValue::NodeId && - (shaderData = m_manager->shaderDataManager()->lookupResource(*uniformValue.constData<Qt3DCore::QNodeId>())) != nullptr) { - // Try to check if we have a struct or array matching a QShaderData parameter - setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, StringToInt::lookupString(it->nameId)); - } - // Otherwise: param unused by current shader + if (!uniformNamesIds.isEmpty() || !standardUniformNamesIds.isEmpty() || + !attributeNamesIds.isEmpty() || + !shaderStorageBlockNamesIds.isEmpty() || !attributeNamesIds.isEmpty()) { + + // Set default standard uniforms without bindings + const Matrix4x4 worldTransform = *(entity->worldTransform()); + + for (const int uniformNameId : standardUniformNamesIds) + setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, entity, worldTransform); + + // Set default attributes + command->m_activeAttributes = attributeNamesIds; + + // At this point we know whether the command is a valid draw command or not + // We still need to process the uniforms as the command could be a compute command + command->m_isValid = !command->m_activeAttributes.empty(); + + // Parameters remaining could be + // -> uniform scalar / vector + // -> uniform struct / arrays + // -> uniform block / array (4.3) + // -> ssbo block / array (4.3) + + ParameterInfoList::const_iterator it = parameters.cbegin(); + const ParameterInfoList::const_iterator parametersEnd = parameters.cend(); + + while (it != parametersEnd) { + Parameter *param = m_manager->data<Parameter, ParameterManager>(it->handle); + const UniformValue &uniformValue = param->uniformValue(); + if (uniformNamesIds.contains(it->nameId)) { // Parameter is a regular uniform + setUniformValue(command->m_parameterPack, it->nameId, uniformValue); + } else if (uniformBlockNamesIds.indexOf(it->nameId) != -1) { // Parameter is a uniform block + setUniformBlockValue(command->m_parameterPack, shader, shader->uniformBlockForBlockNameId(it->nameId), uniformValue); + } else if (shaderStorageBlockNamesIds.indexOf(it->nameId) != -1) { // Parameters is a SSBO + setShaderStorageValue(command->m_parameterPack, shader, shader->storageBlockForBlockNameId(it->nameId), uniformValue); + } else { // Parameter is a struct + ShaderData *shaderData = nullptr; + if (uniformValue.valueType() == UniformValue::NodeId && + (shaderData = m_manager->shaderDataManager()->lookupResource(*uniformValue.constData<Qt3DCore::QNodeId>())) != nullptr) { + // Try to check if we have a struct or array matching a QShaderData parameter + setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, StringToInt::lookupString(it->nameId)); } - ++it; + // Otherwise: param unused by current shader } + ++it; + } - // Lights - - int lightIdx = 0; - for (const LightSource &lightSource : activeLightSources) { - if (lightIdx == MAX_LIGHTS) - break; - Entity *lightEntity = lightSource.entity; - const Vector3D worldPos = lightEntity->worldBoundingVolume()->center(); - for (Light *light : lightSource.lights) { - if (!light->isEnabled()) - continue; - - ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(light->shaderData()); - if (!shaderData) - continue; + // Lights - if (lightIdx == MAX_LIGHTS) - break; + int lightIdx = 0; + for (const LightSource &lightSource : activeLightSources) { + if (lightIdx == MAX_LIGHTS) + break; + Entity *lightEntity = lightSource.entity; + const Matrix4x4 lightWorldTransform = *(lightEntity->worldTransform()); + const Vector3D worldPos = lightWorldTransform * Vector3D(0.0f, 0.0f, 0.0f); + for (Light *light : lightSource.lights) { + if (!light->isEnabled()) + continue; - // Note: implicit conversion of values to UniformValue - setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[lightIdx], worldPos); - setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[lightIdx], int(QAbstractLight::PointLight)); - setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[lightIdx], Vector3D(1.0f, 1.0f, 1.0f)); - setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[lightIdx], 0.5f); - - setUniformValue(command->m_parameterPack, LIGHT_POSITION_UNROLL_NAMES[lightIdx], worldPos); - setUniformValue(command->m_parameterPack, LIGHT_TYPE_UNROLL_NAMES[lightIdx], int(QAbstractLight::PointLight)); - setUniformValue(command->m_parameterPack, LIGHT_COLOR_UNROLL_NAMES[lightIdx], Vector3D(1.0f, 1.0f, 1.0f)); - setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_UNROLL_NAMES[lightIdx], 0.5f); - - // There is no risk in doing that even if multithreaded - // since we are sure that a shaderData is unique for a given light - // and won't ever be referenced as a Component either - Matrix4x4 *worldTransform = lightEntity->worldTransform(); - if (worldTransform) - shaderData->updateWorldTransform(*worldTransform); - - setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, LIGHT_STRUCT_NAMES[lightIdx]); - setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, LIGHT_STRUCT_UNROLL_NAMES[lightIdx]); - ++lightIdx; - } - } + ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(light->shaderData()); + if (!shaderData) + continue; - if (uniformNamesIds.contains(LIGHT_COUNT_NAME_ID)) - setUniformValue(command->m_parameterPack, LIGHT_COUNT_NAME_ID, UniformValue(qMax((environmentLight ? 0 : 1), lightIdx))); + if (lightIdx == MAX_LIGHTS) + break; - // If no active light sources and no environment light, add a default light - if (activeLightSources.isEmpty() && !environmentLight) { // Note: implicit conversion of values to UniformValue - setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[0], Vector3D(10.0f, 10.0f, 0.0f)); - setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[0], int(QAbstractLight::PointLight)); - setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], Vector3D(1.0f, 1.0f, 1.0f)); - setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[0], 0.5f); - - setUniformValue(command->m_parameterPack, LIGHT_POSITION_UNROLL_NAMES[0], Vector3D(10.0f, 10.0f, 0.0f)); - setUniformValue(command->m_parameterPack, LIGHT_TYPE_UNROLL_NAMES[0], int(QAbstractLight::PointLight)); - setUniformValue(command->m_parameterPack, LIGHT_COLOR_UNROLL_NAMES[0], Vector3D(1.0f, 1.0f, 1.0f)); - setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_UNROLL_NAMES[0], 0.5f); + setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[lightIdx], worldPos); + setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[lightIdx], int(QAbstractLight::PointLight)); + setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[lightIdx], Vector3D(1.0f, 1.0f, 1.0f)); + setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[lightIdx], 0.5f); + + setUniformValue(command->m_parameterPack, LIGHT_POSITION_UNROLL_NAMES[lightIdx], worldPos); + setUniformValue(command->m_parameterPack, LIGHT_TYPE_UNROLL_NAMES[lightIdx], int(QAbstractLight::PointLight)); + setUniformValue(command->m_parameterPack, LIGHT_COLOR_UNROLL_NAMES[lightIdx], Vector3D(1.0f, 1.0f, 1.0f)); + setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_UNROLL_NAMES[lightIdx], 0.5f); + + + // There is no risk in doing that even if multithreaded + // since we are sure that a shaderData is unique for a given light + // and won't ever be referenced as a Component either + Matrix4x4 *worldTransform = lightEntity->worldTransform(); + if (worldTransform) + shaderData->updateWorldTransform(*worldTransform); + + setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, LIGHT_STRUCT_NAMES[lightIdx]); + setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, LIGHT_STRUCT_UNROLL_NAMES[lightIdx]); + ++lightIdx; } + } - // Environment Light - int envLightCount = 0; - if (environmentLight && environmentLight->isEnabled()) { - ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(environmentLight->shaderData()); - if (shaderData) { - setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight")); - envLightCount = 1; - } - } else { - // with some drivers, samplers (like the envbox sampler) need to be bound even though - // they may not be actually used, otherwise draw calls can fail - static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight.irradiance")); - static const int specularId = StringToInt::lookupId(QLatin1String("envLight.specular")); - setUniformValue(command->m_parameterPack, irradianceId, m_renderer->submissionContext()->maxTextureUnitsCount()); - setUniformValue(command->m_parameterPack, specularId, m_renderer->submissionContext()->maxTextureUnitsCount()); + if (uniformNamesIds.contains(LIGHT_COUNT_NAME_ID)) + setUniformValue(command->m_parameterPack, LIGHT_COUNT_NAME_ID, UniformValue(qMax((environmentLight ? 0 : 1), lightIdx))); + + // If no active light sources and no environment light, add a default light + if (activeLightSources.isEmpty() && !environmentLight) { + // Note: implicit conversion of values to UniformValue + setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[0], Vector3D(10.0f, 10.0f, 0.0f)); + setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[0], int(QAbstractLight::PointLight)); + setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], Vector3D(1.0f, 1.0f, 1.0f)); + setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[0], 0.5f); + + setUniformValue(command->m_parameterPack, LIGHT_POSITION_UNROLL_NAMES[0], Vector3D(10.0f, 10.0f, 0.0f)); + setUniformValue(command->m_parameterPack, LIGHT_TYPE_UNROLL_NAMES[0], int(QAbstractLight::PointLight)); + setUniformValue(command->m_parameterPack, LIGHT_COLOR_UNROLL_NAMES[0], Vector3D(1.0f, 1.0f, 1.0f)); + setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_UNROLL_NAMES[0], 0.5f); + } + + // Environment Light + int envLightCount = 0; + if (environmentLight && environmentLight->isEnabled()) { + ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(environmentLight->shaderData()); + if (shaderData) { + setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight")); + envLightCount = 1; } - setUniformValue(command->m_parameterPack, StringToInt::lookupId(QStringLiteral("envLightCount")), envLightCount); + } else { + // with some drivers, samplers (like the envbox sampler) need to be bound even though + // they may not be actually used, otherwise draw calls can fail + static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight.irradiance")); + static const int specularId = StringToInt::lookupId(QLatin1String("envLight.specular")); + setUniformValue(command->m_parameterPack, irradianceId, m_renderer->submissionContext()->maxTextureUnitsCount()); + setUniformValue(command->m_parameterPack, specularId, m_renderer->submissionContext()->maxTextureUnitsCount()); } - // Set frag outputs in the shaders if hash not empty - if (!fragOutputs.isEmpty()) - shader->setFragOutputs(fragOutputs); + setUniformValue(command->m_parameterPack, StringToInt::lookupId(QStringLiteral("envLightCount")), envLightCount); } } - else { - qCWarning(Render::Backend) << Q_FUNC_INFO << "Using default effect as none was provided"; - } } bool RenderView::hasBlitFramebufferInfo() const diff --git a/src/render/renderers/opengl/renderer/renderview_p.h b/src/render/renderers/opengl/renderer/renderview_p.h index 7ebcdb6bd..c7dc37a2c 100644 --- a/src/render/renderers/opengl/renderer/renderview_p.h +++ b/src/render/renderers/opengl/renderer/renderview_p.h @@ -227,10 +227,19 @@ public: RenderPassList passesAndParameters(ParameterInfoList *parameter, Entity *node, bool useDefaultMaterials = true); - QVector<RenderCommand *> buildDrawRenderCommands(const QVector<Entity *> &entities) const; - QVector<RenderCommand *> buildComputeRenderCommands(const QVector<Entity *> &entities) const; - void setCommands(QVector<RenderCommand *> &commands) Q_DECL_NOTHROW { m_commands = commands; } - QVector<RenderCommand *> commands() const Q_DECL_NOTHROW { return m_commands; } + EntityRenderCommandData buildDrawRenderCommands(const QVector<Entity *> &entities, + int offset, int count) const; + EntityRenderCommandData buildComputeRenderCommands(const QVector<Entity *> &entities, + int offset, int count) const; + + + void updateRenderCommand(EntityRenderCommandData *renderCommandData, + int offset, int count); + + + void setCommands(const QVector<RenderCommand> &commands) Q_DECL_NOTHROW { m_commands = commands; } + QVector<RenderCommand> &commands() { return m_commands; } + QVector<RenderCommand> commands() const { return m_commands; } void setAttachmentPack(const AttachmentPack &pack) { m_attachmentPack = pack; } const AttachmentPack &attachmentPack() const { return m_attachmentPack; } @@ -291,7 +300,6 @@ public: private: void setShaderAndUniforms(RenderCommand *command, - RenderPass *pass, ParameterInfoList ¶meters, Entity *entity, const QVector<LightSource> &activeLightSources, @@ -331,10 +339,7 @@ private: QVector<Qt3DCore::QNodeId> m_insertFenceIds; QVector<QWaitFenceData> m_waitFences; - // We do not use pointers to RenderNodes or Drawable's here so that the - // render aspect is free to change the drawables on the next frame whilst - // the render thread is submitting these commands. - QVector<RenderCommand *> m_commands; + QVector<RenderCommand> m_commands; mutable QVector<LightSource> m_lightSources; EnvironmentLight *m_environmentLight; diff --git a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp index 83fab301a..8f1b17119 100644 --- a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp +++ b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp @@ -50,18 +50,73 @@ namespace Render { // In some cases having less jobs is better (especially on fast cpus where // splitting just adds more overhead). Ideally, we should try to set the value // depending on the platform/CPU/nbr of cores -const int RenderViewBuilder::m_optimalParallelJobCount = std::max(std::min(4, QThread::idealThreadCount()), 2); +const int RenderViewBuilder::m_optimalParallelJobCount = QThread::idealThreadCount(); namespace { -class SyncRenderViewCommandBuilders +int findIdealNumberOfWorkers(int elementCount, int packetSize = 100) +{ + if (elementCount == 0 || packetSize == 0) + return 0; + return std::min(std::max(elementCount / packetSize, 1), RenderViewBuilder::optimalJobCount()); +} + + +class SyncPreCommandBuilding { public: - explicit SyncRenderViewCommandBuilders(const RenderViewInitializerJobPtr &renderViewJob, - const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs, - Renderer *renderer) + explicit SyncPreCommandBuilding(RenderViewInitializerJobPtr renderViewInitializerJob, + const QVector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs, + Renderer *renderer, + FrameGraphNode *leafNode) + : m_renderViewInitializer(renderViewInitializerJob) + , m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs) + , m_renderer(renderer) + , m_leafNode(leafNode) + { + } + + void operator()() + { + // Split commands to build among jobs + QMutexLocker lock(m_renderer->cache()->mutex()); + // Rebuild RenderCommands for all entities in RV (ignoring filtering) + RendererCache *cache = m_renderer->cache(); + const RendererCache::LeafNodeData &dataCacheForLeaf = cache->leafNodeCache[m_leafNode]; + RenderView *rv = m_renderViewInitializer->renderView(); + const auto entities = !rv->isCompute() ? cache->renderableEntities : cache->computeEntities; + + rv->setMaterialParameterTable(dataCacheForLeaf.materialParameterGatherer); + + lock.unlock(); + + // Split among the ideal number of command builders + const int idealPacketSize = std::min(std::max(100, entities.size() / RenderViewBuilder::optimalJobCount()), entities.size()); + // Try to split work into an ideal number of workers + const int m = findIdealNumberOfWorkers(entities.size(), idealPacketSize); + + for (int i = 0; i < m; ++i) { + const RenderViewCommandBuilderJobPtr renderViewCommandBuilder = m_renderViewCommandBuilderJobs.at(i); + const int count = (i == m - 1) ? entities.size() - (i * idealPacketSize) : idealPacketSize; + renderViewCommandBuilder->setEntities(entities, i * idealPacketSize, count); + } + } + +private: + RenderViewInitializerJobPtr m_renderViewInitializer; + QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs; + Renderer *m_renderer; + FrameGraphNode *m_leafNode; +}; + +class SyncRenderViewPostCommandUpdate +{ +public: + explicit SyncRenderViewPostCommandUpdate(const RenderViewInitializerJobPtr &renderViewJob, + const QVector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdateJobs, + Renderer *renderer) : m_renderViewJob(renderViewJob) - , m_renderViewBuilderJobs(renderViewBuilderJobs) + , m_renderViewCommandUpdaterJobs(renderViewCommandUpdateJobs) , m_renderer(renderer) {} @@ -70,20 +125,16 @@ public: // Append all the commands and sort them RenderView *rv = m_renderViewJob->renderView(); - int totalCommandCount = 0; - for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) - totalCommandCount += renderViewCommandBuilder->commands().size(); - - QVector<RenderCommand *> commands; - commands.reserve(totalCommandCount); + const EntityRenderCommandDataPtr commandData = m_renderViewCommandUpdaterJobs.first()->renderables(); - // Reduction - for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) - commands += std::move(renderViewCommandBuilder->commands()); - rv->setCommands(commands); + if (commandData) { + const QVector<RenderCommand> commands = std::move(commandData->commands); + rv->setCommands(commands); - // Sort the commands - rv->sort(); + // TO DO: Find way to store commands once or at least only when required + // Sort the commands + rv->sort(); + } // Enqueue our fully populated RenderView with the RenderThread m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex()); @@ -91,15 +142,15 @@ public: private: RenderViewInitializerJobPtr m_renderViewJob; - QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; + QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs; Renderer *m_renderer; }; -class SyncFrustumCulling +class SyncPreFrustumCulling { public: - explicit SyncFrustumCulling(const RenderViewInitializerJobPtr &renderViewJob, - const FrustumCullingJobPtr &frustumCulling) + explicit SyncPreFrustumCulling(const RenderViewInitializerJobPtr &renderViewJob, + const FrustumCullingJobPtr &frustumCulling) : m_renderViewJob(renderViewJob) , m_frustumCullingJob(frustumCulling) {} @@ -120,21 +171,23 @@ private: FrustumCullingJobPtr m_frustumCullingJob; }; -class SyncRenderViewInitialization +class SyncRenderViewPostInitialization { public: - explicit SyncRenderViewInitialization(const RenderViewInitializerJobPtr &renderViewJob, - const FrustumCullingJobPtr &frustumCullingJob, - const FilterLayerEntityJobPtr &filterEntityByLayerJob, - const FilterProximityDistanceJobPtr &filterProximityJob, - const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs, - const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs) + explicit SyncRenderViewPostInitialization(const RenderViewInitializerJobPtr &renderViewJob, + const FrustumCullingJobPtr &frustumCullingJob, + const FilterLayerEntityJobPtr &filterEntityByLayerJob, + const FilterProximityDistanceJobPtr &filterProximityJob, + const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs, + const QVector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs, + const QVector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs) : m_renderViewJob(renderViewJob) , m_frustumCullingJob(frustumCullingJob) , m_filterEntityByLayerJob(filterEntityByLayerJob) , m_filterProximityJob(filterProximityJob) , m_materialGathererJobs(materialGathererJobs) - , m_renderViewBuilderJobs(renderViewBuilderJobs) + , m_renderViewCommandUpdaterJobs(renderViewCommandUpdaterJobs) + , m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs) {} void operator()() @@ -154,8 +207,10 @@ public: materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter())); } - // Command builders - for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) + // Command builders and updates + for (const auto &renderViewCommandUpdater : qAsConst(m_renderViewCommandUpdaterJobs)) + renderViewCommandUpdater->setRenderView(rv); + for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs)) renderViewCommandBuilder->setRenderView(rv); // Set whether frustum culling is enabled or not @@ -168,26 +223,31 @@ private: FilterLayerEntityJobPtr m_filterEntityByLayerJob; FilterProximityDistanceJobPtr m_filterProximityJob; QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs; - QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; + QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs; + QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs; }; -class SyncRenderCommandBuilding +class SyncRenderViewPreCommandUpdate { public: - explicit SyncRenderCommandBuilding(const RenderViewInitializerJobPtr &renderViewJob, - const FrustumCullingJobPtr &frustumCullingJob, - const FilterProximityDistanceJobPtr &filterProximityJob, - const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs, - const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs, - Renderer *renderer, - FrameGraphNode *leafNode) + explicit SyncRenderViewPreCommandUpdate(const RenderViewInitializerJobPtr &renderViewJob, + const FrustumCullingJobPtr &frustumCullingJob, + const FilterProximityDistanceJobPtr &filterProximityJob, + const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs, + const QVector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs, + const QVector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs, + Renderer *renderer, + FrameGraphNode *leafNode, + bool fullCommandRebuild) : m_renderViewJob(renderViewJob) , m_frustumCullingJob(frustumCullingJob) , m_filterProximityJob(filterProximityJob) , m_materialGathererJobs(materialGathererJobs) - , m_renderViewBuilderJobs(renderViewBuilderJobs) + , m_renderViewCommandUpdaterJobs(renderViewCommandUpdaterJobs) + , m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs) , m_renderer(renderer) , m_leafNode(leafNode) + , m_fullRebuild(fullCommandRebuild) {} void operator()() @@ -197,21 +257,44 @@ public: RenderView *rv = m_renderViewJob->renderView(); if (!rv->noDraw()) { - QVector<Entity *> renderableEntities; - const bool isDraw = !rv->isCompute(); - QMutexLocker lock(m_renderer->cache()->mutex()); - const auto& cacheData = m_renderer->cache()->leafNodeCache.value(m_leafNode); + ///////// CACHE LOCKED //////////// + // Retrieve Data from Cache + RendererCache *cache = m_renderer->cache(); + QMutexLocker lock(cache->mutex()); + Q_ASSERT(cache->leafNodeCache.contains(m_leafNode)); - if (isDraw) - renderableEntities = cacheData.renderableEntities; - else - renderableEntities = cacheData.computeEntities; - - const QVector<Entity *> filteredEntities = cacheData.filterEntitiesByLayer; - QVector<LightSource> lightSources = cacheData.gatheredLights; - rv->setEnvironmentLight(cacheData.environmentLight); + const bool isDraw = !rv->isCompute(); + const RendererCache::LeafNodeData &dataCacheForLeaf = cache->leafNodeCache[m_leafNode]; + + // Rebuild RenderCommands if required + // This should happen fairly infrequently (FrameGraph Change, Geometry/Material change) + // and allow to skip that step most of the time + if (m_fullRebuild) { + EntityRenderCommandData commandData; + // Reduction + { + int totalCommandCount = 0; + for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs)) + totalCommandCount += renderViewCommandBuilder->commandData().size(); + commandData.reserve(totalCommandCount); + for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs)) + commandData += std::move(renderViewCommandBuilder->commandData()); + } + + + // Store new cache + RendererCache::LeafNodeData &writableCacheForLeaf = cache->leafNodeCache[m_leafNode]; + writableCacheForLeaf.renderCommandData = std::move(commandData); + } + const EntityRenderCommandData commandData = dataCacheForLeaf.renderCommandData; + const QVector<Entity *> filteredEntities = dataCacheForLeaf.filterEntitiesByLayer; + QVector<Entity *> renderableEntities = isDraw ? cache->renderableEntities : cache->computeEntities; + QVector<LightSource> lightSources = cache->gatheredLights; + rv->setMaterialParameterTable(dataCacheForLeaf.materialParameterGatherer); + rv->setEnvironmentLight(cache->environmentLight); lock.unlock(); + ///////// END OF CACHE LOCKED //////////// // Filter out entities that weren't selected by the layer filters // Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector @@ -229,22 +312,52 @@ public: if (rv->frustumCulling()) renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities, m_frustumCullingJob->visibleEntities()); // Filter out entities which didn't satisfy proximity filtering - renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities, m_filterProximityJob->filteredEntities()); + if (!rv->proximityFilterIds().empty()) + renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities, m_filterProximityJob->filteredEntities()); } - // Split among the number of command builders - int i = 0; - const int m = RenderViewBuilder::optimalJobCount() - 1; - const int packetSize = renderableEntities.size() / RenderViewBuilder::optimalJobCount(); - while (i < m) { - const RenderViewBuilderJobPtr renderViewCommandBuilder = m_renderViewBuilderJobs.at(i); - renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize)); - ++i; + // Early return in case we have nothing to filter + if (renderableEntities.size() == 0) + return; + + // Filter out Render commands for which the Entity wasn't selected because + // of frustum, proximity or layer filtering + EntityRenderCommandDataPtr filteredCommandData = EntityRenderCommandDataPtr::create(); + filteredCommandData->reserve(renderableEntities.size()); + // Because dataCacheForLeaf.renderableEntities or computeEntities are sorted + // What we get out of EntityRenderCommandData is also sorted by Entity + auto eIt = std::cbegin(renderableEntities); + const auto eEnd = std::cend(renderableEntities); + int cIt = 0; + const int cEnd = commandData.size(); + + while (eIt != eEnd) { + const Entity *targetEntity = *eIt; + // Advance until we have commands whose Entity has a lower address + // than the selected filtered entity + while (cIt != cEnd && commandData.entities.at(cIt) < targetEntity) + ++cIt; + + // Push pointers to command data for all commands that match the + // entity + while (cIt != cEnd && commandData.entities.at(cIt) == targetEntity) { + filteredCommandData->push_back(commandData.entities.at(cIt), + commandData.commands.at(cIt), + commandData.passesData.at(cIt)); + ++cIt; + } + ++eIt; } - m_renderViewBuilderJobs.at(i)->setRenderables(renderableEntities.mid(i * packetSize, packetSize + renderableEntities.size() % (m + 1))); - { - QMutexLocker rendererCacheLock(m_renderer->cache()->mutex()); - rv->setMaterialParameterTable(m_renderer->cache()->leafNodeCache.value(m_leafNode).materialParameterGatherer); + + // Split among the number of command builders + // The idealPacketSize is at least 100 entities per worker + const int idealPacketSize = std::min(std::max(100, filteredCommandData->size() / RenderViewBuilder::optimalJobCount()), filteredCommandData->size()); + const int m = findIdealNumberOfWorkers(filteredCommandData->size(), idealPacketSize); + + for (int i = 0; i < m; ++i) { + const RenderViewCommandUpdaterJobPtr renderViewCommandBuilder = m_renderViewCommandUpdaterJobs.at(i); + const int count = (i == m - 1) ? filteredCommandData->size() - (i * idealPacketSize) : idealPacketSize; + renderViewCommandBuilder->setRenderables(filteredCommandData, i * idealPacketSize, count); } } } @@ -254,9 +367,11 @@ private: FrustumCullingJobPtr m_frustumCullingJob; FilterProximityDistanceJobPtr m_filterProximityJob; QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs; - QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; + QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs; + QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs; Renderer *m_renderer; FrameGraphNode *m_leafNode; + bool m_fullRebuild; }; class SetClearDrawBufferIndex @@ -335,84 +450,6 @@ private: FrameGraphNode *m_leafNode; }; -class SyncLightsGatherer -{ -public: - explicit SyncLightsGatherer(LightGathererPtr gatherJob, - Renderer *renderer, - FrameGraphNode *leafNode) - : m_gatherJob(gatherJob) - , m_renderer(renderer) - , m_leafNode(leafNode) - { - } - - void operator()() - { - QMutexLocker lock(m_renderer->cache()->mutex()); - RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; - dataCacheForLeaf.gatheredLights = m_gatherJob->lights(); - dataCacheForLeaf.environmentLight = m_gatherJob->takeEnvironmentLight(); - } - -private: - LightGathererPtr m_gatherJob; - Renderer *m_renderer; - FrameGraphNode *m_leafNode; -}; - -class SyncRenderableEntities -{ -public: - explicit SyncRenderableEntities(RenderableEntityFilterPtr gatherJob, - Renderer *renderer, - FrameGraphNode *leafNode) - : m_gatherJob(gatherJob) - , m_renderer(renderer) - , m_leafNode(leafNode) - { - } - - void operator()() - { - QMutexLocker lock(m_renderer->cache()->mutex()); - RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; - dataCacheForLeaf.renderableEntities = m_gatherJob->filteredEntities(); - std::sort(dataCacheForLeaf.renderableEntities.begin(), dataCacheForLeaf.renderableEntities.end()); - } - -private: - RenderableEntityFilterPtr m_gatherJob; - Renderer *m_renderer; - FrameGraphNode *m_leafNode; -}; - -class SyncComputableEntities -{ -public: - explicit SyncComputableEntities(ComputableEntityFilterPtr gatherJob, - Renderer *renderer, - FrameGraphNode *leafNode) - : m_gatherJob(gatherJob) - , m_renderer(renderer) - , m_leafNode(leafNode) - { - } - - void operator()() - { - QMutexLocker lock(m_renderer->cache()->mutex()); - RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; - dataCacheForLeaf.computeEntities = m_gatherJob->filteredEntities(); - std::sort(dataCacheForLeaf.computeEntities.begin(), dataCacheForLeaf.computeEntities.end()); - } - -private: - ComputableEntityFilterPtr m_gatherJob; - Renderer *m_renderer; - FrameGraphNode *m_leafNode; -}; - } // anonymous RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer) @@ -421,13 +458,11 @@ RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int rende , m_renderer(renderer) , m_layerCacheNeedsToBeRebuilt(false) , m_materialGathererCacheNeedsToBeRebuilt(false) - , m_lightsCacheNeedsToBeRebuilt(false) - , m_renderableCacheNeedsToBeRebuilt(false) - , m_computableCacheNeedsToBeRebuilt(false) + , m_renderCommandCacheNeedsToBeRebuilt(false) , m_renderViewJob(RenderViewInitializerJobPtr::create()) , m_filterEntityByLayerJob() , m_frustumCullingJob(new Render::FrustumCullingJob()) - , m_syncFrustumCullingJob(SynchronizerJobPtr::create(SyncFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling)) + , m_syncPreFrustumCullingJob(SynchronizerJobPtr::create(SyncPreFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling)) , m_setClearDrawBufferIndexJob(SynchronizerJobPtr::create(SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex)) , m_syncFilterEntityByLayerJob() , m_filterProximityJob(Render::FilterProximityDistanceJobPtr::create()) @@ -444,54 +479,49 @@ FilterLayerEntityJobPtr RenderViewBuilder::filterEntityByLayerJob() const return m_filterEntityByLayerJob; } -LightGathererPtr RenderViewBuilder::lightGathererJob() const -{ - return m_lightGathererJob; -} - -RenderableEntityFilterPtr RenderViewBuilder::renderableEntityFilterJob() const +FrustumCullingJobPtr RenderViewBuilder::frustumCullingJob() const { - return m_renderableEntityFilterJob; + return m_frustumCullingJob; } -ComputableEntityFilterPtr RenderViewBuilder::computableEntityFilterJob() const +QVector<RenderViewCommandUpdaterJobPtr> RenderViewBuilder::renderViewCommandUpdaterJobs() const { - return m_computableEntityFilterJob; + return m_renderViewCommandUpdaterJobs; } -FrustumCullingJobPtr RenderViewBuilder::frustumCullingJob() const +QVector<RenderViewCommandBuilderJobPtr> RenderViewBuilder::renderViewCommandBuilderJobs() const { - return m_frustumCullingJob; + return m_renderViewCommandBuilderJobs; } -QVector<RenderViewBuilderJobPtr> RenderViewBuilder::renderViewBuilderJobs() const +QVector<MaterialParameterGathererJobPtr> RenderViewBuilder::materialGathererJobs() const { - return m_renderViewBuilderJobs; + return m_materialGathererJobs; } -QVector<MaterialParameterGathererJobPtr> RenderViewBuilder::materialGathererJobs() const +SynchronizerJobPtr RenderViewBuilder::syncRenderViewPostInitializationJob() const { - return m_materialGathererJobs; + return m_syncRenderViewPostInitializationJob; } -SynchronizerJobPtr RenderViewBuilder::syncRenderViewInitializationJob() const +SynchronizerJobPtr RenderViewBuilder::syncPreFrustumCullingJob() const { - return m_syncRenderViewInitializationJob; + return m_syncPreFrustumCullingJob; } -SynchronizerJobPtr RenderViewBuilder::syncFrustumCullingJob() const +SynchronizerJobPtr RenderViewBuilder::syncRenderViewPreCommandBuildingJob() const { - return m_syncFrustumCullingJob; + return m_syncRenderViewPreCommandBuildingJob; } -SynchronizerJobPtr RenderViewBuilder::syncRenderCommandBuildingJob() const +SynchronizerJobPtr RenderViewBuilder::syncRenderViewPreCommandUpdateJob() const { - return m_syncRenderCommandBuildingJob; + return m_syncRenderViewPreCommandUpdateJob; } -SynchronizerJobPtr RenderViewBuilder::syncRenderViewCommandBuildersJob() const +SynchronizerJobPtr RenderViewBuilder::syncRenderViewPostCommandUpdateJob() const { - return m_syncRenderViewCommandBuildersJob; + return m_syncRenderViewPostCommandUpdateJob; } SynchronizerJobPtr RenderViewBuilder::setClearDrawBufferIndexJob() const @@ -517,37 +547,21 @@ FilterProximityDistanceJobPtr RenderViewBuilder::filterProximityJob() const void RenderViewBuilder::prepareJobs() { // Init what we can here - EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager(); m_filterProximityJob->setManager(m_renderer->nodeManagers()); m_frustumCullingJob->setRoot(m_renderer->sceneRoot()); - if (m_lightsCacheNeedsToBeRebuilt) { - m_lightGathererJob = Render::LightGathererPtr::create(); - m_lightGathererJob->setManager(entityManager); - - m_cacheLightsJob = SynchronizerJobPtr::create(SyncLightsGatherer(m_lightGathererJob, m_renderer, m_leafNode), - JobTypes::EntityComponentTypeFiltering); - m_cacheLightsJob->addDependency(m_lightGathererJob); - } - - if (m_renderableCacheNeedsToBeRebuilt) { - m_renderableEntityFilterJob = RenderableEntityFilterPtr::create(); - m_renderableEntityFilterJob->setManager(entityManager); - - m_cacheRenderableEntitiesJob = SynchronizerJobPtr::create( - SyncRenderableEntities(m_renderableEntityFilterJob, m_renderer, m_leafNode), - JobTypes::EntityComponentTypeFiltering); - m_cacheRenderableEntitiesJob->addDependency(m_renderableEntityFilterJob); - } - - if (m_computableCacheNeedsToBeRebuilt) { - m_computableEntityFilterJob = ComputableEntityFilterPtr::create(); - m_computableEntityFilterJob->setManager(entityManager); + if (m_renderCommandCacheNeedsToBeRebuilt) { - m_cacheComputableEntitiesJob = SynchronizerJobPtr::create( - SyncComputableEntities(m_computableEntityFilterJob, m_renderer, m_leafNode), - JobTypes::EntityComponentTypeFiltering); - m_cacheComputableEntitiesJob->addDependency(m_computableEntityFilterJob); + m_renderViewCommandBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); + for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { + auto renderViewCommandBuilder = Render::RenderViewCommandBuilderJobPtr::create(); + m_renderViewCommandBuilderJobs.push_back(renderViewCommandBuilder); + } + m_syncRenderViewPreCommandBuildingJob = SynchronizerJobPtr::create(SyncPreCommandBuilding(m_renderViewJob, + m_renderViewCommandBuilderJobs, + m_renderer, + m_leafNode), + JobTypes::SyncRenderViewPreCommandBuilding); } m_renderViewJob->setRenderer(m_renderer); @@ -556,12 +570,11 @@ void RenderViewBuilder::prepareJobs() // RenderCommand building is the most consuming task -> split it // Estimate the number of jobs to create based on the number of entities - m_renderViewBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); + m_renderViewCommandUpdaterJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { - auto renderViewCommandBuilder = Render::RenderViewBuilderJobPtr::create(); - renderViewCommandBuilder->setIndex(m_renderViewIndex); - renderViewCommandBuilder->setRenderer(m_renderer); - m_renderViewBuilderJobs.push_back(renderViewCommandBuilder); + auto renderViewCommandUpdater = Render::RenderViewCommandUpdaterJobPtr::create(); + renderViewCommandUpdater->setRenderer(m_renderer); + m_renderViewCommandUpdaterJobs.push_back(renderViewCommandUpdater); } if (m_materialGathererCacheNeedsToBeRebuilt) { @@ -582,7 +595,7 @@ void RenderViewBuilder::prepareJobs() m_syncMaterialGathererJob = SynchronizerJobPtr::create(SyncMaterialParameterGatherer(m_materialGathererJobs, m_renderer, m_leafNode), - JobTypes::SyncMaterialGatherer); + JobTypes::SyncMaterialGatherer); } if (m_layerCacheNeedsToBeRebuilt) { @@ -594,34 +607,37 @@ void RenderViewBuilder::prepareJobs() JobTypes::SyncFilterEntityByLayer); } - m_syncRenderCommandBuildingJob = SynchronizerJobPtr::create(SyncRenderCommandBuilding(m_renderViewJob, - m_frustumCullingJob, - m_filterProximityJob, - m_materialGathererJobs, - m_renderViewBuilderJobs, - m_renderer, - m_leafNode), - JobTypes::SyncRenderViewCommandBuilding); - - m_syncRenderViewCommandBuildersJob = SynchronizerJobPtr::create(SyncRenderViewCommandBuilders(m_renderViewJob, - m_renderViewBuilderJobs, - m_renderer), - JobTypes::SyncRenderViewCommandBuilder); - - m_syncRenderViewInitializationJob = SynchronizerJobPtr::create(SyncRenderViewInitialization(m_renderViewJob, - m_frustumCullingJob, - m_filterEntityByLayerJob, - m_filterProximityJob, - m_materialGathererJobs, - m_renderViewBuilderJobs), - JobTypes::SyncRenderViewInitialization); + m_syncRenderViewPreCommandUpdateJob = SynchronizerJobPtr::create(SyncRenderViewPreCommandUpdate(m_renderViewJob, + m_frustumCullingJob, + m_filterProximityJob, + m_materialGathererJobs, + m_renderViewCommandUpdaterJobs, + m_renderViewCommandBuilderJobs, + m_renderer, + m_leafNode, + m_renderCommandCacheNeedsToBeRebuilt), + JobTypes::SyncRenderViewPreCommandUpdate); + + m_syncRenderViewPostCommandUpdateJob = SynchronizerJobPtr::create(SyncRenderViewPostCommandUpdate(m_renderViewJob, + m_renderViewCommandUpdaterJobs, + m_renderer), + JobTypes::SyncRenderViewPostCommandUpdate); + + m_syncRenderViewPostInitializationJob = SynchronizerJobPtr::create(SyncRenderViewPostInitialization(m_renderViewJob, + m_frustumCullingJob, + m_filterEntityByLayerJob, + m_filterProximityJob, + m_materialGathererJobs, + m_renderViewCommandUpdaterJobs, + m_renderViewCommandBuilderJobs), + JobTypes::SyncRenderViewInitialization); } QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const { QVector<Qt3DCore::QAspectJobPtr> jobs; - jobs.reserve(m_materialGathererJobs.size() + m_renderViewBuilderJobs.size() + 11); + jobs.reserve(m_materialGathererJobs.size() + m_renderViewCommandUpdaterJobs.size() + 11); // Set dependencies @@ -629,97 +645,97 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const // TODO: Maybe only update skinning palettes for non-culled entities m_renderViewJob->addDependency(m_renderer->updateSkinningPaletteJob()); - m_syncFrustumCullingJob->addDependency(m_renderer->updateWorldTransformJob()); - m_syncFrustumCullingJob->addDependency(m_renderer->updateShaderDataTransformJob()); - m_syncFrustumCullingJob->addDependency(m_syncRenderViewInitializationJob); + m_syncPreFrustumCullingJob->addDependency(m_renderer->updateWorldTransformJob()); + m_syncPreFrustumCullingJob->addDependency(m_renderer->updateShaderDataTransformJob()); + m_syncPreFrustumCullingJob->addDependency(m_syncRenderViewPostInitializationJob); m_frustumCullingJob->addDependency(m_renderer->expandBoundingVolumeJob()); - m_frustumCullingJob->addDependency(m_syncFrustumCullingJob); + m_frustumCullingJob->addDependency(m_syncPreFrustumCullingJob); - m_setClearDrawBufferIndexJob->addDependency(m_syncRenderViewInitializationJob); + m_setClearDrawBufferIndexJob->addDependency(m_syncRenderViewPostInitializationJob); - m_syncRenderViewInitializationJob->addDependency(m_renderViewJob); + m_syncRenderViewPostInitializationJob->addDependency(m_renderViewJob); m_filterProximityJob->addDependency(m_renderer->expandBoundingVolumeJob()); - m_filterProximityJob->addDependency(m_syncRenderViewInitializationJob); + m_filterProximityJob->addDependency(m_syncRenderViewPostInitializationJob); - m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob); - m_syncRenderCommandBuildingJob->addDependency(m_filterProximityJob); - m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_syncRenderViewPostInitializationJob); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_filterProximityJob); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_frustumCullingJob); // Ensure the RenderThread won't be able to process dirtyResources // before they have been completely gathered - m_syncRenderCommandBuildingJob->addDependency(m_renderer->introspectShadersJob()); - m_syncRenderCommandBuildingJob->addDependency(m_renderer->bufferGathererJob()); - m_syncRenderCommandBuildingJob->addDependency(m_renderer->textureGathererJob()); - - for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) { - renderViewCommandBuilder->addDependency(m_syncRenderCommandBuildingJob); - m_syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->introspectShadersJob()); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->bufferGathererJob()); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->textureGathererJob()); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->cacheLightJob()); + + for (const auto &renderViewCommandUpdater : qAsConst(m_renderViewCommandUpdaterJobs)) { + renderViewCommandUpdater->addDependency(m_syncRenderViewPreCommandUpdateJob); + m_syncRenderViewPostCommandUpdateJob->addDependency(renderViewCommandUpdater); } - m_renderer->frameCleanupJob()->addDependency(m_syncRenderViewCommandBuildersJob); + m_renderer->frameCleanupJob()->addDependency(m_syncRenderViewPostCommandUpdateJob); m_renderer->frameCleanupJob()->addDependency(m_setClearDrawBufferIndexJob); // Add jobs jobs.push_back(m_renderViewJob); // Step 1 - if (m_lightsCacheNeedsToBeRebuilt) { - jobs.push_back(m_lightGathererJob); // Step 1 - jobs.push_back(m_cacheLightsJob); - m_syncRenderCommandBuildingJob->addDependency(m_cacheLightsJob); - } + jobs.push_back(m_syncRenderViewPostInitializationJob); // Step 2 - if (m_renderableCacheNeedsToBeRebuilt) { - jobs.push_back(m_renderableEntityFilterJob); // Step 1 - jobs.push_back(m_cacheRenderableEntitiesJob); - m_syncRenderCommandBuildingJob->addDependency(m_cacheRenderableEntitiesJob); - } + if (m_renderCommandCacheNeedsToBeRebuilt) { // Step 3 + m_syncRenderViewPreCommandBuildingJob->addDependency(m_renderer->cacheComputableEntitiesJob()); + m_syncRenderViewPreCommandBuildingJob->addDependency(m_renderer->cacheRenderableEntitiesJob()); + m_syncRenderViewPreCommandBuildingJob->addDependency(m_syncRenderViewPostInitializationJob); - if (m_computableCacheNeedsToBeRebuilt) { - // Note: do it only if OpenGL 4.3+ available - jobs.push_back(m_computableEntityFilterJob); // Step 1 - jobs.push_back(m_cacheComputableEntitiesJob); - m_syncRenderCommandBuildingJob->addDependency(m_cacheComputableEntitiesJob); - } + if (m_materialGathererCacheNeedsToBeRebuilt) + m_syncRenderViewPreCommandBuildingJob->addDependency(m_syncMaterialGathererJob); + + jobs.push_back(m_syncRenderViewPreCommandBuildingJob); - jobs.push_back(m_syncRenderViewInitializationJob); // Step 2 + for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs)) { + renderViewCommandBuilder->addDependency(m_syncRenderViewPreCommandBuildingJob); + m_syncRenderViewPreCommandUpdateJob->addDependency(renderViewCommandBuilder); + jobs.push_back(renderViewCommandBuilder); + } + } if (m_layerCacheNeedsToBeRebuilt) { m_filterEntityByLayerJob->addDependency(m_renderer->updateEntityLayersJob()); - m_filterEntityByLayerJob->addDependency(m_syncRenderViewInitializationJob); + m_filterEntityByLayerJob->addDependency(m_syncRenderViewPostInitializationJob); m_filterEntityByLayerJob->addDependency(m_renderer->updateTreeEnabledJob()); m_syncFilterEntityByLayerJob->addDependency(m_filterEntityByLayerJob); - m_syncRenderCommandBuildingJob->addDependency(m_syncFilterEntityByLayerJob); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_syncFilterEntityByLayerJob); jobs.push_back(m_filterEntityByLayerJob); // Step 3 jobs.push_back(m_syncFilterEntityByLayerJob); // Step 4 } - jobs.push_back(m_syncFrustumCullingJob); // Step 3 + jobs.push_back(m_syncPreFrustumCullingJob); // Step 3 jobs.push_back(m_filterProximityJob); // Step 3 jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3 if (m_materialGathererCacheNeedsToBeRebuilt) { for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) { - materialGatherer->addDependency(m_syncRenderViewInitializationJob); + materialGatherer->addDependency(m_syncRenderViewPostInitializationJob); materialGatherer->addDependency(m_renderer->introspectShadersJob()); materialGatherer->addDependency(m_renderer->filterCompatibleTechniqueJob()); jobs.push_back(materialGatherer); // Step3 m_syncMaterialGathererJob->addDependency(materialGatherer); } - m_syncRenderCommandBuildingJob->addDependency(m_syncMaterialGathererJob); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_syncMaterialGathererJob); jobs.push_back(m_syncMaterialGathererJob); // Step 3 } jobs.push_back(m_frustumCullingJob); // Step 4 - jobs.push_back(m_syncRenderCommandBuildingJob); // Step 5 + jobs.push_back(m_syncRenderViewPreCommandUpdateJob); // Step 5 - for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 6 + // Build RenderCommands or Update RenderCommand Uniforms + for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandUpdaterJobs)) // Step 6 jobs.push_back(renderViewCommandBuilder); - jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 7 + jobs.push_back(m_syncRenderViewPostCommandUpdateJob); // Step 7 return jobs; } @@ -754,34 +770,14 @@ bool RenderViewBuilder::materialGathererCacheNeedsToBeRebuilt() const return m_materialGathererCacheNeedsToBeRebuilt; } -void RenderViewBuilder::setRenderableCacheNeedsToBeRebuilt(bool needsToBeRebuilt) -{ - m_renderableCacheNeedsToBeRebuilt = needsToBeRebuilt; -} - -bool RenderViewBuilder::renderableCacheNeedsToBeRebuilt() const -{ - return m_renderableCacheNeedsToBeRebuilt; -} - -void RenderViewBuilder::setComputableCacheNeedsToBeRebuilt(bool needsToBeRebuilt) -{ - m_computableCacheNeedsToBeRebuilt = needsToBeRebuilt; -} - -bool RenderViewBuilder::computableCacheNeedsToBeRebuilt() const -{ - return m_computableCacheNeedsToBeRebuilt; -} - -void RenderViewBuilder::setLightGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt) +void RenderViewBuilder::setRenderCommandCacheNeedsToBeRebuilt(bool needsToBeRebuilt) { - m_lightsCacheNeedsToBeRebuilt = needsToBeRebuilt; + m_renderCommandCacheNeedsToBeRebuilt = needsToBeRebuilt; } -bool RenderViewBuilder::lightGathererCacheNeedsToBeRebuilt() const +bool RenderViewBuilder::renderCommandCacheNeedsToBeRebuilt() const { - return m_lightsCacheNeedsToBeRebuilt; + return m_renderCommandCacheNeedsToBeRebuilt; } int RenderViewBuilder::optimalJobCount() diff --git a/src/render/renderers/opengl/renderer/renderviewbuilder_p.h b/src/render/renderers/opengl/renderer/renderviewbuilder_p.h index e223a5f1e..a2ab80e7e 100644 --- a/src/render/renderers/opengl/renderer/renderviewbuilder_p.h +++ b/src/render/renderers/opengl/renderer/renderviewbuilder_p.h @@ -53,15 +53,14 @@ #include <functional> #include <Qt3DCore/qaspectjob.h> -#include <Qt3DRender/private/filterentitybycomponentjob_p.h> #include <Qt3DRender/private/filterlayerentityjob_p.h> #include <Qt3DRender/private/genericlambdajob_p.h> #include <Qt3DRender/private/materialparametergathererjob_p.h> #include <Qt3DRender/private/nodemanagers_p.h> -#include <Qt3DRender/private/renderviewbuilderjob_p.h> +#include <Qt3DRender/private/renderviewcommandbuilderjob_p.h> +#include <Qt3DRender/private/renderviewcommandupdaterjob_p.h> #include <Qt3DRender/private/renderview_p.h> #include <Qt3DRender/private/frustumcullingjob_p.h> -#include <Qt3DRender/private/lightgatherer_p.h> #include <Qt3DRender/private/filterproximitydistancejob_p.h> QT_BEGIN_NAMESPACE @@ -73,8 +72,6 @@ namespace Render { class Renderer; using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; -using ComputableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>; -using RenderableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>; class Q_AUTOTEST_EXPORT RenderViewBuilder { @@ -83,16 +80,15 @@ public: RenderViewInitializerJobPtr renderViewJob() const; FilterLayerEntityJobPtr filterEntityByLayerJob() const; - LightGathererPtr lightGathererJob() const; - RenderableEntityFilterPtr renderableEntityFilterJob() const; - ComputableEntityFilterPtr computableEntityFilterJob() const; FrustumCullingJobPtr frustumCullingJob() const; - QVector<RenderViewBuilderJobPtr> renderViewBuilderJobs() const; + QVector<RenderViewCommandBuilderJobPtr> renderViewCommandBuilderJobs() const; + QVector<RenderViewCommandUpdaterJobPtr> renderViewCommandUpdaterJobs() const; QVector<MaterialParameterGathererJobPtr> materialGathererJobs() const; - SynchronizerJobPtr syncRenderViewInitializationJob() const; - SynchronizerJobPtr syncFrustumCullingJob() const; - SynchronizerJobPtr syncRenderCommandBuildingJob() const; - SynchronizerJobPtr syncRenderViewCommandBuildersJob() const; + SynchronizerJobPtr syncRenderViewPostInitializationJob() const; + SynchronizerJobPtr syncPreFrustumCullingJob() const; + SynchronizerJobPtr syncRenderViewPreCommandBuildingJob() const; + SynchronizerJobPtr syncRenderViewPreCommandUpdateJob() const; + SynchronizerJobPtr syncRenderViewPostCommandUpdateJob() const; SynchronizerJobPtr setClearDrawBufferIndexJob() const; SynchronizerJobPtr syncFilterEntityByLayerJob() const; FilterProximityDistanceJobPtr filterProximityJob() const; @@ -108,15 +104,8 @@ public: bool layerCacheNeedsToBeRebuilt() const; void setMaterialGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt); bool materialGathererCacheNeedsToBeRebuilt() const; - - void setRenderableCacheNeedsToBeRebuilt(bool needsToBeRebuilt); - bool renderableCacheNeedsToBeRebuilt() const; - - void setComputableCacheNeedsToBeRebuilt(bool needsToBeRebuilt); - bool computableCacheNeedsToBeRebuilt() const; - - void setLightGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt); - bool lightGathererCacheNeedsToBeRebuilt() const; + void setRenderCommandCacheNeedsToBeRebuilt(bool needsToBeRebuilt); + bool renderCommandCacheNeedsToBeRebuilt() const; static int optimalJobCount(); static QVector<Entity *> entitiesInSubset(const QVector<Entity *> &entities, const QVector<Entity *> &subset); @@ -127,32 +116,25 @@ private: Renderer *m_renderer; bool m_layerCacheNeedsToBeRebuilt; bool m_materialGathererCacheNeedsToBeRebuilt; - bool m_lightsCacheNeedsToBeRebuilt; - bool m_renderableCacheNeedsToBeRebuilt; - bool m_computableCacheNeedsToBeRebuilt; + bool m_renderCommandCacheNeedsToBeRebuilt; RenderViewInitializerJobPtr m_renderViewJob; FilterLayerEntityJobPtr m_filterEntityByLayerJob; - LightGathererPtr m_lightGathererJob; - RenderableEntityFilterPtr m_renderableEntityFilterJob; - ComputableEntityFilterPtr m_computableEntityFilterJob; FrustumCullingJobPtr m_frustumCullingJob; - QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; + QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs; + QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs; QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs; - SynchronizerJobPtr m_syncRenderViewInitializationJob; - SynchronizerJobPtr m_syncFrustumCullingJob; - SynchronizerJobPtr m_syncRenderCommandBuildingJob; - SynchronizerJobPtr m_syncRenderViewCommandBuildersJob; + SynchronizerJobPtr m_syncRenderViewPostInitializationJob; + SynchronizerJobPtr m_syncPreFrustumCullingJob; + SynchronizerJobPtr m_syncRenderViewPreCommandBuildingJob; + SynchronizerJobPtr m_syncRenderViewPreCommandUpdateJob; + SynchronizerJobPtr m_syncRenderViewPostCommandUpdateJob; SynchronizerJobPtr m_setClearDrawBufferIndexJob; SynchronizerJobPtr m_syncFilterEntityByLayerJob; SynchronizerJobPtr m_syncMaterialGathererJob; FilterProximityDistanceJobPtr m_filterProximityJob; - SynchronizerJobPtr m_cacheRenderableEntitiesJob; - SynchronizerJobPtr m_cacheComputableEntitiesJob; - SynchronizerJobPtr m_cacheLightsJob; - static const int m_optimalParallelJobCount; }; diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack.cpp b/src/render/renderers/opengl/renderer/shaderparameterpack.cpp index 13d05cac1..1cfb59343 100644 --- a/src/render/renderers/opengl/renderer/shaderparameterpack.cpp +++ b/src/render/renderers/opengl/renderer/shaderparameterpack.cpp @@ -57,7 +57,6 @@ namespace Render { ShaderParameterPack::~ShaderParameterPack() { - m_uniforms.clear(); } void ShaderParameterPack::setUniform(const int glslNameId, const UniformValue &val) diff --git a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h index a5aee6ac4..cb599124c 100644 --- a/src/render/renderers/opengl/renderer/shaderparameterpack_p.h +++ b/src/render/renderers/opengl/renderer/shaderparameterpack_p.h @@ -89,7 +89,56 @@ struct BlockToSSBO { QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, BlockToSSBO, Q_PRIMITIVE_TYPE) -typedef QHash<int, UniformValue> PackUniformHash; +struct PackUniformHash +{ + QVector<int> keys; + QVector<UniformValue> values; + + PackUniformHash() + { + keys.reserve(10); + values.reserve(10); + } + + void insert(int key, const UniformValue &value) + { + const int idx = keys.indexOf(key); + if (idx != -1) { + values[idx] = value; + } else { + keys.push_back(key); + values.push_back(value); + } + } + + UniformValue value(int key) const + { + const int idx = keys.indexOf(key); + if (idx != -1) + return values.at(idx); + return UniformValue(); + } + + UniformValue& value(int key) + { + const int idx = keys.indexOf(key); + if (idx != -1) + return values[idx]; + insert(key, UniformValue()); + return value(key); + } + + void erase(int idx) + { + keys.removeAt(idx); + values.removeAt(idx); + } + + bool contains(int key) const + { + return keys.contains(key); + } +}; class Q_AUTOTEST_EXPORT ShaderParameterPack { diff --git a/src/render/renderers/opengl/textures/gltexture.cpp b/src/render/renderers/opengl/textures/gltexture.cpp index 1b5a972ec..20e6007a0 100644 --- a/src/render/renderers/opengl/textures/gltexture.cpp +++ b/src/render/renderers/opengl/textures/gltexture.cpp @@ -232,11 +232,9 @@ void GLTexture::loadTextureDataFromImages() GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture() { TextureUpdateInfo textureInfo; - m_properties.status = QAbstractTexture::Error; m_wasTextureRecreated = false; const bool hasSharedTextureId = m_sharedTextureId > 0; - // Only load texture data if we are not using a sharedTextureId // Check if dataFunctor or images have changed if (!hasSharedTextureId) { @@ -269,17 +267,17 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture() // Reset image flag setDirtyFlag(TextureImageData, false); } - } - // Don't try to create the texture if the target or format was still not set - // Format should either be set by user or if Automatic - // by either the dataGenerator of the texture or the first Image - // Target should explicitly be set by the user or the dataGenerator - if (m_properties.target == QAbstractTexture::TargetAutomatic || - m_properties.format == QAbstractTexture::Automatic || - m_properties.format == QAbstractTexture::NoFormat) { - textureInfo.properties.status = QAbstractTexture::Error; - return textureInfo; + // Don't try to create the texture if the target or format was still not set + // Format should either be set by user or if Automatic + // by either the dataGenerator of the texture or the first Image + // Target should explicitly be set by the user or the dataGenerator + if (m_properties.target == QAbstractTexture::TargetAutomatic || + m_properties.format == QAbstractTexture::Automatic || + m_properties.format == QAbstractTexture::NoFormat) { + textureInfo.properties.status = QAbstractTexture::Error; + return textureInfo; + } } // If the properties changed or texture has become a shared texture from a diff --git a/src/render/renderstates/qrastermode.cpp b/src/render/renderstates/qrastermode.cpp index c432f1063..648872a84 100644 --- a/src/render/renderstates/qrastermode.cpp +++ b/src/render/renderstates/qrastermode.cpp @@ -48,7 +48,7 @@ namespace Qt3DRender { /*! \class Qt3DRender::QRasterMode \brief The QRasterMode render state allows to control the type of - rasterization to be performed + rasterization to be performed. \since 5.14 \inmodule Qt3DRender \ingroup renderstates @@ -65,7 +65,7 @@ namespace Qt3DRender { /*! \qmltype RasterMode \brief The RasterMode render state allows to control the type of - rasterization to be performed + rasterization to be performed. \since 5.14 \inqmlmodule Qt3D.Render \inherits RenderState diff --git a/src/render/services/vsyncframeadvanceservice.cpp b/src/render/services/vsyncframeadvanceservice.cpp index b49870e68..d7398e2ce 100644 --- a/src/render/services/vsyncframeadvanceservice.cpp +++ b/src/render/services/vsyncframeadvanceservice.cpp @@ -62,7 +62,7 @@ public: QSemaphore m_semaphore; QElapsedTimer m_elapsed; - quint64 m_elapsedTimeSincePreviousFrame; + qint64 m_elapsedTimeSincePreviousFrame; bool m_drivenByRenderThread; }; @@ -75,14 +75,19 @@ VSyncFrameAdvanceService::~VSyncFrameAdvanceService() { } -// Aspect Thread +// Main Thread qint64 VSyncFrameAdvanceService::waitForNextFrame() { Q_D(VSyncFrameAdvanceService); +#ifdef Q_OS_MACOS + if (!d->m_semaphore.tryAcquire(std::max(d->m_semaphore.available(), 1), 4)) + return -1; +#else d->m_semaphore.acquire(std::max(d->m_semaphore.available(), 1)); +#endif - const quint64 currentTime = d->m_elapsed.nsecsElapsed(); + const qint64 currentTime = d->m_elapsed.nsecsElapsed(); qCDebug(VSyncAdvanceService) << "Elapsed nsecs since last call " << currentTime - d->m_elapsedTimeSincePreviousFrame; d->m_elapsedTimeSincePreviousFrame = currentTime; return currentTime; diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp index 7fca2ba3f..258ab44dc 100644 --- a/src/render/texture/qabstracttexture.cpp +++ b/src/render/texture/qabstracttexture.cpp @@ -977,7 +977,7 @@ float QAbstractTexture::maximumAnisotropy() const } /*! - \property Qt3DRender::QAbstractTexture::ComparisonFunction + \property Qt3DRender::QAbstractTexture::comparisonFunction Holds the comparison function of the texture provider. */ @@ -1008,7 +1008,7 @@ QAbstractTexture::ComparisonFunction QAbstractTexture::comparisonFunction() cons } /*! - \property Qt3DRender::QAbstractTexture::ComparisonMode + \property Qt3DRender::QAbstractTexture::comparisonMode Holds the comparison mode of the texture provider. */ @@ -1055,9 +1055,12 @@ QTextureGeneratorPtr QAbstractTexture::dataGenerator() const */ /*! - * \qmlproperty handleType + * \qmlproperty enumeration AbstractTexture::handleType * * Holds the current texture handle type. + * + * \value AbstractTexture.NoHandle + * \value AbstractTexture.OpenGLTextureId */ /*! @@ -1070,7 +1073,6 @@ QAbstractTexture::HandleType QAbstractTexture::handleType() const return d->m_handleType; } - /*! * \property Qt3DRender::QAbstractTexture::handle * @@ -1079,7 +1081,7 @@ QAbstractTexture::HandleType QAbstractTexture::handleType() const */ /*! - * \qmlproperty handle + * \qmlproperty var AbstractTexture::handle * * Holds the current texture handle, if Qt 3D is using the OpenGL renderer, * handle is a texture id integer. @@ -1098,8 +1100,8 @@ QVariant QAbstractTexture::handle() const } /*! - * Allow to update a sub region of the texture without having to change the data - * generator or rely on adding or removing texture images. + * Updates a sub region of the texture, defined by \a update, without having + * to change the data generator or rely on adding or removing texture images. * \since 5.14 */ void QAbstractTexture::updateData(const QTextureDataUpdate &update) @@ -1135,7 +1137,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAbstractTexture::createNodeCreationChange() data.dataFunctor = d->m_dataFunctor; data.sharedTextureId = d->m_sharedTextureId; data.initialDataUpdates = d->m_pendingDataUpdates; - return std::move(creationChange); + return creationChange; } /*! diff --git a/src/render/texture/qabstracttextureimage.cpp b/src/render/texture/qabstracttextureimage.cpp index 9ca4599c5..6f68221fd 100644 --- a/src/render/texture/qabstracttextureimage.cpp +++ b/src/render/texture/qabstracttextureimage.cpp @@ -131,8 +131,8 @@ QTextureImageDataGeneratorPtr QAbstractTextureImagePrivate::dataGenerator() cons /*! \fn Qt3DRender::QTextureImageDataGeneratorPtr Qt3DRender::QAbstractTextureImage::dataGenerator() const - Implement this method to return the \l QTextureImageDataGeneratorPtr, which will - provide the data for the texture image. + Implement this method to return the QTextureImageDataGeneratorPtr instance, + which will provide the data for the texture image. */ /*! diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp index bca66e630..84a228428 100644 --- a/src/render/texture/qtexture.cpp +++ b/src/render/texture/qtexture.cpp @@ -1125,7 +1125,7 @@ TextureDownloadRequest::TextureDownloadRequest(const QTextureFromSourceGenerator } -// Executed in aspect thread +// Executed in main thread void TextureDownloadRequest::onCompleted() { if (cancelled() || !succeeded()) @@ -1142,16 +1142,11 @@ void TextureDownloadRequest::onCompleted() QTextureFromSourceGeneratorPtr oldGenerator = qSharedPointerCast<QTextureFromSourceGenerator>(texture->dataGenerator()); - // We create a new functor - // Which is a copy of the old one + the downloaded sourceData - auto newGenerator = QTextureFromSourceGeneratorPtr::create(*oldGenerator); - // Set raw data on functor so that it can really load something - newGenerator->m_sourceData = m_data; + oldGenerator->m_sourceData = m_data; - // Set new generator on texture - // it implictely marks the texture as dirty so that the functor runs again with the downloaded data - texture->setDataGenerator(newGenerator); + // Mark the texture as dirty so that the functor runs again with the downloaded data + texture->addDirtyFlag(Render::Texture::DirtyDataGenerator); } /*! @@ -1520,7 +1515,10 @@ QTextureLoader::QTextureLoader(QNode *parent) // Regenerate the texture functor when properties we support overriding // from QAbstractTexture get changed. Q_D(QTextureLoader); - auto regenerate = [=] () { d->updateGenerator(); }; + auto regenerate = [=] () { + if (!notificationsBlocked()) // check the change doesn't come from the backend + d->updateGenerator(); + }; connect(this, &QAbstractTexture::formatChanged, regenerate); } diff --git a/src/render/texture/qtexturegenerator.cpp b/src/render/texture/qtexturegenerator.cpp index 5e350af2d..36b5f6498 100644 --- a/src/render/texture/qtexturegenerator.cpp +++ b/src/render/texture/qtexturegenerator.cpp @@ -52,8 +52,7 @@ QTextureGenerator::~QTextureGenerator() } /*! - \class QTextureGenerator - \inherits QAbstractFunctor + \class Qt3DRender::QTextureGenerator \inmodule Qt3DRender \brief Provides the image data for a texture. */ diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp index d120c2b39..1414cd337 100644 --- a/src/render/texture/texture.cpp +++ b/src/render/texture/texture.cpp @@ -149,6 +149,8 @@ void Texture::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) auto newGenerator = node->dataGenerator(); if (newGenerator != m_dataFunctor) { setDataGenerator(newGenerator); + QAbstractTexturePrivate *dTexture = static_cast<QAbstractTexturePrivate *>(QNodePrivate::get(const_cast<QNode *>(frontEnd))); + dTexture->setStatus(QAbstractTexture::Loading); } QAbstractTexturePrivate *dnode = dynamic_cast<QAbstractTexturePrivate *>(QAbstractTexturePrivate::get(const_cast<QAbstractTexture *>(node))); @@ -163,11 +165,11 @@ void Texture::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) m_textureImageIds = ids; addDirtyFlag(DirtyImageGenerators); } - } - if (dnode->m_sharedTextureId != m_sharedTextureId) { - m_sharedTextureId = dnode->m_sharedTextureId; - addDirtyFlag(DirtySharedTextureId); + if (dnode->m_sharedTextureId != m_sharedTextureId) { + m_sharedTextureId = dnode->m_sharedTextureId; + addDirtyFlag(DirtySharedTextureId); + } } } |