3
\$\begingroup\$

I am writing a game engine and am trying to wrap my head around data streaming while rendering. What I mean by this is being able to load resources (however slow it may be) while rendering and not slowing it down visibly. My engine is not a state of the art engine by any means and renders Quake3 style maps. The files needed to load are not super large and can be easily loaded in a few seconds but I want to ability to load in as quick as possible and load connected maps while playing without slowdown. What I am looking for is a sort of functionality where I can start a function and have it either run on it's own thread or just run for a specific amount of time every frame. In other words, I give it maybe a maximum running time of 0.01 and it will return control after that amount of time, meaning I can keep my FPS completely solid. Does such a functionality exist?

I know you can use threading for something like this but I need clarification on the concept. When people use the expression "UI thread" or "I/O thread", what does this mean? Is it a thread that is always being used on a specific core so that it always has priority? Do they have a thread running for the entirety of the engine that just handles specific logic?

\$\endgroup\$
3
\$\begingroup\$

You should load the data from the disk, doing any conversion or processing of that data you need (ideally zero) on a background thread. Once the data is loaded, provide a signal to your main thread (via any one of many available thread sync primitives available to your language/platform) that the resource is loaded and allow the main thread to hand the resource over to the GPU.

The terms "UI thread" or "I/O thread" generally refer to the task the thread is designed to accomplish. The "UI thread" is often synonymous with the main thread, and is the one where the platform's UI is being run and often where the graphics API is being interacted with as well.

The term "I/O thread" generally means a thread whose sole purpose is to do heavy lifting from a disk (input and output, or I/O)... such as loading files from it.

Starting and stopping threads is more expensive than simply putting them to sleep when there is nothing to do, so you'll generally spin up the threads you'll want to use for background work -- such as loading your resources from the disk -- and leave them up for the duration of the application.

Generally you cannot interact with a graphics API from multiple threads without explicit synchronization between them (some exceptions apply, but usually not around the tasks that transfer data to the GPU), so it's best to confine access to the GPU to a single thread.

\$\endgroup\$
  • 1
    \$\begingroup\$ Some APIs are either quite good at multi-threaded GPU resource creation or at least can be good at it depending on the driver. Ignoring OpenGL (as everyone should) and looking at D3D11 we see pretty good support for creating textures on multiple threads and relatively strongly-recommended support for creating shaders on multiple threads. For instance, see msdn.microsoft.com/en-us/library/windows/desktop/… and pay attention to the parts about msdn.microsoft.com/en-us/library/windows/desktop/… \$\endgroup\$ – Sean Middleditch Dec 10 '15 at 19:01
  • \$\begingroup\$ I'd forgotten about that. The last time I bothered checking DriverConcurrentCreates was not widely available (e.g., tended to return false), and the only benefit you got out of the "threading" stuff was command list buildup (which is still useful, but different). It's probably worth the OP checking that out if he/she is using D3D11 as it's presumably got better support these days. \$\endgroup\$ – Josh Dec 10 '15 at 19:32
  • \$\begingroup\$ @JoshPetrie Thanks! When you say the UI thread is usually the main thread, what does this mean? Is there any way the programmer actually specifies this or is does it mean that it actually isn't threaded at all and all the other processes are threaded? Sorry if that's confusing. I am under the impression that if you don't use threading, you're on the main thread. So if you only threaded other actions, and didn't put the UI logic into its own thread, wouldn't it be on the "main thread"? \$\endgroup\$ – user923 Dec 10 '15 at 20:24
  • \$\begingroup\$ You always have at least one thread, the one in which your program starts. That thread is the "main thread." This is also usually the thread where you end up running your UI message pump, so it's also the UI thread. \$\endgroup\$ – Josh Dec 10 '15 at 20:35
  • \$\begingroup\$ @JoshPetrie: I don't do much in the way of high-perf graphics myself, but every doc from the IHVs I've read seem to indicate that they all do multithreaded resource creation these days. I'm perhaps being naive and trusting. :) \$\endgroup\$ – Sean Middleditch Dec 10 '15 at 23:57
0
\$\begingroup\$

You could implement a lazy loading system. I am doing something like this in my engine.

Instead of keeping a reference for the original resource directly in the entity, you can have a reference to a proxy of that resource.

The proxy would have the necessary data for loading the resource (the path or name of the file, for example) and the loaded resource.

When the resource was requested, the proxy could internally check if it already have the loaded resource, and then return the resource.

If the resource is not yet loaded, the proxy can start the loading (in another thread), and while the loading is on route, everytime the resource was requested, the proxy returns a mock resource of that type that can be a singleton instance.

That detail is important: Do not return a null. Returning an empty mock is better because it prevents the need to spread "if (obj != null)" to keep the code safe. You can have one mock file for every resource type (a mute sound file, an empty 3d model, a 1x1 transparent texture etc.).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.