Bug 1611310 - Implement XRInputSource module. r=kip

Differential Revision: https://phabricator.services.mozilla.com/D67430

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Daosheng Mu 2020-04-07 23:49:47 +00:00
parent bfaebdfe1e
commit 7f945fd97b
16 changed files with 348 additions and 46 deletions

View File

@ -32,9 +32,9 @@ enum class GamepadCapabilityFlags : uint16_t {
*/
Cap_LinearAcceleration = 1 << 4,
/**
* Cap_GripSpacePosition is set if the Gamepad has a grip space position.
* Cap_TargetRaySpacePosition is set if the Gamepad has a target ray space position.
*/
Cap_GripSpacePosition = 1 << 5,
Cap_TargetRaySpacePosition = 1 << 5,
/**
* Cap_All used for validity checking during IPC serialization
*/

View File

@ -156,18 +156,30 @@ XRPose* XRFrame::GetPose(const XRSpace& aSpace, const XRSpace& aBaseSpace,
// TODO (Bug 1616390) - Validate that poses may be reported:
// https://immersive-web.github.io/webxr/#poses-may-be-reported
if (aSpace.GetSession()->VisibilityState() != XRVisibilityState::Visible) {
aRv.ThrowInvalidStateError(
"An XRSpace s visibilityState in not 'visible'.");
return nullptr;
}
// TODO (Bug 1616393) - Check if poses must be limited:
// https://immersive-web.github.io/webxr/#poses-must-be-limited
// TODO (Bug 1618723) - Implement XRFrame::GetPose
// https://immersive-web.github.io/webxr/#dom-xrframe-getpose
//
// RefPtr<XRViewerPose> pose =
// new XRViewerPose(mParent, transform, emulatedPosition, views);
// return pose;
//
return nullptr;
const gfx::PointDouble3D& originPosition = aBaseSpace.GetEffectiveOriginPosition();
gfx::PointDouble3D position = aSpace.GetEffectiveOriginPosition();
gfx::QuaternionDouble orientation = aSpace.GetEffectiveOriginOrientation();
gfx::QuaternionDouble invOriginOrientation(aBaseSpace.GetEffectiveOriginOrientation());
invOriginOrientation.Invert();
position = invOriginOrientation.RotatePoint(position);
position -= originPosition;
orientation *= invOriginOrientation;
RefPtr<XRRigidTransform> transform = new XRRigidTransform(mParent, position, orientation);
RefPtr<XRPose> pose = new XRPose(mParent, transform, false);
return pose;
}
void XRFrame::StartAnimationFrame() {

View File

@ -5,7 +5,8 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/XRInputSource.h"
#include "mozilla/dom/XRSpace.h"
#include "XRNativeOriginViewer.h"
#include "XRNativeOriginTracker.h"
namespace mozilla {
namespace dom {
@ -14,6 +15,93 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(XRInputSource, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(XRInputSource, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(XRInputSource, Release)
// Follow the controller profile ids from https://github.com/immersive-web/webxr-input-profiles.
nsTArray<nsString> GetInputSourceProfile(VRControllerType aType) {
nsTArray<nsString> profile;
nsString id;
switch(aType) {
case VRControllerType::HTCVive:
id.AssignLiteral("htc-vive");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-touchpad");
profile.AppendElement(id);
break;
case VRControllerType::HTCViveCosmos:
id.AssignLiteral("htc-vive-cosmos");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-thumbstick");
profile.AppendElement(id);
break;
case VRControllerType::HTCViveFocus:
id.AssignLiteral("htc-vive-focus");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-touchpad");
profile.AppendElement(id);
break;
case VRControllerType::HTCViveFocusPlus:
id.AssignLiteral("htc-vive-focus-plus");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-touchpad");
profile.AppendElement(id);
break;
case VRControllerType::MSMR:
id.AssignLiteral("microsoft-mixed-reality");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-touchpad-thumbstick");
profile.AppendElement(id);
break;
case VRControllerType::ValveIndex:
id.AssignLiteral("valve-index");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-touchpad-thumbstick");
profile.AppendElement(id);
break;
case VRControllerType::OculusGo:
id.AssignLiteral("oculus-go");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-touchpad");
profile.AppendElement(id);
break;
case VRControllerType::OculusTouch:
id.AssignLiteral("oculus-touch");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-thumbstick");
profile.AppendElement(id);
break;
case VRControllerType::OculusTouch2:
id.AssignLiteral("oculus-touch-v2");
profile.AppendElement(id);
id.AssignLiteral("oculus-touch");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-thumbstick");
profile.AppendElement(id);
break;
case VRControllerType::PicoGaze:
id.AssignLiteral("pico-gaze");
profile.AppendElement(id);
id.AssignLiteral("generic-button");
profile.AppendElement(id);
break;
case VRControllerType::PicoG2:
id.AssignLiteral("pico-g-v2");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-touchpad");
profile.AppendElement(id);
break;
case VRControllerType::PicoNeo2:
id.AssignLiteral("pico-neco-v2");
profile.AppendElement(id);
id.AssignLiteral("generic-trigger-squeeze-thumbstick");
profile.AppendElement(id);
break;
default:
NS_WARNING("Unsupported XR input source profile.\n");
break;
}
return profile;
}
XRInputSource::XRInputSource(nsISupports* aParent) : mParent(aParent) {}
JSObject* XRInputSource::WrapObject(JSContext* aCx,
@ -22,33 +110,94 @@ JSObject* XRInputSource::WrapObject(JSContext* aCx,
}
XRHandedness XRInputSource::Handedness() {
// TODO (Bug 1611310): Implement XRInputSource
return XRHandedness::None;
return mHandedness;
}
XRTargetRayMode XRInputSource::TargetRayMode() {
// TODO (Bug 1611310): Implement XRInputSource
return XRTargetRayMode::Tracked_pointer;
return mTargetRayMode;
}
XRSpace* XRInputSource::TargetRaySpace() {
// TODO (Bug 1611310): Implement XRInputSource
return nullptr;
return mTargetRaySpace;
}
XRSpace* XRInputSource::GetGripSpace() {
// TODO (Bug 1611310): Implement XRInputSource
return nullptr;
return mGripSpace;
}
void XRInputSource::GetProfiles(nsTArray<nsString>& aResult) {
// TODO (Bug 1611310): Implement XRInputSource
aResult = mProfiles;
}
Gamepad* XRInputSource::GetGamepad() {
// TODO (Bug 1611310): Implement XRInputSource
// TODO (Bug 1617023): Implement Gamepad for XRInputSource.
return nullptr;
}
void XRInputSource::Setup(XRSession* aSession, uint32_t aIndex) {
MOZ_ASSERT(aSession);
gfx::VRDisplayClient* displayClient = aSession->GetDisplayClient();
if (!displayClient) {
MOZ_ASSERT(displayClient);
return;
}
const gfx::VRDisplayInfo& displayInfo = displayClient->GetDisplayInfo();
const gfx::VRControllerState& controllerState = displayInfo.mControllerState[aIndex];
MOZ_ASSERT(controllerState.controllerName[0] != '\0');
mProfiles = GetInputSourceProfile(controllerState.type);
mHandedness = XRHandedness::None;
switch(controllerState.hand) {
case GamepadHand::_empty:
mHandedness = XRHandedness::None;
break;
case GamepadHand::Left:
mHandedness = XRHandedness::Left;
break;
case GamepadHand::Right:
mHandedness = XRHandedness::Right;
break;
default:
MOZ_ASSERT(false && "Unknown GamepadHand type.");
break;
}
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;
// We use weak pointers of poses in XRNativeOriginTracker to sync their data internally.
nativeOriginTargetRay = new XRNativeOriginTracker(&controllerState.targetRayPose);
nativeOriginGrip = new XRNativeOriginTracker(&controllerState.pose);
break;
case gfx::TargetRayMode::Screen:
mTargetRayMode = XRTargetRayMode::Screen;
break;
default:
MOZ_ASSERT(false && "Undefined TargetRayMode type.");
break;
}
mTargetRaySpace = new XRSpace(aSession->GetParentObject(), aSession, nativeOriginTargetRay);
mGripSpace = new XRSpace(aSession->GetParentObject(), aSession, nativeOriginGrip);
mIndex = aIndex;
}
void XRInputSource::SetGamepadIsConnected(bool aConnected) {
}
void XRInputSource::Update(XRSession* aSession) {
}
int32_t XRInputSource::GetIndex() {
return mIndex;
}
} // namespace dom
} // namespace mozilla

View File

@ -13,9 +13,14 @@
#include "gfxVR.h"
namespace mozilla {
namespace gfx {
class VRDisplayClient;
} // namespace gfx
namespace dom {
class Gamepad;
class XRSpace;
class XRSession;
class XRNativeOrigin;
enum class XRHandedness : uint8_t;
enum class XRTargetRayMode : uint8_t;
@ -38,11 +43,24 @@ class XRInputSource final : public nsWrapperCache {
XRSpace* GetGripSpace();
void GetProfiles(nsTArray<nsString>& aResult);
Gamepad* GetGamepad();
void Setup(XRSession* aSession, uint32_t aIndex);
void SetGamepadIsConnected(bool aConnected);
void Update(XRSession* aSession);
int32_t GetIndex();
protected:
virtual ~XRInputSource() = default;
nsCOMPtr<nsISupports> mParent;
private:
nsTArray<nsString> mProfiles;
XRHandedness mHandedness;
XRTargetRayMode mTargetRayMode;
RefPtr<XRSpace> mTargetRaySpace;
RefPtr<XRSpace> mGripSpace;
int32_t mIndex;
};
} // namespace dom

View File

@ -5,7 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/XRInputSourceArray.h"
#include "mozilla/dom/XRSpace.h"
#include "mozilla/dom/XRSession.h"
namespace mozilla {
namespace dom {
@ -27,6 +27,39 @@ JSObject* XRInputSourceArray::WrapObject(JSContext* aCx,
return XRInputSourceArray_Binding::Wrap(aCx, this, aGivenProto);
}
void XRInputSourceArray::Update(XRSession* aSession) {
MOZ_ASSERT(aSession);
gfx::VRDisplayClient* displayClient = aSession->GetDisplayClient();
if (!displayClient) {
return;
}
for (int32_t i = 0; i < gfx::kVRControllerMaxCount; ++i) {
const gfx::VRControllerState& controllerState = displayClient->GetDisplayInfo().mControllerState[i];
if (controllerState.controllerName[0] == '\0') {
break; // We would not have an empty slot before others.
}
bool found = false;
RefPtr<XRInputSource> inputSource = nullptr;
for (auto& input : mInputSources) {
if (input->GetIndex() == i) {
found = true;
inputSource = input;
break;
}
}
// Checking if it is added before.
if (!found) {
inputSource = new XRInputSource(mParent);
inputSource->Setup(aSession, i);
mInputSources.AppendElement(inputSource);
}
// If added, updating the current controller states.
inputSource->Update(aSession);
}
}
uint32_t XRInputSourceArray::Length() { return mInputSources.Length(); }
XRInputSource* XRInputSourceArray::IndexedGetter(uint32_t aIndex,

View File

@ -13,6 +13,9 @@
#include "gfxVR.h"
namespace mozilla {
namespace gfx {
struct VRControllerState;
}
namespace dom {
class XRInputSource;
@ -28,9 +31,12 @@ class XRInputSourceArray final : public nsISupports, public nsWrapperCache {
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// WebIDL Memberss
// WebIDL Members
XRInputSource* IndexedGetter(uint32_t aIndex, bool& aFound);
uint32_t Length();
void Setup(XRSession* aSession, RefPtr<gfx::VRDisplayClient> aDisplayClient);
void Update(XRSession* aSession);
void Clear();
protected:
virtual ~XRInputSourceArray() = default;

View File

@ -19,6 +19,10 @@ class XRNativeOrigin {
XRNativeOrigin() = default;
virtual gfx::PointDouble3D GetPosition() = 0;
virtual gfx::QuaternionDouble GetOrientation() {
static const gfx::QuaternionDouble orientation;
return orientation;
}
protected:
virtual ~XRNativeOrigin() = default;

View File

@ -0,0 +1,36 @@
/* -*- 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 "XRNativeOriginTracker.h"
namespace mozilla {
namespace dom {
XRNativeOriginTracker::XRNativeOriginTracker(const gfx::VRPose* aPose)
: mPose(aPose) {
MOZ_ASSERT(aPose);
}
gfx::PointDouble3D XRNativeOriginTracker::GetPosition() {
MOZ_ASSERT(mPose);
return gfx::PointDouble3D(mPose->position[0],
mPose->position[1],
mPose->position[2]);
}
gfx::QuaternionDouble XRNativeOriginTracker::GetOrientation() {
MOZ_ASSERT(mPose);
gfx::QuaternionDouble orientation(mPose->orientation[0],
mPose->orientation[1], mPose->orientation[2], mPose->orientation[3]);
// Quaternion was inverted for WebVR in XXXVRSession when handling controller poses.
// We need to re-invert it here again.
// TODO: Remove those extra inverts when WebVR support is disabled.
orientation.Invert();
return orientation;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,31 @@
/* -*- 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_XRNativeOriginTracker_h_
#define mozilla_dom_XRNativeOriginTracker_h_
#include "gfxVR.h"
namespace mozilla {
namespace dom {
class XRNativeOriginTracker : public XRNativeOrigin {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(XRNativeOriginTracker, override)
explicit XRNativeOriginTracker(const gfx::VRPose* aPose);
gfx::PointDouble3D GetPosition() override;
gfx::QuaternionDouble GetOrientation() override;
private:
~XRNativeOriginTracker() = default;
const gfx::VRPose* mPose;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_XRNativeOriginTracker_h_

View File

@ -5,7 +5,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "XRPermissionRequest.h"
#include "nsIGlobalObject.h"
#include "nsGlobalWindowInner.h"
#include "mozilla/Preferences.h"
#include "nsContentUtils.h"

View File

@ -108,13 +108,14 @@ XRSession::XRSession(
aClient->SessionStarted(this);
}
mActiveRenderState = new XRRenderState(aWindow, this);
// TODO (Bug 1611310): Implement XRInputSource and populate mInputSources
mInputSources = new XRInputSourceArray(aWindow);
mStartTimeStamp = TimeStamp::Now();
if (IsImmersive()) {
mDisplayPresentation =
mDisplayClient->BeginPresentation({}, gfx::kVRGroupContent);
}
// TODO: Handle XR input sources are no longer available cases.
// https://immersive-web.github.io/webxr/#dom-xrsession-inputsources
mInputSources = new XRInputSourceArray(aWindow);
}
XRSession::~XRSession() { MOZ_ASSERT(mShutdown); }

View File

@ -40,10 +40,8 @@ JSObject* XRSpace::WrapObject(JSContext* aCx,
XRSession* XRSpace::GetSession() const { return mSession; }
gfx::QuaternionDouble XRSpace::GetEffectiveOriginOrientation() const {
// Currently all of our native origin's will be axis aligned, so
// we can just return the offset, as if it were multiplied against
// an identity quaternion.
return mOriginOffsetOrientation;
gfx::QuaternionDouble orientation = mNativeOrigin->GetOrientation() * mOriginOffsetOrientation;
return orientation;
}
gfx::PointDouble3D XRSpace::GetEffectiveOriginPosition() const {

View File

@ -42,6 +42,7 @@ UNIFIED_SOURCES = [
'XRNativeOriginFixed.cpp',
'XRNativeOriginLocal.cpp',
'XRNativeOriginLocalFloor.cpp',
'XRNativeOriginTracker.cpp',
'XRNativeOriginViewer.cpp',
'XRPermissionRequest.cpp',
'XRPose.cpp',

View File

@ -47,8 +47,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.9"
static const int32_t kVRExternalVersion = 16;
#define SHMEM_VERSION "0.0.10"
static const int32_t kVRExternalVersion = 17;
// We assign VR presentations to groups with a bitmask.
// Currently, we will only display either content or chrome.
@ -63,7 +63,6 @@ static const uint32_t kVRGroupAll = 0xffffffff;
static const int kVRDisplayNameMaxLen = 256;
static const int kVRControllerNameMaxLen = 256;
static const int kProfileNameListMaxLen = 256;
static const int kVRControllerMaxCount = 16;
static const int kVRControllerMaxButtons = 64;
static const int kVRControllerMaxAxis = 16;
@ -120,9 +119,9 @@ enum class ControllerCapabilityFlags : uint16_t {
*/
Cap_LinearAcceleration = 1 << 4,
/**
* Cap_GripSpacePosition is set if the Gamepad has a grip space position.
* Cap_TargetRaySpacePosition is set if the Gamepad has a target ray space position.
*/
Cap_GripSpacePosition = 1 << 5,
Cap_TargetRaySpacePosition = 1 << 5,
/**
* Cap_All used for validity checking during IPC serialization
*/
@ -371,11 +370,6 @@ struct VRControllerState {
// https://immersive-web.github.io/webxr/#enumdef-xrtargetraymode
TargetRayMode targetRayMode;
// Space-delimited list of input profile names, in decending order
// of specificity.
// https://immersive-web.github.io/webxr/#dom-xrinputsource-profiles
char profiles[kProfileNameListMaxLen];
// https://immersive-web.github.io/webxr-gamepads-module/#enumdef-gamepadmappingtype
GamepadMappingType mappingType;
@ -416,14 +410,14 @@ struct VRControllerState {
#endif
// When Cap_Position is set in flags, pose corresponds
// to the controllers' pose in target ray space:
// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace
VRPose pose;
// When Cap_GripSpacePosition is set in flags, gripPose corresponds
// to the controllers' pose in grip space:
// https://immersive-web.github.io/webxr/#dom-xrinputsource-gripspace
VRPose gripPose;
VRPose pose;
// When Cap_TargetRaySpacePosition is set in flags, targetRayPose corresponds
// to the controllers' pose in target ray space:
// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace
VRPose targetRayPose;
bool isPositionValid;
bool isOrientationValid;

View File

@ -1305,6 +1305,7 @@ void OculusSession::UpdateControllerPose(VRSystemState& aState,
} else {
controllerState.isPositionValid = false;
}
controllerState.targetRayPose = controllerState.pose;
}
}
}

View File

@ -1113,6 +1113,24 @@ void OpenVRSession::UpdateControllerPoses(VRSystemState& aState) {
controllerState.pose.linearAcceleration[1] = 0.0f;
controllerState.pose.linearAcceleration[2] = 0.0f;
controllerState.isPositionValid = true;
// Calculate its target ray space by shifting degrees in x-axis
// for ergonomic.
const float kPointerAngleDegrees = -0.698; // 40 degrees.
gfx::Matrix4x4 rayMtx(m);
rayMtx.RotateX(kPointerAngleDegrees);
gfx::Quaternion rayRot;
rayRot.SetFromRotationMatrix(rayMtx);
rayRot.Invert();
controllerState.targetRayPose = controllerState.pose;
controllerState.targetRayPose.orientation[0] = rayRot.x;
controllerState.targetRayPose.orientation[1] = rayRot.y;
controllerState.targetRayPose.orientation[2] = rayRot.z;
controllerState.targetRayPose.orientation[3] = rayRot.w;
controllerState.targetRayPose.position[0] = rayMtx._41;
controllerState.targetRayPose.position[1] = rayMtx._42;
controllerState.targetRayPose.position[2] = rayMtx._43;
}
}
}