1

I am trying to make QML component that would live output and scale image 2000x2000@60 fps.

I ended up with custom QQuickItem as QQuickImageProvider seems to be designed for other purposes and QQuickPaintedItem did not gave me performance desidered.

So I have:

MyQuickItem.cpp

MyQuickItem::MyQuickItem(QQuickItem *parent)
    : QQuickItem(parent)
{
    setFlag(ItemHasContents, true);
}

void MyQuickItem::setImage(QImage image)
{
    if (!image.isNull()) {
        currentImg = image;
        update();
    }
}

QSGNode* MyQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
{
    QSGImageNode * node;
    if (!oldNode) {
        node = window()->createImageNode();
        oldNode = node;
    } else {
        node = static_cast<QSGImageNode *>(oldNode);
    }

    QSGTexture *texture = window()->createTextureFromImage(currentImg);

    node->setRect(boundingRect());
    node->setSourceRect(QRectF(QPointF(0.0, 0.0), texture->textureSize()));
    node->setTexture(texture);
    node->setOwnsTexture(true);

    return node;
}

Registring this as

qmlRegisterType<MyQuickItem>("MyItem", 1, 0, "MyItem");

QQmlComponent* component = new QQmlComponent(engine, ":/test.qml");
MyQuickItem* myItem = quickItem->findChild<MyQuickItem*>("myItem");
if (myItem ) {
    connect(this, &ImageGenerator::newFrame, radarItem, &MyQuickItem::setImage);
}

and creating in QML:

import MyItem1.0
import QtQuick 2.3

Item {
    MyItem{
        id: myImage
        objectName: "myItem"
        visible: true
        anchors.fill: parent
        anchors.centerIn: parent
    }

    Rectangle {
        id: boundingRect
        border.color: "blue"
        border.width: 3
        color: "transparent"
        anchors.fill: parent
    }
    anchors.fill: parent
}

I've got this working. ImageGenerator generates 2000x2000 QImage and sends it to MyItem that is MyQuickItem.

And it is still very slow. It consumes approx 30% of i5-4460 and "freezes" other UI components.

Investigation:

Changing QSGImageNode to QSGRectangleNode with solid color, but still doing

QSGTexture *texture = window()->createTextureFromImage(currentImg);

decrease CPU usage down to 1-3%.

But as soon as I add

texture->bind();

hello 30% CPU again.

So, one problem is that 2000x2000 image is too slow to be uploaded to GPU.

On the other hand

QSGTexture *texture = window()->createTextureFromImage(currentImg.scaled(boundingRect().size().toSize())); 

without and with bind() gives same 30% CPU.

other problem is that scaling 2000x2000 to fit QML component size on CPU is too slow.

Any possibility to decrese this disgusting CPU consumption?

P.S. I can not generate QImage with other size but can use poiner to buffer to generate image to.

Originally this image generator was used on QWidget and there were no such problems: QImage was created 2000x2000 and set as image to QWidget. Same CPU consumption was like 2-3%.

1 Answer 1

2

TL:DR;

Partial solution:

construct QImage as

m_pImage = new QImage( width, height, QImage::Format_ARGB32_Premultiplied );

and fill it accordingly with premultiplied ARGB

Investigation:

Analyzing output with QSG_RENDER_TIMING = 1 environment variable set I've found that GUI thread was blocked for 60ms every frame just waiting for sync. Converting image was 45ms long and uploading just 15ms.

Here I've found that if original image is not Format_RGB32 or Format_ARGB32_Premultiplied it will be converted to Format_ARGB32_Premultiplied.

After changing original image to Format_ARGB32_Premultiplied I've got GUI thread blocked only for 1ms, convert 0ms and upload for same 15ms.

It still consuming 30% of CPU (IDK why) but at least I do not have anymore this freezes on UI elements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.