Running StereoKit from an async Main
Description
I recently updated our apps to use the latest StereoKit nuget (0.3.6-preview.5), but it caused them to crash/hang immediately on startup. I think the problem has to do with the fact that we use an async Main() (static async Task Main()) rather than void Main(). We can work around it by isolating our async stuff and using a regular void Main(), but I thought it was strange. The exception seems to be thrown somewhere deep in the OpenXR native code during initialization, but it's a bit hard to trace. Is this a known issue?
Platform / Environment
Observed on ARM and ARM64 (UWP) deploying to the HoloLens 2.
I encountered a similar issue in https://github.com/maluoi/StereoKit/issues/338, although that wasn't on UWP. But there might very well be an issue with async Main, but only @maluoi would known why :smile:
To be quite honest, I didn't know you could make Main async until @paulmelis mentioned it, and I'm still not entirely sure what the ramifications of that are. It sounds like this may be a more common scenario than I had initially imagined, so I guess it's time for me to do a deeper dive on that! Will let you all know how that goes :)
Okay, so I learned something new today! It seems as though await calls can cause your code to switch threads, even in cases that may intuitively look otherwise!
So using an await between SK.Initialize and SK.Run/Step can mean execution is no longer on the same thread. Initialize and Run/Step both expect to be run from the same thread, which is a bit of a requirement for how graphics works. This may not have been an issue before (it would be a problem for GL, but DX would be okay with it), but with the async assets feature, I've been trying to do some smarter thread handling, and hadn't handled this case!
I think the most I can do in this case is double check the thread Id is the same from Initialize and Run/Step, and fail vocally if not.
Interesting! I did not know that either, but it explains a lot.
HoloLens requires a lot of async API calls from various UWP libraries for reading/writing files and folders, accessing spatial anchors, etc. We're using such calls for additional initialization between SK.Initialize and SK.Run, which led to the whole async Main business. So it seems like this might not be all that uncommon of a situation for people to potentially run into? Certainly an informative error message will help!
Okay, I have a pretty good idea how to prevent this in the future, so this situation will continue to improve as async assets develop! In the meantime, I have added a pair of warnings that should help illuminate the situation.
I've been experiencing this async strangeness too, and my Program main() is this.
public static async Task Main(string[] args)
I too depend on async call between Initialize and Step(run). #512