diff --git a/dom/vr/VRDisplay.cpp b/dom/vr/VRDisplay.cpp index d5ab29b2724e..686bf054272a 100644 --- a/dom/vr/VRDisplay.cpp +++ b/dom/vr/VRDisplay.cpp @@ -285,7 +285,7 @@ VRPose::GetPosition(JSContext* aCx, JS::MutableHandle aRetval, ErrorResult& aRv) { - SetFloat32Array(aCx, aRetval, mPosition, mVRState.position, 3, + SetFloat32Array(aCx, aRetval, mPosition, mVRState.pose.position, 3, !mPosition && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position), aRv); } @@ -295,7 +295,7 @@ VRPose::GetLinearVelocity(JSContext* aCx, JS::MutableHandle aRetval, ErrorResult& aRv) { - SetFloat32Array(aCx, aRetval, mLinearVelocity, mVRState.linearVelocity, 3, + SetFloat32Array(aCx, aRetval, mLinearVelocity, mVRState.pose.linearVelocity, 3, !mLinearVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position), aRv); } @@ -305,7 +305,7 @@ VRPose::GetLinearAcceleration(JSContext* aCx, JS::MutableHandle aRetval, ErrorResult& aRv) { - SetFloat32Array(aCx, aRetval, mLinearAcceleration, mVRState.linearAcceleration, 3, + SetFloat32Array(aCx, aRetval, mLinearAcceleration, mVRState.pose.linearAcceleration, 3, !mLinearAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration), aRv); @@ -316,7 +316,7 @@ VRPose::GetOrientation(JSContext* aCx, JS::MutableHandle aRetval, ErrorResult& aRv) { - SetFloat32Array(aCx, aRetval, mOrientation, mVRState.orientation, 4, + SetFloat32Array(aCx, aRetval, mOrientation, mVRState.pose.orientation, 4, !mOrientation && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation), aRv); } @@ -326,7 +326,7 @@ VRPose::GetAngularVelocity(JSContext* aCx, JS::MutableHandle aRetval, ErrorResult& aRv) { - SetFloat32Array(aCx, aRetval, mAngularVelocity, mVRState.angularVelocity, 3, + SetFloat32Array(aCx, aRetval, mAngularVelocity, mVRState.pose.angularVelocity, 3, !mAngularVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation), aRv); } @@ -336,7 +336,7 @@ VRPose::GetAngularAcceleration(JSContext* aCx, JS::MutableHandle aRetval, ErrorResult& aRv) { - SetFloat32Array(aCx, aRetval, mAngularAcceleration, mVRState.angularAcceleration, 3, + SetFloat32Array(aCx, aRetval, mAngularAcceleration, mVRState.pose.angularAcceleration, 3, !mAngularAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration), aRv); } diff --git a/dom/vr/VRServiceTest.cpp b/dom/vr/VRServiceTest.cpp index a654468a5457..2f991d6a8d3d 100644 --- a/dom/vr/VRServiceTest.cpp +++ b/dom/vr/VRServiceTest.cpp @@ -95,50 +95,50 @@ VRMockDisplay::SetPose(const Nullable& aPosition, const Float32Array& value = aOrientation.Value(); value.ComputeLengthAndData(); MOZ_ASSERT(value.Length() == 4); - mSensorState.orientation[0] = value.Data()[0]; - mSensorState.orientation[1] = value.Data()[1]; - mSensorState.orientation[2] = value.Data()[2]; - mSensorState.orientation[3] = value.Data()[3]; + mSensorState.pose.orientation[0] = value.Data()[0]; + mSensorState.pose.orientation[1] = value.Data()[1]; + mSensorState.pose.orientation[2] = value.Data()[2]; + mSensorState.pose.orientation[3] = value.Data()[3]; } if (!aAngularVelocity.IsNull()) { const Float32Array& value = aAngularVelocity.Value(); value.ComputeLengthAndData(); MOZ_ASSERT(value.Length() == 3); - mSensorState.angularVelocity[0] = value.Data()[0]; - mSensorState.angularVelocity[1] = value.Data()[1]; - mSensorState.angularVelocity[2] = value.Data()[2]; + mSensorState.pose.angularVelocity[0] = value.Data()[0]; + mSensorState.pose.angularVelocity[1] = value.Data()[1]; + mSensorState.pose.angularVelocity[2] = value.Data()[2]; } if (!aAngularAcceleration.IsNull()) { const Float32Array& value = aAngularAcceleration.Value(); value.ComputeLengthAndData(); MOZ_ASSERT(value.Length() == 3); - mSensorState.angularAcceleration[0] = value.Data()[0]; - mSensorState.angularAcceleration[1] = value.Data()[1]; - mSensorState.angularAcceleration[2] = value.Data()[2]; + mSensorState.pose.angularAcceleration[0] = value.Data()[0]; + mSensorState.pose.angularAcceleration[1] = value.Data()[1]; + mSensorState.pose.angularAcceleration[2] = value.Data()[2]; } if (!aPosition.IsNull()) { const Float32Array& value = aPosition.Value(); value.ComputeLengthAndData(); MOZ_ASSERT(value.Length() == 3); - mSensorState.position[0] = value.Data()[0]; - mSensorState.position[1] = value.Data()[1]; - mSensorState.position[2] = value.Data()[2]; + mSensorState.pose.position[0] = value.Data()[0]; + mSensorState.pose.position[1] = value.Data()[1]; + mSensorState.pose.position[2] = value.Data()[2]; } if (!aLinearVelocity.IsNull()) { const Float32Array& value = aLinearVelocity.Value(); value.ComputeLengthAndData(); MOZ_ASSERT(value.Length() == 3); - mSensorState.linearVelocity[0] = value.Data()[0]; - mSensorState.linearVelocity[1] = value.Data()[1]; - mSensorState.linearVelocity[2] = value.Data()[2]; + mSensorState.pose.linearVelocity[0] = value.Data()[0]; + mSensorState.pose.linearVelocity[1] = value.Data()[1]; + mSensorState.pose.linearVelocity[2] = value.Data()[2]; } if (!aLinearAcceleration.IsNull()) { const Float32Array& value = aLinearAcceleration.Value(); value.ComputeLengthAndData(); MOZ_ASSERT(value.Length() == 3); - mSensorState.linearAcceleration[0] = value.Data()[0]; - mSensorState.linearAcceleration[1] = value.Data()[1]; - mSensorState.linearAcceleration[2] = value.Data()[2]; + mSensorState.pose.linearAcceleration[0] = value.Data()[0]; + mSensorState.pose.linearAcceleration[1] = value.Data()[1]; + mSensorState.pose.linearAcceleration[2] = value.Data()[2]; } } diff --git a/gfx/vr/VRDisplayClient.cpp b/gfx/vr/VRDisplayClient.cpp index 38e10c22aa2e..58a5cf5ab32c 100644 --- a/gfx/vr/VRDisplayClient.cpp +++ b/gfx/vr/VRDisplayClient.cpp @@ -9,7 +9,10 @@ #include "prlink.h" #include "prenv.h" #include "gfxPrefs.h" +#include "nsIGlobalObject.h" +#include "nsRefPtrHashtable.h" #include "nsString.h" +#include "mozilla/dom/GamepadManager.h" #include "mozilla/Preferences.h" #include "mozilla/Unused.h" #include "nsServiceManagerUtils.h" @@ -34,6 +37,7 @@ VRDisplayClient::VRDisplayClient(const VRDisplayInfo& aDisplayInfo) , mPresentationCount(0) , mLastEventFrameId(0) , mLastPresentingGeneration(0) + , mLastEventControllerState{} { MOZ_COUNT_CTOR(VRDisplayClient); } @@ -128,6 +132,140 @@ VRDisplayClient::FireEvents() mLastEventFrameId = mDisplayInfo.mFrameId; vm->RunFrameRequestCallbacks(); } + + FireGamepadEvents(); +} + +void +VRDisplayClient::FireGamepadEvents() +{ + RefPtr gamepadManager(dom::GamepadManager::GetService()); + if (!gamepadManager) { + return; + } + for (int stateIndex=0; stateIndex < kVRControllerMaxCount; stateIndex++) { + const VRControllerState& state = mDisplayInfo.mControllerState[stateIndex]; + const VRControllerState& lastState = mLastEventControllerState[stateIndex]; + uint32_t gamepadId = mDisplayInfo.mDisplayID * kVRControllerMaxCount + stateIndex; + bool bIsNew = false; + + // Send events to notify that controllers are removed + if (state.controllerName[0] == '\0') { + // Controller is not present + if (lastState.controllerName[0] != '\0') { + // Controller has been removed + dom::GamepadRemoved info; + dom::GamepadChangeEventBody body(info); + dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body); + gamepadManager->Update(event); + } + // Do not process any further events for removed controllers + continue; + } + + // Send events to notify that new controllers are added + if (lastState.controllerName[0] == '\0') { + dom::GamepadAdded info(NS_ConvertUTF8toUTF16(state.controllerName), + dom::GamepadMappingType::_empty, + state.hand, + mDisplayInfo.mDisplayID, + state.numButtons, + state.numAxes, + state.numHaptics); + dom::GamepadChangeEventBody body(info); + dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body); + gamepadManager->Update(event); + bIsNew = true; + } + + // Send events for handedness changes + if (state.hand != lastState.hand) { + dom::GamepadHandInformation info(state.hand); + dom::GamepadChangeEventBody body(info); + dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body); + gamepadManager->Update(event); + } + + // Send events for axis value changes + for (uint32_t axisIndex = 0; axisIndex < state.numAxes; axisIndex++) { + if (state.axisValue[axisIndex] != lastState.axisValue[axisIndex]) { + dom::GamepadAxisInformation info(axisIndex, state.axisValue[axisIndex]); + dom::GamepadChangeEventBody body(info); + dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body); + gamepadManager->Update(event); + } + } + + // Send events for trigger, touch, and button value changes + if (!bIsNew) { + // When a new controller is added, we do not emit button events for + // the initial state of the inputs. + for (uint32_t buttonIndex = 0; buttonIndex < state.numButtons; buttonIndex++) { + bool bPressed = (state.buttonPressed & (1ULL << buttonIndex)) != 0; + bool bTouched = (state.buttonTouched & (1ULL << buttonIndex)) != 0; + bool bLastPressed = (lastState.buttonPressed & (1ULL << buttonIndex)) != 0; + bool bLastTouched = (lastState.buttonTouched & (1ULL << buttonIndex)) != 0; + + if (state.triggerValue[buttonIndex] != lastState.triggerValue[buttonIndex] || + bPressed != bLastPressed || + bTouched != bLastTouched) { + dom::GamepadButtonInformation info(buttonIndex, state.triggerValue[buttonIndex], bPressed, bTouched); + dom::GamepadChangeEventBody body(info); + dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body); + gamepadManager->Update(event); + } + } + } + + // Send events for pose changes + // Note that VRPose is asserted to be a POD type so memcmp is safe + if (state.flags != lastState.flags || + state.isPositionValid != lastState.isPositionValid || + state.isOrientationValid != lastState.isOrientationValid || + memcmp(&state.pose, &lastState.pose, sizeof(VRPose)) != 0) { + + // Convert pose to GamepadPoseState + dom::GamepadPoseState poseState; + poseState.Clear(); + poseState.flags = state.flags; + + // Orientation values + poseState.isOrientationValid = state.isOrientationValid; + poseState.orientation[0] = state.pose.orientation[0]; + poseState.orientation[1] = state.pose.orientation[1]; + poseState.orientation[2] = state.pose.orientation[2]; + poseState.orientation[3] = state.pose.orientation[3]; + poseState.angularVelocity[0] = state.pose.angularVelocity[0]; + poseState.angularVelocity[1] = state.pose.angularVelocity[1]; + poseState.angularVelocity[2] = state.pose.angularVelocity[2]; + poseState.angularAcceleration[0] = state.pose.angularAcceleration[0]; + poseState.angularAcceleration[1] = state.pose.angularAcceleration[1]; + poseState.angularAcceleration[2] = state.pose.angularAcceleration[2]; + + // Position values + poseState.isPositionValid = state.isPositionValid; + poseState.position[0] = state.pose.position[0]; + poseState.position[1] = state.pose.position[1]; + poseState.position[2] = state.pose.position[2]; + poseState.linearVelocity[0] = state.pose.linearVelocity[0]; + poseState.linearVelocity[1] = state.pose.linearVelocity[1]; + poseState.linearVelocity[2] = state.pose.linearVelocity[2]; + poseState.linearAcceleration[0] = state.pose.linearAcceleration[0]; + poseState.linearAcceleration[1] = state.pose.linearAcceleration[1]; + poseState.linearAcceleration[2] = state.pose.linearAcceleration[2]; + + // Send the event + dom::GamepadPoseInformation info(poseState); + dom::GamepadChangeEventBody body(info); + dom::GamepadChangeEvent event(gamepadId, dom::GamepadServiceType::VR, body); + gamepadManager->Update(event); + } + } + + // Note that VRControllerState is asserted to be a POD type and memcpy is safe. + memcpy(mLastEventControllerState, + mDisplayInfo.mControllerState, + sizeof(VRControllerState) * kVRControllerMaxCount); } VRHMDSensorState diff --git a/gfx/vr/VRDisplayClient.h b/gfx/vr/VRDisplayClient.h index 7609c341e595..aeb12e309ad6 100644 --- a/gfx/vr/VRDisplayClient.h +++ b/gfx/vr/VRDisplayClient.h @@ -51,6 +51,7 @@ protected: virtual ~VRDisplayClient(); void FireEvents(); + void FireGamepadEvents(); VRDisplayInfo mDisplayInfo; @@ -60,6 +61,10 @@ protected: int mPresentationCount; uint64_t mLastEventFrameId; uint32_t mLastPresentingGeneration; + + // Difference between mDisplayInfo.mControllerState and mLastEventControllerState + // determines what gamepad events to fire when updated. + VRControllerState mLastEventControllerState[kVRControllerMaxCount]; private: VRSubmitFrameResultInfo mSubmitFrameResult; }; diff --git a/gfx/vr/VRDisplayHost.cpp b/gfx/vr/VRDisplayHost.cpp index af9a37a76421..ec59468de052 100644 --- a/gfx/vr/VRDisplayHost.cpp +++ b/gfx/vr/VRDisplayHost.cpp @@ -352,7 +352,7 @@ VRControllerHost::VRControllerHost(VRDeviceType aType, dom::GamepadHand aHand, { MOZ_COUNT_CTOR(VRControllerHost); mControllerInfo.mType = aType; - mControllerInfo.mControllerState.mHand = aHand; + mControllerInfo.mControllerState.hand = aHand; mControllerInfo.mMappingType = dom::GamepadMappingType::_empty; mControllerInfo.mDisplayID = aDisplayID; mControllerInfo.mControllerID = VRSystemManager::AllocateControllerID(); @@ -372,25 +372,25 @@ VRControllerHost::GetControllerInfo() const void VRControllerHost::SetButtonPressed(uint64_t aBit) { - mControllerInfo.mControllerState.mButtonPressed = aBit; + mControllerInfo.mControllerState.buttonPressed = aBit; } uint64_t VRControllerHost::GetButtonPressed() { - return mControllerInfo.mControllerState.mButtonPressed; + return mControllerInfo.mControllerState.buttonPressed; } void VRControllerHost::SetButtonTouched(uint64_t aBit) { - mControllerInfo.mControllerState.mButtonTouched = aBit; + mControllerInfo.mControllerState.buttonTouched = aBit; } uint64_t VRControllerHost::GetButtonTouched() { - return mControllerInfo.mControllerState.mButtonTouched; + return mControllerInfo.mControllerState.buttonTouched; } void @@ -408,7 +408,7 @@ VRControllerHost::GetPose() dom::GamepadHand VRControllerHost::GetHand() { - return mControllerInfo.mControllerState.mHand; + return mControllerInfo.mControllerState.hand; } void diff --git a/gfx/vr/external_api/moz_external_vr.h b/gfx/vr/external_api/moz_external_vr.h index 3f6eaf3f6924..ebfd7f17ade8 100644 --- a/gfx/vr/external_api/moz_external_vr.h +++ b/gfx/vr/external_api/moz_external_vr.h @@ -24,11 +24,12 @@ namespace mozilla { #ifdef MOZILLA_INTERNAL_API namespace dom { enum class GamepadHand : uint8_t; + enum class GamepadCapabilityFlags : uint16_t; } #endif // MOZILLA_INTERNAL_API namespace gfx { -static const int32_t kVRExternalVersion = 0; +static const int32_t kVRExternalVersion = 1; // We assign VR presentations to groups with a bitmask. // Currently, we will only display either content or chrome. @@ -44,7 +45,7 @@ static const uint32_t kVRGroupAll = 0xffffffff; static const int kVRDisplayNameMaxLen = 256; static const int kVRControllerNameMaxLen = 256; static const int kVRControllerMaxCount = 16; -static const int kVRControllerMaxTriggers = 16; +static const int kVRControllerMaxButtons = 64; static const int kVRControllerMaxAxis = 16; static const int kVRLayerMaxCount = 8; @@ -82,6 +83,32 @@ enum class ControllerHand : uint8_t { EndGuard_ }; +enum class ControllerCapabilityFlags : uint16_t { + Cap_None = 0, + /** + * Cap_Position is set if the Gamepad is capable of tracking its position. + */ + Cap_Position = 1 << 1, + /** + * Cap_Orientation is set if the Gamepad is capable of tracking its orientation. + */ + Cap_Orientation = 1 << 2, + /** + * Cap_AngularAcceleration is set if the Gamepad is capable of tracking its + * angular acceleration. + */ + Cap_AngularAcceleration = 1 << 3, + /** + * Cap_LinearAcceleration is set if the Gamepad is capable of tracking its + * linear acceleration. + */ + Cap_LinearAcceleration = 1 << 4, + /** + * Cap_All used for validity checking during IPC serialization + */ + Cap_All = (1 << 5) - 1 +}; + #endif // ifndef MOZILLA_INTERNAL_API enum class VRDisplayCapabilityFlags : uint16_t { @@ -140,20 +167,25 @@ enum class VRDisplayCapabilityFlags : uint16_t { MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags) #endif // MOZILLA_INTERNAL_API +struct VRPose +{ + float orientation[4]; + float position[3]; + float angularVelocity[3]; + float angularAcceleration[3]; + float linearVelocity[3]; + float linearAcceleration[3]; +}; + struct VRHMDSensorState { uint64_t inputFrameID; double timestamp; VRDisplayCapabilityFlags flags; // These members will only change with inputFrameID: - float orientation[4]; - float position[3]; + VRPose pose; float leftViewMatrix[16]; float rightViewMatrix[16]; - float angularVelocity[3]; - float angularAcceleration[3]; - float linearVelocity[3]; - float linearAcceleration[3]; #ifdef MOZILLA_INTERNAL_API @@ -248,22 +280,30 @@ struct VRDisplayState struct VRControllerState { - char mControllerName[kVRControllerNameMaxLen]; + char controllerName[kVRControllerNameMaxLen]; #ifdef MOZILLA_INTERNAL_API - dom::GamepadHand mHand; + dom::GamepadHand hand; #else - ControllerHand mHand; + ControllerHand hand; #endif - uint32_t mNumButtons; - uint32_t mNumAxes; - uint32_t mNumTriggers; - uint32_t mNumHaptics; + uint32_t numButtons; + uint32_t numAxes; + uint32_t numHaptics; // The current button pressed bit of button mask. - uint64_t mButtonPressed; + uint64_t buttonPressed; // The current button touched bit of button mask. - uint64_t mButtonTouched; - float mTriggerValue[kVRControllerMaxTriggers]; - float mAxisValue[kVRControllerMaxAxis]; + uint64_t buttonTouched; + float triggerValue[kVRControllerMaxButtons]; + float axisValue[kVRControllerMaxAxis]; + +#ifdef MOZILLA_INTERNAL_API + dom::GamepadCapabilityFlags flags; +#else + ControllerCapabilityFlags flags; +#endif + VRPose pose; + bool isPositionValid; + bool isOrientationValid; }; struct VRLayerEyeRect diff --git a/gfx/vr/gfxVR.cpp b/gfx/vr/gfxVR.cpp index bc38ed5de897..789b87073d51 100644 --- a/gfx/vr/gfxVR.cpp +++ b/gfx/vr/gfxVR.cpp @@ -189,10 +189,10 @@ VRHMDSensorState::CalcViewMatrices(const gfx::Matrix4x4* aHeadToEyeTransforms) gfx::Matrix4x4 matHead; if (flags & VRDisplayCapabilityFlags::Cap_Orientation) { - matHead.SetRotationFromQuaternion(gfx::Quaternion(orientation[0], orientation[1], - orientation[2], orientation[3])); + matHead.SetRotationFromQuaternion(gfx::Quaternion(pose.orientation[0], pose.orientation[1], + pose.orientation[2], pose.orientation[3])); } - matHead.PreTranslate(-position[0], -position[1], -position[2]); + matHead.PreTranslate(-pose.position[0], -pose.position[1], -pose.position[2]); gfx::Matrix4x4 matView = matHead * aHeadToEyeTransforms[VRDisplayState::Eye_Left]; matView.Normalize(); diff --git a/gfx/vr/gfxVR.h b/gfx/vr/gfxVR.h index 659a9f7b2aad..045656f58341 100644 --- a/gfx/vr/gfxVR.h +++ b/gfx/vr/gfxVR.h @@ -60,6 +60,7 @@ struct VRDisplayInfo uint32_t mGroupMask; uint64_t mFrameId; VRDisplayState mDisplayState; + VRControllerState mControllerState[kVRControllerMaxCount]; VRHMDSensorState mLastSensorState[kVRMaxLatencyFrames]; const VRHMDSensorState& GetSensorState() const @@ -89,10 +90,11 @@ struct VRDisplayInfo return false; } } - // Note that mDisplayState is asserted to be a POD type, so memcmp is safe + // Note that mDisplayState and mControllerState are asserted to be POD types, so memcmp is safe return mType == other.mType && mDisplayID == other.mDisplayID && memcmp(&mDisplayState, &other.mDisplayState, sizeof(VRDisplayState)) == 0 && + memcmp(mControllerState, other.mControllerState, sizeof(VRControllerState) * kVRControllerMaxCount) == 0 && mPresentingGroups == other.mPresentingGroups && mGroupMask == other.mGroupMask && mFrameId == other.mFrameId; @@ -123,13 +125,13 @@ struct VRControllerInfo { VRDeviceType GetType() const { return mType; } uint32_t GetControllerID() const { return mControllerID; } - const char* GetControllerName() const { return mControllerState.mControllerName; } + const char* GetControllerName() const { return mControllerState.controllerName; } dom::GamepadMappingType GetMappingType() const { return mMappingType; } uint32_t GetDisplayID() const { return mDisplayID; } - dom::GamepadHand GetHand() const { return mControllerState.mHand; } - uint32_t GetNumButtons() const { return mControllerState.mNumButtons; } - uint32_t GetNumAxes() const { return mControllerState.mNumAxes; } - uint32_t GetNumHaptics() const { return mControllerState.mNumHaptics; } + dom::GamepadHand GetHand() const { return mControllerState.hand; } + uint32_t GetNumButtons() const { return mControllerState.numButtons; } + uint32_t GetNumAxes() const { return mControllerState.numAxes; } + uint32_t GetNumHaptics() const { return mControllerState.numHaptics; } uint32_t mControllerID; VRDeviceType mType; @@ -137,15 +139,12 @@ struct VRControllerInfo uint32_t mDisplayID; VRControllerState mControllerState; bool operator==(const VRControllerInfo& other) const { + // Note that mControllerState is asserted to be a POD type, so memcmp is safe return mType == other.mType && mControllerID == other.mControllerID && - strncmp(mControllerState.mControllerName, other.mControllerState.mControllerName, kVRControllerNameMaxLen) == 0 && + memcmp(&mControllerState, &other.mControllerState, sizeof(VRControllerState)) == 0 && mMappingType == other.mMappingType && - mDisplayID == other.mDisplayID && - mControllerState.mHand == other.mControllerState.mHand && - mControllerState.mNumButtons == other.mControllerState.mNumButtons && - mControllerState.mNumAxes == other.mControllerState.mNumAxes && - mControllerState.mNumHaptics == other.mControllerState.mNumHaptics; + mDisplayID == other.mDisplayID; } bool operator!=(const VRControllerInfo& other) const { diff --git a/gfx/vr/gfxVRExternal.cpp b/gfx/vr/gfxVRExternal.cpp index 8429e9ff0da0..6448203ada6e 100644 --- a/gfx/vr/gfxVRExternal.cpp +++ b/gfx/vr/gfxVRExternal.cpp @@ -52,8 +52,6 @@ using namespace mozilla::gfx::impl; using namespace mozilla::layers; using namespace mozilla::dom; -static const uint32_t kNumExternalHaptcs = 1; - int VRDisplayExternal::sPushIndex = 0; VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState) @@ -65,7 +63,7 @@ VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState) mDisplayInfo.mDisplayState = aDisplayState; // default to an identity quaternion - mLastSensorState.orientation[3] = 1.0f; + mLastSensorState.pose.orientation[3] = 1.0f; } VRDisplayExternal::~VRDisplayExternal() @@ -78,8 +76,6 @@ void VRDisplayExternal::Destroy() { StopPresentation(); - - // TODO - Implement } void @@ -93,7 +89,7 @@ VRDisplayExternal::Refresh() VRManager *vm = VRManager::Get(); VRSystemManagerExternal* manager = vm->GetExternalManager(); - manager->PullState(&mDisplayInfo.mDisplayState, &mLastSensorState); + manager->PullState(&mDisplayInfo.mDisplayState, &mLastSensorState, mDisplayInfo.mControllerState); } VRHMDSensorState @@ -238,7 +234,7 @@ VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture, VRDisplayState displayState; memset(&displayState, 0, sizeof(VRDisplayState)); while (displayState.mLastSubmittedFrameId < aFrameId) { - if (manager->PullState(&displayState, &mLastSensorState)) { + if (manager->PullState(&displayState, &mLastSensorState, mDisplayInfo.mControllerState)) { if (!displayState.mIsConnected) { // Service has shut down or hardware has been disconnected return false; @@ -254,26 +250,6 @@ VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture, return displayState.mLastSubmittedFrameSuccessful; } -VRControllerExternal::VRControllerExternal(dom::GamepadHand aHand, uint32_t aDisplayID, - uint32_t aNumButtons, uint32_t aNumTriggers, - uint32_t aNumAxes, const nsCString& aId) - : VRControllerHost(VRDeviceType::External, aHand, aDisplayID) -{ - MOZ_COUNT_CTOR_INHERITED(VRControllerExternal, VRControllerHost); - - VRControllerState& state = mControllerInfo.mControllerState; - strncpy(state.mControllerName, aId.BeginReading(), kVRControllerNameMaxLen); - state.mNumButtons = aNumButtons; - state.mNumAxes = aNumAxes; - state.mNumTriggers = aNumTriggers; - state.mNumHaptics = kNumExternalHaptcs; -} - -VRControllerExternal::~VRControllerExternal() -{ - MOZ_COUNT_DTOR_INHERITED(VRControllerExternal, VRControllerHost); -} - VRSystemManagerExternal::VRSystemManagerExternal(VRExternalShmem* aAPIShmem /* = nullptr*/) : mExternalShmem(aAPIShmem) #if !defined(MOZ_WIDGET_ANDROID) @@ -458,7 +434,6 @@ VRSystemManagerExternal::Shutdown() if (mDisplay) { mDisplay = nullptr; } - RemoveControllers(); CloseShmem(); #if defined(MOZ_WIDGET_ANDROID) mDoShutdown = false; @@ -537,12 +512,6 @@ VRSystemManagerExternal::GetIsPresenting() return false; } -void -VRSystemManagerExternal::HandleInput() -{ - // TODO - Implement This! -} - void VRSystemManagerExternal::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex, @@ -562,31 +531,40 @@ VRSystemManagerExternal::StopVibrateHaptic(uint32_t aControllerIdx) void VRSystemManagerExternal::GetControllers(nsTArray>& aControllerResult) { + // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal aControllerResult.Clear(); - for (uint32_t i = 0; i < mExternalController.Length(); ++i) { - aControllerResult.AppendElement(mExternalController[i]); - } } void VRSystemManagerExternal::ScanForControllers() { - // TODO - Implement this + // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal + if (mDisplay) { + mDisplay->Refresh(); + } + return; +} + +void +VRSystemManagerExternal::HandleInput() +{ + // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal + if (mDisplay) { + mDisplay->Refresh(); + } + return; } void VRSystemManagerExternal::RemoveControllers() { - // The controller count is changed, removing the existing gamepads first. - for (uint32_t i = 0; i < mExternalController.Length(); ++i) { - RemoveGamepad(i); - } - mExternalController.Clear(); - mControllerCount = 0; + // Controller updates are handled in VRDisplayClient for VRSystemManagerExternal } bool -VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, VRHMDSensorState* aSensorState /* = nullptr */) +VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, + VRHMDSensorState* aSensorState /* = nullptr */, + VRControllerState* aControllerState /* = nullptr */) { bool success = false; MOZ_ASSERT(mExternalShmem); @@ -597,6 +575,9 @@ VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, VRHMDSensorSta if (aSensorState) { memcpy(aSensorState, (void*)&(mExternalShmem->state.sensorState), sizeof(VRHMDSensorState)); } + if (aControllerState) { + memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount); + } success = mExternalShmem->state.enumerationCompleted; pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex)); mDoShutdown = aDisplayState->shutdown; @@ -609,6 +590,9 @@ VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState, VRHMDSensorSta if (aSensorState) { memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState)); } + if (aControllerState) { + memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount); + } success = true; } #endif // defined(MOZ_WIDGET_ANDROID) diff --git a/gfx/vr/gfxVRExternal.h b/gfx/vr/gfxVRExternal.h index 227593ef17ca..7329a6295340 100644 --- a/gfx/vr/gfxVRExternal.h +++ b/gfx/vr/gfxVRExternal.h @@ -46,6 +46,7 @@ protected: public: explicit VRDisplayExternal(const VRDisplayState& aDisplayState); void Refresh(); + const VRControllerState& GetLastControllerState(uint32_t aStateIndex) const; protected: virtual ~VRDisplayExternal(); void Destroy(); @@ -60,17 +61,6 @@ private: VRHMDSensorState mLastSensorState; }; -class VRControllerExternal : public VRControllerHost -{ -public: - explicit VRControllerExternal(dom::GamepadHand aHand, uint32_t aDisplayID, uint32_t aNumButtons, - uint32_t aNumTriggers, uint32_t aNumAxes, - const nsCString& aId); - -protected: - virtual ~VRControllerExternal(); -}; - } // namespace impl class VRSystemManagerExternal : public VRSystemManager @@ -96,7 +86,9 @@ public: double aDuration, const VRManagerPromise& aPromise) override; virtual void StopVibrateHaptic(uint32_t aControllerIdx) override; - bool PullState(VRDisplayState* aDisplayState, VRHMDSensorState* aSensorState = nullptr); + bool PullState(VRDisplayState* aDisplayState, + VRHMDSensorState* aSensorState = nullptr, + VRControllerState* aControllerState = nullptr); void PushState(VRBrowserState* aBrowserState, const bool aNotifyCond = false); protected: @@ -106,7 +98,6 @@ protected: private: // there can only be one RefPtr mDisplay; - nsTArray> mExternalController; #if defined(XP_MACOSX) int mShmemFD; #elif defined(XP_WIN) diff --git a/gfx/vr/gfxVROSVR.cpp b/gfx/vr/gfxVROSVR.cpp index 76fb03e2f7fe..6af82362dd25 100644 --- a/gfx/vr/gfxVROSVR.cpp +++ b/gfx/vr/gfxVROSVR.cpp @@ -317,22 +317,22 @@ VRDisplayOSVR::GetSensorState() if (ret == OSVR_RETURN_SUCCESS) { result.flags |= VRDisplayCapabilityFlags::Cap_Orientation; - result.orientation[0] = orientation.data[1]; - result.orientation[1] = orientation.data[2]; - result.orientation[2] = orientation.data[3]; - result.orientation[3] = orientation.data[0]; + result.pose.orientation[0] = orientation.data[1]; + result.pose.orientation[1] = orientation.data[2]; + result.pose.orientation[2] = orientation.data[3]; + result.pose.orientation[3] = orientation.data[0]; } else { // default to an identity quaternion - result.orientation[3] = 1.0f; + result.pose.orientation[3] = 1.0f; } OSVR_PositionState position; ret = osvr_GetPositionState(*m_iface, ×tamp, &position); if (ret == OSVR_RETURN_SUCCESS) { result.flags |= VRDisplayCapabilityFlags::Cap_Position; - result.position[0] = position.data[0]; - result.position[1] = position.data[1]; - result.position[2] = position.data[2]; + result.pose.position[0] = position.data[0]; + result.pose.position[1] = position.data[1]; + result.pose.position[2] = position.data[2]; } result.CalcViewMatrices(mHeadToEye); diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp index b402f8a32fea..40feca75bba1 100644 --- a/gfx/vr/gfxVROculus.cpp +++ b/gfx/vr/gfxVROculus.cpp @@ -952,7 +952,7 @@ VRDisplayOculus::GetSensorState() predictedFrameTime = ovr_GetPredictedDisplayTime(mSession->Get(), 0); } result = GetSensorState(predictedFrameTime); - result.position[1] -= mEyeHeight; + result.pose.position[1] -= mEyeHeight; result.CalcViewMatrices(headToEyeTransforms); } result.inputFrameID = mDisplayInfo.mFrameId; @@ -973,41 +973,41 @@ VRDisplayOculus::GetSensorState(double absTime) if (state.StatusFlags & ovrStatus_OrientationTracked) { result.flags |= VRDisplayCapabilityFlags::Cap_Orientation; - result.orientation[0] = pose.ThePose.Orientation.x; - result.orientation[1] = pose.ThePose.Orientation.y; - result.orientation[2] = pose.ThePose.Orientation.z; - result.orientation[3] = pose.ThePose.Orientation.w; + result.pose.orientation[0] = pose.ThePose.Orientation.x; + result.pose.orientation[1] = pose.ThePose.Orientation.y; + result.pose.orientation[2] = pose.ThePose.Orientation.z; + result.pose.orientation[3] = pose.ThePose.Orientation.w; - result.angularVelocity[0] = pose.AngularVelocity.x; - result.angularVelocity[1] = pose.AngularVelocity.y; - result.angularVelocity[2] = pose.AngularVelocity.z; + result.pose.angularVelocity[0] = pose.AngularVelocity.x; + result.pose.angularVelocity[1] = pose.AngularVelocity.y; + result.pose.angularVelocity[2] = pose.AngularVelocity.z; result.flags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration; - result.angularAcceleration[0] = pose.AngularAcceleration.x; - result.angularAcceleration[1] = pose.AngularAcceleration.y; - result.angularAcceleration[2] = pose.AngularAcceleration.z; + result.pose.angularAcceleration[0] = pose.AngularAcceleration.x; + result.pose.angularAcceleration[1] = pose.AngularAcceleration.y; + result.pose.angularAcceleration[2] = pose.AngularAcceleration.z; } else { // default to an identity quaternion - result.orientation[3] = 1.0f; + result.pose.orientation[3] = 1.0f; } if (state.StatusFlags & ovrStatus_PositionTracked) { result.flags |= VRDisplayCapabilityFlags::Cap_Position; - result.position[0] = pose.ThePose.Position.x; - result.position[1] = pose.ThePose.Position.y; - result.position[2] = pose.ThePose.Position.z; + result.pose.position[0] = pose.ThePose.Position.x; + result.pose.position[1] = pose.ThePose.Position.y; + result.pose.position[2] = pose.ThePose.Position.z; - result.linearVelocity[0] = pose.LinearVelocity.x; - result.linearVelocity[1] = pose.LinearVelocity.y; - result.linearVelocity[2] = pose.LinearVelocity.z; + result.pose.linearVelocity[0] = pose.LinearVelocity.x; + result.pose.linearVelocity[1] = pose.LinearVelocity.y; + result.pose.linearVelocity[2] = pose.LinearVelocity.z; result.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration; - result.linearAcceleration[0] = pose.LinearAcceleration.x; - result.linearAcceleration[1] = pose.LinearAcceleration.y; - result.linearAcceleration[2] = pose.LinearAcceleration.z; + result.pose.linearAcceleration[0] = pose.LinearAcceleration.x; + result.pose.linearAcceleration[1] = pose.LinearAcceleration.y; + result.pose.linearAcceleration[2] = pose.LinearAcceleration.z; } result.flags |= VRDisplayCapabilityFlags::Cap_External; result.flags |= VRDisplayCapabilityFlags::Cap_MountDetection; @@ -1330,17 +1330,17 @@ VRControllerOculus::VRControllerOculus(dom::GamepadHand aHand, uint32_t aDisplay break; } - strncpy(state.mControllerName, touchID, kVRControllerNameMaxLen); + strncpy(state.controllerName, touchID, kVRControllerNameMaxLen); MOZ_ASSERT(kNumOculusButton == static_cast(OculusLeftControllerButtonType::NumButtonType) && kNumOculusButton == static_cast(OculusRightControllerButtonType::NumButtonType)); - state.mNumButtons = kNumOculusButton; - state.mNumAxes = static_cast( + state.numButtons = kNumOculusButton; + state.numAxes = static_cast( OculusControllerAxisType::NumVRControllerAxisType); - state.mNumHaptics = kNumOculusHaptcs; + state.numHaptics = kNumOculusHaptcs; } float diff --git a/gfx/vr/gfxVROpenVR.cpp b/gfx/vr/gfxVROpenVR.cpp index 1f74179aee17..40535a198f89 100644 --- a/gfx/vr/gfxVROpenVR.cpp +++ b/gfx/vr/gfxVROpenVR.cpp @@ -287,24 +287,24 @@ VRDisplayOpenVR::GetSensorState() rot.Invert(); result.flags |= VRDisplayCapabilityFlags::Cap_Orientation; - result.orientation[0] = rot.x; - result.orientation[1] = rot.y; - result.orientation[2] = rot.z; - result.orientation[3] = rot.w; - result.angularVelocity[0] = pose.vAngularVelocity.v[0]; - result.angularVelocity[1] = pose.vAngularVelocity.v[1]; - result.angularVelocity[2] = pose.vAngularVelocity.v[2]; + result.pose.orientation[0] = rot.x; + result.pose.orientation[1] = rot.y; + result.pose.orientation[2] = rot.z; + result.pose.orientation[3] = rot.w; + result.pose.angularVelocity[0] = pose.vAngularVelocity.v[0]; + result.pose.angularVelocity[1] = pose.vAngularVelocity.v[1]; + result.pose.angularVelocity[2] = pose.vAngularVelocity.v[2]; result.flags |= VRDisplayCapabilityFlags::Cap_Position; - result.position[0] = m._41; - result.position[1] = m._42; - result.position[2] = m._43; - result.linearVelocity[0] = pose.vVelocity.v[0]; - result.linearVelocity[1] = pose.vVelocity.v[1]; - result.linearVelocity[2] = pose.vVelocity.v[2]; + result.pose.position[0] = m._41; + result.pose.position[1] = m._42; + result.pose.position[2] = m._43; + result.pose.linearVelocity[0] = pose.vVelocity.v[0]; + result.pose.linearVelocity[1] = pose.vVelocity.v[1]; + result.pose.linearVelocity[2] = pose.vVelocity.v[2]; } else { // default to an identity quaternion - result.orientation[3] = 1.0f; + result.pose.orientation[3] = 1.0f; } result.CalcViewMatrices(headToEyeTransforms); @@ -438,11 +438,10 @@ VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aDisplay MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost); VRControllerState& state = mControllerInfo.mControllerState; - strncpy(state.mControllerName, aId.BeginReading(), kVRControllerNameMaxLen); - state.mNumButtons = aNumButtons; - state.mNumAxes = aNumAxes; - state.mNumTriggers = aNumTriggers; - state.mNumHaptics = kNumOpenVRHaptcs; + strncpy(state.controllerName, aId.BeginReading(), kVRControllerNameMaxLen); + state.numButtons = aNumButtons; + state.numAxes = aNumAxes; + state.numHaptics = kNumOpenVRHaptcs; } VRControllerOpenVR::~VRControllerOpenVR() @@ -466,31 +465,31 @@ VRControllerOpenVR::GetTrackedIndex() float VRControllerOpenVR::GetAxisMove(uint32_t aAxis) { - return mControllerInfo.mControllerState.mAxisValue[aAxis]; + return mControllerInfo.mControllerState.axisValue[aAxis]; } void VRControllerOpenVR::SetAxisMove(uint32_t aAxis, float aValue) { - mControllerInfo.mControllerState.mAxisValue[aAxis] = aValue; + mControllerInfo.mControllerState.axisValue[aAxis] = aValue; } void VRControllerOpenVR::SetTrigger(uint32_t aButton, float aValue) { - mControllerInfo.mControllerState.mTriggerValue[aButton] = aValue; + mControllerInfo.mControllerState.triggerValue[aButton] = aValue; } float VRControllerOpenVR::GetTrigger(uint32_t aButton) { - return mControllerInfo.mControllerState.mTriggerValue[aButton]; + return mControllerInfo.mControllerState.triggerValue[aButton]; } void VRControllerOpenVR::SetHand(dom::GamepadHand aHand) { - mControllerInfo.mControllerState.mHand = aHand; + mControllerInfo.mControllerState.hand = aHand; } void diff --git a/gfx/vr/gfxVRPuppet.cpp b/gfx/vr/gfxVRPuppet.cpp index dd4747046b06..d6166b659108 100644 --- a/gfx/vr/gfxVRPuppet.cpp +++ b/gfx/vr/gfxVRPuppet.cpp @@ -104,21 +104,21 @@ VRDisplayPuppet::VRDisplayPuppet() gfx::Quaternion rot; mSensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation; - mSensorState.orientation[0] = rot.x; - mSensorState.orientation[1] = rot.y; - mSensorState.orientation[2] = rot.z; - mSensorState.orientation[3] = rot.w; - mSensorState.angularVelocity[0] = 0.0f; - mSensorState.angularVelocity[1] = 0.0f; - mSensorState.angularVelocity[2] = 0.0f; + mSensorState.pose.orientation[0] = rot.x; + mSensorState.pose.orientation[1] = rot.y; + mSensorState.pose.orientation[2] = rot.z; + mSensorState.pose.orientation[3] = rot.w; + mSensorState.pose.angularVelocity[0] = 0.0f; + mSensorState.pose.angularVelocity[1] = 0.0f; + mSensorState.pose.angularVelocity[2] = 0.0f; mSensorState.flags |= VRDisplayCapabilityFlags::Cap_Position; - mSensorState.position[0] = 0.0f; - mSensorState.position[1] = 0.0f; - mSensorState.position[2] = 0.0f; - mSensorState.linearVelocity[0] = 0.0f; - mSensorState.linearVelocity[1] = 0.0f; - mSensorState.linearVelocity[2] = 0.0f; + mSensorState.pose.position[0] = 0.0f; + mSensorState.pose.position[1] = 0.0f; + mSensorState.pose.position[2] = 0.0f; + mSensorState.pose.linearVelocity[0] = 0.0f; + mSensorState.pose.linearVelocity[1] = 0.0f; + mSensorState.pose.linearVelocity[2] = 0.0f; } VRDisplayPuppet::~VRDisplayPuppet() @@ -585,10 +585,10 @@ VRControllerPuppet::VRControllerPuppet(dom::GamepadHand aHand, uint32_t aDisplay { MOZ_COUNT_CTOR_INHERITED(VRControllerPuppet, VRControllerHost); VRControllerState& state = mControllerInfo.mControllerState; - strncpy(state.mControllerName, "Puppet Gamepad", kVRControllerNameMaxLen); - state.mNumButtons = kNumPuppetButtonMask; - state.mNumAxes = kNumPuppetAxis; - state.mNumHaptics = kNumPuppetHaptcs; + strncpy(state.controllerName, "Puppet Gamepad", kVRControllerNameMaxLen); + state.numButtons = kNumPuppetButtonMask; + state.numAxes = kNumPuppetAxis; + state.numHaptics = kNumPuppetHaptcs; } VRControllerPuppet::~VRControllerPuppet() @@ -672,13 +672,13 @@ VRControllerPuppet::GetPoseMoveState() float VRControllerPuppet::GetAxisMove(uint32_t aAxis) { - return mControllerInfo.mControllerState.mAxisValue[aAxis]; + return mControllerInfo.mControllerState.axisValue[aAxis]; } void VRControllerPuppet::SetAxisMove(uint32_t aAxis, float aValue) { - mControllerInfo.mControllerState.mAxisValue[aAxis] = aValue; + mControllerInfo.mControllerState.axisValue[aAxis] = aValue; } VRSystemManagerPuppet::VRSystemManagerPuppet() diff --git a/gfx/vr/ipc/VRManagerChild.cpp b/gfx/vr/ipc/VRManagerChild.cpp index 24d621ffab8a..de4dbd9d5071 100644 --- a/gfx/vr/ipc/VRManagerChild.cpp +++ b/gfx/vr/ipc/VRManagerChild.cpp @@ -44,6 +44,7 @@ VRManagerChild::VRManagerChild() , mBackend(layers::LayersBackend::LAYERS_NONE) , mPromiseID(0) , mVRMockDisplay(nullptr) + , mLastControllerState{} { MOZ_ASSERT(NS_IsMainThread()); diff --git a/gfx/vr/ipc/VRManagerChild.h b/gfx/vr/ipc/VRManagerChild.h index ee06964e90a9..14dc32b3669c 100644 --- a/gfx/vr/ipc/VRManagerChild.h +++ b/gfx/vr/ipc/VRManagerChild.h @@ -139,6 +139,7 @@ private: uint32_t mPromiseID; nsRefPtrHashtable mPromiseList; RefPtr mVRMockDisplay; + VRControllerState mLastControllerState[kVRControllerMaxCount]; DISALLOW_COPY_AND_ASSIGN(VRManagerChild); }; diff --git a/gfx/vr/ipc/VRMessageUtils.h b/gfx/vr/ipc/VRMessageUtils.h index 1f8998ce0196..50a1c69d86c5 100644 --- a/gfx/vr/ipc/VRMessageUtils.h +++ b/gfx/vr/ipc/VRMessageUtils.h @@ -8,6 +8,7 @@ #define mozilla_gfx_vr_VRMessageUtils_h #include "ipc/IPCMessageUtils.h" +#include "mozilla/ArrayUtils.h" #include "mozilla/GfxMessageUtils.h" #include "VRManager.h" @@ -109,9 +110,12 @@ struct ParamTraits WriteParam(aMsg, aParam.mGroupMask); WriteParam(aMsg, aParam.mFrameId); WriteParam(aMsg, aParam.mDisplayState); - for (int i = 0; i < mozilla::gfx::kVRMaxLatencyFrames; i++) { + for (size_t i = 0; i < mozilla::ArrayLength(aParam.mLastSensorState); i++) { WriteParam(aMsg, aParam.mLastSensorState[i]); } + for (size_t i = 0; i < mozilla::ArrayLength(aParam.mControllerState); i++) { + WriteParam(aMsg, aParam.mControllerState[i]); + } } static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) @@ -124,26 +128,28 @@ struct ParamTraits !ReadParam(aMsg, aIter, &(aResult->mDisplayState))) { return false; } - for (int i = 0; i < mozilla::gfx::kVRMaxLatencyFrames; i++) { + for (size_t i = 0; i < mozilla::ArrayLength(aResult->mLastSensorState); i++) { if (!ReadParam(aMsg, aIter, &(aResult->mLastSensorState[i]))) { return false; } } - + for (size_t i = 0; i < mozilla::ArrayLength(aResult->mControllerState); i++) { + if (!ReadParam(aMsg, aIter, &(aResult->mControllerState[i]))) { + return false; + } + } return true; } }; + template <> -struct ParamTraits +struct ParamTraits { - typedef mozilla::gfx::VRHMDSensorState paramType; + typedef mozilla::gfx::VRPose paramType; static void Write(Message* aMsg, const paramType& aParam) { - WriteParam(aMsg, aParam.timestamp); - WriteParam(aMsg, aParam.inputFrameID); - WriteParam(aMsg, aParam.flags); WriteParam(aMsg, aParam.orientation[0]); WriteParam(aMsg, aParam.orientation[1]); WriteParam(aMsg, aParam.orientation[2]); @@ -163,20 +169,11 @@ struct ParamTraits WriteParam(aMsg, aParam.linearAcceleration[0]); WriteParam(aMsg, aParam.linearAcceleration[1]); WriteParam(aMsg, aParam.linearAcceleration[2]); - for (int i=0; i < 16; i++) { - WriteParam(aMsg, aParam.leftViewMatrix[i]); - } - for (int i=0; i < 16; i++) { - WriteParam(aMsg, aParam.rightViewMatrix[i]); - } } static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) { - if (!ReadParam(aMsg, aIter, &(aResult->timestamp)) || - !ReadParam(aMsg, aIter, &(aResult->inputFrameID)) || - !ReadParam(aMsg, aIter, &(aResult->flags)) || - !ReadParam(aMsg, aIter, &(aResult->orientation[0])) || + if (!ReadParam(aMsg, aIter, &(aResult->orientation[0])) || !ReadParam(aMsg, aIter, &(aResult->orientation[1])) || !ReadParam(aMsg, aIter, &(aResult->orientation[2])) || !ReadParam(aMsg, aIter, &(aResult->orientation[3])) || @@ -197,12 +194,43 @@ struct ParamTraits !ReadParam(aMsg, aIter, &(aResult->linearAcceleration[2]))) { return false; } - for (int i=0; i < 16; i++) { + return true; + } +}; + +template <> +struct ParamTraits +{ + typedef mozilla::gfx::VRHMDSensorState paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, aParam.timestamp); + WriteParam(aMsg, aParam.inputFrameID); + WriteParam(aMsg, aParam.flags); + WriteParam(aMsg, aParam.pose); + for (size_t i = 0; i < mozilla::ArrayLength(aParam.leftViewMatrix); i++) { + WriteParam(aMsg, aParam.leftViewMatrix[i]); + } + for (size_t i = 0; i < mozilla::ArrayLength(aParam.rightViewMatrix); i++) { + WriteParam(aMsg, aParam.rightViewMatrix[i]); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) + { + if (!ReadParam(aMsg, aIter, &(aResult->timestamp)) || + !ReadParam(aMsg, aIter, &(aResult->inputFrameID)) || + !ReadParam(aMsg, aIter, &(aResult->flags)) || + !ReadParam(aMsg, aIter, &(aResult->pose))) { + return false; + } + for (size_t i = 0; i < mozilla::ArrayLength(aResult->leftViewMatrix); i++) { if (!ReadParam(aMsg, aIter, &(aResult->leftViewMatrix[i]))) { return false; } } - for (int i=0; i < 16; i++) { + for (size_t i = 0; i < mozilla::ArrayLength(aResult->rightViewMatrix); i++) { if (!ReadParam(aMsg, aIter, &(aResult->rightViewMatrix[i]))) { return false; } @@ -246,19 +274,23 @@ struct ParamTraits static void Write(Message* aMsg, const paramType& aParam) { nsCString controllerName; - controllerName.Assign(aParam.mControllerName); // FINDME!! HACK! - Bounds checking? + controllerName.Assign(aParam.controllerName); // FINDME!! HACK! - Bounds checking? WriteParam(aMsg, controllerName); - WriteParam(aMsg, aParam.mNumButtons); - WriteParam(aMsg, aParam.mNumAxes); - WriteParam(aMsg, aParam.mNumTriggers); - WriteParam(aMsg, aParam.mNumHaptics); - WriteParam(aMsg, aParam.mButtonPressed); - WriteParam(aMsg, aParam.mButtonTouched); - for (int i=0; i < mozilla::gfx::kVRControllerMaxAxis; i++) { - WriteParam(aMsg, aParam.mAxisValue[i]); + WriteParam(aMsg, aParam.hand); + WriteParam(aMsg, aParam.numButtons); + WriteParam(aMsg, aParam.numAxes); + WriteParam(aMsg, aParam.numHaptics); + WriteParam(aMsg, aParam.buttonPressed); + WriteParam(aMsg, aParam.buttonTouched); + WriteParam(aMsg, aParam.flags); + WriteParam(aMsg, aParam.pose); + WriteParam(aMsg, aParam.isPositionValid); + WriteParam(aMsg, aParam.isOrientationValid); + for (size_t i = 0; i < mozilla::ArrayLength(aParam.axisValue); i++) { + WriteParam(aMsg, aParam.axisValue[i]); } - for (int i=0; i < mozilla::gfx::kVRControllerMaxTriggers; i++) { - WriteParam(aMsg, aParam.mTriggerValue[i]); + for (size_t i = 0; i < mozilla::ArrayLength(aParam.triggerValue); i++) { + WriteParam(aMsg, aParam.triggerValue[i]); } } @@ -266,25 +298,29 @@ struct ParamTraits { nsCString controllerName; if (!ReadParam(aMsg, aIter, &(controllerName)) || - !ReadParam(aMsg, aIter, &(aResult->mNumButtons)) || - !ReadParam(aMsg, aIter, &(aResult->mNumAxes)) || - !ReadParam(aMsg, aIter, &(aResult->mNumTriggers)) || - !ReadParam(aMsg, aIter, &(aResult->mNumHaptics)) || - !ReadParam(aMsg, aIter, &(aResult->mButtonPressed)) || - !ReadParam(aMsg, aIter, &(aResult->mButtonTouched))) { + !ReadParam(aMsg, aIter, &(aResult->hand)) || + !ReadParam(aMsg, aIter, &(aResult->numButtons)) || + !ReadParam(aMsg, aIter, &(aResult->numAxes)) || + !ReadParam(aMsg, aIter, &(aResult->numHaptics)) || + !ReadParam(aMsg, aIter, &(aResult->buttonPressed)) || + !ReadParam(aMsg, aIter, &(aResult->buttonTouched)) || + !ReadParam(aMsg, aIter, &(aResult->flags)) || + !ReadParam(aMsg, aIter, &(aResult->pose)) || + !ReadParam(aMsg, aIter, &(aResult->isPositionValid)) || + !ReadParam(aMsg, aIter, &(aResult->isOrientationValid))) { return false; } - for (int i=0; i < mozilla::gfx::kVRControllerMaxAxis; i++) { - if (!ReadParam(aMsg, aIter, &(aResult->mAxisValue[i]))) { + for (size_t i = 0; i < mozilla::ArrayLength(aResult->axisValue); i++) { + if (!ReadParam(aMsg, aIter, &(aResult->axisValue[i]))) { return false; } } - for (int i=0; i < mozilla::gfx::kVRControllerMaxTriggers; i++) { - if (!ReadParam(aMsg, aIter, &(aResult->mTriggerValue[i]))) { + for (size_t i = 0; i < mozilla::ArrayLength(aResult->triggerValue); i++) { + if (!ReadParam(aMsg, aIter, &(aResult->triggerValue[i]))) { return false; } } - strncpy(aResult->mControllerName, controllerName.BeginReading(), mozilla::gfx::kVRControllerNameMaxLen); // FINDME! TODO! HACK! Safe? Better way? + strncpy(aResult->controllerName, controllerName.BeginReading(), mozilla::gfx::kVRControllerNameMaxLen); // FINDME! TODO! HACK! Safe? Better way? return true; } diff --git a/gfx/vr/service/OpenVRSession.cpp b/gfx/vr/service/OpenVRSession.cpp index b52e10dad58c..28ca3fc472f6 100644 --- a/gfx/vr/service/OpenVRSession.cpp +++ b/gfx/vr/service/OpenVRSession.cpp @@ -1,14 +1,13 @@ #include "OpenVRSession.h" +#include "gfxPrefs.h" #if defined(XP_WIN) #include #include "mozilla/gfx/DeviceManagerDx.h" #endif // defined(XP_WIN) -#if defined(MOZILLA_INTERNAL_API) #include "mozilla/dom/GamepadEventTypes.h" #include "mozilla/dom/GamepadBinding.h" -#endif #if !defined(M_PI) #define M_PI 3.14159265358979323846264338327950288 @@ -17,17 +16,91 @@ #define BTN_MASK_FROM_ID(_id) \ ::vr::ButtonMaskFromId(vr::EVRButtonId::_id) +static const uint32_t kNumOpenVRHaptcs = 1; + using namespace mozilla::gfx; namespace mozilla { namespace gfx { +namespace { + +dom::GamepadHand +GetControllerHandFromControllerRole(::vr::ETrackedControllerRole aRole) +{ + dom::GamepadHand hand; + + switch(aRole) { + case ::vr::ETrackedControllerRole::TrackedControllerRole_Invalid: + case ::vr::ETrackedControllerRole::TrackedControllerRole_OptOut: + hand = dom::GamepadHand::_empty; + break; + case ::vr::ETrackedControllerRole::TrackedControllerRole_LeftHand: + hand = dom::GamepadHand::Left; + break; + case ::vr::ETrackedControllerRole::TrackedControllerRole_RightHand: + hand = dom::GamepadHand::Right; + break; + default: + hand = dom::GamepadHand::_empty; + MOZ_ASSERT(false); + break; + } + + return hand; +} + + +void +UpdateButton(VRControllerState& aState, const ::vr::VRControllerState_t& aControllerState, uint32_t aButtonIndex, uint64_t aButtonMask) +{ + uint64_t mask = (1ULL << aButtonIndex); + if ((aControllerState.ulButtonPressed & aButtonMask) == 0) { + // not pressed + aState.buttonPressed &= ~mask; + aState.triggerValue[aButtonIndex] = 0.0f; + } else { + // pressed + aState.buttonPressed |= mask; + aState.triggerValue[aButtonIndex] = 1.0f; + } + if ((aControllerState.ulButtonTouched & aButtonMask) == 0) { + // not touched + aState.buttonTouched &= ~mask; + } else { + // touched + aState.buttonTouched |= mask; + } +} + +void +UpdateTrigger(VRControllerState& aState, uint32_t aButtonIndex, float aValue, float aThreshold) +{ + // For OpenVR, the threshold value of ButtonPressed and ButtonTouched is 0.55. + // We prefer to let developers to set their own threshold for the adjustment. + // Therefore, we don't check ButtonPressed and ButtonTouched with ButtonMask here. + // we just check the button value is larger than the threshold value or not. + uint64_t mask = (1ULL << aButtonIndex); + aState.triggerValue[aButtonIndex] = aValue; + if (aValue > aThreshold) { + aState.buttonPressed |= mask; + aState.buttonTouched |= mask; + } else { + aState.buttonPressed &= ~mask; + aState.buttonTouched &= ~mask; + } +} + +}; // anonymous namespace + OpenVRSession::OpenVRSession() : VRSession() , mVRSystem(nullptr) , mVRChaperone(nullptr) , mVRCompositor(nullptr) + , mControllerDeviceIndex{0} , mShouldQuit(false) + , mIsWindowsMR(false) { } @@ -43,8 +116,10 @@ OpenVRSession::Initialize(mozilla::gfx::VRSystemState& aSystemState) // Already initialized return true; } + if (!::vr::VR_IsRuntimeInstalled()) { + return false; + } if (!::vr::VR_IsHmdPresent()) { - fprintf(stderr, "No HMD detected, VR_IsHmdPresent returned false.\n"); return false; } @@ -143,121 +218,121 @@ OpenVRSession::InitState(VRSystemState& aSystemState) state.mEyeResolution.height = h; // default to an identity quaternion - aSystemState.sensorState.orientation[3] = 1.0f; + aSystemState.sensorState.pose.orientation[3] = 1.0f; UpdateStageParameters(state); - UpdateEyeParameters(state); + UpdateEyeParameters(aSystemState); VRHMDSensorState& sensorState = aSystemState.sensorState; sensorState.flags = (VRDisplayCapabilityFlags)( (int)VRDisplayCapabilityFlags::Cap_Orientation | (int)VRDisplayCapabilityFlags::Cap_Position); - sensorState.orientation[3] = 1.0f; // Default to an identity quaternion + sensorState.pose.orientation[3] = 1.0f; // Default to an identity quaternion return true; } void -OpenVRSession::UpdateStageParameters(VRDisplayState& state) +OpenVRSession::UpdateStageParameters(VRDisplayState& aState) { float sizeX = 0.0f; float sizeZ = 0.0f; if (mVRChaperone->GetPlayAreaSize(&sizeX, &sizeZ)) { ::vr::HmdMatrix34_t t = mVRSystem->GetSeatedZeroPoseToStandingAbsoluteTrackingPose(); - state.mStageSize.width = sizeX; - state.mStageSize.height = sizeZ; + aState.mStageSize.width = sizeX; + aState.mStageSize.height = sizeZ; - state.mSittingToStandingTransform[0] = t.m[0][0]; - state.mSittingToStandingTransform[1] = t.m[1][0]; - state.mSittingToStandingTransform[2] = t.m[2][0]; - state.mSittingToStandingTransform[3] = 0.0f; + aState.mSittingToStandingTransform[0] = t.m[0][0]; + aState.mSittingToStandingTransform[1] = t.m[1][0]; + aState.mSittingToStandingTransform[2] = t.m[2][0]; + aState.mSittingToStandingTransform[3] = 0.0f; - state.mSittingToStandingTransform[4] = t.m[0][1]; - state.mSittingToStandingTransform[5] = t.m[1][1]; - state.mSittingToStandingTransform[6] = t.m[2][1]; - state.mSittingToStandingTransform[7] = 0.0f; + aState.mSittingToStandingTransform[4] = t.m[0][1]; + aState.mSittingToStandingTransform[5] = t.m[1][1]; + aState.mSittingToStandingTransform[6] = t.m[2][1]; + aState.mSittingToStandingTransform[7] = 0.0f; - state.mSittingToStandingTransform[8] = t.m[0][2]; - state.mSittingToStandingTransform[9] = t.m[1][2]; - state.mSittingToStandingTransform[10] = t.m[2][2]; - state.mSittingToStandingTransform[11] = 0.0f; + aState.mSittingToStandingTransform[8] = t.m[0][2]; + aState.mSittingToStandingTransform[9] = t.m[1][2]; + aState.mSittingToStandingTransform[10] = t.m[2][2]; + aState.mSittingToStandingTransform[11] = 0.0f; - state.mSittingToStandingTransform[12] = t.m[0][3]; - state.mSittingToStandingTransform[13] = t.m[1][3]; - state.mSittingToStandingTransform[14] = t.m[2][3]; - state.mSittingToStandingTransform[15] = 1.0f; + aState.mSittingToStandingTransform[12] = t.m[0][3]; + aState.mSittingToStandingTransform[13] = t.m[1][3]; + aState.mSittingToStandingTransform[14] = t.m[2][3]; + aState.mSittingToStandingTransform[15] = 1.0f; } else { // If we fail, fall back to reasonable defaults. // 1m x 1m space, 0.75m high in seated position + aState.mStageSize.width = 1.0f; + aState.mStageSize.height = 1.0f; - state.mStageSize.width = 1.0f; - state.mStageSize.height = 1.0f; + aState.mSittingToStandingTransform[0] = 1.0f; + aState.mSittingToStandingTransform[1] = 0.0f; + aState.mSittingToStandingTransform[2] = 0.0f; + aState.mSittingToStandingTransform[3] = 0.0f; - state.mSittingToStandingTransform[0] = 1.0f; - state.mSittingToStandingTransform[1] = 0.0f; - state.mSittingToStandingTransform[2] = 0.0f; - state.mSittingToStandingTransform[3] = 0.0f; + aState.mSittingToStandingTransform[4] = 0.0f; + aState.mSittingToStandingTransform[5] = 1.0f; + aState.mSittingToStandingTransform[6] = 0.0f; + aState.mSittingToStandingTransform[7] = 0.0f; - state.mSittingToStandingTransform[4] = 0.0f; - state.mSittingToStandingTransform[5] = 1.0f; - state.mSittingToStandingTransform[6] = 0.0f; - state.mSittingToStandingTransform[7] = 0.0f; + aState.mSittingToStandingTransform[8] = 0.0f; + aState.mSittingToStandingTransform[9] = 0.0f; + aState.mSittingToStandingTransform[10] = 1.0f; + aState.mSittingToStandingTransform[11] = 0.0f; - state.mSittingToStandingTransform[8] = 0.0f; - state.mSittingToStandingTransform[9] = 0.0f; - state.mSittingToStandingTransform[10] = 1.0f; - state.mSittingToStandingTransform[11] = 0.0f; - - state.mSittingToStandingTransform[12] = 0.0f; - state.mSittingToStandingTransform[13] = 0.75f; - state.mSittingToStandingTransform[14] = 0.0f; - state.mSittingToStandingTransform[15] = 1.0f; + aState.mSittingToStandingTransform[12] = 0.0f; + aState.mSittingToStandingTransform[13] = 0.75f; + aState.mSittingToStandingTransform[14] = 0.0f; + aState.mSittingToStandingTransform[15] = 1.0f; } } void -OpenVRSession::UpdateEyeParameters(VRDisplayState& state, gfx::Matrix4x4* headToEyeTransforms /* = nullptr */) +OpenVRSession::UpdateEyeParameters(VRSystemState& aState) { + // This must be called every frame in order to + // account for continuous adjustments to ipd. + gfx::Matrix4x4 headToEyeTransforms[2]; + for (uint32_t eye = 0; eye < 2; ++eye) { ::vr::HmdMatrix34_t eyeToHead = mVRSystem->GetEyeToHeadTransform(static_cast<::vr::Hmd_Eye>(eye)); - state.mEyeTranslation[eye].x = eyeToHead.m[0][3]; - state.mEyeTranslation[eye].y = eyeToHead.m[1][3]; - state.mEyeTranslation[eye].z = eyeToHead.m[2][3]; + aState.displayState.mEyeTranslation[eye].x = eyeToHead.m[0][3]; + aState.displayState.mEyeTranslation[eye].y = eyeToHead.m[1][3]; + aState.displayState.mEyeTranslation[eye].z = eyeToHead.m[2][3]; float left, right, up, down; mVRSystem->GetProjectionRaw(static_cast<::vr::Hmd_Eye>(eye), &left, &right, &up, &down); - state.mEyeFOV[eye].upDegrees = atan(-up) * 180.0 / M_PI; - state.mEyeFOV[eye].rightDegrees = atan(right) * 180.0 / M_PI; - state.mEyeFOV[eye].downDegrees = atan(down) * 180.0 / M_PI; - state.mEyeFOV[eye].leftDegrees = atan(-left) * 180.0 / M_PI; + aState.displayState.mEyeFOV[eye].upDegrees = atan(-up) * 180.0 / M_PI; + aState.displayState.mEyeFOV[eye].rightDegrees = atan(right) * 180.0 / M_PI; + aState.displayState.mEyeFOV[eye].downDegrees = atan(down) * 180.0 / M_PI; + aState.displayState.mEyeFOV[eye].leftDegrees = atan(-left) * 180.0 / M_PI; - if (headToEyeTransforms) { - Matrix4x4 pose; - // NOTE! eyeToHead.m is a 3x4 matrix, not 4x4. But - // because of its arrangement, we can copy the 12 elements in and - // then transpose them to the right place. - memcpy(&pose._11, &eyeToHead.m, sizeof(eyeToHead.m)); - pose.Transpose(); - pose.Invert(); - headToEyeTransforms[eye] = pose; - } + Matrix4x4 pose; + // NOTE! eyeToHead.m is a 3x4 matrix, not 4x4. But + // because of its arrangement, we can copy the 12 elements in and + // then transpose them to the right place. + memcpy(&pose._11, &eyeToHead.m, sizeof(eyeToHead.m)); + pose.Transpose(); + pose.Invert(); + headToEyeTransforms[eye] = pose; } + aState.sensorState.CalcViewMatrices(headToEyeTransforms); } void -OpenVRSession::GetSensorState(VRSystemState& state) +OpenVRSession::UpdateHeadsetPose(VRSystemState& aState) { const uint32_t posesSize = ::vr::k_unTrackedDeviceIndex_Hmd + 1; ::vr::TrackedDevicePose_t poses[posesSize]; // Note: We *must* call WaitGetPoses in order for any rendering to happen at all. mVRCompositor->WaitGetPoses(nullptr, 0, poses, posesSize); - gfx::Matrix4x4 headToEyeTransforms[2]; - UpdateEyeParameters(state.displayState, headToEyeTransforms); ::vr::Compositor_FrameTiming timing; timing.m_nSize = sizeof(::vr::Compositor_FrameTiming); if (mVRCompositor->GetFrameTiming(&timing)) { - state.sensorState.timestamp = timing.m_flSystemTimeInSeconds; + aState.sensorState.timestamp = timing.m_flSystemTimeInSeconds; } else { // This should not happen, but log it just in case fprintf(stderr, "OpenVR - IVRCompositor::GetFrameTiming failed"); @@ -281,39 +356,411 @@ OpenVRSession::GetSensorState(VRSystemState& state) rot.SetFromRotationMatrix(m); rot.Invert(); - state.sensorState.flags = (VRDisplayCapabilityFlags)((int)state.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Orientation); - state.sensorState.orientation[0] = rot.x; - state.sensorState.orientation[1] = rot.y; - state.sensorState.orientation[2] = rot.z; - state.sensorState.orientation[3] = rot.w; - state.sensorState.angularVelocity[0] = pose.vAngularVelocity.v[0]; - state.sensorState.angularVelocity[1] = pose.vAngularVelocity.v[1]; - state.sensorState.angularVelocity[2] = pose.vAngularVelocity.v[2]; + aState.sensorState.flags = (VRDisplayCapabilityFlags)((int)aState.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Orientation); + aState.sensorState.pose.orientation[0] = rot.x; + aState.sensorState.pose.orientation[1] = rot.y; + aState.sensorState.pose.orientation[2] = rot.z; + aState.sensorState.pose.orientation[3] = rot.w; + aState.sensorState.pose.angularVelocity[0] = pose.vAngularVelocity.v[0]; + aState.sensorState.pose.angularVelocity[1] = pose.vAngularVelocity.v[1]; + aState.sensorState.pose.angularVelocity[2] = pose.vAngularVelocity.v[2]; - state.sensorState.flags =(VRDisplayCapabilityFlags)((int)state.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Position); - state.sensorState.position[0] = m._41; - state.sensorState.position[1] = m._42; - state.sensorState.position[2] = m._43; - state.sensorState.linearVelocity[0] = pose.vVelocity.v[0]; - state.sensorState.linearVelocity[1] = pose.vVelocity.v[1]; - state.sensorState.linearVelocity[2] = pose.vVelocity.v[2]; + aState.sensorState.flags =(VRDisplayCapabilityFlags)((int)aState.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Position); + aState.sensorState.pose.position[0] = m._41; + aState.sensorState.pose.position[1] = m._42; + aState.sensorState.pose.position[2] = m._43; + aState.sensorState.pose.linearVelocity[0] = pose.vVelocity.v[0]; + aState.sensorState.pose.linearVelocity[1] = pose.vVelocity.v[1]; + aState.sensorState.pose.linearVelocity[2] = pose.vVelocity.v[2]; } - - state.sensorState.CalcViewMatrices(headToEyeTransforms); - state.sensorState.inputFrameID++; } void -OpenVRSession::GetControllerState(VRSystemState &state) +OpenVRSession::EnumerateControllers(VRSystemState& aState) { - // TODO - Implement + MOZ_ASSERT(mVRSystem); + + bool controllerPresent[kVRControllerMaxCount] = { false }; + + // Basically, we would have HMDs in the tracked devices, + // but we are just interested in the controllers. + for (::vr::TrackedDeviceIndex_t trackedDevice = ::vr::k_unTrackedDeviceIndex_Hmd + 1; + trackedDevice < ::vr::k_unMaxTrackedDeviceCount; ++trackedDevice) { + + if (!mVRSystem->IsTrackedDeviceConnected(trackedDevice)) { + continue; + } + + const ::vr::ETrackedDeviceClass deviceType = mVRSystem-> + GetTrackedDeviceClass(trackedDevice); + if (deviceType != ::vr::TrackedDeviceClass_Controller + && deviceType != ::vr::TrackedDeviceClass_GenericTracker) { + continue; + } + + uint32_t stateIndex = 0; + uint32_t firstEmptyIndex = kVRControllerMaxCount; + + // Find the existing controller + for (stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) { + if (mControllerDeviceIndex[stateIndex] == 0 && firstEmptyIndex == kVRControllerMaxCount) { + firstEmptyIndex = stateIndex; + } + if (mControllerDeviceIndex[stateIndex] == trackedDevice) { + break; + } + } + if (stateIndex == kVRControllerMaxCount) { + // This is a new controller, let's add it + if (firstEmptyIndex == kVRControllerMaxCount) { + NS_WARNING("OpenVR - Too many controllers, need to increase kVRControllerMaxCount."); + continue; + } + stateIndex = firstEmptyIndex; + mControllerDeviceIndex[stateIndex] = trackedDevice; + VRControllerState& controllerState = aState.controllerState[stateIndex]; + uint32_t numButtons = 0; + uint32_t numAxes = 0; + + // Scan the axes that the controllers support + for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) { + const uint32_t supportAxis = mVRSystem->GetInt32TrackedDeviceProperty(trackedDevice, + static_cast( + ::vr::Prop_Axis0Type_Int32 + j)); + switch (supportAxis) { + case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick: + case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad: + numAxes += 2; // It has x and y axes. + ++numButtons; + break; + case ::vr::k_eControllerAxis_Trigger: + if (j <= 2) { + ++numButtons; + } else { + #ifdef DEBUG + // SteamVR Knuckles is the only special case for using 2D axis values on triggers. + ::vr::ETrackedPropertyError err; + uint32_t requiredBufferLen; + char charBuf[128]; + requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(trackedDevice, + ::vr::Prop_RenderModelName_String, charBuf, 128, &err); + MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success); + nsCString deviceId(charBuf); + MOZ_ASSERT(deviceId.Find("knuckles") != kNotFound); + #endif // #ifdef DEBUG + numButtons += 2; + } + break; + } + } + + // Scan the buttons that the controllers support + const uint64_t supportButtons = mVRSystem->GetUint64TrackedDeviceProperty( + trackedDevice, ::vr::Prop_SupportedButtons_Uint64); + if (supportButtons & + BTN_MASK_FROM_ID(k_EButton_A)) { + ++numButtons; + } + if (supportButtons & + BTN_MASK_FROM_ID(k_EButton_Grip)) { + ++numButtons; + } + if (supportButtons & + BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) { + ++numButtons; + } + if (supportButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Left)) { + ++numButtons; + } + if (supportButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Up)) { + ++numButtons; + } + if (supportButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Right)) { + ++numButtons; + } + if (supportButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Down)) { + ++numButtons; + } + + nsCString deviceId; + GetControllerDeviceId(deviceType, trackedDevice, deviceId); + + strncpy(controllerState.controllerName, deviceId.BeginReading(), kVRControllerNameMaxLen); + controllerState.numButtons = numButtons; + controllerState.numAxes = numAxes; + controllerState.numHaptics = kNumOpenVRHaptcs; + + // If the Windows MR controller doesn't has the amount + // of buttons or axes as our expectation, switching off + // the workaround for Windows MR. + if (mIsWindowsMR && (numAxes < 4 || numButtons < 5)) { + mIsWindowsMR = false; + NS_WARNING("OpenVR - Switching off Windows MR mode."); + } + } + controllerPresent[stateIndex] = true; + } + // Clear out entries for disconnected controllers + for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) { + if (!controllerPresent[stateIndex] && mControllerDeviceIndex[stateIndex] != 0) { + mControllerDeviceIndex[stateIndex] = 0; + memset(&aState.controllerState[stateIndex], 0, sizeof(VRControllerState)); + } + } +} + +void +OpenVRSession::UpdateControllerButtons(VRSystemState& aState) +{ + MOZ_ASSERT(mVRSystem); + + // Compared to Edge, we have a wrong implementation for the vertical axis value. + // In order to not affect the current VR content, we add a workaround for yAxis. + const float yAxisInvert = (mIsWindowsMR) ? -1.0f : 1.0f; + const float triggerThreshold = gfxPrefs::VRControllerTriggerThreshold(); + + for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) { + ::vr::TrackedDeviceIndex_t trackedDevice = mControllerDeviceIndex[stateIndex]; + if (trackedDevice == 0) { + continue; + } + VRControllerState& controllerState = aState.controllerState[stateIndex]; + const ::vr::ETrackedControllerRole role = mVRSystem-> + GetControllerRoleForTrackedDeviceIndex( + trackedDevice); + dom::GamepadHand hand = GetControllerHandFromControllerRole(role); + controllerState.hand = hand; + + ::vr::VRControllerState_t vrControllerState; + if (mVRSystem->GetControllerState(trackedDevice, &vrControllerState, sizeof(vrControllerState))) { + uint32_t axisIdx = 0; + uint32_t buttonIdx = 0; + for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) { + const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty( + trackedDevice, + static_cast<::vr::TrackedDeviceProperty>( + ::vr::Prop_Axis0Type_Int32 + j)); + switch (axisType) { + case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick: + case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad: + { + if (mIsWindowsMR) { + // Adjust the input mapping for Windows MR which has + // different order. + axisIdx = (axisIdx == 0) ? 2 : 0; + buttonIdx = (buttonIdx == 0) ? 4 : 0; + } + + controllerState.axisValue[axisIdx] = vrControllerState.rAxis[j].x; + ++axisIdx; + controllerState.axisValue[axisIdx] = vrControllerState.rAxis[j].y * yAxisInvert; + ++axisIdx; + uint64_t buttonMask = ::vr::ButtonMaskFromId( + static_cast<::vr::EVRButtonId>(::vr::k_EButton_Axis0 + j)); + + UpdateButton(controllerState, vrControllerState, buttonIdx, buttonMask); + ++buttonIdx; + + if (mIsWindowsMR) { + axisIdx = (axisIdx == 4) ? 2 : 4; + buttonIdx = (buttonIdx == 5) ? 1 : 2; + } + break; + } + case vr::EVRControllerAxisType::k_eControllerAxis_Trigger: + { + if (j <= 2) { + UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].x, triggerThreshold); + ++buttonIdx; + } else { + // For SteamVR Knuckles. + UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].x, triggerThreshold); + ++buttonIdx; + UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].y, triggerThreshold); + ++buttonIdx; + } + break; + } + } + } + + const uint64_t supportedButtons = mVRSystem->GetUint64TrackedDeviceProperty( + trackedDevice, ::vr::Prop_SupportedButtons_Uint64); + if (supportedButtons & + BTN_MASK_FROM_ID(k_EButton_A)) { + UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_A)); + ++buttonIdx; + } + if (supportedButtons & + BTN_MASK_FROM_ID(k_EButton_Grip)) { + UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_Grip)); + ++buttonIdx; + } + if (supportedButtons & + BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) { + UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)); + ++buttonIdx; + } + if (mIsWindowsMR) { + // button 4 in Windows MR has already been assigned + // to k_eControllerAxis_TrackPad. + ++buttonIdx; + } + if (supportedButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Left)) { + UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Left)); + ++buttonIdx; + } + if (supportedButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Up)) { + UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Up)); + ++buttonIdx; + } + if (supportedButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Right)) { + UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Right)); + ++buttonIdx; + } + if (supportedButtons & + BTN_MASK_FROM_ID(k_EButton_DPad_Down)) { + UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Down)); + ++buttonIdx; + } + } + } +} + +void +OpenVRSession::UpdateControllerPoses(VRSystemState& aState) +{ + MOZ_ASSERT(mVRSystem); + + ::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount]; + mVRSystem->GetDeviceToAbsoluteTrackingPose(::vr::TrackingUniverseSeated, 0.0f, + poses, ::vr::k_unMaxTrackedDeviceCount); + + for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) { + ::vr::TrackedDeviceIndex_t trackedDevice = mControllerDeviceIndex[stateIndex]; + if (trackedDevice == 0) { + continue; + } + VRControllerState& controllerState = aState.controllerState[stateIndex]; + const ::vr::TrackedDevicePose_t& pose = poses[trackedDevice]; + + if (pose.bDeviceIsConnected) { + controllerState.flags = (dom::GamepadCapabilityFlags::Cap_Orientation | + dom::GamepadCapabilityFlags::Cap_Position); + } else { + controllerState.flags = dom::GamepadCapabilityFlags::Cap_None; + } + if (pose.bPoseIsValid && + pose.eTrackingResult == ::vr::TrackingResult_Running_OK) { + gfx::Matrix4x4 m; + + // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4. But + // because of its arrangement, we can copy the 12 elements in and + // then transpose them to the right place. We do this so we can + // pull out a Quaternion. + memcpy(&m.components, &pose.mDeviceToAbsoluteTracking, sizeof(pose.mDeviceToAbsoluteTracking)); + m.Transpose(); + + gfx::Quaternion rot; + rot.SetFromRotationMatrix(m); + rot.Invert(); + + controllerState.pose.orientation[0] = rot.x; + controllerState.pose.orientation[1] = rot.y; + controllerState.pose.orientation[2] = rot.z; + controllerState.pose.orientation[3] = rot.w; + controllerState.pose.angularVelocity[0] = pose.vAngularVelocity.v[0]; + controllerState.pose.angularVelocity[1] = pose.vAngularVelocity.v[1]; + controllerState.pose.angularVelocity[2] = pose.vAngularVelocity.v[2]; + controllerState.pose.angularAcceleration[0] = 0.0f; + controllerState.pose.angularAcceleration[1] = 0.0f; + controllerState.pose.angularAcceleration[2] = 0.0f; + controllerState.isOrientationValid = true; + + controllerState.pose.position[0] = m._41; + controllerState.pose.position[1] = m._42; + controllerState.pose.position[2] = m._43; + controllerState.pose.linearVelocity[0] = pose.vVelocity.v[0]; + controllerState.pose.linearVelocity[1] = pose.vVelocity.v[1]; + controllerState.pose.linearVelocity[2] = pose.vVelocity.v[2]; + controllerState.pose.linearAcceleration[0] = 0.0f; + controllerState.pose.linearAcceleration[1] = 0.0f; + controllerState.pose.linearAcceleration[2] = 0.0f; + controllerState.isPositionValid = true; + } else { + controllerState.isOrientationValid = false; + controllerState.isPositionValid = false; + } + } +} + +void +OpenVRSession::GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType, + ::vr::TrackedDeviceIndex_t aDeviceIndex, + nsCString& aId) +{ + switch (aDeviceType) { + case ::vr::TrackedDeviceClass_Controller: + { + ::vr::ETrackedPropertyError err; + uint32_t requiredBufferLen; + bool isFound = false; + char charBuf[128]; + requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex, + ::vr::Prop_RenderModelName_String, charBuf, 128, &err); + if (requiredBufferLen > 128) { + MOZ_CRASH("Larger than the buffer size."); + } + MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success); + nsCString deviceId(charBuf); + if (deviceId.Find("knuckles") != kNotFound) { + aId.AssignLiteral("OpenVR Knuckles"); + isFound = true; + } + requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex, + ::vr::Prop_SerialNumber_String, charBuf, 128, &err); + if (requiredBufferLen > 128) { + MOZ_CRASH("Larger than the buffer size."); + } + MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success); + deviceId.Assign(charBuf); + if (deviceId.Find("MRSOURCE") != kNotFound) { + aId.AssignLiteral("Spatial Controller (Spatial Interaction Source) "); + mIsWindowsMR = true; + isFound = true; + } + if (!isFound) { + aId.AssignLiteral("OpenVR Gamepad"); + } + break; + } + case ::vr::TrackedDeviceClass_GenericTracker: + { + aId.AssignLiteral("OpenVR Tracker"); + break; + } + default: + MOZ_ASSERT(false); + break; + } } void OpenVRSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState) { - GetSensorState(aSystemState); - GetControllerState(aSystemState); + UpdateHeadsetPose(aSystemState); + UpdateEyeParameters(aSystemState); + EnumerateControllers(aSystemState); + UpdateControllerButtons(aSystemState); + UpdateControllerPoses(aSystemState); + aSystemState.sensorState.inputFrameID++; } bool diff --git a/gfx/vr/service/OpenVRSession.h b/gfx/vr/service/OpenVRSession.h index 5e987c7803ef..77fd96abcee1 100644 --- a/gfx/vr/service/OpenVRSession.h +++ b/gfx/vr/service/OpenVRSession.h @@ -42,13 +42,17 @@ private: ::vr::IVRSystem* mVRSystem = nullptr; ::vr::IVRChaperone* mVRChaperone = nullptr; ::vr::IVRCompositor* mVRCompositor = nullptr; + ::vr::TrackedDeviceIndex_t mControllerDeviceIndex[kVRControllerMaxCount]; bool mShouldQuit; + bool mIsWindowsMR; bool InitState(mozilla::gfx::VRSystemState& aSystemState); - void UpdateStageParameters(mozilla::gfx::VRDisplayState& state); - void UpdateEyeParameters(mozilla::gfx::VRDisplayState& state, gfx::Matrix4x4* headToEyeTransforms = nullptr); - void GetSensorState(mozilla::gfx::VRSystemState& state); - void GetControllerState(VRSystemState &state); + void UpdateStageParameters(mozilla::gfx::VRDisplayState& aState); + void UpdateEyeParameters(mozilla::gfx::VRSystemState& aState); + void UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState); + void EnumerateControllers(VRSystemState& aState); + void UpdateControllerPoses(VRSystemState& aState); + void UpdateControllerButtons(VRSystemState& aState); bool SubmitFrame(void* aTextureHandle, ::vr::ETextureType aTextureType, @@ -57,6 +61,9 @@ private: #if defined(XP_WIN) bool CreateD3DObjects(); #endif + void GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType, + ::vr::TrackedDeviceIndex_t aDeviceIndex, + nsCString& aId); }; } // namespace mozilla