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

DrawPixmapFragments on OpenGL crash when passing in large data size



  • Hi all,

    I have tried using drawPixmapFragments on QOpenGLWidget to render pixmaps in batch and came upon this crash when I send a pretty large data count right after a small data count.

    Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
    Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000114404000
    Exception Note:        EXC_CORPSE_NOTIFY
    
    Termination Signal:    Segmentation fault: 11
    Termination Reason:    Namespace SIGNAL, Code 0xb
    Terminating Process:   exc handler [0]
    
    VM Regions Near 0x114404000:
        MALLOC_LARGE           0000000114381000-00000001143db000 [  360K] rw-/rwx SM=COW  
    --> 
        MALLOC_LARGE           000000011441b000-000000011451b000 [ 1024K] rw-/rwx SM=COW  
    
    Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
    0   ???                           	0x00000001149db12d 0 + 4640846125
    1   GLEngine                      	0x00007fffd8605c60 glDrawArrays_IMM_Exec + 811
    2   libQt5Gui_debug.5.dylib       	0x000000010af8e143 QOpenGLFunctions::glDrawArrays(unsigned int, int, int) + 99
    3   libQt5Gui_debug.5.dylib       	0x000000010af95e3c QOpenGL2PaintEngineExPrivate::drawPixmapFragments(QPainter::PixmapFragment const*, int, QPixmap const&, QFlags<QPainter::PixmapFragmentHint>) + 2700
    4   libQt5Gui_debug.5.dylib       	0x000000010af9539a QOpenGL2PaintEngineEx::drawPixmapFragments(QPainter::PixmapFragment const*, int, QPixmap const&, QFlags<QPainter::PixmapFragmentHint>) + 298
    5   libQt5Gui_debug.5.dylib       	0x000000010aeaecef QPainter::drawPixmapFragments(QPainter::PixmapFragment const*, int, QPixmap const&, QFlags<QPainter::PixmapFragmentHint>) + 543
    
    

    Here is the example code of what I mean. The below code doesn't make sense. But in actual, I can confirm that I am calling drawPixmapFragments function back to back with valid data, correct size and a valid pixmaps. The only difference is the data size and the pixmap itself.

    typedef QVarLengthArray<QPainter::PixmapFragment, 9> QPixmapFragmentsArray;
    static void s_AppendFragments(const QRect& pixmapRect, const QRectF& rcDest,
                                  QPixmapFragmentsArray& pixmapFragmentArray, int num)
    {
        for (int i = 0; i < num; ++i)
        {
            QPainter::PixmapFragment d;
            d.opacity = 1.0;
            d.rotation = 0.0;
            d.sourceLeft = pixmapRect.left();
            d.sourceTop = pixmapRect.top();
            d.width = pixmapRect.width();
            d.height = pixmapRect.height();
            d.scaleX = rcDest.width() / d.width;
            d.scaleY = rcDest.height() / d.height;
            d.y = rcDest.center().y();
            d.x = rcDest.center().x();
            pixmapFragmentArray.append(d);
        }
    }
    
    static void TestFunc(QPainter* painter, const QPixmap& pixmap1, const QPixmap& pixmap2) // called from paint
    {
        QPixmapFragmentsArray data1;
        QPixmapFragmentsArray data2;
        s_AppendFragments(pixmap1.rect(), QRectF(10, 10, 50, 50), data1, 5940);
        s_AppendFragments(pixmap2.rect(), QRectF(10, 10, 50, 50), data2, 35640);
    
        if (!data1.isEmpty())
        {
            painter->drawPixmapFragments(data1.data(), data1.size(), pixmap1);
        }
    
        if (!data2.isEmpty())
        {
            painter->drawPixmapFragments(data2.data(), data2.size(), pixmap2); 
        }
    }
    

    I am on MacOS Sierra (10.12.2)
    Qt 5.4.1

    Thanks in advance :)


  • Lifetime Qt Champion

    Hi,

    What kind of data size are you trying to manipulate ?



  • @SGaist , Sorry, I am not getting your question. The first call to drawPixmapFragments is being fed with an array of PixmapFragment of size 5940, and the second call with size of 35640.

    I kind of doubt the QDataBuffer that is used by QOpenGL2PEXVertexArray in QOpenGLPaintEngine which will try to reserve memory using realloc when it is adding vertex. But I am really not sure in this. The crash happens when the second call give a pretty large size of array as compared to the first call. If the second call has just slightly higher array size as compared to the first, then I will see some artifact in drawing for that one frame. However, if the first call itself was giving the large array size, then there is no problem.



  • With the help of a friend, I found out that the issue is indeed in Qt's OpenGLPaintEngine. When we try to realloc a bigger data size than the previous one, realloc might be giving a buffer pointed to different memory address. However, in QOpenGL2PaintEngineExPrivate::transferMode, if the mode are the same back to back, then it did not bother to update the vertex attribute pointer to the new buffer address. Should I raise a bug?


  • Qt Champions 2019

    @Sivan Sounds like a bug, you should raise a bug in the bug tracker.




Log in to reply