What are the performance implications of using an immediate-mode GUI compared to a retained-mode GUI?

C++PerformanceUser InterfaceDesktop ApplicationImmediate Mode

C++ Problem Overview


I am currently working on a standard Windows desktop application (standard meaning no fancy stuff: just buttons, text, sliders, etc.), and have decided to write a GUI framework on my own, after looking into some GUI frameworks and being repelled by all of them. Since it’s a hobby project, I am also willing to experiment, and decided to make the GUI immediate-mode, not retained-mode, as I really like the way it simplifies the code. Here is the question, though:

What are the performance implications of using an immediate-mode GUI compared to a retained-mode GUI, when using it for a typical desktop application?

I always hear that an IMGUI performs worse, since it has to redraw every frame (or, if it somehow caches, it still has to do the logic every frame). But of how much more are we talking here? Am I burning twice the CPU time? More? If I hypothetically ran 20 IMGUI programs, would it max out the CPU (presuming I already optimized it)? I just want to know the ballpark and whether the tradeoffs are still viable in a non-game environment, where there is no need to redraw every frame.

There is also one more implication concerning latency that I don’t understand. In the chapter discussing IMGUI in a work-in-progress book by Johannes Norneby, it is explained as follows:

> ### Frame shearing > > One aspect of IMGUI to be aware of in the context of real-time > applications (constantly rendering new frames many times per second) > is that user interactions will always be in response to something that > was drawn on a previous frame. This is because the user interface must > be drawn at least once for the user to be aware that there are widgets > there to be interacted with. Most of the time this doesn’t cause any > problems if the frame rate is high enough, but it is something to be > aware of.

How is this any different in a retained-mode GUI? Does it mean that I have one more frame of input lag over a retained-mode GUI?

C++ Solutions


Solution 1 - C++

Since there seems to be some interest in this question still (judging by the views), I thought I might as well post an update.

I ended up implementing an immediate-mode GUI as my master’s thesis, and have some numbers in on the performance. The gist is:

It's fine - quality of implementation dominates, not systematic characteristics.

Compared to many other existing retained mode GUIs, my immediate mode implementation generally performs a lot faster. The theoretical performance differences between the paradigms are eclipsed by the fact that most GUIs are horribly unoptimized. Overall, imgui is a completely viable approach to creating a GUI that responds fast and does not drain the battery.

I created a Spotify clone with about 50% of the UI elements, and rendering a single frame was in the microsecond range. In fact, the application consistently used less than 400 μs for a single frame. With V-Sync enabled on a 60 Hz monitor, this equates to roughly 3% CPU load on a single core (400 μs per 16 ms) for a naive implementation. Furthermore, a decent chunk of these 400 μs were caused by constant factors that wouldn’t increase the load with more UI elements (e.g., receiving input or setting up GPU state that doesn’t scale with UI complexity).

The perfectionist in me still disliked the fact that a GUI that did nothing was consuming cycles, but the upsides were tremendous: When the GUI was being heavily interacted with, or when the window was being resized, it was still hitting 400 μs! This blows many existing retained-mode GUIs out of the water. Try resizing Spotify, Windows Explorer, Visual Studio, or basically any other desktop application, and see how it reacts, to understand what I mean. My guess would be that Spotify goes down to about 2 fps on my PC when resizing.

And changing the UI is basically free. If you display a hundred buttons in one frame, and then replace them all with textboxes in the next, there is still no difference to the performance. Retained-mode GUIs tend to struggle in such scenarios.

Three more thoughts:

  • Most of the time is spent on text rendering, the rest is close to irrelevant. If you want to heavily optimize, this is going to be the thing to focus on. But even with little optimization, it can be made decent.

  • I doubt that the vast difference in performance can be explained only—or even at all—by the difference between the retained and immediate modes. For example, Spotify uses a Web stack for UI; that’s bound to be slow.

    I guess, WPF, Win32, and the likes are just slow because they can get away with it, or because they were optimized for completely different hardware than the one we use nowadays. They also do more, of course, but not remotely enough to justify the difference.

  • I’m sure you could make a retained-mode GUI that is a lot faster than my immediate-mode GUI. There is just little incentive for it in general, which is a little sad, to be honest; I like efficient things.

Update

Since a couple of people asked, I’ve decided to release my thesis.

Please be aware that you will be looking at something that was not meant for public release and doesn’t pass my personal lowest quality expectations for a publicly released piece of software (which is why I hadn’t released it in the first place). So please only use it for educational purposes and not for building actual software with it. I won’t be supporting it, either.

The download includes the thesis itself (in German!), some pre-built executables for Windows, and the source code (in C++):

<https://1drv.ms/u/s!AsdZfH5hzKtp9zy1YZtHgeSMApOp?e=FbxLUs>

Have fun!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionpulp_userView Question on Stackoverflow
Solution 1 - C++pulp_userView Answer on Stackoverflow