Bug 1631635 - Implement IsPositionEmulated for XRInputSource. r=kip,imanol

Differential Revision: https://phabricator.services.mozilla.com/D71678
This commit is contained in:
Daosheng Mu 2020-04-21 11:17:34 +00:00
parent 92bbbc45cb
commit 2b669b7fa8
14 changed files with 145 additions and 28 deletions

View File

@ -36,7 +36,8 @@ bool GamepadPose::HasOrientation() const {
}
bool GamepadPose::HasPosition() const {
return bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position);
return bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position) ||
bool(mPoseState.flags & GamepadCapabilityFlags::Cap_PositionEmulated);
}
void GamepadPose::GetPosition(JSContext* aJSContext,
@ -44,7 +45,8 @@ void GamepadPose::GetPosition(JSContext* aJSContext,
ErrorResult& aRv) {
const bool valid =
mPoseState.isPositionValid &&
bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position);
(bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position) ||
bool(mPoseState.flags & GamepadCapabilityFlags::Cap_PositionEmulated));
SetFloat32Array(aJSContext, this, aRetval, mPosition,
valid ? mPoseState.position : nullptr, 3, aRv);
}
@ -54,7 +56,8 @@ void GamepadPose::GetLinearVelocity(JSContext* aJSContext,
ErrorResult& aRv) {
const bool valid =
mPoseState.isPositionValid &&
bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position);
(bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position) ||
bool(mPoseState.flags & GamepadCapabilityFlags::Cap_PositionEmulated));
SetFloat32Array(aJSContext, this, aRetval, mLinearVelocity,
valid ? mPoseState.linearVelocity : nullptr, 3, aRv);
}

View File

@ -32,13 +32,19 @@ enum class GamepadCapabilityFlags : uint16_t {
*/
Cap_LinearAcceleration = 1 << 4,
/**
* Cap_TargetRaySpacePosition is set if the Gamepad has a target ray space position.
* Cap_GripSpacePosition is set if the Gamepad has a grip space position.
*/
Cap_TargetRaySpacePosition = 1 << 5,
Cap_GripSpacePosition = 1 << 5,
/**
* Cap_PositionEmulated is set if the VRDisplay is capable of setting a
* emulated position (e.g. neck model) even if still doesn't support 6DOF
* tracking.
*/
Cap_PositionEmulated = 1 << 6,
/**
* Cap_All used for validity checking during IPC serialization
*/
Cap_All = (1 << 6) - 1
Cap_All = (1 << 7) - 1
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GamepadCapabilityFlags)

View File

@ -49,7 +49,8 @@ VRFieldOfView::VRFieldOfView(nsISupports* aParent,
mLeftDegrees(aSrc.leftDegrees) {}
bool VRDisplayCapabilities::HasPosition() const {
return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Position);
return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Position) ||
bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_PositionEmulated);
}
bool VRDisplayCapabilities::HasOrientation() const {
@ -266,7 +267,9 @@ void VRPose::GetLinearVelocity(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv) {
const bool valid =
bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position);
bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) ||
bool(mVRState.flags &
gfx::VRDisplayCapabilityFlags::Cap_PositionEmulated);
SetFloat32Array(aCx, this, aRetval, mLinearVelocity,
valid ? mVRState.pose.linearVelocity : nullptr, 3, aRv);
}

View File

