Quick SG engine renders twice.
-
Hi there,
I'm developing something with QT binding BGFX. I'd like to paint something OpenGL under QML things. So I tried to connect the main window signals such as beforeRenderPassRecording and beforeSynchronizing.
While the code runs, I see my OpenGL draws, then QML things, and OpenGL draws again. So the QML things is overlaid by OpenGL rendering.
My QML is as following:
import QtQuick 2.12 import QtQuick.Window 2.12 Window { id : kcad_main_window width: 640 height: 480 visible: true title: qsTr("Hello World") Text { id: text1 x: 22 y: 15 color: "#ff0000" text: qsTr("Text") font.pixelSize: 12 } Text { id: text2 x: 601 y: 15 color: "#ff0000" text: qsTr("Text") font.pixelSize: 12 } Text { id: text3 x: 22 y: 454 color: "#ff0000" text: qsTr("Text") font.pixelSize: 12 } Text { id: text4 x: 601 y: 454 color: "#ff0000" text: qsTr("Text") font.pixelSize: 12 } }
I get native window handle with this method:
QQuickWindow *p_main_win = qobject_cast<QQuickWindow*>( engine.rootObjects().at(0) ); p_bgfx_bridge_inst->set_wid(p_main_win -> winId());
I connected all 16 signals according to this document and output debug information within all 16 slots to trace:
https://doc.qt.io/qt-6/qquickwindow.html
Then I maxmized my window, log as below:MY_DEBUG_HERE: Signal: afterAnimating MY_DEBUG_HERE: Signal: beforeFrameBegin MY_DEBUG_HERE: Signal: beforeSynchronizing MY_DEBUG_HERE: Signal: afterSynchronizing MY_DEBUG_HERE: Signal: beforeRendering MY_DEBUG_HERE: Signal: beforeRenderPassRecording MY_DEBUG_HERE: Signal: afterRenderPassRecording MY_DEBUG_HERE: Signal: afterRendering MY_DEBUG_HERE: Signal: frameSwapped MY_DEBUG_HERE: Signal: afterFrameEnd MY_DEBUG_HERE: Signal: afterAnimating MY_DEBUG_HERE: Signal: beforeFrameBegin MY_DEBUG_HERE: Signal: beforeSynchronizing MY_DEBUG_HERE: Signal: afterSynchronizing MY_DEBUG_HERE: Signal: beforeRendering MY_DEBUG_HERE: Signal: beforeRenderPassRecording MY_DEBUG_HERE: Signal: afterRenderPassRecording MY_DEBUG_HERE: Signal: afterRendering MY_DEBUG_HERE: Signal: frameSwapped MY_DEBUG_HERE: Signal: afterFrameEnd
If I enable log with following code:
QLoggingCategory::setFilterRules(QStringLiteral("qt.scenegraph.*=true")); qSetMessagePattern("%{category}: %{message}");
The overall output is as following:
qt.scenegraph.renderloop: update from item QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.renderloop: update from item QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.renderloop: reisze() QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.renderloop: exposureChanged() QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.renderloop: handleExposure() QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.renderloop: - render thread already running qt.scenegraph.renderloop: polishAndSync (in expose) QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.time.renderloop: [window 0x555555a1ea30][gui thread] polishAndSync: start, elapsed since last call: 9174 ms default: MY_DEBUG_HERE: Signal: afterAnimating qt.scenegraph.renderloop: - lock for sync qt.scenegraph.renderloop: - wait for sync qt.scenegraph.renderloop: (RT) WM_RequestSync qt.scenegraph.renderloop: (RT) - triggered from expose qt.scenegraph.renderloop: (RT) --- done processEventsAndWaitForMore() qt.scenegraph.renderloop: (RT) syncAndRender() qt.scenegraph.time.renderloop: [window 0x555555a1ea30][render thread 0x5555558eb050] syncAndRender: start, elapsed since last call: 9173 ms qt.scenegraph.renderloop: rhi swapchain size QSize(2288, 1296) default: MY_DEBUG_HERE: Signal: beforeFrameBegin qt.scenegraph.renderloop: (RT) - updatePending, doing sync qt.scenegraph.renderloop: (RT) sync() default: MY_DEBUG_HERE: Signal: beforeSynchronizing default: MY_DEBUG_HERE: Signal: afterSynchronizing qt.scenegraph.renderloop: (RT) - rendering started default: MY_DEBUG_HERE: Signal: beforeRendering default: MY_DEBUG_HERE: Signal: beforeRenderPassRecording default: MY_DEBUG_HERE: Signal: afterRenderPassRecording qt.scenegraph.time.renderer: time in renderer: total=5ms, preprocess=0, updates=0, rendering=5 default: MY_DEBUG_HERE: Signal: afterRendering default: MY_DEBUG_HERE: Signal: frameSwapped qt.scenegraph.renderloop: (RT) - rendering done default: MY_DEBUG_HERE: Signal: afterFrameEnd qt.scenegraph.renderloop: (RT) - wake Gui after expose qt.scenegraph.time.renderloop: [window 0x555555a1ea30][render thread 0x5555558eb050] syncAndRender: frame rendered in 12ms, sync=0, render=5, swap=7 qt.scenegraph.renderloop: (RT) --- begin processEvents() qt.scenegraph.renderloop: (RT) --- done processEvents() qt.scenegraph.renderloop: (RT) done drawing, sleep... qt.scenegraph.renderloop: (RT) --- begin processEventsAndWaitForMore() qt.scenegraph.renderloop: - unlock after sync qt.scenegraph.time.renderloop: [window 0x555555a1ea30][gui thread] Frame prepared, polish=0 ms, lock=0 ms, blockedForSync=13 ms, animations=0 ms qt.scenegraph.renderloop: - done with handleExposure() qt.scenegraph.renderloop: - update request QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.renderloop: polishAndSync (normal) QQuickWindowQmlImpl(0x555555a1ea30 active exposed, visibility=QWindow::Maximized, flags=QFlags<Qt::WindowType>(Window), title="Hello World", geometry=70,64 2288x1296) qt.scenegraph.time.renderloop: [window 0x555555a1ea30][gui thread] polishAndSync: start, elapsed since last call: 13 ms default: MY_DEBUG_HERE: Signal: afterAnimating qt.scenegraph.renderloop: - lock for sync qt.scenegraph.renderloop: - wait for sync qt.scenegraph.renderloop: (RT) WM_RequestSync qt.scenegraph.renderloop: (RT) --- done processEventsAndWaitForMore() qt.scenegraph.renderloop: (RT) syncAndRender() qt.scenegraph.time.renderloop: [window 0x555555a1ea30][render thread 0x5555558eb050] syncAndRender: start, elapsed since last call: 14 ms default: MY_DEBUG_HERE: Signal: beforeFrameBegin qt.scenegraph.renderloop: (RT) - updatePending, doing sync qt.scenegraph.renderloop: (RT) sync() default: MY_DEBUG_HERE: Signal: beforeSynchronizing default: MY_DEBUG_HERE: Signal: afterSynchronizing qt.scenegraph.renderloop: (RT) - sync complete, waking Gui qt.scenegraph.renderloop: (RT) - rendering started default: MY_DEBUG_HERE: Signal: beforeRendering default: MY_DEBUG_HERE: Signal: beforeRenderPassRecording qt.scenegraph.renderloop: - unlock after sync qt.scenegraph.time.renderloop: [window 0x555555a1ea30][gui thread] Frame prepared, polish=0 ms, lock=0 ms, blockedForSync=1 ms, animations=0 ms default: MY_DEBUG_HERE: Signal: afterRenderPassRecording qt.scenegraph.time.renderer: time in renderer: total=31ms, preprocess=0, updates=0, rendering=31 default: MY_DEBUG_HERE: Signal: afterRendering default: MY_DEBUG_HERE: Signal: frameSwapped qt.scenegraph.renderloop: (RT) - rendering done default: MY_DEBUG_HERE: Signal: afterFrameEnd qt.scenegraph.time.renderloop: [window 0x555555a1ea30][render thread 0x5555558eb050] syncAndRender: frame rendered in 40ms, sync=0, render=32, swap=8 qt.scenegraph.renderloop: (RT) --- begin processEvents() qt.scenegraph.renderloop: (RT) --- done processEvents() qt.scenegraph.renderloop: (RT) done drawing, sleep... qt.scenegraph.renderloop: (RT) --- begin processEventsAndWaitForMore()
You can see all the signals are emitted twice. The log of 2 passes is slightly different. You can make a diff and see the difference. It's rather strange.
My env is QT 6.5.3, Ubuntu 23.04 with X Window (not wayland).
Waiting for any suggestion. Thanks.
-
I found that 2 problems exists.
The first problem is: there's an issue with threading. While I debug my program step by step, the render sequence is: "bgfx -> QML -> bgfx ->QML". Every render is executed twice but the sequence is right. The expected behavior should be "bgfx -> QML" but 2 passes is all right. But while the program is free running, the sequence is strange and the last QML rendering seems not performed.
The second problem is: when QML is rendered and the signal "frameSwapped" is emitted, the BGFX rendered contents are cleared. Only QML contents display on window. So there's no underlay under QML contents. The expected behavior should be QML contents overlaid above BGFX contents.