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);
-
@mxyn said in Segmentation fault when painting a png in updatePaintNode() using QSGTexture:
it throws a segmentation fault
Where exactly?
-
@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 drawnI'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);
-
QSGGeometry * geo2 = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); // create geometry
The crash is due to the 2D point which is not enough to hold the texture, the call with QSGGeometry::defaultAttributes_TexturedPoint2D() (QSGGeometry::TexturedPoint2D) will solve the issue.