Question

I'm attempting to optimize some code because I must draw the same QPixmap onto a larger one many many times. Since passing a QPixmap by value in my own methods would create copies with each call, I thought I could shave some time off by working with pointers to QPixmaps. However, it seems my work has been in vein. I think it's because calling QPainter::drawPixmap(..., const QPixmap&, ...) creates a copy of it.

QPixmap *pixmap = new QPixmap(10,10);
painter.drawPixmap(0,0, *pixmap);

Is a copy being created in this example?

If so, how might I go about optimizing the drawing many images onto another?

I have already read this Q/A here: Does dereferencing a pointer make a copy of it? but a definite answer for my specific case eludes me.

Was it helpful?

Solution 2

According to the QPixmap class reference:

QPixmap objects can be passed around by value since the QPixmap class uses implicit data sharing. For more information, see the Implicit Data Sharing documentation.

QPixmap implementation:

QPixmap::QPixmap(const QPixmap &pixmap)
    : QPaintDevice()
{
    if (!qt_pixmap_thread_test()) {
        init(0, 0, QPixmapData::PixmapType);
        return;
    }
    if (pixmap.paintingActive()) {                // make a deep copy
        operator=(pixmap.copy());
    } else {
        data = pixmap.data;
    }
}

Only when the pixmap is painting active you'll need a deep copy otherwise the new pixmap would only need to copy the orignal data pointer.

For difference of const reference and pointer:

QPixmap largeMap(1000, 1000);
QPainter p(&largeMap);

int count = 100000;
qint64 time1, time2;
QPixmap *pSmallMap = new QPixmap("e:/test.png");
QPixmap smallMap = QPixmap("e:/test.png");

time1 =  QDateTime::currentMSecsSinceEpoch();
for (int i = 0; i < count; ++i) {
    p.drawPixmap(0, 0, *pSmallMap);
}
time2 =  QDateTime::currentMSecsSinceEpoch();;
qDebug("def time = %d\n", time2 - time1);

time1 =  QDateTime::currentMSecsSinceEpoch();
for (int i = 0; i < count; ++i) {
    p.drawPixmap(0, 0, smallMap);
}
time2 =  QDateTime::currentMSecsSinceEpoch();;
qDebug("normal time = %d\n", time2 - time1);

compile under visual studio 2010 Debug configuration would produce following assembly :

    28:         p.drawPixmap(0, 0, *pSmallMap);
003B1647 8B 55 C4             mov         edx,dword ptr [ebp-3Ch]  //the pixmap pointer
003B164A 52                   push        edx  
003B164B 6A 00                push        0  //x
003B164D 6A 00                push        0  //y
003B164F 8D 4D F0             lea         ecx,[ebp-10h]  //the qpainter pointer
003B1652 FF 15 9C D7 3B 00    call        dword ptr [__imp_QPainter::drawPixmap (3BD79Ch)]

    35:         p.drawPixmap(0, 0, smallMap);
003B16A8 8D 4D E0             lea         ecx,[ebp-20h]  //the pixmap pointer
003B16AB 51                   push        ecx            
003B16AC 6A 00                push        0              //x
003B16AE 6A 00                push        0              //y
003B16B0 8D 4D F0             lea         ecx,[ebp-10h]  //the qpainter pointer
003B16B3 FF 15 9C D7 3B 00    call        dword ptr [__imp_QPainter::drawPixmap (3BD79Ch)]  

There should be no differece between this two, because the compiler will produce the same assembly code: pass the pointer to the drawPixmap function.

And QDateTime::currentMSecsSinceEpoch() nearly show the same result on my box.

OTHER TIPS

No. The function drawPixmap takes a const reference to the pixmap, so there is no copy being made. Here's the prototype for the QPainter member function:

  void  drawPixmap ( int x, int y, const QPixmap & pixmap )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top