diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2019-10-02 12:45:21 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2019-10-08 14:40:59 +0200 |
commit | bf437f7da6c57307f93a24162981d4efd989fc53 (patch) | |
tree | 5137cbd5ae47d149c911b924ed92a1d3cb3cc826 /src/render/materialsystem | |
parent | 417fb3cb1af27313d2b4e1aafb094fee33388328 (diff) |
Update QShaderData to use direct sync
Also a bit of cleanup
Change-Id: I317fa2dbaa62a55fe371e982ed23976e65696d79
Reviewed-by: Mike Krus <mike.krus@kdab.com>
Diffstat (limited to 'src/render/materialsystem')
-rw-r--r-- | src/render/materialsystem/shaderdata.cpp | 241 | ||||
-rw-r--r-- | src/render/materialsystem/shaderdata_p.h | 31 |
2 files changed, 118 insertions, 154 deletions
diff --git a/src/render/materialsystem/shaderdata.cpp b/src/render/materialsystem/shaderdata.cpp index 130333898..34d4641e9 100644 --- a/src/render/materialsystem/shaderdata.cpp +++ b/src/render/materialsystem/shaderdata.cpp @@ -64,8 +64,6 @@ const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>(); } -QVector<Qt3DCore::QNodeId> ShaderData::m_updatedShaderData; - ShaderData::ShaderData() : m_managers(nullptr) { @@ -80,51 +78,82 @@ void ShaderData::setManagers(NodeManagers *managers) m_managers = managers; } -void ShaderData::initializeFromPeer(const QNodeCreatedChangeBasePtr &change) +void ShaderData::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) { - const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QShaderDataData>>(change); - const QShaderDataData &data = typedChange->data; - - m_propertyReader = data.propertyReader; - - for (const QPair<QByteArray, QVariant> &entry : data.properties) { - if (entry.first == QByteArrayLiteral("data") || - entry.first == QByteArrayLiteral("childNodes")) // We don't handle default Node properties - continue; - const QVariant &propertyValue = entry.second; - const QString propertyName = QString::fromLatin1(entry.first); - - m_originalProperties.insert(propertyName, propertyValue); - - // We check if the property is a QNodeId or QVector<QNodeId> so that we can - // check nested QShaderData for update - if (propertyValue.userType() == qNodeIdTypeId) { - m_nestedShaderDataProperties.insert(propertyName, propertyValue); - } else if (propertyValue.userType() == QMetaType::QVariantList) { - QVariantList list = propertyValue.value<QVariantList>(); - if (list.count() > 0 && list.at(0).userType() == qNodeIdTypeId) - m_nestedShaderDataProperties.insert(propertyName, propertyValue); - } - } + const QShaderData *node = qobject_cast<const QShaderData *>(frontEnd); + if (!node) + return; + BackendNode::syncFromFrontEnd(frontEnd, firstTime); + + if (firstTime) { + m_propertyReader = node->propertyReader(); + + const QMetaObject *metaObj = node->metaObject(); + const int propertyOffset = QShaderData::staticMetaObject.propertyOffset(); + const int propertyCount = metaObj->propertyCount(); + // Dynamic properties names + const auto dynamicPropertyNames = node->dynamicPropertyNames(); - // We look for transformed properties once the complete hash of - // originalProperties is available - QHash<QString, QVariant>::iterator it = m_originalProperties.begin(); - const QHash<QString, QVariant>::iterator end = m_originalProperties.end(); - - while (it != end) { - if (it.value().type() == QVariant::Vector3D) { - // if there is a matching QShaderData::TransformType propertyTransformed - QVariant value = m_originalProperties.value(it.key() + QLatin1String("Transformed")); - // if that's the case, we apply a space transformation to the property - if (value.isValid() && value.type() == QVariant::Int) - m_transformedProperties.insert(it.key(), static_cast<TransformType>(value.toInt())); + QVector<QString> propertyNames; + propertyNames.reserve(propertyCount - propertyOffset + dynamicPropertyNames.size()); + + // Statiically defined properties + for (int i = propertyOffset; i < propertyCount; ++i) { + const QMetaProperty pro = metaObj->property(i); + if (pro.isWritable()) + propertyNames.push_back(QString::fromLatin1(pro.name())); + } + // Dynamic properties + for (const QByteArray &propertyName : dynamicPropertyNames) + propertyNames.push_back(QString::fromLatin1(propertyName)); + + for (const QString &propertyName : propertyNames) { + if (propertyName == QStringLiteral("data") || + propertyName == QStringLiteral("childNodes")) // We don't handle default Node properties + continue; + + const QVariant &propertyValue = m_propertyReader->readProperty(node->property(propertyName.toLatin1())); + bool isNested = false; + bool isTransformed = false; + + // We check if the property is a QNodeId + isNested = (propertyValue.userType() == qNodeIdTypeId); + // We check if QVector<QNodeId> + if (propertyValue.userType() == QMetaType::QVariantList) { + QVariantList list = propertyValue.value<QVariantList>(); + if (list.count() > 0 && list.at(0).userType() == qNodeIdTypeId) + isNested = true; + } + + // We check if property is a Transformed property + if (propertyValue.userType() == QVariant::Vector3D) { + // if there is a matching QShaderData::TransformType propertyTransformed + isTransformed = propertyNames.contains(propertyName + QLatin1String("Transformed")); + } + m_originalProperties.insert(propertyName, { propertyValue, isNested, isTransformed }); + } + BackendNode::markDirty(AbstractRenderer::ParameterDirty); + } else { + // Updates + if (!m_propertyReader.isNull()) { + auto it = m_originalProperties.begin(); + const auto end = m_originalProperties.end(); + + while (it != end) { + const QVariant newValue = m_propertyReader->readProperty(node->property(it.key().toLatin1())); + PropertyValue &propValue = it.value(); + if (propValue.value != newValue) { + // Note we aren't notified about nested QShaderData in this call + // only scalar / vec properties + propValue.value = newValue; + BackendNode::markDirty(AbstractRenderer::ParameterDirty); + } + ++it; + } } - ++it; } } - ShaderData *ShaderData::lookupResource(NodeManagers *managers, QNodeId id) { return managers->shaderDataManager()->lookupResource(id); @@ -135,120 +164,62 @@ ShaderData *ShaderData::lookupResource(QNodeId id) return ShaderData::lookupResource(m_managers, id); } -// Call by cleanup job (single thread) -void ShaderData::clearUpdatedProperties() -{ - // DISABLED: Is only useful when building UBO from a ShaderData, which is disable since 5.7 - // const QHash<QString, QVariant>::const_iterator end = m_nestedShaderDataProperties.end(); - // QHash<QString, QVariant>::const_iterator it = m_nestedShaderDataProperties.begin(); - - // while (it != end) { - // if (it.value().userType() == QMetaType::QVariantList) { - // const auto values = it.value().value<QVariantList>(); - // for (const QVariant &v : values) { - // ShaderData *nested = lookupResource(v.value<QNodeId>()); - // if (nested != nullptr) - // nested->clearUpdatedProperties(); - // } - // } else { - // ShaderData *nested = lookupResource(it.value().value<QNodeId>()); - // if (nested != nullptr) - // nested->clearUpdatedProperties(); - // } - // ++it; - // } -} - void ShaderData::cleanup(NodeManagers *managers) { Q_UNUSED(managers) - // DISABLED: Is only useful when building UBO from a ShaderData, which is disable since 5.7 - // for (Qt3DCore::QNodeId id : qAsConst(m_updatedShaderData)) { - // ShaderData *shaderData = ShaderData::lookupResource(managers, id); - // if (shaderData) - // shaderData->clearUpdatedProperties(); - // } - m_updatedShaderData.clear(); } +// RenderCommand updater jobs QVariant ShaderData::getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix) { // Note protecting m_worldMatrix at this point as we assume all world updates // have been performed when reaching this point - auto it = m_transformedProperties.find(name); - if (it != m_transformedProperties.end()) { - const TransformType transformType = it.value(); - switch (transformType) { - case ModelToEye: - return QVariant::fromValue(viewMatrix * m_worldMatrix * Vector3D(m_originalProperties.value(name).value<QVector3D>())); - case ModelToWorld: - return QVariant::fromValue(m_worldMatrix * Vector3D(m_originalProperties.value(it.key()).value<QVector3D>())); - case ModelToWorldDirection: - return QVariant::fromValue(Vector3D(m_worldMatrix * Vector4D(m_originalProperties.value(it.key()).value<QVector3D>(), 0.0f))); - case NoTransform: - break; + const auto it = m_originalProperties.constFind(name); + if (it != m_originalProperties.constEnd()) { + const PropertyValue &propertyValue = it.value(); + if (propertyValue.isTransformed) { + const auto transformedIt = m_originalProperties.constFind(name + QLatin1String("Transformed")); + if (transformedIt != m_originalProperties.constEnd()) { + const PropertyValue &transformedValue = transformedIt.value(); + const TransformType transformType = static_cast<TransformType>(transformedValue.value.toInt()); + switch (transformType) { + case ModelToEye: + return QVariant::fromValue(viewMatrix * m_worldMatrix * Vector3D(propertyValue.value.value<QVector3D>())); + case ModelToWorld: + return QVariant::fromValue(m_worldMatrix * Vector3D(propertyValue.value.value<QVector3D>())); + case ModelToWorldDirection: + return QVariant::fromValue(Vector3D(m_worldMatrix * Vector4D(propertyValue.value.value<QVector3D>(), 0.0f))); + case NoTransform: + break; + } + } } + return propertyValue.value; } return QVariant(); } -// Called by FramePreparationJob or by RenderView when dealing with lights -void ShaderData::updateWorldTransform(const Matrix4x4 &worldMatrix) -{ - QMutexLocker lock(&m_mutex); - if (m_worldMatrix != worldMatrix) { - m_worldMatrix = worldMatrix; - } -} - -// This will add the ShaderData to be cleared from updates at the end of the frame -// by the cleanup job -// Called by renderview jobs (several concurrent threads) -void ShaderData::markDirty() -{ - QMutexLocker lock(&m_mutex); - if (!ShaderData::m_updatedShaderData.contains(peerId())) - ShaderData::m_updatedShaderData.append(peerId()); -} - -/*! - \internal - Lookup if the current ShaderData or a nested ShaderData has updated properties. - UpdateProperties contains either the value of the propertie of a QNodeId if it's another ShaderData. - Transformed properties are updated for all of ShaderData that have ones at the point. - - \note This needs to be performed for every top level ShaderData every time it is used. - As we don't know if the transformed properties use the same viewMatrix for all RenderViews. - */ - +// Unit tests only ShaderData::TransformType ShaderData::propertyTransformType(const QString &name) const { - return m_transformedProperties.value(name, TransformType::NoTransform); + const auto it = m_originalProperties.constFind(name); + if (it != m_originalProperties.constEnd()) { + const PropertyValue &propertyValue = it.value(); + if (propertyValue.isTransformed) { + auto transformedIt = m_originalProperties.constFind(name + QLatin1String("Transformed")); + if (transformedIt != m_originalProperties.end()) + return static_cast<TransformType>(transformedIt.value().value.toInt()); + } + } + return NoTransform; } -void ShaderData::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) +// Called by FramePreparationJob or by RenderView when dealing with lights +void ShaderData::updateWorldTransform(const Matrix4x4 &worldMatrix) { - if (!m_propertyReader.isNull() && e->type() == PropertyUpdated) { - QString propertyName; - QVariant propertyValue; - - if (auto propertyChange = qSharedPointerDynamicCast<QPropertyUpdatedChange>(e)) { - propertyName = QString::fromLatin1(propertyChange->propertyName()); - propertyValue = m_propertyReader->readProperty(propertyChange->value()); - } else if (auto propertyChange = qSharedPointerDynamicCast<QDynamicPropertyUpdatedChange>(e)) { - propertyName = QString::fromLatin1(propertyChange->propertyName()); - propertyValue = m_propertyReader->readProperty(propertyChange->value()); - } else { - Q_UNREACHABLE(); - } - - // Note we aren't notified about nested QShaderData in this call - // only scalar / vec properties - m_originalProperties.insert(propertyName, propertyValue); - BackendNode::markDirty(AbstractRenderer::ParameterDirty); + if (m_worldMatrix != worldMatrix) { + m_worldMatrix = worldMatrix; } - - BackendNode::sceneChangeEvent(e); } RenderShaderDataFunctor::RenderShaderDataFunctor(AbstractRenderer *renderer, NodeManagers *managers) diff --git a/src/render/materialsystem/shaderdata_p.h b/src/render/materialsystem/shaderdata_p.h index f9c3ecc79..c9cc22939 100644 --- a/src/render/materialsystem/shaderdata_p.h +++ b/src/render/materialsystem/shaderdata_p.h @@ -76,49 +76,42 @@ public: ModelToWorld, ModelToWorldDirection }; + struct PropertyValue { + QVariant value; + bool isNested; + bool isTransformed; + }; ShaderData(); ~ShaderData(); - QHash<QString, QVariant> properties() const { return m_originalProperties; } + QHash<QString, PropertyValue> properties() const { return m_originalProperties; } // Called by FramePreparationJob void updateWorldTransform(const Matrix4x4 &worldMatrix); - // Call by RenderViewJob - void markDirty(); + QVariant getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix); + // Unit tests purposes only TransformType propertyTransformType(const QString &name) const; - QVariant getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix); // Called by FrameCleanupJob static void cleanup(NodeManagers *managers); void setManagers(NodeManagers *managers); -protected: - void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) override; - void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override; + void syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) override; +protected: PropertyReaderInterfacePtr m_propertyReader; - // 1 to 1 match with frontend properties, modified only by sceneChangeEvent - QHash<QString, QVariant> m_originalProperties; - - // Contains properties thar are of type ShaderData - QHash<QString, QVariant> m_nestedShaderDataProperties; - - // Contains property that are defined like: postionTransformed: ModelToEye - QHash<QString, TransformType> m_transformedProperties; + // 1 to 1 match with frontend properties + QHash<QString, PropertyValue> m_originalProperties; - QMutex m_mutex; - static QVector<Qt3DCore::QNodeId> m_updatedShaderData; Matrix4x4 m_worldMatrix; - Matrix4x4 m_viewMatrix; NodeManagers *m_managers; - void clearUpdatedProperties(); static ShaderData *lookupResource(NodeManagers *managers, Qt3DCore::QNodeId id); ShaderData *lookupResource(Qt3DCore::QNodeId id); |