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

Multithreading issues #190

Open
johann2 opened this issue Oct 4, 2024 · 1 comment
Open

Multithreading issues #190

johann2 opened this issue Oct 4, 2024 · 1 comment

Comments

@johann2
Copy link

johann2 commented Oct 4, 2024

I'm not sure how important multi-threaded use is for this project, but I thought, I'd write down the issues I've run into while attempting to integrate yakui with my game. This post doesn't have much of actionable feedback, but hopefully it can serve as a data point for future API design decisions. Also, if I overlooked an approach that would be much easier to implement, I'm most interested in learning more about it.

My game runs on 2 threads (actually more, but these 2 are relevant): one is for the window event loop and rendering and the other is for gameplay. I've considered multiple options, but so far, each of them has some significant drawbacks.

  1. Arc<Mutex>. This didn't work at all, because Yakui isn't Send or Sync. If it did, it would've solved all my problems, (until the first deadlock)

  2. Send all the relevant info (list of items to display, the current UI state, etc) from the game thread to the main thread. Send gameplay events, such as move item from container A to B, item used, etc back to the game thread. This approach seems kind of unergonomic and also has a risk of weird synchronization bugs. (For example: an item in container got used by some other system, but the UI has outdated data and can generate another use event for an already used item)

  3. Have the Yakui entry point in the game thread and send input events from the render thread to the game thread. Also send generated polygons and textures from the game thread to render thread every frame.

Option 3 is the approach I finally decided to pursue. However, I feel that with some API changes, the integration time could be brought down considerably.

I've solved the rendering part, after less than a day of mucking about with the code. I took the yakui-wgpu crate as a template and implemented a struct without any reference to the Yakui or RenderDom objects, containing only the geometry and texture updates, so it could be sent between the threads. It's probably a bit slower, because it does copy a bit more data and it's a bit more complex than just passing the PaintDom pointer to the renderer. I could do a pull request with the changes, if you're interested.

The second issue is getting the input to the game thread. I had to add the dependency to winit and yakui-winit to the game thread, something I've managed to avoid so far. What makes things complicated is that in addition to sending the input events to the game thread, I also need to check if the event gets sunk by the UI or not. Listening to another channel for responses seems to be the most obvious way, but it has the potential to block the render thread unnecessarily.

In my use case, I can get away with letting the events to always bubble, but this may be important for some other use cases.

In conclusion, if multi threaded use is something you're interested in supporting out of the box, my main ideas are:

  1. A data structure that has all the info for painting the UI that's Send and Sync,maybe Clone too.
  2. Instead of the handle_window_event function, consider having a function that converts from winit events to yakui events that could be sent to another thread and handled there.
  3. I'm not sure how to address the problem with bubbling/sinking feedback. Maybe having the part of yakui that receives events somehow accessible to other threads?

Thanks for reading this long post and also thank you for writing this library, it's the first UI library I've actually enjoyed using.

@LPGhatguy
Copy link
Member

Thank you for all of the wonderful feedback and ideas! I'll be mulling this over and see if I come up with anything helpful.

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

2 participants