OpenXR: Add support for Foveated Inset #118511
OpenXR: Add support for Foveated Inset #118511BastiaanOlij wants to merge 2 commits intogodotengine:masterfrom
Conversation
dsnopek
left a comment
There was a problem hiding this comment.
Thanks!
In order for the user to have quality control and ensure the camera settings can be configured, this PR introduces a new viewport node that controls the rendering of the foveated inset:
Requiring the user to add these nodes isn't ideal. You mention that it's needed for the user to have control - what exactly do they need to control? The near and far camera plane is one thing, but I'm drawing a blank on anything else.
Could we have project settings for the configurable things? Or, if that's too much, maybe an "automatic" setting that sets up a reasonable default (just copying from the current camera and XR origin), which folks can disable, and make their own nodes if they need more control?
Also, I worry a bit about having the 2nd XROrigin3D node. When unloading an old scene (which has the main XROrigin3D node) and loading another, I think it might be possible for the foveated inset one to become "current" because I don't think we are segregating XROrigin3D nodes by viewport (like we do for cameras).
Perhaps we should be segregating XROrigin3D nodes by viewport?
| @@ -807,6 +807,7 @@ bool OpenXRAPI::load_supported_view_configuration_types() { | |||
| if (!is_view_configuration_supported(view_configuration)) { | |||
| print_verbose(vformat("OpenXR: %s isn't supported, defaulting to %s.", OpenXRUtil::get_view_configuration_name(view_configuration), OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[0]))); | |||
|
|
|||
| // Fall back to the first supported. | |||
There was a problem hiding this comment.
Falling back to the first supported view configuration worries me a little bit. If the user picked "Stereo with Foveated Inset", this should fall back on stereo. If the device supports mono and stereo, and mono happens to be first, we shouldn't fallback on mono.
This will probably be OK, since the spec says "The returned list of primary view configurations should be in order from what the runtime considered highest to lowest user preference. Thus the first enumerated view configuration type should be the one the runtime prefers the application to use if possible."
But it still worries me a bit - an explicit fallback from "Stereo with Foveated Inset" -> "Stereo" would be better
This is one of the things I got stuck with last time. We don't have access to the camera used for the main view, so any camera attributes or environment overrides applied to the main camera, cant' be automatically duplicated on the inset camera. One idea I'm toying with is to create the XROrigin3D and XRCamera3D nodes within the viewport node, but exposing the additional environment and camera attributes setting on this viewport. Because I do agree with you, demanding this is troubled. Still, this was the quickest way I could get to testing the heart of it all. |
Maybe we could have a property on
Ooo, yeah, having the Although, I'd really prefer if the user didn't even need to create the
Unfortunately, I don't know. I haven't had a chance to switch to Windows recently, so I've just been testing by deploying to the headset |
It's a real PITA, it's something I really got stuck on in my other PR, you can have a look at what sort of uglyness I had to come up with. That's where I just created everything directly on the rendering server. The problem is that we're storing too much info on the Viewport node that is leading, and we have no access to this information in the XRServer nor rendering server. So I figured that what we're doing with composition layers, made more sense here, just add a node so people can configure what needs to be configured. |
5286462 to
e33c674
Compare
|
@dsnopek I think I've found all the problems that were keeping it from working correctly, so you can try the updated build and see if it works. I've been testing on the XR3, I'll do some testing on AndroidXR tomorrow. Also the test project has a few updates so be sure to pull that. I've added a transparent plane so there is a color difference for the inset render, just so we can see if it works. From your earlier testing I have a feeling AndroidXR has the inset as the first 2 views, and context as the last 2 views, which goes against the OpenXR specification and will give us problems if we do want to change quality differences between the two. I have not changed the way the viewports work, I haven't had time for that yet. But all in all I think the heart of this is beating strong. |
This is on purpose for testing, note the MeshInstance child of the inset XRCamera3D. Just hide that and your darkened area goes away :)
That sounds like a runtime problem. We don't really control how things are blended. Sadly for some reason my eye tracking on my XR3 isn't functioning atm so I can't test if Varjo has the same issue. I'll ask Denny if he can verify.
No idea, maybe something related to the swapchain not being accessible? Any output in the logs?
Yeah I think once we have a proper test build, we should ask someone on the AndroidXR team to have a look. |
e33c674 to
c7c1612
Compare
|
Ok, this is nearly done. @dsnopek I've changed the viewport node so it creates all that is needed, and made the extension create the node and add it to the root of the scene tree. I've updated the demo accordingly. One problem we have discovered that is not a fault of this PR, but likely an issue that has been around for a long time but less noticeable for the main XR camera. The combined frustum that we use for culling is too small and can cull objects at the edge of the inset view causing very noticeable visual artifacts. |
dsnopek
left a comment
There was a problem hiding this comment.
Thanks! This is working great in my testing on the Samsung Galaxy XR, using the latest from this PR and your demo project
I've changed the viewport node so it creates all that is needed, and made the extension create the node and add it to the root of the scene tree.
This looks awesome! I think the only thing that's missing is a setting to prevent it from doing this, so that folks can do it manually if they want.
The combined frustum that we use for culling is too small and can cull objects at the edge of the inset view causing very noticeable visual artifacts.
Ah, now that you say this, I can absolutely tell this is the cause of the flickering I was seeing. It happens when I move my cube hands to the edge of the inset
| HashMap<String, bool *> request_extensions; | ||
|
|
||
| // Extension was replaced in OpenXR 1.1, use `XR_VARJO_quad_views` in OpenXR 1.0. | ||
| // Note: we currently always include this as there is a dependency with `XR_VARJO_foveated_rendering`. |
There was a problem hiding this comment.
I think the note should mention that we are doing this for Varjo specifically.
For Android XR, we don't need to enable either of these extensions when using OpenXR 1.1 (although, it does support them and we could use them with OpenXR 1.0).
So, we're specifically waiting for Varjo to support the OpenXR 1.1 feature and update their XR_VARJO_foveated_rendering extension for it.
There was a problem hiding this comment.
I was under the impression that XR_VARJO_foveated_rendering is what triggers an eye tracked foveated inset? Or is that something I misunderstood. I'm not sure what enabling this on AndroidXR adds then?
There was a problem hiding this comment.
On Android XR, when using OpenXR 1.1, you don't need to enable either extension - using foveated inset will do everything, even with eye tracking.
But if you do try to enable XR_VARJO_foveated_rendering without also enabling XR_VARJO_quad_views then the OpenXR session will fail to create (because of the dependency).
On Android XR, those extension appear to only be there for OpenXR 1.0 compatibility (although, its fine to enable them in OpenXR 1.1)
| This viewport is used for rendering our foveated inset. | ||
| </brief_description> | ||
| <description> | ||
| This viewport is used for rendering our foveated inset. When foveated inset rendering is supported OpenXR will create and configure this viewport correctly and use its output. The viewport will be available after OpenXR reaches the "begun" state. You can access it by calling [code]get_tree().get_root().get_node("OpenXRFoveatedInsetViewport")[/code] at this time. |
There was a problem hiding this comment.
Maybe mention [method OpenXRExtensionWrapper.on_state_ready] instead of "begun"?
There was a problem hiding this comment.
The problem is that we emit a signal called session_begun for historic reasons. So that is what the user reading these docs sees. That we internally are now following the session states as named by OpenXR is hidden to the developer.
fe3beb2 to
3d10bf8
Compare
dsnopek
left a comment
There was a problem hiding this comment.
With the latest changes, this is looking great to me!
I still think that comment should mention that we are waiting for Varjo specifically (since Android XR can do everything with just OpenXR 1.1), but that's totally in nitpicking territory :-)
|
Note: the remaining style check CI issue is a false positive. I think this is because the |
You can work it around by adding a pragma comment: clangd should be able to notice this normally but we seem to be hitting an edge case. |
3d10bf8 to
bbdaa53
Compare
| OpenXRFoveatedInsetExtension *fi_ext = OpenXRFoveatedInsetExtension::get_singleton(); | ||
| ERR_FAIL_NULL(fi_ext); | ||
|
|
||
| fi_ext->unregister_viewport(get_viewport_rid()); |
There was a problem hiding this comment.
Should also memdelete xr_camera and xr_origin
There was a problem hiding this comment.
Actually, we don't need to! They were added as children of this node, so they'll be freed when this node is freed



This PR implements support for OpenXR Foveated inset rendering if supported by the hardware.
When using foveated inset rendering, the main viewport output renders a high FOV, lower resolution render which is augmented with a separate high resolution render pass at the users focal point.
A good overview of the technique is explained on Varjos website here.
In order for the user to have quality control and ensure the camera settings can be configured, this PR introduces a new viewport node that controls the rendering of the foveated inset:

An extra
XROrigin3Dnode is required with a few lines of code so it is placed in the same location as the mainXROrigin3Dnode.We also have a separate
XRCamera3Dnode with it'stracker' set to 'inset(note that I am still working on a nice solution for the dropdown here).Todos:
This logic is all based on #115799 (merged) and #116424
A sample project can be found here.
This PR supersedes #81505 and #108156