Bug 1481683 - Change gfx/vr/service and gfxvrExternal CRLF line break types to LF. r=kip
authorDaosheng Mu <daoshengmu@gmail.com>
Thu, 25 Oct 2018 21:33:25 +0000
changeset 443061 e16d573e399117c6967b1c6d755711ef9cdc063b
parent 443060 fa2a921894439692532511de633fe9db3586dc7c
child 443062 20e04b1355dc3f265435feaef946682834f74b46
push id34935
push userccoroiu@mozilla.com
push dateFri, 26 Oct 2018 04:43:55 +0000
treeherdermozilla-central@d0b577458d53 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskip
bugs1481683
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1481683 - Change gfx/vr/service and gfxvrExternal CRLF line break types to LF. r=kip MozReview-Commit-ID: 4mFBUls14e7 Differential Revision: https://phabricator.services.mozilla.com/D8785
gfx/vr/gfxVRExternal.cpp
gfx/vr/gfxVRExternal.h
gfx/vr/service/OculusSession.cpp
gfx/vr/service/OculusSession.h
gfx/vr/service/OpenVRSession.cpp
gfx/vr/service/OpenVRSession.h
gfx/vr/service/VRService.cpp
gfx/vr/service/VRService.h
gfx/vr/service/VRSession.cpp
gfx/vr/service/VRSession.h
gfx/vr/service/moz.build
--- a/gfx/vr/gfxVRExternal.cpp
+++ b/gfx/vr/gfxVRExternal.cpp
@@ -1,902 +1,900 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <math.h>
-
-#include "prlink.h"
-#include "prenv.h"
-#include "gfxPrefs.h"
-#include "mozilla/Preferences.h"
-
-#include "mozilla/gfx/Quaternion.h"
-
-#ifdef XP_WIN
-#include "CompositorD3D11.h"
-#include "TextureD3D11.h"
-static const char* kShmemName = "moz.gecko.vr_ext.0.0.1";
-#elif defined(XP_MACOSX)
-#include "mozilla/gfx/MacIOSurface.h"
-#include <sys/mman.h>
-#include <sys/stat.h>        /* For mode constants */
-#include <fcntl.h>           /* For O_* constants */
-#include <errno.h>
-static const char* kShmemName = "/moz.gecko.vr_ext.0.0.1";
-#elif defined(MOZ_WIDGET_ANDROID)
-#include <string.h>
-#include <pthread.h>
-#include "GeckoVRManager.h"
-#endif // defined(MOZ_WIDGET_ANDROID)
-
-#include "gfxVRExternal.h"
-#include "VRManagerParent.h"
-#include "VRManager.h"
-#include "VRThread.h"
-
-#include "nsServiceManagerUtils.h"
-#include "nsIScreenManager.h"
-
-#include "mozilla/dom/GamepadEventTypes.h"
-#include "mozilla/dom/GamepadBinding.h"
-#include "mozilla/Telemetry.h"
-
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::gfx::impl;
-using namespace mozilla::layers;
-using namespace mozilla::dom;
-
-VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState)
-  : VRDisplayHost(VRDeviceType::External)
-  , mHapticPulseRemaining{}
-  , mBrowserState{}
-  , mLastSensorState{}
-{
-  MOZ_COUNT_CTOR_INHERITED(VRDisplayExternal, VRDisplayHost);
-  mDisplayInfo.mDisplayState = aDisplayState;
-
-  // default to an identity quaternion
-  mLastSensorState.pose.orientation[3] = 1.0f;
-}
-
-VRDisplayExternal::~VRDisplayExternal()
-{
-  Destroy();
-  MOZ_COUNT_DTOR_INHERITED(VRDisplayExternal, VRDisplayHost);
-}
-
-void
-VRDisplayExternal::Destroy()
-{
-  StopAllHaptics();
-  StopPresentation();
-}
-
-void
-VRDisplayExternal::ZeroSensor()
-{
-}
-
-void
-VRDisplayExternal::Run1msTasks(double aDeltaTime)
-{
-  VRDisplayHost::Run1msTasks(aDeltaTime);
-  UpdateHaptics(aDeltaTime);
-}
-
-void
-VRDisplayExternal::Run10msTasks()
-{
-  VRDisplayHost::Run10msTasks();
-  ExpireNavigationTransition();
-  PullState();
-  PushState();
-
-  // 1ms tasks will always be run before
-  // the 10ms tasks, so no need to include
-  // them here as well.
-}
-
-void
-VRDisplayExternal::ExpireNavigationTransition()
-{
-  if (!mVRNavigationTransitionEnd.IsNull() &&
-      TimeStamp::Now() > mVRNavigationTransitionEnd) {
-    mBrowserState.navigationTransitionActive = false;
-  }
-}
-
-VRHMDSensorState
-VRDisplayExternal::GetSensorState()
-{
-  return mLastSensorState;
-}
-
-void
-VRDisplayExternal::StartPresentation()
-{
-  if (mBrowserState.presentationActive) {
-    return;
-  }
-  mTelemetry.Clear();
-  mTelemetry.mPresentationStart = TimeStamp::Now();
-
-  // Indicate that we are ready to start immersive mode
-  mBrowserState.presentationActive = true;
-  mBrowserState.layerState[0].type = VRLayerType::LayerType_Stereo_Immersive;
-  PushState();
-
-  mDisplayInfo.mDisplayState.mLastSubmittedFrameId = 0;
-  if (mDisplayInfo.mDisplayState.mReportsDroppedFrames) {
-    mTelemetry.mLastDroppedFrameCount = mDisplayInfo.mDisplayState.mDroppedFrameCount;
-  }
-
-#if defined(MOZ_WIDGET_ANDROID)
-  mLastSubmittedFrameId = 0;
-  mLastStartedFrame = 0;
-#endif
-}
-
-void
-VRDisplayExternal::StopPresentation()
-{
-  if (!mBrowserState.presentationActive) {
-    return;
-  }
-
-  // Indicate that we have stopped immersive mode
-  mBrowserState.presentationActive = false;
-  memset(mBrowserState.layerState, 0, sizeof(VRLayerState) * mozilla::ArrayLength(mBrowserState.layerState));
-
-  PushState(true);
-
-  Telemetry::HistogramID timeSpentID = Telemetry::HistogramCount;
-  Telemetry::HistogramID droppedFramesID = Telemetry::HistogramCount;
-  int viewIn = 0;
-
-  if (mDisplayInfo.mDisplayState.mEightCC == GFX_VR_EIGHTCC('O', 'c', 'u', 'l', 'u', 's', ' ', 'D')) {
-    // Oculus Desktop API
-    timeSpentID = Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OCULUS;
-    droppedFramesID = Telemetry::WEBVR_DROPPED_FRAMES_IN_OCULUS;
-    viewIn = 1;
-  } else if (mDisplayInfo.mDisplayState.mEightCC == GFX_VR_EIGHTCC('O', 'p', 'e', 'n', 'V', 'R', ' ', ' ')) {
-    // OpenVR API
-    timeSpentID = Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OPENVR;
-    droppedFramesID = Telemetry::WEBVR_DROPPED_FRAMES_IN_OPENVR;
-    viewIn = 2;
-  }
-
-  if (viewIn) {
-    const TimeDuration duration = TimeStamp::Now() - mTelemetry.mPresentationStart;
-    Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, viewIn);
-    Telemetry::Accumulate(timeSpentID,
-                          duration.ToMilliseconds());
-    const uint32_t droppedFramesPerSec = (mDisplayInfo.mDisplayState.mDroppedFrameCount -
-                                          mTelemetry.mLastDroppedFrameCount) / duration.ToSeconds();
-    Telemetry::Accumulate(droppedFramesID, droppedFramesPerSec);
-  }
-}
-
-void
-VRDisplayExternal::StartVRNavigation()
-{
-  mBrowserState.navigationTransitionActive = true;
-  mVRNavigationTransitionEnd = TimeStamp();
-  PushState();
-}
-
-void
-VRDisplayExternal::StopVRNavigation(const TimeDuration& aTimeout)
-{
-  if (aTimeout.ToMilliseconds() <= 0) {
-    mBrowserState.navigationTransitionActive = false;
-    mVRNavigationTransitionEnd = TimeStamp();
-    PushState();
-  }
-  mVRNavigationTransitionEnd = TimeStamp::Now() + aTimeout;
-}
-
-bool
-VRDisplayExternal::PopulateLayerTexture(const layers::SurfaceDescriptor& aTexture,
-                                        VRLayerTextureType* aTextureType,
-                                        VRLayerTextureHandle* aTextureHandle)
-{
-  switch (aTexture.type()) {
-#if defined(XP_WIN)
-    case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
-      const SurfaceDescriptorD3D10& surf = aTexture.get_SurfaceDescriptorD3D10();
-      *aTextureType = VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor;
-      *aTextureHandle = (void *)surf.handle();
-      return true;
-    }
-#elif defined(XP_MACOSX)
-    case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
-      // MacIOSurface ptr can't be fetched or used at different threads.
-      // Both of fetching and using this MacIOSurface are at the VRService thread.
-      const auto& desc = aTexture.get_SurfaceDescriptorMacIOSurface();
-      *aTextureType = VRLayerTextureType::LayerTextureType_MacIOSurface;
-      *aTextureHandle = desc.surfaceId();
-      return true;
-    }
-#elif defined(MOZ_WIDGET_ANDROID)
-    case SurfaceDescriptor::TSurfaceTextureDescriptor: {
-      const SurfaceTextureDescriptor& desc = aTexture.get_SurfaceTextureDescriptor();
-      java::GeckoSurfaceTexture::LocalRef surfaceTexture = java::GeckoSurfaceTexture::Lookup(desc.handle());
-      if (!surfaceTexture) {
-        NS_WARNING("VRDisplayHost::SubmitFrame failed to get a SurfaceTexture");
-        return false;
-      }
-      *aTextureType = VRLayerTextureType::LayerTextureType_GeckoSurfaceTexture;
-      *aTextureHandle = desc.handle();
-      return true;
-    }
-#endif
-    default: {
-      MOZ_ASSERT(false);
-      return false;
-    }
-  }
-}
-
-bool
-VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture,
-                               uint64_t aFrameId,
-                               const gfx::Rect& aLeftEyeRect,
-                               const gfx::Rect& aRightEyeRect)
-{
-  MOZ_ASSERT(mBrowserState.layerState[0].type == VRLayerType::LayerType_Stereo_Immersive);
-  VRLayer_Stereo_Immersive& layer = mBrowserState.layerState[0].layer_stereo_immersive;
-  if (!PopulateLayerTexture(aTexture, &layer.mTextureType, &layer.mTextureHandle)) {
-    return false;
-  }
-  layer.mFrameId = aFrameId;
-  layer.mInputFrameId = mDisplayInfo.mLastSensorState[mDisplayInfo.mFrameId % kVRMaxLatencyFrames].inputFrameID;
-
-  layer.mLeftEyeRect.x = aLeftEyeRect.x;
-  layer.mLeftEyeRect.y = aLeftEyeRect.y;
-  layer.mLeftEyeRect.width = aLeftEyeRect.width;
-  layer.mLeftEyeRect.height = aLeftEyeRect.height;
-  layer.mRightEyeRect.x = aRightEyeRect.x;
-  layer.mRightEyeRect.y = aRightEyeRect.y;
-  layer.mRightEyeRect.width = aRightEyeRect.width;
-  layer.mRightEyeRect.height = aRightEyeRect.height;
-
-  PushState(true);
-
-#if defined(MOZ_WIDGET_ANDROID)
-  PullState([&]() {
-    return (mDisplayInfo.mDisplayState.mLastSubmittedFrameId >= aFrameId) ||
-            mDisplayInfo.mDisplayState.mSuppressFrames ||
-            !mDisplayInfo.mDisplayState.mIsConnected;
-  });
-
-  if (mDisplayInfo.mDisplayState.mSuppressFrames || !mDisplayInfo.mDisplayState.mIsConnected) {
-    // External implementation wants to supress frames, service has shut down or hardware has been disconnected.
-    return false;
-  }
-#else
-  while (mDisplayInfo.mDisplayState.mLastSubmittedFrameId < aFrameId) {
-    if (PullState()) {
-      if (mDisplayInfo.mDisplayState.mSuppressFrames || !mDisplayInfo.mDisplayState.mIsConnected) {
-        // External implementation wants to supress frames, service has shut down or hardware has been disconnected.
-        return false;
-      }
-    }
-#ifdef XP_WIN
-    Sleep(0);
-#else
-    sleep(0);
-#endif
-  }
-#endif // defined(MOZ_WIDGET_ANDROID)
-
-  return mDisplayInfo.mDisplayState.mLastSubmittedFrameSuccessful;
-}
-
-void
-VRDisplayExternal::VibrateHaptic(uint32_t aControllerIdx,
-                                 uint32_t aHapticIndex,
-                                 double aIntensity,
-                                 double aDuration,
-                                 const VRManagerPromise& aPromise)
-{
-  TimeStamp now = TimeStamp::Now();
-  size_t bestSlotIndex = 0;
-  // Default to an empty slot, or the slot holding the oldest haptic pulse
-  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
-    const VRHapticState& state = mBrowserState.hapticState[i];
-    if (state.inputFrameID == 0) {
-      // Unused slot, use it
-      bestSlotIndex = i;
-      break;
-    }
-    if (mHapticPulseRemaining[i] < mHapticPulseRemaining[bestSlotIndex]) {
-      // If no empty slots are available, fall back to overriding
-      // the pulse which is ending soonest.
-      bestSlotIndex = i;
-    }
-  }
-  // Override the last pulse on the same actuator if present.
-  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
-    const VRHapticState& state = mBrowserState.hapticState[i];
-    if (state.inputFrameID == 0) {
-      // This is an empty slot -- no match
-      continue;
-    }
-    if (state.controllerIndex == aControllerIdx &&
-        state.hapticIndex == aHapticIndex) {
-      // Found pulse on same actuator -- let's override it.
-      bestSlotIndex = i;
-    }
-  }
-  ClearHapticSlot(bestSlotIndex);
-
-  // Populate the selected slot with new haptic state
-  size_t bufferIndex = mDisplayInfo.mFrameId % kVRMaxLatencyFrames;
-  VRHapticState& bestSlot = mBrowserState.hapticState[bestSlotIndex];
-  bestSlot.inputFrameID =
-    mDisplayInfo.mLastSensorState[bufferIndex].inputFrameID;
-  bestSlot.controllerIndex = aControllerIdx;
-  bestSlot.hapticIndex = aHapticIndex;
-  bestSlot.pulseStart =
-    (now - mDisplayInfo.mLastFrameStart[bufferIndex]).ToSeconds();
-  bestSlot.pulseDuration = aDuration;
-  bestSlot.pulseIntensity = aIntensity;
-   // Convert from seconds to ms
-  mHapticPulseRemaining[bestSlotIndex] = aDuration * 1000.0f;
-  MOZ_ASSERT(bestSlotIndex <= mHapticPromises.Length());
-  if (bestSlotIndex == mHapticPromises.Length()) {
-    mHapticPromises.AppendElement(
-      UniquePtr<VRManagerPromise>(new VRManagerPromise(aPromise)));
-  } else {
-    mHapticPromises[bestSlotIndex] =
-      UniquePtr<VRManagerPromise>(new VRManagerPromise(aPromise));
-  }
-  PushState();
-}
-
-void
-VRDisplayExternal::ClearHapticSlot(size_t aSlot)
-{
-  MOZ_ASSERT(aSlot < mozilla::ArrayLength(mBrowserState.hapticState));
-  memset(&mBrowserState.hapticState[aSlot], 0, sizeof(VRHapticState));
-  mHapticPulseRemaining[aSlot] = 0.0f;
-  if (aSlot < mHapticPromises.Length() && mHapticPromises[aSlot]) {
-    VRManager* vm = VRManager::Get();
-    vm->NotifyVibrateHapticCompleted(*mHapticPromises[aSlot]);
-    mHapticPromises[aSlot] = nullptr;
-  }
-}
-
-void
-VRDisplayExternal::UpdateHaptics(double aDeltaTime)
-{
-  bool bNeedPush = false;
-  // Check for any haptic pulses that have ended and clear them
-  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
-    const VRHapticState& state = mBrowserState.hapticState[i];
-    if (state.inputFrameID == 0) {
-      // Nothing in this slot
-      continue;
-    }
-    mHapticPulseRemaining[i] -= aDeltaTime;
-    if (mHapticPulseRemaining[i] <= 0.0f) {
-      // The pulse has finished
-      ClearHapticSlot(i);
-      bNeedPush = true;
-    }
-  }
-  if (bNeedPush) {
-    PushState();
-  }
-}
-
-void
-VRDisplayExternal::StopVibrateHaptic(uint32_t aControllerIdx)
-{
-  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
-    VRHapticState& state = mBrowserState.hapticState[i];
-    if (state.controllerIndex == aControllerIdx) {
-      memset(&state, 0, sizeof(VRHapticState));
-    }
-  }
-  PushState();
-}
-
-void
-VRDisplayExternal::StopAllHaptics()
-{
-  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
-    ClearHapticSlot(i);
-  }
-  PushState();
-}
-
-void
-VRDisplayExternal::PushState(bool aNotifyCond)
-{
-  VRManager *vm = VRManager::Get();
-  VRSystemManagerExternal* manager = vm->GetExternalManager();
-  manager->PushState(&mBrowserState, aNotifyCond);
-}
-
-#if defined(MOZ_WIDGET_ANDROID)
-bool
-VRDisplayExternal::PullState(const std::function<bool()>& aWaitCondition)
-{
-  VRManager *vm = VRManager::Get();
-  VRSystemManagerExternal* manager = vm->GetExternalManager();
-  return manager->PullState(&mDisplayInfo.mDisplayState,
-                            &mLastSensorState,
-                            mDisplayInfo.mControllerState,
-                            aWaitCondition);
-}
-#else
-bool
-VRDisplayExternal::PullState()
-{
-  VRManager *vm = VRManager::Get();
-  VRSystemManagerExternal* manager = vm->GetExternalManager();
-  return manager->PullState(&mDisplayInfo.mDisplayState,
-                            &mLastSensorState,
-                            mDisplayInfo.mControllerState);
-}
-#endif
-
-VRSystemManagerExternal::VRSystemManagerExternal(VRExternalShmem* aAPIShmem /* = nullptr*/)
- : mExternalShmem(aAPIShmem)
-#if !defined(MOZ_WIDGET_ANDROID)
- , mSameProcess(aAPIShmem != nullptr)
-#endif
-{
-#if defined(XP_MACOSX)
-  mShmemFD = 0;
-#elif defined(XP_WIN)
-  mShmemFile = NULL;
-#elif defined(MOZ_WIDGET_ANDROID)
-  mExternalStructFailed = false;
-  mEnumerationCompleted = false;
-#endif
-  mDoShutdown = false;
-
-  if (!aAPIShmem) {
-    OpenShmem();
-  }
-}
-
-VRSystemManagerExternal::~VRSystemManagerExternal()
-{
-  CloseShmem();
-}
-
-void
-VRSystemManagerExternal::OpenShmem()
-{
-  if (mExternalShmem) {
-    return;
-#if defined(MOZ_WIDGET_ANDROID)
-  } else if (mExternalStructFailed) {
-    return;
-#endif // defined(MOZ_WIDGET_ANDROID)
-  }
-
-#if defined(XP_MACOSX)
-  if (mShmemFD == 0) {
-    mShmemFD = shm_open(kShmemName, O_RDWR, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
-  }
-  if (mShmemFD <= 0) {
-    mShmemFD = 0;
-    return;
-  }
-
-  struct stat sb;
-  fstat(mShmemFD, &sb);
-  off_t length = sb.st_size;
-  if (length < (off_t)sizeof(VRExternalShmem)) {
-    // TODO - Implement logging
-    CloseShmem();
-    return;
-  }
-
-  mExternalShmem = (VRExternalShmem*)mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, mShmemFD, 0);
-  if (mExternalShmem == MAP_FAILED) {
-    // TODO - Implement logging
-    mExternalShmem = NULL;
-    CloseShmem();
-    return;
-  }
-
-#elif defined(XP_WIN)
-  if (mShmemFile == NULL) {
-    if (gfxPrefs::VRProcessEnabled()) {
-      mShmemFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
-                                      sizeof(VRExternalShmem), kShmemName);
-	    MOZ_ASSERT(GetLastError() == 0);
-    } else {
-      mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName);
-    }
-
-    if (mShmemFile == NULL) {
-      // TODO - Implement logging
-      CloseShmem();
-      return;
-    }
-  }
-  LARGE_INTEGER length;
-  length.QuadPart = sizeof(VRExternalShmem);
-  mExternalShmem = (VRExternalShmem*)MapViewOfFile(mShmemFile, // handle to map object
-    FILE_MAP_ALL_ACCESS,  // read/write permission
-    0,
-    0,
-    length.QuadPart);
-
-  if (mExternalShmem == NULL) {
-    // TODO - Implement logging
-    CloseShmem();
-    return;
-  }
-#elif defined(MOZ_WIDGET_ANDROID)
-  mExternalShmem = (VRExternalShmem*)mozilla::GeckoVRManager::GetExternalContext();
-  if (!mExternalShmem) {
-    return;
-  }
-  int32_t version = -1;
-  int32_t size = 0;
-  if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
-    version = mExternalShmem->version;
-    size = mExternalShmem->size;
-    pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
-  } else {
-    return;
-  }
-  if (version != kVRExternalVersion) {
-    mExternalShmem = nullptr;
-    mExternalStructFailed = true;
-    return;
-  }
-  if (size != sizeof(VRExternalShmem)) {
-    mExternalShmem = nullptr;
-    mExternalStructFailed = true;
-    return;
-  }
-#endif
-  CheckForShutdown();
-}
-
-void
-VRSystemManagerExternal::CheckForShutdown()
-{
-  if (mDoShutdown) {
-    Shutdown();
-  }
-}
-
-void
-VRSystemManagerExternal::CloseShmem()
-{
-#if !defined(MOZ_WIDGET_ANDROID)
-  if (mSameProcess) {
-    return;
-  }
-#endif
-#if defined(XP_MACOSX)
-  if (mExternalShmem) {
-    munmap((void *)mExternalShmem, sizeof(VRExternalShmem));
-    mExternalShmem = NULL;
-  }
-  if (mShmemFD) {
-    close(mShmemFD);
-  }
-  mShmemFD = 0;
-#elif defined(XP_WIN)
-  if (mExternalShmem) {
-    UnmapViewOfFile((void *)mExternalShmem);
-    mExternalShmem = NULL;
-  }
-  if (mShmemFile) {
-    CloseHandle(mShmemFile);
-    mShmemFile = NULL;
-  }
-#elif defined(MOZ_WIDGET_ANDROID)
-  mExternalShmem = NULL;
-#endif
-}
-
-/*static*/ already_AddRefed<VRSystemManagerExternal>
-VRSystemManagerExternal::Create(VRExternalShmem* aAPIShmem /* = nullptr*/)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!gfxPrefs::VREnabled()) {
-    return nullptr;
-  }
-
-  if ((!gfxPrefs::VRExternalEnabled() && aAPIShmem == nullptr)
-#if defined(XP_WIN)
-      || !XRE_IsGPUProcess()
-#endif
-     ) {
-    return nullptr;
-  }
-
-  RefPtr<VRSystemManagerExternal> manager = new VRSystemManagerExternal(aAPIShmem);
-  return manager.forget();
-}
-
-void
-VRSystemManagerExternal::Destroy()
-{
-  Shutdown();
-}
-
-void
-VRSystemManagerExternal::Shutdown()
-{
-  if (mDisplay) {
-    mDisplay = nullptr;
-  }
-  CloseShmem();
-  mDoShutdown = false;
-}
-
-void
-VRSystemManagerExternal::Run100msTasks()
-{
-  VRSystemManager::Run100msTasks();
-  // 1ms and 10ms tasks will always be run before
-  // the 100ms tasks, so no need to run them
-  // redundantly here.
-
-  CheckForShutdown();
-}
-
-void
-VRSystemManagerExternal::Enumerate()
-{
-  if (mDisplay == nullptr) {
-    OpenShmem();
-    if (mExternalShmem) {
-      VRDisplayState displayState;
-      memset(&displayState, 0, sizeof(VRDisplayState));
-      // We must block until enumeration has completed in order
-      // to signal that the WebVR promise should be resolved at the
-      // right time.
-#if defined(MOZ_WIDGET_ANDROID)
-      PullState(&displayState, nullptr, nullptr, [&](){
-        return mEnumerationCompleted;
-      });
-#else
-      while (!PullState(&displayState)) {
-#ifdef XP_WIN
-        Sleep(0);
-#else
-        sleep(0);
-#endif // XP_WIN
-      }
-#endif // defined(MOZ_WIDGET_ANDROID)
-
-      if (displayState.mIsConnected) {
-        mDisplay = new VRDisplayExternal(displayState);
-      }
-    }
-  }
-}
-
-bool
-VRSystemManagerExternal::ShouldInhibitEnumeration()
-{
-  if (VRSystemManager::ShouldInhibitEnumeration()) {
-    return true;
-  }
-  if (!mEarliestRestartTime.IsNull() && mEarliestRestartTime > TimeStamp::Now()) {
-    // When the VR Service shuts down it informs us of how long we
-    // must wait until we can re-start it.
-    // We must wait until mEarliestRestartTime before attempting
-    // to enumerate again.
-    return true;
-  }
-  if (mDisplay) {
-    // When we find an a VR device, don't
-    // allow any further enumeration as it
-    // may get picked up redundantly by other
-    // API's.
-    return true;
-  }
-  return false;
-}
-
-void
-VRSystemManagerExternal::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
-{
-  if (mDisplay) {
-    aHMDResult.AppendElement(mDisplay);
-  }
-}
-
-bool
-VRSystemManagerExternal::GetIsPresenting()
-{
-  if (mDisplay) {
-    VRDisplayInfo displayInfo(mDisplay->GetDisplayInfo());
-    return displayInfo.GetPresentingGroups() != 0;
-  }
-
-  return false;
-}
-
-void
-VRSystemManagerExternal::VibrateHaptic(uint32_t aControllerIdx,
-                                       uint32_t aHapticIndex,
-                                       double aIntensity,
-                                       double aDuration,
-                                       const VRManagerPromise& aPromise)
-{
-  if (mDisplay) {
-    // VRDisplayClient::FireGamepadEvents() assigns a controller ID with ranges
-    // based on displayID.  We must translate this to the indexes understood by
-    // VRDisplayExternal.
-    uint32_t controllerBaseIndex =
-      kVRControllerMaxCount * mDisplay->GetDisplayInfo().mDisplayID;
-    uint32_t controllerIndex = aControllerIdx - controllerBaseIndex;
-    double aDurationSeconds = aDuration * 0.001f;
-    mDisplay->VibrateHaptic(
-      controllerIndex, aHapticIndex, aIntensity, aDurationSeconds, aPromise);
-  }
-}
-
-void
-VRSystemManagerExternal::StopVibrateHaptic(uint32_t aControllerIdx)
-{
-  if (mDisplay) {
-    // VRDisplayClient::FireGamepadEvents() assigns a controller ID with ranges
-    // based on displayID.  We must translate this to the indexes understood by
-    // VRDisplayExternal.
-    uint32_t controllerBaseIndex =
-      kVRControllerMaxCount * mDisplay->GetDisplayInfo().mDisplayID;
-    uint32_t controllerIndex = aControllerIdx - controllerBaseIndex;
-    mDisplay->StopVibrateHaptic(controllerIndex);
-  }
-}
-
-void
-VRSystemManagerExternal::GetControllers(
-  nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
-{
-  // Controller updates are handled in VRDisplayClient for
-  // VRSystemManagerExternal
-  aControllerResult.Clear();
-}
-
-void
-VRSystemManagerExternal::ScanForControllers()
-{
-  // Controller updates are handled in VRDisplayClient for
-  // VRSystemManagerExternal
-  return;
-}
-
-void
-VRSystemManagerExternal::HandleInput()
-{
-  // Controller updates are handled in VRDisplayClient for
-  // VRSystemManagerExternal
-  return;
-}
-
-void
-VRSystemManagerExternal::RemoveControllers()
-{
-  if (mDisplay) {
-    mDisplay->StopAllHaptics();
-  }
-  // Controller updates are handled in VRDisplayClient for
-  // VRSystemManagerExternal
-}
-
-#if defined(MOZ_WIDGET_ANDROID)
-bool
-VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
-                                   VRHMDSensorState* aSensorState /* = nullptr */,
-                                   VRControllerState* aControllerState /* = nullptr */,
-                                   const std::function<bool()>& aWaitCondition /* = nullptr */)
-{
-  MOZ_ASSERT(mExternalShmem);
-  if (!mExternalShmem) {
-    return false;
-  }
-  bool done = false;
-  while(!done) {
-    if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
-      while (true) {
-        memcpy(aDisplayState, (void*)&(mExternalShmem->state.displayState), sizeof(VRDisplayState));
-        if (aSensorState) {
-          memcpy(aSensorState, (void*)&(mExternalShmem->state.sensorState), sizeof(VRHMDSensorState));
-        }
-        if (aControllerState) {
-          memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
-        }
-        mEnumerationCompleted = mExternalShmem->state.enumerationCompleted;
-        if (aDisplayState->shutdown) {
-          mDoShutdown = true;
-          TimeStamp now = TimeStamp::Now();
-          if (!mEarliestRestartTime.IsNull() && mEarliestRestartTime < now) {
-            mEarliestRestartTime = now + TimeDuration::FromMilliseconds((double)aDisplayState->mMinRestartInterval);
-          }
-        }
-        if (!aWaitCondition || aWaitCondition()) {
-          done = true;
-          break;
-        }
-        // Block current thead using the condition variable until data changes
-        pthread_cond_wait((pthread_cond_t*)&mExternalShmem->systemCond, (pthread_mutex_t*)&mExternalShmem->systemMutex);
-      }
-      pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
-    } else if (!aWaitCondition) {
-      // pthread_mutex_lock failed and we are not waiting for a condition to exit from PullState call.
-      // return false to indicate that PullState call failed
-      return false;
-    }
-  }
-  return true;
-}
-#else 
-bool
-VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
-                                   VRHMDSensorState* aSensorState /* = nullptr */,
-                                   VRControllerState* aControllerState /* = nullptr */)
-{
-  bool success = false;
-  MOZ_ASSERT(mExternalShmem);
-  if (mExternalShmem) {
-    VRExternalShmem tmp;
-    memcpy(&tmp, (void *)mExternalShmem, sizeof(VRExternalShmem));
-    if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1 && tmp.state.enumerationCompleted) {
-      memcpy(aDisplayState, &tmp.state.displayState, sizeof(VRDisplayState));
-      if (aSensorState) {
-        memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState));
-      }
-      if (aControllerState) {
-        memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
-      }
-      if (aDisplayState->shutdown) {
-        mDoShutdown = true;
-        TimeStamp now = TimeStamp::Now();
-        if (!mEarliestRestartTime.IsNull() && mEarliestRestartTime < now) {
-          mEarliestRestartTime = now + TimeDuration::FromMilliseconds((double)aDisplayState->mMinRestartInterval);
-        }
-      }
-      success = true;
-    }
-  }
-
-  return success;
-}
-#endif // defined(MOZ_WIDGET_ANDROID)
-
-void
-VRSystemManagerExternal::PushState(VRBrowserState* aBrowserState, bool aNotifyCond)
-{
-  MOZ_ASSERT(aBrowserState);
-  MOZ_ASSERT(mExternalShmem);
-  if (mExternalShmem) {
-#if defined(MOZ_WIDGET_ANDROID)
-    if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) == 0) {
-      memcpy((void *)&(mExternalShmem->browserState), aBrowserState, sizeof(VRBrowserState));
-      if (aNotifyCond) {
-        pthread_cond_signal((pthread_cond_t*)&(mExternalShmem->browserCond));
-      }
-      pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
-    }
-#else
-    mExternalShmem->browserGenerationA++;
-    memcpy((void *)&(mExternalShmem->browserState), (void *)aBrowserState, sizeof(VRBrowserState));
-    mExternalShmem->browserGenerationB++;
-#endif // defined(MOZ_WIDGET_ANDROID)
-  }
-}
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <math.h>
+
+#include "prlink.h"
+#include "prenv.h"
+#include "gfxPrefs.h"
+#include "mozilla/Preferences.h"
+
+#include "mozilla/gfx/Quaternion.h"
+
+#ifdef XP_WIN
+#include "CompositorD3D11.h"
+#include "TextureD3D11.h"
+static const char* kShmemName = "moz.gecko.vr_ext.0.0.1";
+#elif defined(XP_MACOSX)
+#include "mozilla/gfx/MacIOSurface.h"
+#include <sys/mman.h>
+#include <sys/stat.h>        /* For mode constants */
+#include <fcntl.h>           /* For O_* constants */
+#include <errno.h>
+static const char* kShmemName = "/moz.gecko.vr_ext.0.0.1";
+#elif defined(MOZ_WIDGET_ANDROID)
+#include <string.h>
+#include <pthread.h>
+#include "GeckoVRManager.h"
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+#include "gfxVRExternal.h"
+#include "VRManagerParent.h"
+#include "VRManager.h"
+#include "VRThread.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsIScreenManager.h"
+
+#include "mozilla/dom/GamepadEventTypes.h"
+#include "mozilla/dom/GamepadBinding.h"
+#include "mozilla/Telemetry.h"
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::gfx::impl;
+using namespace mozilla::layers;
+using namespace mozilla::dom;
+
+VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState)
+  : VRDisplayHost(VRDeviceType::External)
+  , mHapticPulseRemaining{}
+  , mBrowserState{}
+  , mLastSensorState{}
+{
+  MOZ_COUNT_CTOR_INHERITED(VRDisplayExternal, VRDisplayHost);
+  mDisplayInfo.mDisplayState = aDisplayState;
+
+  // default to an identity quaternion
+  mLastSensorState.pose.orientation[3] = 1.0f;
+}
+
+VRDisplayExternal::~VRDisplayExternal()
+{
+  Destroy();
+  MOZ_COUNT_DTOR_INHERITED(VRDisplayExternal, VRDisplayHost);
+}
+
+void
+VRDisplayExternal::Destroy()
+{
+  StopAllHaptics();
+  StopPresentation();
+}
+
+void
+VRDisplayExternal::ZeroSensor()
+{
+}
+
+void
+VRDisplayExternal::Run1msTasks(double aDeltaTime)
+{
+  VRDisplayHost::Run1msTasks(aDeltaTime);
+  UpdateHaptics(aDeltaTime);
+}
+
+void
+VRDisplayExternal::Run10msTasks()
+{
+  VRDisplayHost::Run10msTasks();
+  ExpireNavigationTransition();
+  PullState();
+  PushState();
+
+  // 1ms tasks will always be run before
+  // the 10ms tasks, so no need to include
+  // them here as well.
+}
+
+void
+VRDisplayExternal::ExpireNavigationTransition()
+{
+  if (!mVRNavigationTransitionEnd.IsNull() &&
+      TimeStamp::Now() > mVRNavigationTransitionEnd) {
+    mBrowserState.navigationTransitionActive = false;
+  }
+}
+
+VRHMDSensorState
+VRDisplayExternal::GetSensorState()
+{
+  return mLastSensorState;
+}
+
+void
+VRDisplayExternal::StartPresentation()
+{
+  if (mBrowserState.presentationActive) {
+    return;
+  }
+  mTelemetry.Clear();
+  mTelemetry.mPresentationStart = TimeStamp::Now();
+
+  // Indicate that we are ready to start immersive mode
+  mBrowserState.presentationActive = true;
+  mBrowserState.layerState[0].type = VRLayerType::LayerType_Stereo_Immersive;
+  PushState();
+
+  mDisplayInfo.mDisplayState.mLastSubmittedFrameId = 0;
+  if (mDisplayInfo.mDisplayState.mReportsDroppedFrames) {
+    mTelemetry.mLastDroppedFrameCount = mDisplayInfo.mDisplayState.mDroppedFrameCount;
+  }
+
+#if defined(MOZ_WIDGET_ANDROID)
+  mLastSubmittedFrameId = 0;
+  mLastStartedFrame = 0;
+#endif
+}
+
+void
+VRDisplayExternal::StopPresentation()
+{
+  if (!mBrowserState.presentationActive) {
+    return;
+  }
+
+  // Indicate that we have stopped immersive mode
+  mBrowserState.presentationActive = false;
+  memset(mBrowserState.layerState, 0, sizeof(VRLayerState) * mozilla::ArrayLength(mBrowserState.layerState));
+
+  PushState(true);
+
+  Telemetry::HistogramID timeSpentID = Telemetry::HistogramCount;
+  Telemetry::HistogramID droppedFramesID = Telemetry::HistogramCount;
+  int viewIn = 0;
+
+  if (mDisplayInfo.mDisplayState.mEightCC == GFX_VR_EIGHTCC('O', 'c', 'u', 'l', 'u', 's', ' ', 'D')) {
+    // Oculus Desktop API
+    timeSpentID = Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OCULUS;
+    droppedFramesID = Telemetry::WEBVR_DROPPED_FRAMES_IN_OCULUS;
+    viewIn = 1;
+  } else if (mDisplayInfo.mDisplayState.mEightCC == GFX_VR_EIGHTCC('O', 'p', 'e', 'n', 'V', 'R', ' ', ' ')) {
+    // OpenVR API
+    timeSpentID = Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OPENVR;
+    droppedFramesID = Telemetry::WEBVR_DROPPED_FRAMES_IN_OPENVR;
+    viewIn = 2;
+  }
+
+  if (viewIn) {
+    const TimeDuration duration = TimeStamp::Now() - mTelemetry.mPresentationStart;
+    Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, viewIn);
+    Telemetry::Accumulate(timeSpentID,
+                          duration.ToMilliseconds());
+    const uint32_t droppedFramesPerSec = (mDisplayInfo.mDisplayState.mDroppedFrameCount -
+                                          mTelemetry.mLastDroppedFrameCount) / duration.ToSeconds();
+    Telemetry::Accumulate(droppedFramesID, droppedFramesPerSec);
+  }
+}
+
+void
+VRDisplayExternal::StartVRNavigation()
+{
+  mBrowserState.navigationTransitionActive = true;
+  mVRNavigationTransitionEnd = TimeStamp();
+  PushState();
+}
+
+void
+VRDisplayExternal::StopVRNavigation(const TimeDuration& aTimeout)
+{
+  if (aTimeout.ToMilliseconds() <= 0) {
+    mBrowserState.navigationTransitionActive = false;
+    mVRNavigationTransitionEnd = TimeStamp();
+    PushState();
+  }
+  mVRNavigationTransitionEnd = TimeStamp::Now() + aTimeout;
+}
+
+bool
+VRDisplayExternal::PopulateLayerTexture(const layers::SurfaceDescriptor& aTexture,
+                                        VRLayerTextureType* aTextureType,
+                                        VRLayerTextureHandle* aTextureHandle)
+{
+  switch (aTexture.type()) {
+#if defined(XP_WIN)
+    case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
+      const SurfaceDescriptorD3D10& surf = aTexture.get_SurfaceDescriptorD3D10();
+      *aTextureType = VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor;
+      *aTextureHandle = (void *)surf.handle();
+      return true;
+    }
+#elif defined(XP_MACOSX)
+    case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
+      // MacIOSurface ptr can't be fetched or used at different threads.
+      // Both of fetching and using this MacIOSurface are at the VRService thread.
+      const auto& desc = aTexture.get_SurfaceDescriptorMacIOSurface();
+      *aTextureType = VRLayerTextureType::LayerTextureType_MacIOSurface;
+      *aTextureHandle = desc.surfaceId();
+      return true;
+    }
+#elif defined(MOZ_WIDGET_ANDROID)
+    case SurfaceDescriptor::TSurfaceTextureDescriptor: {
+      const SurfaceTextureDescriptor& desc = aTexture.get_SurfaceTextureDescriptor();
+      java::GeckoSurfaceTexture::LocalRef surfaceTexture = java::GeckoSurfaceTexture::Lookup(desc.handle());
+      if (!surfaceTexture) {
+        NS_WARNING("VRDisplayHost::SubmitFrame failed to get a SurfaceTexture");
+        return false;
+      }
+      *aTextureType = VRLayerTextureType::LayerTextureType_GeckoSurfaceTexture;
+      *aTextureHandle = desc.handle();
+      return true;
+    }
+#endif
+    default: {
+      MOZ_ASSERT(false);
+      return false;
+    }
+  }
+}
+
+bool
+VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture,
+                               uint64_t aFrameId,
+                               const gfx::Rect& aLeftEyeRect,
+                               const gfx::Rect& aRightEyeRect)
+{
+  MOZ_ASSERT(mBrowserState.layerState[0].type == VRLayerType::LayerType_Stereo_Immersive);
+  VRLayer_Stereo_Immersive& layer = mBrowserState.layerState[0].layer_stereo_immersive;
+  if (!PopulateLayerTexture(aTexture, &layer.mTextureType, &layer.mTextureHandle)) {
+    return false;
+  }
+  layer.mFrameId = aFrameId;
+  layer.mInputFrameId = mDisplayInfo.mLastSensorState[mDisplayInfo.mFrameId % kVRMaxLatencyFrames].inputFrameID;
+
+  layer.mLeftEyeRect.x = aLeftEyeRect.x;
+  layer.mLeftEyeRect.y = aLeftEyeRect.y;
+  layer.mLeftEyeRect.width = aLeftEyeRect.width;
+  layer.mLeftEyeRect.height = aLeftEyeRect.height;
+  layer.mRightEyeRect.x = aRightEyeRect.x;
+  layer.mRightEyeRect.y = aRightEyeRect.y;
+  layer.mRightEyeRect.width = aRightEyeRect.width;
+  layer.mRightEyeRect.height = aRightEyeRect.height;
+
+  PushState(true);
+
+#if defined(MOZ_WIDGET_ANDROID)
+  PullState([&]() {
+    return (mDisplayInfo.mDisplayState.mLastSubmittedFrameId >= aFrameId) ||
+            mDisplayInfo.mDisplayState.mSuppressFrames ||
+            !mDisplayInfo.mDisplayState.mIsConnected;
+  });
+
+  if (mDisplayInfo.mDisplayState.mSuppressFrames || !mDisplayInfo.mDisplayState.mIsConnected) {
+    // External implementation wants to supress frames, service has shut down or hardware has been disconnected.
+    return false;
+  }
+#else
+  while (mDisplayInfo.mDisplayState.mLastSubmittedFrameId < aFrameId) {
+    if (PullState()) {
+      if (mDisplayInfo.mDisplayState.mSuppressFrames || !mDisplayInfo.mDisplayState.mIsConnected) {
+        // External implementation wants to supress frames, service has shut down or hardware has been disconnected.
+        return false;
+      }
+    }
+#ifdef XP_WIN
+    Sleep(0);
+#else
+    sleep(0);
+#endif
+  }
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+  return mDisplayInfo.mDisplayState.mLastSubmittedFrameSuccessful;
+}
+
+void
+VRDisplayExternal::VibrateHaptic(uint32_t aControllerIdx,
+                                 uint32_t aHapticIndex,
+                                 double aIntensity,
+                                 double aDuration,
+                                 const VRManagerPromise& aPromise)
+{
+  TimeStamp now = TimeStamp::Now();
+  size_t bestSlotIndex = 0;
+  // Default to an empty slot, or the slot holding the oldest haptic pulse
+  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
+    const VRHapticState& state = mBrowserState.hapticState[i];
+    if (state.inputFrameID == 0) {
+      // Unused slot, use it
+      bestSlotIndex = i;
+      break;
+    }
+    if (mHapticPulseRemaining[i] < mHapticPulseRemaining[bestSlotIndex]) {
+      // If no empty slots are available, fall back to overriding
+      // the pulse which is ending soonest.
+      bestSlotIndex = i;
+    }
+  }
+  // Override the last pulse on the same actuator if present.
+  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
+    const VRHapticState& state = mBrowserState.hapticState[i];
+    if (state.inputFrameID == 0) {
+      // This is an empty slot -- no match
+      continue;
+    }
+    if (state.controllerIndex == aControllerIdx &&
+        state.hapticIndex == aHapticIndex) {
+      // Found pulse on same actuator -- let's override it.
+      bestSlotIndex = i;
+    }
+  }
+  ClearHapticSlot(bestSlotIndex);
+
+  // Populate the selected slot with new haptic state
+  size_t bufferIndex = mDisplayInfo.mFrameId % kVRMaxLatencyFrames;
+  VRHapticState& bestSlot = mBrowserState.hapticState[bestSlotIndex];
+  bestSlot.inputFrameID =
+    mDisplayInfo.mLastSensorState[bufferIndex].inputFrameID;
+  bestSlot.controllerIndex = aControllerIdx;
+  bestSlot.hapticIndex = aHapticIndex;
+  bestSlot.pulseStart =
+    (now - mDisplayInfo.mLastFrameStart[bufferIndex]).ToSeconds();
+  bestSlot.pulseDuration = aDuration;
+  bestSlot.pulseIntensity = aIntensity;
+   // Convert from seconds to ms
+  mHapticPulseRemaining[bestSlotIndex] = aDuration * 1000.0f;
+  MOZ_ASSERT(bestSlotIndex <= mHapticPromises.Length());
+  if (bestSlotIndex == mHapticPromises.Length()) {
+    mHapticPromises.AppendElement(
+      UniquePtr<VRManagerPromise>(new VRManagerPromise(aPromise)));
+  } else {
+    mHapticPromises[bestSlotIndex] =
+      UniquePtr<VRManagerPromise>(new VRManagerPromise(aPromise));
+  }
+  PushState();
+}
+
+void
+VRDisplayExternal::ClearHapticSlot(size_t aSlot)
+{
+  MOZ_ASSERT(aSlot < mozilla::ArrayLength(mBrowserState.hapticState));
+  memset(&mBrowserState.hapticState[aSlot], 0, sizeof(VRHapticState));
+  mHapticPulseRemaining[aSlot] = 0.0f;
+  if (aSlot < mHapticPromises.Length() && mHapticPromises[aSlot]) {
+    VRManager* vm = VRManager::Get();
+    vm->NotifyVibrateHapticCompleted(*mHapticPromises[aSlot]);
+    mHapticPromises[aSlot] = nullptr;
+  }
+}
+
+void
+VRDisplayExternal::UpdateHaptics(double aDeltaTime)
+{
+  bool bNeedPush = false;
+  // Check for any haptic pulses that have ended and clear them
+  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
+    const VRHapticState& state = mBrowserState.hapticState[i];
+    if (state.inputFrameID == 0) {
+      // Nothing in this slot
+      continue;
+    }
+    mHapticPulseRemaining[i] -= aDeltaTime;
+    if (mHapticPulseRemaining[i] <= 0.0f) {
+      // The pulse has finished
+      ClearHapticSlot(i);
+      bNeedPush = true;
+    }
+  }
+  if (bNeedPush) {
+    PushState();
+  }
+}
+
+void
+VRDisplayExternal::StopVibrateHaptic(uint32_t aControllerIdx)
+{
+  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
+    VRHapticState& state = mBrowserState.hapticState[i];
+    if (state.controllerIndex == aControllerIdx) {
+      memset(&state, 0, sizeof(VRHapticState));
+    }
+  }
+  PushState();
+}
+
+void
+VRDisplayExternal::StopAllHaptics()
+{
+  for (size_t i = 0; i < mozilla::ArrayLength(mBrowserState.hapticState); i++) {
+    ClearHapticSlot(i);
+  }
+  PushState();
+}
+
+void
+VRDisplayExternal::PushState(bool aNotifyCond)
+{
+  VRManager *vm = VRManager::Get();
+  VRSystemManagerExternal* manager = vm->GetExternalManager();
+  manager->PushState(&mBrowserState, aNotifyCond);
+}
+
+#if defined(MOZ_WIDGET_ANDROID)
+bool
+VRDisplayExternal::PullState(const std::function<bool()>& aWaitCondition)
+{
+  VRManager *vm = VRManager::Get();
+  VRSystemManagerExternal* manager = vm->GetExternalManager();
+  return manager->PullState(&mDisplayInfo.mDisplayState,
+                            &mLastSensorState,
+                            mDisplayInfo.mControllerState,
+                            aWaitCondition);
+}
+#else
+bool
+VRDisplayExternal::PullState()
+{
+  VRManager *vm = VRManager::Get();
+  VRSystemManagerExternal* manager = vm->GetExternalManager();
+  return manager->PullState(&mDisplayInfo.mDisplayState,
+                            &mLastSensorState,
+                            mDisplayInfo.mControllerState);
+}
+#endif
+
+VRSystemManagerExternal::VRSystemManagerExternal(VRExternalShmem* aAPIShmem /* = nullptr*/)
+ : mExternalShmem(aAPIShmem)
+#if !defined(MOZ_WIDGET_ANDROID)
+ , mSameProcess(aAPIShmem != nullptr)
+#endif
+{
+#if defined(XP_MACOSX)
+  mShmemFD = 0;
+#elif defined(XP_WIN)
+  mShmemFile = NULL;
+#elif defined(MOZ_WIDGET_ANDROID)
+  mExternalStructFailed = false;
+  mEnumerationCompleted = false;
+#endif
+  mDoShutdown = false;
+
+  if (!aAPIShmem) {
+    OpenShmem();
+  }
+}
+
+VRSystemManagerExternal::~VRSystemManagerExternal()
+{
+  CloseShmem();
+}
+
+void
+VRSystemManagerExternal::OpenShmem()
+{
+  if (mExternalShmem) {
+    return;
+#if defined(MOZ_WIDGET_ANDROID)
+  } else if (mExternalStructFailed) {
+    return;
+#endif // defined(MOZ_WIDGET_ANDROID)
+  }
+
+#if defined(XP_MACOSX)
+  if (mShmemFD == 0) {
+    mShmemFD = shm_open(kShmemName, O_RDWR, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
+  }
+  if (mShmemFD <= 0) {
+    mShmemFD = 0;
+    return;
+  }
+
+  struct stat sb;
+  fstat(mShmemFD, &sb);
+  off_t length = sb.st_size;
+  if (length < (off_t)sizeof(VRExternalShmem)) {
+    // TODO - Implement logging
+    CloseShmem();
+    return;
+  }
+
+  mExternalShmem = (VRExternalShmem*)mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, mShmemFD, 0);
+  if (mExternalShmem == MAP_FAILED) {
+    // TODO - Implement logging
+    mExternalShmem = NULL;
+    CloseShmem();
+    return;
+  }
+
+#elif defined(XP_WIN)
+  if (mShmemFile == NULL) {
+    if (gfxPrefs::VRProcessEnabled()) {
+      mShmemFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+                                      sizeof(VRExternalShmem), kShmemName);
+	    MOZ_ASSERT(GetLastError() == 0);
+    } else {
+      mShmemFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, kShmemName);
+    }
+
+    if (mShmemFile == NULL) {
+      // TODO - Implement logging
+      CloseShmem();
+      return;
+    }
+  }
+  LARGE_INTEGER length;
+  length.QuadPart = sizeof(VRExternalShmem);
+  mExternalShmem = (VRExternalShmem*)MapViewOfFile(mShmemFile, // handle to map object
+    FILE_MAP_ALL_ACCESS,  // read/write permission
+    0,
+    0,
+    length.QuadPart);
+
+  if (mExternalShmem == NULL) {
+    // TODO - Implement logging
+    CloseShmem();
+    return;
+  }
+#elif defined(MOZ_WIDGET_ANDROID)
+  mExternalShmem = (VRExternalShmem*)mozilla::GeckoVRManager::GetExternalContext();
+  if (!mExternalShmem) {
+    return;
+  }
+  int32_t version = -1;
+  int32_t size = 0;
+  if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
+    version = mExternalShmem->version;
+    size = mExternalShmem->size;
+    pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
+  } else {
+    return;
+  }
+  if (version != kVRExternalVersion) {
+    mExternalShmem = nullptr;
+    mExternalStructFailed = true;
+    return;
+  }
+  if (size != sizeof(VRExternalShmem)) {
+    mExternalShmem = nullptr;
+    mExternalStructFailed = true;
+    return;
+  }
+#endif
+  CheckForShutdown();
+}
+
+void
+VRSystemManagerExternal::CheckForShutdown()
+{
+  if (mDoShutdown) {
+    Shutdown();
+  }
+}
+
+void
+VRSystemManagerExternal::CloseShmem()
+{
+#if !defined(MOZ_WIDGET_ANDROID)
+  if (mSameProcess) {
+    return;
+  }
+#endif
+#if defined(XP_MACOSX)
+  if (mExternalShmem) {
+    munmap((void *)mExternalShmem, sizeof(VRExternalShmem));
+    mExternalShmem = NULL;
+  }
+  if (mShmemFD) {
+    close(mShmemFD);
+  }
+  mShmemFD = 0;
+#elif defined(XP_WIN)
+  if (mExternalShmem) {
+    UnmapViewOfFile((void *)mExternalShmem);
+    mExternalShmem = NULL;
+  }
+  if (mShmemFile) {
+    CloseHandle(mShmemFile);
+    mShmemFile = NULL;
+  }
+#elif defined(MOZ_WIDGET_ANDROID)
+  mExternalShmem = NULL;
+#endif
+}
+
+/*static*/ already_AddRefed<VRSystemManagerExternal>
+VRSystemManagerExternal::Create(VRExternalShmem* aAPIShmem /* = nullptr*/)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gfxPrefs::VREnabled()) {
+    return nullptr;
+  }
+
+  if ((!gfxPrefs::VRExternalEnabled() && aAPIShmem == nullptr)
+#if defined(XP_WIN)
+      || !XRE_IsGPUProcess()
+#endif
+     ) {
+    return nullptr;
+  }
+
+  RefPtr<VRSystemManagerExternal> manager = new VRSystemManagerExternal(aAPIShmem);
+  return manager.forget();
+}
+
+void
+VRSystemManagerExternal::Destroy()
+{
+  Shutdown();
+}
+
+void
+VRSystemManagerExternal::Shutdown()
+{
+  if (mDisplay) {
+    mDisplay = nullptr;
+  }
+  CloseShmem();
+  mDoShutdown = false;
+}
+
+void
+VRSystemManagerExternal::Run100msTasks()
+{
+  VRSystemManager::Run100msTasks();
+  // 1ms and 10ms tasks will always be run before
+  // the 100ms tasks, so no need to run them
+  // redundantly here.
+
+  CheckForShutdown();
+}
+
+void
+VRSystemManagerExternal::Enumerate()
+{
+  if (mDisplay == nullptr) {
+    OpenShmem();
+    if (mExternalShmem) {
+      VRDisplayState displayState;
+      memset(&displayState, 0, sizeof(VRDisplayState));
+      // We must block until enumeration has completed in order
+      // to signal that the WebVR promise should be resolved at the
+      // right time.
+#if defined(MOZ_WIDGET_ANDROID)
+      PullState(&displayState, nullptr, nullptr, [&](){
+        return mEnumerationCompleted;
+      });
+#else
+      while (!PullState(&displayState)) {
+#ifdef XP_WIN
+        Sleep(0);
+#else
+        sleep(0);
+#endif // XP_WIN
+      }
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+      if (displayState.mIsConnected) {
+        mDisplay = new VRDisplayExternal(displayState);
+      }
+    }
+  }
+}
+
+bool
+VRSystemManagerExternal::ShouldInhibitEnumeration()
+{
+  if (VRSystemManager::ShouldInhibitEnumeration()) {
+    return true;
+  }
+  if (!mEarliestRestartTime.IsNull() && mEarliestRestartTime > TimeStamp::Now()) {
+    // When the VR Service shuts down it informs us of how long we
+    // must wait until we can re-start it.
+    // We must wait until mEarliestRestartTime before attempting
+    // to enumerate again.
+    return true;
+  }
+  if (mDisplay) {
+    // When we find an a VR device, don't
+    // allow any further enumeration as it
+    // may get picked up redundantly by other
+    // API's.
+    return true;
+  }
+  return false;
+}
+
+void
+VRSystemManagerExternal::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
+{
+  if (mDisplay) {
+    aHMDResult.AppendElement(mDisplay);
+  }
+}
+
+bool
+VRSystemManagerExternal::GetIsPresenting()
+{
+  if (mDisplay) {
+    VRDisplayInfo displayInfo(mDisplay->GetDisplayInfo());
+    return displayInfo.GetPresentingGroups() != 0;
+  }
+
+  return false;
+}
+
+void
+VRSystemManagerExternal::VibrateHaptic(uint32_t aControllerIdx,
+                                       uint32_t aHapticIndex,
+                                       double aIntensity,
+                                       double aDuration,
+                                       const VRManagerPromise& aPromise)
+{
+  if (mDisplay) {
+    // VRDisplayClient::FireGamepadEvents() assigns a controller ID with ranges
+    // based on displayID.  We must translate this to the indexes understood by
+    // VRDisplayExternal.
+    uint32_t controllerBaseIndex =
+      kVRControllerMaxCount * mDisplay->GetDisplayInfo().mDisplayID;
+    uint32_t controllerIndex = aControllerIdx - controllerBaseIndex;
+    double aDurationSeconds = aDuration * 0.001f;
+    mDisplay->VibrateHaptic(
+      controllerIndex, aHapticIndex, aIntensity, aDurationSeconds, aPromise);
+  }
+}
+
+void
+VRSystemManagerExternal::StopVibrateHaptic(uint32_t aControllerIdx)
+{
+  if (mDisplay) {
+    // VRDisplayClient::FireGamepadEvents() assigns a controller ID with ranges
+    // based on displayID.  We must translate this to the indexes understood by
+    // VRDisplayExternal.
+    uint32_t controllerBaseIndex =
+      kVRControllerMaxCount * mDisplay->GetDisplayInfo().mDisplayID;
+    uint32_t controllerIndex = aControllerIdx - controllerBaseIndex;
+    mDisplay->StopVibrateHaptic(controllerIndex);
+  }
+}
+
+void
+VRSystemManagerExternal::GetControllers(
+  nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
+{
+  // Controller updates are handled in VRDisplayClient for
+  // VRSystemManagerExternal
+  aControllerResult.Clear();
+}
+
+void
+VRSystemManagerExternal::ScanForControllers()
+{
+  // Controller updates are handled in VRDisplayClient for
+  // VRSystemManagerExternal
+}
+
+void
+VRSystemManagerExternal::HandleInput()
+{
+  // Controller updates are handled in VRDisplayClient for
+  // VRSystemManagerExternal
+}
+
+void
+VRSystemManagerExternal::RemoveControllers()
+{
+  if (mDisplay) {
+    mDisplay->StopAllHaptics();
+  }
+  // Controller updates are handled in VRDisplayClient for
+  // VRSystemManagerExternal
+}
+
+#if defined(MOZ_WIDGET_ANDROID)
+bool
+VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
+                                   VRHMDSensorState* aSensorState /* = nullptr */,
+                                   VRControllerState* aControllerState /* = nullptr */,
+                                   const std::function<bool()>& aWaitCondition /* = nullptr */)
+{
+  MOZ_ASSERT(mExternalShmem);
+  if (!mExternalShmem) {
+    return false;
+  }
+  bool done = false;
+  while(!done) {
+    if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 0) {
+      while (true) {
+        memcpy(aDisplayState, (void*)&(mExternalShmem->state.displayState), sizeof(VRDisplayState));
+        if (aSensorState) {
+          memcpy(aSensorState, (void*)&(mExternalShmem->state.sensorState), sizeof(VRHMDSensorState));
+        }
+        if (aControllerState) {
+          memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
+        }
+        mEnumerationCompleted = mExternalShmem->state.enumerationCompleted;
+        if (aDisplayState->shutdown) {
+          mDoShutdown = true;
+          TimeStamp now = TimeStamp::Now();
+          if (!mEarliestRestartTime.IsNull() && mEarliestRestartTime < now) {
+            mEarliestRestartTime = now + TimeDuration::FromMilliseconds((double)aDisplayState->mMinRestartInterval);
+          }
+        }
+        if (!aWaitCondition || aWaitCondition()) {
+          done = true;
+          break;
+        }
+        // Block current thead using the condition variable until data changes
+        pthread_cond_wait((pthread_cond_t*)&mExternalShmem->systemCond, (pthread_mutex_t*)&mExternalShmem->systemMutex);
+      }
+      pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
+    } else if (!aWaitCondition) {
+      // pthread_mutex_lock failed and we are not waiting for a condition to exit from PullState call.
+      // return false to indicate that PullState call failed
+      return false;
+    }
+  }
+  return true;
+}
+#else 
+bool
+VRSystemManagerExternal::PullState(VRDisplayState* aDisplayState,
+                                   VRHMDSensorState* aSensorState /* = nullptr */,
+                                   VRControllerState* aControllerState /* = nullptr */)
+{
+  bool success = false;
+  MOZ_ASSERT(mExternalShmem);
+  if (mExternalShmem) {
+    VRExternalShmem tmp;
+    memcpy(&tmp, (void *)mExternalShmem, sizeof(VRExternalShmem));
+    if (tmp.generationA == tmp.generationB && tmp.generationA != 0 && tmp.generationA != -1 && tmp.state.enumerationCompleted) {
+      memcpy(aDisplayState, &tmp.state.displayState, sizeof(VRDisplayState));
+      if (aSensorState) {
+        memcpy(aSensorState, &tmp.state.sensorState, sizeof(VRHMDSensorState));
+      }
+      if (aControllerState) {
+        memcpy(aControllerState, (void*)&(mExternalShmem->state.controllerState), sizeof(VRControllerState) * kVRControllerMaxCount);
+      }
+      if (aDisplayState->shutdown) {
+        mDoShutdown = true;
+        TimeStamp now = TimeStamp::Now();
+        if (!mEarliestRestartTime.IsNull() && mEarliestRestartTime < now) {
+          mEarliestRestartTime = now + TimeDuration::FromMilliseconds((double)aDisplayState->mMinRestartInterval);
+        }
+      }
+      success = true;
+    }
+  }
+
+  return success;
+}
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+void
+VRSystemManagerExternal::PushState(VRBrowserState* aBrowserState, bool aNotifyCond)
+{
+  MOZ_ASSERT(aBrowserState);
+  MOZ_ASSERT(mExternalShmem);
+  if (mExternalShmem) {
+#if defined(MOZ_WIDGET_ANDROID)
+    if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) == 0) {
+      memcpy((void *)&(mExternalShmem->browserState), aBrowserState, sizeof(VRBrowserState));
+      if (aNotifyCond) {
+        pthread_cond_signal((pthread_cond_t*)&(mExternalShmem->browserCond));
+      }
+      pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
+    }
+#else
+    mExternalShmem->browserGenerationA++;
+    memcpy((void *)&(mExternalShmem->browserState), (void *)aBrowserState, sizeof(VRBrowserState));
+    mExternalShmem->browserGenerationB++;
+#endif // defined(MOZ_WIDGET_ANDROID)
+  }
+}
--- a/gfx/vr/gfxVRExternal.h
+++ b/gfx/vr/gfxVRExternal.h
@@ -1,155 +1,155 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_VR_EXTERNAL_H
-#define GFX_VR_EXTERNAL_H
-
-#include "nsTArray.h"
-#include "nsIScreen.h"
-#include "nsCOMPtr.h"
-#include "mozilla/RefPtr.h"
-
-#include "mozilla/gfx/2D.h"
-#include "mozilla/EnumeratedArray.h"
-#include "mozilla/UniquePtr.h"
-
-#include "gfxVR.h"
-#include "VRDisplayHost.h"
-
-#if defined(XP_MACOSX)
-class MacIOSurface;
-#endif
-namespace mozilla {
-namespace gfx {
-namespace impl {
-
-class VRDisplayExternal : public VRDisplayHost
-{
-public:
-  void ZeroSensor() override;
-
-protected:
-  VRHMDSensorState GetSensorState() override;
-  void StartPresentation() override;
-  void StopPresentation() override;
-  void StartVRNavigation() override;
-  void StopVRNavigation(const TimeDuration& aTimeout) override;
-
-  bool SubmitFrame(const layers::SurfaceDescriptor& aTexture,
-                   uint64_t aFrameId,
-                   const gfx::Rect& aLeftEyeRect,
-                   const gfx::Rect& aRightEyeRect) override;
-
-public:
-  explicit VRDisplayExternal(const VRDisplayState& aDisplayState);
-  void Refresh();
-  const VRControllerState& GetLastControllerState(uint32_t aStateIndex) const;
-  void VibrateHaptic(uint32_t aControllerIdx,
-                     uint32_t aHapticIndex,
-                     double aIntensity,
-                     double aDuration,
-                     const VRManagerPromise& aPromise);
-  void StopVibrateHaptic(uint32_t aControllerIdx);
-  void StopAllHaptics();
-  void Run1msTasks(double aDeltaTime) override;
-  void Run10msTasks() override;
-protected:
-  virtual ~VRDisplayExternal();
-  void Destroy();
-
-private:
-  bool PopulateLayerTexture(const layers::SurfaceDescriptor& aTexture,
-                            VRLayerTextureType* aTextureType,
-                            VRLayerTextureHandle* aTextureHandle);
-  void PushState(bool aNotifyCond = false);
-#if defined(MOZ_WIDGET_ANDROID)
-  bool PullState(const std::function<bool()>& aWaitCondition = nullptr);
-#else
-  bool PullState();
-#endif
-  void ClearHapticSlot(size_t aSlot);
-  void ExpireNavigationTransition();
-  void UpdateHaptics(double aDeltaTime);
-  nsTArray<UniquePtr<VRManagerPromise>> mHapticPromises;
-  // Duration of haptic pulse time remaining (milliseconds)
-  double mHapticPulseRemaining[kVRHapticsMaxCount];
-  VRTelemetry mTelemetry;
-  TimeStamp mVRNavigationTransitionEnd;
-  VRBrowserState mBrowserState;
-  VRHMDSensorState mLastSensorState;
-};
-
-} // namespace impl
-
-class VRSystemManagerExternal : public VRSystemManager
-{
-public:
-  static already_AddRefed<VRSystemManagerExternal> Create(VRExternalShmem* aAPIShmem = nullptr);
-
-  virtual void Destroy() override;
-  virtual void Shutdown() override;
-  virtual void Run100msTasks() override;
-  virtual void Enumerate() override;
-  virtual bool ShouldInhibitEnumeration() override;
-  virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
-  virtual bool GetIsPresenting() override;
-  virtual void HandleInput() override;
-  virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
-                              aControllerResult) override;
-  virtual void ScanForControllers() override;
-  virtual void RemoveControllers() override;
-  virtual void VibrateHaptic(uint32_t aControllerIdx,
-                             uint32_t aHapticIndex,
-                             double aIntensity,
-                             double aDuration,
-                             const VRManagerPromise& aPromise) override;
-  virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
-#if defined(MOZ_WIDGET_ANDROID)
-  bool PullState(VRDisplayState* aDisplayState,
-                 VRHMDSensorState* aSensorState = nullptr,
-                 VRControllerState* aControllerState = nullptr,
-                 const std::function<bool()>& aWaitCondition = nullptr);
-#else
-  bool PullState(VRDisplayState* aDisplayState,
-                 VRHMDSensorState* aSensorState = nullptr,
-                 VRControllerState* aControllerState = nullptr);
-#endif
-  void PushState(VRBrowserState* aBrowserState, const bool aNotifyCond = false);
-
-protected:
-  explicit VRSystemManagerExternal(VRExternalShmem* aAPIShmem = nullptr);
-  virtual ~VRSystemManagerExternal();
-
-private:
-  // there can only be one
-  RefPtr<impl::VRDisplayExternal> mDisplay;
-#if defined(XP_MACOSX)
-  int mShmemFD;
-#elif defined(XP_WIN)
-  base::ProcessHandle mShmemFile;
-#elif defined(MOZ_WIDGET_ANDROID)
-  
-  bool mExternalStructFailed;
-  bool mEnumerationCompleted;
-#endif
-  bool mDoShutdown;
-
-  volatile VRExternalShmem* mExternalShmem;
-#if !defined(MOZ_WIDGET_ANDROID)
-  bool mSameProcess;
-#endif
-  TimeStamp mEarliestRestartTime;
-
-  void OpenShmem();
-  void CloseShmem();
-  void CheckForShutdown();
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-
-#endif /* GFX_VR_EXTERNAL_H */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_VR_EXTERNAL_H
+#define GFX_VR_EXTERNAL_H
+
+#include "nsTArray.h"
+#include "nsIScreen.h"
+#include "nsCOMPtr.h"
+#include "mozilla/RefPtr.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/EnumeratedArray.h"
+#include "mozilla/UniquePtr.h"
+
+#include "gfxVR.h"
+#include "VRDisplayHost.h"
+
+#if defined(XP_MACOSX)
+class MacIOSurface;
+#endif
+namespace mozilla {
+namespace gfx {
+namespace impl {
+
+class VRDisplayExternal : public VRDisplayHost
+{
+public:
+  void ZeroSensor() override;
+
+protected:
+  VRHMDSensorState GetSensorState() override;
+  void StartPresentation() override;
+  void StopPresentation() override;
+  void StartVRNavigation() override;
+  void StopVRNavigation(const TimeDuration& aTimeout) override;
+
+  bool SubmitFrame(const layers::SurfaceDescriptor& aTexture,
+                   uint64_t aFrameId,
+                   const gfx::Rect& aLeftEyeRect,
+                   const gfx::Rect& aRightEyeRect) override;
+
+public:
+  explicit VRDisplayExternal(const VRDisplayState& aDisplayState);
+  void Refresh();
+  const VRControllerState& GetLastControllerState(uint32_t aStateIndex) const;
+  void VibrateHaptic(uint32_t aControllerIdx,
+                     uint32_t aHapticIndex,
+                     double aIntensity,
+                     double aDuration,
+                     const VRManagerPromise& aPromise);
+  void StopVibrateHaptic(uint32_t aControllerIdx);
+  void StopAllHaptics();
+  void Run1msTasks(double aDeltaTime) override;
+  void Run10msTasks() override;
+protected:
+  virtual ~VRDisplayExternal();
+  void Destroy();
+
+private:
+  bool PopulateLayerTexture(const layers::SurfaceDescriptor& aTexture,
+                            VRLayerTextureType* aTextureType,
+                            VRLayerTextureHandle* aTextureHandle);
+  void PushState(bool aNotifyCond = false);
+#if defined(MOZ_WIDGET_ANDROID)
+  bool PullState(const std::function<bool()>& aWaitCondition = nullptr);
+#else
+  bool PullState();
+#endif
+  void ClearHapticSlot(size_t aSlot);
+  void ExpireNavigationTransition();
+  void UpdateHaptics(double aDeltaTime);
+  nsTArray<UniquePtr<VRManagerPromise>> mHapticPromises;
+  // Duration of haptic pulse time remaining (milliseconds)
+  double mHapticPulseRemaining[kVRHapticsMaxCount];
+  VRTelemetry mTelemetry;
+  TimeStamp mVRNavigationTransitionEnd;
+  VRBrowserState mBrowserState;
+  VRHMDSensorState mLastSensorState;
+};
+
+} // namespace impl
+
+class VRSystemManagerExternal : public VRSystemManager
+{
+public:
+  static already_AddRefed<VRSystemManagerExternal> Create(VRExternalShmem* aAPIShmem = nullptr);
+
+  virtual void Destroy() override;
+  virtual void Shutdown() override;
+  virtual void Run100msTasks() override;
+  virtual void Enumerate() override;
+  virtual bool ShouldInhibitEnumeration() override;
+  virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
+  virtual bool GetIsPresenting() override;
+  virtual void HandleInput() override;
+  virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
+                              aControllerResult) override;
+  virtual void ScanForControllers() override;
+  virtual void RemoveControllers() override;
+  virtual void VibrateHaptic(uint32_t aControllerIdx,
+                             uint32_t aHapticIndex,
+                             double aIntensity,
+                             double aDuration,
+                             const VRManagerPromise& aPromise) override;
+  virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
+#if defined(MOZ_WIDGET_ANDROID)
+  bool PullState(VRDisplayState* aDisplayState,
+                 VRHMDSensorState* aSensorState = nullptr,
+                 VRControllerState* aControllerState = nullptr,
+                 const std::function<bool()>& aWaitCondition = nullptr);
+#else
+  bool PullState(VRDisplayState* aDisplayState,
+                 VRHMDSensorState* aSensorState = nullptr,
+                 VRControllerState* aControllerState = nullptr);
+#endif
+  void PushState(VRBrowserState* aBrowserState, const bool aNotifyCond = false);
+
+protected:
+  explicit VRSystemManagerExternal(VRExternalShmem* aAPIShmem = nullptr);
+  virtual ~VRSystemManagerExternal();
+
+private:
+  // there can only be one
+  RefPtr<impl::VRDisplayExternal> mDisplay;
+#if defined(XP_MACOSX)
+  int mShmemFD;
+#elif defined(XP_WIN)
+  base::ProcessHandle mShmemFile;
+#elif defined(MOZ_WIDGET_ANDROID)
+  
+  bool mExternalStructFailed;
+  bool mEnumerationCompleted;
+#endif
+  bool mDoShutdown;
+
+  volatile VRExternalShmem* mExternalShmem;
+#if !defined(MOZ_WIDGET_ANDROID)
+  bool mSameProcess;
+#endif
+  TimeStamp mEarliestRestartTime;
+
+  void OpenShmem();
+  void CloseShmem();
+  void CheckForShutdown();
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+
+#endif /* GFX_VR_EXTERNAL_H */
--- a/gfx/vr/service/OculusSession.cpp
+++ b/gfx/vr/service/OculusSession.cpp
@@ -1,1586 +1,1586 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef XP_WIN
-#error "Oculus support only available for Windows"
-#endif
-
-#include <math.h>
-#include <d3d11.h>
-
-#include "gfxPrefs.h"
-#include "mozilla/dom/GamepadEventTypes.h"
-#include "mozilla/dom/GamepadBinding.h"
-#include "mozilla/gfx/DeviceManagerDx.h"
-#include "mozilla/SharedLibrary.h"
-#include "OculusSession.h"
-
-/** XXX The DX11 objects and quad blitting could be encapsulated
- *    into a separate object if either Oculus starts supporting
- *     non-Windows platforms or the blit is needed by other HMD\
- *     drivers.
- *     Alternately, we could remove the extra blit for
- *     Oculus as well with some more refactoring.
- */
-
-// See CompositorD3D11Shaders.h
-namespace mozilla {
-namespace layers {
-struct ShaderBytes
-{
-  const void* mData;
-  size_t mLength;
-};
-extern ShaderBytes sRGBShader;
-extern ShaderBytes sLayerQuadVS;
-} // namespace layers
-} // namespace mozilla
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::layers;
-
-namespace {
-
-static pfn_ovr_Initialize ovr_Initialize = nullptr;
-static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
-static pfn_ovr_GetLastErrorInfo ovr_GetLastErrorInfo = nullptr;
-static pfn_ovr_GetVersionString ovr_GetVersionString = nullptr;
-static pfn_ovr_TraceMessage ovr_TraceMessage = nullptr;
-static pfn_ovr_IdentifyClient ovr_IdentifyClient = nullptr;
-static pfn_ovr_GetHmdDesc ovr_GetHmdDesc = nullptr;
-static pfn_ovr_GetTrackerCount ovr_GetTrackerCount = nullptr;
-static pfn_ovr_GetTrackerDesc ovr_GetTrackerDesc = nullptr;
-static pfn_ovr_Create ovr_Create = nullptr;
-static pfn_ovr_Destroy ovr_Destroy = nullptr;
-static pfn_ovr_GetSessionStatus ovr_GetSessionStatus = nullptr;
-static pfn_ovr_IsExtensionSupported ovr_IsExtensionSupported = nullptr;
-static pfn_ovr_EnableExtension ovr_EnableExtension = nullptr;
-static pfn_ovr_SetTrackingOriginType ovr_SetTrackingOriginType = nullptr;
-static pfn_ovr_GetTrackingOriginType ovr_GetTrackingOriginType = nullptr;
-static pfn_ovr_RecenterTrackingOrigin ovr_RecenterTrackingOrigin = nullptr;
-static pfn_ovr_SpecifyTrackingOrigin ovr_SpecifyTrackingOrigin = nullptr;
-static pfn_ovr_ClearShouldRecenterFlag ovr_ClearShouldRecenterFlag = nullptr;
-static pfn_ovr_GetTrackingState ovr_GetTrackingState = nullptr;
-static pfn_ovr_GetDevicePoses ovr_GetDevicePoses = nullptr;
-static pfn_ovr_GetTrackerPose ovr_GetTrackerPose = nullptr;
-static pfn_ovr_GetInputState ovr_GetInputState = nullptr;
-static pfn_ovr_GetConnectedControllerTypes ovr_GetConnectedControllerTypes =
-  nullptr;
-static pfn_ovr_GetTouchHapticsDesc ovr_GetTouchHapticsDesc = nullptr;
-static pfn_ovr_SetControllerVibration ovr_SetControllerVibration = nullptr;
-static pfn_ovr_SubmitControllerVibration ovr_SubmitControllerVibration =
-  nullptr;
-static pfn_ovr_GetControllerVibrationState ovr_GetControllerVibrationState =
-  nullptr;
-static pfn_ovr_TestBoundary ovr_TestBoundary = nullptr;
-static pfn_ovr_TestBoundaryPoint ovr_TestBoundaryPoint = nullptr;
-static pfn_ovr_SetBoundaryLookAndFeel ovr_SetBoundaryLookAndFeel = nullptr;
-static pfn_ovr_ResetBoundaryLookAndFeel ovr_ResetBoundaryLookAndFeel = nullptr;
-static pfn_ovr_GetBoundaryGeometry ovr_GetBoundaryGeometry = nullptr;
-static pfn_ovr_GetBoundaryDimensions ovr_GetBoundaryDimensions = nullptr;
-static pfn_ovr_GetBoundaryVisible ovr_GetBoundaryVisible = nullptr;
-static pfn_ovr_RequestBoundaryVisible ovr_RequestBoundaryVisible = nullptr;
-static pfn_ovr_GetTextureSwapChainLength ovr_GetTextureSwapChainLength =
-  nullptr;
-static pfn_ovr_GetTextureSwapChainCurrentIndex
-  ovr_GetTextureSwapChainCurrentIndex = nullptr;
-static pfn_ovr_GetTextureSwapChainDesc ovr_GetTextureSwapChainDesc = nullptr;
-static pfn_ovr_CommitTextureSwapChain ovr_CommitTextureSwapChain = nullptr;
-static pfn_ovr_DestroyTextureSwapChain ovr_DestroyTextureSwapChain = nullptr;
-static pfn_ovr_DestroyMirrorTexture ovr_DestroyMirrorTexture = nullptr;
-static pfn_ovr_GetFovTextureSize ovr_GetFovTextureSize = nullptr;
-static pfn_ovr_GetRenderDesc2 ovr_GetRenderDesc2 = nullptr;
-static pfn_ovr_WaitToBeginFrame ovr_WaitToBeginFrame = nullptr;
-static pfn_ovr_BeginFrame ovr_BeginFrame = nullptr;
-static pfn_ovr_EndFrame ovr_EndFrame = nullptr;
-static pfn_ovr_SubmitFrame ovr_SubmitFrame = nullptr;
-static pfn_ovr_GetPerfStats ovr_GetPerfStats = nullptr;
-static pfn_ovr_ResetPerfStats ovr_ResetPerfStats = nullptr;
-static pfn_ovr_GetPredictedDisplayTime ovr_GetPredictedDisplayTime = nullptr;
-static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
-static pfn_ovr_GetBool ovr_GetBool = nullptr;
-static pfn_ovr_SetBool ovr_SetBool = nullptr;
-static pfn_ovr_GetInt ovr_GetInt = nullptr;
-static pfn_ovr_SetInt ovr_SetInt = nullptr;
-static pfn_ovr_GetFloat ovr_GetFloat = nullptr;
-static pfn_ovr_SetFloat ovr_SetFloat = nullptr;
-static pfn_ovr_GetFloatArray ovr_GetFloatArray = nullptr;
-static pfn_ovr_SetFloatArray ovr_SetFloatArray = nullptr;
-static pfn_ovr_GetString ovr_GetString = nullptr;
-static pfn_ovr_SetString ovr_SetString = nullptr;
-static pfn_ovr_GetExternalCameras ovr_GetExternalCameras = nullptr;
-static pfn_ovr_SetExternalCameraProperties ovr_SetExternalCameraProperties =
-  nullptr;
-
-#ifdef XP_WIN
-static pfn_ovr_CreateTextureSwapChainDX ovr_CreateTextureSwapChainDX = nullptr;
-static pfn_ovr_GetTextureSwapChainBufferDX ovr_GetTextureSwapChainBufferDX =
-  nullptr;
-static pfn_ovr_CreateMirrorTextureDX ovr_CreateMirrorTextureDX = nullptr;
-static pfn_ovr_GetMirrorTextureBufferDX ovr_GetMirrorTextureBufferDX = nullptr;
-#endif
-
-static pfn_ovr_CreateTextureSwapChainGL ovr_CreateTextureSwapChainGL = nullptr;
-static pfn_ovr_GetTextureSwapChainBufferGL ovr_GetTextureSwapChainBufferGL =
-  nullptr;
-static pfn_ovr_CreateMirrorTextureGL ovr_CreateMirrorTextureGL = nullptr;
-static pfn_ovr_GetMirrorTextureBufferGL ovr_GetMirrorTextureBufferGL = nullptr;
-
-#ifdef HAVE_64BIT_BUILD
-#define BUILD_BITS 64
-#else
-#define BUILD_BITS 32
-#endif
-
-#define OVR_PRODUCT_VERSION 1
-#define OVR_MAJOR_VERSION 1
-#define OVR_MINOR_VERSION 19
-
-static const uint32_t kNumOculusButtons = 6;
-static const uint32_t kNumOculusHaptcs = 1;
-static const uint32_t kNumOculusAxes = 2;
-ovrControllerType OculusControllerTypes[2] = { ovrControllerType_LTouch,
-                                               ovrControllerType_RTouch };
-const char* OculusControllerNames[2] = { "Oculus Touch (Left)",
-                                         "Oculus Touch (Right)" };
-dom::GamepadHand OculusControllerHand[2] = { dom::GamepadHand::Left,
-                                             dom::GamepadHand::Right };
-ovrButton OculusControllerButtons[2][kNumOculusButtons] = {
-  { ovrButton_LThumb,
-    (ovrButton)0,
-    (ovrButton)0,
-    ovrButton_X,
-    ovrButton_Y,
-    (ovrButton)0 },
-  { ovrButton_RThumb,
-    (ovrButton)0,
-    (ovrButton)0,
-    ovrButton_A,
-    ovrButton_B,
-    (ovrButton)0 },
-};
-
-ovrTouch OculusControllerTouches[2][kNumOculusButtons] = {
-  { (ovrTouch)0,
-    ovrTouch_LIndexTrigger,
-    (ovrTouch)0,
-    (ovrTouch)0,
-    (ovrTouch)0,
-    ovrTouch_LThumbRest },
-  { (ovrTouch)0,
-    ovrTouch_RIndexTrigger,
-    (ovrTouch)0,
-    (ovrTouch)0,
-    (ovrTouch)0,
-    ovrTouch_RThumbRest },
-};
-
-void
-UpdateButton(const ovrInputState& aInputState,
-             uint32_t aHandIdx,
-             uint32_t aButtonIdx,
-             VRControllerState& aControllerState)
-{
-  if (aInputState.Buttons & OculusControllerButtons[aHandIdx][aButtonIdx]) {
-    aControllerState.buttonPressed |= ((uint64_t)1 << aButtonIdx);
-  }
-  if (aInputState.Touches & OculusControllerTouches[aHandIdx][aButtonIdx]) {
-    aControllerState.buttonTouched |= ((uint64_t)1 << aButtonIdx);
-  }
-}
-
-VRFieldOfView
-FromFovPort(const ovrFovPort& aFOV)
-{
-  VRFieldOfView fovInfo;
-  fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
-  fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
-  fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
-  fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
-  return fovInfo;
-}
-
-} // anonymous namespace
-
-namespace mozilla {
-namespace gfx {
-
-OculusSession::OculusSession()
-  : VRSession()
-  , mOvrLib(nullptr)
-  , mSession(nullptr)
-  , mInitFlags((ovrInitFlags)0)
-  , mTextureSet(nullptr)
-  , mQuadVS(nullptr)
-  , mQuadPS(nullptr)
-  , mLinearSamplerState(nullptr)
-  , mVSConstantBuffer(nullptr)
-  , mPSConstantBuffer(nullptr)
-  , mVertexBuffer(nullptr)
-  , mInputLayout(nullptr)
-  , mRemainingVibrateTime{}
-  , mHapticPulseIntensity{}
-  , mIsPresenting(false)
-{
-}
-
-OculusSession::~OculusSession()
-{
-  Shutdown();
-}
-
-bool
-OculusSession::Initialize(mozilla::gfx::VRSystemState& aSystemState)
-{
-  if (!CreateD3DObjects()) {
-    return false;
-  }
-  if (!CreateShaders()) {
-    return false;
-  }
-
-  if (!LoadOvrLib()) {
-    return false;
-  }
-  // We start off with an invisible session, then re-initialize
-  // with visible session once WebVR content starts rendering.
-  if (!ChangeVisibility(false)) {
-    return false;
-  }
-  if (!InitState(aSystemState)) {
-    return false;
-  }
-
-  mPresentationSize =
-    IntSize(aSystemState.displayState.mEyeResolution.width * 2,
-            aSystemState.displayState.mEyeResolution.height);
-  return true;
-}
-
-void
-OculusSession::UpdateVisibility()
-{
-  // Do not immediately re-initialize with an invisible session after
-  // the end of a VR presentation.  Waiting for the configured duraction
-  // ensures that the user will not drop to Oculus Home during VR link
-  // traversal.
-  if (mIsPresenting) {
-    // We are currently rendering immersive content.
-    // Avoid interrupting the session
-    return;
-  }
-  if (mInitFlags & ovrInit_Invisible) {
-    // We are already invisible
-    return;
-  }
-  if (mLastPresentationEnd.IsNull()) {
-    // There has been no presentation yet
-    return;
-  }
-
-  TimeDuration duration = TimeStamp::Now() - mLastPresentationEnd;
-  TimeDuration timeout = TimeDuration::FromMilliseconds(gfxPrefs::VROculusPresentTimeout());
-  if (timeout <= TimeDuration(0) || duration >= timeout) {
-    if (!ChangeVisibility(false)) {
-      gfxWarning() << "OculusSession::ChangeVisibility(false) failed";
-    }
-  }
-}
-
-void
-OculusSession::CoverTransitions()
-{
-  // While content is loading or during immersive-mode link
-  // traversal, we need to prevent the user from seeing the
-  // last rendered frame.
-  // We render black frames to cover up the transition.
-  MOZ_ASSERT(mSession);
-  if (mIsPresenting) {
-    // We are currently rendering immersive content.
-    // Avoid interrupting the session
-    return;
-  }
-
-  if (mInitFlags & ovrInit_Invisible) {
-    // We are invisible, nothing to cover up
-    return;
-  }
-
-  // Render a black frame
-  ovrLayerEyeFov layer;
-  memset(&layer, 0, sizeof(layer));
-  layer.Header.Type = ovrLayerType_Disabled;
-  ovrLayerHeader* layers = &layer.Header;
-  ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1);
-}
-
-bool
-OculusSession::ChangeVisibility(bool bVisible)
-{
-  ovrInitFlags flags =
-    (ovrInitFlags)(ovrInit_RequestVersion | ovrInit_MixedRendering);
-  if (gfxPrefs::VROculusInvisibleEnabled() && !bVisible) {
-    flags = (ovrInitFlags)(flags | ovrInit_Invisible);
-  }
-  if (mInitFlags == flags) {
-    // The new state is the same, nothing to do
-    return true;
-  }
-
-  // Tear everything down
-  StopRendering();
-  StopSession();
-  StopLib();
-
-  // Start it back up
-  if (!StartLib(flags)) {
-    return false;
-  }
-  if (!StartSession()) {
-    return false;
-  }
-  return true;
-}
-
-void OculusSession::Shutdown()
-{
-  StopRendering();
-  StopSession();
-  StopLib();
-  UnloadOvrLib();
-  DestroyShaders();
-}
-
-void
-OculusSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState)
-{
-  if (!mSession) {
-    return;
-  }
-
-  ovrSessionStatus status;
-  if (OVR_SUCCESS(ovr_GetSessionStatus(mSession, &status))) {
-    aSystemState.displayState.mIsConnected = status.HmdPresent;
-    aSystemState.displayState.mIsMounted = status.HmdMounted;
-    mShouldQuit = status.ShouldQuit;
-\
-  } else {
-    aSystemState.displayState.mIsConnected = false;
-    aSystemState.displayState.mIsMounted = false;
-  }
-  UpdateHaptics();
-  UpdateVisibility();
-  CoverTransitions();
-}
-
-void
-OculusSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState)
-{
-  UpdateHeadsetPose(aSystemState);
-  UpdateEyeParameters(aSystemState);
-  UpdateControllers(aSystemState);
-  UpdateTelemetry(aSystemState);
-  aSystemState.sensorState.inputFrameID++;
-}
-
-bool
-OculusSession::StartPresentation()
-{
-  /**
-   * XXX - We should resolve fail the promise returned by
-   *       VRDisplay.requestPresent() when the DX11 resources fail allocation
-   *       in VRDisplayOculus::StartPresentation().
-   *       Bailing out here prevents the crash but content should be aware
-   *       that frames are not being presented.
-   *       See Bug 1299309.
-   **/
-  if (!ChangeVisibility(true)) {
-    return false;
-  }
-  if (!StartRendering()) {
-    StopRendering();
-    return false;
-  }
-  mIsPresenting = true;
-  return true;
-}
-
-void
-OculusSession::StopPresentation()
-{
-  mLastPresentationEnd = TimeStamp::Now();
-  mIsPresenting = false;
-}
-
-bool
-OculusSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                           ID3D11Texture2D* aTexture)
-{
-  if (!IsPresentationReady()) {
-    return false;
-  }
-
-  D3D11_TEXTURE2D_DESC textureDesc = { 0 };
-  aTexture->GetDesc(&textureDesc);
-
-  int currentRenderTarget = 0;
-  ovrResult orv = ovr_GetTextureSwapChainCurrentIndex(
-    mSession, mTextureSet, &currentRenderTarget);
-  if (orv != ovrSuccess) {
-    NS_WARNING("ovr_GetTextureSwapChainCurrentIndex failed.");
-    return false;
-  }
-
-  ID3D11RenderTargetView* view = mRTView[currentRenderTarget];
-
-  float clear[] = { 0.0f, 0.0f, 0.0f, 1.0f };
-  mContext->ClearRenderTargetView(view, clear);
-  mContext->OMSetRenderTargets(1, &view, nullptr);
-
-  Matrix viewMatrix = Matrix::Translation(-1.0, 1.0);
-  viewMatrix.PreScale(2.0f / float(textureDesc.Width),
-                      2.0f / float(textureDesc.Height));
-  viewMatrix.PreScale(1.0f, -1.0f);
-  Matrix4x4 projection = Matrix4x4::From2D(viewMatrix);
-  projection._33 = 0.0f;
-
-  Matrix transform2d;
-  gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
-
-  D3D11_VIEWPORT viewport;
-  viewport.MinDepth = 0.0f;
-  viewport.MaxDepth = 1.0f;
-  viewport.Width = textureDesc.Width;
-  viewport.Height = textureDesc.Height;
-  viewport.TopLeftX = 0;
-  viewport.TopLeftY = 0;
-
-  D3D11_RECT scissor;
-  scissor.left = 0;
-  scissor.right = textureDesc.Width;
-  scissor.top = 0;
-  scissor.bottom = textureDesc.Height;
-
-  memcpy(&mVSConstants.layerTransform,
-         &transform._11,
-         sizeof(mVSConstants.layerTransform));
-  memcpy(
-    &mVSConstants.projection, &projection._11, sizeof(mVSConstants.projection));
-  mVSConstants.renderTargetOffset[0] = 0.0f;
-  mVSConstants.renderTargetOffset[1] = 0.0f;
-  mVSConstants.layerQuad =
-    Rect(0.0f, 0.0f, textureDesc.Width, textureDesc.Height);
-  mVSConstants.textureCoords = Rect(0.0f, 1.0f, 1.0f, -1.0f);
-
-  mPSConstants.layerOpacity[0] = 1.0f;
-
-  ID3D11Buffer* vbuffer = mVertexBuffer;
-  UINT vsize = sizeof(Vertex);
-  UINT voffset = 0;
-  mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
-  mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
-  mContext->IASetInputLayout(mInputLayout);
-  mContext->RSSetViewports(1, &viewport);
-  mContext->RSSetScissorRects(1, &scissor);
-  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
-  mContext->VSSetShader(mQuadVS, nullptr, 0);
-  mContext->PSSetShader(mQuadPS, nullptr, 0);
-
-  RefPtr<ID3D11ShaderResourceView> srView;
-  HRESULT hr = mDevice->CreateShaderResourceView(
-    aTexture, nullptr, getter_AddRefs(srView));
-  if (FAILED(hr)) {
-    gfxWarning() << "Could not create shader resource view for Oculus: "
-                 << hexa(hr);
-    return false;
-  }
-  ID3D11ShaderResourceView* viewPtr = srView.get();
-  mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &viewPtr);
-  // XXX Use Constant from TexSlot in CompositorD3D11.cpp?
-
-  ID3D11SamplerState* sampler = mLinearSamplerState;
-  mContext->PSSetSamplers(0, 1, &sampler);
-
-  if (!UpdateConstantBuffers()) {
-    NS_WARNING("Failed to update constant buffers for Oculus");
-    return false;
-  }
-
-  mContext->Draw(4, 0);
-
-  orv = ovr_CommitTextureSwapChain(mSession, mTextureSet);
-  if (orv != ovrSuccess) {
-    NS_WARNING("ovr_CommitTextureSwapChain failed.");
-    return false;
-  }
-
-  ovrLayerEyeFov layer;
-  memset(&layer, 0, sizeof(layer));
-  layer.Header.Type = ovrLayerType_EyeFov;
-  layer.Header.Flags = 0;
-  layer.ColorTexture[0] = mTextureSet;
-  layer.ColorTexture[1] = nullptr;
-  layer.Fov[0] = mFOVPort[0];
-  layer.Fov[1] = mFOVPort[1];
-  layer.Viewport[0].Pos.x = textureDesc.Width * aLayer.mLeftEyeRect.x;
-  layer.Viewport[0].Pos.y = textureDesc.Height * aLayer.mLeftEyeRect.y;
-  layer.Viewport[0].Size.w = textureDesc.Width * aLayer.mLeftEyeRect.width;
-  layer.Viewport[0].Size.h = textureDesc.Height * aLayer.mLeftEyeRect.height;
-  layer.Viewport[1].Pos.x = textureDesc.Width * aLayer.mRightEyeRect.x;
-  layer.Viewport[1].Pos.y = textureDesc.Height * aLayer.mRightEyeRect.y;
-  layer.Viewport[1].Size.w = textureDesc.Width * aLayer.mRightEyeRect.width;
-  layer.Viewport[1].Size.h = textureDesc.Height * aLayer.mRightEyeRect.height;
-
-  for (uint32_t i = 0; i < 2; ++i) {
-    layer.RenderPose[i].Orientation.x = mFrameStartPose[i].Orientation.x;
-    layer.RenderPose[i].Orientation.y = mFrameStartPose[i].Orientation.y;
-    layer.RenderPose[i].Orientation.z = mFrameStartPose[i].Orientation.z;
-    layer.RenderPose[i].Orientation.w = mFrameStartPose[i].Orientation.w;
-    layer.RenderPose[i].Position.x = mFrameStartPose[i].Position.x;
-    layer.RenderPose[i].Position.y = mFrameStartPose[i].Position.y;
-    layer.RenderPose[i].Position.z = mFrameStartPose[i].Position.z;
-  }
-
-  ovrLayerHeader* layers = &layer.Header;
-  orv = ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1);
-  // ovr_SubmitFrame will fail during the Oculus health and safety warning.
-  // and will start succeeding once the warning has been dismissed by the user.
-
-  if (!OVR_UNQUALIFIED_SUCCESS(orv)) {
-    /**
-     * We wish to throttle the framerate for any case that the rendered
-     * result is not visible.  In some cases, such as during the Oculus
-     * "health and safety warning", orv will be > 0 (OVR_SUCCESS but not
-     * OVR_UNQUALIFIED_SUCCESS) and ovr_SubmitFrame will not block.
-     * In this case, returning true would have resulted in an unthrottled
-     * render loop hiting excessive frame rates and consuming resources.
-     */
-    return false;
-  }
-
-  return true;
-}
-
-bool
-OculusSession::LoadOvrLib()
-{
-  if (mOvrLib) {
-    // Already loaded, early exit
-    return true;
-  }
-#if defined(_WIN32)
-  nsTArray<nsString> libSearchPaths;
-  nsString libName;
-  nsString searchPath;
-
-  static const char dirSep = '\\';
-  static const int pathLen = 260;
-  searchPath.SetCapacity(pathLen);
-  int realLen =
-    ::GetSystemDirectoryW(char16ptr_t(searchPath.BeginWriting()), pathLen);
-  if (realLen != 0 && realLen < pathLen) {
-    searchPath.SetLength(realLen);
-    libSearchPaths.AppendElement(searchPath);
-  }
-  libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
-
-  // search the path/module dir
-  libSearchPaths.InsertElementsAt(0, 1, EmptyString());
-
-  // If the env var is present, we override libName
-  if (_wgetenv(L"OVR_LIB_PATH")) {
-    searchPath = _wgetenv(L"OVR_LIB_PATH");
-    libSearchPaths.InsertElementsAt(0, 1, searchPath);
-  }
-
-  if (_wgetenv(L"OVR_LIB_NAME")) {
-    libName = _wgetenv(L"OVR_LIB_NAME");
-  }
-
-  for (uint32_t i = 0; i < libSearchPaths.Length(); ++i) {
-    nsString& libPath = libSearchPaths[i];
-    nsString fullName;
-    if (libPath.Length() == 0) {
-      fullName.Assign(libName);
-    } else {
-      fullName.AppendPrintf("%s%c%s", libPath.get(), dirSep, libName.get());
-    }
-
-    mOvrLib = LoadLibraryWithFlags(fullName.get());
-    if (mOvrLib) {
-      break;
-    }
-  }
-#else
-#error "Unsupported platform!"
-#endif
-
-  if (!mOvrLib) {
-    return false;
-  }
-
-#define REQUIRE_FUNCTION(_x)                                                   \
-  do {                                                                         \
-    *(void**)&_x = (void*)PR_FindSymbol(mOvrLib, #_x);                         \
-    if (!_x) {                                                                 \
-      printf_stderr(#_x " symbol missing\n");                                  \
-      goto fail;                                                               \
-    }                                                                          \
-  } while (0)
-
-  REQUIRE_FUNCTION(ovr_Initialize);
-  REQUIRE_FUNCTION(ovr_Shutdown);
-  REQUIRE_FUNCTION(ovr_GetLastErrorInfo);
-  REQUIRE_FUNCTION(ovr_GetVersionString);
-  REQUIRE_FUNCTION(ovr_TraceMessage);
-  REQUIRE_FUNCTION(ovr_IdentifyClient);
-  REQUIRE_FUNCTION(ovr_GetHmdDesc);
-  REQUIRE_FUNCTION(ovr_GetTrackerCount);
-  REQUIRE_FUNCTION(ovr_GetTrackerDesc);
-  REQUIRE_FUNCTION(ovr_Create);
-  REQUIRE_FUNCTION(ovr_Destroy);
-  REQUIRE_FUNCTION(ovr_GetSessionStatus);
-  REQUIRE_FUNCTION(ovr_IsExtensionSupported);
-  REQUIRE_FUNCTION(ovr_EnableExtension);
-  REQUIRE_FUNCTION(ovr_SetTrackingOriginType);
-  REQUIRE_FUNCTION(ovr_GetTrackingOriginType);
-  REQUIRE_FUNCTION(ovr_RecenterTrackingOrigin);
-  REQUIRE_FUNCTION(ovr_SpecifyTrackingOrigin);
-  REQUIRE_FUNCTION(ovr_ClearShouldRecenterFlag);
-  REQUIRE_FUNCTION(ovr_GetTrackingState);
-  REQUIRE_FUNCTION(ovr_GetDevicePoses);
-  REQUIRE_FUNCTION(ovr_GetTrackerPose);
-  REQUIRE_FUNCTION(ovr_GetInputState);
-  REQUIRE_FUNCTION(ovr_GetConnectedControllerTypes);
-  REQUIRE_FUNCTION(ovr_GetTouchHapticsDesc);
-  REQUIRE_FUNCTION(ovr_SetControllerVibration);
-  REQUIRE_FUNCTION(ovr_SubmitControllerVibration);
-  REQUIRE_FUNCTION(ovr_GetControllerVibrationState);
-  REQUIRE_FUNCTION(ovr_TestBoundary);
-  REQUIRE_FUNCTION(ovr_TestBoundaryPoint);
-  REQUIRE_FUNCTION(ovr_SetBoundaryLookAndFeel);
-  REQUIRE_FUNCTION(ovr_ResetBoundaryLookAndFeel);
-  REQUIRE_FUNCTION(ovr_GetBoundaryGeometry);
-  REQUIRE_FUNCTION(ovr_GetBoundaryDimensions);
-  REQUIRE_FUNCTION(ovr_GetBoundaryVisible);
-  REQUIRE_FUNCTION(ovr_RequestBoundaryVisible);
-  REQUIRE_FUNCTION(ovr_GetTextureSwapChainLength);
-  REQUIRE_FUNCTION(ovr_GetTextureSwapChainCurrentIndex);
-  REQUIRE_FUNCTION(ovr_GetTextureSwapChainDesc);
-  REQUIRE_FUNCTION(ovr_CommitTextureSwapChain);
-  REQUIRE_FUNCTION(ovr_DestroyTextureSwapChain);
-  REQUIRE_FUNCTION(ovr_DestroyMirrorTexture);
-  REQUIRE_FUNCTION(ovr_GetFovTextureSize);
-  REQUIRE_FUNCTION(ovr_GetRenderDesc2);
-  REQUIRE_FUNCTION(ovr_WaitToBeginFrame);
-  REQUIRE_FUNCTION(ovr_BeginFrame);
-  REQUIRE_FUNCTION(ovr_EndFrame);
-  REQUIRE_FUNCTION(ovr_SubmitFrame);
-  REQUIRE_FUNCTION(ovr_GetPerfStats);
-  REQUIRE_FUNCTION(ovr_ResetPerfStats);
-  REQUIRE_FUNCTION(ovr_GetPredictedDisplayTime);
-  REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
-  REQUIRE_FUNCTION(ovr_GetBool);
-  REQUIRE_FUNCTION(ovr_SetBool);
-  REQUIRE_FUNCTION(ovr_GetInt);
-  REQUIRE_FUNCTION(ovr_SetInt);
-  REQUIRE_FUNCTION(ovr_GetFloat);
-  REQUIRE_FUNCTION(ovr_SetFloat);
-  REQUIRE_FUNCTION(ovr_GetFloatArray);
-  REQUIRE_FUNCTION(ovr_SetFloatArray);
-  REQUIRE_FUNCTION(ovr_GetString);
-  REQUIRE_FUNCTION(ovr_SetString);
-  REQUIRE_FUNCTION(ovr_GetExternalCameras);
-  REQUIRE_FUNCTION(ovr_SetExternalCameraProperties);
-
-#ifdef XP_WIN
-
-  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainDX);
-  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferDX);
-  REQUIRE_FUNCTION(ovr_CreateMirrorTextureDX);
-  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferDX);
-
-#endif
-
-  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainGL);
-  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferGL);
-  REQUIRE_FUNCTION(ovr_CreateMirrorTextureGL);
-  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferGL);
-
-#undef REQUIRE_FUNCTION
-
-  return true;
-
-fail:
-  ovr_Initialize = nullptr;
-  PR_UnloadLibrary(mOvrLib);
-  mOvrLib = nullptr;
-  return false;
-}
-
-void
-OculusSession::UnloadOvrLib()
-{
-  if (mOvrLib) {
-    PR_UnloadLibrary(mOvrLib);
-    mOvrLib = nullptr;
-  }
-}
-
-bool
-OculusSession::StartLib(ovrInitFlags aFlags)
-{
-  if (mInitFlags == 0) {
-    ovrInitParams params;
-    memset(&params, 0, sizeof(params));
-    params.Flags = aFlags;
-    params.RequestedMinorVersion = OVR_MINOR_VERSION;
-    params.LogCallback = nullptr;
-    params.ConnectionTimeoutMS = 0;
-
-    ovrResult orv = ovr_Initialize(&params);
-
-    if (orv == ovrSuccess) {
-      mInitFlags = aFlags;
-    } else {
-      return false;
-    }
-  }
-  MOZ_ASSERT(mInitFlags == aFlags);
-  return true;
-}
-
-void
-OculusSession::StopLib()
-{
-  if (mInitFlags) {
-    ovr_Shutdown();
-    mInitFlags = (ovrInitFlags)0;
-  }
-}
-
-bool
-OculusSession::StartSession()
-{
-  // ovr_Create can be slow when no HMD is present and we wish
-  // to keep the same oculus session when possible, so we detect
-  // presence of an HMD with ovr_GetHmdDesc before calling ovr_Create
-  ovrHmdDesc desc = ovr_GetHmdDesc(NULL);
-  if (desc.Type == ovrHmd_None) {
-    // No HMD connected, destroy any existing session
-    if (mSession) {
-      ovr_Destroy(mSession);
-      mSession = nullptr;
-    }
-    return false;
-  }
-  if (mSession != nullptr) {
-    // HMD Detected and we already have a session, let's keep using it.
-    return true;
-  }
-
-  // HMD Detected and we don't have a session yet,
-  // try to create a new session
-  ovrSession session;
-  ovrGraphicsLuid luid;
-  ovrResult orv = ovr_Create(&session, &luid);
-  if (orv == ovrSuccess) {
-    orv = ovr_SetTrackingOriginType(session, ovrTrackingOrigin_FloorLevel);
-    if (orv != ovrSuccess) {
-      NS_WARNING("ovr_SetTrackingOriginType failed.\n");
-    }
-    mSession = session;
-    return true;
-  }
-
-  // Failed to create a session for the HMD
-  return false;
-}
-
-void
-OculusSession::StopSession()
-{
-  if (mSession) {
-    ovr_Destroy(mSession);
-    mSession = nullptr;
-  }
-}
-
-bool
-OculusSession::CreateD3DObjects()
-{
-  RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetVRDevice();
-  if (!device) {
-    return false;
-  }
-  if (!CreateD3DContext(device)) {
-    return false;
-  }
-  return true;
-}
-
-bool
-OculusSession::CreateShaders()
-{
-  if (!mQuadVS) {
-    if (FAILED(mDevice->CreateVertexShader(
-          sLayerQuadVS.mData, sLayerQuadVS.mLength, nullptr, &mQuadVS))) {
-      NS_WARNING("Failed to create vertex shader for Oculus");
-      return false;
-    }
-  }
-
-  if (!mQuadPS) {
-    if (FAILED(mDevice->CreatePixelShader(
-          sRGBShader.mData, sRGBShader.mLength, nullptr, &mQuadPS))) {
-      NS_WARNING("Failed to create pixel shader for Oculus");
-      return false;
-    }
-  }
-
-  CD3D11_BUFFER_DESC cBufferDesc(sizeof(layers::VertexShaderConstants),
-                                 D3D11_BIND_CONSTANT_BUFFER,
-                                 D3D11_USAGE_DYNAMIC,
-                                 D3D11_CPU_ACCESS_WRITE);
-
-  if (!mVSConstantBuffer) {
-    if (FAILED(mDevice->CreateBuffer(
-          &cBufferDesc, nullptr, getter_AddRefs(mVSConstantBuffer)))) {
-      NS_WARNING("Failed to vertex shader constant buffer for Oculus");
-      return false;
-    }
-  }
-
-  if (!mPSConstantBuffer) {
-    cBufferDesc.ByteWidth = sizeof(layers::PixelShaderConstants);
-    if (FAILED(mDevice->CreateBuffer(
-          &cBufferDesc, nullptr, getter_AddRefs(mPSConstantBuffer)))) {
-      NS_WARNING("Failed to pixel shader constant buffer for Oculus");
-      return false;
-    }
-  }
-
-  if (!mLinearSamplerState) {
-    CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
-    if (FAILED(mDevice->CreateSamplerState(
-          &samplerDesc, getter_AddRefs(mLinearSamplerState)))) {
-      NS_WARNING("Failed to create sampler state for Oculus");
-      return false;
-    }
-  }
-
-  if (!mInputLayout) {
-    D3D11_INPUT_ELEMENT_DESC layout[] = {
-      { "POSITION",
-        0,
-        DXGI_FORMAT_R32G32_FLOAT,
-        0,
-        0,
-        D3D11_INPUT_PER_VERTEX_DATA,
-        0 },
-    };
-
-    if (FAILED(mDevice->CreateInputLayout(layout,
-                                          sizeof(layout) /
-                                            sizeof(D3D11_INPUT_ELEMENT_DESC),
-                                          sLayerQuadVS.mData,
-                                          sLayerQuadVS.mLength,
-                                          getter_AddRefs(mInputLayout)))) {
-      NS_WARNING("Failed to create input layout for Oculus");
-      return false;
-    }
-  }
-
-  if (!mVertexBuffer) {
-    Vertex vertices[] = {
-      { { 0.0, 0.0 } }, { { 1.0, 0.0 } }, { { 0.0, 1.0 } }, { { 1.0, 1.0 } }
-    };
-    CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
-    D3D11_SUBRESOURCE_DATA data;
-    data.pSysMem = (void*)vertices;
-
-    if (FAILED(mDevice->CreateBuffer(
-          &bufferDesc, &data, getter_AddRefs(mVertexBuffer)))) {
-      NS_WARNING("Failed to create vertex buffer for Oculus");
-      return false;
-    }
-  }
-
-  memset(&mVSConstants, 0, sizeof(mVSConstants));
-  memset(&mPSConstants, 0, sizeof(mPSConstants));
-  return true;
-}
-
-void
-OculusSession::DestroyShaders()
-{
-}
-
-bool
-OculusSession::UpdateConstantBuffers()
-{
-  HRESULT hr;
-  D3D11_MAPPED_SUBRESOURCE resource;
-  resource.pData = nullptr;
-
-  hr =
-    mContext->Map(mVSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
-  if (FAILED(hr) || !resource.pData) {
-    return false;
-  }
-  *(VertexShaderConstants*)resource.pData = mVSConstants;
-  mContext->Unmap(mVSConstantBuffer, 0);
-  resource.pData = nullptr;
-
-  hr =
-    mContext->Map(mPSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
-  if (FAILED(hr) || !resource.pData) {
-    return false;
-  }
-  *(PixelShaderConstants*)resource.pData = mPSConstants;
-  mContext->Unmap(mPSConstantBuffer, 0);
-
-  ID3D11Buffer* buffer = mVSConstantBuffer;
-  mContext->VSSetConstantBuffers(0, 1, &buffer);
-  buffer = mPSConstantBuffer;
-  mContext->PSSetConstantBuffers(0, 1, &buffer);
-  return true;
-}
-
-bool
-OculusSession::StartRendering()
-{
-  if (!mTextureSet) {
-    /**
-     * The presentation format is determined by content, which describes the
-     * left and right eye rectangles in the VRLayer.  The default, if no
-     * coordinates are passed is to place the left and right eye textures
-     * side-by-side within the buffer.
-     *
-     * XXX - An optimization would be to dynamically resize this buffer
-     *       to accomodate sites that are choosing to render in a lower
-     *       resolution or are using space outside of the left and right
-     *       eye textures for other purposes.  (Bug 1291443)
-     */
-
-    ovrTextureSwapChainDesc desc;
-    memset(&desc, 0, sizeof(desc));
-    desc.Type = ovrTexture_2D;
-    desc.ArraySize = 1;
-    desc.Format = OVR_FORMAT_B8G8R8A8_UNORM_SRGB;
-    desc.Width = mPresentationSize.width;
-    desc.Height = mPresentationSize.height;
-    desc.MipLevels = 1;
-    desc.SampleCount = 1;
-    desc.StaticImage = false;
-    desc.MiscFlags = ovrTextureMisc_DX_Typeless;
-    desc.BindFlags = ovrTextureBind_DX_RenderTarget;
-
-    ovrResult orv =
-      ovr_CreateTextureSwapChainDX(mSession, mDevice, &desc, &mTextureSet);
-    if (orv != ovrSuccess) {
-      NS_WARNING("ovr_CreateTextureSwapChainDX failed");
-      return false;
-    }
-
-    int textureCount = 0;
-    orv = ovr_GetTextureSwapChainLength(mSession, mTextureSet, &textureCount);
-    if (orv != ovrSuccess) {
-      NS_WARNING("ovr_GetTextureSwapChainLength failed");
-      return false;
-    }
-    mTexture.SetLength(textureCount);
-    mRTView.SetLength(textureCount);
-    mSRV.SetLength(textureCount);
-    for (int i = 0; i < textureCount; ++i) {
-
-      ID3D11Texture2D* texture = nullptr;
-      orv = ovr_GetTextureSwapChainBufferDX(
-        mSession, mTextureSet, i, IID_PPV_ARGS(&texture));
-      if (orv != ovrSuccess) {
-        NS_WARNING("Failed to create Oculus texture swap chain.");
-        return false;
-      }
-
-      RefPtr<ID3D11RenderTargetView> rtView;
-      CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D,
-                                             DXGI_FORMAT_B8G8R8A8_UNORM);
-      HRESULT hr = mDevice->CreateRenderTargetView(
-        texture, &rtvDesc, getter_AddRefs(rtView));
-      if (FAILED(hr)) {
-        NS_WARNING(
-          "Failed to create RenderTargetView for Oculus texture swap chain.");
-        texture->Release();
-        return false;
-      }
-
-      RefPtr<ID3D11ShaderResourceView> srv;
-      CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(D3D11_SRV_DIMENSION_TEXTURE2D,
-                                               DXGI_FORMAT_B8G8R8A8_UNORM);
-      hr = mDevice->CreateShaderResourceView(
-        texture, &srvDesc, getter_AddRefs(srv));
-      if (FAILED(hr)) {
-        NS_WARNING(
-          "Failed to create ShaderResourceView for Oculus texture swap chain.");
-        texture->Release();
-        return false;
-      }
-
-      mTexture[i] = texture;
-      mRTView[i] = rtView;
-      mSRV[i] = srv;
-      texture->Release();
-    }
-  }
-  return true;
-}
-
-bool
-OculusSession::IsPresentationReady() const
-{
-  return mTextureSet != nullptr;
-}
-
-void
-OculusSession::StopRendering()
-{
-  mSRV.Clear();
-  mRTView.Clear();
-  mTexture.Clear();
-
-  if (mTextureSet && mSession) {
-    ovr_DestroyTextureSwapChain(mSession, mTextureSet);
-  }
-  mTextureSet = nullptr;
-  mIsPresenting = false;
-}
-
-bool
-OculusSession::InitState(VRSystemState& aSystemState)
-{
-  VRDisplayState& state = aSystemState.displayState;
-  strncpy(state.mDisplayName, "Oculus VR HMD", kVRDisplayNameMaxLen);
-  state.mIsConnected = true;
-  state.mIsMounted = false;
-
-  ovrHmdDesc desc = ovr_GetHmdDesc(mSession);
-
-  state.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None;
-  if (desc.AvailableTrackingCaps & ovrTrackingCap_Orientation) {
-    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Orientation;
-    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
-  }
-  if (desc.AvailableTrackingCaps & ovrTrackingCap_Position) {
-    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Position;
-    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
-    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_StageParameters;
-  }
-  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
-  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_MountDetection;
-  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
-  state.mReportsDroppedFrames = true;
-
-  mFOVPort[VRDisplayState::Eye_Left] = desc.DefaultEyeFov[ovrEye_Left];
-  mFOVPort[VRDisplayState::Eye_Right] = desc.DefaultEyeFov[ovrEye_Right];
-
-  state.mEyeFOV[VRDisplayState::Eye_Left] =
-    FromFovPort(mFOVPort[VRDisplayState::Eye_Left]);
-  state.mEyeFOV[VRDisplayState::Eye_Right] =
-    FromFovPort(mFOVPort[VRDisplayState::Eye_Right]);
-
-  float pixelsPerDisplayPixel = 1.0;
-  ovrSizei texSize[2];
-
-  // get eye texture sizes
-  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
-    texSize[eye] = ovr_GetFovTextureSize(
-      mSession, (ovrEyeType)eye, mFOVPort[eye], pixelsPerDisplayPixel);
-  }
-
-  // take the max of both for eye resolution
-  state.mEyeResolution.width = std::max(texSize[VRDisplayState::Eye_Left].w,
-                                        texSize[VRDisplayState::Eye_Right].w);
-  state.mEyeResolution.height = std::max(texSize[VRDisplayState::Eye_Left].h,
-                                         texSize[VRDisplayState::Eye_Right].h);
-
-  // default to an identity quaternion
-  aSystemState.sensorState.pose.orientation[3] = 1.0f;
-
-  UpdateStageParameters(state);
-  UpdateEyeParameters(aSystemState);
-
-  VRHMDSensorState& sensorState = aSystemState.sensorState;
-  sensorState.flags =
-    (VRDisplayCapabilityFlags)((int)VRDisplayCapabilityFlags::Cap_Orientation |
-                               (int)VRDisplayCapabilityFlags::Cap_Position);
-  sensorState.pose.orientation[3] = 1.0f; // Default to an identity quaternion
-
-  return true;
-}
-
-void
-OculusSession::UpdateStageParameters(VRDisplayState& aState)
-{
-  ovrVector3f playArea;
-  ovrResult res =
-    ovr_GetBoundaryDimensions(mSession, ovrBoundary_PlayArea, &playArea);
-  if (res == ovrSuccess) {
-    aState.mStageSize.width = playArea.x;
-    aState.mStageSize.height = playArea.z;
-  } else {
-    // If we fail, fall back to reasonable defaults.
-    // 1m x 1m space
-    aState.mStageSize.width = 1.0f;
-    aState.mStageSize.height = 1.0f;
-  }
-
-  float eyeHeight =
-    ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
-
-  aState.mSittingToStandingTransform[0] = 1.0f;
-  aState.mSittingToStandingTransform[1] = 0.0f;
-  aState.mSittingToStandingTransform[2] = 0.0f;
-  aState.mSittingToStandingTransform[3] = 0.0f;
-
-  aState.mSittingToStandingTransform[4] = 0.0f;
-  aState.mSittingToStandingTransform[5] = 1.0f;
-  aState.mSittingToStandingTransform[6] = 0.0f;
-  aState.mSittingToStandingTransform[7] = 0.0f;
-
-  aState.mSittingToStandingTransform[8] = 0.0f;
-  aState.mSittingToStandingTransform[9] = 0.0f;
-  aState.mSittingToStandingTransform[10] = 1.0f;
-  aState.mSittingToStandingTransform[11] = 0.0f;
-
-  aState.mSittingToStandingTransform[12] = 0.0f;
-  aState.mSittingToStandingTransform[13] = eyeHeight;
-  aState.mSittingToStandingTransform[14] = 0.0f;
-  aState.mSittingToStandingTransform[15] = 1.0f;
-}
-
-void
-OculusSession::UpdateEyeParameters(VRSystemState& aState)
-{
-  if (!mSession) {
-    return;
-  }
-  // This must be called every frame in order to
-  // account for continuous adjustments to ipd.
-  gfx::Matrix4x4 headToEyeTransforms[2];
-  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
-    // As of Oculus 1.17 SDK, we must use the ovr_GetRenderDesc2 function to
-    // return the updated version of ovrEyeRenderDesc.  This is normally done by
-    // the Oculus static lib shim, but we need to do this explicitly as we are
-    // loading the Oculus runtime dll directly.
-    ovrEyeRenderDesc renderDesc =
-      ovr_GetRenderDesc2(mSession, (ovrEyeType)eye, mFOVPort[eye]);
-    aState.displayState.mEyeTranslation[eye].x =
-      renderDesc.HmdToEyePose.Position.x;
-    aState.displayState.mEyeTranslation[eye].y =
-      renderDesc.HmdToEyePose.Position.y;
-    aState.displayState.mEyeTranslation[eye].z =
-      renderDesc.HmdToEyePose.Position.z;
-
-    Matrix4x4 pose;
-    pose.SetRotationFromQuaternion(
-      gfx::Quaternion(renderDesc.HmdToEyePose.Orientation.x,
-                      renderDesc.HmdToEyePose.Orientation.y,
-                      renderDesc.HmdToEyePose.Orientation.z,
-                      renderDesc.HmdToEyePose.Orientation.w));
-    pose.PreTranslate(renderDesc.HmdToEyePose.Position.x,
-                      renderDesc.HmdToEyePose.Position.y,
-                      renderDesc.HmdToEyePose.Position.z);
-    pose.Invert();
-    headToEyeTransforms[eye] = pose;
-  }
-  aState.sensorState.CalcViewMatrices(headToEyeTransforms);
-
-  Matrix4x4 matView[2];
-  memcpy(matView[0].components,
-         aState.sensorState.leftViewMatrix,
-         sizeof(float) * 16);
-  memcpy(matView[1].components,
-         aState.sensorState.rightViewMatrix,
-         sizeof(float) * 16);
-
-  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
-    Point3D eyeTranslation;
-    Quaternion eyeRotation;
-    Point3D eyeScale;
-    if (!matView[eye].Decompose(eyeTranslation, eyeRotation, eyeScale)) {
-      NS_WARNING("Failed to decompose eye pose matrix for Oculus");
-    }
-
-    mFrameStartPose[eye].Orientation.x = eyeRotation.x;
-    mFrameStartPose[eye].Orientation.y = eyeRotation.y;
-    mFrameStartPose[eye].Orientation.z = eyeRotation.z;
-    mFrameStartPose[eye].Orientation.w = eyeRotation.w;
-    mFrameStartPose[eye].Position.x = eyeTranslation.x;
-    mFrameStartPose[eye].Position.y = eyeTranslation.y;
-    mFrameStartPose[eye].Position.z = eyeTranslation.z;
-  }
-}
-
-void
-OculusSession::UpdateHeadsetPose(VRSystemState& aState)
-{
-  if (!mSession) {
-    return;
-  }
-  double predictedFrameTime = 0.0f;
-  if (gfxPrefs::VRPosePredictionEnabled()) {
-    // XXX We might need to call ovr_GetPredictedDisplayTime even if we don't
-    // use the result. If we don't call it, the Oculus driver will spew out many
-    // warnings...
-    predictedFrameTime = ovr_GetPredictedDisplayTime(mSession, 0);
-  }
-  ovrTrackingState trackingState =
-    ovr_GetTrackingState(mSession, predictedFrameTime, true);
-  ovrPoseStatef& pose(trackingState.HeadPose);
-
-  aState.sensorState.timestamp = pose.TimeInSeconds;
-
-  if (trackingState.StatusFlags & ovrStatus_OrientationTracked) {
-    aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
-
-    aState.sensorState.pose.orientation[0] = pose.ThePose.Orientation.x;
-    aState.sensorState.pose.orientation[1] = pose.ThePose.Orientation.y;
-    aState.sensorState.pose.orientation[2] = pose.ThePose.Orientation.z;
-    aState.sensorState.pose.orientation[3] = pose.ThePose.Orientation.w;
-
-    aState.sensorState.pose.angularVelocity[0] = pose.AngularVelocity.x;
-    aState.sensorState.pose.angularVelocity[1] = pose.AngularVelocity.y;
-    aState.sensorState.pose.angularVelocity[2] = pose.AngularVelocity.z;
-
-    aState.sensorState.flags |=
-      VRDisplayCapabilityFlags::Cap_AngularAcceleration;
-
-    aState.sensorState.pose.angularAcceleration[0] = pose.AngularAcceleration.x;
-    aState.sensorState.pose.angularAcceleration[1] = pose.AngularAcceleration.y;
-    aState.sensorState.pose.angularAcceleration[2] = pose.AngularAcceleration.z;
-  } else {
-    // default to an identity quaternion
-    aState.sensorState.pose.orientation[3] = 1.0f;
-  }
-
-  if (trackingState.StatusFlags & ovrStatus_PositionTracked) {
-    float eyeHeight =
-      ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
-    aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
-
-    aState.sensorState.pose.position[0] = pose.ThePose.Position.x;
-    aState.sensorState.pose.position[1] = pose.ThePose.Position.y - eyeHeight;
-    aState.sensorState.pose.position[2] = pose.ThePose.Position.z;
-
-    aState.sensorState.pose.linearVelocity[0] = pose.LinearVelocity.x;
-    aState.sensorState.pose.linearVelocity[1] = pose.LinearVelocity.y;
-    aState.sensorState.pose.linearVelocity[2] = pose.LinearVelocity.z;
-
-    aState.sensorState.flags |=
-      VRDisplayCapabilityFlags::Cap_LinearAcceleration;
-
-    aState.sensorState.pose.linearAcceleration[0] = pose.LinearAcceleration.x;
-    aState.sensorState.pose.linearAcceleration[1] = pose.LinearAcceleration.y;
-    aState.sensorState.pose.linearAcceleration[2] = pose.LinearAcceleration.z;
-  }
-  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_External;
-  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_MountDetection;
-  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Present;
-}
-
-void
-OculusSession::UpdateControllers(VRSystemState& aState)
-{
-  if (!mSession) {
-    return;
-  }
-
-  ovrInputState inputState;
-  bool hasInputState =
-    ovr_GetInputState(mSession, ovrControllerType_Touch, &inputState) ==
-    ovrSuccess;
-
-  if (!hasInputState) {
-    return;
-  }
-
-  EnumerateControllers(aState, inputState);
-  UpdateControllerInputs(aState, inputState);
-  UpdateControllerPose(aState, inputState);
-}
-
-void
-OculusSession::UpdateControllerPose(VRSystemState& aState,
-                                    const ovrInputState& aInputState)
-{
-  ovrTrackingState trackingState = ovr_GetTrackingState(mSession, 0.0, false);
-  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
-    // Left Touch Controller will always be at index 0 and
-    // and Right Touch Controller will always be at index 1
-    VRControllerState& controllerState = aState.controllerState[handIdx];
-    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
-      ovrPoseStatef& pose = trackingState.HandPoses[handIdx];
-      bool bNewController =
-        !(controllerState.flags & dom::GamepadCapabilityFlags::Cap_Orientation);
-      if (bNewController) {
-        controllerState.flags |= dom::GamepadCapabilityFlags::Cap_Orientation;
-        controllerState.flags |= dom::GamepadCapabilityFlags::Cap_Position;
-        controllerState.flags |=
-          dom::GamepadCapabilityFlags::Cap_AngularAcceleration;
-        controllerState.flags |=
-          dom::GamepadCapabilityFlags::Cap_LinearAcceleration;
-      }
-
-      if (bNewController || trackingState.HandStatusFlags[handIdx] &
-                              ovrStatus_OrientationTracked) {
-        controllerState.pose.orientation[0] = pose.ThePose.Orientation.x;
-        controllerState.pose.orientation[1] = pose.ThePose.Orientation.y;
-        controllerState.pose.orientation[2] = pose.ThePose.Orientation.z;
-        controllerState.pose.orientation[3] = pose.ThePose.Orientation.w;
-        controllerState.pose.angularVelocity[0] = pose.AngularVelocity.x;
-        controllerState.pose.angularVelocity[1] = pose.AngularVelocity.y;
-        controllerState.pose.angularVelocity[2] = pose.AngularVelocity.z;
-        controllerState.pose.angularAcceleration[0] =
-          pose.AngularAcceleration.x;
-        controllerState.pose.angularAcceleration[1] =
-          pose.AngularAcceleration.y;
-        controllerState.pose.angularAcceleration[2] =
-          pose.AngularAcceleration.z;
-        controllerState.isOrientationValid = true;
-      } else {
-        controllerState.isOrientationValid = false;
-      }
-      if (bNewController ||
-          trackingState.HandStatusFlags[handIdx] & ovrStatus_PositionTracked) {
-        controllerState.pose.position[0] = pose.ThePose.Position.x;
-        controllerState.pose.position[1] = pose.ThePose.Position.y;
-        controllerState.pose.position[2] = pose.ThePose.Position.z;
-        controllerState.pose.linearVelocity[0] = pose.LinearVelocity.x;
-        controllerState.pose.linearVelocity[1] = pose.LinearVelocity.y;
-        controllerState.pose.linearVelocity[2] = pose.LinearVelocity.z;
-        controllerState.pose.linearAcceleration[0] = pose.LinearAcceleration.x;
-        controllerState.pose.linearAcceleration[1] = pose.LinearAcceleration.y;
-        controllerState.pose.linearAcceleration[2] = pose.LinearAcceleration.z;
-
-        float eyeHeight =
-          ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
-        controllerState.pose.position[1] -= eyeHeight;
-        controllerState.isPositionValid = true;
-      } else {
-        controllerState.isPositionValid = false;
-      }
-    }
-  }
-}
-
-void
-OculusSession::EnumerateControllers(VRSystemState& aState,
-                                    const ovrInputState& aInputState)
-{
-  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
-    // Left Touch Controller will always be at index 0 and
-    // and Right Touch Controller will always be at index 1
-    VRControllerState& controllerState = aState.controllerState[handIdx];
-    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
-      bool bNewController = false;
-      // Left Touch Controller detected
-      if (controllerState.controllerName[0] == '\0') {
-        // Controller has been just enumerated
-        strncpy(controllerState.controllerName,
-                OculusControllerNames[handIdx],
-                kVRControllerNameMaxLen);
-        controllerState.hand = OculusControllerHand[handIdx];
-        controllerState.numButtons = kNumOculusButtons;
-        controllerState.numAxes = kNumOculusAxes;
-        controllerState.numHaptics = kNumOculusHaptcs;
-        bNewController = true;
-      }
-    } else {
-      // Left Touch Controller not detected
-      if (controllerState.controllerName[0] != '\0') {
-        // Clear any newly disconnected ontrollers
-        memset(&controllerState, 0, sizeof(VRControllerState));
-      }
-    }
-  }
-}
-
-void
-OculusSession::UpdateControllerInputs(VRSystemState& aState,
-                                      const ovrInputState& aInputState)
-{
-  const float triggerThreshold = gfxPrefs::VRControllerTriggerThreshold();
-
-  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
-    // Left Touch Controller will always be at index 0 and
-    // and Right Touch Controller will always be at index 1
-    VRControllerState& controllerState = aState.controllerState[handIdx];
-    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
-      // Update Button States
-      controllerState.buttonPressed = 0;
-      controllerState.buttonTouched = 0;
-      uint32_t buttonIdx = 0;
-
-      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
-      buttonIdx++;
-      UpdateTrigger(controllerState,
-                    buttonIdx,
-                    aInputState.IndexTrigger[handIdx],
-                    triggerThreshold);
-      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
-      buttonIdx++;
-      UpdateTrigger(controllerState,
-                    buttonIdx,
-                    aInputState.HandTrigger[handIdx],
-                    triggerThreshold);
-      buttonIdx++;
-      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
-      buttonIdx++;
-      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
-      buttonIdx++;
-      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
-      buttonIdx++;
-
-      MOZ_ASSERT(buttonIdx == kNumOculusButtons);
-
-      // Update Thumbstick axis
-      uint32_t axisIdx = 0;
-      float axisValue = aInputState.Thumbstick[handIdx].x;
-      if (abs(axisValue) < 0.0000009f) {
-        axisValue = 0.0f; // Clear noise signal
-      }
-      controllerState.axisValue[axisIdx] = axisValue;
-      axisIdx++;
-
-      // Note that y axis is intentionally inverted!
-      axisValue = -aInputState.Thumbstick[handIdx].y;
-      if (abs(axisValue) < 0.0000009f) {
-        axisValue = 0.0f; // Clear noise signal
-      }
-      controllerState.axisValue[axisIdx] = axisValue;
-      axisIdx++;
-
-      MOZ_ASSERT(axisIdx == kNumOculusAxes);
-    }
-  }
-}
-
-void
-OculusSession::UpdateTelemetry(VRSystemState& aSystemState)
-{
-  if (!mSession) {
-    return;
-  }
-  ovrPerfStats perfStats;
-  if (ovr_GetPerfStats(mSession, &perfStats) == ovrSuccess) {
-    if (perfStats.FrameStatsCount) {
-      aSystemState.displayState.mDroppedFrameCount =
-        perfStats.FrameStats[0].AppDroppedFrameCount;
-    }
-  }
-}
-
-void
-OculusSession::VibrateHaptic(uint32_t aControllerIdx,
-                             uint32_t aHapticIndex,
-                             float aIntensity,
-                             float aDuration)
-{
-  if (!mSession) {
-    return;
-  }
-
-  if (aDuration <= 0.0f) {
-    StopVibrateHaptic(aControllerIdx);
-    return;
-  }
-
-  // Vibration amplitude in the [0.0, 1.0] range
-  MOZ_ASSERT(aControllerIdx >= 0 && aControllerIdx <= 1);
-  mHapticPulseIntensity[aControllerIdx] = aIntensity > 1.0 ? 1.0 : aIntensity;
-  mRemainingVibrateTime[aControllerIdx] = aDuration;
-  ovrControllerType hand = OculusControllerTypes[aControllerIdx];
-
-  // The gamepad extensions API does not yet have independent control
-  // of frequency and amplitude.  We are always sending 0.0f (160hz)
-  // to the frequency argument.
-  ovrResult result = ovr_SetControllerVibration(
-    mSession, hand, 0.0f, mHapticPulseIntensity[aControllerIdx]);
-  if (result != ovrSuccess) {
-    // This may happen if called when not presenting.
-    gfxWarning() << "ovr_SetControllerVibration failed.";
-  }
-}
-
-void
-OculusSession::StopVibrateHaptic(uint32_t aControllerIdx)
-{
-  if (!mSession) {
-    return;
-  }
-  MOZ_ASSERT(aControllerIdx >= 0 && aControllerIdx <= 1);
-  ovrControllerType hand = OculusControllerTypes[aControllerIdx];
-  mRemainingVibrateTime[aControllerIdx] = 0.0f;
-  mHapticPulseIntensity[aControllerIdx] = 0.0f;
-
-  ovrResult result = ovr_SetControllerVibration(mSession, hand, 0.0f, 0.0f);
-  if (result != ovrSuccess) {
-    // This may happen if called when not presenting.
-    gfxWarning() << "ovr_SetControllerVibration failed.";
-  }
-}
-
-void
-OculusSession::StopAllHaptics()
-{
-  // Left Oculus Touch
-  StopVibrateHaptic(0);
-  // Right Oculus Touch
-  StopVibrateHaptic(1);
-}
-
-void
-OculusSession::UpdateHaptics()
-{
-  if (!mSession) {
-    return;
-  }
-  // The Oculus API and hardware takes at least 33ms to respond
-  // to haptic state changes, so it is not beneficial to create
-  // a dedicated haptic feedback thread and update multiple
-  // times per frame.
-  // If we wish to support more accurate effects with sub-frame timing,
-  // we should use the buffered haptic feedback API's.
-
-  TimeStamp now = TimeStamp::Now();
-  if (mLastHapticUpdate.IsNull()) {
-    mLastHapticUpdate = now;
-    return;
-  }
-  float deltaTime = (float)(now - mLastHapticUpdate).ToSeconds();
-  mLastHapticUpdate = now;
-  for (int i = 0; i < 2; i++) {
-    if (mRemainingVibrateTime[i] <= 0.0f) {
-      continue;
-    }
-    mRemainingVibrateTime[i] -= deltaTime;
-    ovrControllerType hand = OculusControllerTypes[i];
-    if (mRemainingVibrateTime[i] > 0.0f) {
-      ovrResult result = ovr_SetControllerVibration(
-        mSession, hand, 0.0f, mHapticPulseIntensity[i]);
-      if (result != ovrSuccess) {
-        // This may happen if called when not presenting.
-        gfxWarning() << "ovr_SetControllerVibration failed.";
-      }
-    } else {
-      StopVibrateHaptic(i);
-    }
-  }
-}
-
-} // namespace mozilla
-} // namespace gfx
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef XP_WIN
+#error "Oculus support only available for Windows"
+#endif
+
+#include <math.h>
+#include <d3d11.h>
+
+#include "gfxPrefs.h"
+#include "mozilla/dom/GamepadEventTypes.h"
+#include "mozilla/dom/GamepadBinding.h"
+#include "mozilla/gfx/DeviceManagerDx.h"
+#include "mozilla/SharedLibrary.h"
+#include "OculusSession.h"
+
+/** XXX The DX11 objects and quad blitting could be encapsulated
+ *    into a separate object if either Oculus starts supporting
+ *     non-Windows platforms or the blit is needed by other HMD\
+ *     drivers.
+ *     Alternately, we could remove the extra blit for
+ *     Oculus as well with some more refactoring.
+ */
+
+// See CompositorD3D11Shaders.h
+namespace mozilla {
+namespace layers {
+struct ShaderBytes
+{
+  const void* mData;
+  size_t mLength;
+};
+extern ShaderBytes sRGBShader;
+extern ShaderBytes sLayerQuadVS;
+} // namespace layers
+} // namespace mozilla
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+namespace {
+
+static pfn_ovr_Initialize ovr_Initialize = nullptr;
+static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
+static pfn_ovr_GetLastErrorInfo ovr_GetLastErrorInfo = nullptr;
+static pfn_ovr_GetVersionString ovr_GetVersionString = nullptr;
+static pfn_ovr_TraceMessage ovr_TraceMessage = nullptr;
+static pfn_ovr_IdentifyClient ovr_IdentifyClient = nullptr;
+static pfn_ovr_GetHmdDesc ovr_GetHmdDesc = nullptr;
+static pfn_ovr_GetTrackerCount ovr_GetTrackerCount = nullptr;
+static pfn_ovr_GetTrackerDesc ovr_GetTrackerDesc = nullptr;
+static pfn_ovr_Create ovr_Create = nullptr;
+static pfn_ovr_Destroy ovr_Destroy = nullptr;
+static pfn_ovr_GetSessionStatus ovr_GetSessionStatus = nullptr;
+static pfn_ovr_IsExtensionSupported ovr_IsExtensionSupported = nullptr;
+static pfn_ovr_EnableExtension ovr_EnableExtension = nullptr;
+static pfn_ovr_SetTrackingOriginType ovr_SetTrackingOriginType = nullptr;
+static pfn_ovr_GetTrackingOriginType ovr_GetTrackingOriginType = nullptr;
+static pfn_ovr_RecenterTrackingOrigin ovr_RecenterTrackingOrigin = nullptr;
+static pfn_ovr_SpecifyTrackingOrigin ovr_SpecifyTrackingOrigin = nullptr;
+static pfn_ovr_ClearShouldRecenterFlag ovr_ClearShouldRecenterFlag = nullptr;
+static pfn_ovr_GetTrackingState ovr_GetTrackingState = nullptr;
+static pfn_ovr_GetDevicePoses ovr_GetDevicePoses = nullptr;
+static pfn_ovr_GetTrackerPose ovr_GetTrackerPose = nullptr;
+static pfn_ovr_GetInputState ovr_GetInputState = nullptr;
+static pfn_ovr_GetConnectedControllerTypes ovr_GetConnectedControllerTypes =
+  nullptr;
+static pfn_ovr_GetTouchHapticsDesc ovr_GetTouchHapticsDesc = nullptr;
+static pfn_ovr_SetControllerVibration ovr_SetControllerVibration = nullptr;
+static pfn_ovr_SubmitControllerVibration ovr_SubmitControllerVibration =
+  nullptr;
+static pfn_ovr_GetControllerVibrationState ovr_GetControllerVibrationState =
+  nullptr;
+static pfn_ovr_TestBoundary ovr_TestBoundary = nullptr;
+static pfn_ovr_TestBoundaryPoint ovr_TestBoundaryPoint = nullptr;
+static pfn_ovr_SetBoundaryLookAndFeel ovr_SetBoundaryLookAndFeel = nullptr;
+static pfn_ovr_ResetBoundaryLookAndFeel ovr_ResetBoundaryLookAndFeel = nullptr;
+static pfn_ovr_GetBoundaryGeometry ovr_GetBoundaryGeometry = nullptr;
+static pfn_ovr_GetBoundaryDimensions ovr_GetBoundaryDimensions = nullptr;
+static pfn_ovr_GetBoundaryVisible ovr_GetBoundaryVisible = nullptr;
+static pfn_ovr_RequestBoundaryVisible ovr_RequestBoundaryVisible = nullptr;
+static pfn_ovr_GetTextureSwapChainLength ovr_GetTextureSwapChainLength =
+  nullptr;
+static pfn_ovr_GetTextureSwapChainCurrentIndex
+  ovr_GetTextureSwapChainCurrentIndex = nullptr;
+static pfn_ovr_GetTextureSwapChainDesc ovr_GetTextureSwapChainDesc = nullptr;
+static pfn_ovr_CommitTextureSwapChain ovr_CommitTextureSwapChain = nullptr;
+static pfn_ovr_DestroyTextureSwapChain ovr_DestroyTextureSwapChain = nullptr;
+static pfn_ovr_DestroyMirrorTexture ovr_DestroyMirrorTexture = nullptr;
+static pfn_ovr_GetFovTextureSize ovr_GetFovTextureSize = nullptr;
+static pfn_ovr_GetRenderDesc2 ovr_GetRenderDesc2 = nullptr;
+static pfn_ovr_WaitToBeginFrame ovr_WaitToBeginFrame = nullptr;
+static pfn_ovr_BeginFrame ovr_BeginFrame = nullptr;
+static pfn_ovr_EndFrame ovr_EndFrame = nullptr;
+static pfn_ovr_SubmitFrame ovr_SubmitFrame = nullptr;
+static pfn_ovr_GetPerfStats ovr_GetPerfStats = nullptr;
+static pfn_ovr_ResetPerfStats ovr_ResetPerfStats = nullptr;
+static pfn_ovr_GetPredictedDisplayTime ovr_GetPredictedDisplayTime = nullptr;
+static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
+static pfn_ovr_GetBool ovr_GetBool = nullptr;
+static pfn_ovr_SetBool ovr_SetBool = nullptr;
+static pfn_ovr_GetInt ovr_GetInt = nullptr;
+static pfn_ovr_SetInt ovr_SetInt = nullptr;
+static pfn_ovr_GetFloat ovr_GetFloat = nullptr;
+static pfn_ovr_SetFloat ovr_SetFloat = nullptr;
+static pfn_ovr_GetFloatArray ovr_GetFloatArray = nullptr;
+static pfn_ovr_SetFloatArray ovr_SetFloatArray = nullptr;
+static pfn_ovr_GetString ovr_GetString = nullptr;
+static pfn_ovr_SetString ovr_SetString = nullptr;
+static pfn_ovr_GetExternalCameras ovr_GetExternalCameras = nullptr;
+static pfn_ovr_SetExternalCameraProperties ovr_SetExternalCameraProperties =
+  nullptr;
+
+#ifdef XP_WIN
+static pfn_ovr_CreateTextureSwapChainDX ovr_CreateTextureSwapChainDX = nullptr;
+static pfn_ovr_GetTextureSwapChainBufferDX ovr_GetTextureSwapChainBufferDX =
+  nullptr;
+static pfn_ovr_CreateMirrorTextureDX ovr_CreateMirrorTextureDX = nullptr;
+static pfn_ovr_GetMirrorTextureBufferDX ovr_GetMirrorTextureBufferDX = nullptr;
+#endif
+
+static pfn_ovr_CreateTextureSwapChainGL ovr_CreateTextureSwapChainGL = nullptr;
+static pfn_ovr_GetTextureSwapChainBufferGL ovr_GetTextureSwapChainBufferGL =
+  nullptr;
+static pfn_ovr_CreateMirrorTextureGL ovr_CreateMirrorTextureGL = nullptr;
+static pfn_ovr_GetMirrorTextureBufferGL ovr_GetMirrorTextureBufferGL = nullptr;
+
+#ifdef HAVE_64BIT_BUILD
+#define BUILD_BITS 64
+#else
+#define BUILD_BITS 32
+#endif
+
+#define OVR_PRODUCT_VERSION 1
+#define OVR_MAJOR_VERSION 1
+#define OVR_MINOR_VERSION 19
+
+static const uint32_t kNumOculusButtons = 6;
+static const uint32_t kNumOculusHaptcs = 1;
+static const uint32_t kNumOculusAxes = 2;
+ovrControllerType OculusControllerTypes[2] = { ovrControllerType_LTouch,
+                                               ovrControllerType_RTouch };
+const char* OculusControllerNames[2] = { "Oculus Touch (Left)",
+                                         "Oculus Touch (Right)" };
+dom::GamepadHand OculusControllerHand[2] = { dom::GamepadHand::Left,
+                                             dom::GamepadHand::Right };
+ovrButton OculusControllerButtons[2][kNumOculusButtons] = {
+  { ovrButton_LThumb,
+    (ovrButton)0,
+    (ovrButton)0,
+    ovrButton_X,
+    ovrButton_Y,
+    (ovrButton)0 },
+  { ovrButton_RThumb,
+    (ovrButton)0,
+    (ovrButton)0,
+    ovrButton_A,
+    ovrButton_B,
+    (ovrButton)0 },
+};
+
+ovrTouch OculusControllerTouches[2][kNumOculusButtons] = {
+  { (ovrTouch)0,
+    ovrTouch_LIndexTrigger,
+    (ovrTouch)0,
+    (ovrTouch)0,
+    (ovrTouch)0,
+    ovrTouch_LThumbRest },
+  { (ovrTouch)0,
+    ovrTouch_RIndexTrigger,
+    (ovrTouch)0,
+    (ovrTouch)0,
+    (ovrTouch)0,
+    ovrTouch_RThumbRest },
+};
+
+void
+UpdateButton(const ovrInputState& aInputState,
+             uint32_t aHandIdx,
+             uint32_t aButtonIdx,
+             VRControllerState& aControllerState)
+{
+  if (aInputState.Buttons & OculusControllerButtons[aHandIdx][aButtonIdx]) {
+    aControllerState.buttonPressed |= ((uint64_t)1 << aButtonIdx);
+  }
+  if (aInputState.Touches & OculusControllerTouches[aHandIdx][aButtonIdx]) {
+    aControllerState.buttonTouched |= ((uint64_t)1 << aButtonIdx);
+  }
+}
+
+VRFieldOfView
+FromFovPort(const ovrFovPort& aFOV)
+{
+  VRFieldOfView fovInfo;
+  fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
+  fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
+  fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
+  fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
+  return fovInfo;
+}
+
+} // anonymous namespace
+
+namespace mozilla {
+namespace gfx {
+
+OculusSession::OculusSession()
+  : VRSession()
+  , mOvrLib(nullptr)
+  , mSession(nullptr)
+  , mInitFlags((ovrInitFlags)0)
+  , mTextureSet(nullptr)
+  , mQuadVS(nullptr)
+  , mQuadPS(nullptr)
+  , mLinearSamplerState(nullptr)
+  , mVSConstantBuffer(nullptr)
+  , mPSConstantBuffer(nullptr)
+  , mVertexBuffer(nullptr)
+  , mInputLayout(nullptr)
+  , mRemainingVibrateTime{}
+  , mHapticPulseIntensity{}
+  , mIsPresenting(false)
+{
+}
+
+OculusSession::~OculusSession()
+{
+  Shutdown();
+}
+
+bool
+OculusSession::Initialize(mozilla::gfx::VRSystemState& aSystemState)
+{
+  if (!CreateD3DObjects()) {
+    return false;
+  }
+  if (!CreateShaders()) {
+    return false;
+  }
+
+  if (!LoadOvrLib()) {
+    return false;
+  }
+  // We start off with an invisible session, then re-initialize
+  // with visible session once WebVR content starts rendering.
+  if (!ChangeVisibility(false)) {
+    return false;
+  }
+  if (!InitState(aSystemState)) {
+    return false;
+  }
+
+  mPresentationSize =
+    IntSize(aSystemState.displayState.mEyeResolution.width * 2,
+            aSystemState.displayState.mEyeResolution.height);
+  return true;
+}
+
+void
+OculusSession::UpdateVisibility()
+{
+  // Do not immediately re-initialize with an invisible session after
+  // the end of a VR presentation.  Waiting for the configured duraction
+  // ensures that the user will not drop to Oculus Home during VR link
+  // traversal.
+  if (mIsPresenting) {
+    // We are currently rendering immersive content.
+    // Avoid interrupting the session
+    return;
+  }
+  if (mInitFlags & ovrInit_Invisible) {
+    // We are already invisible
+    return;
+  }
+  if (mLastPresentationEnd.IsNull()) {
+    // There has been no presentation yet
+    return;
+  }
+
+  TimeDuration duration = TimeStamp::Now() - mLastPresentationEnd;
+  TimeDuration timeout = TimeDuration::FromMilliseconds(gfxPrefs::VROculusPresentTimeout());
+  if (timeout <= TimeDuration(0) || duration >= timeout) {
+    if (!ChangeVisibility(false)) {
+      gfxWarning() << "OculusSession::ChangeVisibility(false) failed";
+    }
+  }
+}
+
+void
+OculusSession::CoverTransitions()
+{
+  // While content is loading or during immersive-mode link
+  // traversal, we need to prevent the user from seeing the
+  // last rendered frame.
+  // We render black frames to cover up the transition.
+  MOZ_ASSERT(mSession);
+  if (mIsPresenting) {
+    // We are currently rendering immersive content.
+    // Avoid interrupting the session
+    return;
+  }
+
+  if (mInitFlags & ovrInit_Invisible) {
+    // We are invisible, nothing to cover up
+    return;
+  }
+
+  // Render a black frame
+  ovrLayerEyeFov layer;
+  memset(&layer, 0, sizeof(layer));
+  layer.Header.Type = ovrLayerType_Disabled;
+  ovrLayerHeader* layers = &layer.Header;
+  ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1);
+}
+
+bool
+OculusSession::ChangeVisibility(bool bVisible)
+{
+  ovrInitFlags flags =
+    (ovrInitFlags)(ovrInit_RequestVersion | ovrInit_MixedRendering);
+  if (gfxPrefs::VROculusInvisibleEnabled() && !bVisible) {
+    flags = (ovrInitFlags)(flags | ovrInit_Invisible);
+  }
+  if (mInitFlags == flags) {
+    // The new state is the same, nothing to do
+    return true;
+  }
+
+  // Tear everything down
+  StopRendering();
+  StopSession();
+  StopLib();
+
+  // Start it back up
+  if (!StartLib(flags)) {
+    return false;
+  }
+  if (!StartSession()) {
+    return false;
+  }
+  return true;
+}
+
+void OculusSession::Shutdown()
+{
+  StopRendering();
+  StopSession();
+  StopLib();
+  UnloadOvrLib();
+  DestroyShaders();
+}
+
+void
+OculusSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState)
+{
+  if (!mSession) {
+    return;
+  }
+
+  ovrSessionStatus status;
+  if (OVR_SUCCESS(ovr_GetSessionStatus(mSession, &status))) {
+    aSystemState.displayState.mIsConnected = status.HmdPresent;
+    aSystemState.displayState.mIsMounted = status.HmdMounted;
+    mShouldQuit = status.ShouldQuit;
+\
+  } else {
+    aSystemState.displayState.mIsConnected = false;
+    aSystemState.displayState.mIsMounted = false;
+  }
+  UpdateHaptics();
+  UpdateVisibility();
+  CoverTransitions();
+}
+
+void
+OculusSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState)
+{
+  UpdateHeadsetPose(aSystemState);
+  UpdateEyeParameters(aSystemState);
+  UpdateControllers(aSystemState);
+  UpdateTelemetry(aSystemState);
+  aSystemState.sensorState.inputFrameID++;
+}
+
+bool
+OculusSession::StartPresentation()
+{
+  /**
+   * XXX - We should resolve fail the promise returned by
+   *       VRDisplay.requestPresent() when the DX11 resources fail allocation
+   *       in VRDisplayOculus::StartPresentation().
+   *       Bailing out here prevents the crash but content should be aware
+   *       that frames are not being presented.
+   *       See Bug 1299309.
+   **/
+  if (!ChangeVisibility(true)) {
+    return false;
+  }
+  if (!StartRendering()) {
+    StopRendering();
+    return false;
+  }
+  mIsPresenting = true;
+  return true;
+}
+
+void
+OculusSession::StopPresentation()
+{
+  mLastPresentationEnd = TimeStamp::Now();
+  mIsPresenting = false;
+}
+
+bool
+OculusSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                           ID3D11Texture2D* aTexture)
+{
+  if (!IsPresentationReady()) {
+    return false;
+  }
+
+  D3D11_TEXTURE2D_DESC textureDesc = { 0 };
+  aTexture->GetDesc(&textureDesc);
+
+  int currentRenderTarget = 0;
+  ovrResult orv = ovr_GetTextureSwapChainCurrentIndex(
+    mSession, mTextureSet, &currentRenderTarget);
+  if (orv != ovrSuccess) {
+    NS_WARNING("ovr_GetTextureSwapChainCurrentIndex failed.");
+    return false;
+  }
+
+  ID3D11RenderTargetView* view = mRTView[currentRenderTarget];
+
+  float clear[] = { 0.0f, 0.0f, 0.0f, 1.0f };
+  mContext->ClearRenderTargetView(view, clear);
+  mContext->OMSetRenderTargets(1, &view, nullptr);
+
+  Matrix viewMatrix = Matrix::Translation(-1.0, 1.0);
+  viewMatrix.PreScale(2.0f / float(textureDesc.Width),
+                      2.0f / float(textureDesc.Height));
+  viewMatrix.PreScale(1.0f, -1.0f);
+  Matrix4x4 projection = Matrix4x4::From2D(viewMatrix);
+  projection._33 = 0.0f;
+
+  Matrix transform2d;
+  gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
+
+  D3D11_VIEWPORT viewport;
+  viewport.MinDepth = 0.0f;
+  viewport.MaxDepth = 1.0f;
+  viewport.Width = textureDesc.Width;
+  viewport.Height = textureDesc.Height;
+  viewport.TopLeftX = 0;
+  viewport.TopLeftY = 0;
+
+  D3D11_RECT scissor;
+  scissor.left = 0;
+  scissor.right = textureDesc.Width;
+  scissor.top = 0;
+  scissor.bottom = textureDesc.Height;
+
+  memcpy(&mVSConstants.layerTransform,
+         &transform._11,
+         sizeof(mVSConstants.layerTransform));
+  memcpy(
+    &mVSConstants.projection, &projection._11, sizeof(mVSConstants.projection));
+  mVSConstants.renderTargetOffset[0] = 0.0f;
+  mVSConstants.renderTargetOffset[1] = 0.0f;
+  mVSConstants.layerQuad =
+    Rect(0.0f, 0.0f, textureDesc.Width, textureDesc.Height);
+  mVSConstants.textureCoords = Rect(0.0f, 1.0f, 1.0f, -1.0f);
+
+  mPSConstants.layerOpacity[0] = 1.0f;
+
+  ID3D11Buffer* vbuffer = mVertexBuffer;
+  UINT vsize = sizeof(Vertex);
+  UINT voffset = 0;
+  mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
+  mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
+  mContext->IASetInputLayout(mInputLayout);
+  mContext->RSSetViewports(1, &viewport);
+  mContext->RSSetScissorRects(1, &scissor);
+  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+  mContext->VSSetShader(mQuadVS, nullptr, 0);
+  mContext->PSSetShader(mQuadPS, nullptr, 0);
+
+  RefPtr<ID3D11ShaderResourceView> srView;
+  HRESULT hr = mDevice->CreateShaderResourceView(
+    aTexture, nullptr, getter_AddRefs(srView));
+  if (FAILED(hr)) {
+    gfxWarning() << "Could not create shader resource view for Oculus: "
+                 << hexa(hr);
+    return false;
+  }
+  ID3D11ShaderResourceView* viewPtr = srView.get();
+  mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &viewPtr);
+  // XXX Use Constant from TexSlot in CompositorD3D11.cpp?
+
+  ID3D11SamplerState* sampler = mLinearSamplerState;
+  mContext->PSSetSamplers(0, 1, &sampler);
+
+  if (!UpdateConstantBuffers()) {
+    NS_WARNING("Failed to update constant buffers for Oculus");
+    return false;
+  }
+
+  mContext->Draw(4, 0);
+
+  orv = ovr_CommitTextureSwapChain(mSession, mTextureSet);
+  if (orv != ovrSuccess) {
+    NS_WARNING("ovr_CommitTextureSwapChain failed.");
+    return false;
+  }
+
+  ovrLayerEyeFov layer;
+  memset(&layer, 0, sizeof(layer));
+  layer.Header.Type = ovrLayerType_EyeFov;
+  layer.Header.Flags = 0;
+  layer.ColorTexture[0] = mTextureSet;
+  layer.ColorTexture[1] = nullptr;
+  layer.Fov[0] = mFOVPort[0];
+  layer.Fov[1] = mFOVPort[1];
+  layer.Viewport[0].Pos.x = textureDesc.Width * aLayer.mLeftEyeRect.x;
+  layer.Viewport[0].Pos.y = textureDesc.Height * aLayer.mLeftEyeRect.y;
+  layer.Viewport[0].Size.w = textureDesc.Width * aLayer.mLeftEyeRect.width;
+  layer.Viewport[0].Size.h = textureDesc.Height * aLayer.mLeftEyeRect.height;
+  layer.Viewport[1].Pos.x = textureDesc.Width * aLayer.mRightEyeRect.x;
+  layer.Viewport[1].Pos.y = textureDesc.Height * aLayer.mRightEyeRect.y;
+  layer.Viewport[1].Size.w = textureDesc.Width * aLayer.mRightEyeRect.width;
+  layer.Viewport[1].Size.h = textureDesc.Height * aLayer.mRightEyeRect.height;
+
+  for (uint32_t i = 0; i < 2; ++i) {
+    layer.RenderPose[i].Orientation.x = mFrameStartPose[i].Orientation.x;
+    layer.RenderPose[i].Orientation.y = mFrameStartPose[i].Orientation.y;
+    layer.RenderPose[i].Orientation.z = mFrameStartPose[i].Orientation.z;
+    layer.RenderPose[i].Orientation.w = mFrameStartPose[i].Orientation.w;
+    layer.RenderPose[i].Position.x = mFrameStartPose[i].Position.x;
+    layer.RenderPose[i].Position.y = mFrameStartPose[i].Position.y;
+    layer.RenderPose[i].Position.z = mFrameStartPose[i].Position.z;
+  }
+
+  ovrLayerHeader* layers = &layer.Header;
+  orv = ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1);
+  // ovr_SubmitFrame will fail during the Oculus health and safety warning.
+  // and will start succeeding once the warning has been dismissed by the user.
+
+  if (!OVR_UNQUALIFIED_SUCCESS(orv)) {
+    /**
+     * We wish to throttle the framerate for any case that the rendered
+     * result is not visible.  In some cases, such as during the Oculus
+     * "health and safety warning", orv will be > 0 (OVR_SUCCESS but not
+     * OVR_UNQUALIFIED_SUCCESS) and ovr_SubmitFrame will not block.
+     * In this case, returning true would have resulted in an unthrottled
+     * render loop hiting excessive frame rates and consuming resources.
+     */
+    return false;
+  }
+
+  return true;
+}
+
+bool
+OculusSession::LoadOvrLib()
+{
+  if (mOvrLib) {
+    // Already loaded, early exit
+    return true;
+  }
+#if defined(_WIN32)
+  nsTArray<nsString> libSearchPaths;
+  nsString libName;
+  nsString searchPath;
+
+  static const char dirSep = '\\';
+  static const int pathLen = 260;
+  searchPath.SetCapacity(pathLen);
+  int realLen =
+    ::GetSystemDirectoryW(char16ptr_t(searchPath.BeginWriting()), pathLen);
+  if (realLen != 0 && realLen < pathLen) {
+    searchPath.SetLength(realLen);
+    libSearchPaths.AppendElement(searchPath);
+  }
+  libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
+
+  // search the path/module dir
+  libSearchPaths.InsertElementsAt(0, 1, EmptyString());
+
+  // If the env var is present, we override libName
+  if (_wgetenv(L"OVR_LIB_PATH")) {
+    searchPath = _wgetenv(L"OVR_LIB_PATH");
+    libSearchPaths.InsertElementsAt(0, 1, searchPath);
+  }
+
+  if (_wgetenv(L"OVR_LIB_NAME")) {
+    libName = _wgetenv(L"OVR_LIB_NAME");
+  }
+
+  for (uint32_t i = 0; i < libSearchPaths.Length(); ++i) {
+    nsString& libPath = libSearchPaths[i];
+    nsString fullName;
+    if (libPath.Length() == 0) {
+      fullName.Assign(libName);
+    } else {
+      fullName.AppendPrintf("%s%c%s", libPath.get(), dirSep, libName.get());
+    }
+
+    mOvrLib = LoadLibraryWithFlags(fullName.get());
+    if (mOvrLib) {
+      break;
+    }
+  }
+#else
+#error "Unsupported platform!"
+#endif
+
+  if (!mOvrLib) {
+    return false;
+  }
+
+#define REQUIRE_FUNCTION(_x)                                                   \
+  do {                                                                         \
+    *(void**)&_x = (void*)PR_FindSymbol(mOvrLib, #_x);                         \
+    if (!_x) {                                                                 \
+      printf_stderr(#_x " symbol missing\n");                                  \
+      goto fail;                                                               \
+    }                                                                          \
+  } while (0)
+
+  REQUIRE_FUNCTION(ovr_Initialize);
+  REQUIRE_FUNCTION(ovr_Shutdown);
+  REQUIRE_FUNCTION(ovr_GetLastErrorInfo);
+  REQUIRE_FUNCTION(ovr_GetVersionString);
+  REQUIRE_FUNCTION(ovr_TraceMessage);
+  REQUIRE_FUNCTION(ovr_IdentifyClient);
+  REQUIRE_FUNCTION(ovr_GetHmdDesc);
+  REQUIRE_FUNCTION(ovr_GetTrackerCount);
+  REQUIRE_FUNCTION(ovr_GetTrackerDesc);
+  REQUIRE_FUNCTION(ovr_Create);
+  REQUIRE_FUNCTION(ovr_Destroy);
+  REQUIRE_FUNCTION(ovr_GetSessionStatus);
+  REQUIRE_FUNCTION(ovr_IsExtensionSupported);
+  REQUIRE_FUNCTION(ovr_EnableExtension);
+  REQUIRE_FUNCTION(ovr_SetTrackingOriginType);
+  REQUIRE_FUNCTION(ovr_GetTrackingOriginType);
+  REQUIRE_FUNCTION(ovr_RecenterTrackingOrigin);
+  REQUIRE_FUNCTION(ovr_SpecifyTrackingOrigin);
+  REQUIRE_FUNCTION(ovr_ClearShouldRecenterFlag);
+  REQUIRE_FUNCTION(ovr_GetTrackingState);
+  REQUIRE_FUNCTION(ovr_GetDevicePoses);
+  REQUIRE_FUNCTION(ovr_GetTrackerPose);
+  REQUIRE_FUNCTION(ovr_GetInputState);
+  REQUIRE_FUNCTION(ovr_GetConnectedControllerTypes);
+  REQUIRE_FUNCTION(ovr_GetTouchHapticsDesc);
+  REQUIRE_FUNCTION(ovr_SetControllerVibration);
+  REQUIRE_FUNCTION(ovr_SubmitControllerVibration);
+  REQUIRE_FUNCTION(ovr_GetControllerVibrationState);
+  REQUIRE_FUNCTION(ovr_TestBoundary);
+  REQUIRE_FUNCTION(ovr_TestBoundaryPoint);
+  REQUIRE_FUNCTION(ovr_SetBoundaryLookAndFeel);
+  REQUIRE_FUNCTION(ovr_ResetBoundaryLookAndFeel);
+  REQUIRE_FUNCTION(ovr_GetBoundaryGeometry);
+  REQUIRE_FUNCTION(ovr_GetBoundaryDimensions);
+  REQUIRE_FUNCTION(ovr_GetBoundaryVisible);
+  REQUIRE_FUNCTION(ovr_RequestBoundaryVisible);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainLength);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainCurrentIndex);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainDesc);
+  REQUIRE_FUNCTION(ovr_CommitTextureSwapChain);
+  REQUIRE_FUNCTION(ovr_DestroyTextureSwapChain);
+  REQUIRE_FUNCTION(ovr_DestroyMirrorTexture);
+  REQUIRE_FUNCTION(ovr_GetFovTextureSize);
+  REQUIRE_FUNCTION(ovr_GetRenderDesc2);
+  REQUIRE_FUNCTION(ovr_WaitToBeginFrame);
+  REQUIRE_FUNCTION(ovr_BeginFrame);
+  REQUIRE_FUNCTION(ovr_EndFrame);
+  REQUIRE_FUNCTION(ovr_SubmitFrame);
+  REQUIRE_FUNCTION(ovr_GetPerfStats);
+  REQUIRE_FUNCTION(ovr_ResetPerfStats);
+  REQUIRE_FUNCTION(ovr_GetPredictedDisplayTime);
+  REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
+  REQUIRE_FUNCTION(ovr_GetBool);
+  REQUIRE_FUNCTION(ovr_SetBool);
+  REQUIRE_FUNCTION(ovr_GetInt);
+  REQUIRE_FUNCTION(ovr_SetInt);
+  REQUIRE_FUNCTION(ovr_GetFloat);
+  REQUIRE_FUNCTION(ovr_SetFloat);
+  REQUIRE_FUNCTION(ovr_GetFloatArray);
+  REQUIRE_FUNCTION(ovr_SetFloatArray);
+  REQUIRE_FUNCTION(ovr_GetString);
+  REQUIRE_FUNCTION(ovr_SetString);
+  REQUIRE_FUNCTION(ovr_GetExternalCameras);
+  REQUIRE_FUNCTION(ovr_SetExternalCameraProperties);
+
+#ifdef XP_WIN
+
+  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainDX);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferDX);
+  REQUIRE_FUNCTION(ovr_CreateMirrorTextureDX);
+  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferDX);
+
+#endif
+
+  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainGL);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferGL);
+  REQUIRE_FUNCTION(ovr_CreateMirrorTextureGL);
+  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferGL);
+
+#undef REQUIRE_FUNCTION
+
+  return true;
+
+fail:
+  ovr_Initialize = nullptr;
+  PR_UnloadLibrary(mOvrLib);
+  mOvrLib = nullptr;
+  return false;
+}
+
+void
+OculusSession::UnloadOvrLib()
+{
+  if (mOvrLib) {
+    PR_UnloadLibrary(mOvrLib);
+    mOvrLib = nullptr;
+  }
+}
+
+bool
+OculusSession::StartLib(ovrInitFlags aFlags)
+{
+  if (mInitFlags == 0) {
+    ovrInitParams params;
+    memset(&params, 0, sizeof(params));
+    params.Flags = aFlags;
+    params.RequestedMinorVersion = OVR_MINOR_VERSION;
+    params.LogCallback = nullptr;
+    params.ConnectionTimeoutMS = 0;
+
+    ovrResult orv = ovr_Initialize(&params);
+
+    if (orv == ovrSuccess) {
+      mInitFlags = aFlags;
+    } else {
+      return false;
+    }
+  }
+  MOZ_ASSERT(mInitFlags == aFlags);
+  return true;
+}
+
+void
+OculusSession::StopLib()
+{
+  if (mInitFlags) {
+    ovr_Shutdown();
+    mInitFlags = (ovrInitFlags)0;
+  }
+}
+
+bool
+OculusSession::StartSession()
+{
+  // ovr_Create can be slow when no HMD is present and we wish
+  // to keep the same oculus session when possible, so we detect
+  // presence of an HMD with ovr_GetHmdDesc before calling ovr_Create
+  ovrHmdDesc desc = ovr_GetHmdDesc(NULL);
+  if (desc.Type == ovrHmd_None) {
+    // No HMD connected, destroy any existing session
+    if (mSession) {
+      ovr_Destroy(mSession);
+      mSession = nullptr;
+    }
+    return false;
+  }
+  if (mSession != nullptr) {
+    // HMD Detected and we already have a session, let's keep using it.
+    return true;
+  }
+
+  // HMD Detected and we don't have a session yet,
+  // try to create a new session
+  ovrSession session;
+  ovrGraphicsLuid luid;
+  ovrResult orv = ovr_Create(&session, &luid);
+  if (orv == ovrSuccess) {
+    orv = ovr_SetTrackingOriginType(session, ovrTrackingOrigin_FloorLevel);
+    if (orv != ovrSuccess) {
+      NS_WARNING("ovr_SetTrackingOriginType failed.\n");
+    }
+    mSession = session;
+    return true;
+  }
+
+  // Failed to create a session for the HMD
+  return false;
+}
+
+void
+OculusSession::StopSession()
+{
+  if (mSession) {
+    ovr_Destroy(mSession);
+    mSession = nullptr;
+  }
+}
+
+bool
+OculusSession::CreateD3DObjects()
+{
+  RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetVRDevice();
+  if (!device) {
+    return false;
+  }
+  if (!CreateD3DContext(device)) {
+    return false;
+  }
+  return true;
+}
+
+bool
+OculusSession::CreateShaders()
+{
+  if (!mQuadVS) {
+    if (FAILED(mDevice->CreateVertexShader(
+          sLayerQuadVS.mData, sLayerQuadVS.mLength, nullptr, &mQuadVS))) {
+      NS_WARNING("Failed to create vertex shader for Oculus");
+      return false;
+    }
+  }
+
+  if (!mQuadPS) {
+    if (FAILED(mDevice->CreatePixelShader(
+          sRGBShader.mData, sRGBShader.mLength, nullptr, &mQuadPS))) {
+      NS_WARNING("Failed to create pixel shader for Oculus");
+      return false;
+    }
+  }
+
+  CD3D11_BUFFER_DESC cBufferDesc(sizeof(layers::VertexShaderConstants),
+                                 D3D11_BIND_CONSTANT_BUFFER,
+                                 D3D11_USAGE_DYNAMIC,
+                                 D3D11_CPU_ACCESS_WRITE);
+
+  if (!mVSConstantBuffer) {
+    if (FAILED(mDevice->CreateBuffer(
+          &cBufferDesc, nullptr, getter_AddRefs(mVSConstantBuffer)))) {
+      NS_WARNING("Failed to vertex shader constant buffer for Oculus");
+      return false;
+    }
+  }
+
+  if (!mPSConstantBuffer) {
+    cBufferDesc.ByteWidth = sizeof(layers::PixelShaderConstants);
+    if (FAILED(mDevice->CreateBuffer(
+          &cBufferDesc, nullptr, getter_AddRefs(mPSConstantBuffer)))) {
+      NS_WARNING("Failed to pixel shader constant buffer for Oculus");
+      return false;
+    }
+  }
+
+  if (!mLinearSamplerState) {
+    CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
+    if (FAILED(mDevice->CreateSamplerState(
+          &samplerDesc, getter_AddRefs(mLinearSamplerState)))) {
+      NS_WARNING("Failed to create sampler state for Oculus");
+      return false;
+    }
+  }
+
+  if (!mInputLayout) {
+    D3D11_INPUT_ELEMENT_DESC layout[] = {
+      { "POSITION",
+        0,
+        DXGI_FORMAT_R32G32_FLOAT,
+        0,
+        0,
+        D3D11_INPUT_PER_VERTEX_DATA,
+        0 },
+    };
+
+    if (FAILED(mDevice->CreateInputLayout(layout,
+                                          sizeof(layout) /
+                                            sizeof(D3D11_INPUT_ELEMENT_DESC),
+                                          sLayerQuadVS.mData,
+                                          sLayerQuadVS.mLength,
+                                          getter_AddRefs(mInputLayout)))) {
+      NS_WARNING("Failed to create input layout for Oculus");
+      return false;
+    }
+  }
+
+  if (!mVertexBuffer) {
+    Vertex vertices[] = {
+      { { 0.0, 0.0 } }, { { 1.0, 0.0 } }, { { 0.0, 1.0 } }, { { 1.0, 1.0 } }
+    };
+    CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
+    D3D11_SUBRESOURCE_DATA data;
+    data.pSysMem = (void*)vertices;
+
+    if (FAILED(mDevice->CreateBuffer(
+          &bufferDesc, &data, getter_AddRefs(mVertexBuffer)))) {
+      NS_WARNING("Failed to create vertex buffer for Oculus");
+      return false;
+    }
+  }
+
+  memset(&mVSConstants, 0, sizeof(mVSConstants));
+  memset(&mPSConstants, 0, sizeof(mPSConstants));
+  return true;
+}
+
+void
+OculusSession::DestroyShaders()
+{
+}
+
+bool
+OculusSession::UpdateConstantBuffers()
+{
+  HRESULT hr;
+  D3D11_MAPPED_SUBRESOURCE resource;
+  resource.pData = nullptr;
+
+  hr =
+    mContext->Map(mVSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
+  if (FAILED(hr) || !resource.pData) {
+    return false;
+  }
+  *(VertexShaderConstants*)resource.pData = mVSConstants;
+  mContext->Unmap(mVSConstantBuffer, 0);
+  resource.pData = nullptr;
+
+  hr =
+    mContext->Map(mPSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
+  if (FAILED(hr) || !resource.pData) {
+    return false;
+  }
+  *(PixelShaderConstants*)resource.pData = mPSConstants;
+  mContext->Unmap(mPSConstantBuffer, 0);
+
+  ID3D11Buffer* buffer = mVSConstantBuffer;
+  mContext->VSSetConstantBuffers(0, 1, &buffer);
+  buffer = mPSConstantBuffer;
+  mContext->PSSetConstantBuffers(0, 1, &buffer);
+  return true;
+}
+
+bool
+OculusSession::StartRendering()
+{
+  if (!mTextureSet) {
+    /**
+     * The presentation format is determined by content, which describes the
+     * left and right eye rectangles in the VRLayer.  The default, if no
+     * coordinates are passed is to place the left and right eye textures
+     * side-by-side within the buffer.
+     *
+     * XXX - An optimization would be to dynamically resize this buffer
+     *       to accomodate sites that are choosing to render in a lower
+     *       resolution or are using space outside of the left and right
+     *       eye textures for other purposes.  (Bug 1291443)
+     */
+
+    ovrTextureSwapChainDesc desc;
+    memset(&desc, 0, sizeof(desc));
+    desc.Type = ovrTexture_2D;
+    desc.ArraySize = 1;
+    desc.Format = OVR_FORMAT_B8G8R8A8_UNORM_SRGB;
+    desc.Width = mPresentationSize.width;
+    desc.Height = mPresentationSize.height;
+    desc.MipLevels = 1;
+    desc.SampleCount = 1;
+    desc.StaticImage = false;
+    desc.MiscFlags = ovrTextureMisc_DX_Typeless;
+    desc.BindFlags = ovrTextureBind_DX_RenderTarget;
+
+    ovrResult orv =
+      ovr_CreateTextureSwapChainDX(mSession, mDevice, &desc, &mTextureSet);
+    if (orv != ovrSuccess) {
+      NS_WARNING("ovr_CreateTextureSwapChainDX failed");
+      return false;
+    }
+
+    int textureCount = 0;
+    orv = ovr_GetTextureSwapChainLength(mSession, mTextureSet, &textureCount);
+    if (orv != ovrSuccess) {
+      NS_WARNING("ovr_GetTextureSwapChainLength failed");
+      return false;
+    }
+    mTexture.SetLength(textureCount);
+    mRTView.SetLength(textureCount);
+    mSRV.SetLength(textureCount);
+    for (int i = 0; i < textureCount; ++i) {
+
+      ID3D11Texture2D* texture = nullptr;
+      orv = ovr_GetTextureSwapChainBufferDX(
+        mSession, mTextureSet, i, IID_PPV_ARGS(&texture));
+      if (orv != ovrSuccess) {
+        NS_WARNING("Failed to create Oculus texture swap chain.");
+        return false;
+      }
+
+      RefPtr<ID3D11RenderTargetView> rtView;
+      CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D,
+                                             DXGI_FORMAT_B8G8R8A8_UNORM);
+      HRESULT hr = mDevice->CreateRenderTargetView(
+        texture, &rtvDesc, getter_AddRefs(rtView));
+      if (FAILED(hr)) {
+        NS_WARNING(
+          "Failed to create RenderTargetView for Oculus texture swap chain.");
+        texture->Release();
+        return false;
+      }
+
+      RefPtr<ID3D11ShaderResourceView> srv;
+      CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(D3D11_SRV_DIMENSION_TEXTURE2D,
+                                               DXGI_FORMAT_B8G8R8A8_UNORM);
+      hr = mDevice->CreateShaderResourceView(
+        texture, &srvDesc, getter_AddRefs(srv));
+      if (FAILED(hr)) {
+        NS_WARNING(
+          "Failed to create ShaderResourceView for Oculus texture swap chain.");
+        texture->Release();
+        return false;
+      }
+
+      mTexture[i] = texture;
+      mRTView[i] = rtView;
+      mSRV[i] = srv;
+      texture->Release();
+    }
+  }
+  return true;
+}
+
+bool
+OculusSession::IsPresentationReady() const
+{
+  return mTextureSet != nullptr;
+}
+
+void
+OculusSession::StopRendering()
+{
+  mSRV.Clear();
+  mRTView.Clear();
+  mTexture.Clear();
+
+  if (mTextureSet && mSession) {
+    ovr_DestroyTextureSwapChain(mSession, mTextureSet);
+  }
+  mTextureSet = nullptr;
+  mIsPresenting = false;
+}
+
+bool
+OculusSession::InitState(VRSystemState& aSystemState)
+{
+  VRDisplayState& state = aSystemState.displayState;
+  strncpy(state.mDisplayName, "Oculus VR HMD", kVRDisplayNameMaxLen);
+  state.mIsConnected = true;
+  state.mIsMounted = false;
+
+  ovrHmdDesc desc = ovr_GetHmdDesc(mSession);
+
+  state.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None;
+  if (desc.AvailableTrackingCaps & ovrTrackingCap_Orientation) {
+    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Orientation;
+    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
+  }
+  if (desc.AvailableTrackingCaps & ovrTrackingCap_Position) {
+    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Position;
+    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
+    state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_StageParameters;
+  }
+  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
+  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_MountDetection;
+  state.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
+  state.mReportsDroppedFrames = true;
+
+  mFOVPort[VRDisplayState::Eye_Left] = desc.DefaultEyeFov[ovrEye_Left];
+  mFOVPort[VRDisplayState::Eye_Right] = desc.DefaultEyeFov[ovrEye_Right];
+
+  state.mEyeFOV[VRDisplayState::Eye_Left] =
+    FromFovPort(mFOVPort[VRDisplayState::Eye_Left]);
+  state.mEyeFOV[VRDisplayState::Eye_Right] =
+    FromFovPort(mFOVPort[VRDisplayState::Eye_Right]);
+
+  float pixelsPerDisplayPixel = 1.0;
+  ovrSizei texSize[2];
+
+  // get eye texture sizes
+  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
+    texSize[eye] = ovr_GetFovTextureSize(
+      mSession, (ovrEyeType)eye, mFOVPort[eye], pixelsPerDisplayPixel);
+  }
+
+  // take the max of both for eye resolution
+  state.mEyeResolution.width = std::max(texSize[VRDisplayState::Eye_Left].w,
+                                        texSize[VRDisplayState::Eye_Right].w);
+  state.mEyeResolution.height = std::max(texSize[VRDisplayState::Eye_Left].h,
+                                         texSize[VRDisplayState::Eye_Right].h);
+
+  // default to an identity quaternion
+  aSystemState.sensorState.pose.orientation[3] = 1.0f;
+
+  UpdateStageParameters(state);
+  UpdateEyeParameters(aSystemState);
+
+  VRHMDSensorState& sensorState = aSystemState.sensorState;
+  sensorState.flags =
+    (VRDisplayCapabilityFlags)((int)VRDisplayCapabilityFlags::Cap_Orientation |
+                               (int)VRDisplayCapabilityFlags::Cap_Position);
+  sensorState.pose.orientation[3] = 1.0f; // Default to an identity quaternion
+
+  return true;
+}
+
+void
+OculusSession::UpdateStageParameters(VRDisplayState& aState)
+{
+  ovrVector3f playArea;
+  ovrResult res =
+    ovr_GetBoundaryDimensions(mSession, ovrBoundary_PlayArea, &playArea);
+  if (res == ovrSuccess) {
+    aState.mStageSize.width = playArea.x;
+    aState.mStageSize.height = playArea.z;
+  } else {
+    // If we fail, fall back to reasonable defaults.
+    // 1m x 1m space
+    aState.mStageSize.width = 1.0f;
+    aState.mStageSize.height = 1.0f;
+  }
+
+  float eyeHeight =
+    ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
+
+  aState.mSittingToStandingTransform[0] = 1.0f;
+  aState.mSittingToStandingTransform[1] = 0.0f;
+  aState.mSittingToStandingTransform[2] = 0.0f;
+  aState.mSittingToStandingTransform[3] = 0.0f;
+
+  aState.mSittingToStandingTransform[4] = 0.0f;
+  aState.mSittingToStandingTransform[5] = 1.0f;
+  aState.mSittingToStandingTransform[6] = 0.0f;
+  aState.mSittingToStandingTransform[7] = 0.0f;
+
+  aState.mSittingToStandingTransform[8] = 0.0f;
+  aState.mSittingToStandingTransform[9] = 0.0f;
+  aState.mSittingToStandingTransform[10] = 1.0f;
+  aState.mSittingToStandingTransform[11] = 0.0f;
+
+  aState.mSittingToStandingTransform[12] = 0.0f;
+  aState.mSittingToStandingTransform[13] = eyeHeight;
+  aState.mSittingToStandingTransform[14] = 0.0f;
+  aState.mSittingToStandingTransform[15] = 1.0f;
+}
+
+void
+OculusSession::UpdateEyeParameters(VRSystemState& aState)
+{
+  if (!mSession) {
+    return;
+  }
+  // This must be called every frame in order to
+  // account for continuous adjustments to ipd.
+  gfx::Matrix4x4 headToEyeTransforms[2];
+  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
+    // As of Oculus 1.17 SDK, we must use the ovr_GetRenderDesc2 function to
+    // return the updated version of ovrEyeRenderDesc.  This is normally done by
+    // the Oculus static lib shim, but we need to do this explicitly as we are
+    // loading the Oculus runtime dll directly.
+    ovrEyeRenderDesc renderDesc =
+      ovr_GetRenderDesc2(mSession, (ovrEyeType)eye, mFOVPort[eye]);
+    aState.displayState.mEyeTranslation[eye].x =
+      renderDesc.HmdToEyePose.Position.x;
+    aState.displayState.mEyeTranslation[eye].y =
+      renderDesc.HmdToEyePose.Position.y;
+    aState.displayState.mEyeTranslation[eye].z =
+      renderDesc.HmdToEyePose.Position.z;
+
+    Matrix4x4 pose;
+    pose.SetRotationFromQuaternion(
+      gfx::Quaternion(renderDesc.HmdToEyePose.Orientation.x,
+                      renderDesc.HmdToEyePose.Orientation.y,
+                      renderDesc.HmdToEyePose.Orientation.z,
+                      renderDesc.HmdToEyePose.Orientation.w));
+    pose.PreTranslate(renderDesc.HmdToEyePose.Position.x,
+                      renderDesc.HmdToEyePose.Position.y,
+                      renderDesc.HmdToEyePose.Position.z);
+    pose.Invert();
+    headToEyeTransforms[eye] = pose;
+  }
+  aState.sensorState.CalcViewMatrices(headToEyeTransforms);
+
+  Matrix4x4 matView[2];
+  memcpy(matView[0].components,
+         aState.sensorState.leftViewMatrix,
+         sizeof(float) * 16);
+  memcpy(matView[1].components,
+         aState.sensorState.rightViewMatrix,
+         sizeof(float) * 16);
+
+  for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; eye++) {
+    Point3D eyeTranslation;
+    Quaternion eyeRotation;
+    Point3D eyeScale;
+    if (!matView[eye].Decompose(eyeTranslation, eyeRotation, eyeScale)) {
+      NS_WARNING("Failed to decompose eye pose matrix for Oculus");
+    }
+
+    mFrameStartPose[eye].Orientation.x = eyeRotation.x;
+    mFrameStartPose[eye].Orientation.y = eyeRotation.y;
+    mFrameStartPose[eye].Orientation.z = eyeRotation.z;
+    mFrameStartPose[eye].Orientation.w = eyeRotation.w;
+    mFrameStartPose[eye].Position.x = eyeTranslation.x;
+    mFrameStartPose[eye].Position.y = eyeTranslation.y;
+    mFrameStartPose[eye].Position.z = eyeTranslation.z;
+  }
+}
+
+void
+OculusSession::UpdateHeadsetPose(VRSystemState& aState)
+{
+  if (!mSession) {
+    return;
+  }
+  double predictedFrameTime = 0.0f;
+  if (gfxPrefs::VRPosePredictionEnabled()) {
+    // XXX We might need to call ovr_GetPredictedDisplayTime even if we don't
+    // use the result. If we don't call it, the Oculus driver will spew out many
+    // warnings...
+    predictedFrameTime = ovr_GetPredictedDisplayTime(mSession, 0);
+  }
+  ovrTrackingState trackingState =
+    ovr_GetTrackingState(mSession, predictedFrameTime, true);
+  ovrPoseStatef& pose(trackingState.HeadPose);
+
+  aState.sensorState.timestamp = pose.TimeInSeconds;
+
+  if (trackingState.StatusFlags & ovrStatus_OrientationTracked) {
+    aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
+
+    aState.sensorState.pose.orientation[0] = pose.ThePose.Orientation.x;
+    aState.sensorState.pose.orientation[1] = pose.ThePose.Orientation.y;
+    aState.sensorState.pose.orientation[2] = pose.ThePose.Orientation.z;
+    aState.sensorState.pose.orientation[3] = pose.ThePose.Orientation.w;
+
+    aState.sensorState.pose.angularVelocity[0] = pose.AngularVelocity.x;
+    aState.sensorState.pose.angularVelocity[1] = pose.AngularVelocity.y;
+    aState.sensorState.pose.angularVelocity[2] = pose.AngularVelocity.z;
+
+    aState.sensorState.flags |=
+      VRDisplayCapabilityFlags::Cap_AngularAcceleration;
+
+    aState.sensorState.pose.angularAcceleration[0] = pose.AngularAcceleration.x;
+    aState.sensorState.pose.angularAcceleration[1] = pose.AngularAcceleration.y;
+    aState.sensorState.pose.angularAcceleration[2] = pose.AngularAcceleration.z;
+  } else {
+    // default to an identity quaternion
+    aState.sensorState.pose.orientation[3] = 1.0f;
+  }
+
+  if (trackingState.StatusFlags & ovrStatus_PositionTracked) {
+    float eyeHeight =
+      ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
+    aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
+
+    aState.sensorState.pose.position[0] = pose.ThePose.Position.x;
+    aState.sensorState.pose.position[1] = pose.ThePose.Position.y - eyeHeight;
+    aState.sensorState.pose.position[2] = pose.ThePose.Position.z;
+
+    aState.sensorState.pose.linearVelocity[0] = pose.LinearVelocity.x;
+    aState.sensorState.pose.linearVelocity[1] = pose.LinearVelocity.y;
+    aState.sensorState.pose.linearVelocity[2] = pose.LinearVelocity.z;
+
+    aState.sensorState.flags |=
+      VRDisplayCapabilityFlags::Cap_LinearAcceleration;
+
+    aState.sensorState.pose.linearAcceleration[0] = pose.LinearAcceleration.x;
+    aState.sensorState.pose.linearAcceleration[1] = pose.LinearAcceleration.y;
+    aState.sensorState.pose.linearAcceleration[2] = pose.LinearAcceleration.z;
+  }
+  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_External;
+  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_MountDetection;
+  aState.sensorState.flags |= VRDisplayCapabilityFlags::Cap_Present;
+}
+
+void
+OculusSession::UpdateControllers(VRSystemState& aState)
+{
+  if (!mSession) {
+    return;
+  }
+
+  ovrInputState inputState;
+  bool hasInputState =
+    ovr_GetInputState(mSession, ovrControllerType_Touch, &inputState) ==
+    ovrSuccess;
+
+  if (!hasInputState) {
+    return;
+  }
+
+  EnumerateControllers(aState, inputState);
+  UpdateControllerInputs(aState, inputState);
+  UpdateControllerPose(aState, inputState);
+}
+
+void
+OculusSession::UpdateControllerPose(VRSystemState& aState,
+                                    const ovrInputState& aInputState)
+{
+  ovrTrackingState trackingState = ovr_GetTrackingState(mSession, 0.0, false);
+  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
+    // Left Touch Controller will always be at index 0 and
+    // and Right Touch Controller will always be at index 1
+    VRControllerState& controllerState = aState.controllerState[handIdx];
+    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
+      ovrPoseStatef& pose = trackingState.HandPoses[handIdx];
+      bool bNewController =
+        !(controllerState.flags & dom::GamepadCapabilityFlags::Cap_Orientation);
+      if (bNewController) {
+        controllerState.flags |= dom::GamepadCapabilityFlags::Cap_Orientation;
+        controllerState.flags |= dom::GamepadCapabilityFlags::Cap_Position;
+        controllerState.flags |=
+          dom::GamepadCapabilityFlags::Cap_AngularAcceleration;
+        controllerState.flags |=
+          dom::GamepadCapabilityFlags::Cap_LinearAcceleration;
+      }
+
+      if (bNewController || trackingState.HandStatusFlags[handIdx] &
+                              ovrStatus_OrientationTracked) {
+        controllerState.pose.orientation[0] = pose.ThePose.Orientation.x;
+        controllerState.pose.orientation[1] = pose.ThePose.Orientation.y;
+        controllerState.pose.orientation[2] = pose.ThePose.Orientation.z;
+        controllerState.pose.orientation[3] = pose.ThePose.Orientation.w;
+        controllerState.pose.angularVelocity[0] = pose.AngularVelocity.x;
+        controllerState.pose.angularVelocity[1] = pose.AngularVelocity.y;
+        controllerState.pose.angularVelocity[2] = pose.AngularVelocity.z;
+        controllerState.pose.angularAcceleration[0] =
+          pose.AngularAcceleration.x;
+        controllerState.pose.angularAcceleration[1] =
+          pose.AngularAcceleration.y;
+        controllerState.pose.angularAcceleration[2] =
+          pose.AngularAcceleration.z;
+        controllerState.isOrientationValid = true;
+      } else {
+        controllerState.isOrientationValid = false;
+      }
+      if (bNewController ||
+          trackingState.HandStatusFlags[handIdx] & ovrStatus_PositionTracked) {
+        controllerState.pose.position[0] = pose.ThePose.Position.x;
+        controllerState.pose.position[1] = pose.ThePose.Position.y;
+        controllerState.pose.position[2] = pose.ThePose.Position.z;
+        controllerState.pose.linearVelocity[0] = pose.LinearVelocity.x;
+        controllerState.pose.linearVelocity[1] = pose.LinearVelocity.y;
+        controllerState.pose.linearVelocity[2] = pose.LinearVelocity.z;
+        controllerState.pose.linearAcceleration[0] = pose.LinearAcceleration.x;
+        controllerState.pose.linearAcceleration[1] = pose.LinearAcceleration.y;
+        controllerState.pose.linearAcceleration[2] = pose.LinearAcceleration.z;
+
+        float eyeHeight =
+          ovr_GetFloat(mSession, OVR_KEY_EYE_HEIGHT, OVR_DEFAULT_EYE_HEIGHT);
+        controllerState.pose.position[1] -= eyeHeight;
+        controllerState.isPositionValid = true;
+      } else {
+        controllerState.isPositionValid = false;
+      }
+    }
+  }
+}
+
+void
+OculusSession::EnumerateControllers(VRSystemState& aState,
+                                    const ovrInputState& aInputState)
+{
+  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
+    // Left Touch Controller will always be at index 0 and
+    // and Right Touch Controller will always be at index 1
+    VRControllerState& controllerState = aState.controllerState[handIdx];
+    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
+      bool bNewController = false;
+      // Left Touch Controller detected
+      if (controllerState.controllerName[0] == '\0') {
+        // Controller has been just enumerated
+        strncpy(controllerState.controllerName,
+                OculusControllerNames[handIdx],
+                kVRControllerNameMaxLen);
+        controllerState.hand = OculusControllerHand[handIdx];
+        controllerState.numButtons = kNumOculusButtons;
+        controllerState.numAxes = kNumOculusAxes;
+        controllerState.numHaptics = kNumOculusHaptcs;
+        bNewController = true;
+      }
+    } else {
+      // Left Touch Controller not detected
+      if (controllerState.controllerName[0] != '\0') {
+        // Clear any newly disconnected ontrollers
+        memset(&controllerState, 0, sizeof(VRControllerState));
+      }
+    }
+  }
+}
+
+void
+OculusSession::UpdateControllerInputs(VRSystemState& aState,
+                                      const ovrInputState& aInputState)
+{
+  const float triggerThreshold = gfxPrefs::VRControllerTriggerThreshold();
+
+  for (uint32_t handIdx = 0; handIdx < 2; handIdx++) {
+    // Left Touch Controller will always be at index 0 and
+    // and Right Touch Controller will always be at index 1
+    VRControllerState& controllerState = aState.controllerState[handIdx];
+    if (aInputState.ControllerType & OculusControllerTypes[handIdx]) {
+      // Update Button States
+      controllerState.buttonPressed = 0;
+      controllerState.buttonTouched = 0;
+      uint32_t buttonIdx = 0;
+
+      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
+      buttonIdx++;
+      UpdateTrigger(controllerState,
+                    buttonIdx,
+                    aInputState.IndexTrigger[handIdx],
+                    triggerThreshold);
+      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
+      buttonIdx++;
+      UpdateTrigger(controllerState,
+                    buttonIdx,
+                    aInputState.HandTrigger[handIdx],
+                    triggerThreshold);
+      buttonIdx++;
+      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
+      buttonIdx++;
+      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
+      buttonIdx++;
+      UpdateButton(aInputState, handIdx, buttonIdx, controllerState);
+      buttonIdx++;
+
+      MOZ_ASSERT(buttonIdx == kNumOculusButtons);
+
+      // Update Thumbstick axis
+      uint32_t axisIdx = 0;
+      float axisValue = aInputState.Thumbstick[handIdx].x;
+      if (abs(axisValue) < 0.0000009f) {
+        axisValue = 0.0f; // Clear noise signal
+      }
+      controllerState.axisValue[axisIdx] = axisValue;
+      axisIdx++;
+
+      // Note that y axis is intentionally inverted!
+      axisValue = -aInputState.Thumbstick[handIdx].y;
+      if (abs(axisValue) < 0.0000009f) {
+        axisValue = 0.0f; // Clear noise signal
+      }
+      controllerState.axisValue[axisIdx] = axisValue;
+      axisIdx++;
+
+      MOZ_ASSERT(axisIdx == kNumOculusAxes);
+    }
+  }
+}
+
+void
+OculusSession::UpdateTelemetry(VRSystemState& aSystemState)
+{
+  if (!mSession) {
+    return;
+  }
+  ovrPerfStats perfStats;
+  if (ovr_GetPerfStats(mSession, &perfStats) == ovrSuccess) {
+    if (perfStats.FrameStatsCount) {
+      aSystemState.displayState.mDroppedFrameCount =
+        perfStats.FrameStats[0].AppDroppedFrameCount;
+    }
+  }
+}
+
+void
+OculusSession::VibrateHaptic(uint32_t aControllerIdx,
+                             uint32_t aHapticIndex,
+                             float aIntensity,
+                             float aDuration)
+{
+  if (!mSession) {
+    return;
+  }
+
+  if (aDuration <= 0.0f) {
+    StopVibrateHaptic(aControllerIdx);
+    return;
+  }
+
+  // Vibration amplitude in the [0.0, 1.0] range
+  MOZ_ASSERT(aControllerIdx >= 0 && aControllerIdx <= 1);
+  mHapticPulseIntensity[aControllerIdx] = aIntensity > 1.0 ? 1.0 : aIntensity;
+  mRemainingVibrateTime[aControllerIdx] = aDuration;
+  ovrControllerType hand = OculusControllerTypes[aControllerIdx];
+
+  // The gamepad extensions API does not yet have independent control
+  // of frequency and amplitude.  We are always sending 0.0f (160hz)
+  // to the frequency argument.
+  ovrResult result = ovr_SetControllerVibration(
+    mSession, hand, 0.0f, mHapticPulseIntensity[aControllerIdx]);
+  if (result != ovrSuccess) {
+    // This may happen if called when not presenting.
+    gfxWarning() << "ovr_SetControllerVibration failed.";
+  }
+}
+
+void
+OculusSession::StopVibrateHaptic(uint32_t aControllerIdx)
+{
+  if (!mSession) {
+    return;
+  }
+  MOZ_ASSERT(aControllerIdx >= 0 && aControllerIdx <= 1);
+  ovrControllerType hand = OculusControllerTypes[aControllerIdx];
+  mRemainingVibrateTime[aControllerIdx] = 0.0f;
+  mHapticPulseIntensity[aControllerIdx] = 0.0f;
+
+  ovrResult result = ovr_SetControllerVibration(mSession, hand, 0.0f, 0.0f);
+  if (result != ovrSuccess) {
+    // This may happen if called when not presenting.
+    gfxWarning() << "ovr_SetControllerVibration failed.";
+  }
+}
+
+void
+OculusSession::StopAllHaptics()
+{
+  // Left Oculus Touch
+  StopVibrateHaptic(0);
+  // Right Oculus Touch
+  StopVibrateHaptic(1);
+}
+
+void
+OculusSession::UpdateHaptics()
+{
+  if (!mSession) {
+    return;
+  }
+  // The Oculus API and hardware takes at least 33ms to respond
+  // to haptic state changes, so it is not beneficial to create
+  // a dedicated haptic feedback thread and update multiple
+  // times per frame.
+  // If we wish to support more accurate effects with sub-frame timing,
+  // we should use the buffered haptic feedback API's.
+
+  TimeStamp now = TimeStamp::Now();
+  if (mLastHapticUpdate.IsNull()) {
+    mLastHapticUpdate = now;
+    return;
+  }
+  float deltaTime = (float)(now - mLastHapticUpdate).ToSeconds();
+  mLastHapticUpdate = now;
+  for (int i = 0; i < 2; i++) {
+    if (mRemainingVibrateTime[i] <= 0.0f) {
+      continue;
+    }
+    mRemainingVibrateTime[i] -= deltaTime;
+    ovrControllerType hand = OculusControllerTypes[i];
+    if (mRemainingVibrateTime[i] > 0.0f) {
+      ovrResult result = ovr_SetControllerVibration(
+        mSession, hand, 0.0f, mHapticPulseIntensity[i]);
+      if (result != ovrSuccess) {
+        // This may happen if called when not presenting.
+        gfxWarning() << "ovr_SetControllerVibration failed.";
+      }
+    } else {
+      StopVibrateHaptic(i);
+    }
+  }
+}
+
+} // namespace mozilla
+} // namespace gfx
--- a/gfx/vr/service/OculusSession.h
+++ b/gfx/vr/service/OculusSession.h
@@ -1,114 +1,114 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_VR_SERVICE_OCULUSSESSION_H
-#define GFX_VR_SERVICE_OCULUSSESSION_H
-
-#include "VRSession.h"
-
-#include "mozilla/gfx/2D.h"
-#include "moz_external_vr.h"
-#include "nsTArray.h"
-#include "oculus/ovr_capi_dynamic.h"
-#include "prlink.h"
-#include "ShaderDefinitionsD3D11.h" // for VertexShaderConstants and PixelShaderConstants
-
-struct ID3D11Device;
-
-namespace mozilla {
-namespace layers {
-struct VertexShaderConstants;
-struct PixelShaderConstants;
-}
-namespace gfx {
-
-class OculusSession : public VRSession
-{
-public:
-  OculusSession();
-  virtual ~OculusSession();
-
-  bool Initialize(mozilla::gfx::VRSystemState& aSystemState) override;
-  void Shutdown() override;
-  void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) override;
-  void StartFrame(mozilla::gfx::VRSystemState& aSystemState) override;
-  bool StartPresentation() override;
-  void StopPresentation() override;
-  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                   ID3D11Texture2D* aTexture) override;
-  void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
-                    float aIntensity, float aDuration) override;
-  void StopVibrateHaptic(uint32_t aControllerIdx) override;
-  void StopAllHaptics() override;
-
-private:
-  bool LoadOvrLib();
-  void UnloadOvrLib();
-  bool StartLib(ovrInitFlags aFlags);
-  void StopLib();
-  bool StartSession();
-  void StopSession();
-  bool StartRendering();
-  void StopRendering();
-  bool CreateD3DObjects();
-  bool CreateShaders();
-  void DestroyShaders();
-  void CoverTransitions();
-  void UpdateVisibility();
-  bool ChangeVisibility(bool bVisible);
-  bool InitState(mozilla::gfx::VRSystemState& aSystemState);
-  void UpdateStageParameters(mozilla::gfx::VRDisplayState& aState);
-  void UpdateEyeParameters(mozilla::gfx::VRSystemState& aState);
-  void UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState);
-  void UpdateControllers(VRSystemState& aState);
-  void UpdateControllerInputs(VRSystemState& aState,
-                              const ovrInputState& aInputState);
-  void UpdateHaptics();
-  void EnumerateControllers(VRSystemState& aState,
-                            const ovrInputState& aInputState);
-  void UpdateControllerPose(VRSystemState& aState,
-                            const ovrInputState& aInputState);
-  void UpdateTelemetry(VRSystemState& aSystemState);
-  bool IsPresentationReady() const;
-  bool UpdateConstantBuffers();
-
-  PRLibrary* mOvrLib;
-  ovrSession mSession;
-  ovrInitFlags mInitFlags;
-  ovrTextureSwapChain mTextureSet;
-  nsTArray<RefPtr<ID3D11RenderTargetView>> mRTView;
-  nsTArray<RefPtr<ID3D11Texture2D>> mTexture;
-  nsTArray<RefPtr<ID3D11ShaderResourceView>> mSRV;
-
-  ID3D11VertexShader* mQuadVS;
-  ID3D11PixelShader* mQuadPS;
-  RefPtr<ID3D11SamplerState> mLinearSamplerState;
-  layers::VertexShaderConstants mVSConstants;
-  layers::PixelShaderConstants mPSConstants;
-  RefPtr<ID3D11Buffer> mVSConstantBuffer;
-  RefPtr<ID3D11Buffer> mPSConstantBuffer;
-  RefPtr<ID3D11Buffer> mVertexBuffer;
-  RefPtr<ID3D11InputLayout> mInputLayout;
-
-  IntSize mPresentationSize;
-  ovrFovPort mFOVPort[2];
-
-  // Most recent HMD eye poses, from start of frame
-  ovrPosef mFrameStartPose[2];
-
-  float mRemainingVibrateTime[2];
-  float mHapticPulseIntensity[2];
-  TimeStamp mLastHapticUpdate;
-
-  // The timestamp of the last ending presentation
-  TimeStamp mLastPresentationEnd;
-  bool mIsPresenting;
-};
-
-} // namespace mozilla
-} // namespace gfx
-
-#endif // GFX_VR_SERVICE_OCULUSSESSION_H
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_VR_SERVICE_OCULUSSESSION_H
+#define GFX_VR_SERVICE_OCULUSSESSION_H
+
+#include "VRSession.h"
+
+#include "mozilla/gfx/2D.h"
+#include "moz_external_vr.h"
+#include "nsTArray.h"
+#include "oculus/ovr_capi_dynamic.h"
+#include "prlink.h"
+#include "ShaderDefinitionsD3D11.h" // for VertexShaderConstants and PixelShaderConstants
+
+struct ID3D11Device;
+
+namespace mozilla {
+namespace layers {
+struct VertexShaderConstants;
+struct PixelShaderConstants;
+}
+namespace gfx {
+
+class OculusSession : public VRSession
+{
+public:
+  OculusSession();
+  virtual ~OculusSession();
+
+  bool Initialize(mozilla::gfx::VRSystemState& aSystemState) override;
+  void Shutdown() override;
+  void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) override;
+  void StartFrame(mozilla::gfx::VRSystemState& aSystemState) override;
+  bool StartPresentation() override;
+  void StopPresentation() override;
+  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                   ID3D11Texture2D* aTexture) override;
+  void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
+                    float aIntensity, float aDuration) override;
+  void StopVibrateHaptic(uint32_t aControllerIdx) override;
+  void StopAllHaptics() override;
+
+private:
+  bool LoadOvrLib();
+  void UnloadOvrLib();
+  bool StartLib(ovrInitFlags aFlags);
+  void StopLib();
+  bool StartSession();
+  void StopSession();
+  bool StartRendering();
+  void StopRendering();
+  bool CreateD3DObjects();
+  bool CreateShaders();
+  void DestroyShaders();
+  void CoverTransitions();
+  void UpdateVisibility();
+  bool ChangeVisibility(bool bVisible);
+  bool InitState(mozilla::gfx::VRSystemState& aSystemState);
+  void UpdateStageParameters(mozilla::gfx::VRDisplayState& aState);
+  void UpdateEyeParameters(mozilla::gfx::VRSystemState& aState);
+  void UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState);
+  void UpdateControllers(VRSystemState& aState);
+  void UpdateControllerInputs(VRSystemState& aState,
+                              const ovrInputState& aInputState);
+  void UpdateHaptics();
+  void EnumerateControllers(VRSystemState& aState,
+                            const ovrInputState& aInputState);
+  void UpdateControllerPose(VRSystemState& aState,
+                            const ovrInputState& aInputState);
+  void UpdateTelemetry(VRSystemState& aSystemState);
+  bool IsPresentationReady() const;
+  bool UpdateConstantBuffers();
+
+  PRLibrary* mOvrLib;
+  ovrSession mSession;
+  ovrInitFlags mInitFlags;
+  ovrTextureSwapChain mTextureSet;
+  nsTArray<RefPtr<ID3D11RenderTargetView>> mRTView;
+  nsTArray<RefPtr<ID3D11Texture2D>> mTexture;
+  nsTArray<RefPtr<ID3D11ShaderResourceView>> mSRV;
+
+  ID3D11VertexShader* mQuadVS;
+  ID3D11PixelShader* mQuadPS;
+  RefPtr<ID3D11SamplerState> mLinearSamplerState;
+  layers::VertexShaderConstants mVSConstants;
+  layers::PixelShaderConstants mPSConstants;
+  RefPtr<ID3D11Buffer> mVSConstantBuffer;
+  RefPtr<ID3D11Buffer> mPSConstantBuffer;
+  RefPtr<ID3D11Buffer> mVertexBuffer;
+  RefPtr<ID3D11InputLayout> mInputLayout;
+
+  IntSize mPresentationSize;
+  ovrFovPort mFOVPort[2];
+
+  // Most recent HMD eye poses, from start of frame
+  ovrPosef mFrameStartPose[2];
+
+  float mRemainingVibrateTime[2];
+  float mHapticPulseIntensity[2];
+  TimeStamp mLastHapticUpdate;
+
+  // The timestamp of the last ending presentation
+  TimeStamp mLastPresentationEnd;
+  bool mIsPresenting;
+};
+
+} // namespace mozilla
+} // namespace gfx
+
+#endif // GFX_VR_SERVICE_OCULUSSESSION_H
--- a/gfx/vr/service/OpenVRSession.cpp
+++ b/gfx/vr/service/OpenVRSession.cpp
@@ -1,1057 +1,1057 @@
-#include "OpenVRSession.h"
-#include "gfxPrefs.h"
-
-#if defined(XP_WIN)
-#include <d3d11.h>
-#include "mozilla/gfx/DeviceManagerDx.h"
-#elif defined(XP_MACOSX)
-#include "mozilla/gfx/MacIOSurface.h"
-#endif
-
-#include "mozilla/dom/GamepadEventTypes.h"
-#include "mozilla/dom/GamepadBinding.h"
-#include "VRThread.h"
-
-#if !defined(M_PI)
-#define M_PI 3.14159265358979323846264338327950288
-#endif
-
-#define BTN_MASK_FROM_ID(_id) \
-  ::vr::ButtonMaskFromId(vr::EVRButtonId::_id)
-
-// Haptic feedback is updated every 5ms, as this is
-// the minimum period between new haptic pulse requests.
-// Effectively, this results in a pulse width modulation
-// with an interval of 5ms.  Through experimentation, the
-// maximum duty cycle was found to be about 3.9ms
-const uint32_t kVRHapticUpdateInterval = 5;
-
-using namespace mozilla::gfx;
-
-namespace mozilla {
-namespace gfx {
-
-namespace {
-
-dom::GamepadHand
-GetControllerHandFromControllerRole(::vr::ETrackedControllerRole aRole)
-{
-  dom::GamepadHand hand;
-
-  switch(aRole) {
-    case ::vr::ETrackedControllerRole::TrackedControllerRole_Invalid:
-    case ::vr::ETrackedControllerRole::TrackedControllerRole_OptOut:
-      hand = dom::GamepadHand::_empty;
-      break;
-    case ::vr::ETrackedControllerRole::TrackedControllerRole_LeftHand:
-      hand = dom::GamepadHand::Left;
-      break;
-    case ::vr::ETrackedControllerRole::TrackedControllerRole_RightHand:
-      hand = dom::GamepadHand::Right;
-      break;
-    default:
-      hand = dom::GamepadHand::_empty;
-      MOZ_ASSERT(false);
-      break;
-  }
-
-  return hand;
-}
-
-
-void
-UpdateButton(VRControllerState& aState, const ::vr::VRControllerState_t& aControllerState, uint32_t aButtonIndex, uint64_t aButtonMask)
-{
-  uint64_t mask = (1ULL << aButtonIndex);
-  if ((aControllerState.ulButtonPressed & aButtonMask) == 0) {
-    // not pressed
-    aState.buttonPressed &= ~mask;
-    aState.triggerValue[aButtonIndex] = 0.0f;
-  } else {
-    // pressed
-    aState.buttonPressed |= mask;
-    aState.triggerValue[aButtonIndex] = 1.0f;
-  }
-  if ((aControllerState.ulButtonTouched & aButtonMask) == 0) {
-    // not touched
-    aState.buttonTouched &= ~mask;
-  } else {
-    // touched
-    aState.buttonTouched |= mask;
-  }
-}
-
-}; // anonymous namespace
-
-OpenVRSession::OpenVRSession()
-  : VRSession()
-  , mVRSystem(nullptr)
-  , mVRChaperone(nullptr)
-  , mVRCompositor(nullptr)
-  , mControllerDeviceIndex{}
-  , mHapticPulseRemaining{}
-  , mHapticPulseIntensity{}
-  , mIsWindowsMR(false)
-  , mControllerHapticStateMutex("OpenVRSession::mControllerHapticStateMutex")
-{
-}
-
-OpenVRSession::~OpenVRSession()
-{
-  Shutdown();
-}
-
-bool
-OpenVRSession::Initialize(mozilla::gfx::VRSystemState& aSystemState)
-{
-  if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
-    return false;
-  }
-  if (mVRSystem != nullptr) {
-    // Already initialized
-    return true;
-  }
-  if (!::vr::VR_IsRuntimeInstalled()) {
-    return false;
-  }
-  if (!::vr::VR_IsHmdPresent()) {
-    return false;
-  }
-
-  ::vr::HmdError err;
-
-  ::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
-  if (err) {
-    return false;
-  }
-
-  mVRSystem = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
-  if (err || !mVRSystem) {
-    Shutdown();
-    return false;
-  }
-  mVRChaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
-  if (err || !mVRChaperone) {
-    Shutdown();
-    return false;
-  }
-  mVRCompositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
-  if (err || !mVRCompositor) {
-    Shutdown();
-    return false;
-  }
-
-#if defined(XP_WIN)
-  if (!CreateD3DObjects()) {
-    Shutdown();
-    return false;
-  }
-
-#endif
-
-  // Configure coordinate system
-  mVRCompositor->SetTrackingSpace(::vr::TrackingUniverseSeated);
-
-  if (!InitState(aSystemState)) {
-    Shutdown();
-    return false;
-  }
-
-  StartHapticThread();
-  StartHapticTimer();
-  
-  // Succeeded
-  return true;
-}
-
-#if defined(XP_WIN)
-bool
-OpenVRSession::CreateD3DObjects()
-{
-  RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetVRDevice();
-  if (!device) {
-    return false;
-  }
-  if (!CreateD3DContext(device)) {
-    return false;
-  }
-  return true;
-}
-#endif
-
-void
-OpenVRSession::Shutdown()
-{
-  StopHapticTimer();
-  StopHapticThread();
-  if (mVRSystem || mVRCompositor || mVRSystem) {
-    ::vr::VR_Shutdown();
-    mVRCompositor = nullptr;
-    mVRChaperone = nullptr;
-    mVRSystem = nullptr;
-  }
-}
-
-bool
-OpenVRSession::InitState(VRSystemState& aSystemState)
-{
-  VRDisplayState& state = aSystemState.displayState;
-  strncpy(state.mDisplayName, "OpenVR HMD", kVRDisplayNameMaxLen);
-  state.mEightCC = GFX_VR_EIGHTCC('O', 'p', 'e', 'n', 'V', 'R', ' ', ' ');
-  state.mIsConnected = mVRSystem->IsTrackedDeviceConnected(::vr::k_unTrackedDeviceIndex_Hmd);
-  state.mIsMounted = false;
-  state.mCapabilityFlags = (VRDisplayCapabilityFlags)((int)VRDisplayCapabilityFlags::Cap_None |
-    (int)VRDisplayCapabilityFlags::Cap_Orientation |
-    (int)VRDisplayCapabilityFlags::Cap_Position |
-    (int)VRDisplayCapabilityFlags::Cap_External |
-    (int)VRDisplayCapabilityFlags::Cap_Present |
-    (int)VRDisplayCapabilityFlags::Cap_StageParameters);
-  state.mReportsDroppedFrames = true;
-
-  ::vr::ETrackedPropertyError err;
-  bool bHasProximitySensor = mVRSystem->GetBoolTrackedDeviceProperty(::vr::k_unTrackedDeviceIndex_Hmd, ::vr::Prop_ContainsProximitySensor_Bool, &err);
-  if (err == ::vr::TrackedProp_Success && bHasProximitySensor) {
-    state.mCapabilityFlags = (VRDisplayCapabilityFlags)((int)state.mCapabilityFlags | (int)VRDisplayCapabilityFlags::Cap_MountDetection);
-  }
-
-  uint32_t w, h;
-  mVRSystem->GetRecommendedRenderTargetSize(&w, &h);
-  state.mEyeResolution.width = w;
-  state.mEyeResolution.height = h;
-
-  // default to an identity quaternion
-  aSystemState.sensorState.pose.orientation[3] = 1.0f;
-
-  UpdateStageParameters(state);
-  UpdateEyeParameters(aSystemState);
-
-  VRHMDSensorState& sensorState = aSystemState.sensorState;
-  sensorState.flags = (VRDisplayCapabilityFlags)(
-    (int)VRDisplayCapabilityFlags::Cap_Orientation |
-    (int)VRDisplayCapabilityFlags::Cap_Position);
-  sensorState.pose.orientation[3] = 1.0f; // Default to an identity quaternion
-
-  return true;
-}
-
-void
-OpenVRSession::UpdateStageParameters(VRDisplayState& aState)
-{
-  float sizeX = 0.0f;
-  float sizeZ = 0.0f;
-  if (mVRChaperone->GetPlayAreaSize(&sizeX, &sizeZ)) {
-    ::vr::HmdMatrix34_t t = mVRSystem->GetSeatedZeroPoseToStandingAbsoluteTrackingPose();
-    aState.mStageSize.width = sizeX;
-    aState.mStageSize.height = sizeZ;
-
-    aState.mSittingToStandingTransform[0] = t.m[0][0];
-    aState.mSittingToStandingTransform[1] = t.m[1][0];
-    aState.mSittingToStandingTransform[2] = t.m[2][0];
-    aState.mSittingToStandingTransform[3] = 0.0f;
-
-    aState.mSittingToStandingTransform[4] = t.m[0][1];
-    aState.mSittingToStandingTransform[5] = t.m[1][1];
-    aState.mSittingToStandingTransform[6] = t.m[2][1];
-    aState.mSittingToStandingTransform[7] = 0.0f;
-
-    aState.mSittingToStandingTransform[8] = t.m[0][2];
-    aState.mSittingToStandingTransform[9] = t.m[1][2];
-    aState.mSittingToStandingTransform[10] = t.m[2][2];
-    aState.mSittingToStandingTransform[11] = 0.0f;
-
-    aState.mSittingToStandingTransform[12] = t.m[0][3];
-    aState.mSittingToStandingTransform[13] = t.m[1][3];
-    aState.mSittingToStandingTransform[14] = t.m[2][3];
-    aState.mSittingToStandingTransform[15] = 1.0f;
-  } else {
-    // If we fail, fall back to reasonable defaults.
-    // 1m x 1m space, 0.75m high in seated position
-    aState.mStageSize.width = 1.0f;
-    aState.mStageSize.height = 1.0f;
-
-    aState.mSittingToStandingTransform[0] = 1.0f;
-    aState.mSittingToStandingTransform[1] = 0.0f;
-    aState.mSittingToStandingTransform[2] = 0.0f;
-    aState.mSittingToStandingTransform[3] = 0.0f;
-
-    aState.mSittingToStandingTransform[4] = 0.0f;
-    aState.mSittingToStandingTransform[5] = 1.0f;
-    aState.mSittingToStandingTransform[6] = 0.0f;
-    aState.mSittingToStandingTransform[7] = 0.0f;
-
-    aState.mSittingToStandingTransform[8] = 0.0f;
-    aState.mSittingToStandingTransform[9] = 0.0f;
-    aState.mSittingToStandingTransform[10] = 1.0f;
-    aState.mSittingToStandingTransform[11] = 0.0f;
-
-    aState.mSittingToStandingTransform[12] = 0.0f;
-    aState.mSittingToStandingTransform[13] = 0.75f;
-    aState.mSittingToStandingTransform[14] = 0.0f;
-    aState.mSittingToStandingTransform[15] = 1.0f;
-  }
-}
-
-void
-OpenVRSession::UpdateEyeParameters(VRSystemState& aState)
-{
-  // This must be called every frame in order to
-  // account for continuous adjustments to ipd.
-  gfx::Matrix4x4 headToEyeTransforms[2];
-
-  for (uint32_t eye = 0; eye < 2; ++eye) {
-    ::vr::HmdMatrix34_t eyeToHead = mVRSystem->GetEyeToHeadTransform(static_cast<::vr::Hmd_Eye>(eye));
-    aState.displayState.mEyeTranslation[eye].x = eyeToHead.m[0][3];
-    aState.displayState.mEyeTranslation[eye].y = eyeToHead.m[1][3];
-    aState.displayState.mEyeTranslation[eye].z = eyeToHead.m[2][3];
-
-    float left, right, up, down;
-    mVRSystem->GetProjectionRaw(static_cast<::vr::Hmd_Eye>(eye), &left, &right, &up, &down);
-    aState.displayState.mEyeFOV[eye].upDegrees = atan(-up) * 180.0 / M_PI;
-    aState.displayState.mEyeFOV[eye].rightDegrees = atan(right) * 180.0 / M_PI;
-    aState.displayState.mEyeFOV[eye].downDegrees = atan(down) * 180.0 / M_PI;
-    aState.displayState.mEyeFOV[eye].leftDegrees = atan(-left) * 180.0 / M_PI;
-
-    Matrix4x4 pose;
-    // NOTE! eyeToHead.m is a 3x4 matrix, not 4x4.  But
-    // because of its arrangement, we can copy the 12 elements in and
-    // then transpose them to the right place.
-    memcpy(&pose._11, &eyeToHead.m, sizeof(eyeToHead.m));
-    pose.Transpose();
-    pose.Invert();
-    headToEyeTransforms[eye] = pose;
-  }
-  aState.sensorState.CalcViewMatrices(headToEyeTransforms);
-}
-
-void
-OpenVRSession::UpdateHeadsetPose(VRSystemState& aState)
-{
-  const uint32_t posesSize = ::vr::k_unTrackedDeviceIndex_Hmd + 1;
-  ::vr::TrackedDevicePose_t poses[posesSize];
-  // Note: We *must* call WaitGetPoses in order for any rendering to happen at all.
-  mVRCompositor->WaitGetPoses(poses, posesSize, nullptr, 0);
-
-  ::vr::Compositor_FrameTiming timing;
-  timing.m_nSize = sizeof(::vr::Compositor_FrameTiming);
-  if (mVRCompositor->GetFrameTiming(&timing)) {
-    aState.sensorState.timestamp = timing.m_flSystemTimeInSeconds;
-  } else {
-    // This should not happen, but log it just in case
-    fprintf(stderr, "OpenVR - IVRCompositor::GetFrameTiming failed");
-  }
-
-  if (poses[::vr::k_unTrackedDeviceIndex_Hmd].bDeviceIsConnected &&
-    poses[::vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid &&
-    poses[::vr::k_unTrackedDeviceIndex_Hmd].eTrackingResult == ::vr::TrackingResult_Running_OK)
-  {
-    const ::vr::TrackedDevicePose_t& pose = poses[::vr::k_unTrackedDeviceIndex_Hmd];
-
-    gfx::Matrix4x4 m;
-    // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4.  But
-    // because of its arrangement, we can copy the 12 elements in and
-    // then transpose them to the right place.  We do this so we can
-    // pull out a Quaternion.
-    memcpy(&m._11, &pose.mDeviceToAbsoluteTracking, sizeof(pose.mDeviceToAbsoluteTracking));
-    m.Transpose();
-
-    gfx::Quaternion rot;
-    rot.SetFromRotationMatrix(m);
-    rot.Invert();
-
-    aState.sensorState.flags = (VRDisplayCapabilityFlags)((int)aState.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Orientation);
-    aState.sensorState.pose.orientation[0] = rot.x;
-    aState.sensorState.pose.orientation[1] = rot.y;
-    aState.sensorState.pose.orientation[2] = rot.z;
-    aState.sensorState.pose.orientation[3] = rot.w;
-    aState.sensorState.pose.angularVelocity[0] = pose.vAngularVelocity.v[0];
-    aState.sensorState.pose.angularVelocity[1] = pose.vAngularVelocity.v[1];
-    aState.sensorState.pose.angularVelocity[2] = pose.vAngularVelocity.v[2];
-
-    aState.sensorState.flags =(VRDisplayCapabilityFlags)((int)aState.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Position);
-    aState.sensorState.pose.position[0] = m._41;
-    aState.sensorState.pose.position[1] = m._42;
-    aState.sensorState.pose.position[2] = m._43;
-    aState.sensorState.pose.linearVelocity[0] = pose.vVelocity.v[0];
-    aState.sensorState.pose.linearVelocity[1] = pose.vVelocity.v[1];
-    aState.sensorState.pose.linearVelocity[2] = pose.vVelocity.v[2];
-  }
-}
-
-void
-OpenVRSession::EnumerateControllers(VRSystemState& aState)
-{
-  MOZ_ASSERT(mVRSystem);
-
-  MutexAutoLock lock(mControllerHapticStateMutex);
-
-  bool controllerPresent[kVRControllerMaxCount] = { false };
-
-  // Basically, we would have HMDs in the tracked devices,
-  // but we are just interested in the controllers.
-  for (::vr::TrackedDeviceIndex_t trackedDevice = ::vr::k_unTrackedDeviceIndex_Hmd + 1;
-       trackedDevice < ::vr::k_unMaxTrackedDeviceCount; ++trackedDevice) {
-
-    if (!mVRSystem->IsTrackedDeviceConnected(trackedDevice)) {
-      continue;
-    }
-
-    const ::vr::ETrackedDeviceClass deviceType = mVRSystem->
-                                                 GetTrackedDeviceClass(trackedDevice);
-    if (deviceType != ::vr::TrackedDeviceClass_Controller
-        && deviceType != ::vr::TrackedDeviceClass_GenericTracker) {
-      continue;
-    }
-
-    uint32_t stateIndex = 0;
-    uint32_t firstEmptyIndex = kVRControllerMaxCount;
-
-    // Find the existing controller
-    for (stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
-      if (mControllerDeviceIndex[stateIndex] == 0 && firstEmptyIndex == kVRControllerMaxCount) {
-        firstEmptyIndex = stateIndex;
-      }
-      if (mControllerDeviceIndex[stateIndex] == trackedDevice) {
-        break;
-      }
-    }
-    if (stateIndex == kVRControllerMaxCount) {
-      // This is a new controller, let's add it
-      if (firstEmptyIndex == kVRControllerMaxCount) {
-        NS_WARNING("OpenVR - Too many controllers, need to increase kVRControllerMaxCount.");
-        continue;
-      }
-      stateIndex = firstEmptyIndex;
-      mControllerDeviceIndex[stateIndex] = trackedDevice;
-      VRControllerState& controllerState = aState.controllerState[stateIndex];
-      uint32_t numButtons = 0;
-      uint32_t numAxes = 0;
-
-      // Scan the axes that the controllers support
-      for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) {
-        const uint32_t supportAxis = mVRSystem->GetInt32TrackedDeviceProperty(trackedDevice,
-                                      static_cast<vr::TrackedDeviceProperty>(
-                                      ::vr::Prop_Axis0Type_Int32 + j));
-        switch (supportAxis) {
-          case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
-          case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
-            numAxes += 2; // It has x and y axes.
-            ++numButtons;
-            break;
-          case ::vr::k_eControllerAxis_Trigger:
-            if (j <= 2) {
-              ++numButtons;
-            } else {
-          #ifdef DEBUG
-              // SteamVR Knuckles is the only special case for using 2D axis values on triggers.
-              ::vr::ETrackedPropertyError err;
-              uint32_t requiredBufferLen;
-              char charBuf[128];
-              requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(trackedDevice,
-                                  ::vr::Prop_RenderModelName_String, charBuf, 128, &err);
-              MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
-              nsCString deviceId(charBuf);
-              MOZ_ASSERT(deviceId.Find("knuckles") != kNotFound);
-          #endif // #ifdef DEBUG
-              numButtons += 2;
-            }
-            break;
-        }
-      }
-
-      // Scan the buttons that the controllers support
-      const uint64_t supportButtons = mVRSystem->GetUint64TrackedDeviceProperty(
-                                       trackedDevice, ::vr::Prop_SupportedButtons_Uint64);
-      if (supportButtons &
-          BTN_MASK_FROM_ID(k_EButton_A)) {
-        ++numButtons;
-      }
-      if (supportButtons &
-          BTN_MASK_FROM_ID(k_EButton_Grip)) {
-        ++numButtons;
-      }
-      if (supportButtons &
-          BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
-        ++numButtons;
-      }
-      if (supportButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
-        ++numButtons;
-      }
-      if (supportButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Up)) {
-        ++numButtons;
-      }
-      if (supportButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Right)) {
-        ++numButtons;
-      }
-      if (supportButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Down)) {
-        ++numButtons;
-      }
-
-      nsCString deviceId;
-      GetControllerDeviceId(deviceType, trackedDevice, deviceId);
-
-      strncpy(controllerState.controllerName, deviceId.BeginReading(), kVRControllerNameMaxLen);
-      controllerState.numButtons = numButtons;
-      controllerState.numAxes = numAxes;
-      controllerState.numHaptics = kNumOpenVRHaptics;
-
-      // If the Windows MR controller doesn't has the amount
-      // of buttons or axes as our expectation, switching off
-      // the workaround for Windows MR.
-      if (mIsWindowsMR && (numAxes < 4 || numButtons < 5)) {
-        mIsWindowsMR = false;
-        NS_WARNING("OpenVR - Switching off Windows MR mode.");
-      }
-    }
-    controllerPresent[stateIndex] = true;
-  }
-  // Clear out entries for disconnected controllers
-  for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
-    if (!controllerPresent[stateIndex] && mControllerDeviceIndex[stateIndex] != 0) {
-      mControllerDeviceIndex[stateIndex] = 0;
-      memset(&aState.controllerState[stateIndex], 0, sizeof(VRControllerState));
-    }
-  }
-}
-
-void
-OpenVRSession::UpdateControllerButtons(VRSystemState& aState)
-{
-  MOZ_ASSERT(mVRSystem);
-
-  // Compared to Edge, we have a wrong implementation for the vertical axis value.
-  // In order to not affect the current VR content, we add a workaround for yAxis.
-  const float yAxisInvert = (mIsWindowsMR) ? -1.0f : 1.0f;
-  const float triggerThreshold = gfxPrefs::VRControllerTriggerThreshold();
-
-  for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
-    ::vr::TrackedDeviceIndex_t trackedDevice = mControllerDeviceIndex[stateIndex];
-    if (trackedDevice == 0) {
-      continue;
-    }
-    VRControllerState& controllerState = aState.controllerState[stateIndex];
-    const ::vr::ETrackedControllerRole role = mVRSystem->
-                                          GetControllerRoleForTrackedDeviceIndex(
-                                          trackedDevice);
-    dom::GamepadHand hand = GetControllerHandFromControllerRole(role);
-    controllerState.hand = hand;
-
-    ::vr::VRControllerState_t vrControllerState;
-    if (mVRSystem->GetControllerState(trackedDevice, &vrControllerState, sizeof(vrControllerState))) {
-      uint32_t axisIdx = 0;
-      uint32_t buttonIdx = 0;
-      for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) {
-        const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty(
-                                   trackedDevice,
-                                   static_cast<::vr::TrackedDeviceProperty>(
-                                   ::vr::Prop_Axis0Type_Int32 + j));
-        switch (axisType) {
-          case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
-          case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
-          {
-            if (mIsWindowsMR) {
-              // Adjust the input mapping for Windows MR which has
-              // different order.
-              axisIdx = (axisIdx == 0) ? 2 : 0;
-              buttonIdx = (buttonIdx == 0) ? 4 : 0;
-            }
-
-            controllerState.axisValue[axisIdx] = vrControllerState.rAxis[j].x;
-            ++axisIdx;
-            controllerState.axisValue[axisIdx] = vrControllerState.rAxis[j].y * yAxisInvert;
-            ++axisIdx;
-            uint64_t buttonMask = ::vr::ButtonMaskFromId(
-                                 static_cast<::vr::EVRButtonId>(::vr::k_EButton_Axis0 + j));
-
-            UpdateButton(controllerState, vrControllerState, buttonIdx, buttonMask);
-            ++buttonIdx;
-
-            if (mIsWindowsMR) {
-              axisIdx = (axisIdx == 4) ? 2 : 4;
-              buttonIdx = (buttonIdx == 5) ? 1 : 2;
-            }
-            break;
-          }
-          case vr::EVRControllerAxisType::k_eControllerAxis_Trigger:
-          {
-            if (j <= 2) {
-              UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].x, triggerThreshold);
-              ++buttonIdx;
-            } else {
-              // For SteamVR Knuckles.
-              UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].x, triggerThreshold);
-              ++buttonIdx;
-              UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].y, triggerThreshold);
-              ++buttonIdx;
-            }
-            break;
-          }
-        }
-      }
-
-      const uint64_t supportedButtons = mVRSystem->GetUint64TrackedDeviceProperty(
-                                         trackedDevice, ::vr::Prop_SupportedButtons_Uint64);
-      if (supportedButtons &
-          BTN_MASK_FROM_ID(k_EButton_A)) {
-        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_A));
-        ++buttonIdx;
-      }
-      if (supportedButtons &
-          BTN_MASK_FROM_ID(k_EButton_Grip)) {
-        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_Grip));
-        ++buttonIdx;
-      }
-      if (supportedButtons &
-          BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
-        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_ApplicationMenu));
-        ++buttonIdx;
-      }
-      if (mIsWindowsMR) {
-        // button 4 in Windows MR has already been assigned
-        // to k_eControllerAxis_TrackPad.
-        ++buttonIdx;
-      }
-      if (supportedButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
-        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Left));
-        ++buttonIdx;
-      }
-      if (supportedButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Up)) {
-        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Up));
-        ++buttonIdx;
-      }
-      if (supportedButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Right)) {
-        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Right));
-        ++buttonIdx;
-      }
-      if (supportedButtons &
-          BTN_MASK_FROM_ID(k_EButton_DPad_Down)) {
-        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Down));
-        ++buttonIdx;
-      }
-    }
-  }
-}
-
-void
-OpenVRSession::UpdateControllerPoses(VRSystemState& aState)
-{
-  MOZ_ASSERT(mVRSystem);
-
-  ::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount];
-  mVRSystem->GetDeviceToAbsoluteTrackingPose(::vr::TrackingUniverseSeated, 0.0f,
-                                             poses, ::vr::k_unMaxTrackedDeviceCount);
-
-  for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
-    ::vr::TrackedDeviceIndex_t trackedDevice = mControllerDeviceIndex[stateIndex];
-    if (trackedDevice == 0) {
-      continue;
-    }
-    VRControllerState& controllerState = aState.controllerState[stateIndex];
-    const ::vr::TrackedDevicePose_t& pose = poses[trackedDevice];
-
-    if (pose.bDeviceIsConnected) {
-      controllerState.flags = (dom::GamepadCapabilityFlags::Cap_Orientation |
-                               dom::GamepadCapabilityFlags::Cap_Position);
-    } else {
-      controllerState.flags =  dom::GamepadCapabilityFlags::Cap_None;
-    }
-    if (pose.bPoseIsValid &&
-        pose.eTrackingResult == ::vr::TrackingResult_Running_OK) {
-      gfx::Matrix4x4 m;
-
-      // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4.  But
-      // because of its arrangement, we can copy the 12 elements in and
-      // then transpose them to the right place.  We do this so we can
-      // pull out a Quaternion.
-      memcpy(&m.components, &pose.mDeviceToAbsoluteTracking, sizeof(pose.mDeviceToAbsoluteTracking));
-      m.Transpose();
-
-      gfx::Quaternion rot;
-      rot.SetFromRotationMatrix(m);
-      rot.Invert();
-
-      controllerState.pose.orientation[0] = rot.x;
-      controllerState.pose.orientation[1] = rot.y;
-      controllerState.pose.orientation[2] = rot.z;
-      controllerState.pose.orientation[3] = rot.w;
-      controllerState.pose.angularVelocity[0] = pose.vAngularVelocity.v[0];
-      controllerState.pose.angularVelocity[1] = pose.vAngularVelocity.v[1];
-      controllerState.pose.angularVelocity[2] = pose.vAngularVelocity.v[2];
-      controllerState.pose.angularAcceleration[0] = 0.0f;
-      controllerState.pose.angularAcceleration[1] = 0.0f;
-      controllerState.pose.angularAcceleration[2] = 0.0f;
-      controllerState.isOrientationValid = true;
-
-      controllerState.pose.position[0] = m._41;
-      controllerState.pose.position[1] = m._42;
-      controllerState.pose.position[2] = m._43;
-      controllerState.pose.linearVelocity[0] = pose.vVelocity.v[0];
-      controllerState.pose.linearVelocity[1] = pose.vVelocity.v[1];
-      controllerState.pose.linearVelocity[2] = pose.vVelocity.v[2];
-      controllerState.pose.linearAcceleration[0] = 0.0f;
-      controllerState.pose.linearAcceleration[1] = 0.0f;
-      controllerState.pose.linearAcceleration[2] = 0.0f;
-      controllerState.isPositionValid = true;
-    } else {
-      controllerState.isOrientationValid = false;
-      controllerState.isPositionValid = false;
-    }
-  }
-}
-
-void
-OpenVRSession::GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType,
-                                     ::vr::TrackedDeviceIndex_t aDeviceIndex,
-                                     nsCString& aId)
-{
-  switch (aDeviceType) {
-    case ::vr::TrackedDeviceClass_Controller:
-    {
-      ::vr::ETrackedPropertyError err;
-      uint32_t requiredBufferLen;
-      bool isFound = false;
-      char charBuf[128];
-      requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex,
-                          ::vr::Prop_RenderModelName_String, charBuf, 128, &err);
-      if (requiredBufferLen > 128) {
-        MOZ_CRASH("Larger than the buffer size.");
-      }
-      MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
-      nsCString deviceId(charBuf);
-      if (deviceId.Find("knuckles") != kNotFound) {
-        aId.AssignLiteral("OpenVR Knuckles");
-        isFound = true;
-      }
-      requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex,
-        ::vr::Prop_SerialNumber_String, charBuf, 128, &err);
-      if (requiredBufferLen > 128) {
-        MOZ_CRASH("Larger than the buffer size.");
-      }
-      MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
-      deviceId.Assign(charBuf);
-      if (deviceId.Find("MRSOURCE") != kNotFound) {
-        aId.AssignLiteral("Spatial Controller (Spatial Interaction Source) ");
-        mIsWindowsMR = true;
-        isFound = true;
-      }
-      if (!isFound) {
-        aId.AssignLiteral("OpenVR Gamepad");
-      }
-      break;
-    }
-    case ::vr::TrackedDeviceClass_GenericTracker:
-    {
-      aId.AssignLiteral("OpenVR Tracker");
-      break;
-    }
-    default:
-      MOZ_ASSERT(false);
-      break;
-  }
-}
-
-void
-OpenVRSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState)
-{
-  UpdateHeadsetPose(aSystemState);
-  UpdateEyeParameters(aSystemState);
-  EnumerateControllers(aSystemState);
-  UpdateControllerButtons(aSystemState);
-  UpdateControllerPoses(aSystemState);
-  UpdateTelemetry(aSystemState);
-}
-
-void
-OpenVRSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState)
-{
-  bool isHmdPresent = ::vr::VR_IsHmdPresent();
-  if (!isHmdPresent) {
-    mShouldQuit = true;
-  }
-
-  ::vr::VREvent_t event;
-  while (mVRSystem && mVRSystem->PollNextEvent(&event, sizeof(event))) {
-    switch (event.eventType) {
-      case ::vr::VREvent_TrackedDeviceUserInteractionStarted:
-        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
-          aSystemState.displayState.mIsMounted = true;
-        }
-        break;
-      case ::vr::VREvent_TrackedDeviceUserInteractionEnded:
-        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
-          aSystemState.displayState.mIsMounted = false;
-        }
-        break;
-      case ::vr::EVREventType::VREvent_TrackedDeviceActivated:
-        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
-          aSystemState.displayState.mIsConnected = true;
-        }
-        break;
-      case ::vr::EVREventType::VREvent_TrackedDeviceDeactivated:
-        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
-          aSystemState.displayState.mIsConnected = false;
-        }
-        break;
-      case ::vr::EVREventType::VREvent_DriverRequestedQuit:
-      case ::vr::EVREventType::VREvent_Quit:
-      case ::vr::EVREventType::VREvent_ProcessQuit:
-      case ::vr::EVREventType::VREvent_QuitAcknowledged:
-      case ::vr::EVREventType::VREvent_QuitAborted_UserPrompt:
-        mShouldQuit = true;
-        break;
-      default:
-        // ignore
-        break;
-    }
-  }
-}
-
-#if defined(XP_WIN)
-bool
-OpenVRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                           ID3D11Texture2D* aTexture)
-{
-  return SubmitFrame((void *)aTexture,
-                     ::vr::ETextureType::TextureType_DirectX,
-                     aLayer.mLeftEyeRect, aLayer.mRightEyeRect);
-}
-#elif defined(XP_MACOSX)
-bool
-OpenVRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                           const VRLayerTextureHandle& aTexture)
-{
-  return SubmitFrame(aTexture,
-                     ::vr::ETextureType::TextureType_IOSurface,
-                     aLayer.mLeftEyeRect, aLayer.mRightEyeRect);
-}
-#endif
-
-bool
-OpenVRSession::SubmitFrame(const VRLayerTextureHandle& aTextureHandle,
-                           ::vr::ETextureType aTextureType,
-                           const VRLayerEyeRect& aLeftEyeRect,
-                           const VRLayerEyeRect& aRightEyeRect)
-{
-  ::vr::Texture_t tex;
-#if defined(XP_MACOSX)
-  // We get aTextureHandle from get_SurfaceDescriptorMacIOSurface() at VRDisplayExternal.
-  // scaleFactor and opaque are skipped because they always are 1.0 and false.
-  RefPtr<MacIOSurface> surf = MacIOSurface::LookupSurface(aTextureHandle);
-  if (!surf) {
-    NS_WARNING("OpenVRSession::SubmitFrame failed to get a MacIOSurface");
-    return false;
-  }
-
-  const void* ioSurface = surf->GetIOSurfacePtr();
-  tex.handle = (void *)ioSurface;
-#else
-  tex.handle = aTextureHandle;
-#endif
-  tex.eType = aTextureType;
-  tex.eColorSpace = ::vr::EColorSpace::ColorSpace_Auto;
-
-  ::vr::VRTextureBounds_t bounds;
-  bounds.uMin = aLeftEyeRect.x;
-  bounds.vMin = 1.0 - aLeftEyeRect.y;
-  bounds.uMax = aLeftEyeRect.x + aLeftEyeRect.width;
-  bounds.vMax = 1.0 - (aLeftEyeRect.y + aLeftEyeRect.height);
-
-  ::vr::EVRCompositorError err;
-  err = mVRCompositor->Submit(::vr::EVREye::Eye_Left, &tex, &bounds);
-  if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
-    printf_stderr("OpenVR Compositor Submit() failed.\n");
-  }
-
-  bounds.uMin = aRightEyeRect.x;
-  bounds.vMin = 1.0 - aRightEyeRect.y;
-  bounds.uMax = aRightEyeRect.x + aRightEyeRect.width;
-  bounds.vMax = 1.0 - (aRightEyeRect.y + aRightEyeRect.height);
-
-  err = mVRCompositor->Submit(::vr::EVREye::Eye_Right, &tex, &bounds);
-  if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
-    printf_stderr("OpenVR Compositor Submit() failed.\n");
-  }
-
-  mVRCompositor->PostPresentHandoff();
-  return true;
-}
-
-void
-OpenVRSession::StopPresentation()
-{
-  mVRCompositor->ClearLastSubmittedFrame();
-
-  ::vr::Compositor_CumulativeStats stats;
-  mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
-}
-
-bool
-OpenVRSession::StartPresentation()
-{
-  return true;
-}
-
-void
-OpenVRSession::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
-                             float aIntensity, float aDuration)
-{
-  MutexAutoLock lock(mControllerHapticStateMutex);
-  if (aHapticIndex >= kNumOpenVRHaptics ||
-      aControllerIdx >= kVRControllerMaxCount) {
-    return;
-  }
-
-  ::vr::TrackedDeviceIndex_t deviceIndex = mControllerDeviceIndex[aControllerIdx];
-  if (deviceIndex == 0) {
-    return;
-  }
-
-  mHapticPulseRemaining[aControllerIdx][aHapticIndex] = aDuration;
-  mHapticPulseIntensity[aControllerIdx][aHapticIndex] = aIntensity;
-
-  /**
-   *  TODO - The haptic feedback pulses will have latency of one frame and we
-   *         are simulating intensity with pulse-width modulation.
-   *         We should use of the OpenVR Input API to correct this
-   *         and replace the TriggerHapticPulse calls which have been
-   *         deprecated.
-   */
-}
-
-void
-OpenVRSession::StartHapticThread()
-{
-  if (!mHapticThread) {
-    mHapticThread = new VRThread(NS_LITERAL_CSTRING("VR_OpenVR_Haptics"));
-  }
-  mHapticThread->Start();
-}
-
-void
-OpenVRSession::StopHapticThread()
-{
-  if (mHapticThread) {
-    mHapticThread->Shutdown();
-    mHapticThread = nullptr;
-  }
-}
-
-void
-OpenVRSession::StartHapticTimer()
-{
-  if (!mHapticTimer && mHapticThread) {
-    mLastHapticUpdate = TimeStamp();
-    mHapticTimer = NS_NewTimer();
-    mHapticTimer->SetTarget(mHapticThread->GetThread()->EventTarget());
-    mHapticTimer->InitWithNamedFuncCallback(
-      HapticTimerCallback,
-      this,
-      kVRHapticUpdateInterval,
-      nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP,
-      "OpenVRSession::HapticTimerCallback");
-  }
-}
-
-void
-OpenVRSession::StopHapticTimer()
-{
-  if (mHapticTimer) {
-    mHapticTimer->Cancel();
-    mHapticTimer = nullptr;
-  }
-}
-
-/*static*/ void
-OpenVRSession::HapticTimerCallback(nsITimer* aTimer, void* aClosure)
-{
-  /**
-   * It is safe to use the pointer passed in aClosure to reference the
-   * OpenVRSession object as the timer is canceled in OpenVRSession::Shutdown,
-   * which is called by the OpenVRSession destructor, guaranteeing
-   * that this function runs if and only if the VRManager object is valid.
-   */
-  OpenVRSession* self = static_cast<OpenVRSession*>(aClosure);
-  self->UpdateHaptics();
-}
-
-void
-OpenVRSession::UpdateHaptics()
-{
-  MOZ_ASSERT(mHapticThread->GetThread() == NS_GetCurrentThread());
-  MOZ_ASSERT(mVRSystem);
-
-  MutexAutoLock lock(mControllerHapticStateMutex);
-
-  TimeStamp now = TimeStamp::Now();
-  if (mLastHapticUpdate.IsNull()) {
-    mLastHapticUpdate = now;
-    return;
-  }
-  float deltaTime = (float)(now - mLastHapticUpdate).ToSeconds();
-  mLastHapticUpdate = now;
-
-  for (int iController = 0; iController < kVRControllerMaxCount; iController++) {
-    for (int iHaptic = 0; iHaptic < kNumOpenVRHaptics; iHaptic++) {
-      ::vr::TrackedDeviceIndex_t deviceIndex = mControllerDeviceIndex[iController];
-      if (deviceIndex == 0) {
-        continue;
-      }
-      float intensity = mHapticPulseIntensity[iController][iHaptic];
-      float duration = mHapticPulseRemaining[iController][iHaptic];
-      if (duration <= 0.0f || intensity <= 0.0f) {
-        continue;
-      }
-      // We expect OpenVR to vibrate for 5 ms, but we found it only response the
-      // commend ~ 3.9 ms. For duration time longer than 3.9 ms, we separate them
-      // to a loop of 3.9 ms for make users feel that is a continuous events.
-      const float microSec = (duration < 0.0039f ? duration : 0.0039f) * 1000000.0f * intensity;
-      mVRSystem->TriggerHapticPulse(deviceIndex, iHaptic, (uint32_t)microSec);
-
-      duration -= deltaTime;
-      if (duration < 0.0f) {
-        duration = 0.0f;
-      }
-      mHapticPulseRemaining[iController][iHaptic] = duration;
-    }
-  }
-}
-
-void
-OpenVRSession::StopVibrateHaptic(uint32_t aControllerIdx)
-{
-  MutexAutoLock lock(mControllerHapticStateMutex);
-  if (aControllerIdx >= kVRControllerMaxCount) {
-    return;
-  }
-  for (int iHaptic = 0; iHaptic < kNumOpenVRHaptics; iHaptic++) {
-    mHapticPulseRemaining[aControllerIdx][iHaptic] = 0.0f;
-  }
-}
-
-void
-OpenVRSession::StopAllHaptics()
-{
-  MutexAutoLock lock(mControllerHapticStateMutex);
-  for (auto& controller : mHapticPulseRemaining) {
-    for (auto& haptic : controller) {
-      haptic = 0.0f;
-    }
-  }
-}
-
-void
-OpenVRSession::UpdateTelemetry(VRSystemState& aSystemState)
-{
-  ::vr::Compositor_CumulativeStats stats;
-  mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
-  aSystemState.displayState.mDroppedFrameCount = stats.m_nNumReprojectedFrames;
-}
-
-} // namespace mozilla
-} // namespace gfx
+#include "OpenVRSession.h"
+#include "gfxPrefs.h"
+
+#if defined(XP_WIN)
+#include <d3d11.h>
+#include "mozilla/gfx/DeviceManagerDx.h"
+#elif defined(XP_MACOSX)
+#include "mozilla/gfx/MacIOSurface.h"
+#endif
+
+#include "mozilla/dom/GamepadEventTypes.h"
+#include "mozilla/dom/GamepadBinding.h"
+#include "VRThread.h"
+
+#if !defined(M_PI)
+#define M_PI 3.14159265358979323846264338327950288
+#endif
+
+#define BTN_MASK_FROM_ID(_id) \
+  ::vr::ButtonMaskFromId(vr::EVRButtonId::_id)
+
+// Haptic feedback is updated every 5ms, as this is
+// the minimum period between new haptic pulse requests.
+// Effectively, this results in a pulse width modulation
+// with an interval of 5ms.  Through experimentation, the
+// maximum duty cycle was found to be about 3.9ms
+const uint32_t kVRHapticUpdateInterval = 5;
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace gfx {
+
+namespace {
+
+dom::GamepadHand
+GetControllerHandFromControllerRole(::vr::ETrackedControllerRole aRole)
+{
+  dom::GamepadHand hand;
+
+  switch(aRole) {
+    case ::vr::ETrackedControllerRole::TrackedControllerRole_Invalid:
+    case ::vr::ETrackedControllerRole::TrackedControllerRole_OptOut:
+      hand = dom::GamepadHand::_empty;
+      break;
+    case ::vr::ETrackedControllerRole::TrackedControllerRole_LeftHand:
+      hand = dom::GamepadHand::Left;
+      break;
+    case ::vr::ETrackedControllerRole::TrackedControllerRole_RightHand:
+      hand = dom::GamepadHand::Right;
+      break;
+    default:
+      hand = dom::GamepadHand::_empty;
+      MOZ_ASSERT(false);
+      break;
+  }
+
+  return hand;
+}
+
+
+void
+UpdateButton(VRControllerState& aState, const ::vr::VRControllerState_t& aControllerState, uint32_t aButtonIndex, uint64_t aButtonMask)
+{
+  uint64_t mask = (1ULL << aButtonIndex);
+  if ((aControllerState.ulButtonPressed & aButtonMask) == 0) {
+    // not pressed
+    aState.buttonPressed &= ~mask;
+    aState.triggerValue[aButtonIndex] = 0.0f;
+  } else {
+    // pressed
+    aState.buttonPressed |= mask;
+    aState.triggerValue[aButtonIndex] = 1.0f;
+  }
+  if ((aControllerState.ulButtonTouched & aButtonMask) == 0) {
+    // not touched
+    aState.buttonTouched &= ~mask;
+  } else {
+    // touched
+    aState.buttonTouched |= mask;
+  }
+}
+
+}; // anonymous namespace
+
+OpenVRSession::OpenVRSession()
+  : VRSession()
+  , mVRSystem(nullptr)
+  , mVRChaperone(nullptr)
+  , mVRCompositor(nullptr)
+  , mControllerDeviceIndex{}
+  , mHapticPulseRemaining{}
+  , mHapticPulseIntensity{}
+  , mIsWindowsMR(false)
+  , mControllerHapticStateMutex("OpenVRSession::mControllerHapticStateMutex")
+{
+}
+
+OpenVRSession::~OpenVRSession()
+{
+  Shutdown();
+}
+
+bool
+OpenVRSession::Initialize(mozilla::gfx::VRSystemState& aSystemState)
+{
+  if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
+    return false;
+  }
+  if (mVRSystem != nullptr) {
+    // Already initialized
+    return true;
+  }
+  if (!::vr::VR_IsRuntimeInstalled()) {
+    return false;
+  }
+  if (!::vr::VR_IsHmdPresent()) {
+    return false;
+  }
+
+  ::vr::HmdError err;
+
+  ::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
+  if (err) {
+    return false;
+  }
+
+  mVRSystem = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
+  if (err || !mVRSystem) {
+    Shutdown();
+    return false;
+  }
+  mVRChaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
+  if (err || !mVRChaperone) {
+    Shutdown();
+    return false;
+  }
+  mVRCompositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
+  if (err || !mVRCompositor) {
+    Shutdown();
+    return false;
+  }
+
+#if defined(XP_WIN)
+  if (!CreateD3DObjects()) {
+    Shutdown();
+    return false;
+  }
+
+#endif
+
+  // Configure coordinate system
+  mVRCompositor->SetTrackingSpace(::vr::TrackingUniverseSeated);
+
+  if (!InitState(aSystemState)) {
+    Shutdown();
+    return false;
+  }
+
+  StartHapticThread();
+  StartHapticTimer();
+  
+  // Succeeded
+  return true;
+}
+
+#if defined(XP_WIN)
+bool
+OpenVRSession::CreateD3DObjects()
+{
+  RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetVRDevice();
+  if (!device) {
+    return false;
+  }
+  if (!CreateD3DContext(device)) {
+    return false;
+  }
+  return true;
+}
+#endif
+
+void
+OpenVRSession::Shutdown()
+{
+  StopHapticTimer();
+  StopHapticThread();
+  if (mVRSystem || mVRCompositor || mVRSystem) {
+    ::vr::VR_Shutdown();
+    mVRCompositor = nullptr;
+    mVRChaperone = nullptr;
+    mVRSystem = nullptr;
+  }
+}
+
+bool
+OpenVRSession::InitState(VRSystemState& aSystemState)
+{
+  VRDisplayState& state = aSystemState.displayState;
+  strncpy(state.mDisplayName, "OpenVR HMD", kVRDisplayNameMaxLen);
+  state.mEightCC = GFX_VR_EIGHTCC('O', 'p', 'e', 'n', 'V', 'R', ' ', ' ');
+  state.mIsConnected = mVRSystem->IsTrackedDeviceConnected(::vr::k_unTrackedDeviceIndex_Hmd);
+  state.mIsMounted = false;
+  state.mCapabilityFlags = (VRDisplayCapabilityFlags)((int)VRDisplayCapabilityFlags::Cap_None |
+    (int)VRDisplayCapabilityFlags::Cap_Orientation |
+    (int)VRDisplayCapabilityFlags::Cap_Position |
+    (int)VRDisplayCapabilityFlags::Cap_External |
+    (int)VRDisplayCapabilityFlags::Cap_Present |
+    (int)VRDisplayCapabilityFlags::Cap_StageParameters);
+  state.mReportsDroppedFrames = true;
+
+  ::vr::ETrackedPropertyError err;
+  bool bHasProximitySensor = mVRSystem->GetBoolTrackedDeviceProperty(::vr::k_unTrackedDeviceIndex_Hmd, ::vr::Prop_ContainsProximitySensor_Bool, &err);
+  if (err == ::vr::TrackedProp_Success && bHasProximitySensor) {
+    state.mCapabilityFlags = (VRDisplayCapabilityFlags)((int)state.mCapabilityFlags | (int)VRDisplayCapabilityFlags::Cap_MountDetection);
+  }
+
+  uint32_t w, h;
+  mVRSystem->GetRecommendedRenderTargetSize(&w, &h);
+  state.mEyeResolution.width = w;
+  state.mEyeResolution.height = h;
+
+  // default to an identity quaternion
+  aSystemState.sensorState.pose.orientation[3] = 1.0f;
+
+  UpdateStageParameters(state);
+  UpdateEyeParameters(aSystemState);
+
+  VRHMDSensorState& sensorState = aSystemState.sensorState;
+  sensorState.flags = (VRDisplayCapabilityFlags)(
+    (int)VRDisplayCapabilityFlags::Cap_Orientation |
+    (int)VRDisplayCapabilityFlags::Cap_Position);
+  sensorState.pose.orientation[3] = 1.0f; // Default to an identity quaternion
+
+  return true;
+}
+
+void
+OpenVRSession::UpdateStageParameters(VRDisplayState& aState)
+{
+  float sizeX = 0.0f;
+  float sizeZ = 0.0f;
+  if (mVRChaperone->GetPlayAreaSize(&sizeX, &sizeZ)) {
+    ::vr::HmdMatrix34_t t = mVRSystem->GetSeatedZeroPoseToStandingAbsoluteTrackingPose();
+    aState.mStageSize.width = sizeX;
+    aState.mStageSize.height = sizeZ;
+
+    aState.mSittingToStandingTransform[0] = t.m[0][0];
+    aState.mSittingToStandingTransform[1] = t.m[1][0];
+    aState.mSittingToStandingTransform[2] = t.m[2][0];
+    aState.mSittingToStandingTransform[3] = 0.0f;
+
+    aState.mSittingToStandingTransform[4] = t.m[0][1];
+    aState.mSittingToStandingTransform[5] = t.m[1][1];
+    aState.mSittingToStandingTransform[6] = t.m[2][1];
+    aState.mSittingToStandingTransform[7] = 0.0f;
+
+    aState.mSittingToStandingTransform[8] = t.m[0][2];
+    aState.mSittingToStandingTransform[9] = t.m[1][2];
+    aState.mSittingToStandingTransform[10] = t.m[2][2];
+    aState.mSittingToStandingTransform[11] = 0.0f;
+
+    aState.mSittingToStandingTransform[12] = t.m[0][3];
+    aState.mSittingToStandingTransform[13] = t.m[1][3];
+    aState.mSittingToStandingTransform[14] = t.m[2][3];
+    aState.mSittingToStandingTransform[15] = 1.0f;
+  } else {
+    // If we fail, fall back to reasonable defaults.
+    // 1m x 1m space, 0.75m high in seated position
+    aState.mStageSize.width = 1.0f;
+    aState.mStageSize.height = 1.0f;
+
+    aState.mSittingToStandingTransform[0] = 1.0f;
+    aState.mSittingToStandingTransform[1] = 0.0f;
+    aState.mSittingToStandingTransform[2] = 0.0f;
+    aState.mSittingToStandingTransform[3] = 0.0f;
+
+    aState.mSittingToStandingTransform[4] = 0.0f;
+    aState.mSittingToStandingTransform[5] = 1.0f;
+    aState.mSittingToStandingTransform[6] = 0.0f;
+    aState.mSittingToStandingTransform[7] = 0.0f;
+
+    aState.mSittingToStandingTransform[8] = 0.0f;
+    aState.mSittingToStandingTransform[9] = 0.0f;
+    aState.mSittingToStandingTransform[10] = 1.0f;
+    aState.mSittingToStandingTransform[11] = 0.0f;
+
+    aState.mSittingToStandingTransform[12] = 0.0f;
+    aState.mSittingToStandingTransform[13] = 0.75f;
+    aState.mSittingToStandingTransform[14] = 0.0f;
+    aState.mSittingToStandingTransform[15] = 1.0f;
+  }
+}
+
+void
+OpenVRSession::UpdateEyeParameters(VRSystemState& aState)
+{
+  // This must be called every frame in order to
+  // account for continuous adjustments to ipd.
+  gfx::Matrix4x4 headToEyeTransforms[2];
+
+  for (uint32_t eye = 0; eye < 2; ++eye) {
+    ::vr::HmdMatrix34_t eyeToHead = mVRSystem->GetEyeToHeadTransform(static_cast<::vr::Hmd_Eye>(eye));
+    aState.displayState.mEyeTranslation[eye].x = eyeToHead.m[0][3];
+    aState.displayState.mEyeTranslation[eye].y = eyeToHead.m[1][3];
+    aState.displayState.mEyeTranslation[eye].z = eyeToHead.m[2][3];
+
+    float left, right, up, down;
+    mVRSystem->GetProjectionRaw(static_cast<::vr::Hmd_Eye>(eye), &left, &right, &up, &down);
+    aState.displayState.mEyeFOV[eye].upDegrees = atan(-up) * 180.0 / M_PI;
+    aState.displayState.mEyeFOV[eye].rightDegrees = atan(right) * 180.0 / M_PI;
+    aState.displayState.mEyeFOV[eye].downDegrees = atan(down) * 180.0 / M_PI;
+    aState.displayState.mEyeFOV[eye].leftDegrees = atan(-left) * 180.0 / M_PI;
+
+    Matrix4x4 pose;
+    // NOTE! eyeToHead.m is a 3x4 matrix, not 4x4.  But
+    // because of its arrangement, we can copy the 12 elements in and
+    // then transpose them to the right place.
+    memcpy(&pose._11, &eyeToHead.m, sizeof(eyeToHead.m));
+    pose.Transpose();
+    pose.Invert();
+    headToEyeTransforms[eye] = pose;
+  }
+  aState.sensorState.CalcViewMatrices(headToEyeTransforms);
+}
+
+void
+OpenVRSession::UpdateHeadsetPose(VRSystemState& aState)
+{
+  const uint32_t posesSize = ::vr::k_unTrackedDeviceIndex_Hmd + 1;
+  ::vr::TrackedDevicePose_t poses[posesSize];
+  // Note: We *must* call WaitGetPoses in order for any rendering to happen at all.
+  mVRCompositor->WaitGetPoses(poses, posesSize, nullptr, 0);
+
+  ::vr::Compositor_FrameTiming timing;
+  timing.m_nSize = sizeof(::vr::Compositor_FrameTiming);
+  if (mVRCompositor->GetFrameTiming(&timing)) {
+    aState.sensorState.timestamp = timing.m_flSystemTimeInSeconds;
+  } else {
+    // This should not happen, but log it just in case
+    fprintf(stderr, "OpenVR - IVRCompositor::GetFrameTiming failed");
+  }
+
+  if (poses[::vr::k_unTrackedDeviceIndex_Hmd].bDeviceIsConnected &&
+    poses[::vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid &&
+    poses[::vr::k_unTrackedDeviceIndex_Hmd].eTrackingResult == ::vr::TrackingResult_Running_OK)
+  {
+    const ::vr::TrackedDevicePose_t& pose = poses[::vr::k_unTrackedDeviceIndex_Hmd];
+
+    gfx::Matrix4x4 m;
+    // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4.  But
+    // because of its arrangement, we can copy the 12 elements in and
+    // then transpose them to the right place.  We do this so we can
+    // pull out a Quaternion.
+    memcpy(&m._11, &pose.mDeviceToAbsoluteTracking, sizeof(pose.mDeviceToAbsoluteTracking));
+    m.Transpose();
+
+    gfx::Quaternion rot;
+    rot.SetFromRotationMatrix(m);
+    rot.Invert();
+
+    aState.sensorState.flags = (VRDisplayCapabilityFlags)((int)aState.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Orientation);
+    aState.sensorState.pose.orientation[0] = rot.x;
+    aState.sensorState.pose.orientation[1] = rot.y;
+    aState.sensorState.pose.orientation[2] = rot.z;
+    aState.sensorState.pose.orientation[3] = rot.w;
+    aState.sensorState.pose.angularVelocity[0] = pose.vAngularVelocity.v[0];
+    aState.sensorState.pose.angularVelocity[1] = pose.vAngularVelocity.v[1];
+    aState.sensorState.pose.angularVelocity[2] = pose.vAngularVelocity.v[2];
+
+    aState.sensorState.flags =(VRDisplayCapabilityFlags)((int)aState.sensorState.flags | (int)VRDisplayCapabilityFlags::Cap_Position);
+    aState.sensorState.pose.position[0] = m._41;
+    aState.sensorState.pose.position[1] = m._42;
+    aState.sensorState.pose.position[2] = m._43;
+    aState.sensorState.pose.linearVelocity[0] = pose.vVelocity.v[0];
+    aState.sensorState.pose.linearVelocity[1] = pose.vVelocity.v[1];
+    aState.sensorState.pose.linearVelocity[2] = pose.vVelocity.v[2];
+  }
+}
+
+void
+OpenVRSession::EnumerateControllers(VRSystemState& aState)
+{
+  MOZ_ASSERT(mVRSystem);
+
+  MutexAutoLock lock(mControllerHapticStateMutex);
+
+  bool controllerPresent[kVRControllerMaxCount] = { false };
+
+  // Basically, we would have HMDs in the tracked devices,
+  // but we are just interested in the controllers.
+  for (::vr::TrackedDeviceIndex_t trackedDevice = ::vr::k_unTrackedDeviceIndex_Hmd + 1;
+       trackedDevice < ::vr::k_unMaxTrackedDeviceCount; ++trackedDevice) {
+
+    if (!mVRSystem->IsTrackedDeviceConnected(trackedDevice)) {
+      continue;
+    }
+
+    const ::vr::ETrackedDeviceClass deviceType = mVRSystem->
+                                                 GetTrackedDeviceClass(trackedDevice);
+    if (deviceType != ::vr::TrackedDeviceClass_Controller
+        && deviceType != ::vr::TrackedDeviceClass_GenericTracker) {
+      continue;
+    }
+
+    uint32_t stateIndex = 0;
+    uint32_t firstEmptyIndex = kVRControllerMaxCount;
+
+    // Find the existing controller
+    for (stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
+      if (mControllerDeviceIndex[stateIndex] == 0 && firstEmptyIndex == kVRControllerMaxCount) {
+        firstEmptyIndex = stateIndex;
+      }
+      if (mControllerDeviceIndex[stateIndex] == trackedDevice) {
+        break;
+      }
+    }
+    if (stateIndex == kVRControllerMaxCount) {
+      // This is a new controller, let's add it
+      if (firstEmptyIndex == kVRControllerMaxCount) {
+        NS_WARNING("OpenVR - Too many controllers, need to increase kVRControllerMaxCount.");
+        continue;
+      }
+      stateIndex = firstEmptyIndex;
+      mControllerDeviceIndex[stateIndex] = trackedDevice;
+      VRControllerState& controllerState = aState.controllerState[stateIndex];
+      uint32_t numButtons = 0;
+      uint32_t numAxes = 0;
+
+      // Scan the axes that the controllers support
+      for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) {
+        const uint32_t supportAxis = mVRSystem->GetInt32TrackedDeviceProperty(trackedDevice,
+                                      static_cast<vr::TrackedDeviceProperty>(
+                                      ::vr::Prop_Axis0Type_Int32 + j));
+        switch (supportAxis) {
+          case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
+          case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
+            numAxes += 2; // It has x and y axes.
+            ++numButtons;
+            break;
+          case ::vr::k_eControllerAxis_Trigger:
+            if (j <= 2) {
+              ++numButtons;
+            } else {
+          #ifdef DEBUG
+              // SteamVR Knuckles is the only special case for using 2D axis values on triggers.
+              ::vr::ETrackedPropertyError err;
+              uint32_t requiredBufferLen;
+              char charBuf[128];
+              requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(trackedDevice,
+                                  ::vr::Prop_RenderModelName_String, charBuf, 128, &err);
+              MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
+              nsCString deviceId(charBuf);
+              MOZ_ASSERT(deviceId.Find("knuckles") != kNotFound);
+          #endif // #ifdef DEBUG
+              numButtons += 2;
+            }
+            break;
+        }
+      }
+
+      // Scan the buttons that the controllers support
+      const uint64_t supportButtons = mVRSystem->GetUint64TrackedDeviceProperty(
+                                       trackedDevice, ::vr::Prop_SupportedButtons_Uint64);
+      if (supportButtons &
+          BTN_MASK_FROM_ID(k_EButton_A)) {
+        ++numButtons;
+      }
+      if (supportButtons &
+          BTN_MASK_FROM_ID(k_EButton_Grip)) {
+        ++numButtons;
+      }
+      if (supportButtons &
+          BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
+        ++numButtons;
+      }
+      if (supportButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
+        ++numButtons;
+      }
+      if (supportButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Up)) {
+        ++numButtons;
+      }
+      if (supportButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Right)) {
+        ++numButtons;
+      }
+      if (supportButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Down)) {
+        ++numButtons;
+      }
+
+      nsCString deviceId;
+      GetControllerDeviceId(deviceType, trackedDevice, deviceId);
+
+      strncpy(controllerState.controllerName, deviceId.BeginReading(), kVRControllerNameMaxLen);
+      controllerState.numButtons = numButtons;
+      controllerState.numAxes = numAxes;
+      controllerState.numHaptics = kNumOpenVRHaptics;
+
+      // If the Windows MR controller doesn't has the amount
+      // of buttons or axes as our expectation, switching off
+      // the workaround for Windows MR.
+      if (mIsWindowsMR && (numAxes < 4 || numButtons < 5)) {
+        mIsWindowsMR = false;
+        NS_WARNING("OpenVR - Switching off Windows MR mode.");
+      }
+    }
+    controllerPresent[stateIndex] = true;
+  }
+  // Clear out entries for disconnected controllers
+  for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
+    if (!controllerPresent[stateIndex] && mControllerDeviceIndex[stateIndex] != 0) {
+      mControllerDeviceIndex[stateIndex] = 0;
+      memset(&aState.controllerState[stateIndex], 0, sizeof(VRControllerState));
+    }
+  }
+}
+
+void
+OpenVRSession::UpdateControllerButtons(VRSystemState& aState)
+{
+  MOZ_ASSERT(mVRSystem);
+
+  // Compared to Edge, we have a wrong implementation for the vertical axis value.
+  // In order to not affect the current VR content, we add a workaround for yAxis.
+  const float yAxisInvert = (mIsWindowsMR) ? -1.0f : 1.0f;
+  const float triggerThreshold = gfxPrefs::VRControllerTriggerThreshold();
+
+  for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
+    ::vr::TrackedDeviceIndex_t trackedDevice = mControllerDeviceIndex[stateIndex];
+    if (trackedDevice == 0) {
+      continue;
+    }
+    VRControllerState& controllerState = aState.controllerState[stateIndex];
+    const ::vr::ETrackedControllerRole role = mVRSystem->
+                                          GetControllerRoleForTrackedDeviceIndex(
+                                          trackedDevice);
+    dom::GamepadHand hand = GetControllerHandFromControllerRole(role);
+    controllerState.hand = hand;
+
+    ::vr::VRControllerState_t vrControllerState;
+    if (mVRSystem->GetControllerState(trackedDevice, &vrControllerState, sizeof(vrControllerState))) {
+      uint32_t axisIdx = 0;
+      uint32_t buttonIdx = 0;
+      for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) {
+        const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty(
+                                   trackedDevice,
+                                   static_cast<::vr::TrackedDeviceProperty>(
+                                   ::vr::Prop_Axis0Type_Int32 + j));
+        switch (axisType) {
+          case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
+          case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
+          {
+            if (mIsWindowsMR) {
+              // Adjust the input mapping for Windows MR which has
+              // different order.
+              axisIdx = (axisIdx == 0) ? 2 : 0;
+              buttonIdx = (buttonIdx == 0) ? 4 : 0;
+            }
+
+            controllerState.axisValue[axisIdx] = vrControllerState.rAxis[j].x;
+            ++axisIdx;
+            controllerState.axisValue[axisIdx] = vrControllerState.rAxis[j].y * yAxisInvert;
+            ++axisIdx;
+            uint64_t buttonMask = ::vr::ButtonMaskFromId(
+                                 static_cast<::vr::EVRButtonId>(::vr::k_EButton_Axis0 + j));
+
+            UpdateButton(controllerState, vrControllerState, buttonIdx, buttonMask);
+            ++buttonIdx;
+
+            if (mIsWindowsMR) {
+              axisIdx = (axisIdx == 4) ? 2 : 4;
+              buttonIdx = (buttonIdx == 5) ? 1 : 2;
+            }
+            break;
+          }
+          case vr::EVRControllerAxisType::k_eControllerAxis_Trigger:
+          {
+            if (j <= 2) {
+              UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].x, triggerThreshold);
+              ++buttonIdx;
+            } else {
+              // For SteamVR Knuckles.
+              UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].x, triggerThreshold);
+              ++buttonIdx;
+              UpdateTrigger(controllerState, buttonIdx, vrControllerState.rAxis[j].y, triggerThreshold);
+              ++buttonIdx;
+            }
+            break;
+          }
+        }
+      }
+
+      const uint64_t supportedButtons = mVRSystem->GetUint64TrackedDeviceProperty(
+                                         trackedDevice, ::vr::Prop_SupportedButtons_Uint64);
+      if (supportedButtons &
+          BTN_MASK_FROM_ID(k_EButton_A)) {
+        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_A));
+        ++buttonIdx;
+      }
+      if (supportedButtons &
+          BTN_MASK_FROM_ID(k_EButton_Grip)) {
+        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_Grip));
+        ++buttonIdx;
+      }
+      if (supportedButtons &
+          BTN_MASK_FROM_ID(k_EButton_ApplicationMenu)) {
+        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_ApplicationMenu));
+        ++buttonIdx;
+      }
+      if (mIsWindowsMR) {
+        // button 4 in Windows MR has already been assigned
+        // to k_eControllerAxis_TrackPad.
+        ++buttonIdx;
+      }
+      if (supportedButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Left)) {
+        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Left));
+        ++buttonIdx;
+      }
+      if (supportedButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Up)) {
+        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Up));
+        ++buttonIdx;
+      }
+      if (supportedButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Right)) {
+        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Right));
+        ++buttonIdx;
+      }
+      if (supportedButtons &
+          BTN_MASK_FROM_ID(k_EButton_DPad_Down)) {
+        UpdateButton(controllerState, vrControllerState, buttonIdx, BTN_MASK_FROM_ID(k_EButton_DPad_Down));
+        ++buttonIdx;
+      }
+    }
+  }
+}
+
+void
+OpenVRSession::UpdateControllerPoses(VRSystemState& aState)
+{
+  MOZ_ASSERT(mVRSystem);
+
+  ::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount];
+  mVRSystem->GetDeviceToAbsoluteTrackingPose(::vr::TrackingUniverseSeated, 0.0f,
+                                             poses, ::vr::k_unMaxTrackedDeviceCount);
+
+  for (uint32_t stateIndex = 0; stateIndex < kVRControllerMaxCount; stateIndex++) {
+    ::vr::TrackedDeviceIndex_t trackedDevice = mControllerDeviceIndex[stateIndex];
+    if (trackedDevice == 0) {
+      continue;
+    }
+    VRControllerState& controllerState = aState.controllerState[stateIndex];
+    const ::vr::TrackedDevicePose_t& pose = poses[trackedDevice];
+
+    if (pose.bDeviceIsConnected) {
+      controllerState.flags = (dom::GamepadCapabilityFlags::Cap_Orientation |
+                               dom::GamepadCapabilityFlags::Cap_Position);
+    } else {
+      controllerState.flags =  dom::GamepadCapabilityFlags::Cap_None;
+    }
+    if (pose.bPoseIsValid &&
+        pose.eTrackingResult == ::vr::TrackingResult_Running_OK) {
+      gfx::Matrix4x4 m;
+
+      // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4.  But
+      // because of its arrangement, we can copy the 12 elements in and
+      // then transpose them to the right place.  We do this so we can
+      // pull out a Quaternion.
+      memcpy(&m.components, &pose.mDeviceToAbsoluteTracking, sizeof(pose.mDeviceToAbsoluteTracking));
+      m.Transpose();
+
+      gfx::Quaternion rot;
+      rot.SetFromRotationMatrix(m);
+      rot.Invert();
+
+      controllerState.pose.orientation[0] = rot.x;
+      controllerState.pose.orientation[1] = rot.y;
+      controllerState.pose.orientation[2] = rot.z;
+      controllerState.pose.orientation[3] = rot.w;
+      controllerState.pose.angularVelocity[0] = pose.vAngularVelocity.v[0];
+      controllerState.pose.angularVelocity[1] = pose.vAngularVelocity.v[1];
+      controllerState.pose.angularVelocity[2] = pose.vAngularVelocity.v[2];
+      controllerState.pose.angularAcceleration[0] = 0.0f;
+      controllerState.pose.angularAcceleration[1] = 0.0f;
+      controllerState.pose.angularAcceleration[2] = 0.0f;
+      controllerState.isOrientationValid = true;
+
+      controllerState.pose.position[0] = m._41;
+      controllerState.pose.position[1] = m._42;
+      controllerState.pose.position[2] = m._43;
+      controllerState.pose.linearVelocity[0] = pose.vVelocity.v[0];
+      controllerState.pose.linearVelocity[1] = pose.vVelocity.v[1];
+      controllerState.pose.linearVelocity[2] = pose.vVelocity.v[2];
+      controllerState.pose.linearAcceleration[0] = 0.0f;
+      controllerState.pose.linearAcceleration[1] = 0.0f;
+      controllerState.pose.linearAcceleration[2] = 0.0f;
+      controllerState.isPositionValid = true;
+    } else {
+      controllerState.isOrientationValid = false;
+      controllerState.isPositionValid = false;
+    }
+  }
+}
+
+void
+OpenVRSession::GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType,
+                                     ::vr::TrackedDeviceIndex_t aDeviceIndex,
+                                     nsCString& aId)
+{
+  switch (aDeviceType) {
+    case ::vr::TrackedDeviceClass_Controller:
+    {
+      ::vr::ETrackedPropertyError err;
+      uint32_t requiredBufferLen;
+      bool isFound = false;
+      char charBuf[128];
+      requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex,
+                          ::vr::Prop_RenderModelName_String, charBuf, 128, &err);
+      if (requiredBufferLen > 128) {
+        MOZ_CRASH("Larger than the buffer size.");
+      }
+      MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
+      nsCString deviceId(charBuf);
+      if (deviceId.Find("knuckles") != kNotFound) {
+        aId.AssignLiteral("OpenVR Knuckles");
+        isFound = true;
+      }
+      requiredBufferLen = mVRSystem->GetStringTrackedDeviceProperty(aDeviceIndex,
+        ::vr::Prop_SerialNumber_String, charBuf, 128, &err);
+      if (requiredBufferLen > 128) {
+        MOZ_CRASH("Larger than the buffer size.");
+      }
+      MOZ_ASSERT(requiredBufferLen && err == ::vr::TrackedProp_Success);
+      deviceId.Assign(charBuf);
+      if (deviceId.Find("MRSOURCE") != kNotFound) {
+        aId.AssignLiteral("Spatial Controller (Spatial Interaction Source) ");
+        mIsWindowsMR = true;
+        isFound = true;
+      }
+      if (!isFound) {
+        aId.AssignLiteral("OpenVR Gamepad");
+      }
+      break;
+    }
+    case ::vr::TrackedDeviceClass_GenericTracker:
+    {
+      aId.AssignLiteral("OpenVR Tracker");
+      break;
+    }
+    default:
+      MOZ_ASSERT(false);
+      break;
+  }
+}
+
+void
+OpenVRSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState)
+{
+  UpdateHeadsetPose(aSystemState);
+  UpdateEyeParameters(aSystemState);
+  EnumerateControllers(aSystemState);
+  UpdateControllerButtons(aSystemState);
+  UpdateControllerPoses(aSystemState);
+  UpdateTelemetry(aSystemState);
+}
+
+void
+OpenVRSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState)
+{
+  bool isHmdPresent = ::vr::VR_IsHmdPresent();
+  if (!isHmdPresent) {
+    mShouldQuit = true;
+  }
+
+  ::vr::VREvent_t event;
+  while (mVRSystem && mVRSystem->PollNextEvent(&event, sizeof(event))) {
+    switch (event.eventType) {
+      case ::vr::VREvent_TrackedDeviceUserInteractionStarted:
+        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
+          aSystemState.displayState.mIsMounted = true;
+        }
+        break;
+      case ::vr::VREvent_TrackedDeviceUserInteractionEnded:
+        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
+          aSystemState.displayState.mIsMounted = false;
+        }
+        break;
+      case ::vr::EVREventType::VREvent_TrackedDeviceActivated:
+        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
+          aSystemState.displayState.mIsConnected = true;
+        }
+        break;
+      case ::vr::EVREventType::VREvent_TrackedDeviceDeactivated:
+        if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
+          aSystemState.displayState.mIsConnected = false;
+        }
+        break;
+      case ::vr::EVREventType::VREvent_DriverRequestedQuit:
+      case ::vr::EVREventType::VREvent_Quit:
+      case ::vr::EVREventType::VREvent_ProcessQuit:
+      case ::vr::EVREventType::VREvent_QuitAcknowledged:
+      case ::vr::EVREventType::VREvent_QuitAborted_UserPrompt:
+        mShouldQuit = true;
+        break;
+      default:
+        // ignore
+        break;
+    }
+  }
+}
+
+#if defined(XP_WIN)
+bool
+OpenVRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                           ID3D11Texture2D* aTexture)
+{
+  return SubmitFrame((void *)aTexture,
+                     ::vr::ETextureType::TextureType_DirectX,
+                     aLayer.mLeftEyeRect, aLayer.mRightEyeRect);
+}
+#elif defined(XP_MACOSX)
+bool
+OpenVRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                           const VRLayerTextureHandle& aTexture)
+{
+  return SubmitFrame(aTexture,
+                     ::vr::ETextureType::TextureType_IOSurface,
+                     aLayer.mLeftEyeRect, aLayer.mRightEyeRect);
+}
+#endif
+
+bool
+OpenVRSession::SubmitFrame(const VRLayerTextureHandle& aTextureHandle,
+                           ::vr::ETextureType aTextureType,
+                           const VRLayerEyeRect& aLeftEyeRect,
+                           const VRLayerEyeRect& aRightEyeRect)
+{
+  ::vr::Texture_t tex;
+#if defined(XP_MACOSX)
+  // We get aTextureHandle from get_SurfaceDescriptorMacIOSurface() at VRDisplayExternal.
+  // scaleFactor and opaque are skipped because they always are 1.0 and false.
+  RefPtr<MacIOSurface> surf = MacIOSurface::LookupSurface(aTextureHandle);
+  if (!surf) {
+    NS_WARNING("OpenVRSession::SubmitFrame failed to get a MacIOSurface");
+    return false;
+  }
+
+  const void* ioSurface = surf->GetIOSurfacePtr();
+  tex.handle = (void *)ioSurface;
+#else
+  tex.handle = aTextureHandle;
+#endif
+  tex.eType = aTextureType;
+  tex.eColorSpace = ::vr::EColorSpace::ColorSpace_Auto;
+
+  ::vr::VRTextureBounds_t bounds;
+  bounds.uMin = aLeftEyeRect.x;
+  bounds.vMin = 1.0 - aLeftEyeRect.y;
+  bounds.uMax = aLeftEyeRect.x + aLeftEyeRect.width;
+  bounds.vMax = 1.0 - (aLeftEyeRect.y + aLeftEyeRect.height);
+
+  ::vr::EVRCompositorError err;
+  err = mVRCompositor->Submit(::vr::EVREye::Eye_Left, &tex, &bounds);
+  if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
+    printf_stderr("OpenVR Compositor Submit() failed.\n");
+  }
+
+  bounds.uMin = aRightEyeRect.x;
+  bounds.vMin = 1.0 - aRightEyeRect.y;
+  bounds.uMax = aRightEyeRect.x + aRightEyeRect.width;
+  bounds.vMax = 1.0 - (aRightEyeRect.y + aRightEyeRect.height);
+
+  err = mVRCompositor->Submit(::vr::EVREye::Eye_Right, &tex, &bounds);
+  if (err != ::vr::EVRCompositorError::VRCompositorError_None) {
+    printf_stderr("OpenVR Compositor Submit() failed.\n");
+  }
+
+  mVRCompositor->PostPresentHandoff();
+  return true;
+}
+
+void
+OpenVRSession::StopPresentation()
+{
+  mVRCompositor->ClearLastSubmittedFrame();
+
+  ::vr::Compositor_CumulativeStats stats;
+  mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
+}
+
+bool
+OpenVRSession::StartPresentation()
+{
+  return true;
+}
+
+void
+OpenVRSession::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
+                             float aIntensity, float aDuration)
+{
+  MutexAutoLock lock(mControllerHapticStateMutex);
+  if (aHapticIndex >= kNumOpenVRHaptics ||
+      aControllerIdx >= kVRControllerMaxCount) {
+    return;
+  }
+
+  ::vr::TrackedDeviceIndex_t deviceIndex = mControllerDeviceIndex[aControllerIdx];
+  if (deviceIndex == 0) {
+    return;
+  }
+
+  mHapticPulseRemaining[aControllerIdx][aHapticIndex] = aDuration;
+  mHapticPulseIntensity[aControllerIdx][aHapticIndex] = aIntensity;
+
+  /**
+   *  TODO - The haptic feedback pulses will have latency of one frame and we
+   *         are simulating intensity with pulse-width modulation.
+   *         We should use of the OpenVR Input API to correct this
+   *         and replace the TriggerHapticPulse calls which have been
+   *         deprecated.
+   */
+}
+
+void
+OpenVRSession::StartHapticThread()
+{
+  if (!mHapticThread) {
+    mHapticThread = new VRThread(NS_LITERAL_CSTRING("VR_OpenVR_Haptics"));
+  }
+  mHapticThread->Start();
+}
+
+void
+OpenVRSession::StopHapticThread()
+{
+  if (mHapticThread) {
+    mHapticThread->Shutdown();
+    mHapticThread = nullptr;
+  }
+}
+
+void
+OpenVRSession::StartHapticTimer()
+{
+  if (!mHapticTimer && mHapticThread) {
+    mLastHapticUpdate = TimeStamp();
+    mHapticTimer = NS_NewTimer();
+    mHapticTimer->SetTarget(mHapticThread->GetThread()->EventTarget());
+    mHapticTimer->InitWithNamedFuncCallback(
+      HapticTimerCallback,
+      this,
+      kVRHapticUpdateInterval,
+      nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP,
+      "OpenVRSession::HapticTimerCallback");
+  }
+}
+
+void
+OpenVRSession::StopHapticTimer()
+{
+  if (mHapticTimer) {
+    mHapticTimer->Cancel();
+    mHapticTimer = nullptr;
+  }
+}
+
+/*static*/ void
+OpenVRSession::HapticTimerCallback(nsITimer* aTimer, void* aClosure)
+{
+  /**
+   * It is safe to use the pointer passed in aClosure to reference the
+   * OpenVRSession object as the timer is canceled in OpenVRSession::Shutdown,
+   * which is called by the OpenVRSession destructor, guaranteeing
+   * that this function runs if and only if the VRManager object is valid.
+   */
+  OpenVRSession* self = static_cast<OpenVRSession*>(aClosure);
+  self->UpdateHaptics();
+}
+
+void
+OpenVRSession::UpdateHaptics()
+{
+  MOZ_ASSERT(mHapticThread->GetThread() == NS_GetCurrentThread());
+  MOZ_ASSERT(mVRSystem);
+
+  MutexAutoLock lock(mControllerHapticStateMutex);
+
+  TimeStamp now = TimeStamp::Now();
+  if (mLastHapticUpdate.IsNull()) {
+    mLastHapticUpdate = now;
+    return;
+  }
+  float deltaTime = (float)(now - mLastHapticUpdate).ToSeconds();
+  mLastHapticUpdate = now;
+
+  for (int iController = 0; iController < kVRControllerMaxCount; iController++) {
+    for (int iHaptic = 0; iHaptic < kNumOpenVRHaptics; iHaptic++) {
+      ::vr::TrackedDeviceIndex_t deviceIndex = mControllerDeviceIndex[iController];
+      if (deviceIndex == 0) {
+        continue;
+      }
+      float intensity = mHapticPulseIntensity[iController][iHaptic];
+      float duration = mHapticPulseRemaining[iController][iHaptic];
+      if (duration <= 0.0f || intensity <= 0.0f) {
+        continue;
+      }
+      // We expect OpenVR to vibrate for 5 ms, but we found it only response the
+      // commend ~ 3.9 ms. For duration time longer than 3.9 ms, we separate them
+      // to a loop of 3.9 ms for make users feel that is a continuous events.
+      const float microSec = (duration < 0.0039f ? duration : 0.0039f) * 1000000.0f * intensity;
+      mVRSystem->TriggerHapticPulse(deviceIndex, iHaptic, (uint32_t)microSec);
+
+      duration -= deltaTime;
+      if (duration < 0.0f) {
+        duration = 0.0f;
+      }
+      mHapticPulseRemaining[iController][iHaptic] = duration;
+    }
+  }
+}
+
+void
+OpenVRSession::StopVibrateHaptic(uint32_t aControllerIdx)
+{
+  MutexAutoLock lock(mControllerHapticStateMutex);
+  if (aControllerIdx >= kVRControllerMaxCount) {
+    return;
+  }
+  for (int iHaptic = 0; iHaptic < kNumOpenVRHaptics; iHaptic++) {
+    mHapticPulseRemaining[aControllerIdx][iHaptic] = 0.0f;
+  }
+}
+
+void
+OpenVRSession::StopAllHaptics()
+{
+  MutexAutoLock lock(mControllerHapticStateMutex);
+  for (auto& controller : mHapticPulseRemaining) {
+    for (auto& haptic : controller) {
+      haptic = 0.0f;
+    }
+  }
+}
+
+void
+OpenVRSession::UpdateTelemetry(VRSystemState& aSystemState)
+{
+  ::vr::Compositor_CumulativeStats stats;
+  mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
+  aSystemState.displayState.mDroppedFrameCount = stats.m_nNumReprojectedFrames;
+}
+
+} // namespace mozilla
+} // namespace gfx
--- a/gfx/vr/service/OpenVRSession.h
+++ b/gfx/vr/service/OpenVRSession.h
@@ -1,97 +1,97 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_VR_SERVICE_OPENVRSESSION_H
-#define GFX_VR_SERVICE_OPENVRSESSION_H
-
-#include "VRSession.h"
-
-#include "openvr.h"
-#include "mozilla/TimeStamp.h"
-#include "moz_external_vr.h"
-
-#if defined(XP_WIN)
-#include <d3d11_1.h>
-#endif
-class nsITimer;
-
-namespace mozilla {
-namespace gfx {
-class VRThread;
-
-static const int kNumOpenVRHaptics = 1;
-
-class OpenVRSession : public VRSession
-{
-public:
-  OpenVRSession();
-  virtual ~OpenVRSession();
-
-  bool Initialize(mozilla::gfx::VRSystemState& aSystemState) override;
-  void Shutdown() override;
-  void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) override;
-  void StartFrame(mozilla::gfx::VRSystemState& aSystemState) override;
-  bool StartPresentation() override;
-  void StopPresentation() override;
-  void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
-                    float aIntensity, float aDuration) override;
-  void StopVibrateHaptic(uint32_t aControllerIdx) override;
-  void StopAllHaptics() override;
-
-protected:
-#if defined(XP_WIN)
-  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                   ID3D11Texture2D* aTexture) override;
-#elif defined(XP_MACOSX)
-  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                   const VRLayerTextureHandle& aTexture) override;
-#endif
-
-private:
-  // OpenVR State
-  ::vr::IVRSystem* mVRSystem = nullptr;
-  ::vr::IVRChaperone* mVRChaperone = nullptr;
-  ::vr::IVRCompositor* mVRCompositor = nullptr;
-  ::vr::TrackedDeviceIndex_t mControllerDeviceIndex[kVRControllerMaxCount];
-  float mHapticPulseRemaining[kVRControllerMaxCount][kNumOpenVRHaptics];
-  float mHapticPulseIntensity[kVRControllerMaxCount][kNumOpenVRHaptics];
-  bool mIsWindowsMR;
-  TimeStamp mLastHapticUpdate;
-
-  bool InitState(mozilla::gfx::VRSystemState& aSystemState);
-  void UpdateStageParameters(mozilla::gfx::VRDisplayState& aState);
-  void UpdateEyeParameters(mozilla::gfx::VRSystemState& aState);
-  void UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState);
-  void EnumerateControllers(VRSystemState& aState);
-  void UpdateControllerPoses(VRSystemState& aState);
-  void UpdateControllerButtons(VRSystemState& aState);
-  void UpdateTelemetry(VRSystemState& aSystemState);
-
-  bool SubmitFrame(const VRLayerTextureHandle& aTextureHandle,
-                   ::vr::ETextureType aTextureType,
-                   const VRLayerEyeRect& aLeftEyeRect,
-                   const VRLayerEyeRect& aRightEyeRect);
-#if defined(XP_WIN)
-  bool CreateD3DObjects();
-#endif
-  void GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType,
-                             ::vr::TrackedDeviceIndex_t aDeviceIndex,
-                             nsCString& aId);
-  void UpdateHaptics();
-  void StartHapticThread();
-  void StopHapticThread();
-  void StartHapticTimer();
-  void StopHapticTimer();
-  static void HapticTimerCallback(nsITimer* aTimer, void* aClosure);
-  RefPtr<nsITimer> mHapticTimer;
-  RefPtr<VRThread> mHapticThread;
-  mozilla::Mutex mControllerHapticStateMutex;
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-#endif // GFX_VR_SERVICE_OPENVRSESSION_H
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_VR_SERVICE_OPENVRSESSION_H
+#define GFX_VR_SERVICE_OPENVRSESSION_H
+
+#include "VRSession.h"
+
+#include "openvr.h"
+#include "mozilla/TimeStamp.h"
+#include "moz_external_vr.h"
+
+#if defined(XP_WIN)
+#include <d3d11_1.h>
+#endif
+class nsITimer;
+
+namespace mozilla {
+namespace gfx {
+class VRThread;
+
+static const int kNumOpenVRHaptics = 1;
+
+class OpenVRSession : public VRSession
+{
+public:
+  OpenVRSession();
+  virtual ~OpenVRSession();
+
+  bool Initialize(mozilla::gfx::VRSystemState& aSystemState) override;
+  void Shutdown() override;
+  void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) override;
+  void StartFrame(mozilla::gfx::VRSystemState& aSystemState) override;
+  bool StartPresentation() override;
+  void StopPresentation() override;
+  void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
+                    float aIntensity, float aDuration) override;
+  void StopVibrateHaptic(uint32_t aControllerIdx) override;
+  void StopAllHaptics() override;
+
+protected:
+#if defined(XP_WIN)
+  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                   ID3D11Texture2D* aTexture) override;
+#elif defined(XP_MACOSX)
+  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                   const VRLayerTextureHandle& aTexture) override;
+#endif
+
+private:
+  // OpenVR State
+  ::vr::IVRSystem* mVRSystem = nullptr;
+  ::vr::IVRChaperone* mVRChaperone = nullptr;
+  ::vr::IVRCompositor* mVRCompositor = nullptr;
+  ::vr::TrackedDeviceIndex_t mControllerDeviceIndex[kVRControllerMaxCount];
+  float mHapticPulseRemaining[kVRControllerMaxCount][kNumOpenVRHaptics];
+  float mHapticPulseIntensity[kVRControllerMaxCount][kNumOpenVRHaptics];
+  bool mIsWindowsMR;
+  TimeStamp mLastHapticUpdate;
+
+  bool InitState(mozilla::gfx::VRSystemState& aSystemState);
+  void UpdateStageParameters(mozilla::gfx::VRDisplayState& aState);
+  void UpdateEyeParameters(mozilla::gfx::VRSystemState& aState);
+  void UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState);
+  void EnumerateControllers(VRSystemState& aState);
+  void UpdateControllerPoses(VRSystemState& aState);
+  void UpdateControllerButtons(VRSystemState& aState);
+  void UpdateTelemetry(VRSystemState& aSystemState);
+
+  bool SubmitFrame(const VRLayerTextureHandle& aTextureHandle,
+                   ::vr::ETextureType aTextureType,
+                   const VRLayerEyeRect& aLeftEyeRect,
+                   const VRLayerEyeRect& aRightEyeRect);
+#if defined(XP_WIN)
+  bool CreateD3DObjects();
+#endif
+  void GetControllerDeviceId(::vr::ETrackedDeviceClass aDeviceType,
+                             ::vr::TrackedDeviceIndex_t aDeviceIndex,
+                             nsCString& aId);
+  void UpdateHaptics();
+  void StartHapticThread();
+  void StopHapticThread();
+  void StartHapticTimer();
+  void StopHapticTimer();
+  static void HapticTimerCallback(nsITimer* aTimer, void* aClosure);
+  RefPtr<nsITimer> mHapticTimer;
+  RefPtr<VRThread> mHapticThread;
+  mozilla::Mutex mControllerHapticStateMutex;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // GFX_VR_SERVICE_OPENVRSESSION_H
--- a/gfx/vr/service/VRService.cpp
+++ b/gfx/vr/service/VRService.cpp
@@ -1,515 +1,514 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "VRService.h"
-#include "gfxPrefs.h"
-#include "base/thread.h" // for Thread
-#include <cstring>       // for memcmp
-
-#if defined(XP_WIN)
-#include "OculusSession.h"
-#endif
-
-#if defined(XP_WIN) || defined(XP_MACOSX) ||                                   \
-  (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
-#include "OpenVRSession.h"
-#endif
-#if !defined(MOZ_WIDGET_ANDROID)
-#include "OSVRSession.h"
-#endif
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace std;
-
-namespace {
-
-int64_t
-FrameIDFromBrowserState(const mozilla::gfx::VRBrowserState& aState)
-{
-  for (int iLayer = 0; iLayer < kVRLayerMaxCount; iLayer++) {
-    const VRLayerState& layer = aState.layerState[iLayer];
-    if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
-      return layer.layer_stereo_immersive.mFrameId;
-    }
-  }
-  return 0;
-}
-
-bool
-IsImmersiveContentActive(const mozilla::gfx::VRBrowserState& aState)
-{
-  for (int iLayer = 0; iLayer < kVRLayerMaxCount; iLayer++) {
-    const VRLayerState& layer = aState.layerState[iLayer];
-    if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
-      return true;
-    }
-  }
-  return false;
-}
-
-} // anonymous namespace
-
-/*static*/ already_AddRefed<VRService>
-VRService::Create()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!gfxPrefs::VRServiceEnabled()) {
-    return nullptr;
-  }
-
-  RefPtr<VRService> service = new VRService();
-  return service.forget();
-}
-
-VRService::VRService()
-  : mSystemState{}
-  , mBrowserState{}
-  , mBrowserGeneration(0)
-  , mServiceThread(nullptr)
-  , mShutdownRequested(false)
-  , mAPIShmem(nullptr)
-  , mTargetShmemFile(0)
-  , mLastHapticState{}
-  , mFrameStartTime{}
-  , mVRProcessEnabled(gfxPrefs::VRProcessEnabled())
-{
-  // When we have the VR process, we map the memory
-  // of mAPIShmem from GPU process.
-  // If we don't have the VR process, we will instantiate
-  // mAPIShmem in VRService.
-  if (!mVRProcessEnabled) {
-    mAPIShmem = new VRExternalShmem();
-    memset(mAPIShmem, 0, sizeof(VRExternalShmem));
-  }
-}
-
-VRService::~VRService()
-{
-  Stop();
-
-  if (!mVRProcessEnabled && mAPIShmem) {
-    delete mAPIShmem;
-    mAPIShmem = nullptr;
-  }
-}
-
-void
-VRService::Refresh()
-{
-  if (!mAPIShmem) {
-    return;
-  }
-
-  if (mAPIShmem->state.displayState.shutdown) {
-    Stop();
-  }
-}
-
-void
-VRService::Start()
-{
-  if (!mServiceThread) {
-    /**
-     * We must ensure that any time the service is re-started, that
-     * the VRSystemState is reset, including mSystemState.enumerationCompleted
-     * This must happen before VRService::Start returns to the caller, in order
-     * to prevent the WebVR/WebXR promises from being resolved before the
-     * enumeration has been completed.
-     */
-    memset(&mSystemState, 0, sizeof(mSystemState));
-    PushState(mSystemState);
-
-    mServiceThread = new base::Thread("VRService");
-    base::Thread::Options options;
-    /* Timeout values are powers-of-two to enable us get better data.
-       128ms is chosen for transient hangs because 8Hz should be the minimally
-       acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
-    options.transient_hang_timeout = 128; // milliseconds
-    /* 2048ms is chosen for permanent hangs because it's longer than most
-     * Compositor hangs seen in the wild, but is short enough to not miss
-     * getting native hang stacks. */
-    options.permanent_hang_timeout = 2048; // milliseconds
-
-    if (!mServiceThread->StartWithOptions(options)) {
-      delete mServiceThread;
-      mServiceThread = nullptr;
-      return;
-    }
-
-    mServiceThread->message_loop()->PostTask(
-      NewRunnableMethod("gfx::VRService::ServiceInitialize",
-                        this,
-                        &VRService::ServiceInitialize));
-  }
-}
-
-void
-VRService::Stop()
-{
-  if (mServiceThread) {
-    mShutdownRequested = true;
-    delete mServiceThread;
-    mServiceThread = nullptr;
-  }
-  if (mTargetShmemFile) {
-#if defined(XP_WIN)
-    CloseHandle(mTargetShmemFile);
-#endif
-    mTargetShmemFile = 0;
-  }
-  if (mVRProcessEnabled && mAPIShmem) {
-#if defined(XP_WIN)
-    UnmapViewOfFile((void*)mAPIShmem);
-#endif
-    mAPIShmem = nullptr;
-  }
-  mSession = nullptr;
-}
-
-bool
-VRService::InitShmem()
-{
-  if (!mVRProcessEnabled) {
-    return true;
-  }
-
-#if defined(XP_WIN)
-  const char* kShmemName = "moz.gecko.vr_ext.0.0.1";
-  base::ProcessHandle targetHandle = 0;
-
-  // Opening a file-mapping object by name
-  targetHandle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, // read/write access
-                                  FALSE,       // do not inherit the name
-                                  kShmemName); // name of mapping object
-
-  MOZ_ASSERT(GetLastError() == 0);
-
-  LARGE_INTEGER length;
-  length.QuadPart = sizeof(VRExternalShmem);
-  mAPIShmem = (VRExternalShmem*)MapViewOfFile(
-    reinterpret_cast<base::ProcessHandle>(targetHandle), // handle to map object
-    FILE_MAP_ALL_ACCESS, // read/write permission
-    0,
-    0,
-    length.QuadPart);
-  MOZ_ASSERT(GetLastError() == 0);
-  // TODO - Implement logging
-  mTargetShmemFile = targetHandle;
-  if (!mAPIShmem) {
-    MOZ_ASSERT(mAPIShmem);
-    return false;
-  }
-#else
-    // TODO: Implement shmem for other platforms.
-#endif
-
-  return true;
-}
-
-bool
-VRService::IsInServiceThread()
-{
-  return (mServiceThread != nullptr) &&
-         mServiceThread->thread_id() == PlatformThread::CurrentId();
-}
-
-void
-VRService::ServiceInitialize()
-{
-  MOZ_ASSERT(IsInServiceThread());
-
-  if (!InitShmem()) {
-    return;
-  }
-
-  mShutdownRequested = false;
-  memset(&mBrowserState, 0, sizeof(mBrowserState));
-
-  // Try to start a VRSession
-  UniquePtr<VRSession> session;
-
-  // We try Oculus first to ensure we use Oculus
-  // devices trough the most native interface
-  // when possible.
-#if defined(XP_WIN)
-  // Try Oculus
-  session = MakeUnique<OculusSession>();
-  if (!session->Initialize(mSystemState)) {
-    session = nullptr;
-  }
-#endif
-
-#if defined(XP_WIN) || defined(XP_MACOSX) ||                                   \
-  (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
-  // Try OpenVR
-  if (!session) {
-    session = MakeUnique<OpenVRSession>();
-    if (!session->Initialize(mSystemState)) {
-      session = nullptr;
-    }
-  }
-#endif
-#if !defined(MOZ_WIDGET_ANDROID)
-  // Try OSVR
-  if (!session) {
-    session = MakeUnique<OSVRSession>();
-    if (!session->Initialize(mSystemState)) {
-      session = nullptr;
-    }
-  }
-#endif
-
-  if (session) {
-    mSession = std::move(session);
-    // Setting enumerationCompleted to true indicates to the browser
-    // that it should resolve any promises in the WebVR/WebXR API
-    // waiting for hardware detection.
-    mSystemState.enumerationCompleted = true;
-    PushState(mSystemState);
-
-    MessageLoop::current()->PostTask(
-      NewRunnableMethod("gfx::VRService::ServiceWaitForImmersive",
-                        this,
-                        &VRService::ServiceWaitForImmersive));
-  } else {
-    // VR hardware was not detected.
-    // We must inform the browser of the failure so it may try again
-    // later and resolve WebVR promises.  A failure or shutdown is
-    // indicated by enumerationCompleted being set to true, with all
-    // other fields remaining zeroed out.
-    memset(&mSystemState, 0, sizeof(mSystemState));
-    mSystemState.enumerationCompleted = true;
-    mSystemState.displayState.mMinRestartInterval =
-      gfxPrefs::VRExternalNotDetectedTimeout();
-    mSystemState.displayState.shutdown = true;
-    PushState(mSystemState);
-  }
-}
-
-void
-VRService::ServiceShutdown()
-{
-  MOZ_ASSERT(IsInServiceThread());
-
-  // Notify the browser that we have shut down.
-  // This is indicated by enumerationCompleted being set
-  // to true, with all other fields remaining zeroed out.
-  memset(&mSystemState, 0, sizeof(mSystemState));
-  mSystemState.enumerationCompleted = true;
-  mSystemState.displayState.shutdown = true;
-  if (mSession && mSession->ShouldQuit()) {
-    mSystemState.displayState.mMinRestartInterval =
-      gfxPrefs::VRExternalQuitTimeout();
-  }
-  PushState(mSystemState);
-  mSession = nullptr;
-}
-
-void
-VRService::ServiceWaitForImmersive()
-{
-  MOZ_ASSERT(IsInServiceThread());
-  MOZ_ASSERT(mSession);
-
-  mSession->ProcessEvents(mSystemState);
-  PushState(mSystemState);
-  PullState(mBrowserState);
-
-  if (mSession->ShouldQuit() || mShutdownRequested) {
-    // Shut down
-    MessageLoop::current()->PostTask(NewRunnableMethod(
-      "gfx::VRService::ServiceShutdown", this, &VRService::ServiceShutdown));
-  } else if (IsImmersiveContentActive(mBrowserState)) {
-    // Enter Immersive Mode
-    mSession->StartPresentation();
-    mSession->StartFrame(mSystemState);
-    PushState(mSystemState);
-
-    MessageLoop::current()->PostTask(
-      NewRunnableMethod("gfx::VRService::ServiceImmersiveMode",
-                        this,
-                        &VRService::ServiceImmersiveMode));
-  } else {
-    // Continue waiting for immersive mode
-    MessageLoop::current()->PostTask(
-      NewRunnableMethod("gfx::VRService::ServiceWaitForImmersive",
-                        this,
-                        &VRService::ServiceWaitForImmersive));
-  }
-}
-
-void
-VRService::ServiceImmersiveMode()
-{
-  MOZ_ASSERT(IsInServiceThread());
-  MOZ_ASSERT(mSession);
-
-  mSession->ProcessEvents(mSystemState);
-  UpdateHaptics();
-  PushState(mSystemState);
-  PullState(mBrowserState);
-
-  if (mSession->ShouldQuit() || mShutdownRequested) {
-    // Shut down
-    MessageLoop::current()->PostTask(NewRunnableMethod(
-      "gfx::VRService::ServiceShutdown", this, &VRService::ServiceShutdown));
-    return;
-  } else if (!IsImmersiveContentActive(mBrowserState)) {
-    // Exit immersive mode
-    mSession->StopAllHaptics();
-    mSession->StopPresentation();
-    MessageLoop::current()->PostTask(
-      NewRunnableMethod("gfx::VRService::ServiceWaitForImmersive",
-                        this,
-                        &VRService::ServiceWaitForImmersive));
-    return;
-  }
-
-  uint64_t newFrameId = FrameIDFromBrowserState(mBrowserState);
-  if (newFrameId != mSystemState.displayState.mLastSubmittedFrameId) {
-    // A new immersive frame has been received.
-    // Submit the textures to the VR system compositor.
-    bool success = false;
-    for (int iLayer = 0; iLayer < kVRLayerMaxCount; iLayer++) {
-      const VRLayerState& layer = mBrowserState.layerState[iLayer];
-      if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
-        // SubmitFrame may block in order to control the timing for
-        // the next frame start
-        success = mSession->SubmitFrame(layer.layer_stereo_immersive);
-        break;
-      }
-    }
-
-    // Changing mLastSubmittedFrameId triggers a new frame to start
-    // rendering.  Changes to mLastSubmittedFrameId and the values
-    // used for rendering, such as headset pose, must be pushed
-    // atomically to the browser.
-    mSystemState.displayState.mLastSubmittedFrameId = newFrameId;
-    mSystemState.displayState.mLastSubmittedFrameSuccessful = success;
-
-    // StartFrame may block to control the timing for the next frame start
-    mSession->StartFrame(mSystemState);
-    mSystemState.sensorState.inputFrameID++;
-    size_t historyIndex =
-      mSystemState.sensorState.inputFrameID % ArrayLength(mFrameStartTime);
-    mFrameStartTime[historyIndex] = TimeStamp::Now();
-    PushState(mSystemState);
-  }
-
-  // Continue immersive mode
-  MessageLoop::current()->PostTask(
-    NewRunnableMethod("gfx::VRService::ServiceImmersiveMode",
-                      this,
-                      &VRService::ServiceImmersiveMode));
-}
-
-void
-VRService::UpdateHaptics()
-{
-  MOZ_ASSERT(IsInServiceThread());
-  MOZ_ASSERT(mSession);
-
-  for (size_t i = 0; i < ArrayLength(mBrowserState.hapticState); i++) {
-    VRHapticState& state = mBrowserState.hapticState[i];
-    VRHapticState& lastState = mLastHapticState[i];
-    // Note that VRHapticState is asserted to be a POD type, thus memcmp is safe
-    if (memcmp(&state, &lastState, sizeof(VRHapticState)) == 0) {
-      // No change since the last update
-      continue;
-    }
-    if (state.inputFrameID == 0) {
-      // The haptic feedback was stopped
-      mSession->StopVibrateHaptic(state.controllerIndex);
-    } else {
-      TimeStamp now;
-      if (now.IsNull()) {
-        // TimeStamp::Now() is expensive, so we
-        // must call it only when needed and save the
-        // output for further loop iterations.
-        now = TimeStamp::Now();
-      }
-      // This is a new haptic pulse, or we are overriding a prior one
-      size_t historyIndex = state.inputFrameID % ArrayLength(mFrameStartTime);
-      float startOffset =
-        (float)(now - mFrameStartTime[historyIndex]).ToSeconds();
-
-      // state.pulseStart is guaranteed never to be in the future
-      mSession->VibrateHaptic(state.controllerIndex,
-                              state.hapticIndex,
-                              state.pulseIntensity,
-                              state.pulseDuration + state.pulseStart -
-                                startOffset);
-    }
-    // Record the state for comparison in the next run
-    memcpy(&lastState, &state, sizeof(VRHapticState));
-  }
-}
-
-void
-VRService::PushState(const mozilla::gfx::VRSystemState& aState)
-{
-  if (!mAPIShmem) {
-    return;
-  }
-  // Copying the VR service state to the shmem is atomic, infallable,
-  // and non-blocking on x86/x64 architectures.  Arm requires a mutex
-  // that is locked for the duration of the memcpy to and from shmem on
-  // both sides.
-
-#if defined(MOZ_WIDGET_ANDROID)
-  if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) ==
-      0) {
-    memcpy((void*)&mAPIShmem->state, &aState, sizeof(VRSystemState));
-    pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
-  }
-#else
-  mAPIShmem->generationA++;
-  memcpy((void*)&mAPIShmem->state, &aState, sizeof(VRSystemState));
-  mAPIShmem->generationB++;
-#endif
-}
-
-void
-VRService::PullState(mozilla::gfx::VRBrowserState& aState)
-{
-  if (!mAPIShmem) {
-    return;
-  }
-  // Copying the browser state from the shmem is non-blocking
-  // on x86/x64 architectures.  Arm requires a mutex that is
-  // locked for the duration of the memcpy to and from shmem on
-  // both sides.
-  // On x86/x64 It is fallable -- If a dirty copy is detected by
-  // a mismatch of browserGenerationA and browserGenerationB,
-  // the copy is discarded and will not replace the last known
-  // browser state.
-
-#if defined(MOZ_WIDGET_ANDROID)
-  if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) ==
-      0) {
-    memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
-    pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
-  }
-#else
-  VRExternalShmem tmp;
-  if (mAPIShmem->browserGenerationA != mBrowserGeneration) {
-    memcpy(&tmp, mAPIShmem, sizeof(VRExternalShmem));
-    if (tmp.browserGenerationA == tmp.browserGenerationB &&
-        tmp.browserGenerationA != 0 && tmp.browserGenerationA != -1) {
-      memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
-      mBrowserGeneration = tmp.browserGenerationA;
-    }
-  }
-#endif
-}
-
-VRExternalShmem*
-VRService::GetAPIShmem()
-{
-  return mAPIShmem;
-}
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VRService.h"
+#include "gfxPrefs.h"
+#include "base/thread.h" // for Thread
+#include <cstring>       // for memcmp
+
+#if defined(XP_WIN)
+#include "OculusSession.h"
+#endif
+
+#if defined(XP_WIN) || defined(XP_MACOSX) ||                                   \
+  (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
+#include "OpenVRSession.h"
+#endif
+#if !defined(MOZ_WIDGET_ANDROID)
+#include "OSVRSession.h"
+#endif
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace std;
+
+namespace {
+
+int64_t
+FrameIDFromBrowserState(const mozilla::gfx::VRBrowserState& aState)
+{
+  for (const auto& layer : aState.layerState) {
+    if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
+      return layer.layer_stereo_immersive.mFrameId;
+    }
+  }
+  return 0;
+}
+
+bool
+IsImmersiveContentActive(const mozilla::gfx::VRBrowserState& aState)
+{
+  for (const auto& layer : aState.layerState) {
+    if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
+      return true;
+    }
+  }
+  return false;
+}
+
+} // anonymous namespace
+
+/*static*/ already_AddRefed<VRService>
+VRService::Create()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gfxPrefs::VRServiceEnabled()) {
+    return nullptr;
+  }
+
+  RefPtr<VRService> service = new VRService();
+  return service.forget();
+}
+
+VRService::VRService()
+  : mSystemState{}
+  , mBrowserState{}
+  , mBrowserGeneration(0)
+  , mServiceThread(nullptr)
+  , mShutdownRequested(false)
+  , mAPIShmem(nullptr)
+  , mTargetShmemFile(0)
+  , mLastHapticState{}
+  , mFrameStartTime{}
+  , mVRProcessEnabled(gfxPrefs::VRProcessEnabled())
+{
+  // When we have the VR process, we map the memory
+  // of mAPIShmem from GPU process.
+  // If we don't have the VR process, we will instantiate
+  // mAPIShmem in VRService.
+  if (!mVRProcessEnabled) {
+    mAPIShmem = new VRExternalShmem();
+    memset(mAPIShmem, 0, sizeof(VRExternalShmem));
+  }
+}
+
+VRService::~VRService()
+{
+  Stop();
+
+  if (!mVRProcessEnabled && mAPIShmem) {
+    delete mAPIShmem;
+    mAPIShmem = nullptr;
+  }
+}
+
+void
+VRService::Refresh()
+{
+  if (!mAPIShmem) {
+    return;
+  }
+
+  if (mAPIShmem->state.displayState.shutdown) {
+    Stop();
+  }
+}
+
+void
+VRService::Start()
+{
+  if (!mServiceThread) {
+    /**
+     * We must ensure that any time the service is re-started, that
+     * the VRSystemState is reset, including mSystemState.enumerationCompleted
+     * This must happen before VRService::Start returns to the caller, in order
+     * to prevent the WebVR/WebXR promises from being resolved before the
+     * enumeration has been completed.
+     */
+    memset(&mSystemState, 0, sizeof(mSystemState));
+    PushState(mSystemState);
+
+    mServiceThread = new base::Thread("VRService");
+    base::Thread::Options options;
+    /* Timeout values are powers-of-two to enable us get better data.
+       128ms is chosen for transient hangs because 8Hz should be the minimally
+       acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
+    options.transient_hang_timeout = 128; // milliseconds
+    /* 2048ms is chosen for permanent hangs because it's longer than most
+     * Compositor hangs seen in the wild, but is short enough to not miss
+     * getting native hang stacks. */
+    options.permanent_hang_timeout = 2048; // milliseconds
+
+    if (!mServiceThread->StartWithOptions(options)) {
+      delete mServiceThread;
+      mServiceThread = nullptr;
+      return;
+    }
+
+    mServiceThread->message_loop()->PostTask(
+      NewRunnableMethod("gfx::VRService::ServiceInitialize",
+                        this,
+                        &VRService::ServiceInitialize));
+  }
+}
+
+void
+VRService::Stop()
+{
+  if (mServiceThread) {
+    mShutdownRequested = true;
+    delete mServiceThread;
+    mServiceThread = nullptr;
+  }
+  if (mTargetShmemFile) {
+#if defined(XP_WIN)
+    CloseHandle(mTargetShmemFile);
+#endif
+    mTargetShmemFile = 0;
+  }
+  if (mVRProcessEnabled && mAPIShmem) {
+#if defined(XP_WIN)
+    UnmapViewOfFile((void*)mAPIShmem);
+#endif
+    mAPIShmem = nullptr;
+  }
+  mSession = nullptr;
+}
+
+bool
+VRService::InitShmem()
+{
+  if (!mVRProcessEnabled) {
+    return true;
+  }
+
+#if defined(XP_WIN)
+  const char* kShmemName = "moz.gecko.vr_ext.0.0.1";
+  base::ProcessHandle targetHandle = 0;
+
+  // Opening a file-mapping object by name
+  targetHandle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, // read/write access
+                                  FALSE,       // do not inherit the name
+                                  kShmemName); // name of mapping object
+
+  MOZ_ASSERT(GetLastError() == 0);
+
+  LARGE_INTEGER length;
+  length.QuadPart = sizeof(VRExternalShmem);
+  mAPIShmem = (VRExternalShmem*)MapViewOfFile(
+    reinterpret_cast<base::ProcessHandle>(targetHandle), // handle to map object
+    FILE_MAP_ALL_ACCESS, // read/write permission
+    0,
+    0,
+    length.QuadPart);
+  MOZ_ASSERT(GetLastError() == 0);
+  // TODO - Implement logging
+  mTargetShmemFile = targetHandle;
+  if (!mAPIShmem) {
+    MOZ_ASSERT(mAPIShmem);
+    return false;
+  }
+#else
+    // TODO: Implement shmem for other platforms.
+#endif
+
+  return true;
+}
+
+bool
+VRService::IsInServiceThread()
+{
+  return (mServiceThread != nullptr) &&
+         mServiceThread->thread_id() == PlatformThread::CurrentId();
+}
+
+void
+VRService::ServiceInitialize()
+{
+  MOZ_ASSERT(IsInServiceThread());
+
+  if (!InitShmem()) {
+    return;
+  }
+
+  mShutdownRequested = false;
+  memset(&mBrowserState, 0, sizeof(mBrowserState));
+
+  // Try to start a VRSession
+  UniquePtr<VRSession> session;
+
+  // We try Oculus first to ensure we use Oculus
+  // devices trough the most native interface
+  // when possible.
+#if defined(XP_WIN)
+  // Try Oculus
+  session = MakeUnique<OculusSession>();
+  if (!session->Initialize(mSystemState)) {
+    session = nullptr;
+  }
+#endif
+
+#if defined(XP_WIN) || defined(XP_MACOSX) ||                                   \
+  (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID))
+  // Try OpenVR
+  if (!session) {
+    session = MakeUnique<OpenVRSession>();
+    if (!session->Initialize(mSystemState)) {
+      session = nullptr;
+    }
+  }
+#endif
+#if !defined(MOZ_WIDGET_ANDROID)
+  // Try OSVR
+  if (!session) {
+    session = MakeUnique<OSVRSession>();
+    if (!session->Initialize(mSystemState)) {
+      session = nullptr;
+    }
+  }
+#endif
+
+  if (session) {
+    mSession = std::move(session);
+    // Setting enumerationCompleted to true indicates to the browser
+    // that it should resolve any promises in the WebVR/WebXR API
+    // waiting for hardware detection.
+    mSystemState.enumerationCompleted = true;
+    PushState(mSystemState);
+
+    MessageLoop::current()->PostTask(
+      NewRunnableMethod("gfx::VRService::ServiceWaitForImmersive",
+                        this,
+                        &VRService::ServiceWaitForImmersive));
+  } else {
+    // VR hardware was not detected.
+    // We must inform the browser of the failure so it may try again
+    // later and resolve WebVR promises.  A failure or shutdown is
+    // indicated by enumerationCompleted being set to true, with all
+    // other fields remaining zeroed out.
+    memset(&mSystemState, 0, sizeof(mSystemState));
+    mSystemState.enumerationCompleted = true;
+    mSystemState.displayState.mMinRestartInterval =
+      gfxPrefs::VRExternalNotDetectedTimeout();
+    mSystemState.displayState.shutdown = true;
+    PushState(mSystemState);
+  }
+}
+
+void
+VRService::ServiceShutdown()
+{
+  MOZ_ASSERT(IsInServiceThread());
+
+  // Notify the browser that we have shut down.
+  // This is indicated by enumerationCompleted being set
+  // to true, with all other fields remaining zeroed out.
+  memset(&mSystemState, 0, sizeof(mSystemState));
+  mSystemState.enumerationCompleted = true;
+  mSystemState.displayState.shutdown = true;
+  if (mSession && mSession->ShouldQuit()) {
+    mSystemState.displayState.mMinRestartInterval =
+      gfxPrefs::VRExternalQuitTimeout();
+  }
+  PushState(mSystemState);
+  mSession = nullptr;
+}
+
+void
+VRService::ServiceWaitForImmersive()
+{
+  MOZ_ASSERT(IsInServiceThread());
+  MOZ_ASSERT(mSession);
+
+  mSession->ProcessEvents(mSystemState);
+  PushState(mSystemState);
+  PullState(mBrowserState);
+
+  if (mSession->ShouldQuit() || mShutdownRequested) {
+    // Shut down
+    MessageLoop::current()->PostTask(NewRunnableMethod(
+      "gfx::VRService::ServiceShutdown", this, &VRService::ServiceShutdown));
+  } else if (IsImmersiveContentActive(mBrowserState)) {
+    // Enter Immersive Mode
+    mSession->StartPresentation();
+    mSession->StartFrame(mSystemState);
+    PushState(mSystemState);
+
+    MessageLoop::current()->PostTask(
+      NewRunnableMethod("gfx::VRService::ServiceImmersiveMode",
+                        this,
+                        &VRService::ServiceImmersiveMode));
+  } else {
+    // Continue waiting for immersive mode
+    MessageLoop::current()->PostTask(
+      NewRunnableMethod("gfx::VRService::ServiceWaitForImmersive",
+                        this,
+                        &VRService::ServiceWaitForImmersive));
+  }
+}
+
+void
+VRService::ServiceImmersiveMode()
+{
+  MOZ_ASSERT(IsInServiceThread());
+  MOZ_ASSERT(mSession);
+
+  mSession->ProcessEvents(mSystemState);
+  UpdateHaptics();
+  PushState(mSystemState);
+  PullState(mBrowserState);
+
+  if (mSession->ShouldQuit() || mShutdownRequested) {
+    // Shut down
+    MessageLoop::current()->PostTask(NewRunnableMethod(
+      "gfx::VRService::ServiceShutdown", this, &VRService::ServiceShutdown));
+    return;
+  }
+
+  if (!IsImmersiveContentActive(mBrowserState)) {
+    // Exit immersive mode
+    mSession->StopAllHaptics();
+    mSession->StopPresentation();
+    MessageLoop::current()->PostTask(
+      NewRunnableMethod("gfx::VRService::ServiceWaitForImmersive",
+                        this,
+                        &VRService::ServiceWaitForImmersive));
+    return;
+  }
+
+  uint64_t newFrameId = FrameIDFromBrowserState(mBrowserState);
+  if (newFrameId != mSystemState.displayState.mLastSubmittedFrameId) {
+    // A new immersive frame has been received.
+    // Submit the textures to the VR system compositor.
+    bool success = false;
+    for (const auto& layer : mBrowserState.layerState) {
+      if (layer.type == VRLayerType::LayerType_Stereo_Immersive) {
+        // SubmitFrame may block in order to control the timing for
+        // the next frame start
+        success = mSession->SubmitFrame(layer.layer_stereo_immersive);
+        break;
+      }
+    }
+
+    // Changing mLastSubmittedFrameId triggers a new frame to start
+    // rendering.  Changes to mLastSubmittedFrameId and the values
+    // used for rendering, such as headset pose, must be pushed
+    // atomically to the browser.
+    mSystemState.displayState.mLastSubmittedFrameId = newFrameId;
+    mSystemState.displayState.mLastSubmittedFrameSuccessful = success;
+
+    // StartFrame may block to control the timing for the next frame start
+    mSession->StartFrame(mSystemState);
+    mSystemState.sensorState.inputFrameID++;
+    size_t historyIndex =
+      mSystemState.sensorState.inputFrameID % ArrayLength(mFrameStartTime);
+    mFrameStartTime[historyIndex] = TimeStamp::Now();
+    PushState(mSystemState);
+  }
+
+  // Continue immersive mode
+  MessageLoop::current()->PostTask(
+    NewRunnableMethod("gfx::VRService::ServiceImmersiveMode",
+                      this,
+                      &VRService::ServiceImmersiveMode));
+}
+
+void
+VRService::UpdateHaptics()
+{
+  MOZ_ASSERT(IsInServiceThread());
+  MOZ_ASSERT(mSession);
+
+  for (size_t i = 0; i < ArrayLength(mBrowserState.hapticState); i++) {
+    VRHapticState& state = mBrowserState.hapticState[i];
+    VRHapticState& lastState = mLastHapticState[i];
+    // Note that VRHapticState is asserted to be a POD type, thus memcmp is safe
+    if (memcmp(&state, &lastState, sizeof(VRHapticState)) == 0) {
+      // No change since the last update
+      continue;
+    }
+    if (state.inputFrameID == 0) {
+      // The haptic feedback was stopped
+      mSession->StopVibrateHaptic(state.controllerIndex);
+    } else {
+      TimeStamp now;
+      if (now.IsNull()) {
+        // TimeStamp::Now() is expensive, so we
+        // must call it only when needed and save the
+        // output for further loop iterations.
+        now = TimeStamp::Now();
+      }
+      // This is a new haptic pulse, or we are overriding a prior one
+      size_t historyIndex = state.inputFrameID % ArrayLength(mFrameStartTime);
+      float startOffset =
+        (float)(now - mFrameStartTime[historyIndex]).ToSeconds();
+
+      // state.pulseStart is guaranteed never to be in the future
+      mSession->VibrateHaptic(state.controllerIndex,
+                              state.hapticIndex,
+                              state.pulseIntensity,
+                              state.pulseDuration + state.pulseStart -
+                                startOffset);
+    }
+    // Record the state for comparison in the next run
+    memcpy(&lastState, &state, sizeof(VRHapticState));
+  }
+}
+
+void
+VRService::PushState(const mozilla::gfx::VRSystemState& aState)
+{
+  if (!mAPIShmem) {
+    return;
+  }
+  // Copying the VR service state to the shmem is atomic, infallable,
+  // and non-blocking on x86/x64 architectures.  Arm requires a mutex
+  // that is locked for the duration of the memcpy to and from shmem on
+  // both sides.
+
+#if defined(MOZ_WIDGET_ANDROID)
+  if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) ==
+      0) {
+    memcpy((void*)&mAPIShmem->state, &aState, sizeof(VRSystemState));
+    pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
+  }
+#else
+  mAPIShmem->generationA++;
+  memcpy((void*)&mAPIShmem->state, &aState, sizeof(VRSystemState));
+  mAPIShmem->generationB++;
+#endif
+}
+
+void
+VRService::PullState(mozilla::gfx::VRBrowserState& aState)
+{
+  if (!mAPIShmem) {
+    return;
+  }
+  // Copying the browser state from the shmem is non-blocking
+  // on x86/x64 architectures.  Arm requires a mutex that is
+  // locked for the duration of the memcpy to and from shmem on
+  // both sides.
+  // On x86/x64 It is fallable -- If a dirty copy is detected by
+  // a mismatch of browserGenerationA and browserGenerationB,
+  // the copy is discarded and will not replace the last known
+  // browser state.
+
+#if defined(MOZ_WIDGET_ANDROID)
+  if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->browserMutex)) ==
+      0) {
+    memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
+    pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->browserMutex));
+  }
+#else
+  VRExternalShmem tmp;
+  if (mAPIShmem->browserGenerationA != mBrowserGeneration) {
+    memcpy(&tmp, mAPIShmem, sizeof(VRExternalShmem));
+    if (tmp.browserGenerationA == tmp.browserGenerationB &&
+        tmp.browserGenerationA != 0 && tmp.browserGenerationA != -1) {
+      memcpy(&aState, &tmp.browserState, sizeof(VRBrowserState));
+      mBrowserGeneration = tmp.browserGenerationA;
+    }
+  }
+#endif
+}
+
+VRExternalShmem*
+VRService::GetAPIShmem()
+{
+  return mAPIShmem;
+}
--- a/gfx/vr/service/VRService.h
+++ b/gfx/vr/service/VRService.h
@@ -1,92 +1,92 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_VR_SERVICE_VRSERVICE_H
-#define GFX_VR_SERVICE_VRSERVICE_H
-
-#include "mozilla/Atomics.h"
-#include "moz_external_vr.h"
-#include "base/process.h" // for base::ProcessHandle
-
-namespace base {
-class Thread;
-} // namespace base
-namespace mozilla {
-namespace gfx {
-
-class VRSession;
-
-static const int kVRFrameTimingHistoryDepth = 100;
-
-class VRService
-{
-public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRService)
-  static already_AddRefed<VRService> Create();
-
-  void Refresh();
-  void Start();
-  void Stop();
-  VRExternalShmem* GetAPIShmem();
-
-private:
-  VRService();
-  ~VRService();
-  
-  bool InitShmem();
-  void PushState(const mozilla::gfx::VRSystemState& aState);
-  void PullState(mozilla::gfx::VRBrowserState& aState);
-
-  /**
-   * VRSystemState contains the most recent state of the VR
-   * system, to be shared with the browser by Shmem.
-   * mSystemState is the VR Service copy of this data, which
-   * is memcpy'ed atomically to the Shmem.
-   * VRSystemState is written by the VR Service, but read-only
-   * by the browser.
-   */
-  VRSystemState mSystemState;
-  /**
-   * VRBrowserState contains the most recent state of the browser.
-   * mBrowserState is memcpy'ed from the Shmem atomically
-   */
-  VRBrowserState mBrowserState;
-  int64_t mBrowserGeneration;
-
-  UniquePtr<VRSession> mSession;
-  base::Thread* mServiceThread;
-  bool mShutdownRequested;
-
-  VRExternalShmem* MOZ_OWNING_REF mAPIShmem;
-  base::ProcessHandle mTargetShmemFile;
-  VRHapticState mLastHapticState[kVRHapticsMaxCount];
-  TimeStamp mFrameStartTime[kVRFrameTimingHistoryDepth];
-  // We store the value of gfxPrefs::VRProcessEnabled() in mVRProcessEnabled.
-  // This allows us to read the value in the VRService destructor, after
-  // gfxPrefs has been shut down.  We should investigate why gfxPrefs
-  // is shutting down earlier - See bug xxx
-  bool mVRProcessEnabled;
-
-  bool IsInServiceThread();
-  void UpdateHaptics();
-
-  /**
-   * The VR Service thread is a state machine that always has one
-   * task queued depending on the state.
-   *
-   * VR Service thread state task functions:
-   */
-  void ServiceInitialize();
-  void ServiceShutdown();
-  void ServiceWaitForImmersive();
-  void ServiceImmersiveMode();
-
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-#endif // GFX_VR_SERVICE_VRSERVICE_H
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_VR_SERVICE_VRSERVICE_H
+#define GFX_VR_SERVICE_VRSERVICE_H
+
+#include "mozilla/Atomics.h"
+#include "moz_external_vr.h"
+#include "base/process.h" // for base::ProcessHandle
+
+namespace base {
+class Thread;
+} // namespace base
+namespace mozilla {
+namespace gfx {
+
+class VRSession;
+
+static const int kVRFrameTimingHistoryDepth = 100;
+
+class VRService
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRService)
+  static already_AddRefed<VRService> Create();
+
+  void Refresh();
+  void Start();
+  void Stop();
+  VRExternalShmem* GetAPIShmem();
+
+private:
+  VRService();
+  ~VRService();
+  
+  bool InitShmem();
+  void PushState(const mozilla::gfx::VRSystemState& aState);
+  void PullState(mozilla::gfx::VRBrowserState& aState);
+
+  /**
+   * VRSystemState contains the most recent state of the VR
+   * system, to be shared with the browser by Shmem.
+   * mSystemState is the VR Service copy of this data, which
+   * is memcpy'ed atomically to the Shmem.
+   * VRSystemState is written by the VR Service, but read-only
+   * by the browser.
+   */
+  VRSystemState mSystemState;
+  /**
+   * VRBrowserState contains the most recent state of the browser.
+   * mBrowserState is memcpy'ed from the Shmem atomically
+   */
+  VRBrowserState mBrowserState;
+  int64_t mBrowserGeneration;
+
+  UniquePtr<VRSession> mSession;
+  base::Thread* mServiceThread;
+  bool mShutdownRequested;
+
+  VRExternalShmem* MOZ_OWNING_REF mAPIShmem;
+  base::ProcessHandle mTargetShmemFile;
+  VRHapticState mLastHapticState[kVRHapticsMaxCount];
+  TimeStamp mFrameStartTime[kVRFrameTimingHistoryDepth];
+  // We store the value of gfxPrefs::VRProcessEnabled() in mVRProcessEnabled.
+  // This allows us to read the value in the VRService destructor, after
+  // gfxPrefs has been shut down.  We should investigate why gfxPrefs
+  // is shutting down earlier - See bug xxx
+  bool mVRProcessEnabled;
+
+  bool IsInServiceThread();
+  void UpdateHaptics();
+
+  /**
+   * The VR Service thread is a state machine that always has one
+   * task queued depending on the state.
+   *
+   * VR Service thread state task functions:
+   */
+  void ServiceInitialize();
+  void ServiceShutdown();
+  void ServiceWaitForImmersive();
+  void ServiceImmersiveMode();
+
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // GFX_VR_SERVICE_VRSERVICE_H
--- a/gfx/vr/service/VRSession.cpp
+++ b/gfx/vr/service/VRSession.cpp
@@ -1,160 +1,155 @@
-#include "VRSession.h"
-
-#include "moz_external_vr.h"
-
-#if defined(XP_WIN)
-#include <d3d11.h>
-#endif // defined(XP_WIN)
-
-using namespace mozilla::gfx;
-
-VRSession::VRSession()
-  : mShouldQuit(false)
-{
-
-}
-
-VRSession::~VRSession()
-{
-
-}
-
-#if defined(XP_WIN)
-bool
-VRSession::CreateD3DContext(RefPtr<ID3D11Device> aDevice)
-{
-  if (!mDevice) {
-    if (!aDevice) {
-      NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device");
-      return false;
-    }
-    if (FAILED(aDevice->QueryInterface(__uuidof(ID3D11Device1), getter_AddRefs(mDevice)))) {
-      NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device1");
-      return false;
-    }
-  }
-  if (!mContext) {
-    mDevice->GetImmediateContext1(getter_AddRefs(mContext));
-    if (!mContext) {
-      NS_WARNING("VRSession::CreateD3DObjects failed to get an immediate context");
-      return false;
-    }
-  }
-  if (!mDeviceContextState) {
-    D3D_FEATURE_LEVEL featureLevels[] {
-      D3D_FEATURE_LEVEL_11_1,
-      D3D_FEATURE_LEVEL_11_0
-    };
-    mDevice->CreateDeviceContextState(0,
-                                      featureLevels,
-                                      2,
-                                      D3D11_SDK_VERSION,
-                                      __uuidof(ID3D11Device1),
-                                      nullptr,
-                                      getter_AddRefs(mDeviceContextState));
-  }
-  if (!mDeviceContextState) {
-    NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11DeviceContextState");
-    return false;
-  }
-  return true;
-}
-
-ID3D11Device1*
-VRSession::GetD3DDevice()
-{
-  return mDevice;
-}
-
-ID3D11DeviceContext1*
-VRSession::GetD3DDeviceContext()
-{
-  return mContext;
-}
-
-ID3DDeviceContextState*
-VRSession::GetD3DDeviceContextState()
-{
-  return mDeviceContextState;
-}
-
-#endif // defined(XP_WIN)
-
-bool
-VRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer)
-{
-#if defined(XP_WIN)
-
-  if (aLayer.mTextureType == VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor) {
-      RefPtr<ID3D11Texture2D> dxTexture;
-      HRESULT hr = mDevice->OpenSharedResource((HANDLE)aLayer.mTextureHandle,
-        __uuidof(ID3D11Texture2D),
-        (void**)(ID3D11Texture2D**)getter_AddRefs(dxTexture));
-      if (FAILED(hr) || !dxTexture) {
-        NS_WARNING("Failed to open shared texture");
-        return false;
-      }
-
-      // Similar to LockD3DTexture in TextureD3D11.cpp
-      RefPtr<IDXGIKeyedMutex> mutex;
-      dxTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
-      if (mutex) {
-        HRESULT hr = mutex->AcquireSync(0, 1000);
-        if (hr == WAIT_TIMEOUT) {
-          gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout";
-        }
-        else if (hr == WAIT_ABANDONED) {
-          gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
-        }
-        if (FAILED(hr)) {
-          NS_WARNING("Failed to lock the texture");
-          return false;
-        }
-      }
-      bool success = SubmitFrame(aLayer, dxTexture);
-      if (mutex) {
-        HRESULT hr = mutex->ReleaseSync(0);
-        if (FAILED(hr)) {
-          NS_WARNING("Failed to unlock the texture");
-        }
-      }
-      if (!success) {
-        return false;
-      }
-      return true;
-  }
-
-#elif defined(XP_MACOSX)
-
-  if (aLayer.mTextureType == VRLayerTextureType::LayerTextureType_MacIOSurface) {
-    return SubmitFrame(aLayer, aLayer.mTextureHandle);
-  }
-
-#endif
-
-  return false;
-}
-
-void
-VRSession::UpdateTrigger(VRControllerState& aState, uint32_t aButtonIndex, float aValue, float aThreshold)
-{
-  // For OpenVR, the threshold value of ButtonPressed and ButtonTouched is 0.55.
-  // We prefer to let developers to set their own threshold for the adjustment.
-  // Therefore, we don't check ButtonPressed and ButtonTouched with ButtonMask here.
-  // we just check the button value is larger than the threshold value or not.
-  uint64_t mask = (1ULL << aButtonIndex);
-  aState.triggerValue[aButtonIndex] = aValue;
-  if (aValue > aThreshold) {
-    aState.buttonPressed |= mask;
-    aState.buttonTouched |= mask;
-  } else {
-    aState.buttonPressed &= ~mask;
-    aState.buttonTouched &= ~mask;
-  }
-}
-
-bool
-VRSession::ShouldQuit() const
-{
-  return mShouldQuit;
-}
+#include "VRSession.h"
+
+#include "moz_external_vr.h"
+
+#if defined(XP_WIN)
+#include <d3d11.h>
+#endif // defined(XP_WIN)
+
+using namespace mozilla::gfx;
+
+VRSession::VRSession()
+  : mShouldQuit(false)
+{
+
+}
+
+#if defined(XP_WIN)
+bool
+VRSession::CreateD3DContext(RefPtr<ID3D11Device> aDevice)
+{
+  if (!mDevice) {
+    if (!aDevice) {
+      NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device");
+      return false;
+    }
+    if (FAILED(aDevice->QueryInterface(__uuidof(ID3D11Device1), getter_AddRefs(mDevice)))) {
+      NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11Device1");
+      return false;
+    }
+  }
+  if (!mContext) {
+    mDevice->GetImmediateContext1(getter_AddRefs(mContext));
+    if (!mContext) {
+      NS_WARNING("VRSession::CreateD3DObjects failed to get an immediate context");
+      return false;
+    }
+  }
+  if (!mDeviceContextState) {
+    D3D_FEATURE_LEVEL featureLevels[] {
+      D3D_FEATURE_LEVEL_11_1,
+      D3D_FEATURE_LEVEL_11_0
+    };
+    mDevice->CreateDeviceContextState(0,
+                                      featureLevels,
+                                      2,
+                                      D3D11_SDK_VERSION,
+                                      __uuidof(ID3D11Device1),
+                                      nullptr,
+                                      getter_AddRefs(mDeviceContextState));
+  }
+  if (!mDeviceContextState) {
+    NS_WARNING("VRSession::CreateD3DObjects failed to get a D3D11DeviceContextState");
+    return false;
+  }
+  return true;
+}
+
+ID3D11Device1*
+VRSession::GetD3DDevice()
+{
+  return mDevice;
+}
+
+ID3D11DeviceContext1*
+VRSession::GetD3DDeviceContext()
+{
+  return mContext;
+}
+
+ID3DDeviceContextState*
+VRSession::GetD3DDeviceContextState()
+{
+  return mDeviceContextState;
+}
+
+#endif // defined(XP_WIN)
+
+bool
+VRSession::SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer)
+{
+#if defined(XP_WIN)
+
+  if (aLayer.mTextureType == VRLayerTextureType::LayerTextureType_D3D10SurfaceDescriptor) {
+      RefPtr<ID3D11Texture2D> dxTexture;
+      HRESULT hr = mDevice->OpenSharedResource((HANDLE)aLayer.mTextureHandle,
+        __uuidof(ID3D11Texture2D),
+        (void**)(ID3D11Texture2D**)getter_AddRefs(dxTexture));
+      if (FAILED(hr) || !dxTexture) {
+        NS_WARNING("Failed to open shared texture");
+        return false;
+      }
+
+      // Similar to LockD3DTexture in TextureD3D11.cpp
+      RefPtr<IDXGIKeyedMutex> mutex;
+      dxTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
+      if (mutex) {
+        HRESULT hr = mutex->AcquireSync(0, 1000);
+        if (hr == WAIT_TIMEOUT) {
+          gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout";
+        }
+        else if (hr == WAIT_ABANDONED) {
+          gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
+        }
+        if (FAILED(hr)) {
+          NS_WARNING("Failed to lock the texture");
+          return false;
+        }
+      }
+      bool success = SubmitFrame(aLayer, dxTexture);
+      if (mutex) {
+        HRESULT hr = mutex->ReleaseSync(0);
+        if (FAILED(hr)) {
+          NS_WARNING("Failed to unlock the texture");
+        }
+      }
+      if (!success) {
+        return false;
+      }
+      return true;
+  }
+
+#elif defined(XP_MACOSX)
+
+  if (aLayer.mTextureType == VRLayerTextureType::LayerTextureType_MacIOSurface) {
+    return SubmitFrame(aLayer, aLayer.mTextureHandle);
+  }
+
+#endif
+
+  return false;
+}
+
+void
+VRSession::UpdateTrigger(VRControllerState& aState, uint32_t aButtonIndex, float aValue, float aThreshold)
+{
+  // For OpenVR, the threshold value of ButtonPressed and ButtonTouched is 0.55.
+  // We prefer to let developers to set their own threshold for the adjustment.
+  // Therefore, we don't check ButtonPressed and ButtonTouched with ButtonMask here.
+  // we just check the button value is larger than the threshold value or not.
+  uint64_t mask = (1ULL << aButtonIndex);
+  aState.triggerValue[aButtonIndex] = aValue;
+  if (aValue > aThreshold) {
+    aState.buttonPressed |= mask;
+    aState.buttonTouched |= mask;
+  } else {
+    aState.buttonPressed &= ~mask;
+    aState.buttonTouched &= ~mask;
+  }
+}
+
+bool
+VRSession::ShouldQuit() const
+{
+  return mShouldQuit;
+}
--- a/gfx/vr/service/VRSession.h
+++ b/gfx/vr/service/VRSession.h
@@ -1,62 +1,62 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_VR_SERVICE_VRSESSION_H
-#define GFX_VR_SERVICE_VRSESSION_H
-
-#include "moz_external_vr.h"
-
-#if defined(XP_WIN)
-#include <d3d11_1.h>
-#elif defined(XP_MACOSX)
-class MacIOSurface;
-#endif
-
-namespace mozilla {
-namespace gfx {
-
-class VRSession
-{
-public:
-  VRSession();
-  virtual ~VRSession();
-
-  virtual bool Initialize(mozilla::gfx::VRSystemState& aSystemState) = 0;
-  virtual void Shutdown() = 0;
-  virtual void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) = 0;
-  virtual void StartFrame(mozilla::gfx::VRSystemState& aSystemState) = 0;
-  virtual bool StartPresentation() = 0;
-  virtual void StopPresentation() = 0;
-  virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
-                             float aIntensity, float aDuration) = 0;
-  virtual void StopVibrateHaptic(uint32_t aControllerIdx) = 0;
-  virtual void StopAllHaptics() = 0;
-  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer);
-  bool ShouldQuit() const;
-
-protected:
-  bool mShouldQuit;
-#if defined(XP_WIN)
-  virtual bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                           ID3D11Texture2D* aTexture) = 0;
-  bool CreateD3DContext(RefPtr<ID3D11Device> aDevice);
-  RefPtr<ID3D11Device1> mDevice;
-  RefPtr<ID3D11DeviceContext1> mContext;
-  ID3D11Device1* GetD3DDevice();
-  ID3D11DeviceContext1* GetD3DDeviceContext();
-  ID3DDeviceContextState* GetD3DDeviceContextState();
-  RefPtr<ID3DDeviceContextState> mDeviceContextState;
-#elif defined(XP_MACOSX)
-  virtual bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
-                           const VRLayerTextureHandle& aTexture) = 0;
-#endif
-  void UpdateTrigger(VRControllerState& aState, uint32_t aButtonIndex, float aValue, float aThreshold);
-};
-
-} // namespace mozilla
-} // namespace gfx
-
-#endif // GFX_VR_SERVICE_VRSESSION_H
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_VR_SERVICE_VRSESSION_H
+#define GFX_VR_SERVICE_VRSESSION_H
+
+#include "moz_external_vr.h"
+
+#if defined(XP_WIN)
+#include <d3d11_1.h>
+#elif defined(XP_MACOSX)
+class MacIOSurface;
+#endif
+
+namespace mozilla {
+namespace gfx {
+
+class VRSession
+{
+public:
+  VRSession();
+  virtual ~VRSession() = default;
+
+  virtual bool Initialize(mozilla::gfx::VRSystemState& aSystemState) = 0;
+  virtual void Shutdown() = 0;
+  virtual void ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) = 0;
+  virtual void StartFrame(mozilla::gfx::VRSystemState& aSystemState) = 0;
+  virtual bool StartPresentation() = 0;
+  virtual void StopPresentation() = 0;
+  virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
+                             float aIntensity, float aDuration) = 0;
+  virtual void StopVibrateHaptic(uint32_t aControllerIdx) = 0;
+  virtual void StopAllHaptics() = 0;
+  bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer);
+  bool ShouldQuit() const;
+
+protected:
+  bool mShouldQuit;
+#if defined(XP_WIN)
+  virtual bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                           ID3D11Texture2D* aTexture) = 0;
+  bool CreateD3DContext(RefPtr<ID3D11Device> aDevice);
+  RefPtr<ID3D11Device1> mDevice;
+  RefPtr<ID3D11DeviceContext1> mContext;
+  ID3D11Device1* GetD3DDevice();
+  ID3D11DeviceContext1* GetD3DDeviceContext();
+  ID3DDeviceContextState* GetD3DDeviceContextState();
+  RefPtr<ID3DDeviceContextState> mDeviceContextState;
+#elif defined(XP_MACOSX)
+  virtual bool SubmitFrame(const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
+                           const VRLayerTextureHandle& aTexture) = 0;
+#endif
+  void UpdateTrigger(VRControllerState& aState, uint32_t aButtonIndex, float aValue, float aThreshold);
+};
+
+} // namespace mozilla
+} // namespace gfx
+
+#endif // GFX_VR_SERVICE_VRSESSION_H
--- a/gfx/vr/service/moz.build
+++ b/gfx/vr/service/moz.build
@@ -1,45 +1,45 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Build Oculus support on Windows only
-if CONFIG['OS_TARGET'] == 'WINNT':
-    SOURCES += [
-        'OculusSession.cpp',
-    ]
-
-# Build OSVR on all platforms except Android
-if CONFIG['OS_TARGET'] != 'Android':
-    UNIFIED_SOURCES += [
-        'OSVRSession.cpp',
-        'VRService.cpp',
-        'VRSession.cpp',
-    ]
-    include('/ipc/chromium/chromium-config.mozbuild')
-
-# Build OpenVR on Windows, Linux, and macOS desktop targets
-if CONFIG['OS_TARGET'] in ('WINNT', 'Linux', 'Darwin'):
-    DIRS += [
-        'openvr',
-    ]
-    LOCAL_INCLUDES += [
-        '/dom/base',
-        '/gfx/layers/d3d11'
-    ]
-
-    # OpenVRSession includes MacIOSurface.h which includes Mac headers
-    # which define Size and Points types in the root namespace that
-    # often conflict with our own types.
-    SOURCES += [
-        'OpenVRSession.cpp'
-    ]
-
-FINAL_LIBRARY = 'xul'
-
-# This is intended as a temporary hack to enable VS2015 builds.
-if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
-    # ovr_capi_dynamic.h '<unnamed-tag>': Alignment specifier is less than
-    # actual alignment (8), and will be ignored
-    CXXFLAGS += ['-wd4359']
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Build Oculus support on Windows only
+if CONFIG['OS_TARGET'] == 'WINNT':
+    SOURCES += [
+        'OculusSession.cpp',
+    ]
+
+# Build OSVR on all platforms except Android
+if CONFIG['OS_TARGET'] != 'Android':
+    UNIFIED_SOURCES += [
+        'OSVRSession.cpp',
+        'VRService.cpp',
+        'VRSession.cpp',
+    ]
+    include('/ipc/chromium/chromium-config.mozbuild')
+
+# Build OpenVR on Windows, Linux, and macOS desktop targets
+if CONFIG['OS_TARGET'] in ('WINNT', 'Linux', 'Darwin'):
+    DIRS += [
+        'openvr',
+    ]
+    LOCAL_INCLUDES += [
+        '/dom/base',
+        '/gfx/layers/d3d11'
+    ]
+
+    # OpenVRSession includes MacIOSurface.h which includes Mac headers
+    # which define Size and Points types in the root namespace that
+    # often conflict with our own types.
+    SOURCES += [
+        'OpenVRSession.cpp'
+    ]
+
+FINAL_LIBRARY = 'xul'
+
+# This is intended as a temporary hack to enable VS2015 builds.
+if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
+    # ovr_capi_dynamic.h '<unnamed-tag>': Alignment specifier is less than
+    # actual alignment (8), and will be ignored
+    CXXFLAGS += ['-wd4359']