tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

OculusSession.cpp (54993B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef XP_WIN
      8 #  error "Oculus support only available for Windows"
      9 #endif
     10 
     11 #include <math.h>
     12 #include <d3d11.h>
     13 
     14 #include "mozilla/StaticPrefs_dom.h"
     15 #include "mozilla/dom/GamepadEventTypes.h"
     16 #include "mozilla/dom/GamepadBinding.h"
     17 #include "mozilla/gfx/DeviceManagerDx.h"
     18 #include "mozilla/gfx/Logging.h"
     19 #include "mozilla/SharedLibrary.h"
     20 #include "OculusSession.h"
     21 
     22 /** XXX The DX11 objects and quad blitting could be encapsulated
     23 *    into a separate object if either Oculus starts supporting
     24 *     non-Windows platforms or the blit is needed by other HMD\
     25 *     drivers.
     26 *     Alternately, we could remove the extra blit for
     27 *     Oculus as well with some more refactoring.
     28 */
     29 
     30 // See CompositorD3D11Shaders.h
     31 namespace mozilla {
     32 namespace layers {
     33 struct ShaderBytes {
     34  const void* mData;
     35  size_t mLength;
     36 };
     37 extern ShaderBytes sRGBShader;
     38 extern ShaderBytes sLayerQuadVS;
     39 }  // namespace layers
     40 }  // namespace mozilla
     41 
     42 using namespace mozilla;
     43 using namespace mozilla::gfx;
     44 using namespace mozilla::layers;
     45 
     46 namespace {
     47 
     48 static pfn_ovr_Initialize ovr_Initialize = nullptr;
     49 static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
     50 static pfn_ovr_GetLastErrorInfo ovr_GetLastErrorInfo = nullptr;
     51 static pfn_ovr_GetVersionString ovr_GetVersionString = nullptr;
     52 static pfn_ovr_TraceMessage ovr_TraceMessage = nullptr;
     53 static pfn_ovr_IdentifyClient ovr_IdentifyClient = nullptr;
     54 static pfn_ovr_GetHmdDesc ovr_GetHmdDesc = nullptr;
     55 static pfn_ovr_GetTrackerCount ovr_GetTrackerCount = nullptr;
     56 static pfn_ovr_GetTrackerDesc ovr_GetTrackerDesc = nullptr;
     57 static pfn_ovr_Create ovr_Create = nullptr;
     58 static pfn_ovr_Destroy ovr_Destroy = nullptr;
     59 static pfn_ovr_GetSessionStatus ovr_GetSessionStatus = nullptr;
     60 static pfn_ovr_IsExtensionSupported ovr_IsExtensionSupported = nullptr;
     61 static pfn_ovr_EnableExtension ovr_EnableExtension = nullptr;
     62 static pfn_ovr_SetTrackingOriginType ovr_SetTrackingOriginType = nullptr;
     63 static pfn_ovr_GetTrackingOriginType ovr_GetTrackingOriginType = nullptr;
     64 static pfn_ovr_RecenterTrackingOrigin ovr_RecenterTrackingOrigin = nullptr;
     65 static pfn_ovr_SpecifyTrackingOrigin ovr_SpecifyTrackingOrigin = nullptr;
     66 static pfn_ovr_ClearShouldRecenterFlag ovr_ClearShouldRecenterFlag = nullptr;
     67 static pfn_ovr_GetTrackingState ovr_GetTrackingState = nullptr;
     68 static pfn_ovr_GetDevicePoses ovr_GetDevicePoses = nullptr;
     69 static pfn_ovr_GetTrackerPose ovr_GetTrackerPose = nullptr;
     70 static pfn_ovr_GetInputState ovr_GetInputState = nullptr;
     71 static pfn_ovr_GetConnectedControllerTypes ovr_GetConnectedControllerTypes =
     72    nullptr;
     73 static pfn_ovr_GetTouchHapticsDesc ovr_GetTouchHapticsDesc = nullptr;
     74 static pfn_ovr_SetControllerVibration ovr_SetControllerVibration = nullptr;
     75 static pfn_ovr_SubmitControllerVibration ovr_SubmitControllerVibration =
     76    nullptr;
     77 static pfn_ovr_GetControllerVibrationState ovr_GetControllerVibrationState =
     78    nullptr;
     79 static pfn_ovr_TestBoundary ovr_TestBoundary = nullptr;
     80 static pfn_ovr_TestBoundaryPoint ovr_TestBoundaryPoint = nullptr;
     81 static pfn_ovr_SetBoundaryLookAndFeel ovr_SetBoundaryLookAndFeel = nullptr;
     82 static pfn_ovr_ResetBoundaryLookAndFeel ovr_ResetBoundaryLookAndFeel = nullptr;
     83 static pfn_ovr_GetBoundaryGeometry ovr_GetBoundaryGeometry = nullptr;
     84 static pfn_ovr_GetBoundaryDimensions ovr_GetBoundaryDimensions = nullptr;
     85 static pfn_ovr_GetBoundaryVisible ovr_GetBoundaryVisible = nullptr;
     86 static pfn_ovr_RequestBoundaryVisible ovr_RequestBoundaryVisible = nullptr;
     87 static pfn_ovr_GetTextureSwapChainLength ovr_GetTextureSwapChainLength =
     88    nullptr;
     89 static pfn_ovr_GetTextureSwapChainCurrentIndex
     90    ovr_GetTextureSwapChainCurrentIndex = nullptr;
     91 static pfn_ovr_GetTextureSwapChainDesc ovr_GetTextureSwapChainDesc = nullptr;
     92 static pfn_ovr_CommitTextureSwapChain ovr_CommitTextureSwapChain = nullptr;
     93 static pfn_ovr_DestroyTextureSwapChain ovr_DestroyTextureSwapChain = nullptr;
     94 static pfn_ovr_DestroyMirrorTexture ovr_DestroyMirrorTexture = nullptr;
     95 static pfn_ovr_GetFovTextureSize ovr_GetFovTextureSize = nullptr;
     96 static pfn_ovr_GetRenderDesc2 ovr_GetRenderDesc2 = nullptr;
     97 static pfn_ovr_WaitToBeginFrame ovr_WaitToBeginFrame = nullptr;
     98 static pfn_ovr_BeginFrame ovr_BeginFrame = nullptr;
     99 static pfn_ovr_EndFrame ovr_EndFrame = nullptr;
    100 static pfn_ovr_SubmitFrame ovr_SubmitFrame = nullptr;
    101 static pfn_ovr_GetPerfStats ovr_GetPerfStats = nullptr;
    102 static pfn_ovr_ResetPerfStats ovr_ResetPerfStats = nullptr;
    103 static pfn_ovr_GetPredictedDisplayTime ovr_GetPredictedDisplayTime = nullptr;
    104 static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
    105 static pfn_ovr_GetBool ovr_GetBool = nullptr;
    106 static pfn_ovr_SetBool ovr_SetBool = nullptr;
    107 static pfn_ovr_GetInt ovr_GetInt = nullptr;
    108 static pfn_ovr_SetInt ovr_SetInt = nullptr;
    109 static pfn_ovr_GetFloat ovr_GetFloat = nullptr;
    110 static pfn_ovr_SetFloat ovr_SetFloat = nullptr;
    111 static pfn_ovr_GetFloatArray ovr_GetFloatArray = nullptr;
    112 static pfn_ovr_SetFloatArray ovr_SetFloatArray = nullptr;
    113 static pfn_ovr_GetString ovr_GetString = nullptr;
    114 static pfn_ovr_SetString ovr_SetString = nullptr;
    115 static pfn_ovr_GetExternalCameras ovr_GetExternalCameras = nullptr;
    116 static pfn_ovr_SetExternalCameraProperties ovr_SetExternalCameraProperties =
    117    nullptr;
    118 
    119 #ifdef XP_WIN
    120 static pfn_ovr_CreateTextureSwapChainDX ovr_CreateTextureSwapChainDX = nullptr;
    121 static pfn_ovr_GetTextureSwapChainBufferDX ovr_GetTextureSwapChainBufferDX =
    122    nullptr;
    123 static pfn_ovr_CreateMirrorTextureDX ovr_CreateMirrorTextureDX = nullptr;
    124 static pfn_ovr_GetMirrorTextureBufferDX ovr_GetMirrorTextureBufferDX = nullptr;
    125 #endif
    126 
    127 static pfn_ovr_CreateTextureSwapChainGL ovr_CreateTextureSwapChainGL = nullptr;
    128 static pfn_ovr_GetTextureSwapChainBufferGL ovr_GetTextureSwapChainBufferGL =
    129    nullptr;
    130 static pfn_ovr_CreateMirrorTextureGL ovr_CreateMirrorTextureGL = nullptr;
    131 static pfn_ovr_GetMirrorTextureBufferGL ovr_GetMirrorTextureBufferGL = nullptr;
    132 
    133 #ifdef HAVE_64BIT_BUILD
    134 #  define BUILD_BITS 64
    135 #else
    136 #  define BUILD_BITS 32
    137 #endif
    138 
    139 #define OVR_PRODUCT_VERSION 1
    140 #define OVR_MAJOR_VERSION 1
    141 #define OVR_MINOR_VERSION 19
    142 
    143 static const uint32_t kNumOculusButtons = 7;
    144 static const uint32_t kNumOculusHaptcs = 1;
    145 static const uint32_t kNumOculusAxes = 4;
    146 ovrControllerType OculusControllerTypes[2] = {ovrControllerType_LTouch,
    147                                              ovrControllerType_RTouch};
    148 const char* OculusControllerNames[2] = {"Oculus Touch (Left)",
    149                                        "Oculus Touch (Right)"};
    150 dom::GamepadHand OculusControllerHand[2] = {dom::GamepadHand::Left,
    151                                            dom::GamepadHand::Right};
    152 
    153 ovrButton OculusControllerButtons[2][kNumOculusButtons] = {
    154    {(ovrButton)0, (ovrButton)0, (ovrButton)0, ovrButton_LThumb, ovrButton_X,
    155     ovrButton_Y, (ovrButton)0},
    156    {(ovrButton)0, (ovrButton)0, (ovrButton)0, ovrButton_RThumb, ovrButton_A,
    157     ovrButton_B, (ovrButton)0},
    158 };
    159 
    160 ovrTouch OculusControllerTouches[2][kNumOculusButtons] = {
    161    {ovrTouch_LIndexTrigger, (ovrTouch)0, (ovrTouch)0, ovrTouch_LThumb,
    162     ovrTouch_X, ovrTouch_Y, ovrTouch_LThumbRest},
    163    {ovrTouch_RIndexTrigger, (ovrTouch)0, (ovrTouch)0, ovrTouch_RThumb,
    164     ovrTouch_A, ovrTouch_B, ovrTouch_RThumbRest},
    165 };
    166 
    167 void UpdateButton(const ovrInputState& aInputState, uint32_t aHandIdx,
    168                  uint32_t aButtonIdx, VRControllerState& aControllerState) {
    169  if (aInputState.Buttons & OculusControllerButtons[aHandIdx][aButtonIdx]) {
    170    aControllerState.buttonPressed |= ((uint64_t)1 << aButtonIdx);
    171    aControllerState.triggerValue[aButtonIdx] = 1.0f;
    172  } else {
    173    aControllerState.triggerValue[aButtonIdx] = 0.0f;
    174  }
    175  if (aInputState.Touches & OculusControllerTouches[aHandIdx][aButtonIdx]) {
    176    aControllerState.buttonTouched |= ((uint64_t)1 << aButtonIdx);
    177  }
    178 }
    179 
    180 VRFieldOfView FromFovPort(const ovrFovPort& aFOV) {
    181  VRFieldOfView fovInfo;
    182  fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
    183  fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
    184  fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
    185  fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
    186  return fovInfo;
    187 }
    188 
    189 }  // anonymous namespace
    190 
    191 namespace mozilla {
    192 namespace gfx {
    193 
    194 OculusSession::OculusSession()
    195    : VRSession(),
    196      mOvrLib(nullptr),
    197      mSession(nullptr),
    198      mInitFlags((ovrInitFlags)0),
    199      mTextureSet(nullptr),
    200      mQuadVS(nullptr),
    201      mQuadPS(nullptr),
    202      mLinearSamplerState(nullptr),
    203      mVSConstantBuffer(nullptr),
    204      mPSConstantBuffer(nullptr),
    205      mVertexBuffer(nullptr),
    206      mInputLayout(nullptr),
    207      mRemainingVibrateTime{},
    208      mHapticPulseIntensity{},
    209      mIsPresenting(false) {}
    210 
    211 OculusSession::~OculusSession() { Shutdown(); }
    212 
    213 bool OculusSession::Initialize(mozilla::gfx::VRSystemState& aSystemState,
    214                               bool aDetectRuntimesOnly) {
    215  if (StaticPrefs::dom_vr_puppet_enabled()) {
    216    // Ensure that tests using the VR Puppet do not find real hardware
    217    return false;
    218  }
    219  if (!StaticPrefs::dom_vr_enabled() || !StaticPrefs::dom_vr_oculus_enabled()) {
    220    return false;
    221  }
    222 
    223  if (aDetectRuntimesOnly) {
    224    if (LoadOvrLib()) {
    225      aSystemState.displayState.capabilityFlags |=
    226          VRDisplayCapabilityFlags::Cap_ImmersiveVR;
    227    }
    228    return false;
    229  }
    230 
    231  if (!CreateD3DObjects()) {
    232    return false;
    233  }
    234  if (!CreateShaders()) {
    235    return false;
    236  }
    237  // Ideally, we should move LoadOvrLib() up to the first line to avoid
    238  // unnecessary D3D objects creation. But it will cause a WPT fail in Win 7
    239  // debug.
    240  if (!LoadOvrLib()) {
    241    return false;
    242  }
    243  // We start off with an invisible session, then re-initialize
    244  // with visible session once WebVR content starts rendering.
    245  if (!ChangeVisibility(false)) {
    246    return false;
    247  }
    248  if (!InitState(aSystemState)) {
    249    return false;
    250  }
    251 
    252  mPresentationSize = IntSize(aSystemState.displayState.eyeResolution.width * 2,
    253                              aSystemState.displayState.eyeResolution.height);
    254  return true;
    255 }
    256 
    257 void OculusSession::UpdateVisibility() {
    258  // Do not immediately re-initialize with an invisible session after
    259  // the end of a VR presentation.  Waiting for the configured duraction
    260  // ensures that the user will not drop to Oculus Home during VR link
    261  // traversal.
    262  if (mIsPresenting) {
    263    // We are currently rendering immersive content.
    264    // Avoid interrupting the session
    265    return;
    266  }
    267  if (mInitFlags & ovrInit_Invisible) {
    268    // We are already invisible
    269    return;
    270  }
    271  if (mLastPresentationEnd.IsNull()) {
    272    // There has been no presentation yet
    273    return;
    274  }
    275 
    276  TimeDuration duration = TimeStamp::Now() - mLastPresentationEnd;
    277  TimeDuration timeout = TimeDuration::FromMilliseconds(
    278      StaticPrefs::dom_vr_oculus_present_timeout());
    279  if (timeout <= TimeDuration(0) || duration >= timeout) {
    280    if (!ChangeVisibility(false)) {
    281      gfxWarning() << "OculusSession::ChangeVisibility(false) failed";
    282    }
    283  }
    284 }
    285 
    286 void OculusSession::CoverTransitions() {
    287  // While content is loading or during immersive-mode link
    288  // traversal, we need to prevent the user from seeing the
    289  // last rendered frame.
    290  // We render black frames to cover up the transition.
    291  MOZ_ASSERT(mSession);
    292  if (mIsPresenting) {
    293    // We are currently rendering immersive content.
    294    // Avoid interrupting the session
    295    return;
    296  }
    297 
    298  if (mInitFlags & ovrInit_Invisible) {
    299    // We are invisible, nothing to cover up
    300    return;
    301  }
    302 
    303  // Render a black frame
    304  ovrLayerEyeFov layer;
    305  memset(&layer, 0, sizeof(layer));
    306  layer.Header.Type = ovrLayerType_Disabled;
    307  ovrLayerHeader* layers = &layer.Header;
    308  ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1);
    309 }
    310 
    311 bool OculusSession::ChangeVisibility(bool bVisible) {
    312  ovrInitFlags flags =
    313      (ovrInitFlags)(ovrInit_RequestVersion | ovrInit_MixedRendering);
    314  if (StaticPrefs::dom_vr_oculus_invisible_enabled() && !bVisible) {
    315    flags = (ovrInitFlags)(flags | ovrInit_Invisible);
    316  }
    317  if (mInitFlags == flags) {
    318    // The new state is the same, nothing to do
    319    return true;
    320  }
    321 
    322  // Tear everything down
    323  StopRendering();
    324  StopSession();
    325  StopLib();
    326 
    327  // Start it back up
    328  if (!StartLib(flags)) {
    329    return false;
    330  }
    331  if (!StartSession()) {
    332    return false;
    333  }
    334  return true;
    335 }
    336 
    337 void OculusSession::Shutdown() {
    338  StopRendering();
    339  StopSession();
    340  StopLib();
    341  UnloadOvrLib();
    342  DestroyShaders();
    343 }
    344 
    345 void OculusSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) {
    346  if (!mSession) {
    347    return;
    348  }
    349 
    350  ovrSessionStatus status;
    351  if (OVR_SUCCESS(ovr_GetSessionStatus(mSession, &status))) {
    352    aSystemState.displayState.isConnected = status.HmdPresent;
    353    aSystemState.displayState.isMounted = status.HmdMounted;
    354    mShouldQuit = status.ShouldQuit;
    355 
    356  } else {
    357    aSystemState.displayState.isConnected = false;
    358    aSystemState.displayState.isMounted = false;
    359  }
    360  UpdateHaptics();
    361  UpdateVisibility();
    362  CoverTransitions();
    363 }
    364 
    365 void OculusSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState) {
    366  UpdateHeadsetPose(aSystemState);
    367  UpdateEyeParameters(aSystemState);
    368  UpdateControllers(aSystemState);
    369  UpdateTelemetry(aSystemState);
    370  aSystemState.sensorState.inputFrameID++;
    371 }
    372 
    373 bool OculusSession::StartPresentation() {
    374  /**
    375   * XXX - We should resolve fail the promise returned by
    376   *       VRDisplay.requestPresent() when the DX11 resources fail allocation
    377   *       in VRDisplayOculus::StartPresentation().
    378   *       Bailing out here prevents the crash but content should be aware
    379   *       that frames are not being presented.
    380   *       See Bug 1299309.
    381   **/
    382  if (!ChangeVisibility(true)) {
    383    return false;
    384  }
    385  if (!StartRendering()) {
    386    StopRendering();
    387    return false;
    388  }
    389  mIsPresenting = true;
    390  return true;
    391 }
    392 
    393 void OculusSession::StopPresentation() {
    394  mLastPresentationEnd = TimeStamp::Now();
    395  mIsPresenting = false;
    396 }
    397 
    398 bool OculusSession::SubmitFrame(
    399    const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
    400    ID3D11Texture2D* aTexture) {
    401  if (!IsPresentationReady()) {
    402    return false;
    403  }
    404 
    405  D3D11_TEXTURE2D_DESC textureDesc = {0};
    406  aTexture->GetDesc(&textureDesc);
    407 
    408  int currentRenderTarget = 0;
    409  ovrResult orv = ovr_GetTextureSwapChainCurrentIndex(mSession, mTextureSet,
    410                                                      &currentRenderTarget);
    411  if (orv != ovrSuccess) {
    412    NS_WARNING("ovr_GetTextureSwapChainCurrentIndex failed.");
    413    return false;
    414  }
    415 
    416  ID3D11RenderTargetView* view = mRTView[currentRenderTarget];
    417 
    418  float clear[] = {0.0f, 0.0f, 0.0f, 1.0f};
    419  mContext->ClearRenderTargetView(view, clear);
    420  mContext->OMSetRenderTargets(1, &view, nullptr);
    421 
    422  Matrix viewMatrix = Matrix::Translation(-1.0, 1.0);
    423  viewMatrix.PreScale(2.0f / float(textureDesc.Width),
    424                      2.0f / float(textureDesc.Height));
    425  viewMatrix.PreScale(1.0f, -1.0f);
    426  Matrix4x4 projection = Matrix4x4::From2D(viewMatrix);
    427  projection._33 = 0.0f;
    428 
    429  Matrix transform2d;
    430  gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
    431 
    432  D3D11_VIEWPORT viewport;
    433  viewport.MinDepth = 0.0f;
    434  viewport.MaxDepth = 1.0f;
    435  viewport.Width = textureDesc.Width;
    436  viewport.Height = textureDesc.Height;
    437  viewport.TopLeftX = 0;
    438  viewport.TopLeftY = 0;
    439 
    440  D3D11_RECT scissor;
    441  scissor.left = 0;
    442  scissor.right = textureDesc.Width;
    443  scissor.top = 0;
    444  scissor.bottom = textureDesc.Height;
    445 
    446  memcpy(&mVSConstants.layerTransform, &transform._11,
    447         sizeof(mVSConstants.layerTransform));
    448  memcpy(&mVSConstants.projection, &projection._11,
    449         sizeof(mVSConstants.projection));
    450  mVSConstants.renderTargetOffset[0] = 0.0f;
    451  mVSConstants.renderTargetOffset[1] = 0.0f;
    452  mVSConstants.layerQuad =
    453      Rect(0.0f, 0.0f, textureDesc.Width, textureDesc.Height);
    454  mVSConstants.textureCoords = Rect(0.0f, 1.0f, 1.0f, -1.0f);
    455 
    456  mPSConstants.layerOpacity[0] = 1.0f;
    457 
    458  ID3D11Buffer* vbuffer = mVertexBuffer;
    459  UINT vsize = sizeof(Vertex);
    460  UINT voffset = 0;
    461  mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
    462  mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
    463  mContext->IASetInputLayout(mInputLayout);
    464  mContext->RSSetViewports(1, &viewport);
    465  mContext->RSSetScissorRects(1, &scissor);
    466  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
    467  mContext->VSSetShader(mQuadVS, nullptr, 0);
    468  mContext->PSSetShader(mQuadPS, nullptr, 0);
    469 
    470  RefPtr<ID3D11ShaderResourceView> srView;
    471  HRESULT hr = mDevice->CreateShaderResourceView(aTexture, nullptr,
    472                                                 getter_AddRefs(srView));
    473  if (FAILED(hr)) {
    474    gfxWarning() << "Could not create shader resource view for Oculus: "
    475                 << hexa(hr);
    476    return false;
    477  }
    478  ID3D11ShaderResourceView* viewPtr = srView.get();
    479  mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &viewPtr);
    480  // XXX Use Constant from TexSlot in CompositorD3D11.cpp?
    481 
    482  ID3D11SamplerState* sampler = mLinearSamplerState;
    483  mContext->PSSetSamplers(0, 1, &sampler);
    484 
    485  if (!UpdateConstantBuffers()) {
    486    NS_WARNING("Failed to update constant buffers for Oculus");
    487    return false;
    488  }
    489 
    490  mContext->Draw(4, 0);
    491 
    492  orv = ovr_CommitTextureSwapChain(mSession, mTextureSet);
    493  if (orv != ovrSuccess) {
    494    NS_WARNING("ovr_CommitTextureSwapChain failed.");
    495    return false;
    496  }
    497 
    498  ovrLayerEyeFov layer;
    499  memset(&layer, 0, sizeof(layer));
    500  layer.Header.Type = ovrLayerType_EyeFov;
    501  layer.Header.Flags = 0;
    502  layer.ColorTexture[0] = mTextureSet;
    503  layer.ColorTexture[1] = nullptr;
    504  layer.Fov[0] = mFOVPort[0];
    505  layer.Fov[1] = mFOVPort[1];
    506  layer.Viewport[0].Pos.x = textureDesc.Width * aLayer.leftEyeRect.x;
    507  layer.Viewport[0].Pos.y = textureDesc.Height * aLayer.leftEyeRect.y;
    508  layer.Viewport[0].Size.w = textureDesc.Width * aLayer.leftEyeRect.width;
    509  layer.Viewport[0].Size.h = textureDesc.Height * aLayer.leftEyeRect.height;
    510  layer.Viewport[1].Pos.x = textureDesc.Width * aLayer.rightEyeRect.x;
    511  layer.Viewport[1].Pos.y = textureDesc.Height * aLayer.rightEyeRect.y;
    512  layer.Viewport[1].Size.w = textureDesc.Width * aLayer.rightEyeRect.width;
    513  layer.Viewport[1].Size.h = textureDesc.Height * aLayer.rightEyeRect.height;
    514 
    515  for (uint32_t i = 0; i < 2; ++i) {
    516    layer.RenderPose[i].Orientation.x = mFrameStartPose[i].Orientation.x;
    517    layer.RenderPose[i].Orientation.y = mFrameStartPose[i].Orientation.y;
    518    layer.RenderPose[i].Orientation.z = mFrameStartPose[i].Orientation.z;
    519    layer.RenderPose[i].Orientation.w = mFrameStartPose[i].Orientation.w;
    520    layer.RenderPose[i].Position.x = mFrameStartPose[i].Position.x;
    521    layer.RenderPose[i].Position.y = mFrameStartPose[i].Position.y;
    522    layer.RenderPose[i].Position.z = mFrameStartPose[i].Position.z;
    523  }
    524 
    525  ovrLayerHeader* layers = &layer.Header;
    526  orv = ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1);
    527  // ovr_SubmitFrame will fail during the Oculus health and safety warning.
    528  // and will start succeeding once the warning has been dismissed by the user.
    529 
    530  if (!OVR_UNQUALIFIED_SUCCESS(orv)) {
    531    /**
    532     * We wish to throttle the framerate for any case that the rendered
    533     * result is not visible.  In some cases, such as during the Oculus
    534     * "health and safety warning", orv will be > 0 (OVR_SUCCESS but not
    535     * OVR_UNQUALIFIED_SUCCESS) and ovr_SubmitFrame will not block.
    536     * In this case, returning true would have resulted in an unthrottled
    537     * render loop hiting excessive frame rates and consuming resources.
    538     */
    539    return false;
    540  }
    541 
    542  return true;
    543 }
    544 
    545 bool OculusSession::LoadOvrLib() {
    546  if (mOvrLib) {
    547    // Already loaded, early exit
    548    return true;
    549  }
    550 #if defined(_WIN32)
    551  nsTArray<nsString> libSearchPaths;
    552  nsString libName;
    553  nsString searchPath;
    554 
    555  for (;;) {
    556    UINT requiredLength = ::GetSystemDirectoryW(
    557        char16ptr_t(searchPath.BeginWriting()), searchPath.Length());
    558    if (!requiredLength) {
    559      break;
    560    }
    561    if (requiredLength < searchPath.Length()) {
    562      searchPath.Truncate(requiredLength);
    563      libSearchPaths.AppendElement(searchPath);
    564      break;
    565    }
    566    searchPath.SetLength(requiredLength);
    567  }
    568  libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
    569 
    570  // search the path/module dir
    571  libSearchPaths.InsertElementsAt(0, 1, u""_ns);
    572 
    573  // If the env var is present, we override libName
    574  if (_wgetenv(L"OVR_LIB_PATH")) {
    575    searchPath = _wgetenv(L"OVR_LIB_PATH");
    576    libSearchPaths.InsertElementsAt(0, 1, searchPath);
    577  }
    578 
    579  if (_wgetenv(L"OVR_LIB_NAME")) {
    580    libName = _wgetenv(L"OVR_LIB_NAME");
    581  }
    582 
    583  if (libName.IsEmpty()) {
    584    return false;
    585  }
    586 
    587  for (uint32_t i = 0; i < libSearchPaths.Length(); ++i) {
    588    nsString& libPath = libSearchPaths[i];
    589    nsString fullName;
    590    if (libPath.Length() == 0) {
    591      fullName.Assign(libName);
    592    } else {
    593      fullName.Assign(libPath + u"\\"_ns + libName);
    594    }
    595 
    596    mOvrLib = LoadLibraryWithFlags(fullName.get());
    597    if (mOvrLib) {
    598      break;
    599    }
    600  }
    601 #else
    602 #  error "Unsupported platform!"
    603 #endif
    604 
    605  if (!mOvrLib) {
    606    return false;
    607  }
    608 
    609 #define REQUIRE_FUNCTION(_x)                           \
    610  do {                                                 \
    611    *(void**)&_x = (void*)PR_FindSymbol(mOvrLib, #_x); \
    612    if (!_x) {                                         \
    613      printf_stderr(#_x " symbol missing\n");          \
    614      goto fail;                                       \
    615    }                                                  \
    616  } while (0)
    617 
    618  REQUIRE_FUNCTION(ovr_Initialize);
    619  REQUIRE_FUNCTION(ovr_Shutdown);
    620  REQUIRE_FUNCTION(ovr_GetLastErrorInfo);
    621  REQUIRE_FUNCTION(ovr_GetVersionString);
    622  REQUIRE_FUNCTION(ovr_TraceMessage);
    623  REQUIRE_FUNCTION(ovr_IdentifyClient);
    624  REQUIRE_FUNCTION(ovr_GetHmdDesc);
    625  REQUIRE_FUNCTION(ovr_GetTrackerCount);
    626  REQUIRE_FUNCTION(ovr_GetTrackerDesc);
    627  REQUIRE_FUNCTION(ovr_Create);
    628  REQUIRE_FUNCTION(ovr_Destroy);
    629  REQUIRE_FUNCTION(ovr_GetSessionStatus);
    630  REQUIRE_FUNCTION(ovr_IsExtensionSupported);
    631  REQUIRE_FUNCTION(ovr_EnableExtension);
    632  REQUIRE_FUNCTION(ovr_SetTrackingOriginType);
    633  REQUIRE_FUNCTION(ovr_GetTrackingOriginType);
    634  REQUIRE_FUNCTION(ovr_RecenterTrackingOrigin);
    635  REQUIRE_FUNCTION(ovr_SpecifyTrackingOrigin);
    636  REQUIRE_FUNCTION(ovr_ClearShouldRecenterFlag);
    637  REQUIRE_FUNCTION(ovr_GetTrackingState);
    638  REQUIRE_FUNCTION(ovr_GetDevicePoses);
    639  REQUIRE_FUNCTION(ovr_GetTrackerPose);
    640  REQUIRE_FUNCTION(ovr_GetInputState);
    641  REQUIRE_FUNCTION(ovr_GetConnectedControllerTypes);
    642  REQUIRE_FUNCTION(ovr_GetTouchHapticsDesc);
    643  REQUIRE_FUNCTION(ovr_SetControllerVibration);
    644  REQUIRE_FUNCTION(ovr_SubmitControllerVibration);
    645  REQUIRE_FUNCTION(ovr_GetControllerVibrationState);
    646  REQUIRE_FUNCTION(ovr_TestBoundary);
    647  REQUIRE_FUNCTION(ovr_TestBoundaryPoint);
    648  REQUIRE_FUNCTION(ovr_SetBoundaryLookAndFeel);
    649  REQUIRE_FUNCTION(ovr_ResetBoundaryLookAndFeel);
    650  REQUIRE_FUNCTION(ovr_GetBoundaryGeometry);
    651  REQUIRE_FUNCTION(ovr_GetBoundaryDimensions);
    652  REQUIRE_FUNCTION(ovr_GetBoundaryVisible);
    653  REQUIRE_FUNCTION(ovr_RequestBoundaryVisible);
    654  REQUIRE_FUNCTION(ovr_GetTextureSwapChainLength);
    655  REQUIRE_FUNCTION(ovr_GetTextureSwapChainCurrentIndex);
    656  REQUIRE_FUNCTION(ovr_GetTextureSwapChainDesc);
    657  REQUIRE_FUNCTION(ovr_CommitTextureSwapChain);
    658  REQUIRE_FUNCTION(ovr_DestroyTextureSwapChain);
    659  REQUIRE_FUNCTION(ovr_DestroyMirrorTexture);
    660  REQUIRE_FUNCTION(ovr_GetFovTextureSize);
    661  REQUIRE_FUNCTION(ovr_GetRenderDesc2);
    662  REQUIRE_FUNCTION(ovr_WaitToBeginFrame);
    663  REQUIRE_FUNCTION(ovr_BeginFrame);
    664  REQUIRE_FUNCTION(ovr_EndFrame);
    665  REQUIRE_FUNCTION(ovr_SubmitFrame);
    666  REQUIRE_FUNCTION(ovr_GetPerfStats);
    667  REQUIRE_FUNCTION(ovr_ResetPerfStats);
    668  REQUIRE_FUNCTION(ovr_GetPredictedDisplayTime);
    669  REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
    670  REQUIRE_FUNCTION(ovr_GetBool);
    671  REQUIRE_FUNCTION(ovr_SetBool);
    672  REQUIRE_FUNCTION(ovr_GetInt);
    673  REQUIRE_FUNCTION(ovr_SetInt);
    674  REQUIRE_FUNCTION(ovr_GetFloat);
    675  REQUIRE_FUNCTION(ovr_SetFloat);
    676  REQUIRE_FUNCTION(ovr_GetFloatArray);
    677  REQUIRE_FUNCTION(ovr_SetFloatArray);
    678  REQUIRE_FUNCTION(ovr_GetString);
    679  REQUIRE_FUNCTION(ovr_SetString);
    680  REQUIRE_FUNCTION(ovr_GetExternalCameras);
    681  REQUIRE_FUNCTION(ovr_SetExternalCameraProperties);
    682 
    683 #ifdef XP_WIN
    684 
    685  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainDX);
    686  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferDX);
    687  REQUIRE_FUNCTION(ovr_CreateMirrorTextureDX);
    688  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferDX);
    689 
    690 #endif
    691 
    692  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainGL);
    693  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferGL);
    694  REQUIRE_FUNCTION(ovr_CreateMirrorTextureGL);
    695  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferGL);
    696 
    697 #undef REQUIRE_FUNCTION
    698 
    699  return true;
    700 
    701 fail:
    702  ovr_Initialize = nullptr;
    703  PR_UnloadLibrary(mOvrLib);
    704  mOvrLib = nullptr;
    705  return false;
    706 }
    707 
    708 void OculusSession::UnloadOvrLib() {
    709  if (mOvrLib) {
    710    PR_UnloadLibrary(mOvrLib);
    711    mOvrLib = nullptr;
    712  }
    713 }
    714 
    715 bool OculusSession::StartLib(ovrInitFlags aFlags) {
    716  if (mInitFlags == 0) {
    717    ovrInitParams params;
    718    memset(&params, 0, sizeof(params));
    719    params.Flags = aFlags;
    720    params.RequestedMinorVersion = OVR_MINOR_VERSION;
    721    params.LogCallback = nullptr;
    722    params.ConnectionTimeoutMS = 0;
    723 
    724    ovrResult orv = ovr_Initialize(&params);
    725 
    726    if (orv == ovrSuccess) {
    727      mInitFlags = aFlags;
    728    } else {
    729      return false;
    730    }
    731  }
    732  MOZ_ASSERT(mInitFlags == aFlags);
    733  return true;
    734 }
    735 
    736 void OculusSession::StopLib() {
    737  if (mInitFlags) {
    738    ovr_Shutdown();
    739    mInitFlags = (ovrInitFlags)0;
    740  }
    741 }
    742 
    743 bool OculusSession::StartSession() {
    744  // ovr_Create can be slow when no HMD is present and we wish
    745  // to keep the same oculus session when possible, so we detect
    746  // presence of an HMD with ovr_GetHmdDesc before calling ovr_Create
    747  ovrHmdDesc desc = ovr_GetHmdDesc(NULL);
    748  if (desc.Type == ovrHmd_None) {
    749    // No HMD connected, destroy any existing session
    750    if (mSession) {
    751      ovr_Destroy(mSession);
    752      mSession = nullptr;
    753    }
    754    return false;
    755  }
    756  if (mSession != nullptr) {
    757    // HMD Detected and we already have a session, let's keep using it.
    758    return true;
    759  }
    760 
    761  // HMD Detected and we don't have a session yet,
    762  // try to create a new session
    763  ovrSession session;
    764  ovrGraphicsLuid luid;
    765  ovrResult orv = ovr_Create(&session, &luid);
    766  if (orv == ovrSuccess) {
    767    orv = ovr_SetTrackingOriginType(session, ovrTrackingOrigin_FloorLevel);
    768    if (orv != ovrSuccess) {
    769      NS_WARNING("ovr_SetTrackingOriginType failed.\n");
    770    }
    771    mSession = session;
    772    return true;
    773  }
    774 
    775  // Failed to create a session for the HMD
    776  return false;
    777 }
    778 
    779 void OculusSession::StopSession() {
    780  if (mSession) {
    781    ovr_Destroy(mSession);
    782    mSession = nullptr;
    783  }
    784 }
    785 
    786 bool OculusSession::CreateD3DObjects() {
    787  RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetVRDevice();
    788  if (!device) {
    789    return false;
    790  }
    791  if (!CreateD3DContext(device)) {
    792    return false;
    793  }
    794  return true;
    795 }
    796 
    797 bool OculusSession::CreateShaders() {
    798  if (!mQuadVS) {
    799    if (FAILED(mDevice->CreateVertexShader(
    800            sLayerQuadVS.mData, sLayerQuadVS.mLength, nullptr, &mQuadVS))) {
    801      NS_WARNING("Failed to create vertex shader for Oculus");
    802      return false;
    803    }
    804  }
    805 
    806  if (!mQuadPS) {
    807    if (FAILED(mDevice->CreatePixelShader(sRGBShader.mData, sRGBShader.mLength,
    808                                          nullptr, &mQuadPS))) {
    809      NS_WARNING("Failed to create pixel shader for Oculus");
    810      return false;
    811    }
    812  }
    813 
    814  CD3D11_BUFFER_DESC cBufferDesc(sizeof(layers::VertexShaderConstants),
    815                                 D3D11_BIND_CONSTANT_BUFFER,
    816                                 D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
    817 
    818  if (!mVSConstantBuffer) {
    819    if (FAILED(mDevice->CreateBuffer(&cBufferDesc, nullptr,
    820                                     getter_AddRefs(mVSConstantBuffer)))) {
    821      NS_WARNING("Failed to vertex shader constant buffer for Oculus");
    822      return false;
    823    }
    824  }
    825 
    826  if (!mPSConstantBuffer) {
    827    cBufferDesc.ByteWidth = sizeof(layers::PixelShaderConstants);
    828    if (FAILED(mDevice->CreateBuffer(&cBufferDesc, nullptr,
    829                                     getter_AddRefs(mPSConstantBuffer)))) {
    830      NS_WARNING("Failed to pixel shader constant buffer for Oculus");
    831      return false;
    832    }
    833  }
    834 
    835  if (!mLinearSamplerState) {
    836    CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
    837    if (FAILED(mDevice->CreateSamplerState(
    838            &samplerDesc, getter_AddRefs(mLinearSamplerState)))) {
    839      NS_WARNING("Failed to create sampler state for Oculus");
    840      return false;
    841    }
    842  }
    843 
    844  if (!mInputLayout) {
    845    D3D11_INPUT_ELEMENT_DESC layout[] = {
    846        {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
    847         D3D11_INPUT_PER_VERTEX_DATA, 0},
    848    };
    849 
    850    if (FAILED(mDevice->CreateInputLayout(
    851            layout, sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
    852            sLayerQuadVS.mData, sLayerQuadVS.mLength,
    853            getter_AddRefs(mInputLayout)))) {
    854      NS_WARNING("Failed to create input layout for Oculus");
    855      return false;
    856    }
    857  }
    858 
    859  if (!mVertexBuffer) {
    860    Vertex vertices[] = {
    861        {{0.0, 0.0}}, {{1.0, 0.0}}, {{0.0, 1.0}}, {{1.0, 1.0}}};
    862    CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
    863    D3D11_SUBRESOURCE_DATA data;
    864    data.pSysMem = (void*)vertices;
    865 
    866    if (FAILED(mDevice->CreateBuffer(&bufferDesc, &data,
    867                                     getter_AddRefs(mVertexBuffer)))) {
    868      NS_WARNING("Failed to create vertex buffer for Oculus");
    869      return false;
    870    }
    871  }
    872 
    873  memset(&mVSConstants, 0, sizeof(mVSConstants));
    874  memset(&mPSConstants, 0, sizeof(mPSConstants));
    875  return true;
    876 }
    877 
    878 void OculusSession::DestroyShaders() {}
    879 
    880 bool OculusSession::UpdateConstantBuffers() {
    881  HRESULT hr;
    882  D3D11_MAPPED_SUBRESOURCE resource;
    883  resource.pData = nullptr;
    884 
    885  hr = mContext->Map(mVSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0,
    886                     &resource);
    887  if (FAILED(hr) || !resource.pData) {
    888    return false;
    889  }
    890  *(VertexShaderConstants*)resource.pData = mVSConstants;
    891  mContext->Unmap(mVSConstantBuffer, 0);
    892  resource.pData = nullptr;
    893 
    894  hr = mContext->Map(mPSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0,
    895                     &resource);
    896  if (FAILED(hr) || !resource.pData) {
    897    return false;
    898  }
    899  *(PixelShaderConstants*)resource.pData = mPSConstants;
    900  mContext->Unmap(mPSConstantBuffer, 0);
    901 
    902  ID3D11Buffer* buffer = mVSConstantBuffer;
    903  mContext->VSSetConstantBuffers(0, 1, &buffer);
    904  buffer = mPSConstantBuffer;
    905  mContext->PSSetConstantBuffers(0, 1, &buffer);
    906  return true;
    907 }
    908 
    909 bool OculusSession::StartRendering() {
    910  if (!mTextureSet) {
    911    /**
    912     * The presentation format is determined by content, which describes the
    913     * left and right eye rectangles in the VRLayer.  The default, if no
    914     * coordinates are passed is to place the left and right eye textures
    915     * side-by-side within the buffer.
    916     *
    917     * XXX - An optimization would be to dynamically resize this buffer
    918     *       to accomodate sites that are choosing to render in a lower
    919     *       resolution or are using space outside of the left and right
    920     *       eye textures for other purposes.  (Bug 1291443)
    921     */
    922 
    923    ovrTextureSwapChainDesc desc;
    924    memset(&desc, 0, sizeof(desc));
    925    desc.Type = ovrTexture_2D;
    926    desc.ArraySize = 1;
    927    desc.Format = OVR_FORMAT_B8G8R8A8_UNORM_SRGB;
    928    desc.Width = mPresentationSize.width;
    929    desc.Height = mPresentationSize.height;
    930    desc.MipLevels = 1;
    931    desc.SampleCount = 1;
    932    desc.StaticImage = false;
    933    desc.MiscFlags = ovrTextureMisc_DX_Typeless;
    934    desc.BindFlags = ovrTextureBind_DX_RenderTarget;
    935 
    936    ovrResult orv =
    937        ovr_CreateTextureSwapChainDX(mSession, mDevice, &desc, &mTextureSet);
    938    if (orv != ovrSuccess) {
    939      NS_WARNING("ovr_CreateTextureSwapChainDX failed");
    940      return false;
    941    }
    942 
    943    int textureCount = 0;
    944    orv = ovr_GetTextureSwapChainLength(mSession, mTextureSet, &textureCount);
    945    if (orv != ovrSuccess) {
    946      NS_WARNING("ovr_GetTextureSwapChainLength failed");
    947      return false;
    948    }
    949    mTexture.SetLength(textureCount);
    950    mRTView.SetLength(textureCount);
    951    mSRV.SetLength(textureCount);
    952    for (int i = 0; i < textureCount; ++i) {
    953      ID3D11Texture2D* texture = nullptr;
    954      orv = ovr_GetTextureSwapChainBufferDX(mSession, mTextureSet, i,
    955                                            IID_PPV_ARGS(&texture));
    956      if (orv != ovrSuccess) {
    957        NS_WARNING("Failed to create Oculus texture swap chain.");
    958        return false;
    959      }
    960 
    961      RefPtr<ID3D11RenderTargetView> rtView;
    962      CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D,
    963                                             DXGI_FORMAT_B8G8R8A8_UNORM);
    964      HRESULT hr = mDevice->CreateRenderTargetView(texture, &rtvDesc,
    965                                                   getter_AddRefs(rtView));
    966      if (FAILED(hr)) {
    967        NS_WARNING(
    968            "Failed to create RenderTargetView for Oculus texture swap chain.");
    969        texture->Release();
    970        return false;
    971      }
    972 
    973      RefPtr<ID3D11ShaderResourceView> srv;
    974      CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(D3D11_SRV_DIMENSION_TEXTURE2D,
    975                                               DXGI_FORMAT_B8G8R8A8_UNORM);
    976      hr = mDevice->CreateShaderResourceView(texture, &srvDesc,
    977                                             getter_AddRefs(srv));
    978      if (FAILED(hr)) {
    979        NS_WARNING(
    980            "Failed to create ShaderResourceView for Oculus texture swap "
    981            "chain.");
    982        texture->Release();
    983        return false;
    984      }
    985 
    986      mTexture[i] = texture;
    987      mRTView[i] = rtView;
    988      mSRV[i] = srv;
    989      texture->Release();
    990    }
    991  }
    992  return true;
    993 }
    994 
    995 bool OculusSession::IsPresentationReady() const {
    996  return mTextureSet != nullptr;
    997 }
    998 
    999 void OculusSession::StopRendering() {
   1000  mSRV.Clear();
   1001  mRTView.Clear();
   1002  mTexture.Clear();
   1003 
   1004  if (mTextureSet && mSession) {
   1005    ovr_DestroyTextureSwapChain(mSession, mTextureSet);
   1006  }
   1007  mTextureSet = nullptr;
   1008  mIsPresenting = false;
   1009 }
   1010 
   1011 bool OculusSession::InitState(VRSystemState& aSystemState) {
   1012  VRDisplayState& state = aSystemState.displayState;
   1013  strncpy(state.displayName.data(), "Oculus VR HMD", kVRDisplayNameMaxLen);
   1014  state.isConnected = true;
   1015  state.isMounted = false;
   1016 
   1017  ovrHmdDesc desc = ovr_GetHmdDesc(mSession);
   1018 
   1019  state.capabilityFlags = VRDisplayCapabilityFlags::Cap_None;
   1020  if (desc.AvailableTrackingCaps & ovrTrackingCap_Orientation) {
   1021    state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_Orientation;
   1022    state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
   1023  }
   1024  if (desc.AvailableTrackingCaps & ovrTrackingCap_Position) {
   1025    state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_Position;
   1026    state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
   1027    state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_StageParameters;
   1028  }
   1029  state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
   1030  state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_MountDetection;
   1031  state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
   1032  state.capabilityFlags |= VRDisplayCapabilityFlags::Cap_ImmersiveVR;
   1033  state.blendMode = VRDisplayBlendMode::Opaque;
   1034  state.reportsDroppedFrames = true;
   1035 
   1036  mFOVPort[VRDisplayState::Eye_Left] = desc.DefaultEyeFov[ovrEye_Left];
   1037  mFOVPort[VRDisplayState::Eye_Right] = desc.DefaultEyeFov[ovrEye_Right];
   1038 
   1039  state.eyeFOV[VRDisplayState::Eye_Left] =
   1040      FromFovPort(mFOVPort[VRDisplayState::Eye_Left]);
   1041  state.eyeFOV[VRDisplayState::Eye_Right] =
   1042      FromFovPort(mFOVPort[VRDisplayState::Eye_Right]);
   1043 
   1044  float pixelsPerDisplayPixel = 1.0;
   1045  ovrSizei texSize[2];
   1046 
   1047  // get eye texture sizes
   1048  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
   1049    texSize[eye] = ovr_GetFovTextureSize(mSession, (ovrEyeType)eye,
   1050                                         mFOVPort[eye], pixelsPerDisplayPixel);
   1051  }
   1052 
   1053  // take the max of both for eye resolution
   1054  state.eyeResolution.width = std::max(texSize[VRDisplayState::Eye_Left].w,
   1055                                       texSize[VRDisplayState::Eye_Right].w);
   1056  state.eyeResolution.height = std::max(texSize[VRDisplayState::Eye_Left].h,
   1057                                        texSize[VRDisplayState::Eye_Right].h);
   1058  state.nativeFramebufferScaleFactor = 1.0f;
   1059 
   1060  // default to an identity quaternion
   1061  aSystemState.sensorState.pose.orientation[3] = 1.0f;
   1062 
   1063  UpdateStageParameters(state);
   1064  UpdateEyeParameters(aSystemState);
   1065 
   1066  VRHMDSensorState& sensorState = aSystemState.sensorState;
   1067  sensorState.flags =
   1068      (VRDisplayCapabilityFlags)((int)
   1069                                     VRDisplayCapabilityFlags::Cap_Orientation |
   1070                                 (int)VRDisplayCapabilityFlags::Cap_Position);
   1071  sensorState.pose.orientation[3] = 1.0f;  // Default to an identity quaternion
   1072 
   1073  return true;
   1074 }
   1075 
   1076 void OculusSession::UpdateStageParameters(VRDisplayState& aState) {
   1077  ovrVector3f playArea;
   1078  ovrResult res =
   1079      ovr_GetBoundaryDimensions(mSession, ovrBoundary_PlayArea, &playArea);
   1080  if (res == ovrSuccess) {
   1081    aState.stageSize.width = playArea.x;
   1082    aState.stageSize.height = playArea.z;
   1083  } else {
   1084    // If we fail, fall back to reasonable defaults.
   1085    // 1m x 1m space
   1086    aState.stageSize.width = 1.0f;
   1087    aState.stageSize.height = 1.0f;
   1088  }
   1089 
   1090  float eyeHeight =
   1091      ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
   1092 
   1093  aState.sittingToStandingTransform[0] = 1.0f;
   1094  aState.sittingToStandingTransform[1] = 0.0f;
   1095  aState.sittingToStandingTransform[2] = 0.0f;
   1096  aState.sittingToStandingTransform[3] = 0.0f;
   1097 
   1098  aState.sittingToStandingTransform[4] = 0.0f;
   1099  aState.sittingToStandingTransform[5] = 1.0f;
   1100  aState.sittingToStandingTransform[6] = 0.0f;
   1101  aState.sittingToStandingTransform[7] = 0.0f;
   1102 
   1103  aState.sittingToStandingTransform[8] = 0.0f;
   1104  aState.sittingToStandingTransform[9] = 0.0f;
   1105  aState.sittingToStandingTransform[10] = 1.0f;
   1106  aState.sittingToStandingTransform[11] = 0.0f;
   1107 
   1108  aState.sittingToStandingTransform[12] = 0.0f;
   1109  aState.sittingToStandingTransform[13] = eyeHeight;
   1110  aState.sittingToStandingTransform[14] = 0.0f;
   1111  aState.sittingToStandingTransform[15] = 1.0f;
   1112 }
   1113 
   1114 void OculusSession::UpdateEyeParameters(VRSystemState& aState) {
   1115  if (!mSession) {
   1116    return;
   1117  }
   1118  // This must be called every frame in order to
   1119  // account for continuous adjustments to ipd.
   1120  gfx::Matrix4x4 headToEyeTransforms[2];
   1121  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
   1122    // As of Oculus 1.17 SDK, we must use the ovr_GetRenderDesc2 function to
   1123    // return the updated version of ovrEyeRenderDesc.  This is normally done by
   1124    // the Oculus static lib shim, but we need to do this explicitly as we are
   1125    // loading the Oculus runtime dll directly.
   1126    ovrEyeRenderDesc renderDesc =
   1127        ovr_GetRenderDesc2(mSession, (ovrEyeType)eye, mFOVPort[eye]);
   1128    aState.displayState.eyeTranslation[eye].x =
   1129        renderDesc.HmdToEyePose.Position.x;
   1130    aState.displayState.eyeTranslation[eye].y =
   1131        renderDesc.HmdToEyePose.Position.y;
   1132    aState.displayState.eyeTranslation[eye].z =
   1133        renderDesc.HmdToEyePose.Position.z;
   1134 
   1135    Matrix4x4 pose;
   1136    pose.SetRotationFromQuaternion(
   1137        gfx::Quaternion(-renderDesc.HmdToEyePose.Orientation.x,
   1138                        -renderDesc.HmdToEyePose.Orientation.y,
   1139                        -renderDesc.HmdToEyePose.Orientation.z,
   1140                        renderDesc.HmdToEyePose.Orientation.w));
   1141    pose.PreTranslate(renderDesc.HmdToEyePose.Position.x,
   1142                      renderDesc.HmdToEyePose.Position.y,
   1143                      renderDesc.HmdToEyePose.Position.z);
   1144    pose.Invert();
   1145    headToEyeTransforms[eye] = pose;
   1146  }
   1147  aState.sensorState.CalcViewMatrices(headToEyeTransforms);
   1148 
   1149  Matrix4x4 matView[2];
   1150  memcpy(matView[0].components, aState.sensorState.leftViewMatrix.data(),
   1151         sizeof(float) * 16);
   1152  memcpy(matView[1].components, aState.sensorState.rightViewMatrix.data(),
   1153         sizeof(float) * 16);
   1154 
   1155  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
   1156    Point3D eyeTranslation;
   1157    Quaternion eyeRotation;
   1158    Point3D eyeScale;
   1159    if (!matView[eye].Decompose(eyeTranslation, eyeRotation, eyeScale)) {
   1160      NS_WARNING("Failed to decompose eye pose matrix for Oculus");
   1161    }
   1162 
   1163    eyeRotation.Invert();
   1164    mFrameStartPose[eye].Orientation.x = eyeRotation.x;
   1165    mFrameStartPose[eye].Orientation.y = eyeRotation.y;
   1166    mFrameStartPose[eye].Orientation.z = eyeRotation.z;
   1167    mFrameStartPose[eye].Orientation.w = eyeRotation.w;
   1168    mFrameStartPose[eye].Position.x = eyeTranslation.x;
   1169    mFrameStartPose[eye].Position.y = eyeTranslation.y;
   1170    mFrameStartPose[eye].Position.z = eyeTranslation.z;
   1171  }
   1172 }
   1173 
   1174 void OculusSession::UpdateHeadsetPose(VRSystemState& aState) {
   1175  if (!mSession) {
   1176    return;
   1177  }
   1178  double predictedFrameTime = 0.0f;
   1179  if (StaticPrefs::dom_vr_poseprediction_enabled()) {
   1180    // XXX We might need to call ovr_GetPredictedDisplayTime even if we don't
   1181    // use the result. If we don't call it, the Oculus driver will spew out many
   1182    // warnings...
   1183    predictedFrameTime = ovr_GetPredictedDisplayTime(mSession, 0);
   1184  }
   1185  ovrTrackingState trackingState =
   1186      ovr_GetTrackingState(mSession, predictedFrameTime, true);
   1187  ovrPoseStatef& pose(trackingState.HeadPose);
   1188 
   1189  aState.sensorState.timestamp = pose.TimeInSeconds;
   1190 
   1191  if (trackingState.StatusFlags & ovrStatus_OrientationTracked) {
   1192    aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
   1193 
   1194    aState.sensorState.pose.orientation[0] = pose.ThePose.Orientation.x;
   1195    aState.sensorState.pose.orientation[1] = pose.ThePose.Orientation.y;
   1196    aState.sensorState.pose.orientation[2] = pose.ThePose.Orientation.z;
   1197    aState.sensorState.pose.orientation[3] = pose.ThePose.Orientation.w;
   1198 
   1199    aState.sensorState.pose.angularVelocity[0] = pose.AngularVelocity.x;
   1200    aState.sensorState.pose.angularVelocity[1] = pose.AngularVelocity.y;
   1201    aState.sensorState.pose.angularVelocity[2] = pose.AngularVelocity.z;
   1202 
   1203    aState.sensorState.flags |=
   1204        VRDisplayCapabilityFlags::Cap_AngularAcceleration;
   1205 
   1206    aState.sensorState.pose.angularAcceleration[0] = pose.AngularAcceleration.x;
   1207    aState.sensorState.pose.angularAcceleration[1] = pose.AngularAcceleration.y;
   1208    aState.sensorState.pose.angularAcceleration[2] = pose.AngularAcceleration.z;
   1209  } else {
   1210    // default to an identity quaternion
   1211    aState.sensorState.pose.orientation[3] = 1.0f;
   1212  }
   1213 
   1214  if (trackingState.StatusFlags & ovrStatus_PositionTracked) {
   1215    float eyeHeight =
   1216        ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
   1217    aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
   1218 
   1219    aState.sensorState.pose.position[0] = pose.ThePose.Position.x;
   1220    aState.sensorState.pose.position[1] = pose.ThePose.Position.y - eyeHeight;
   1221    aState.sensorState.pose.position[2] = pose.ThePose.Position.z;
   1222 
   1223    aState.sensorState.pose.linearVelocity[0] = pose.LinearVelocity.x;
   1224    aState.sensorState.pose.linearVelocity[1] = pose.LinearVelocity.y;
   1225    aState.sensorState.pose.linearVelocity[2] = pose.LinearVelocity.z;
   1226 
   1227    aState.sensorState.flags |=
   1228        VRDisplayCapabilityFlags::Cap_LinearAcceleration;
   1229 
   1230    aState.sensorState.pose.linearAcceleration[0] = pose.LinearAcceleration.x;
   1231    aState.sensorState.pose.linearAcceleration[1] = pose.LinearAcceleration.y;
   1232    aState.sensorState.pose.linearAcceleration[2] = pose.LinearAcceleration.z;
   1233  }
   1234  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_External;
   1235  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_MountDetection;
   1236  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Present;
   1237 }
   1238 
   1239 void OculusSession::UpdateControllers(VRSystemState& aState) {
   1240  if (!mSession) {
   1241    return;
   1242  }
   1243 
   1244  ovrInputState inputState;
   1245  bool hasInputState = ovr_GetInputState(mSession, ovrControllerType_Touch,
   1246                                         &inputState) == ovrSuccess;
   1247 
   1248  if (!hasInputState) {
   1249    return;
   1250  }
   1251 
   1252  EnumerateControllers(aState, inputState);
   1253  UpdateControllerInputs(aState, inputState);
   1254  UpdateControllerPose(aState, inputState);
   1255 }
   1256 
   1257 void OculusSession::UpdateControllerPose(VRSystemState& aState,
   1258                                         const ovrInputState& aInputState) {
   1259  ovrTrackingState trackingState = ovr_GetTrackingState(mSession, 0.0, false);
   1260  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
   1261    // Left Touch Controller will always be at index 0 and
   1262    // and Right Touch Controller will always be at index 1
   1263    VRControllerState& controllerState = aState.controllerState[handIdx];
   1264    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
   1265      ovrPoseStatef& pose = trackingState.HandPoses[handIdx];
   1266      bool bNewController = !(controllerState.flags &
   1267                              dom::GamepadCapabilityFlags::Cap_Orientation);
   1268      if (bNewController) {
   1269        controllerState.flags |= dom::GamepadCapabilityFlags::Cap_Orientation;
   1270        controllerState.flags |= dom::GamepadCapabilityFlags::Cap_Position;
   1271        controllerState.flags |=
   1272            dom::GamepadCapabilityFlags::Cap_AngularAcceleration;
   1273        controllerState.flags |=
   1274            dom::GamepadCapabilityFlags::Cap_LinearAcceleration;
   1275        controllerState.flags |=
   1276            dom::GamepadCapabilityFlags::Cap_GripSpacePosition;
   1277      }
   1278 
   1279      if (bNewController || trackingState.HandStatusFlags[handIdx] &
   1280                                ovrStatus_OrientationTracked) {
   1281        controllerState.pose.orientation[0] = pose.ThePose.Orientation.x;
   1282        controllerState.pose.orientation[1] = pose.ThePose.Orientation.y;
   1283        controllerState.pose.orientation[2] = pose.ThePose.Orientation.z;
   1284        controllerState.pose.orientation[3] = pose.ThePose.Orientation.w;
   1285        controllerState.pose.angularVelocity[0] = pose.AngularVelocity.x;
   1286        controllerState.pose.angularVelocity[1] = pose.AngularVelocity.y;
   1287        controllerState.pose.angularVelocity[2] = pose.AngularVelocity.z;
   1288        controllerState.pose.angularAcceleration[0] =
   1289            pose.AngularAcceleration.x;
   1290        controllerState.pose.angularAcceleration[1] =
   1291            pose.AngularAcceleration.y;
   1292        controllerState.pose.angularAcceleration[2] =
   1293            pose.AngularAcceleration.z;
   1294        controllerState.isOrientationValid = true;
   1295      } else {
   1296        controllerState.isOrientationValid = false;
   1297      }
   1298      if (bNewController ||
   1299          trackingState.HandStatusFlags[handIdx] & ovrStatus_PositionTracked) {
   1300        controllerState.pose.position[0] = pose.ThePose.Position.x;
   1301        controllerState.pose.position[1] = pose.ThePose.Position.y;
   1302        controllerState.pose.position[2] = pose.ThePose.Position.z;
   1303        controllerState.pose.linearVelocity[0] = pose.LinearVelocity.x;
   1304        controllerState.pose.linearVelocity[1] = pose.LinearVelocity.y;
   1305        controllerState.pose.linearVelocity[2] = pose.LinearVelocity.z;
   1306        controllerState.pose.linearAcceleration[0] = pose.LinearAcceleration.x;
   1307        controllerState.pose.linearAcceleration[1] = pose.LinearAcceleration.y;
   1308        controllerState.pose.linearAcceleration[2] = pose.LinearAcceleration.z;
   1309 
   1310        float eyeHeight =
   1311            ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
   1312        controllerState.pose.position[1] -= eyeHeight;
   1313        controllerState.isPositionValid = true;
   1314      } else {
   1315        controllerState.isPositionValid = false;
   1316      }
   1317      controllerState.targetRayPose = controllerState.pose;
   1318    }
   1319  }
   1320 }
   1321 
   1322 void OculusSession::EnumerateControllers(VRSystemState& aState,
   1323                                         const ovrInputState& aInputState) {
   1324  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
   1325    // Left Touch Controller will always be at index 0 and
   1326    // and Right Touch Controller will always be at index 1
   1327    VRControllerState& controllerState = aState.controllerState[handIdx];
   1328    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
   1329      // Touch Controller detected
   1330      if (controllerState.controllerName[0] == '\0') {
   1331        // Controller has been just enumerated
   1332        strncpy(controllerState.controllerName.data(),
   1333                OculusControllerNames[handIdx],
   1334                controllerState.controllerName.size());
   1335        controllerState.hand = OculusControllerHand[handIdx];
   1336        controllerState.targetRayMode = gfx::TargetRayMode::TrackedPointer;
   1337        controllerState.numButtons = kNumOculusButtons;
   1338        controllerState.numAxes = kNumOculusAxes;
   1339        controllerState.numHaptics = kNumOculusHaptcs;
   1340        controllerState.type = VRControllerType::OculusTouch;
   1341      }
   1342    } else {
   1343      // Touch Controller not detected
   1344      if (controllerState.controllerName[0] != '\0') {
   1345        // Clear any newly disconnected ontrollers
   1346        memset(&controllerState, 0, sizeof(VRControllerState));
   1347      }
   1348    }
   1349  }
   1350 }
   1351 
   1352 void OculusSession::UpdateControllerInputs(VRSystemState& aState,
   1353                                           const ovrInputState& aInputState) {
   1354  const float triggerThreshold =
   1355      StaticPrefs::dom_vr_controller_trigger_threshold();
   1356 
   1357  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
   1358    // Left Touch Controller will always be at index 0 and
   1359    // and Right Touch Controller will always be at index 1
   1360    VRControllerState& controllerState = aState.controllerState[handIdx];
   1361    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
   1362      // Update Button States
   1363      controllerState.buttonPressed = 0;
   1364      controllerState.buttonTouched = 0;
   1365      uint32_t buttonIdx = 0;
   1366 
   1367      // Button 0: Trigger
   1368      VRSession::UpdateTrigger(controllerState, buttonIdx,
   1369                               aInputState.IndexTrigger[handIdx],
   1370                               triggerThreshold);
   1371      ++buttonIdx;
   1372      // Button 1: Grip
   1373      VRSession::UpdateTrigger(controllerState, buttonIdx,
   1374                               aInputState.HandTrigger[handIdx],
   1375                               triggerThreshold);
   1376      ++buttonIdx;
   1377      // Button 2: a placeholder button for trackpad.
   1378      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
   1379      ++buttonIdx;
   1380      // Button 3: Thumbstick
   1381      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
   1382      ++buttonIdx;
   1383      // Button 4: A
   1384      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
   1385      ++buttonIdx;
   1386      // Button 5: B
   1387      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
   1388      ++buttonIdx;
   1389      // Button 6: ThumbRest
   1390      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
   1391      ++buttonIdx;
   1392 
   1393      MOZ_ASSERT(buttonIdx == kNumOculusButtons);
   1394 
   1395      // Update Thumbstick axis
   1396      uint32_t axisIdx = 0;
   1397      // Axis 0, 1: placeholder axes for trackpad.
   1398      axisIdx += 2;
   1399 
   1400      // Axis 2, 3: placeholder axes for thumbstick.
   1401      float axisValue = aInputState.Thumbstick[handIdx].x;
   1402      if (abs(axisValue) < 0.0000009f) {
   1403        axisValue = 0.0f;  // Clear noise signal
   1404      }
   1405      controllerState.axisValue[axisIdx] = axisValue;
   1406      axisIdx++;
   1407 
   1408      // Note that y axis is intentionally inverted!
   1409      axisValue = -aInputState.Thumbstick[handIdx].y;
   1410      if (abs(axisValue) < 0.0000009f) {
   1411        axisValue = 0.0f;  // Clear noise signal
   1412      }
   1413      controllerState.axisValue[axisIdx] = axisValue;
   1414      axisIdx++;
   1415 
   1416      MOZ_ASSERT(axisIdx == kNumOculusAxes);
   1417    }
   1418    SetControllerSelectionAndSqueezeFrameId(
   1419        controllerState, aState.displayState.lastSubmittedFrameId);
   1420  }
   1421 }
   1422 
   1423 void OculusSession::UpdateTelemetry(VRSystemState& aSystemState) {
   1424  if (!mSession) {
   1425    return;
   1426  }
   1427  ovrPerfStats perfStats;
   1428  if (ovr_GetPerfStats(mSession, &perfStats) == ovrSuccess) {
   1429    if (perfStats.FrameStatsCount) {
   1430      aSystemState.displayState.droppedFrameCount =
   1431          perfStats.FrameStats[0].AppDroppedFrameCount;
   1432    }
   1433  }
   1434 }
   1435 
   1436 void OculusSession::VibrateHaptic(uint32_t aControllerIdx,
   1437                                  uint32_t aHapticIndex, float aIntensity,
   1438                                  float aDuration) {
   1439  if (!mSession) {
   1440    return;
   1441  }
   1442 
   1443  if (aDuration <= 0.0f) {
   1444    StopVibrateHaptic(aControllerIdx);
   1445    return;
   1446  }
   1447 
   1448  // Vibration amplitude in the [0.0, 1.0] range
   1449  MOZ_ASSERT(aControllerIdx >= 0 && aControllerIdx <= 1);
   1450  mHapticPulseIntensity[aControllerIdx] = aIntensity > 1.0 ? 1.0 : aIntensity;
   1451  mRemainingVibrateTime[aControllerIdx] = aDuration;
   1452  ovrControllerType hand = OculusControllerTypes[aControllerIdx];
   1453 
   1454  // The gamepad extensions API does not yet have independent control
   1455  // of frequency and amplitude.  We are always sending 0.0f (160hz)
   1456  // to the frequency argument.
   1457  ovrResult result = ovr_SetControllerVibration(
   1458      mSession, hand, 0.0f, mHapticPulseIntensity[aControllerIdx]);
   1459  if (result != ovrSuccess) {
   1460    // This may happen if called when not presenting.
   1461    gfxWarning() << "ovr_SetControllerVibration failed.";
   1462  }
   1463 }
   1464 
   1465 void OculusSession::StopVibrateHaptic(uint32_t aControllerIdx) {
   1466  if (!mSession) {
   1467    return;
   1468  }
   1469  MOZ_ASSERT(aControllerIdx >= 0 && aControllerIdx <= 1);
   1470  ovrControllerType hand = OculusControllerTypes[aControllerIdx];
   1471  mRemainingVibrateTime[aControllerIdx] = 0.0f;
   1472  mHapticPulseIntensity[aControllerIdx] = 0.0f;
   1473 
   1474  ovrResult result = ovr_SetControllerVibration(mSession, hand, 0.0f, 0.0f);
   1475  if (result != ovrSuccess) {
   1476    // This may happen if called when not presenting.
   1477    gfxWarning() << "ovr_SetControllerVibration failed.";
   1478  }
   1479 }
   1480 
   1481 void OculusSession::StopAllHaptics() {
   1482  // Left Oculus Touch
   1483  StopVibrateHaptic(0);
   1484  // Right Oculus Touch
   1485  StopVibrateHaptic(1);
   1486 }
   1487 
   1488 void OculusSession::UpdateHaptics() {
   1489  if (!mSession) {
   1490    return;
   1491  }
   1492  // The Oculus API and hardware takes at least 33ms to respond
   1493  // to haptic state changes, so it is not beneficial to create
   1494  // a dedicated haptic feedback thread and update multiple
   1495  // times per frame.
   1496  // If we wish to support more accurate effects with sub-frame timing,
   1497  // we should use the buffered haptic feedback API's.
   1498 
   1499  TimeStamp now = TimeStamp::Now();
   1500  if (mLastHapticUpdate.IsNull()) {
   1501    mLastHapticUpdate = now;
   1502    return;
   1503  }
   1504  float deltaTime = (float)(now - mLastHapticUpdate).ToSeconds();
   1505  mLastHapticUpdate = now;
   1506  for (int i = 0; i < 2; i++) {
   1507    if (mRemainingVibrateTime[i] <= 0.0f) {
   1508      continue;
   1509    }
   1510    mRemainingVibrateTime[i] -= deltaTime;
   1511    ovrControllerType hand = OculusControllerTypes[i];
   1512    if (mRemainingVibrateTime[i] > 0.0f) {
   1513      ovrResult result = ovr_SetControllerVibration(mSession, hand, 0.0f,
   1514                                                    mHapticPulseIntensity[i]);
   1515      if (result != ovrSuccess) {
   1516        // This may happen if called when not presenting.
   1517        gfxWarning() << "ovr_SetControllerVibration failed.";
   1518      }
   1519    } else {
   1520      StopVibrateHaptic(i);
   1521    }
   1522  }
   1523 }
   1524 
   1525 }  // namespace gfx
   1526 }  // namespace mozilla