Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Segmentation fault when painting a png in updatePaintNode() using QSGTexture



  • I'm stumped. I don't know why this code is throwing a segmentation fault. I can't tell where the seg fault is, but I know that it prints up to debug "t8". So it looks like it is exiting updatePaintNode() without a problem.
    I'm ultimately trying to paint multiple png graphics on the scene in different coordinates every frame. So my current baby step is PAINT ONE png item on the scene graph.

    I tried this code in QPainter and it paints fine. So I know I'm accessing it with the right filename.

    updatePaintNode(....)
    {
        QPixmap px1("pics/RadarCarSmall4.png");
        QImage img("pics/RadarCarSmall5.png");
        painter->drawPixmap(10,10,40,40, px1);   // just trying different ways to access and paint
        painter->drawImage(QPointF(50,50), img);  //just trying different way to access and paint
    

    Then I tried this code in updatePaintNode() and it throws a segmentation fault.

     QSGNode *root = static_cast<QSGNode *>(oldNode);
     if(!root) {
         root = new QSGNode;
     }
    qDebug("1");
        root->removeAllChildNodes();
        QSGGeometryNode *n = new QSGGeometryNode();
        QSGGeometry * geo2 = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4);  // create geometry
        geo2->setDrawingMode(QSGGeometry::DrawTriangleFan);
        geo2->vertexDataAsPoint2D()[0].set(100,100);
        geo2->vertexDataAsPoint2D()[1].set(100,150);
        geo2->vertexDataAsPoint2D()[2].set(150,150);
        geo2->vertexDataAsPoint2D()[3].set(150,100);
    qDebug("4");
        QImage img("pics/RadarCarSmall5.png");                   // create texture
        QSGTexture * t = window()->createTextureFromImage(img);
        QSGOpaqueTextureMaterial *testM = new QSGOpaqueTextureMaterial;    
        testM->setTexture(t);                             // set texture
    
    QSGFlatColorMaterial *z2 = new QSGFlatcolorMaterial;
    z2->setColor(Qt::blue);
        n->setMaterial(testM);   // if I replace testM with z2, the segmentation fault goes away.
        n->setGeometry(geo2);
       root->appendChildNode(n);
    qDebug("t8");
    return root
    }
    

    It's very possible I'm not use window() correctly. All I did was #include <QQuickWindow>... I'm not sure if that's the right way to use it?



  • I found the problem. I should not be using QSGGeometryNode. I should be using QSGSimpleTextureNode.

       QSGSimpleTextureNode *test = new QSGSimpleTextureNode;
        QImage img;
        bool state = img.load(":/scenegraph/customgeometry/radarcar.png");
        QSGTexture * t =  window()->createTextureFromImage(img);
        test->setTexture(t);
        test->setRect(10, 10, 30, 30);
    

  • Qt Champions 2019

    @mxyn said in Segmentation fault when painting a png in updatePaintNode() using QSGTexture:

    it throws a segmentation fault

    Where exactly?



  • I updated my previous code so you can see where debug "t8" get's printed. It seems to seg fault after exiting the function.


  • Qt Champions 2019

    @mxyn Please show stack trace after the crash


  • Qt Champions 2019

    @mxyn said in Segmentation fault when painting a png in updatePaintNode() using QSGTexture:

    QImage img("pics/RadarCarSmall5.png"); // create texture
    QSGTexture * t = window()->createTextureFromImage(img);

    I'm wondering why you're doing this everytime you paint? This can be done once.



  • I would love to! ... How do I pull up the backtrace? I know how to run gdb.... and then backtrace. Is this what you are asking for?

    t8

    Thread 9 "QThread" received signal SIGSEGV, Segmentation fault.
    [Switching to Thread 0x7fa8c4d1c0 (LWP 15010)]
    0x0000007fb7179418 in QSGBatchRenderer::Renderer::renderUnmergedBatch(QSGBatchRenderer::Batch const*) () from /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    (gdb) backtrace
    #0 0x0000007fb7179418 in QSGBatchRenderer::Renderer::renderUnmergedBatch(QSGBatchRenderer::Batch const*) () at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #1 0x0000007fb7179b60 in QSGBatchRenderer::Renderer::renderBatches() ()
    at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #2 0x0000007fb717ed30 in QSGBatchRenderer::Renderer::render() ()
    at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #3 0x0000007fb7170eec in QSGRenderer::renderScene(QSGBindable const&) ()
    at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #4 0x0000007fb717134c in QSGRenderer::renderScene(unsigned int) ()
    at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #5 0x0000007fb71a7cac in QSGDefaultRenderContext::renderNextFrame(QSGRenderer*, unsigned int) ()
    at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #6 0x0000007fb7202d7c in QQuickWindowPrivate::renderSceneGraph(QSize const&) ()
    at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #7 0x0000007fb72b71e0 in QQuickRenderControl::render() ()
    at /usr/lib/aarch64-linux-gnu/libQt5Quick.so.5
    #8 0x0000007fa8c550e0 in Worker::doRender(unsigned char*, unsigned char*) (this=0x7fa8c4c370, inFrame=0x8 <error: Cannot access memory at address 0x8>, outFrame=0xffffec00 <error: Cannot access memory at address 0xffffec00>) at gstqoverlay.cpp:344
    #9 0x0000007fa8c568c0 in QtPrivate::FunctorCall<QtPrivate::IndexesList<0, 1>, QtPrivate::List<unsigned char*, unsigned char*>, bool, bool (Worker::)(unsigned char, unsigned char*)>::call(bool (Worker::)(unsigned char, unsigned char*), Worker*, void**) (arg=0x7f7effbc70, o=<optimized out>, f=<optimized out>) at /usr/include/aarch64-linux-gnu/qt5/QtCore/qobjectdefs_impl.h:136



  • @jsulm Short answer is that I'm just trying to get one item on the screen for now. So I figured it's okay to plop this code in while I'm trying to get a handle on how QSGTexture is drawn.

    Long answer, I'm drawing radar blips that will be moving across the screen. Each blip will be a different color, and the number of blips may go up or down. It is all represented in a model list that contains the colors and the coords of the blips. The model list will also be growing or shrinking with the number of blips I need to draw. So I plan to have each blip mapped to a node, and create this node from scratch each time. This is probably not the most efficient way to do it. I just started learning updatePaintNode() stuff 2 days ago. I would love to hear if you have a better idea on how to take advantage of the batch processing power of updatePaintNode().

    In fact I had made another post hereasking people to give me their opinion on how to make another updatePaintNode() implementation better.



  • @mxyn said in Segmentation fault when painting a png in updatePaintNode() using QSGTexture:

    QSGTexture * t = window()->createTextureFromImage(img);
    QSGOpaqueTextureMaterial *testM = new QSGOpaqueTextureMaterial;

    Check for null on anything that is returning a pointer and see if something is failing to be created.



  • @fcarney I tested for NULL, and none of these debugs printed out. meaning the vars aren't null

    QImage img("pics/RadarCarSmall5.png");                   // create texture
    QSGTexture * t = window()->createTextureFromImage(img);
    
    if(img.isNull())
      qdebug("img is null");
    
    if( t == NULL)
      qDebug( "t is null");
    
    QSGOpaqueTextureMaterial *testM = new QSGOpaqueTextureMaterial;
    testM.setTexture(t);
    if( testM == NULL )
      qDebug("testM is NULL);
    
    

    But I do suspect SOMETHING must be wrong with my texture... Not sure what though...



  • I decided to create a SIMPLE project in QTCreator to try to zero in on what's broken in the code. This code draws a triangle and then a rectangle. I tried setting the rectangle material to red. It worked! It tried setting the rectangle material to a texture, it failed! The guilty lines are:
    //test->setMaterial(m2); // makes a red rectangle
    test->setMaterial(tm); // nothing gets drawn

    I'm hoping someone could try this code on their QTCreator and see if they have the same problem?

    qquickcustomitem.cpp

    #include "qquickcustomitem.h"
    #include <QSGGeometry>
    #include <QSGGeometryNode>
    #include <QSGFlatColorMaterial>
    #include <QDebug>
    #include <QImage>
    #include <QQuickWindow>
    #include <QSGOpaqueTextureMaterial>
    #include <QSGSimpleRectNode>
    
    QQuickCustomItem::QQuickCustomItem(QQuickItem *parent) :
     QQuickItem(parent),
     m_color(Qt::red),
     m_needUpdate(true)
    {
     setFlag(QQuickItem::ItemHasContents);
    }
    
    QColor QQuickCustomItem::color() const
    {
     return m_color;
    }
    void QQuickCustomItem::setColor(const QColor &color)
    {
     if(m_color != color) {
     m_color = color;
     m_needUpdate = true;
     update();
     colorChanged();
     }
    }
    
    
    QSGNode *QQuickCustomItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData
    *updatePaintNodeData)
    {
        Q_UNUSED(updatePaintNodeData)
        QSGGeometryNode *root = static_cast<QSGGeometryNode *>(oldNode);
    
        if(!root) {
            root = new QSGGeometryNode;
            QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3);
            geometry->setDrawingMode(GL_TRIANGLE_FAN);
            geometry->vertexDataAsPoint2D()[0].set(width() / 2, 0);
            geometry->vertexDataAsPoint2D()[1].set(width(), height());
            geometry->vertexDataAsPoint2D()[2].set(0, height());
    
            root->setGeometry(geometry);
            root->setFlag(QSGNode::OwnsGeometry);
            root->setFlag(QSGNode::OwnsMaterial);
        }
    
        if(m_needUpdate) {
            QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
            material->setColor(m_color);
            root->setMaterial(material);
            m_needUpdate = false;
        }
    
        QSGGeometryNode *test = new QSGGeometryNode;
        QSGGeometry *geometry2 = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4);
        geometry2->setDrawingMode(QSGGeometry::DrawTriangleFan);
        geometry2->vertexDataAsPoint2D()[0].set(100,100);
        geometry2->vertexDataAsPoint2D()[1].set(100,150);
        geometry2->vertexDataAsPoint2D()[2].set(150, 150);
        geometry2->vertexDataAsPoint2D()[3].set(150, 100);
    
        QImage img;
        bool state = img.load(":/scenegraph/customgeometry/radarcar.png");
        QSGTexture * t =  window()->createTextureFromImage(img);
        QSGOpaqueTextureMaterial *tm = new QSGOpaqueTextureMaterial;
        tm->setTexture(t);
    
        QSGFlatColorMaterial *m2 = new QSGFlatColorMaterial;
        m2->setColor(Qt::red);
    
        test->setGeometry(geometry2);
        //test->setMaterial(m2);  // makes a red rectangle
        test->setMaterial(tm);    // nothing gets drawn
        root->appendChildNode(test);
        return root;
    }
    
    

    qquickcustomitem.h

    #ifndef QQUICKCUSTOMITEM_H
    #define QQUICKCUSTOMITEM_H
    
    #include <QObject>
    #include <QQuickItem>
    #include <QColor>
    
    
    class QQuickCustomItem : public QQuickItem
    {
        Q_OBJECT
        Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
    public:
        QQuickCustomItem(QQuickItem *parent = Q_NULLPTR);
    protected:
        QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData);
        QColor color() const;
        void setColor(const QColor &color);
    private:
        QColor m_color;
        bool m_needUpdate;
    signals:
        void colorChanged();
    };
    
    
    #endif // QQUICKCUSTOMITEM_H
    
    


  • I found the problem. I should not be using QSGGeometryNode. I should be using QSGSimpleTextureNode.

       QSGSimpleTextureNode *test = new QSGSimpleTextureNode;
        QImage img;
        bool state = img.load(":/scenegraph/customgeometry/radarcar.png");
        QSGTexture * t =  window()->createTextureFromImage(img);
        test->setTexture(t);
        test->setRect(10, 10, 30, 30);