Как использовать QSGGeometryNode без утечки памяти и обеспечить правильную очистку

Я использую QSGGeometry, QSGVertexColorMaterial & QSGGeometryNode нарисовать что-то в реальном времени на моем QQuickItem производный класс, который MyQuickItem Вот.

Следующее мое 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 автоматически удаляются из памяти на более позднем этапе.

1 ответ

Решение

Да, в вашем примере кода вы можете рассчитывать на автоматическую очистку узлов. Вы не пропускаете память из updatePaintNode.

oldnode и child_node

oldnode возвращаемый из QQuickItem::updatePaintNode() автоматически удаляется в нужном потоке в нужное время. Деревья экземпляров QSGNode управляются с помощью QSGNode::OwnedByParent, который устанавливается по умолчанию.

материал

Потому что вы установили флаг QSGNode::OwnsMaterial для вашего child_node material удаляется при удалении child_node.

Второй вопрос: это хороший способ?

Ответ - нет. Нет смысла создавать и удалять узлы каждый раз при рендеринге сцены. Вместо этого вы должны повторно использовать узел / узлы. В приведенном ниже примере кода я предполагаю, что геометрия изменяется, но материал не меняется в течение времени жизни 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;
}
Другие вопросы по тегам