From ab6d43613fde1b32b5bdab174ea9249e47f79e3f Mon Sep 17 00:00:00 2001 From: Sergio Villar Senin Date: Fri, 13 Sep 2024 17:20:51 +0200 Subject: [PATCH] [Pico] Add a OS version check Pico OpenXR runtime had several issues over the time. We had to add workarounds here and there to support those OS versions. As time passes by those workarounds just make the code more complex to maintain without any real benefit (as it affects really old versions of the OS). After this change Pico OS versions < v5.7.1 are no longer supported and Wolvic will refuse to start. This allows us to remove a lot of code workarounding runtime bugs including the legacy hand mesh renderer using spheres. --- .../com/igalia/wolvic/VRBrowserActivity.java | 6 +- app/src/main/cpp/HandMeshRenderer.cpp | 69 ------------------- app/src/main/cpp/HandMeshRenderer.h | 15 ---- app/src/openxr/cpp/DeviceDelegateOpenXR.cpp | 7 -- app/src/openxr/cpp/OpenXRGestureManager.cpp | 5 -- app/src/openxr/cpp/OpenXRHelpers.h | 8 --- app/src/openxr/cpp/OpenXRInputSource.cpp | 23 ------- app/src/openxr/cpp/OpenXRLayers.h | 8 --- app/src/picoxr/AndroidManifest.xml | 2 +- .../igalia/wolvic/PlatformSystemCheck.java | 38 +++++++++- 10 files changed, 38 insertions(+), 143 deletions(-) diff --git a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java index a7ac337d48..691c950415 100644 --- a/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java +++ b/app/src/common/shared/com/igalia/wolvic/VRBrowserActivity.java @@ -196,9 +196,6 @@ public void run() { static final long RESET_CRASH_COUNT_DELAY = 5000; static final int UPDATE_NATIVE_WIDGETS_DELAY = 50; // milliseconds - // Passthrough was enabled on Pico version 5.7.1, via XR_FB_passthrough extension - static final String kPicoVersionPassthroughUpdate = "5.7.1"; - static final String LOGTAG = SystemUtils.createLogtag(VRBrowserActivity.class); ConcurrentHashMap mWidgets; private int mWidgetHandleIndex = 1; @@ -2015,8 +2012,7 @@ public boolean isPassthroughEnabled() { } @Override public boolean isPassthroughSupported() { - return DeviceType.isOculusBuild() || DeviceType.isLynx() || DeviceType.isSnapdragonSpaces() || - (DeviceType.isPicoXR() && Build.ID.compareTo(kPicoVersionPassthroughUpdate) >= 0); + return DeviceType.isOculusBuild() || DeviceType.isLynx() || DeviceType.isSnapdragonSpaces() || DeviceType.isPicoXR(); } @Override diff --git a/app/src/main/cpp/HandMeshRenderer.cpp b/app/src/main/cpp/HandMeshRenderer.cpp index 61f3f87538..a9b98996d2 100644 --- a/app/src/main/cpp/HandMeshRenderer.cpp +++ b/app/src/main/cpp/HandMeshRenderer.cpp @@ -38,75 +38,6 @@ vrb::RenderStatePtr GetHandMeshDefaultRenderState(vrb::CreationContextPtr create return state; } -// HandMeshRendererSpheres - -struct HandMeshSpheres { - vrb::TogglePtr toggle; - std::vector sphereTransforms; -}; - -struct HandMeshRendererSpheres::State { - std::vector handMeshState; -}; - -HandMeshRendererSpheres::HandMeshRendererSpheres(State& aState, vrb::CreationContextPtr& aContext) - : m(aState) { - context = aContext; -} - -HandMeshRendererPtr HandMeshRendererSpheres::Create(vrb::CreationContextPtr& aContext) { - return std::make_unique >(aContext); -} - -void HandMeshRendererSpheres::Update(const uint32_t aControllerIndex, const std::vector& handJointTransforms, - const vrb::GroupPtr& aRoot, HandMeshBufferPtr& buffer, const bool aEnabled, const bool leftHanded) { - assert(!buffer); - - if (aControllerIndex >= m.handMeshState.size()) - m.handMeshState.resize(aControllerIndex + 1); - auto& handMesh = m.handMeshState.at(aControllerIndex); - - // We need to call ToggleAll() even if aEnabled is false, to be able to hide the - // hand mesh. - if (handMesh.toggle) - handMesh.toggle->ToggleAll(aEnabled); - - if (!aEnabled) - return; - - // Lazily create toggle and spheres' geometry and transform nodes. - if (!handMesh.toggle) { - vrb::CreationContextPtr create = context.lock(); - handMesh.toggle = vrb::Toggle::Create(create); - - assert(handJointTransforms.size() > 0); - - auto state = GetHandMeshDefaultRenderState(create); - - float radius = 0.65; - vrb::GeometryPtr sphere = DeviceUtils::GetSphereGeometry(create, 36, radius); - sphere->SetRenderState(state); - - handMesh.sphereTransforms.resize(handJointTransforms.size()); - for (uint32_t i = 0; i < handMesh.sphereTransforms.size(); i++) { - vrb::TransformPtr transform = vrb::Transform::Create(create); - transform->AddNode(sphere); - handMesh.toggle->AddNode(transform); - handMesh.sphereTransforms[i] = transform; - } - } - - // Check that the toggle node has been added to the scene graph - std::vector parents; - handMesh.toggle->GetParents(parents); - if (parents.size() == 0) - aRoot->AddNode(handMesh.toggle); - - assert(handMesh.sphereTransforms.size() == handJointTransforms.size()); - for (int i = 0; i < handMesh.sphereTransforms.size(); i++) - handMesh.sphereTransforms[i]->SetTransform(handJointTransforms[i]); -} - // HandMeshRendererGeometry struct HandMeshGeometry { diff --git a/app/src/main/cpp/HandMeshRenderer.h b/app/src/main/cpp/HandMeshRenderer.h index 0a0c056a35..ee918065fe 100644 --- a/app/src/main/cpp/HandMeshRenderer.h +++ b/app/src/main/cpp/HandMeshRenderer.h @@ -35,21 +35,6 @@ class HandMeshRenderer { }; -// HandMeshRendererSpheres - -class HandMeshRendererSpheres: public HandMeshRenderer { -protected: - struct State; - State& m; - HandMeshRendererSpheres(State&, vrb::CreationContextPtr&); -public: - static HandMeshRendererPtr Create(vrb::CreationContextPtr&); -private: - void Update(const uint32_t aControllerIndex, const std::vector& handJointTransforms, - const vrb::GroupPtr& aRoot, HandMeshBufferPtr& aBuffer, const bool aEnabled, const bool leftHanded) override; -}; - - // HandMeshRendererSkinned struct HandMeshSkinned; diff --git a/app/src/openxr/cpp/DeviceDelegateOpenXR.cpp b/app/src/openxr/cpp/DeviceDelegateOpenXR.cpp index 4a1c6f5bd9..db406fa33d 100644 --- a/app/src/openxr/cpp/DeviceDelegateOpenXR.cpp +++ b/app/src/openxr/cpp/DeviceDelegateOpenXR.cpp @@ -1672,13 +1672,6 @@ DeviceDelegateOpenXR::EnterVR(const crow::BrowserEGLContext& aEGLContext) { if (m.handMeshProperties) { m.handMeshRenderer = HandMeshRendererGeometry::Create(create); m.input->SetHandMeshBufferSizes(m.handMeshProperties->indexCount, m.handMeshProperties->vertexCount); - } else { -#if defined(PICOXR) - // Due to unreliable hand-tracking orientation data on Pico devices running system - // versions earlier than 5.7.1, we use the Spheres strategy. - if (CompareBuildIdString(kPicoVersionHandTrackingUpdate)) - m.handMeshRenderer = HandMeshRendererSpheres::Create(create); -#endif } if (!m.handMeshRenderer) diff --git a/app/src/openxr/cpp/OpenXRGestureManager.cpp b/app/src/openxr/cpp/OpenXRGestureManager.cpp index c8abc4e047..c02df05664 100644 --- a/app/src/openxr/cpp/OpenXRGestureManager.cpp +++ b/app/src/openxr/cpp/OpenXRGestureManager.cpp @@ -29,11 +29,6 @@ OpenXRGestureManager::handFacesHead(const vrb::Matrix &hand, const vrb::Matrix & // For the hand we take the Y axis because that corresponds to head's Z axis when // the hand is in upright position facing head (the gesture we want to detect). auto handDirection = hand.MultiplyDirection({0, 1, 0}).Normalize(); -#ifdef PICOXR - // Axis are inverted in Pico system versions prior to 5.7.1 - if (CompareBuildIdString(kPicoVersionHandTrackingUpdate)) - handDirection = hand.MultiplyDirection({0, 0, -1}); -#endif auto headDirection = head.MultiplyDirection({0, 0, -1}).Normalize(); // First check that vector directions align diff --git a/app/src/openxr/cpp/OpenXRHelpers.h b/app/src/openxr/cpp/OpenXRHelpers.h index 6924c3418f..10ed16db18 100644 --- a/app/src/openxr/cpp/OpenXRHelpers.h +++ b/app/src/openxr/cpp/OpenXRHelpers.h @@ -20,14 +20,6 @@ namespace crow { const vrb::Vector kAverageHeight(0.0f, 1.7f, 0.0f); #endif -// Hand tracking was thoroughly updated on Pico version 5.7.1 -static const std::string kPicoVersionHandTrackingUpdate = "5.7.1"; - -inline bool CompareBuildIdString(const std::string str) { - char buildId[128]; - return CompareSemanticVersionStrings(GetBuildIdString(buildId), str); -} - inline std::string GetXrVersionString(XrVersion ver) { return Fmt("%d.%d.%d", XR_VERSION_MAJOR(ver), XR_VERSION_MINOR(ver), XR_VERSION_PATCH(ver)); } diff --git a/app/src/openxr/cpp/OpenXRInputSource.cpp b/app/src/openxr/cpp/OpenXRInputSource.cpp index d5a75266b8..4fc1299231 100644 --- a/app/src/openxr/cpp/OpenXRInputSource.cpp +++ b/app/src/openxr/cpp/OpenXRInputSource.cpp @@ -633,21 +633,6 @@ OpenXRInputSource::PopulateHandJointLocations(device::RenderMode renderMode, std jointTransforms[i] = transform; jointRadii[i] = mHandJoints[i].radius; } -#if defined(PICOXR) - // Scale joints according to their radius (for rendering). This is currently only - // relevant on Pico with system version earlier than 5.7.1, where we are using spheres - // to render the hands instead of a proper hand model due to incorrect joint orientation. - if (CompareBuildIdString(kPicoVersionHandTrackingUpdate)) { - for (int i = 0; i < mHandJoints.size(); i++) { - if (IsHandJointPositionValid((XrHandJointEXT) i, mHandJoints)) { - float radius = mHandJoints[i].radius; - vrb::Matrix scale = vrb::Matrix::Identity().ScaleInPlace( - vrb::Vector(radius, radius, radius)); - jointTransforms[i].PostMultiplyInPlace(scale); - } - } - } -#endif } void OpenXRInputSource::EmulateControllerFromHand(device::RenderMode renderMode, XrTime predictedDisplayTime, const vrb::Matrix& head, const vrb::Matrix& handJointForAim, DeviceDelegate::PointerMode pointerMode, bool usingEyeTracking, ControllerDelegate& delegate) @@ -717,14 +702,6 @@ void OpenXRInputSource::EmulateControllerFromHand(device::RenderMode renderMode, correctionAngle); pointerTransform = pointerTransform.PostMultiply(correctionMatrix); } -#elif defined(PICOXR) - // On Pico, this only affects system versions earlier than 5.7.1 - if (CompareBuildIdString(kPicoVersionHandTrackingUpdate)) { - float correctionAngle = -M_PI_2; - pointerTransform - .PostMultiplyInPlace(vrb::Matrix::Rotation(vrb::Vector(0.0, 1.0, 0.0),correctionAngle) - .PostMultiply(vrb::Matrix::Rotation(vrb::Vector(0.0, 0.0, 1.0), correctionAngle))); - } #endif device::CapabilityFlags flags = device::Orientation | device::Position; diff --git a/app/src/openxr/cpp/OpenXRLayers.h b/app/src/openxr/cpp/OpenXRLayers.h index c9f529ce8a..14ab607935 100644 --- a/app/src/openxr/cpp/OpenXRLayers.h +++ b/app/src/openxr/cpp/OpenXRLayers.h @@ -189,14 +189,6 @@ class OpenXRLayerBase : public OpenXRLayer { info.width = width; info.height = height; bool shouldZeroInitialize = aSurfaceType == VRLayerSurface::SurfaceType::AndroidSurface; -#if defined(PICOXR) - // Circumvent a bug in the pico OpenXR runtime in versions below 5.4.0. - char buildId[128] = {0}; - if (CompareSemanticVersionStrings(GetBuildIdString(buildId), "5.4.0")) { - // System version is < 5.4.0 - shouldZeroInitialize = false; - } -#endif if (shouldZeroInitialize) { // These members must be zero // See https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/xrCreateSwapchainAndroidSurfaceKHR.html#XR_KHR_android_surface_swapchain diff --git a/app/src/picoxr/AndroidManifest.xml b/app/src/picoxr/AndroidManifest.xml index b7408a5607..6dadf8938d 100644 --- a/app/src/picoxr/AndroidManifest.xml +++ b/app/src/picoxr/AndroidManifest.xml @@ -10,8 +10,8 @@ + - diff --git a/app/src/picoxr/java/com/igalia/wolvic/PlatformSystemCheck.java b/app/src/picoxr/java/com/igalia/wolvic/PlatformSystemCheck.java index 8b6ab0c248..4bd5bcfb3e 100644 --- a/app/src/picoxr/java/com/igalia/wolvic/PlatformSystemCheck.java +++ b/app/src/picoxr/java/com/igalia/wolvic/PlatformSystemCheck.java @@ -1,10 +1,44 @@ package com.igalia.wolvic; +import android.util.Log; + +import com.igalia.wolvic.utils.SystemUtils; + public class PlatformSystemCheck extends SystemCheck { + private static final String PICO_OS_VERSION_PROPERTY = "ro.build.display.id"; + private static final int MIN_PICO_OS_MAJOR_VERSION = 5; + private static final int MIN_PICO_OS_MINOR_VERSION = 7; + private static final int MIN_PICO_OS_PATCH_VERSION = 1; + private static final String LOGTAG = SystemUtils.createLogtag(PlatformSystemCheck.class); + + /** + * Compares two version strings in the form x.y.z where x, y, and z are integers. + * @return a negative integer, zero, or a positive integer as the first version + * is less than, equal to, or greater than the second version. + */ + private int compare(String str1, String str2) { + String[] parts1 = str1.split("\\."); + String[] parts2 = str2.split("\\."); + + for (int i = 0; i < Math.min(parts1.length, parts2.length); i++) { + int num1 = Integer.parseInt(parts1[i]); + int num2 = Integer.parseInt(parts2[i]); + + if (num1 != num2) + return num1 - num2; + } + return parts1.length - parts2.length; + } @Override - public boolean isOSVersionCompatible() { return true; } + public boolean isOSVersionCompatible() { + String osVersion = getSystemProperty(PICO_OS_VERSION_PROPERTY); + Log.i(LOGTAG, "Checking that OS version is at least " + minSupportedVersion() + " (found " + osVersion + ")"); + return compare(osVersion, minSupportedVersion()) >= 0; + } @Override - public String minSupportedVersion() { return ""; } + public String minSupportedVersion() { + return MIN_PICO_OS_MAJOR_VERSION + "." + MIN_PICO_OS_MINOR_VERSION + "." + MIN_PICO_OS_PATCH_VERSION; + } }