天天看點

QT之 scene graph 的局部重新整理嘗試(一)

Qt5以後的版本,都推薦使用GPU去渲染,提高渲染的效果,即使用scene graph這個機制去渲染。 使用Qt的Scene Graph來開發應用,要點是批量渲染。這是由OpenGL的特性決定的,因為通過OpenGL,将以往CPU串行的部分并行化,進而大大提升渲染效率,再加上OpenGL本質上是一個巨大的狀态機,在進行批量渲染的時候,可以有效地減少OpenGL狀态切換所帶來的性能開銷,同時OpenGL預留的一些狀态,需要開發者有基本的認知,由于OpenGL是一個開放的标準,是以考慮到相容性,其采用了C/S架構。C端即CPU部分,S端對應GPU。在頂點和紋理資料從C端傳入S端之前,會在C端形成一個緩沖區(一說緩存),我們常說的VBO、FBO和PBO就是這一類緩沖區。正确地設定緩沖區的數量和大小,可以為應用程式的性能提升帶來很大的幫助。但是它采用的是整屏重新整理的政策,這時候就很讓人頭疼了,背景百年不變,又是這麼大一張圖,還每一幀都去重新整理,這個效率的話就可想而知。是以一直也都在找相關的接口,能否達到想要的目的。

後來,發現QQuickItem有一個Flag的屬性。如下:

flags QQuickItem::Flags
This enum type is used to specify various item properties.

Constant				Value				Description
QQuickItem::ItemClipsChildrenToShape	0x01			       Indicates this item should visually clip its children so that they are rendered only within the boundaries of this item.
QQuickItem::ItemAcceptsInputMethod	0x02				Indicates the item supports text input methods.
QQuickItem::ItemIsFocusScope		0x04				Indicates the item is a focus scope. See Keyboard Focus in Qt Quick for more information.
QQuickItem::ItemHasContents		0x08				Indicates the item has visual content and should be rendered by the scene graph.
QQuickItem::ItemAcceptsDrops		0x10				Indicates the item accepts drag and drop events.
           

其中的Flag  QQuickItem::ItemHasContents 描述這個item是否有可視化的内容,是否應該被scene graph去渲染。于是就猜想這個屬性是否能到我們想要的效果呢?如果通過如下的方法:

void QQuickItem::setFlag(Flag flag, bool enabled = true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disabled.
These provide various hints for the item; for example, the ItemClipsChildrenToShape flag indicates that all children of this item should be clipped to fit within the item area.
           

設定flag  QQuickItem::ItemHasContents為false,是否GPU的buffer可以cache這個Item的東西,而不去在重新整理渲染這個東西呢?

于是寫了測試代碼:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QQuickView>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQuickView myview;
    myview.setSource(QUrl(QStringLiteral("qrc:/main.qml")));


    QQuickItem* item = myview.rootObject();
    QQuickItem* testItem = item->findChild<QQuickItem *>("txt");
    testItem->setFlag(QQuickItem::ItemHasContents,false);
    
    myview.show();

    return app.exec();
}
           

QML檔案:

import QtQuick 2.5

Item {
    width: 640
    height: 480

    Text {
        id: txt
        objectName: "txt"
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}
           

執行結果如下:

QT之 scene graph 的局部重新整理嘗試(一)

我們可以看到神馬都沒了,雖然不去渲染了,但是并沒有在buffer區cache住這段圖像。但是這個東西和設定這個item的visible有啥差別呢?有必要去重複這個東西嘛?然後我進行了各種嘗試,最後發現一個使用的用處,如下:

将上面的QML修改一下,如下:

import QtQuick 2.5

Item {
    width: 640
    height: 480

    Text {
        id: txt
        objectName: "txt"
        text: qsTr("Hello World")
        anchors.centerIn: parent

        Rectangle{
            id: testRect
            objectName: "testRect"
            width: 20
            height: 20
            color: "red"
        }
    }
}
           

這個時候的測試結果會是啥呢?是否是和設定txt控件的visible屬性一樣呢?會整個界面都是空白嗎?

測試結果如下:

QT之 scene graph 的局部重新整理嘗試(一)

結果隻有txt控件沒有顯示,而它的子控件還是顯示的。這點的用處可能就在某些情況下,可以設定單單設定某個節點不顯示。

但是Qt提供這個flag真的是出于這個目的嗎?後來在幫助文檔上面找到了一些線索。

我在關于QQuickItem這邊的幫助文檔沒有找到相關的描述,于是我去找QGraphicsItem 是否有相關的屬性,進而會有說明呢?

結果功夫不負有心人,真的被我找到了,QGraphicsItem果然也有和QQuickItem相對應的屬性,描述如下:

QGraphicsItem::ItemHasNoContents	0x400			The item does not paint anything (i.e., calling paint() on the item has no effect). You should set this flag on items that do not need to be painted to ensure that Graphics View avoids unnecessary painting preparations. This flag was introduced in Qt 4.6.
           

這邊描述說明當設定了這個屬性,渲染架構不但不回去渲染繪制它,連 painting preparations繪制的預準備 都不用了,更加提高了效率。

至于我為什麼會去查找QGraphicsItem,是由于QT的scene graph渲染引擎和graphics view的渲染引擎除了底層的渲染的差別較大,但是上層提供的接口還是有很多類似之處,而且graphics view的渲染引擎是較為成熟了,是以相關的資料也會較為齊全。

總結:這個flag 的屬性并沒有預期的那樣得到我想要的結果,沒有達到局部渲染的效果,但是還是有收獲的,了解了Flag QQuickItem::ItemHasContents  屬性,而且也為接下來尋找局部渲染找到了一條思路,可去參考   graphics view  這邊是否有方法解決,scene graph 這邊是否會有對應的方法呢?

這篇文章沒有解決問題,是以也隻就是抛磚引玉了,大家如果有找到方法歡迎不吝賜教,後面我找到方法或者有其他的嘗試我會繼續加載照片文章~~

繼續閱讀