Noticable slowdown when using
-
Hey.
I have the following setup:
QMainWindow - QDockWidget -- MyOpenGLWidget
MyOpenGLWidget
derives fromQOpenGLWidget
andQOpenGLFunctions
.
I'm attaching theQDockWidget
toQMainWindow
usingmainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget)
and theMyOpenGLWidget
toQDockWidget
with
dockWidget->setWidget(openGLWidget)
Now, the
MyOpenGLWidget
is internally usingDead ImGUI
to draw a node graph, I don't know if that's important, but in theMyOpenGLWidget
constructor, we're setting the vsync and triple buffering like thisauto surfaceFormat = QOpenGLWindow::format(); surfaceFormat.setSwapBehavior(QSurfaceFormat::TripleBuffer); surfaceFormat.setSwapInterval(1); setFormat(surfaceFormat);
Now, the problem is that the node graph is noticeably less responsive, when docked in the
QMainWindow
. It can be observed when scrolling, zooming and creating new nodes in the node graph.
It's not GPU bound, as if it would, then undocking it wouldn't make the thing feel more responsive, but it does. I found theQOpenGLWidget
documentation, and the alternatives section states that adding theQOpenGLWidget
to window turns on OpenGL-based compositing for the whole window, which hurts performance.
The proposed workaround was to instead create aQOpenGLWindow
, useQWidget::createWindowContainer
. So that's what I didQOpenGLWindow* glWindow = new QOpenGLWindow(); QWidget* widgetContainer = QWidget::createWindowContainer(glWindow, dockWidget); MyOpenGLWidget* = new MyOpenGLWidget(widgetContainer); dockWidget->setWidget(widgetContainer); mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
Sadly, it didn't change anything. Is there something else I can do/something I'm missing to make this work? It's really annoying to have the widget be much slower if we're missing some Qt specific setup here.
-
Oh man, getting Qt to work properly in a graphics intensive application at a good frame rate is tricky!
QOpenGLWidget has absolute dog shit performance. Unfortunately you need it if you want the best integration with the rest of the Qt and nice things such as context menus. In my tests though rendering with QOpenGLWidget has an order of magnitude worse performance than simply using a QGLWidget or just QWindow. I think something really stupid is happening inside the implementations.. (texture copy or something like that perhaps..)
In general one problem is that if your setSwapInterval actually works (plenty of bugs there across the whole stack) you're blocking your thread until your swap returns. So if your display is running at 60fps then you're stuck there for 16ms at a time which delays any user input processing that much since the event loop can't run. But it gets even worse if you're rendering multiple windows/widgets! If you're swapping twice then you're blocking twice and now your frame rate is halved, so you're dropping to 30fps and the UI is sluggish as a snail!
In my game editor I've got a decent enough solution but it has taken some effort.
Essentially what I've done is:
- I've settled on QWindow myself and creating the context myself and then wrapping that up inside QWidgetContainer.
- I use a "busy loop" that runs and uses QApplication::processEvents directly with AllEvents | WaitMoreEvents
- I use a separate thread to give a heartbeat, it sleeps some user defined interval and then posts a message to the main thread (on windows it'll try to use the compositor flush to sleep). Main thread then renders on the heartbeat message.
- I disabled app level VSYNC completely (i.e setSwapInterval is always 0)
The key takeaways are that
- if you use any kind of blocking such as VSYNC or thread sleep etc. in your main thread your UI janks!
- if you don't use any kind of blocking and just busy loop as fast you can in your event loop you burn a lot of cycles and drain the users battery!
so whatever solution you want to create you need
- ideally scaling so the frame rate is good and scales to the load
- interruptible waits for throttling the main loop, react to user input as soon as possible
- steady fps with good timing resolution