SuRGeoNix/Flyleaf

Multi-UI Thread Support

Closed this issue · 7 comments

Hello,

I get an exception when I try to use this library in a separate window that runs on its own thread.

I have tried putting the engine in the constructor of the window so its in the same thread

image

However that gives me:

image

image

If i keep the engine on the main thread by calling it in App, then when I try to use a Player I get the same exception that the current thread does not own the object.

@Wolfleader101 I've never tested with multiple UI threads and not really design for that. So I guess each window will need a different dispatcher pass down to the Player. I will have to review this.

@Wolfleader101 I've never tested with multiple UI threads and not really design for that. So I guess each window will need a different dispatcher pass down to the Player. I will have to review this.

Yea that would probably be the best way. I started looking into how FFMediaElement does it too. If i get a chance to implement the changes into this lib I will make sure to make a PR.

@Wolfleader101 The first question before implementing this is: Why use Multiple UI Threads? I can't see any advantages. The only reason to use them is when you overload the UI thread with things that they shouldn't actually run there. I could understand using async / parallel (Multiple CPU Cores) in "the" UI thread.

In any case it will be difficult to integrate it with the current design / implementation. Currently, it uses the same UI Invoke logic for WinForms/WPF/WinUI 3. Not sure if it will be still possible when using multiple UI threads.

I will try to include this design logic in v4 though.

@Wolfleader101 The first question before implementing this is: Why use Multiple UI Threads? I can't see any advantages. The only reason to use them is when you overload the UI thread with things that they shouldn't actually run there. I could understand using async / parallel (Multiple CPU Cores) in "the" UI thread.

In any case it will be difficult to integrate it with the current design / implementation. Currently, it uses the same UI Invoke logic for WinForms/WPF/WinUI 3. Not sure if it will be still possible when using multiple UI threads.

I will try to include this design logic in v4 though.

Maybe my understand of this is incorrect - but say I have 2 windows in my WPF app, would it not make sense for that 2nd window to have its own UI Thread? Especially if that window contains just say 4 camera streams all running at once in that window.

You don't want any lag caused by the cameras to affect the rest of the app.

@Wolfleader101 Everything in Windows UI (rendering) runs in a single UI thread. The Multiple UI threads are a simulation in .NET not actual UI threads. I guess they did that because a lot of people are messing things with the Invokes/UI Updates with things that take a lot of time while they shouldn't. Even if you have 1K cameras the rendering process should be fast (the preparation/pre-rendering could be slow but this should run on a different non-UI thread)

(I might be wrong but that's my understanding, I will look deeper into it - I've seen that a lot of people - even Microsoft too - they discourage you from using multiple UI threads)

@Wolfleader101 Everything in Windows UI (rendering) runs in a single UI thread. The Multiple UI threads are a simulation in .NET not actual UI threads. I guess they did that because a lot of people are messing things with the Invokes/UI Updates with things that take a lot of time while they shouldn't. Even if you have 1K cameras the rendering process should be fast (the preparation/pre-rendering could be slow but this should run on a different non-UI thread)

Ah ok that makes more sense, so no real gains from running a separate camera window on its own thread....
Like you said assuming the pre-rendering is on its own thread. Ok thank you, i will have to look into that then and give this library another try!

@SuRGeoNix What about something like this

          var cameraWindowThread = new Thread(() =>
          {
              _camWindow = new CameraWindow(vm);

              _camWindow .Closed += (s, e) =>
              {
                  _camWindow .Cleanup();

                  Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
                  _camWindow = null;
              };

              _camWindow .Show();

              Dispatcher.Run();
          });
          cameraWindowThread.Name = $"Camera Window Thread";
          cameraWindowThread.SetApartmentState(ApartmentState.STA);
          cameraWindowThread.IsBackground = true;
          cameraWindowThread.Priority = ThreadPriority.Lowest;
          cameraWindowThread.Start();

@Wolfleader101 Closing this for now and I will review it for v4