From 47d45cc2954d4b3f62f5ffb63085e07c28acdc58 Mon Sep 17 00:00:00 2001 From: Sergio Villar Senin Date: Tue, 3 Dec 2024 10:58:30 +0100 Subject: [PATCH] Migration to Gecko 128.5.1esr The recent backports to the 128.x ESR releases brought changes to the shared memory structures we use for WebXR. Most of them are migrations from C arrays to std::arrays but there are some other changes. Apart from that the structures used in Chromium for hand tracking and AR had to be updated too. --- app/src/main/cpp/ExternalVR.cpp | 48 +++--- app/src/main/cpp/moz_external_vr.h | 250 ++++++++++++++++++++++++----- 2 files changed, 239 insertions(+), 59 deletions(-) diff --git a/app/src/main/cpp/ExternalVR.cpp b/app/src/main/cpp/ExternalVR.cpp index 19840f4bfe5..5a0760f55cf 100644 --- a/app/src/main/cpp/ExternalVR.cpp +++ b/app/src/main/cpp/ExternalVR.cpp @@ -113,6 +113,13 @@ class Wait { VRB_NO_NEW_DELETE }; +// template method that returns the data size of a std::array of type T +template +size_t +arraySize(const std::array&) { + return sizeof(T) * N; +} + } // namespace namespace crow { @@ -160,8 +167,8 @@ struct ExternalVR::State { system.displayState.isMounted = true; system.displayState.nativeFramebufferScaleFactor = 1.0f; const vrb::Matrix identity = vrb::Matrix::Identity(); - memcpy(&(system.sensorState.leftViewMatrix), identity.Data(), sizeof(system.sensorState.leftViewMatrix)); - memcpy(&(system.sensorState.rightViewMatrix), identity.Data(), sizeof(system.sensorState.rightViewMatrix)); + memcpy(system.sensorState.leftViewMatrix.data(), identity.Data(), arraySize(system.sensorState.leftViewMatrix)); + memcpy(system.sensorState.rightViewMatrix.data(), identity.Data(), arraySize(system.sensorState.rightViewMatrix)); system.sensorState.pose.orientation[3] = 1.0f; lastFrameId = 0; firstPresentingFrame = false; @@ -292,7 +299,7 @@ ExternalVR::SetDeviceName(const std::string& aName) { if (aName.length() == 0) { return; } - strncpy(m.system.displayState.displayName, aName.c_str(), + strncpy(m.system.displayState.displayName.data(), aName.c_str(), mozilla::gfx::kVRDisplayNameMaxLen - 1); m.system.displayState.displayName[mozilla::gfx::kVRDisplayNameMaxLen - 1] = '\0'; } @@ -362,7 +369,7 @@ ExternalVR::SetEyeTransform(const device::Eye aEye, const vrb::Matrix& aTransfor mozilla::gfx::VRDisplayState::Eye which = (aEye == device::Eye::Right ? mozilla::gfx::VRDisplayState::Eye_Right : mozilla::gfx::VRDisplayState::Eye_Left); - memcpy(&(m.system.displayState.eyeTransform[which]), aTransform.Data(), sizeof(m.system.displayState.eyeTransform[which])); + memcpy(m.system.displayState.eyeTransform[which].data(), aTransform.Data(), arraySize(m.system.displayState.eyeTransform[which])); m.eyeTransforms[device::EyeIndex(aEye)] = aTransform; } @@ -385,12 +392,12 @@ ExternalVR::SetStageSize(const float aWidth, const float aDepth) { void ExternalVR::SetSittingToStandingTransform(const vrb::Matrix& aTransform) { - memcpy(&(m.system.displayState.sittingToStandingTransform), aTransform.Data(), sizeof(m.system.displayState.sittingToStandingTransform)); + memcpy(m.system.displayState.sittingToStandingTransform.data(), aTransform.Data(), arraySize(m.system.displayState.sittingToStandingTransform)); } void ExternalVR::SetBlendModes(std::vector aBlendModes) { - memset(&m.system.displayState.blendModes, (int) mozilla::gfx::VRDisplayBlendMode::_empty, sizeof(m.system.displayState.blendModes)); + std::fill(m.system.displayState.blendModes.begin(), m.system.displayState.blendModes.end(), mozilla::gfx::VRDisplayBlendMode::_empty); int i = 0; for (const auto& blendMode : aBlendModes) { switch (blendMode) { @@ -513,29 +520,24 @@ ExternalVR::PushFramePoses(const vrb::Matrix& aHeadTransform, const std::vector< const vrb::Matrix inverseHeadTransform = aHeadTransform.Inverse(); vrb::Quaternion quaternion(inverseHeadTransform); vrb::Vector translation = aHeadTransform.GetTranslation(); - memcpy(&(m.system.sensorState.pose.orientation), quaternion.Data(), - sizeof(m.system.sensorState.pose.orientation)); - memcpy(&(m.system.sensorState.pose.position), translation.Data(), - sizeof(m.system.sensorState.pose.position)); + memcpy(m.system.sensorState.pose.orientation.data(), quaternion.Data(), arraySize(m.system.sensorState.pose.orientation)); + memcpy(m.system.sensorState.pose.position.data(), translation.Data(), arraySize(m.system.sensorState.pose.position)); m.system.sensorState.inputFrameID++; m.system.displayState.lastSubmittedFrameId = m.lastFrameId; vrb::Matrix leftView = m.eyeTransforms[device::EyeIndex(device::Eye::Left)].Inverse().PostMultiply(inverseHeadTransform); vrb::Matrix rightView = m.eyeTransforms[device::EyeIndex(device::Eye::Right)].Inverse().PostMultiply(inverseHeadTransform); - memcpy(&(m.system.sensorState.leftViewMatrix), leftView.Data(), - sizeof(m.system.sensorState.leftViewMatrix)); - memcpy(&(m.system.sensorState.rightViewMatrix), rightView.Data(), - sizeof(m.system.sensorState.rightViewMatrix)); - + memcpy(m.system.sensorState.leftViewMatrix.data(), leftView.Data(), arraySize(m.system.sensorState.leftViewMatrix)); + memcpy(m.system.sensorState.rightViewMatrix.data(), rightView.Data(), arraySize(m.system.sensorState.rightViewMatrix)); - memset(m.system.controllerState, 0, sizeof(m.system.controllerState)); + memset(m.system.controllerState.data(), 0, arraySize(m.system.controllerState)); for (int i = 0; i < aControllers.size(); ++i) { const Controller& controller = aControllers[i]; if (controller.immersiveName.empty() || !controller.enabled) { continue; } mozilla::gfx::VRControllerState& immersiveController = m.system.controllerState[i]; - memcpy(immersiveController.controllerName, controller.immersiveName.c_str(), controller.immersiveName.size() + 1); + memcpy(immersiveController.controllerName.data(), controller.immersiveName.c_str(), controller.immersiveName.size() + 1); immersiveController.numButtons = controller.numButtons; immersiveController.buttonPressed = controller.immersivePressedState; immersiveController.buttonTouched = controller.immersiveTouchedState; @@ -557,11 +559,11 @@ ExternalVR::PushFramePoses(const vrb::Matrix& aHeadTransform, const std::vector< immersiveController.isOrientationValid = true; vrb::Quaternion rotate(controller.transformMatrix.AfineInverse()); - memcpy(&(immersiveController.targetRayPose.orientation), rotate.Data(), sizeof(immersiveController.targetRayPose.orientation)); + memcpy(immersiveController.targetRayPose.orientation.data(), rotate.Data(), arraySize(immersiveController.targetRayPose.orientation)); if (flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_Position) || flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_PositionEmulated)) { vrb::Vector position(controller.transformMatrix.GetTranslation()); - memcpy(&(immersiveController.targetRayPose.position), position.Data(), sizeof(immersiveController.targetRayPose.position)); + memcpy(immersiveController.targetRayPose.position.data(), position.Data(), arraySize(immersiveController.targetRayPose.position)); } } @@ -573,8 +575,8 @@ ExternalVR::PushFramePoses(const vrb::Matrix& aHeadTransform, const std::vector< #endif vrb::Vector position(immersiveBeamTransform.GetTranslation()); vrb::Quaternion rotate(immersiveBeamTransform.AfineInverse()); - memcpy(&(immersiveController.pose.position), position.Data(), sizeof(immersiveController.pose.position)); - memcpy(&(immersiveController.pose.orientation), rotate.Data(), sizeof(immersiveController.pose.orientation)); + memcpy(immersiveController.pose.position.data(), position.Data(), arraySize(immersiveController.pose.position)); + memcpy(immersiveController.pose.orientation.data(), rotate.Data(), arraySize(immersiveController.pose.orientation)); } // TODO:: We should add TargetRayMode::_end in moz_external_vr.h to help this check. @@ -598,7 +600,7 @@ ExternalVR::PushFramePoses(const vrb::Matrix& aHeadTransform, const std::vector< // Since the palm joint is at index zero, we pass joints from 1 to 25 (omitting the palm). assert(controller.handJointTransforms.size() == mozilla::gfx::kHandTrackingNumJoints + 1); for (int j = 0; j < mozilla::gfx::kHandTrackingNumJoints; j++) { - memcpy(&immersiveController.handTrackingData.handJointData[j].transform, + memcpy(immersiveController.handTrackingData.handJointData[j].transform.data(), &controller.handJointTransforms[j + 1], sizeof(vrb::Matrix)); immersiveController.handTrackingData.handJointData[j].radius = controller.handJointRadii[j + 1]; } @@ -627,7 +629,7 @@ ExternalVR::WaitFrameResult() { } #if CHROMIUM - if(m.browser.dropFame) { + if(m.browser.dropFrame) { m.system.displayState.droppedFrameCount++; return false; } diff --git a/app/src/main/cpp/moz_external_vr.h b/app/src/main/cpp/moz_external_vr.h index 941eeb2034b..b056ccadb05 100644 --- a/app/src/main/cpp/moz_external_vr.h +++ b/app/src/main/cpp/moz_external_vr.h @@ -18,16 +18,17 @@ # include # include # include "mozilla/TypedEnumBits.h" +# include "mozilla/dom/TiedFields.h" # include "mozilla/gfx/2D.h" # include # include -# include #endif // MOZILLA_INTERNAL_API #if defined(__ANDROID__) # include #endif // defined(__ANDROID__) +#include #include #include @@ -47,8 +48,8 @@ namespace gfx { // and mapped files if we have both release and nightlies // running at the same time? Or...what if we have multiple // release builds running on same machine? (Bug 1563232) -#define SHMEM_VERSION "0.0.11" -static const int32_t kVRExternalVersion = 20; +#define SHMEM_VERSION "0.0.13" +static const int32_t kVRExternalVersion = 21; // We assign VR presentations to groups with a bitmask. // Currently, we will only display either content or chrome. @@ -82,16 +83,40 @@ struct Point3D_POD { float x; float y; float z; + +#ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { return std::tie(x, y, z); } + + bool operator==(const Point3D_POD& other) const { + return TiedFields(*this) == TiedFields(other); + } +#endif }; struct IntSize_POD { int32_t width; int32_t height; + +#ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { return std::tie(width, height); } + + bool operator==(const IntSize_POD& other) const { + return TiedFields(*this) == TiedFields(other); + } +#endif }; struct FloatSize_POD { float width; float height; + +#ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { return std::tie(width, height); } + + bool operator==(const FloatSize_POD& other) const { + return TiedFields(*this) == TiedFields(other); + } +#endif }; #ifndef MOZILLA_INTERNAL_API @@ -159,14 +184,99 @@ enum class VRControllerType : uint8_t { _end }; +} // namespace gfx + +template +bool IsEnumCase(T); + +template <> +inline constexpr bool IsEnumCase( + const gfx::VRControllerType raw) { + switch (raw) { + case gfx::VRControllerType::_empty: + case gfx::VRControllerType::HTCVive: + case gfx::VRControllerType::HTCViveCosmos: + case gfx::VRControllerType::HTCViveFocus: + case gfx::VRControllerType::HTCViveFocusPlus: + case gfx::VRControllerType::MSMR: + case gfx::VRControllerType::ValveIndex: + case gfx::VRControllerType::OculusGo: + case gfx::VRControllerType::OculusTouch: + case gfx::VRControllerType::OculusTouch2: + case gfx::VRControllerType::OculusTouch3: + case gfx::VRControllerType::PicoGaze: + case gfx::VRControllerType::PicoG2: + case gfx::VRControllerType::PicoNeo2: + case gfx::VRControllerType::Pico4: + case gfx::VRControllerType::MetaQuest3: + case gfx::VRControllerType::MagicLeap2: + case gfx::VRControllerType::PicoNeo3: + case gfx::VRControllerType::_end: + return true; + } + return false; +} +namespace gfx { + +// - + enum class TargetRayMode : uint8_t { Gaze, TrackedPointer, Screen }; +} // namespace gfx +template <> +inline constexpr bool IsEnumCase( + const gfx::TargetRayMode raw) { + switch (raw) { + case gfx::TargetRayMode::Gaze: + case gfx::TargetRayMode::TrackedPointer: + case gfx::TargetRayMode::Screen: + return true; + } + return false; +} +namespace gfx { + +// - + enum class GamepadMappingType : uint8_t { _empty, Standard, XRStandard }; +} // namespace gfx +template <> +inline constexpr bool IsEnumCase( + const gfx::GamepadMappingType raw) { + switch (raw) { + case gfx::GamepadMappingType::_empty: + case gfx::GamepadMappingType::Standard: + case gfx::GamepadMappingType::XRStandard: + return true; + } + return false; +} +namespace gfx { + +// - + enum class VRDisplayBlendMode : uint8_t { _empty, Opaque, Additive, AlphaBlend }; enum class ImmersiveXRSessionType : uint8_t { VR, AR }; +} // namespace gfx +template <> +inline constexpr bool IsEnumCase( + const gfx::VRDisplayBlendMode raw) { + switch (raw) { + case gfx::VRDisplayBlendMode::_empty: + case gfx::VRDisplayBlendMode::Opaque: + case gfx::VRDisplayBlendMode::Additive: + case gfx::VRDisplayBlendMode::AlphaBlend: + return true; + } + return false; +} +namespace gfx { + +// - + enum class VRDisplayCapabilityFlags : uint16_t { Cap_None = 0, /** @@ -256,26 +366,43 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayBlendMode) #endif // MOZILLA_INTERNAL_API struct VRPose { - float orientation[4]; - float position[3]; - float angularVelocity[3]; - float angularAcceleration[3]; - float linearVelocity[3]; - float linearAcceleration[3]; + std::array orientation; + std::array position; + std::array angularVelocity; + std::array angularAcceleration; + std::array linearVelocity; + std::array linearAcceleration; + +#ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { + return std::tie(orientation, position, angularVelocity, angularAcceleration, + linearVelocity, linearAcceleration); + } + + bool operator==(const VRPose& other) const { + return TiedFields(*this) == TiedFields(other); + } +#endif // MOZILLA_INTERNAL_API }; struct VRHMDSensorState { uint64_t inputFrameID; double timestamp; VRDisplayCapabilityFlags flags; + uint16_t _padding; // These members will only change with inputFrameID: VRPose pose; - float leftViewMatrix[16]; - float rightViewMatrix[16]; + std::array leftViewMatrix; + std::array rightViewMatrix; #ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { + return std::tie(inputFrameID, timestamp, flags, _padding, pose, + leftViewMatrix, rightViewMatrix); + } + void Clear() { memset(this, 0, sizeof(VRHMDSensorState)); } bool operator==(const VRHMDSensorState& other) const { @@ -298,6 +425,13 @@ struct VRFieldOfView { double leftDegrees; #ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { + return std::tie(upDegrees, rightDegrees, downDegrees, leftDegrees); + } + + bool operator==(const VRFieldOfView& other) const { + return TiedFields(*this) == TiedFields(other); + } VRFieldOfView() = default; VRFieldOfView(double up, double right, double down, double left) @@ -313,12 +447,6 @@ struct VRFieldOfView { leftDegrees = atan(left) * 180.0 / M_PI; } - bool operator==(const VRFieldOfView& other) const { - return other.upDegrees == upDegrees && other.downDegrees == downDegrees && - other.rightDegrees == rightDegrees && - other.leftDegrees == leftDegrees; - } - bool operator!=(const VRFieldOfView& other) const { return !(*this == other); } @@ -339,56 +467,76 @@ struct VRDisplayState { // When true, indicates that the VR service has shut down bool shutdown; + std::array _padding1; // Minimum number of milliseconds to wait before attempting // to start the VR service again uint32_t minRestartInterval; - char displayName[kVRDisplayNameMaxLen]; + std::array displayName; // eight byte character code identifier // LSB first, so "ABCDEFGH" -> ('H'<<56) + ('G'<<48) + ('F'<<40) + // ('E'<<32) + ('D'<<24) + ('C'<<16) + // ('B'<<8) + 'A'). uint64_t eightCC; VRDisplayCapabilityFlags capabilityFlags; - VRDisplayBlendMode blendModes[kVRBlendModesMaxLen]; - VRFieldOfView eyeFOV[VRDisplayState::NumEyes]; - float eyeTransform[VRDisplayState::NumEyes][16]; + std::array blendModes; + std::array _padding2; + std::array eyeFOV; + static_assert(std::is_pod::value); + std::array, VRDisplayState::NumEyes> eyeTransform; + static_assert(std::is_pod::value); IntSize_POD eyeResolution; + static_assert(std::is_pod::value); float nativeFramebufferScaleFactor; bool suppressFrames; bool isConnected; bool isMounted; + uint8_t _padding3; FloatSize_POD stageSize; + static_assert(std::is_pod::value); // We can't use a Matrix4x4 here unless we ensure it's a POD type - float sittingToStandingTransform[16]; + std::array sittingToStandingTransform; uint64_t lastSubmittedFrameId; bool lastSubmittedFrameSuccessful; + std::array _padding4; uint32_t presentingGeneration; // Telemetry bool reportsDroppedFrames; + std::array _padding5; uint64_t droppedFrameCount; #ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { + return std::tie(shutdown, _padding1, minRestartInterval, displayName, + eightCC, capabilityFlags, blendModes, _padding2, eyeFOV, + eyeTransform, eyeResolution, nativeFramebufferScaleFactor, + suppressFrames, isConnected, isMounted, _padding3, + stageSize, sittingToStandingTransform, lastSubmittedFrameId, + lastSubmittedFrameSuccessful, _padding4, + presentingGeneration, reportsDroppedFrames, _padding5, + droppedFrameCount); + } + + bool operator==(const VRDisplayState& other) const { + return TiedFields(*this) == TiedFields(other); + } + void Clear() { memset(this, 0, sizeof(VRDisplayState)); } #endif }; +static_assert(std::is_pod::value); -#if CHROMIUM -// WebXR hand-tracking support +// https://www.w3.org/TR/webxr-hand-input-1/#skeleton-joints-section +static const uint32_t kHandTrackingNumJoints = 25; struct VRHandJointData { - float transform[16]; + std::array transform; float radius; }; - -// https://www.w3.org/TR/webxr-hand-input-1/#skeleton-joints-section -static const uint32_t kHandTrackingNumJoints = 25; - struct VRHandTrackingData { - VRHandJointData handJointData[kHandTrackingNumJoints]; + std::array handJointData; }; -#endif struct VRControllerState { - char controllerName[kVRControllerNameMaxLen]; + std::array controllerName; #ifdef MOZILLA_INTERNAL_API dom::GamepadHand hand; #else @@ -403,6 +551,8 @@ struct VRControllerState { // https://immersive-web.github.io/webxr-gamepads-module/#enumdef-gamepadmappingtype GamepadMappingType mappingType; + uint32_t _padding1; + // Start frame ID of the most recent primary select // action, or 0 if the select action has never occurred. uint64_t selectActionStartFrameId; @@ -426,12 +576,13 @@ struct VRControllerState { uint32_t numButtons; uint32_t numAxes; uint32_t numHaptics; + uint32_t _padding2; // The current button pressed bit of button mask. uint64_t buttonPressed; // The current button touched bit of button mask. uint64_t buttonTouched; - float triggerValue[kVRControllerMaxButtons]; - float axisValue[kVRControllerMaxAxis]; + std::array triggerValue; + std::array axisValue; #ifdef MOZILLA_INTERNAL_API dom::GamepadCapabilityFlags flags; @@ -439,6 +590,8 @@ struct VRControllerState { ControllerCapabilityFlags flags; #endif + uint16_t _padding3; + // When Cap_Position is set in flags, pose corresponds // to the controllers' pose in grip space: // https://immersive-web.github.io/webxr/#dom-xrinputsource-gripspace @@ -456,8 +609,23 @@ struct VRControllerState { bool hasHandTrackingData; VRHandTrackingData handTrackingData; #endif + uint16_t _padding4; #ifdef MOZILLA_INTERNAL_API + auto MutTiedFields() { + return std::tie(controllerName, hand, type, targetRayMode, mappingType, + _padding1, selectActionStartFrameId, + selectActionStopFrameId, squeezeActionStartFrameId, + squeezeActionStopFrameId, numButtons, numAxes, numHaptics, + _padding2, buttonPressed, buttonTouched, triggerValue, + axisValue, flags, _padding3, pose, targetRayPose, + isPositionValid, isOrientationValid, _padding4); + } + + bool operator==(const VRControllerState& other) const { + return TiedFields(*this) == TiedFields(other); + } + void Clear() { memset(this, 0, sizeof(VRControllerState)); } #endif }; @@ -548,7 +716,7 @@ struct VRBrowserState { bool presentationActive; bool navigationTransitionActive; #if CHROMIUM - bool dropFame; + bool dropFrame; #endif VRLayerState layerState[kVRLayerMaxCount]; VRHapticState hapticState[kVRHapticsMaxCount]; @@ -564,8 +732,13 @@ struct VRSystemState { bool enumerationCompleted; VRDisplayState displayState; VRHMDSensorState sensorState; - VRControllerState controllerState[kVRControllerMaxCount]; + std::array controllerState; }; +static_assert(std::is_pod::value); +static_assert(std::is_pod::value); +static_assert(std::is_pod::value); + +static_assert(std::is_pod::value); enum class VRFxEventType : uint8_t { NONE = 0, @@ -694,6 +867,11 @@ struct VRExternalShmem { // As we are memcpy'ing VRExternalShmem and its members around, it must be a POD // type +static_assert(std::is_pod::value); +static_assert(std::is_pod::value); +static_assert(std::is_pod::value); +static_assert(std::is_pod::value); + static_assert(std::is_pod::value, "VRExternalShmem must be a POD type.");