@ -160,6 +160,7 @@ XRPose* XRFrame::GetPose(const XRSpace& aSpace, const XRSpace& aBaseSpace,
// TODO (Bug 1616393) - Check if poses must be limited:
// https://immersive-web.github.io/webxr/#poses-must-be-limited
const bool emulatedPosition = aSpace.IsPositionEmulated();
gfx::Matrix4x4Double base;
base.SetRotationFromQuaternion(aBaseSpace.GetEffectiveOriginOrientation());
base.PreTranslate(-aBaseSpace.GetEffectiveOriginPosition());
@ -167,7 +168,7 @@ XRPose* XRFrame::GetPose(const XRSpace& aSpace, const XRSpace& aBaseSpace,
gfx::Matrix4x4Double matrix = aSpace.GetEffectiveOriginTransform() * base;
RefPtr<XRRigidTransform> transform = new XRRigidTransform(mParent, matrix);
RefPtr<XRPose> pose = new XRPose(mParent, transform, false);
RefPtr<XRPose> pose = new XRPose(mParent, transform, emulatedPosition);
return pose;
}

View File

@ -8,6 +8,7 @@
#include "mozilla/dom/XRInputSourceEvent.h"
#include "XRNativeOriginViewer.h"
#include "XRNativeOriginTracker.h"
#include "XRInputSpace.h"
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadManager.h"
@ -170,13 +171,11 @@ void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
}
RefPtr<XRNativeOrigin> nativeOriginTargetRay = nullptr;
RefPtr<XRNativeOrigin> nativeOriginGrip = nullptr;
mTargetRayMode = XRTargetRayMode::Tracked_pointer;
switch (controllerState.targetRayMode) {
case gfx::TargetRayMode::Gaze:
mTargetRayMode = XRTargetRayMode::Gaze;
nativeOriginTargetRay = new XRNativeOriginViewer(displayClient);
nativeOriginGrip = new XRNativeOriginViewer(displayClient);
break;
case gfx::TargetRayMode::TrackedPointer:
mTargetRayMode = XRTargetRayMode::Tracked_pointer;
@ -184,7 +183,6 @@ void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
// data internally.
nativeOriginTargetRay =
new XRNativeOriginTracker(&controllerState.targetRayPose);
nativeOriginGrip = new XRNativeOriginTracker(&controllerState.pose);
break;
case gfx::TargetRayMode::Screen:
mTargetRayMode = XRTargetRayMode::Screen;
@ -193,10 +191,10 @@ void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
MOZ_ASSERT(false && "Undefined TargetRayMode type.");
break;
}
mTargetRaySpace =
new XRSpace(aSession->GetParentObject(), aSession, nativeOriginTargetRay);
mGripSpace =
new XRSpace(aSession->GetParentObject(), aSession, nativeOriginGrip);
mTargetRaySpace = new XRInputSpace(aSession->GetParentObject(), aSession,
nativeOriginTargetRay, aIndex);
const uint32_t gamepadId =
displayInfo.mDisplayID * kVRControllerMaxCount + aIndex;
const uint32_t hashKey = GamepadManager::GetGamepadIndexWithServiceType(
@ -207,6 +205,10 @@ void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
displayInfo.mDisplayID, controllerState.numButtons,
controllerState.numAxes, controllerState.numHaptics, 0, 0);
mIndex = aIndex;
if (!mGripSpace) {
CreateGripSpace(aSession, controllerState);
}
}
void XRInputSource::SetGamepadIsConnected(bool aConnected) {
@ -226,6 +228,13 @@ void XRInputSource::Update(XRSession* aSession) {
displayInfo.mControllerState[mIndex];
MOZ_ASSERT(controllerState.controllerName[0] != '\0');
// OculusVR and OpenVR controllers need to wait until
// update functions to assign GamepadCapabilityFlags::Cap_GripSpacePosition
// flag.
if (!mGripSpace) {
CreateGripSpace(aSession, controllerState);
}
// Update button values.
nsTArray<RefPtr<GamepadButton>> buttons;
mGamepad->GetButtons(buttons);
@ -348,5 +357,20 @@ void XRInputSource::DispatchEvent(const nsAString& aEvent,
frame->EndInputSourceEvent();
}
void XRInputSource::CreateGripSpace(
XRSession* aSession, const gfx::VRControllerState& controllerState) {
MOZ_ASSERT(!mGripSpace);
MOZ_ASSERT(aSession && mIndex >= 0 && mGamepad);
if (mTargetRayMode == XRTargetRayMode::Tracked_pointer &&
controllerState.flags & GamepadCapabilityFlags::Cap_GripSpacePosition) {
RefPtr<XRNativeOrigin> nativeOriginGrip = nullptr;
nativeOriginGrip = new XRNativeOriginTracker(&controllerState.pose);
mGripSpace = new XRInputSpace(aSession->GetParentObject(), aSession,
nativeOriginGrip, mIndex);
} else {
mGripSpace = nullptr;
}
}
} // namespace dom
} // namespace mozilla

View File

@ -61,6 +61,8 @@ class XRInputSource final : public nsWrapperCache {
ActionState_Released = 3
};
void CreateGripSpace(XRSession* aSession,
const gfx::VRControllerState& controllerState);
void DispatchEvent(const nsAString& aEvent, XRSession* aSession);
nsTArray<nsString> mProfiles;

34
dom/vr/XRInputSpace.cpp Normal file
View File

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "XRInputSpace.h"
namespace mozilla {
namespace dom {
XRInputSpace::XRInputSpace(nsIGlobalObject* aParent, XRSession* aSession,
XRNativeOrigin* aNativeOrigin,
int32_t aControllerIndex)
: XRSpace(aParent, aSession, aNativeOrigin), mIndex(aControllerIndex) {}
bool XRInputSpace::IsPositionEmulated() const {
gfx::VRDisplayClient* display = mSession->GetDisplayClient();
if (!display) {
// When there are no sensors, the position is considered emulated.
return true;
}
const gfx::VRDisplayInfo& displayInfo = display->GetDisplayInfo();
const gfx::VRControllerState& controllerState =
displayInfo.mControllerState[mIndex];
MOZ_ASSERT(controllerState.controllerName[0] != '\0');
return (
(controllerState.flags & GamepadCapabilityFlags::Cap_PositionEmulated) !=
GamepadCapabilityFlags::Cap_None);
}
} // namespace dom
} // namespace mozilla

