Skip to content

Conversation

@svillar
Copy link
Member

@svillar svillar commented Sep 4, 2025

The check for support for composition layers must be done in the backend (OpenXR) which is the one with enough data to decide.

We were doing it the other way around, checking which devices did support them and forcing it in the Java side because we knew that would work on the native side.

It's much safer and less error prone to do it on the backend. This forces us to make some Java calls asynchronous because we don't know whether the backend has done its checks or not.

}

private boolean supportsCompositionLayers() {
assert(mMaxCompositionLayers.isPresent());
Copy link
Member

Choose a reason for hiding this comment

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

Why the assert ? I mean, if it needs to exists always, why then we need an optional at all ? What's the difference, in terms of business logic, between absence and 0 ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because not having a value means that we haven't received the message from the native code. Whereas 0 is a value that an runtime might return. Very likely no runtime will return that because that would mean that it is unusable but from the API point of view, 0 is a "valid" value.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, what I meant is what does it mean that "we haven´t received the message from the native code" ? Is that an stable state, or is part of the Wolvic's initialization and we just want to avoid blocking the app while waiting ? I want to understand why we haven't received it yet and when it's supposed to be received.

Copy link
Member Author

Choose a reason for hiding this comment

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

Exactly, I wanted to avoid blocking the main java thread waiting for the native code to reply. Perhaps we can do it synchronously and it is not a big deal after that because that should be fast.

}

@Override
public void areCompositionLayersSupported(@NonNull CompositionLayersCallback callback) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm confused about this method and supportsCompositionLayers(). The method name suggests a check and a boolean return type, bit it seems it adds a new callback to the linked list.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes because it's an asynchronous operation. Do you want me to add the Async suffix to make it clearer?

Copy link
Member

Choose a reason for hiding this comment

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

umm, it'd help, indeed. Perhaps use the term "check" to suggest it'd would launch an operation, more than just inspecting some local fields. And the callback could have a name that suggests that it's called when the checks are done.

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense. Will do that

mMaxCompositionLayers = OptionalInt.of(aNumLayers);
Log.i(LOGTAG, "Max composition layers: " + aNumLayers + " so " + (supportsCompositionLayers() ? "enabling" : "disabling") + " layers support");
runOnUiThread(() -> {
boolean supportsLayers = supportsCompositionLayers();
Copy link
Member

Choose a reason for hiding this comment

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

Has the supportCompositionLayers() method need to run on the UI thread ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not that one but the callbacks just bellow do

Copy link
Member

Choose a reason for hiding this comment

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

but then we may declare the boolean at the beginning and reuse it in the log message, can't we ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah OK, the problem was calling it twice. Yeah I can change that.

mWidgetPlacement.proxifyLayer = mProxify;
super.show(aShowFlags);
private void internalShow(boolean proxifyLayer) {
mWidgetPlacement.proxifyLayer = proxifyLayer;
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure how to review this change. In proxifyLayerIfNeeded we add a callback to the mWidgetsManager where the mWidgetPlacement's proxifyLayer field is modified as well. Apparently we do the same here. Are these logics related ? If they are, could you explain how ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure whether I follow your comment. The code in internalShow is the code that was in the old show method. It's just that the check for layers is asynchronous so we might have to run this asynchronously,

virtual bool PopulateTrackedKeyboardInfo(TrackedKeyboardInfo& keyboardInfo) { return false; };
virtual void SetHandTrackingEnabled(bool value) {};
virtual float GetSelectThreshold(int32_t controllerIndex) { return 1.f; };
virtual unsigned MaxCompositionLayers() const { return 1; }
Copy link
Member

Choose a reason for hiding this comment

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

Why are we returning "1" unconditionally ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because that's the minimum. If you have 0 composition layers then you cannot render anything

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I understand.

CHECK_XRCMD(xrGetSystemProperties(instance, system, &systemProperties))
VRB_LOG("OpenXR system name: %s", systemProperties.systemName);

layersEnabled = systemProperties.graphicsProperties.maxLayerCount > 1 && OpenXRExtensions::IsExtensionSupported(XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME);
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't me more efficient to check first the OpenXRExtension bit ?

Copy link
Member Author

Choose a reason for hiding this comment

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

the OpenXR extension check is actually a hash lookup so the comparison is more efficient.

Copy link
Member

Choose a reason for hiding this comment

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

got it.

Copy link
Member

@javifernandez javifernandez left a comment

Choose a reason for hiding this comment

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

I have left some comments but the changes looks good overall.

The check for support for composition layers must be done in the
backend (OpenXR) which is the one with enough data to decide.

We were doing it the other way around, checking which devices did
support them and forcing it in the Java side because we knew that
would work on the native side.

It's much safer and less error prone to do it on the backend. This
forces us to make some Java calls asynchronous because we don't
know whether the backend has done its checks or not.
@svillar
Copy link
Member Author

svillar commented Sep 16, 2025

I have left some comments but the changes looks good overall.

Thanks! Added the changes following your suggestions

@svillar svillar merged commit 7542ccf into main Sep 16, 2025
22 checks passed
@svillar svillar deleted the layers_enabled branch September 16, 2025 15:04
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.

3 participants