Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best-practice advice for threading #1054

Closed
rawnsley opened this issue Mar 28, 2019 · 3 comments
Closed

Best-practice advice for threading #1054

rawnsley opened this issue Mar 28, 2019 · 3 comments

Comments

@rawnsley
Copy link
Contributor

I'm looking for some advice about how to manage threading within a dynamic Filament application. A good example would be an app where objects are loaded progressively and displayed to the user as they become available with the minimum of judder.

I understand the general principle that calls to the Filament API must be done on a dedicated single thread and that the actual rendering is done on background threads that Filament manages and that clients of the API don't need to worry about.

This decoupling means that calls to the Filament "render" methods don't take very long, but it also means that this thread must be available promptly whenever a new frame is required. This implies that any load-related tasks that also need to run on the Filament thread must be shorter than the frame time or the app will judder.

With this in mind my app creates a single thread for Filament that is available to both the render loop and the loader (it's implemented using Kotlin coroutines and newSingleThreadContext, but the principles would be the same regardless). The load process is then a sequence of small, granular tasks submitted to the Filament thread: e.g. create a vertex buffer, create a material instance, etc...

Heavy things like bitmap loading are done on background threads and then the actual texture instantiation is done on the Filament thread. Obviously the more I can do on the background threads the better, so that brings me to my first actual question: Is it safe to call any Filament methods from other threads or is any cross-threaded intrinsically unsafe?

I would also welcome any general advice or observations about my approach. The highly granular tasks work, but I suspect the context switching incurs a significant overhead. In the past I've used a queue of pending jobs that are checked as part of the render loop, which eliminates the context switching, but is a bit indirect (coroutines are much neater) and still requires some sort of timer so it can bail if the frame time is exceeded.

@romainguy
Copy link
Collaborator

You shouldn't worry about context switches, Filament uses more than 2 threads.

It is not safe to call Filament APIs from other threads, they just all be called from the same thread.

What you should do is load meshes, bitmaps, etc. on a background thread and using a work queue or coroutines (pinned to a single thread) pass the loaded data to the thread that will talk to the filament APIs.

Filament APIs are designed to return quickly (all they do is basically send commands to the render thread) so if you do it this way you shouldn't have to worry about missing frames.

render() is pretty much the only function that takes time but its execution is heavily multithreaded.

@pixelflinger
Copy link
Collaborator

You can call filament APIs from different threads only if you provide the synchronization externally. We're not relying on thread-local storage for instance.

Only Renderer.render() must be called on the main filament thread (but that's only because we have an assert() trying to catch bad behaved apps).

I would not recommend going down that road though, I don't think there is much to gain.

The main reason filament APIs can't be called from multiple threads (for instance, you can't call APIs of say Texture and VertexBuffer on different threads) is because these APIs, under-the-hood write into a command queue which is not synchronized. So the mental model you need to have is that calling Filament APIs all write into an unsynchronized queue.

Hope this helps.

@rawnsley
Copy link
Contributor Author

@romainguy @pixelflinger This info makes things much clearer for me - thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants