Skip to content

Conversation

@Baplar
Copy link
Contributor

@Baplar Baplar commented Apr 24, 2025

This is an implementation of Meta’s composition layer filtering OpenXR extension.
It simply consists in detecting said extension, enabling it if available, and adding a set flags on each submitted composition layer to specify the desired level of super sampling and/or sharpening.

I tested it successfully on my Quest 3, and from tests on other OpenXR tools, this should also work at least on Pico headsets.
If the extension is unavailable on the target headset, or if both post-processing settings are left to Disabled in the dashboard, it will fallback to the current existing behavior.

This is my first time working with production-level Rust code, so please correct me on all my non-idiomatic code!

@zmerp
Copy link
Member

zmerp commented Apr 24, 2025

Thank you so much for opening the PR!

Comment on lines 74 to 81
composition_layer_settings: Option<&'a xr::sys::CompositionLayerSettingsFB>,
) -> Self {
Self {
reference_space,
layers,
alpha,
composition_layer_settings,
}
Copy link
Member

Choose a reason for hiding this comment

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

Here I meant you should pass our struct ClientsidePostProcessingConfig, and then construct CompositionLayerSettingsFB inside here. To convert Switch to Option you can use into_option() or as_option()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I figured I could build the CompositionLayerSettingsFB only once when the StreamContext is initialized on streaming start, and reuse it on every frame, like is done for other xr objects stored in the StreamContext.
Do you think it would be preferrable to pass the config struct and build a new layer settings on each frame?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, construct CompositionLayerSettingsFB inside the layer builder each time, in new()

Copy link
Contributor Author

@Baplar Baplar Apr 26, 2025

Choose a reason for hiding this comment

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

I see, I can do that if you wish. But I feel like this will just add a bit of overhead to rebuild the layer settings every frame, instead of building it once and for all and keeping it saved in the stream context. Do you fear that reusing the same object may have an adverse effect in the long run? It seems to work pretty well as it is.

Unless the settings can be updated by the dashboard and sent dynamically to the headset without restarting the stream? In which case, yes, rebuilding it would avoid running on "obsolete" settings, if the user changes the post processing options on the fly.

Copy link
Member

@zmerp zmerp Apr 27, 2025

Choose a reason for hiding this comment

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

I think keeping the same struct instance really makes no difference performance-wise. My advice is purely to avoid leaky abstractions. xr::sys structs deal with raw pointers and sometimes they are platform-specific (FB in this case), which i prefer them to be hidden at lower levels of abstractions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense, I moved its initialization into the projection layer builder.

@Baplar
Copy link
Contributor Author

Baplar commented Apr 30, 2025

Are there still things I need to change or fix?

Copy link
Member

@zmerp zmerp left a comment

Choose a reason for hiding this comment

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

Overall I would say this PR is mergeable as is. @The-personified-devil let me know if you'd like to drop a review or comment

let composition_layer_settings = clientside_post_processing_config
.map(|post_processing| {
xr::CompositionLayerSettingsFlagsFB::from_raw(
(post_processing.sharpening as u64) | (post_processing.super_sampling as u64),
Copy link
Member

Choose a reason for hiding this comment

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

Half-nit, it's not intuitive how this works if you don't know that post_processing.sharpening and post_processing.super_sampling are actually compatible bitfields. it's probably inferred from the context (we are filling in flags)

@zmerp zmerp merged commit e1e71d2 into alvr-org:master May 9, 2025
9 checks passed
zmerp pushed a commit that referenced this pull request Jun 27, 2025
* Client-side OpenXR post-processing

* Remove unnecessary closure

* Refactor composition layer settings creation and reference passing

* Add client-side post-processing to real-time config

* Build composition layer settings struct within projection layer builder
@zmerp zmerp mentioned this pull request Jun 28, 2025
zmerp pushed a commit that referenced this pull request Jun 30, 2025
* Client-side OpenXR post-processing

* Remove unnecessary closure

* Refactor composition layer settings creation and reference passing

* Add client-side post-processing to real-time config

* Build composition layer settings struct within projection layer builder
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

Successfully merging this pull request may close these issues.

2 participants