mkorunoski
mkorunoski

Reputation: 71

QPixmap paint performance issue

I need to recreate the Windows 7 theme where the application window header is transparent and displays blurred screen contents. My idea was to capture the screen contents and display them blurred in the header. For that reason I extended QQuickPaintedItem.

Here is the header:

class DesktopImage : public QQuickPaintedItem
{
    Q_OBJECT

    Q_PROPERTY(int desktopX READ desktopX WRITE setDesktopX NOTIFY desktopXChanged)
    Q_PROPERTY(int desktopY READ desktopY WRITE setDesktopY NOTIFY desktopYChanged)

public:
    explicit DesktopImage(QQuickItem *parent = nullptr);

    void paint(QPainter *painter) override;

    int desktopX() const;
    void setDesktopX(int desktopX);

    int desktopY() const;
    void setDesktopY(int desktopY);

signals:
    void desktopXChanged();
    void desktopYChanged();

private:
    void grabScreensContent();

private:
    QPixmap mScreensContent;
    int mDesktopX;
    int mDesktopY;

};

the grabScreensContent() method do as the name suggest. The paint() method is implemented as follows:

void DesktopImage::paint(QPainter *painter)
{
    QRectF target(0, 0, width(), height());
    QRectF source(mDesktopX, mDesktopY, width(), height());
    painter->drawPixmap(target, mScreensContent, source);
}

on the QML side, I use the type as follows:

DesktopContent {
    id: desktop
    desktopX: window.x
    desktopY: window.y
    width: parent.width
    height: parent.height    
}

as you can see the desktopX (desktopY) properties are bound to the window x (window y) properties so that when the user moves the window the portion of the background that needs to be drawn is properly fetched. However the drawing is not as fluid as one might expect. Here is the result:

Slow pixmap paint

Can someone suggest an performance improvement?

Upvotes: 1

Views: 491

Answers (1)

Alexander V
Alexander V

Reputation: 8718

Take care of renderTarget by setting it to FramebufferObject. This basically should make it as efficient as normal QML rendering yet you can use QPainter which is sometimes conveninent.

DesktopImage::DesktopImage(QQuickItem *parent)
{
    // this setting is not default
    this->setRenderTarget(QQuickPaintedItem::FramebufferObject);
}

Also, only operate with the limited screen area if you don't need the whole screen. This may or may not help depending on the platform / implementation but I always limit the scope on the target first and then position the source within it. The low level painting is not necessarily very intelligent and may expect many changes across the whole area. So we should rather specify the minimum target area and just alter it (this case works like that).

void DesktopImage::paint(QPainter *painter)
{
    QRectF target(mDesktopX, mDesktopY, width(), height()); // now limited
    QRectF source(0, 0, width(), height());                 // now within smaller target
    painter->drawPixmap(target, mScreensContent, source);
}

Upvotes: 2

Related Questions