Skip to content

Add support for the OpenXR futures extension#101951

Merged
akien-mga merged 1 commit intogodotengine:masterfrom
BastiaanOlij:openxr_futures
Mar 19, 2025
Merged

Add support for the OpenXR futures extension#101951
akien-mga merged 1 commit intogodotengine:masterfrom
BastiaanOlij:openxr_futures

Conversation

@BastiaanOlij
Copy link
Copy Markdown
Contributor

This PR introduces the OpenXR Future extension which allows asynchronous calls into APIs from extensions that use the future extension.

When a future is created as an asynchronous function call is made, we can register this future with a callable that will be invoked when the function call finishes.

As Godot requires that classes inherit from Godots Object class for callables to work. This PR also changes OpenXRExtensionWrapper to inherit from Object and updates all existing extension classes accordingly.

OpenXRExtensionWrapperExtension is also changed to now just inherit from OpenXRExtensionWrapper. Outwardly this shouldn't change and shouldn't break existing GDExtension based OpenXR extension wrappers but this does need to be tested.

This PR will remain in draft until testing is done with APIs that apply the future approach and I can confirm this is the correct way to go forward. Looking for feedback from other core XR devs.

Contributed by Khronos Group through the Godot Integration Project

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now exposing this way, this is really only for GDExtensions that need to access this class.
Thinking about alternatively adding a method to OpenXRAPIExtension where we can retrieve any registered extension, but this would lead to needed to register all extension classes in ClassDB.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to do this as a proper GDScript singleton

@BastiaanOlij BastiaanOlij force-pushed the openxr_futures branch 3 times, most recently from 2b3d5cb to 0a7482d Compare January 23, 2025 07:47
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to do a bunch of these changes as it seems metadata is a class member of Object (or introduced by our ClassDB macro). Bit of a PITA.

@BastiaanOlij BastiaanOlij self-assigned this Jan 23, 2025
@AThousandShips AThousandShips changed the title Adding support for the OpenXR futures extension Add support for the OpenXR futures extension Jan 23, 2025
@BastiaanOlij BastiaanOlij force-pushed the openxr_futures branch 2 times, most recently from 3666bc8 to fd2375e Compare January 27, 2025 02:47
Copy link
Copy Markdown
Contributor

@devloglogan devloglogan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to take a quick look through this. Looks cool and makes sense to me! Would be curious to try this out with a relevant API sometime but in the spec it looks like it's only used by Magic Leap currently?

@BastiaanOlij
Copy link
Copy Markdown
Contributor Author

Wanted to take a quick look through this. Looks cool and makes sense to me! Would be curious to try this out with a relevant API sometime but in the spec it looks like it's only used by Magic Leap currently?

It's used by a number of APIs still in development, but it will be some time before those are public.

@BastiaanOlij BastiaanOlij force-pushed the openxr_futures branch 2 times, most recently from 319d3f9 to f0436b1 Compare February 1, 2025 01:39
@m4gr3d m4gr3d self-requested a review February 7, 2025 00:15
@dsnopek
Copy link
Copy Markdown
Contributor

dsnopek commented Feb 27, 2025

As part of the change to have OpenXRExtensionWrapper be an Object, there's a couple other changes that I personally think we should make:

  1. Merge the methods from OpenXRCompositionLayerProvider up into OpenXRExtensionWrapper. While using OpenXRCompositionLayerProvider like a C#/Java/PHP/etc interface makes sense, multiple inheritance in C++ can cause weird issues especially in conjunction with Godot's Object and ClassDB system. I forget the issue and PR numbers, but in the past we had a really hard to debug crash that was the result of this, and I personally think it would be better to avoid the problem entirely by just not using multiple inheritance. (Also, we had some later work that attempted to follow the example of OpenXRCompositionLayerProvider and my review was "let's not do that anymore" because of these issues, but I worry that future contributors may still see OpenXRCompositionLayerProvider and again try to follow its example, so let's just get it out of there)
  2. Deprecated OpenXRExtensionWrapperExtension in favor of just using the now-exposed OpenXRExtensionWrapper. We can do this without breaking compatibility by just making the default implementations of the virtual methods on OpenXRExtensionWrapper use the GDExtension implementations from OpenXRExtensionWrapperExtension, and emptying out OpenXRExtensionWrapperExtension but not removing it. Old GDExtensions would still extend OpenXRExtensionWrapperExtension and continue working fine, but newer GDExtensions could directly extend OpenXRExtensionWrapper. This will eliminate the annoying extension-extension we have in OpenXRExtensionWrapperExtension :-)

Maybe it makes sense to spin the "OpenXRExtensionWrapper becomes an Object" part of this into its own PR to focus on that? Or, if we think this one is ready to merge when the Godot 4.5 dev cycle opens up, I could do the other changes I describe above as a follow-up PR?

UPDATE: The crash related to multiple inheritance that I was referring to in point nr 1 was issue #88613 fixed by PR #88689

@BastiaanOlij
Copy link
Copy Markdown
Contributor Author

@dsnopek the crash issues were caused by a moving pointer between the different classes because of late introduction of a v-table.
This is fixed by making sure the primary base class has a virtual destructor. We dealt with that.

My main worry with point 1 is that we'll end up looping through all wrappers just to find out only one or two actually have compositor logic.

For point 2, it's definitely worth doing a follow up to clean up OpenXRExtensionWrapperExtension however it has become the norm to always implement a *Extension class for exposure to GDExtension and keep the base class abstract.

@dsnopek
Copy link
Copy Markdown
Contributor

dsnopek commented Mar 2, 2025

My main worry with point 1 is that we'll end up looping through all wrappers just to find out only one or two actually have compositor logic.

I'm not saying to get rid of the registration for the extensions that affect compositor layers. Just that it would take OpenXRExtensionWrapper * rather than OpenXRCompositionLayerProvider *. Take a look at register_projection_views_extension() - for that one we're also doing a registration, but we didn't make a new base class for it.

however it has become the norm to always implement a *Extension class for exposure to GDExtension and keep the base class abstract.

We do it both ways for different things in Godot.

The only advantage of keeping it abstract (as opposed to virtual) is that users could try to extend OpenXRExtensionWrapper in GDScript, which won't work because of all the pointer arguments. But we already have the risk, because they could try to do the same with OpenXRExtensionWrapperExtension, and I've never heard of anyone trying to do that. It's really only changing which class name carries the risk.

@BastiaanOlij
Copy link
Copy Markdown
Contributor Author

Ok, I've made this ready for proper review. Been testing this for the past few weeks and it is working fine. Sadly can't share the project I'm working on just yet.

I did change things so it properly uses XrFutureEXT internally and the class methods used by extension in the core can use this type, but the functions exposed to GDExtension and GDScript use uint64_t. Much clearer implementation.

@dsnopek I've left the classes as they are for now, I do think we need to look into this further but changing those would be serious breaking changes, especially the *extension change. I do hear what you're saying here though so far in all my discussions with the core team I get two answers, some always wanting the specific extension classes and others saying its find to just make the base class virtual. I'm not bothered one way or the other.

But changing it now will break our existing vendor extension and I think that's not worth it. Also it will require a bunch of other cleanup that I'd rather do in a separate PR if we decide to go down this route.

@dsnopek
Copy link
Copy Markdown
Contributor

dsnopek commented Mar 13, 2025

@BastiaanOlij:

I do think we need to look into this further but changing those would be serious breaking changes, especially the *extension change.
[...]
But changing it now will break our existing vendor extension and I think that's not worth it.

I'm happy to make a follow-up PR! However, the changes I described above would not be breaking changes - they should be fully backwards compatible. The vendor extension should be able to keep working without any changes

Copy link
Copy Markdown
Contributor

@dsnopek dsnopek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than some little nitpicky stuff in the API, this looks good to me!

@BastiaanOlij
Copy link
Copy Markdown
Contributor Author

@dsnopek I still have to test it but have a look at the future result implementation I did and see if this matches your expectation.
I did it as a separate commit so you can rebase your changes ontop of it.

@BastiaanOlij BastiaanOlij force-pushed the openxr_futures branch 3 times, most recently from 2e04487 to 5c1feec Compare March 14, 2025 13:20
Copy link
Copy Markdown
Contributor

@dsnopek dsnopek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

The addition of the result object looks great - that will be really nice to use from GDScript :-)

This is all looking good to me!

I did it as a separate commit so you can rebase your changes ontop of it.

You can squash them - I should be able to rebase fine

@BastiaanOlij
Copy link
Copy Markdown
Contributor Author

Squashed the commits into one. I think this is ok to merge.

@BastiaanOlij BastiaanOlij force-pushed the openxr_futures branch 2 times, most recently from 291b136 to 2ffaac1 Compare March 17, 2025 03:53
@akien-mga akien-mga merged commit 05a9e01 into godotengine:master Mar 19, 2025
20 checks passed
@akien-mga
Copy link
Copy Markdown
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants