LCOV - code coverage report
Current view: top level - gfx/vr - gfxVROpenVR.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 514 0.8 %
Date: 2017-07-14 16:53:18 Functions: 1 42 2.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include <math.h>
       7             : 
       8             : #include "prlink.h"
       9             : #include "prenv.h"
      10             : #include "gfxPrefs.h"
      11             : #include "nsString.h"
      12             : #include "mozilla/Preferences.h"
      13             : 
      14             : #include "mozilla/gfx/Quaternion.h"
      15             : 
      16             : #ifdef XP_WIN
      17             : #include "CompositorD3D11.h"
      18             : #include "TextureD3D11.h"
      19             : #endif // XP_WIN
      20             : 
      21             : #include "gfxVROpenVR.h"
      22             : #include "VRManager.h"
      23             : 
      24             : #include "nsServiceManagerUtils.h"
      25             : #include "nsIScreenManager.h"
      26             : 
      27             : #include "mozilla/layers/CompositorThread.h"
      28             : #include "mozilla/dom/GamepadEventTypes.h"
      29             : #include "mozilla/dom/GamepadBinding.h"
      30             : 
      31             : #ifndef M_PI
      32             : # define M_PI 3.14159265358979323846
      33             : #endif
      34             : 
      35             : using namespace mozilla;
      36             : using namespace mozilla::gfx;
      37             : using namespace mozilla::gfx::impl;
      38             : using namespace mozilla::layers;
      39             : using namespace mozilla::dom;
      40             : 
      41             : #define BTN_MASK_FROM_ID(_id) \
      42             :   ::vr::ButtonMaskFromId(vr::EVRButtonId::_id)
      43             : 
      44             : static const uint32_t kNumOpenVRHaptcs = 1;
      45             : 
      46           0 : VRDisplayOpenVR::VRDisplayOpenVR(::vr::IVRSystem *aVRSystem,
      47             :                                  ::vr::IVRChaperone *aVRChaperone,
      48           0 :                                  ::vr::IVRCompositor *aVRCompositor)
      49             :   : VRDisplayHost(VRDeviceType::OpenVR)
      50             :   , mVRSystem(aVRSystem)
      51             :   , mVRChaperone(aVRChaperone)
      52             :   , mVRCompositor(aVRCompositor)
      53           0 :   , mIsPresenting(false)
      54             : {
      55           0 :   MOZ_COUNT_CTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost);
      56             : 
      57           0 :   mDisplayInfo.mDisplayName.AssignLiteral("OpenVR HMD");
      58           0 :   mDisplayInfo.mIsConnected = true;
      59           0 :   mDisplayInfo.mIsMounted = false;
      60           0 :   mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None |
      61           0 :                                   VRDisplayCapabilityFlags::Cap_Orientation |
      62           0 :                                   VRDisplayCapabilityFlags::Cap_Position |
      63           0 :                                   VRDisplayCapabilityFlags::Cap_External |
      64           0 :                                   VRDisplayCapabilityFlags::Cap_Present |
      65           0 :                                   VRDisplayCapabilityFlags::Cap_StageParameters;
      66             : 
      67             :   ::vr::ETrackedPropertyError err;
      68           0 :   bool bHasProximitySensor = mVRSystem->GetBoolTrackedDeviceProperty(::vr::k_unTrackedDeviceIndex_Hmd, ::vr::Prop_ContainsProximitySensor_Bool, &err);
      69           0 :   if (err == ::vr::TrackedProp_Success && bHasProximitySensor) {
      70           0 :     mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_MountDetection;
      71             :   }
      72             : 
      73           0 :   mVRCompositor->SetTrackingSpace(::vr::TrackingUniverseSeated);
      74             : 
      75             :   uint32_t w, h;
      76           0 :   mVRSystem->GetRecommendedRenderTargetSize(&w, &h);
      77           0 :   mDisplayInfo.mEyeResolution.width = w;
      78           0 :   mDisplayInfo.mEyeResolution.height = h;
      79             : 
      80             :   // SteamVR gives the application a single FOV to use; it's not configurable as with Oculus
      81           0 :   for (uint32_t eye = 0; eye < 2; ++eye) {
      82             :     // get l/r/t/b clip plane coordinates
      83             :     float l, r, t, b;
      84           0 :     mVRSystem->GetProjectionRaw(static_cast<::vr::Hmd_Eye>(eye), &l, &r, &t, &b);
      85           0 :     mDisplayInfo.mEyeFOV[eye].SetFromTanRadians(-t, r, b, -l);
      86             : 
      87           0 :     ::vr::HmdMatrix34_t eyeToHead = mVRSystem->GetEyeToHeadTransform(static_cast<::vr::Hmd_Eye>(eye));
      88             : 
      89           0 :     mDisplayInfo.mEyeTranslation[eye].x = eyeToHead.m[0][3];
      90           0 :     mDisplayInfo.mEyeTranslation[eye].y = eyeToHead.m[1][3];
      91           0 :     mDisplayInfo.mEyeTranslation[eye].z = eyeToHead.m[2][3];
      92             :   }
      93             : 
      94           0 :   UpdateStageParameters();
      95           0 : }
      96             : 
      97           0 : VRDisplayOpenVR::~VRDisplayOpenVR()
      98             : {
      99           0 :   Destroy();
     100           0 :   MOZ_COUNT_DTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost);
     101           0 : }
     102             : 
     103             : void
     104           0 : VRDisplayOpenVR::Destroy()
     105             : {
     106           0 :   StopPresentation();
     107           0 :   ::vr::VR_Shutdown();
     108           0 : }
     109             : 
     110             : void
     111           0 : VRDisplayOpenVR::UpdateStageParameters()
     112             : {
     113           0 :   float sizeX = 0.0f;
     114           0 :   float sizeZ = 0.0f;
     115           0 :   if (mVRChaperone->GetPlayAreaSize(&sizeX, &sizeZ)) {
     116           0 :     ::vr::HmdMatrix34_t t = mVRSystem->GetSeatedZeroPoseToStandingAbsoluteTrackingPose();
     117           0 :     mDisplayInfo.mStageSize.width = sizeX;
     118           0 :     mDisplayInfo.mStageSize.height = sizeZ;
     119             : 
     120           0 :     mDisplayInfo.mSittingToStandingTransform._11 = t.m[0][0];
     121           0 :     mDisplayInfo.mSittingToStandingTransform._12 = t.m[1][0];
     122           0 :     mDisplayInfo.mSittingToStandingTransform._13 = t.m[2][0];
     123           0 :     mDisplayInfo.mSittingToStandingTransform._14 = 0.0f;
     124             : 
     125           0 :     mDisplayInfo.mSittingToStandingTransform._21 = t.m[0][1];
     126           0 :     mDisplayInfo.mSittingToStandingTransform._22 = t.m[1][1];
     127           0 :     mDisplayInfo.mSittingToStandingTransform._23 = t.m[2][1];
     128           0 :     mDisplayInfo.mSittingToStandingTransform._24 = 0.0f;
     129             : 
     130           0 :     mDisplayInfo.mSittingToStandingTransform._31 = t.m[0][2];
     131           0 :     mDisplayInfo.mSittingToStandingTransform._32 = t.m[1][2];
     132           0 :     mDisplayInfo.mSittingToStandingTransform._33 = t.m[2][2];
     133           0 :     mDisplayInfo.mSittingToStandingTransform._34 = 0.0f;
     134             : 
     135           0 :     mDisplayInfo.mSittingToStandingTransform._41 = t.m[0][3];
     136           0 :     mDisplayInfo.mSittingToStandingTransform._42 = t.m[1][3];
     137           0 :     mDisplayInfo.mSittingToStandingTransform._43 = t.m[2][3];
     138           0 :     mDisplayInfo.mSittingToStandingTransform._44 = 1.0f;
     139             :   } else {
     140             :     // If we fail, fall back to reasonable defaults.
     141             :     // 1m x 1m space, 0.75m high in seated position
     142             : 
     143           0 :     mDisplayInfo.mStageSize.width = 1.0f;
     144           0 :     mDisplayInfo.mStageSize.height = 1.0f;
     145             : 
     146           0 :     mDisplayInfo.mSittingToStandingTransform._11 = 1.0f;
     147           0 :     mDisplayInfo.mSittingToStandingTransform._12 = 0.0f;
     148           0 :     mDisplayInfo.mSittingToStandingTransform._13 = 0.0f;
     149           0 :     mDisplayInfo.mSittingToStandingTransform._14 = 0.0f;
     150             : 
     151           0 :     mDisplayInfo.mSittingToStandingTransform._21 = 0.0f;
     152           0 :     mDisplayInfo.mSittingToStandingTransform._22 = 1.0f;
     153           0 :     mDisplayInfo.mSittingToStandingTransform._23 = 0.0f;
     154           0 :     mDisplayInfo.mSittingToStandingTransform._24 = 0.0f;
     155             : 
     156           0 :     mDisplayInfo.mSittingToStandingTransform._31 = 0.0f;
     157           0 :     mDisplayInfo.mSittingToStandingTransform._32 = 0.0f;
     158           0 :     mDisplayInfo.mSittingToStandingTransform._33 = 1.0f;
     159           0 :     mDisplayInfo.mSittingToStandingTransform._34 = 0.0f;
     160             : 
     161           0 :     mDisplayInfo.mSittingToStandingTransform._41 = 0.0f;
     162           0 :     mDisplayInfo.mSittingToStandingTransform._42 = 0.75f;
     163           0 :     mDisplayInfo.mSittingToStandingTransform._43 = 0.0f;
     164           0 :     mDisplayInfo.mSittingToStandingTransform._44 = 1.0f;
     165             :   }
     166           0 : }
     167             : 
     168             : void
     169           0 : VRDisplayOpenVR::ZeroSensor()
     170             : {
     171           0 :   mVRSystem->ResetSeatedZeroPose();
     172           0 :   UpdateStageParameters();
     173           0 : }
     174             : 
     175             : void
     176           0 : VRDisplayOpenVR::PollEvents()
     177             : {
     178             :   ::vr::VREvent_t event;
     179           0 :   while (mVRSystem->PollNextEvent(&event, sizeof(event))) {
     180           0 :     switch (event.eventType) {
     181             :       case ::vr::VREvent_TrackedDeviceUserInteractionStarted:
     182           0 :         mDisplayInfo.mIsMounted = true;
     183           0 :         break;
     184             :       case ::vr::VREvent_TrackedDeviceUserInteractionEnded:
     185           0 :         mDisplayInfo.mIsMounted = false;
     186           0 :         break;
     187             :       case ::vr::EVREventType::VREvent_DriverRequestedQuit:
     188             :       case ::vr::EVREventType::VREvent_Quit:
     189             :       case ::vr::EVREventType::VREvent_ProcessQuit:
     190             :       case ::vr::EVREventType::VREvent_QuitAcknowledged:
     191             :       case ::vr::EVREventType::VREvent_QuitAborted_UserPrompt:
     192           0 :         mDisplayInfo.mIsConnected = false;
     193           0 :         break;
     194             :       default:
     195             :         // ignore
     196           0 :         break;
     197             :     }
     198             :   }
     199           0 : }
     200             : 
     201             : VRHMDSensorState
     202           0 : VRDisplayOpenVR::GetSensorState()
     203             : {
     204           0 :   PollEvents();
     205             : 
     206             :   ::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount];
     207             :   // Note: We *must* call WaitGetPoses in order for any rendering to happen at all
     208           0 :   mVRCompositor->WaitGetPoses(poses, ::vr::k_unMaxTrackedDeviceCount, nullptr, 0);
     209             : 
     210           0 :   VRHMDSensorState result;
     211             : 
     212             :   ::vr::Compositor_FrameTiming timing;
     213           0 :   timing.m_nSize = sizeof(::vr::Compositor_FrameTiming);
     214           0 :   if (mVRCompositor->GetFrameTiming(&timing)) {
     215           0 :     result.timestamp = timing.m_flSystemTimeInSeconds;
     216             :   } else {
     217             :     // This should not happen, but log it just in case
     218           0 :     NS_WARNING("OpenVR - IVRCompositor::GetFrameTiming failed");
     219             :   }
     220             : 
     221           0 :   if (poses[::vr::k_unTrackedDeviceIndex_Hmd].bDeviceIsConnected &&
     222           0 :       poses[::vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid &&
     223           0 :       poses[::vr::k_unTrackedDeviceIndex_Hmd].eTrackingResult == ::vr::TrackingResult_Running_OK)
     224             :   {
     225           0 :     const ::vr::TrackedDevicePose_t& pose = poses[::vr::k_unTrackedDeviceIndex_Hmd];
     226             : 
     227           0 :     gfx::Matrix4x4 m;
     228             :     // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4.  But
     229             :     // because of its arrangement, we can copy the 12 elements in and
     230             :     // then transpose them to the right place.  We do this so we can
     231             :     // pull out a Quaternion.
     232           0 :     memcpy(&m._11, &pose.mDeviceToAbsoluteTracking, sizeof(float) * 12);
     233           0 :     m.Transpose();
     234             : 
     235           0 :     gfx::Quaternion rot;
     236           0 :     rot.SetFromRotationMatrix(m);
     237           0 :     rot.Invert();
     238             : 
     239           0 :     result.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
     240           0 :     result.orientation[0] = rot.x;
     241           0 :     result.orientation[1] = rot.y;
     242           0 :     result.orientation[2] = rot.z;
     243           0 :     result.orientation[3] = rot.w;
     244           0 :     result.angularVelocity[0] = pose.vAngularVelocity.v[0];
     245           0 :     result.angularVelocity[1] = pose.vAngularVelocity.v[1];
     246           0 :     result.angularVelocity[2] = pose.vAngularVelocity.v[2];
     247             : 
     248           0 :     result.flags |= VRDisplayCapabilityFlags::Cap_Position;
     249           0 :     result.position[0] = m._41;
     250           0 :     result.position[1] = m._42;
     251           0 :     result.position[2] = m._43;
     252           0 :     result.linearVelocity[0] = pose.vVelocity.v[0];
     253           0 :     result.linearVelocity[1] = pose.vVelocity.v[1];
     254           0 :     result.linearVelocity[2] = pose.vVelocity.v[2];
     255             :   }
     256             : 
     257           0 :   result.inputFrameID = mDisplayInfo.mFrameId;
     258           0 :   return result;
     259             : }
     260             : 
     261             : void
     262           0 : VRDisplayOpenVR::StartPresentation()
     263             : {
     264           0 :   if (mIsPresenting) {
     265           0 :     return;
     266             :   }
     267           0 :   mIsPresenting = true;
     268             : }
     269             : 
     270             : void
     271           0 : VRDisplayOpenVR::StopPresentation()
     272             : {
     273           0 :   if (!mIsPresenting) {
     274           0 :     return;
     275             :   }
     276             : 
     277           0 :   mVRCompositor->ClearLastSubmittedFrame();
     278             : 
     279           0 :   mIsPresenting = false;
     280             : }
     281             : 
     282             : 
     283             : #if defined(XP_WIN)
     284             : 
     285             : bool
     286             : VRDisplayOpenVR::SubmitFrame(TextureSourceD3D11* aSource,
     287             :   const IntSize& aSize,
     288             :   const gfx::Rect& aLeftEyeRect,
     289             :   const gfx::Rect& aRightEyeRect)
     290             : {
     291             :   if (!mIsPresenting) {
     292             :     return false;
     293             :   }
     294             : 
     295             :   ::vr::Texture_t tex;
     296             :   tex.handle = (void *)aSource->GetD3D11Texture();
     297             :   tex.eType = ::vr::ETextureType::TextureType_DirectX;
     298             :   tex.eColorSpace = ::vr::EColorSpace::ColorSpace_Auto;
     299             : 
     300             :   ::vr::VRTextureBounds_t bounds;
     301             :   bounds.uMin = aLeftEyeRect.x;
     302             :   bounds.vMin = 1.0 - aLeftEyeRect.y;
     303             :   bounds.uMax = aLeftEyeRect.x + aLeftEyeRect.width;
     304             :   bounds.vMax = 1.0 - aLeftEyeRect.y - aLeftEyeRect.height;
     305             : 
     306             :   ::vr::EVRCompositorError err;
     307             :   err = mVRCompositor->Submit(::vr::EVREye::Eye_Left, &tex, &bounds);
     308             :   if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
     309             :     printf_stderr("OpenVR Compositor Submit() failed.\n");
     310             :   }
     311             : 
     312             :   bounds.uMin = aRightEyeRect.x;
     313             :   bounds.vMin = 1.0 - aRightEyeRect.y;
     314             :   bounds.uMax = aRightEyeRect.x + aRightEyeRect.width;
     315             :   bounds.vMax = 1.0 - aRightEyeRect.y - aRightEyeRect.height;
     316             : 
     317             :   err = mVRCompositor->Submit(::vr::EVREye::Eye_Right, &tex, &bounds);
     318             :   if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
     319             :     printf_stderr("OpenVR Compositor Submit() failed.\n");
     320             :   }
     321             : 
     322             :   mVRCompositor->PostPresentHandoff();
     323             : 
     324             :   return true;
     325             : }
     326             : 
     327             : #endif
     328             : 
     329             : void
     330           0 : VRDisplayOpenVR::NotifyVSync()
     331             : {
     332             :   // We update mIsConneced once per frame.
     333           0 :   mDisplayInfo.mIsConnected = ::vr::VR_IsHmdPresent();
     334             : 
     335             :   // Make sure we respond to OpenVR events even when not presenting
     336           0 :   PollEvents();
     337             : 
     338           0 :   VRDisplayHost::NotifyVSync();
     339           0 : }
     340             : 
     341           0 : VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButtons,
     342           0 :                                        uint32_t aNumAxes, ::vr::ETrackedDeviceClass aDeviceType)
     343             :   : VRControllerHost(VRDeviceType::OpenVR)
     344             :   , mTrigger(0)
     345             :   , mAxisMove(aNumAxes)
     346             :   , mVibrateThread(nullptr)
     347           0 :   , mIsVibrateStopped(false)
     348             : {
     349           0 :   MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
     350             : 
     351           0 :   switch (aDeviceType) {
     352             :     case ::vr::TrackedDeviceClass_Controller:
     353           0 :       mControllerInfo.mControllerName.AssignLiteral("OpenVR Gamepad");
     354           0 :       break;
     355             :     case ::vr::TrackedDeviceClass_GenericTracker:
     356           0 :       mControllerInfo.mControllerName.AssignLiteral("OpenVR Tracker");
     357           0 :       break;
     358             :     default:
     359           0 :       MOZ_ASSERT(false);
     360             :       break;
     361             :   }
     362             : 
     363           0 :   mAxisMove.SetLengthAndRetainStorage(aNumAxes);
     364           0 :   mControllerInfo.mMappingType = GamepadMappingType::_empty;
     365           0 :   mControllerInfo.mHand = aHand;
     366           0 :   mControllerInfo.mNumButtons = aNumButtons;
     367           0 :   mControllerInfo.mNumAxes = aNumAxes;
     368           0 :   mControllerInfo.mNumHaptics = kNumOpenVRHaptcs;
     369           0 : }
     370             : 
     371           0 : VRControllerOpenVR::~VRControllerOpenVR()
     372             : {
     373           0 :   if (mVibrateThread) {
     374           0 :     mVibrateThread->Shutdown();
     375           0 :     mVibrateThread = nullptr;
     376             :   }
     377             : 
     378           0 :   MOZ_COUNT_DTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
     379           0 : }
     380             : 
     381             : void
     382           0 : VRControllerOpenVR::SetTrackedIndex(uint32_t aTrackedIndex)
     383             : {
     384           0 :   mTrackedIndex = aTrackedIndex;
     385           0 : }
     386             : 
     387             : uint32_t
     388           0 : VRControllerOpenVR::GetTrackedIndex()
     389             : {
     390           0 :   return mTrackedIndex;
     391             : }
     392             : 
     393             : float
     394           0 : VRControllerOpenVR::GetAxisMove(uint32_t aAxis)
     395             : {
     396           0 :   return mAxisMove[aAxis];
     397             : }
     398             : 
     399             : void
     400           0 : VRControllerOpenVR::SetAxisMove(uint32_t aAxis, float aValue)
     401             : {
     402           0 :   mAxisMove[aAxis] = aValue;
     403           0 : }
     404             : 
     405             : void
     406           0 : VRControllerOpenVR::SetTrigger(float aValue)
     407             : {
     408           0 :   mTrigger = aValue;
     409           0 : }
     410             : 
     411             : float
     412           0 : VRControllerOpenVR::GetTrigger()
     413             : {
     414           0 :   return mTrigger;
     415             : }
     416             : 
     417             : void
     418           0 : VRControllerOpenVR::SetHand(dom::GamepadHand aHand)
     419             : {
     420           0 :   mControllerInfo.mHand = aHand;
     421           0 : }
     422             : 
     423             : void
     424           0 : VRControllerOpenVR::UpdateVibrateHaptic(::vr::IVRSystem* aVRSystem,
     425             :                                         uint32_t aHapticIndex,
     426             :                                         double aIntensity,
     427             :                                         double aDuration,
     428             :                                         uint64_t aVibrateIndex,
     429             :                                         uint32_t aPromiseID)
     430             : {
     431             :   // UpdateVibrateHaptic() only can be called by mVibrateThread
     432           0 :   MOZ_ASSERT(mVibrateThread == NS_GetCurrentThread());
     433             : 
     434             :   // It has been interrupted by loss focus.
     435           0 :   if (mIsVibrateStopped) {
     436           0 :     VibrateHapticComplete(aPromiseID);
     437           0 :     return;
     438             :   }
     439             :   // Avoid the previous vibrate event to override the new one.
     440           0 :   if (mVibrateIndex != aVibrateIndex) {
     441           0 :     VibrateHapticComplete(aPromiseID);
     442           0 :     return;
     443             :   }
     444             : 
     445           0 :   const double duration = (aIntensity == 0) ? 0 : aDuration;
     446             :   // We expect OpenVR to vibrate for 5 ms, but we found it only response the
     447             :   // commend ~ 3.9 ms. For duration time longer than 3.9 ms, we separate them
     448             :   // to a loop of 3.9 ms for make users feel that is a continuous events.
     449           0 :   const uint32_t microSec = (duration < 3.9 ? duration : 3.9) * 1000 * aIntensity;
     450           0 :   aVRSystem->TriggerHapticPulse(GetTrackedIndex(),
     451           0 :                                 aHapticIndex, microSec);
     452             : 
     453             :   // In OpenVR spec, it mentions TriggerHapticPulse() may not trigger another haptic pulse
     454             :   // on this controller and axis combination for 5ms.
     455           0 :   const double kVibrateRate = 5.0;
     456           0 :   if (duration >= kVibrateRate) {
     457           0 :     MOZ_ASSERT(mVibrateThread);
     458             : 
     459             :     RefPtr<Runnable> runnable =
     460             :       NewRunnableMethod<::vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t>
     461           0 :         ("VRControllerOpenVR::UpdateVibrateHaptic",
     462             :          this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem,
     463           0 :          aHapticIndex, aIntensity, duration - kVibrateRate, aVibrateIndex, aPromiseID);
     464           0 :     NS_DelayedDispatchToCurrentThread(runnable.forget(), kVibrateRate);
     465             :   } else {
     466             :     // The pulse has completed
     467           0 :     VibrateHapticComplete(aPromiseID);
     468             :   }
     469             : }
     470             : 
     471             : void
     472           0 : VRControllerOpenVR::VibrateHapticComplete(uint32_t aPromiseID)
     473             : {
     474           0 :   VRManager *vm = VRManager::Get();
     475             : 
     476           0 :   CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<uint32_t>
     477           0 :     ("VRManager::NotifyVibrateHapticCompleted",
     478           0 :      vm, &VRManager::NotifyVibrateHapticCompleted, aPromiseID));
     479           0 : }
     480             : 
     481             : void
     482           0 : VRControllerOpenVR::VibrateHaptic(::vr::IVRSystem* aVRSystem,
     483             :                                   uint32_t aHapticIndex,
     484             :                                   double aIntensity,
     485             :                                   double aDuration,
     486             :                                   uint32_t aPromiseID)
     487             : {
     488             :   // Spinning up the haptics thread at the first haptics call.
     489           0 :   if (!mVibrateThread) {
     490           0 :     nsresult rv = NS_NewThread(getter_AddRefs(mVibrateThread));
     491           0 :     MOZ_ASSERT(mVibrateThread);
     492             : 
     493           0 :     if (NS_FAILED(rv)) {
     494           0 :       MOZ_ASSERT(false, "Failed to create async thread.");
     495             :     }
     496             :   }
     497           0 :   ++mVibrateIndex;
     498           0 :   mIsVibrateStopped = false;
     499             : 
     500             :   RefPtr<Runnable> runnable =
     501             :       NewRunnableMethod<::vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t>
     502           0 :         ("VRControllerOpenVR::UpdateVibrateHaptic",
     503             :          this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem,
     504           0 :          aHapticIndex, aIntensity, aDuration, mVibrateIndex, aPromiseID);
     505           0 :   mVibrateThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
     506           0 : }
     507             : 
     508             : void
     509           0 : VRControllerOpenVR::StopVibrateHaptic()
     510             : {
     511           0 :   mIsVibrateStopped = true;
     512           0 : }
     513             : 
     514           0 : VRSystemManagerOpenVR::VRSystemManagerOpenVR()
     515           0 :   : mVRSystem(nullptr)
     516             : {
     517           0 : }
     518             : 
     519             : /*static*/ already_AddRefed<VRSystemManagerOpenVR>
     520           3 : VRSystemManagerOpenVR::Create()
     521             : {
     522           3 :   MOZ_ASSERT(NS_IsMainThread());
     523             : 
     524           3 :   if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
     525           3 :     return nullptr;
     526             :   }
     527             : 
     528           0 :   if (!::vr::VR_IsRuntimeInstalled()) {
     529           0 :     return nullptr;
     530             :   }
     531             : 
     532           0 :   RefPtr<VRSystemManagerOpenVR> manager = new VRSystemManagerOpenVR();
     533           0 :   return manager.forget();
     534             : }
     535             : 
     536             : void
     537           0 : VRSystemManagerOpenVR::Destroy()
     538             : {
     539           0 :   Shutdown();
     540           0 : }
     541             : 
     542             : void
     543           0 : VRSystemManagerOpenVR::Shutdown()
     544             : {
     545           0 :   if (mOpenVRHMD) {
     546           0 :     mOpenVRHMD = nullptr;
     547             :   }
     548           0 :   RemoveControllers();
     549           0 :   mVRSystem = nullptr;
     550           0 : }
     551             : 
     552             : bool
     553           0 : VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
     554             : {
     555           0 :   if (!::vr::VR_IsHmdPresent() ||
     556           0 :       (mOpenVRHMD && !mOpenVRHMD->GetIsConnected())) {
     557             :     // OpenVR runtime could be quit accidentally,
     558             :     // and we make it re-initialize.
     559           0 :     mOpenVRHMD = nullptr;
     560           0 :     mVRSystem = nullptr;
     561           0 :   } else if (mOpenVRHMD == nullptr) {
     562             :     ::vr::HmdError err;
     563             : 
     564           0 :     ::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
     565           0 :     if (err) {
     566           0 :       return false;
     567             :     }
     568             : 
     569           0 :     ::vr::IVRSystem *system = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
     570           0 :     if (err || !system) {
     571           0 :       ::vr::VR_Shutdown();
     572           0 :       return false;
     573             :     }
     574           0 :     ::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
     575           0 :     if (err || !chaperone) {
     576           0 :       ::vr::VR_Shutdown();
     577           0 :       return false;
     578             :     }
     579           0 :     ::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
     580           0 :     if (err || !compositor) {
     581           0 :       ::vr::VR_Shutdown();
     582           0 :       return false;
     583             :     }
     584             : 
     585           0 :     mVRSystem = system;
     586           0 :     mOpenVRHMD = new VRDisplayOpenVR(system, chaperone, compositor);
     587             :   }
     588             : 
     589           0 :   if (mOpenVRHMD) {
     590           0 :     aHMDResult.AppendElement(mOpenVRHMD);
     591           0 :     return true;
     592             :   }
     593           0 :   return false;
     594             : }
     595             : 
     596             : bool
     597           0 : VRSystemManagerOpenVR::GetIsPresenting()
     598             : {
     599           0 :   if (mOpenVRHMD) {
     600           0 :     VRDisplayInfo displayInfo(mOpenVRHMD->GetDisplayInfo());
     601           0 :     return displayInfo.GetPresentingGroups() != kVRGroupNone;
     602             :   }
     603             : 
     604           0 :   return false;
     605             : }
     606             : 
     607             : void
     608           0 : VRSystemManagerOpenVR::HandleInput()
     609             : {
     610             :   // mVRSystem is available after VRDisplay is created
     611             :   // at GetHMDs().
     612           0 :   if (!mVRSystem) {
     613           0 :     return;
     614             :   }
     615             : 
     616           0 :   RefPtr<impl::VRControllerOpenVR> controller;
     617             :   ::vr::VRControllerState_t state;
     618             :   ::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount];
     619           0 :   mVRSystem->GetDeviceToAbsoluteTrackingPose(::vr::TrackingUniverseSeated, 0.0f,
     620           0 :                                              poses, ::vr::k_unMaxTrackedDeviceCount);
     621             :   // Process OpenVR controller state
     622           0 :   for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
     623           0 :     uint32_t axisIdx = 0;
     624           0 :     uint32_t buttonIdx = 0;
     625           0 :     controller = mOpenVRController[i];
     626           0 :     const uint32_t trackedIndex = controller->GetTrackedIndex();
     627             : 
     628           0 :     MOZ_ASSERT(mVRSystem->GetTrackedDeviceClass(trackedIndex)
     629             :                == ::vr::TrackedDeviceClass_Controller ||
     630             :                mVRSystem->GetTrackedDeviceClass(trackedIndex)
     631             :                == ::vr::TrackedDeviceClass_GenericTracker);
     632             : 
     633             :     // Sometimes, OpenVR controllers are not located by HMD at the initial time.
     634             :     // That makes us have to update the hand info at runtime although switching controllers
     635             :     // to the other hand does not have new changes at the current OpenVR SDK. But, it makes sense
     636             :     // to detect hand changing at runtime.
     637           0 :     const ::vr::ETrackedControllerRole role = mVRSystem->
     638             :                                                 GetControllerRoleForTrackedDeviceIndex(
     639           0 :                                                 trackedIndex);
     640           0 :     const dom::GamepadHand hand = GetGamepadHandFromControllerRole(role);
     641           0 :     if (hand != controller->GetHand()) {
     642           0 :       controller->SetHand(hand);
     643           0 :       NewHandChangeEvent(i, hand);
     644             :     }
     645             : 
     646           0 :     if (mVRSystem->GetControllerState(trackedIndex, &state, sizeof(state))) {
     647           0 :       for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) {
     648           0 :         const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty(
     649             :                                    trackedIndex,
     650             :                                    static_cast<::vr::TrackedDeviceProperty>(
     651           0 :                                    ::vr::Prop_Axis0Type_Int32 + j));
     652           0 :         switch (axisType) {
     653             :           case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
     654             :           case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
     655           0 :             HandleAxisMove(i, axisIdx,
     656           0 :                            state.rAxis[j].x);
     657           0 :             ++axisIdx;
     658           0 :             HandleAxisMove(i, axisIdx,
     659           0 :                            state.rAxis[j].y);
     660           0 :             ++axisIdx;
     661           0 :             HandleButtonPress(i, buttonIdx,
     662             :                               ::vr::ButtonMaskFromId(
     663           0 :                                  static_cast<::vr::EVRButtonId>(::vr::k_EButton_Axis0 + j)),
     664           0 :                                  state.ulButtonPressed, state.ulButtonTouched);
     665           0 :             ++buttonIdx;
     666           0 :             break;
     667             :           case vr::EVRControllerAxisType::k_eControllerAxis_Trigger:
     668           0 :             HandleTriggerPress(i, buttonIdx, state.rAxis[j].x);
     669           0 :             ++buttonIdx;
     670           0 :             break;
     671             :         }
     672             :       }
     673           0 :       MOZ_ASSERT(axisIdx ==
     674             :                  controller->GetControllerInfo().GetNumAxes());
     675             : 
     676           0 :       const uint64_t supportedButtons = mVRSystem->GetUint64TrackedDeviceProperty(
     677           0 :                                          trackedIndex, ::vr::Prop_SupportedButtons_Uint64);
     678           0 :       if (supportedButtons &
     679           0 :           BTN_MASK_FROM_ID(k_EButton_A)) {
     680           0 :         HandleButtonPress(i, buttonIdx,
     681             :                           BTN_MASK_FROM_ID(k_EButton_A),
     682           0 :                           state.ulButtonPressed, state.ulButtonTouched);
     683           0 :         ++buttonIdx;
     684             :       }
     685           0 :       if (supportedButtons &
     686           0 :           BTN_MASK_FROM_ID(k_EButton_Grip)) {
     687           0 :         HandleButtonPress(i, buttonIdx,
     688             :                           BTN_MASK_FROM_ID(k_EButton_Grip),
     689           0 :                           state.ulButtonPressed, state.ulButtonTouched);
     690           0 :         ++buttonIdx;
     691             :       }
     692           0 :       if (supportedButtons &
     693           0 :           BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
     694           0 :         HandleButtonPress(i, buttonIdx,
     695             :                           BTN_MASK_FROM_ID(k_EButton_ApplicationMenu),
     696           0 :                           state.ulButtonPressed, state.ulButtonTouched);
     697           0 :         ++buttonIdx;
     698             :       }
     699           0 :       if (supportedButtons &
     700           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
     701           0 :         HandleButtonPress(i, buttonIdx,
     702             :                           BTN_MASK_FROM_ID(k_EButton_DPad_Left),
     703           0 :                           state.ulButtonPressed, state.ulButtonTouched);
     704           0 :         ++buttonIdx;
     705             :       }
     706           0 :       if (supportedButtons &
     707           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Up)) {
     708           0 :         HandleButtonPress(i, buttonIdx,
     709             :                           BTN_MASK_FROM_ID(k_EButton_DPad_Up),
     710           0 :                           state.ulButtonPressed, state.ulButtonTouched);
     711           0 :         ++buttonIdx;
     712             :       }
     713           0 :       if (supportedButtons &
     714           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Right)) {
     715           0 :         HandleButtonPress(i, buttonIdx,
     716             :                           BTN_MASK_FROM_ID(k_EButton_DPad_Right),
     717           0 :                           state.ulButtonPressed, state.ulButtonTouched);
     718           0 :         ++buttonIdx;
     719             :       }
     720           0 :       if (supportedButtons &
     721           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Down)) {
     722           0 :         HandleButtonPress(i, buttonIdx,
     723             :                           BTN_MASK_FROM_ID(k_EButton_DPad_Down),
     724           0 :                           state.ulButtonPressed, state.ulButtonTouched);
     725           0 :         ++buttonIdx;
     726             :       }
     727           0 :       MOZ_ASSERT(buttonIdx ==
     728             :                  controller->GetControllerInfo().GetNumButtons());
     729           0 :       controller->SetButtonPressed(state.ulButtonPressed);
     730           0 :       controller->SetButtonTouched(state.ulButtonTouched);
     731             : 
     732             :       // Start to process pose
     733           0 :       const ::vr::TrackedDevicePose_t& pose = poses[trackedIndex];
     734           0 :       GamepadPoseState poseState;
     735             : 
     736           0 :       if (pose.bDeviceIsConnected) {
     737           0 :         poseState.flags |= (GamepadCapabilityFlags::Cap_Orientation |
     738           0 :                             GamepadCapabilityFlags::Cap_Position);
     739             :       }
     740             : 
     741           0 :       if (pose.bPoseIsValid &&
     742           0 :           pose.eTrackingResult == ::vr::TrackingResult_Running_OK) {
     743           0 :         gfx::Matrix4x4 m;
     744             : 
     745             :         // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4.  But
     746             :         // because of its arrangement, we can copy the 12 elements in and
     747             :         // then transpose them to the right place.  We do this so we can
     748             :         // pull out a Quaternion.
     749           0 :         memcpy(&m.components, &pose.mDeviceToAbsoluteTracking, sizeof(float) * 12);
     750           0 :         m.Transpose();
     751             : 
     752           0 :         gfx::Quaternion rot;
     753           0 :         rot.SetFromRotationMatrix(m);
     754           0 :         rot.Invert();
     755             : 
     756           0 :         poseState.orientation[0] = rot.x;
     757           0 :         poseState.orientation[1] = rot.y;
     758           0 :         poseState.orientation[2] = rot.z;
     759           0 :         poseState.orientation[3] = rot.w;
     760           0 :         poseState.angularVelocity[0] = pose.vAngularVelocity.v[0];
     761           0 :         poseState.angularVelocity[1] = pose.vAngularVelocity.v[1];
     762           0 :         poseState.angularVelocity[2] = pose.vAngularVelocity.v[2];
     763           0 :         poseState.isOrientationValid = true;
     764             : 
     765           0 :         poseState.position[0] = m._41;
     766           0 :         poseState.position[1] = m._42;
     767           0 :         poseState.position[2] = m._43;
     768           0 :         poseState.linearVelocity[0] = pose.vVelocity.v[0];
     769           0 :         poseState.linearVelocity[1] = pose.vVelocity.v[1];
     770           0 :         poseState.linearVelocity[2] = pose.vVelocity.v[2];
     771           0 :         poseState.isPositionValid = true;
     772             :       }
     773           0 :       HandlePoseTracking(i, poseState, controller);
     774             :     }
     775             :   }
     776             : }
     777             : 
     778             : void
     779           0 : VRSystemManagerOpenVR::HandleButtonPress(uint32_t aControllerIdx,
     780             :                                          uint32_t aButton,
     781             :                                          uint64_t aButtonMask,
     782             :                                          uint64_t aButtonPressed,
     783             :                                          uint64_t aButtonTouched)
     784             : {
     785           0 :   RefPtr<impl::VRControllerOpenVR> controller(mOpenVRController[aControllerIdx]);
     786           0 :   MOZ_ASSERT(controller);
     787           0 :   const uint64_t pressedDiff = (controller->GetButtonPressed() ^ aButtonPressed);
     788           0 :   const uint64_t touchedDiff = (controller->GetButtonTouched() ^ aButtonTouched);
     789             : 
     790           0 :   if (!pressedDiff && !touchedDiff) {
     791           0 :     return;
     792             :   }
     793             : 
     794           0 :   if (pressedDiff & aButtonMask ||
     795           0 :       touchedDiff & aButtonMask) {
     796             :     // diff & (aButtonPressed, aButtonTouched) would be true while a new button pressed or
     797             :     // touched event, otherwise it is an old event and needs to notify
     798             :     // the button has been released.
     799           0 :     NewButtonEvent(aControllerIdx, aButton, aButtonMask & aButtonPressed,
     800           0 :                    aButtonMask & aButtonTouched,
     801           0 :                    (aButtonMask & aButtonPressed) ? 1.0L : 0.0L);
     802             :   }
     803             : }
     804             : 
     805             : void
     806           0 : VRSystemManagerOpenVR::HandleTriggerPress(uint32_t aControllerIdx,
     807             :                                           uint32_t aButton,
     808             :                                           float aValue)
     809             : {
     810           0 :   RefPtr<impl::VRControllerOpenVR> controller(mOpenVRController[aControllerIdx]);
     811           0 :   MOZ_ASSERT(controller);
     812           0 :   const float oldValue = controller->GetTrigger();
     813             :   // For OpenVR, the threshold value of ButtonPressed and ButtonTouched is 0.55.
     814             :   // We prefer to let developers to set their own threshold for the adjustment.
     815             :   // Therefore, we don't check ButtonPressed and ButtonTouched with ButtonMask here.
     816             :   // we just check the button value is larger than the threshold value or not.
     817           0 :   const float threshold = gfxPrefs::VRControllerTriggerThreshold();
     818             : 
     819             :   // Avoid sending duplicated events in IPC channels.
     820           0 :   if (oldValue != aValue) {
     821           0 :     NewButtonEvent(aControllerIdx, aButton, aValue > threshold,
     822           0 :                    aValue > threshold, aValue);
     823           0 :     controller->SetTrigger(aValue);
     824             :   }
     825           0 : }
     826             : 
     827             : void
     828           0 : VRSystemManagerOpenVR::HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
     829             :                                       float aValue)
     830             : {
     831           0 :   RefPtr<impl::VRControllerOpenVR> controller(mOpenVRController[aControllerIdx]);
     832           0 :   MOZ_ASSERT(controller);
     833             : 
     834           0 :   if (controller->GetAxisMove(aAxis) != aValue) {
     835           0 :     NewAxisMove(aControllerIdx, aAxis, aValue);
     836           0 :     controller->SetAxisMove(aAxis, aValue);
     837             :   }
     838           0 : }
     839             : 
     840             : void
     841           0 : VRSystemManagerOpenVR::HandlePoseTracking(uint32_t aControllerIdx,
     842             :                                           const GamepadPoseState& aPose,
     843             :                                           VRControllerHost* aController)
     844             : {
     845           0 :   MOZ_ASSERT(aController);
     846           0 :   if (aPose != aController->GetPose()) {
     847           0 :     aController->SetPose(aPose);
     848           0 :     NewPoseState(aControllerIdx, aPose);
     849             :   }
     850           0 : }
     851             : 
     852             : dom::GamepadHand
     853           0 : VRSystemManagerOpenVR::GetGamepadHandFromControllerRole(
     854             :                                           ::vr::ETrackedControllerRole aRole)
     855             : {
     856             :   dom::GamepadHand hand;
     857             : 
     858           0 :   switch(aRole) {
     859             :     case ::vr::ETrackedControllerRole::TrackedControllerRole_Invalid:
     860           0 :       hand = dom::GamepadHand::_empty;
     861           0 :       break;
     862             :     case ::vr::ETrackedControllerRole::TrackedControllerRole_LeftHand:
     863           0 :       hand = dom::GamepadHand::Left;
     864           0 :       break;
     865             :     case ::vr::ETrackedControllerRole::TrackedControllerRole_RightHand:
     866           0 :       hand = dom::GamepadHand::Right;
     867           0 :       break;
     868             :     default:
     869           0 :       MOZ_ASSERT(false);
     870             :       break;
     871             :   }
     872             : 
     873           0 :   return hand;
     874             : }
     875             : 
     876             : void
     877           0 : VRSystemManagerOpenVR::VibrateHaptic(uint32_t aControllerIdx,
     878             :                                      uint32_t aHapticIndex,
     879             :                                      double aIntensity,
     880             :                                      double aDuration,
     881             :                                      uint32_t aPromiseID)
     882             : {
     883             :   // mVRSystem is available after VRDisplay is created
     884             :   // at GetHMDs().
     885           0 :   if (!mVRSystem) {
     886           0 :     return;
     887             :   }
     888             : 
     889           0 :   RefPtr<impl::VRControllerOpenVR> controller = mOpenVRController[aControllerIdx];
     890           0 :   MOZ_ASSERT(controller);
     891             : 
     892           0 :   controller->VibrateHaptic(mVRSystem, aHapticIndex, aIntensity, aDuration, aPromiseID);
     893             : }
     894             : 
     895             : void
     896           0 : VRSystemManagerOpenVR::StopVibrateHaptic(uint32_t aControllerIdx)
     897             : {
     898             :   // mVRSystem is available after VRDisplay is created
     899             :   // at GetHMDs().
     900           0 :   if (!mVRSystem) {
     901           0 :     return;
     902             :   }
     903             : 
     904           0 :   RefPtr<impl::VRControllerOpenVR> controller = mOpenVRController[aControllerIdx];
     905           0 :   MOZ_ASSERT(controller);
     906             : 
     907           0 :   controller->StopVibrateHaptic();
     908             : }
     909             : 
     910             : void
     911           0 : VRSystemManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
     912             : {
     913           0 :   aControllerResult.Clear();
     914           0 :   for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
     915           0 :     aControllerResult.AppendElement(mOpenVRController[i]);
     916             :   }
     917           0 : }
     918             : 
     919             : void
     920           0 : VRSystemManagerOpenVR::ScanForControllers()
     921             : {
     922             :   // mVRSystem is available after VRDisplay is created
     923             :   // at GetHMDs().
     924           0 :   if (!mVRSystem) {
     925           0 :     return;
     926             :   }
     927             : 
     928             :   ::vr::TrackedDeviceIndex_t trackedIndexArray[::vr::k_unMaxTrackedDeviceCount];
     929           0 :   uint32_t newControllerCount = 0;
     930             :   // Basically, we would have HMDs in the tracked devices,
     931             :   // but we are just interested in the controllers.
     932           0 :   for (::vr::TrackedDeviceIndex_t trackedDevice = ::vr::k_unTrackedDeviceIndex_Hmd + 1;
     933           0 :        trackedDevice < ::vr::k_unMaxTrackedDeviceCount; ++trackedDevice) {
     934             : 
     935           0 :     if (!mVRSystem->IsTrackedDeviceConnected(trackedDevice)) {
     936           0 :       continue;
     937             :     }
     938             : 
     939           0 :     const ::vr::ETrackedDeviceClass deviceType = mVRSystem->
     940           0 :                                                  GetTrackedDeviceClass(trackedDevice);
     941           0 :     if (deviceType != ::vr::TrackedDeviceClass_Controller
     942           0 :         && deviceType != ::vr::TrackedDeviceClass_GenericTracker) {
     943           0 :       continue;
     944             :     }
     945             : 
     946           0 :     trackedIndexArray[newControllerCount] = trackedDevice;
     947           0 :     ++newControllerCount;
     948             :   }
     949             : 
     950           0 :   if (newControllerCount != mControllerCount) {
     951           0 :     RemoveControllers();
     952             : 
     953             :     // Re-adding controllers to VRControllerManager.
     954           0 :     for (::vr::TrackedDeviceIndex_t i = 0; i < newControllerCount; ++i) {
     955           0 :       const ::vr::TrackedDeviceIndex_t trackedDevice = trackedIndexArray[i];
     956           0 :       const ::vr::ETrackedDeviceClass deviceType = mVRSystem->
     957           0 :                                                    GetTrackedDeviceClass(trackedDevice);
     958           0 :       const ::vr::ETrackedControllerRole role = mVRSystem->
     959             :                                                 GetControllerRoleForTrackedDeviceIndex(
     960           0 :                                                 trackedDevice);
     961           0 :       const GamepadHand hand = GetGamepadHandFromControllerRole(role);
     962           0 :       uint32_t numButtons = 0;
     963           0 :       uint32_t numAxes = 0;
     964             : 
     965             :       // Scan the axes that the controllers support
     966           0 :       for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) {
     967           0 :         const uint32_t supportAxis = mVRSystem->GetInt32TrackedDeviceProperty(trackedDevice,
     968             :                                       static_cast<vr::TrackedDeviceProperty>(
     969           0 :                                       ::vr::Prop_Axis0Type_Int32 + j));
     970           0 :         switch (supportAxis) {
     971             :           case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
     972             :           case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
     973           0 :             numAxes += 2; // It has x and y axes.
     974           0 :             ++numButtons;
     975           0 :             break;
     976             :           case ::vr::k_eControllerAxis_Trigger:
     977           0 :             ++numButtons;
     978           0 :             break;
     979             :         }
     980             :       }
     981             : 
     982             :       // Scan the buttons that the controllers support
     983           0 :       const uint64_t supportButtons = mVRSystem->GetUint64TrackedDeviceProperty(
     984           0 :                                        trackedDevice, ::vr::Prop_SupportedButtons_Uint64);
     985           0 :       if (supportButtons &
     986           0 :           BTN_MASK_FROM_ID(k_EButton_A)) {
     987           0 :         ++numButtons;
     988             :       }
     989           0 :       if (supportButtons &
     990           0 :           BTN_MASK_FROM_ID(k_EButton_Grip)) {
     991           0 :         ++numButtons;
     992             :       }
     993           0 :       if (supportButtons &
     994           0 :           BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
     995           0 :         ++numButtons;
     996             :       }
     997           0 :       if (supportButtons &
     998           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
     999           0 :         ++numButtons;
    1000             :       }
    1001           0 :       if (supportButtons &
    1002           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Up)) {
    1003           0 :         ++numButtons;
    1004             :       }
    1005           0 :       if (supportButtons &
    1006           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Right)) {
    1007           0 :         ++numButtons;
    1008             :       }
    1009           0 :       if (supportButtons &
    1010           0 :           BTN_MASK_FROM_ID(k_EButton_DPad_Down)) {
    1011           0 :         ++numButtons;
    1012             :       }
    1013             : 
    1014             :       RefPtr<VRControllerOpenVR> openVRController =
    1015           0 :         new VRControllerOpenVR(hand, numButtons, numAxes, deviceType);
    1016           0 :       openVRController->SetTrackedIndex(trackedDevice);
    1017           0 :       mOpenVRController.AppendElement(openVRController);
    1018             : 
    1019             :       // Not already present, add it.
    1020           0 :       AddGamepad(openVRController->GetControllerInfo());
    1021           0 :       ++mControllerCount;
    1022             :     }
    1023             :   }
    1024             : }
    1025             : 
    1026             : void
    1027           0 : VRSystemManagerOpenVR::RemoveControllers()
    1028             : {
    1029             :   // The controller count is changed, removing the existing gamepads first.
    1030           0 :   for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
    1031           0 :     RemoveGamepad(i);
    1032             :   }
    1033           0 :   mOpenVRController.Clear();
    1034           0 :   mControllerCount = 0;
    1035           0 : }
    1036             : 

Generated by: LCOV version 1.13