Scene Graph 的優勢
在Qt5中推出了一個新的渲染底層 Scene Graph,來替代Qt4時期的 Graphics View。如果大家使用過Qt5的 Qt Quick 子產品,你會感覺 Qt Quick 的畫面渲染速度和效率比Qt4的 GraphicsView 來說好了很多。主要原因是在渲染部分精簡了渲染堆棧,并且充分利用顯示卡加速,将渲染負擔轉移到GPU來進行,實作了負載均衡。
Scene Graph 是直接建構在OpenGL之上的,是以 Scene Graph 對于OpenGL開發者來說要熟悉一些,而從來沒有接觸過OpenGL開發的開發者就有些為難了,幸好Qt在其之上有 QQuickPaintedItem 等友善的類,它可以像QPainter那樣對其進行渲染操作。
使用Qt的 Scene Graph 來開發應用,為了提升性能要點是批量渲染。這是由OpenGL的特性決定的,因為通過OpenGL,将以往CPU串行的部分并行化,進而大大提升渲染效率,再加上OpenGL本質上是一個巨大的狀态機,在進行批量渲染的時候,可以有效地減少OpenGL狀态切換所帶來的性能開銷,同時OpenGL預留的一些狀态,需要開發者有基本的認知,由于OpenGL是一個開放的标準,是以考慮到相容性,其采用了C/S架構。C端即CPU部分,S端對應GPU。在頂點和紋理資料從C端傳入S端之前,會在C端形成一個緩沖區(一說緩存)。正确地設定緩沖區的數量和大小,可以為應用程式的性能提升帶來很大的幫助。
Qt Quick 中的渲染
渲染如何具體工作可以參考官方文檔
Qt Quick 渲染循環
渲染循環有三種方式:basic,windows 和 threaded。其中 basic 和 windows 是單線程,而 threaded 是指定線程内渲染。Qt會根據情況自動選擇使用哪種方式。當性能不滿足,或者出于測試考慮時,可以強制啟動QSG_RENDER_LOOP。
windows 和 threaded 方式非常依賴于OpenGL将交換間隔設定為1。一些顯示卡驅動允許使用者覆寫或關閉這個值,并忽略Qt的修改請求。但如果沒有這個設定,會導緻交換間隔太短,CPU滿負荷運轉。如果知道系統不能自動調整 vsync-based,請手動設定 QSG_RENDER_LOOP=basic 來啟動 basic 渲染方式。
threaded 渲染方式
threaded 渲染方式使用獨立線程來渲染,由于使用多線程,性能得到顯著提升,且界面回報更加流暢。其簡易示意圖如下:
非 threaded 渲染方式 (basic 和 windows)
這兩種方式使用單線程渲染,但寫代碼時要按照threaded渲染方式來寫,友善日後移植。其簡易示意圖如下:
檢視自己電腦上的渲染方式
QT開發交流+赀料君羊:714620761
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLoggingCategory>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QLoggingCategory::setFilterRules(QStringLiteral("qt.scenegraph.general=true"));
qSetMessagePattern("%{category}: %{message}");
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
運作結果:
qt.scenegraph.general: threaded render loop
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.67 ms
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.67 ms
qt.scenegraph.general: texture atlas dimensions: 1024x512
qt.scenegraph.general: R/G/B/A Buffers: 8 8 8 8
qt.scenegraph.general: Depth Buffer: 24
qt.scenegraph.general: Stencil Buffer: 8
qt.scenegraph.general: Samples: 0
qt.scenegraph.general: GL_VENDOR: Intel
qt.scenegraph.general: GL_RENDERER: Intel(R) UHD Graphics 630
qt.scenegraph.general: GL_VERSION: 4.5.0 - Build 24.20.100.6345
qt.scenegraph.general: GL_EXTENSIONS: 略
qt.scenegraph.general: Max Texture Size: 16384
qt.scenegraph.general: Debug context: false
可以看到我使用的是 threaded 渲染方式,畫面垂直同步花費了 16.67 ms。