• Advertisement
Sign in to follow this  

Responsive UI in compute-heavy games

This topic is 822 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Say, you're working on a game with a complex simulation or lots of AI.  Often in such games, the UI stalls while the game catches up.  I see this a lot in loading screens too; the game (including the spinner or whatever other "now loading" hint the game provides) freezes while the application loads some file, presumably doing something CPU-bound.

 

Why is that, and is there a way to avoid it?  Being a server engineer, I don't work much with UI-driven applications, but I know that your bog-standard desktop application, UI runs on its own thread and business logic runs on another (or several), with input being disclosed via events or some similar messaging construction.  Can this threading model be applied to games like the above?

 

I've done a few simple single-threaded games like side-scrollers and text-based stuff in the past, but I'm fairly ignorant when it comes to the threading models of bigger affairs.

Share this post


Link to post
Share on other sites
Advertisement

Often in such games, the UI stalls while the game catches up. [...]
Why is that, and is there a way to avoid it?

Because it's the easiest to implement, and often is "good enough".
 

I know that your bog-standard desktop application, UI runs on its own thread and business logic runs on another (or several), with input being disclosed via events or some similar messaging construction.

As far as I'm aware, even with desktop applications, this isn't the case by default. You can make desktop applications multithreaded, but I don't believe they are by default.

I'm pretty sure both Win32 and Qt are singlethreaded unless you (as the programmer) choose to spawn more threads, but I might be mistaken about that.
 

Can this threading model be applied to games like the above?

Yep.

Actually, GUIs in games are usually alot simpler than desktop GUIs, and so where desktop GUIs cache alot of the rendering to avoid as much redrawing as possible, games usually just redraw everything every frame and only cache computationally-expensive things like text-rendering, because games usually have smaller (and simpler) widget hierarchies.
This isn't always the case, though. Take MMOs or larger RPGs for example: They have complex widget hierarchies that may need more caching then the average game.

If needed, you can multithread your UI in games as well. But (not being in the game industry myself) I'd guess, you'll just keep your UI on the same thread with the rest of your rendering, and instead spawn threads (or tasks running on worker threads) for whatever the "computationally expensive" thing that you're expecting to slow down the main thread. Slow AI and pathfinding and level geometry streaming can be handled on the separate threads, instead of the (relatively) fast UI code.

Share this post


Link to post
Share on other sites

D3D9 (and OpenGL without a lot of driver-specific hackery) force you to perform almost all of your graphics resource management on a single thread, which also be the one that created your window and the one that polls Windows for input messages. Creating too many large resources per frame will block this thread and ruin your graphical framerate :(

D3D11 partially fixed it, where now any thread can perform graphics resource management. However, the D3D back-end still runs on a single thread, and may act as a bottleneck. If this back-end thread stalls, then your "main" thread (the one performing backbuffer flips, etc) may block until it catches up... So you still have to be careful how much graphics work you do 'per frame' on a loading screen, even from background threads.

D3D12/Vulkan should finally fix this issue.

 

There's also non-graphics related issues. If for whatever reason, the game is doing deserialization of large complex/compressed file formats on the "main thread", then that will impact the loading screen. Some game engines actually do a lot of wasteful deserialization during loading...

Share this post


Link to post
Share on other sites


D3D9 (and OpenGL without a lot of driver-specific hackery) force you to perform almost all of your graphics resource management on a single thread, which also be the one that created your window and the one that polls Windows for input messages. Creating too many large resources per frame will block this thread and ruin your graphical framerate

 

I'm less interested in graphics stalls here than CPU-oriented stalls, like how Civilization 5 locks up when the game is processing AI turns.  Certainly, if your rendering is bottlenecked, you're kind of screwed.

 


There's also non-graphics related issues. If for whatever reason, the game is doing deserialization of large complex/compressed file formats on the "main thread", then that will impact the loading screen. Some game engines actually do a lot of wasteful deserialization during loading...

 

This has always confused me too.  Why on earth would you ever want to load on the main thread?  Certainly, if you properly pack/format your resources, you'll be able to do everything in asynchronous IO land anyway, but it seems to me that a responsive UI should be something sacred when you're writing any consumer-oriented software.

Share this post


Link to post
Share on other sites

[stuff]

 

Ah, I see.  Thanks for the information.  I hadn't considered the aspect of loading graphical resources being stuck on the rendering thread.  It was baffling me, because if I had to do something like run a few hundred megabytes of data through zlib and into RAM I'd do it all on another thread and just pass a pointer to the memory back.

 

The model you describe makes much more sense, and it's a bit uplifting since I've been treating games as these weird special snowflakes  because of their interactive nature and the eccentricities of the graphics APIs.  Knowing that most engines do it pretty much the same way as 90% of multithreaded software out there cures me of my analysis paralysis. :)

Share this post


Link to post
Share on other sites

D3D9 (and OpenGL without a lot of driver-specific hackery) force you to perform almost all of your graphics resource management on a single thread, which also be the one that created your window and the one that polls Windows for input messages.


That's not true for the input message part.
I use a seperate thread for input and another for OpenGL since 20 years without issues for an editor application on Windows.

Share this post


Link to post
Share on other sites


The simple answer is that everyone still sucks at writing multithreaded software.

This is me.  Anybody got any advice to improve?  Any articles, tutorials, blog posts?

And more on topic I also was interested in multithreaded architecture for responsive UI's, any articles or tutorials on that?

Share this post


Link to post
Share on other sites

Anybody got any advice to improve?


Practice makes perfect!

Threading is a beast, and there is lots of documentation and papers on it. Most of it is from the perspective of server side development and scaling a server for many requests, and has to be repurposed for gamedev though...

Share this post


Link to post
Share on other sites

It's a shame that BeOS isn't around any more. I learned C++ on that OS that forced you to multithread everything. It was a great way to learn, and to make all (or a lot of) the possibles mistakes

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement