7

我使用 a QSGGeometry, QSGVertexColorMaterial& a在这里的派生类QSGGeometryNode上实时绘制一些东西。QQuickItemMyQuickItem

以下是我updatePaintNode的重绘逻辑关键所在的方法。

QSGNode * MyQuickItem::updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData) {

  if (!oldNode) {
    oldNode = new QSGNode;
  }

  oldNode->removeAllChildNodes();

  QSGGeometry * geometry = GetMyGeometry();
  QSGVertexColorMaterial * material = new QSGVertexColorMaterial;
  QSGGeometryNode * child_node = new QSGGeometryNode;

  child_node->setGeometry(geometry);
  child_node->setMaterial(material);
  child_node->setFlag(QSGNode::OwnsMaterial);
  oldNode->appendChildNode(child_node);

  return oldNode;
}

问题:
上述逻辑效果很好。功能上完全没有问题。也没有性能问题。但我担心我会导致内存泄漏。看看上面updatePaintNode我分配原始指针的方法中的以下两行。

QSGVertexColorMaterial * material = new QSGVertexColorMaterial;
QSGGeometryNode * child_node = new QSGGeometryNode;

我分配它们并且我不删除它们。这是因为它们应该被删除的点是在updatePaintNode完成之后。那不在我的控制之下。

问题:
如何确保 2 个指针material&child_node正确地从内存中清除?
是否child_node->setFlag(QSGNode::OwnsMaterial)像我在上面所做的那样设置了指向QtSceneGraph的指针的所有权并减轻了我删除指针的负担?

次要问题:
我正在使用oldNode->removeAllChildNodes()清除上一帧中绘制的数据。这是在绘制新数据之前清除屏幕上先前数据的好方法吗?

PS:
我重申:这个实现没有性能问题。我只是想确保我没有造成任何内存泄漏。我尝试使用material&child_node作为智能指针,如下所示:

auto material = std::make_shared<QSGVertexColorMaterial>();
auto child_node = new std::make_shared<QSGGeometryNode>();

但是,当material&child_node稍后从内存中自动清除时,这会导致崩溃。

4

1 回答 1

6

是的,在您的示例代码中,您可以依赖节点的自动清理。您没有从 updatePaintNode 泄漏内存。

oldnode 和 child_node

oldnode从 QQuickItem::updatePaintNode() 返回的内容会在正确的时间在正确的线程上自动删除。QSGNode 实例的树是通过使用默认设置的 QSGNode::OwnedByParent 来管理的。

材料

因为您已经为您的 child_node 设置了标志 QSGNode::OwnsMaterial 在 child_nodematerial被删除时被删除。

第二个问题:这是一个好方法吗?

答案是不。每次渲染场景时都没有必要创建和删除节点。相反,您应该重用节点/节点。在下面的示例代码中,我假设在 QQuickItem 的生命周期内几何会发生变化,但材料不会发生变化。如果材质发生变化,您可能需要调用node->markDirty(QSGNode::DirtyMaterial)。请注意,只创建了一个节点,并且只创建了一次(除非窗口隐藏然后返回 fg 或其他东西)。

QSGNode * MyQuickItem::updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData) {

    QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode);
    if (!node) {
        node = new QSGGeometryNode;

        QSGVertexColorMaterial * material = new QSGVertexColorMaterial;
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);
    }

    // if GetMyGeometry returns every time a new dynamically allocated object then you should
    // call node->setFlag(QSGNode::OwnsGeometry) to not leak memory here:
    QSGGeometry * geometry = GetMyGeometry(); 
    node->setGeometry(geometry);
    // No need to call node->markDirty(QSGNode::DirtyGeometry) because setGeometry is called.

    return node;
}
于 2017-09-25T09:33:51.020 回答