33
dom/vr/XRInputSpace.h Normal file
View File

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_XRInputSpace_h_
#define mozilla_dom_XRInputSpace_h_
#include "XRInputSpace.h"
namespace mozilla {
namespace dom {
class XRInputSpace : public XRSpace {
public:
explicit XRInputSpace(nsIGlobalObject* aParent, XRSession* aSession,
XRNativeOrigin* aNativeOrigin,
int32_t aControllerIndex);
virtual bool IsPositionEmulated() const override;
protected:
virtual ~XRInputSpace() = default;
private:
int32_t mIndex;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_XRInputSpace_h_

View File

@ -19,7 +19,8 @@ gfx::PointDouble3D XRNativeOriginLocal::GetPosition() {
if (!mInitialPositionValid) {
const gfx::VRHMDSensorState& sensorState = mDisplay->GetSensorState();
gfx::PointDouble3D origin;
if (sensorState.flags & VRDisplayCapabilityFlags::Cap_Position) {
if (sensorState.flags & VRDisplayCapabilityFlags::Cap_Position ||
sensorState.flags & VRDisplayCapabilityFlags::Cap_PositionEmulated) {
mInitialPosition.x = sensorState.pose.position[0];
mInitialPosition.y = sensorState.pose.position[1];
mInitialPosition.z = sensorState.pose.position[2];

View File

@ -38,7 +38,7 @@ class XRSpace : public DOMEventTargetHelper {
gfx::QuaternionDouble GetEffectiveOriginOrientation() const;
gfx::PointDouble3D GetEffectiveOriginPosition() const;
gfx::Matrix4x4Double GetEffectiveOriginTransform() const;
bool IsPositionEmulated() const;
virtual bool IsPositionEmulated() const;
protected:
virtual ~XRSpace() = default;

View File

@ -39,6 +39,7 @@ UNIFIED_SOURCES = [
'XRFrame.cpp',
'XRInputSource.cpp',
'XRInputSourceArray.cpp',
'XRInputSpace.cpp',
'XRNativeOriginFixed.cpp',
'XRNativeOriginLocal.cpp',
'XRNativeOriginLocalFloor.cpp',

View File

@ -119,13 +119,19 @@ enum class ControllerCapabilityFlags : uint16_t {
*/
Cap_LinearAcceleration = 1 << 4,
/**
* Cap_TargetRaySpacePosition is set if the Gamepad has a target ray space position.
* Cap_TargetRaySpacePosition is set if the Gamepad has a grip space position.
*/
Cap_TargetRaySpacePosition = 1 << 5,
Cap_GripSpacePosition = 1 << 5,
/**
* Cap_PositionEmulated is set if the XRInputSoruce is capable of setting a
* emulated position (e.g. neck model) even if still doesn't support 6DOF
* tracking.
*/
Cap_PositionEmulated = 1 << 6,
/**
* Cap_All used for validity checking during IPC serialization
*/
Cap_All = (1 << 6) - 1
Cap_All = (1 << 7) - 1
};
#endif // ifndef MOZILLA_INTERNAL_API

View File

@ -1266,7 +1266,7 @@ void OculusSession::UpdateControllerPose(VRSystemState& aState,
controllerState.flags |=
dom::GamepadCapabilityFlags::Cap_LinearAcceleration;
controllerState.flags |=
dom::GamepadCapabilityFlags::Cap_TargetRaySpacePosition;
dom::GamepadCapabilityFlags::Cap_GripSpacePosition;
}
if (bNewController || trackingState.HandStatusFlags[handIdx] &
@ -1409,7 +1409,8 @@ void OculusSession::UpdateControllerInputs(VRSystemState& aState,
MOZ_ASSERT(axisIdx == kNumOculusAxes);
}
SetControllerSelectionAndSqueezeFrameId(controllerState, aState.displayState.lastSubmittedFrameId);
SetControllerSelectionAndSqueezeFrameId(
controllerState, aState.displayState.lastSubmittedFrameId);
}
}

View File

@ -1047,7 +1047,8 @@ void OpenVRSession::UpdateControllerButtons(VRSystemState& aState) {
VRControllerState& controllerState = aState.controllerState[stateIndex];
controllerState.hand = GetControllerHandFromControllerRole(role);
mControllerMapper->UpdateButtons(controllerState, mControllerHand[role]);
SetControllerSelectionAndSqueezeFrameId(controllerState, aState.displayState.lastSubmittedFrameId);
SetControllerSelectionAndSqueezeFrameId(
controllerState, aState.displayState.lastSubmittedFrameId);
}
}
@ -1072,9 +1073,10 @@ void OpenVRSession::UpdateControllerPoses(VRSystemState& aState) {
} else {
const ::vr::TrackedDevicePose_t& pose = poseData.pose;
if (pose.bDeviceIsConnected) {
controllerState.flags = (dom::GamepadCapabilityFlags::Cap_Orientation |
dom::GamepadCapabilityFlags::Cap_Position |
dom::GamepadCapabilityFlags::Cap_TargetRaySpacePosition);
controllerState.flags =
(dom::GamepadCapabilityFlags::Cap_Orientation |
dom::GamepadCapabilityFlags::Cap_Position |
dom::GamepadCapabilityFlags::Cap_GripSpacePosition);
} else {
controllerState.flags = dom::GamepadCapabilityFlags::Cap_None;
}
@ -1119,7 +1121,7 @@ void OpenVRSession::UpdateControllerPoses(VRSystemState& aState) {
// Calculate its target ray space by shifting degrees in x-axis
// for ergonomic.
const float kPointerAngleDegrees = -0.698; // 40 degrees.
const float kPointerAngleDegrees = -0.698; // 40 degrees.
gfx::Matrix4x4 rayMtx(m);
rayMtx.RotateX(kPointerAngleDegrees);
gfx::Quaternion rayRot;