tor-browser

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

OSVRSession.cpp (18948B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "OSVRSession.h"
      8 #include "prenv.h"
      9 #include "nsString.h"
     10 #include "mozilla/Preferences.h"
     11 #include "mozilla/StaticPrefs_dom.h"
     12 #include "mozilla/SharedLibrary.h"
     13 #include "mozilla/gfx/Quaternion.h"
     14 
     15 #if defined(XP_WIN)
     16 #  include <d3d11.h>
     17 #  include "mozilla/gfx/DeviceManagerDx.h"
     18 #endif  // defined(XP_WIN)
     19 
     20 #ifndef M_PI
     21 #  define M_PI 3.14159265358979323846
     22 #endif
     23 
     24 using namespace mozilla;
     25 using namespace mozilla::gfx;
     26 
     27 namespace {
     28 // need to typedef functions that will be used in the code below
     29 extern "C" {
     30 typedef OSVR_ClientContext (*pfn_osvrClientInit)(
     31    const char applicationIdentifier[], uint32_t flags);
     32 typedef OSVR_ReturnCode (*pfn_osvrClientShutdown)(OSVR_ClientContext ctx);
     33 typedef OSVR_ReturnCode (*pfn_osvrClientUpdate)(OSVR_ClientContext ctx);
     34 typedef OSVR_ReturnCode (*pfn_osvrClientCheckStatus)(OSVR_ClientContext ctx);
     35 typedef OSVR_ReturnCode (*pfn_osvrClientGetInterface)(
     36    OSVR_ClientContext ctx, const char path[], OSVR_ClientInterface* iface);
     37 typedef OSVR_ReturnCode (*pfn_osvrClientFreeInterface)(
     38    OSVR_ClientContext ctx, OSVR_ClientInterface iface);
     39 typedef OSVR_ReturnCode (*pfn_osvrGetOrientationState)(
     40    OSVR_ClientInterface iface, OSVR_TimeValue* timestamp,
     41    OSVR_OrientationState* state);
     42 typedef OSVR_ReturnCode (*pfn_osvrGetPositionState)(OSVR_ClientInterface iface,
     43                                                    OSVR_TimeValue* timestamp,
     44                                                    OSVR_PositionState* state);
     45 typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplay)(OSVR_ClientContext ctx,
     46                                                    OSVR_DisplayConfig* disp);
     47 typedef OSVR_ReturnCode (*pfn_osvrClientFreeDisplay)(OSVR_DisplayConfig disp);
     48 typedef OSVR_ReturnCode (*pfn_osvrClientGetNumEyesForViewer)(
     49    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount* eyes);
     50 typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyePose)(
     51    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
     52    OSVR_Pose3* pose);
     53 typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplayDimensions)(
     54    OSVR_DisplayConfig disp, OSVR_DisplayInputCount displayInputIndex,
     55    OSVR_DisplayDimension* width, OSVR_DisplayDimension* height);
     56 typedef OSVR_ReturnCode (
     57    *pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes)(
     58    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
     59    OSVR_SurfaceCount surface, double* left, double* right, double* bottom,
     60    double* top);
     61 typedef OSVR_ReturnCode (*pfn_osvrClientGetRelativeViewportForViewerEyeSurface)(
     62    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
     63    OSVR_SurfaceCount surface, OSVR_ViewportDimension* left,
     64    OSVR_ViewportDimension* bottom, OSVR_ViewportDimension* width,
     65    OSVR_ViewportDimension* height);
     66 typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf)(
     67    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
     68    OSVR_SurfaceCount surface, float near, float far,
     69    OSVR_MatrixConventions flags, float* matrix);
     70 typedef OSVR_ReturnCode (*pfn_osvrClientCheckDisplayStartup)(
     71    OSVR_DisplayConfig disp);
     72 typedef OSVR_ReturnCode (*pfn_osvrClientSetRoomRotationUsingHead)(
     73    OSVR_ClientContext ctx);
     74 }
     75 
     76 static pfn_osvrClientInit osvr_ClientInit = nullptr;
     77 static pfn_osvrClientShutdown osvr_ClientShutdown = nullptr;
     78 static pfn_osvrClientUpdate osvr_ClientUpdate = nullptr;
     79 static pfn_osvrClientCheckStatus osvr_ClientCheckStatus = nullptr;
     80 static pfn_osvrClientGetInterface osvr_ClientGetInterface = nullptr;
     81 static pfn_osvrClientFreeInterface osvr_ClientFreeInterface = nullptr;
     82 static pfn_osvrGetOrientationState osvr_GetOrientationState = nullptr;
     83 static pfn_osvrGetPositionState osvr_GetPositionState = nullptr;
     84 static pfn_osvrClientGetDisplay osvr_ClientGetDisplay = nullptr;
     85 static pfn_osvrClientFreeDisplay osvr_ClientFreeDisplay = nullptr;
     86 static pfn_osvrClientGetNumEyesForViewer osvr_ClientGetNumEyesForViewer =
     87    nullptr;
     88 static pfn_osvrClientGetViewerEyePose osvr_ClientGetViewerEyePose = nullptr;
     89 static pfn_osvrClientGetDisplayDimensions osvr_ClientGetDisplayDimensions =
     90    nullptr;
     91 static pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes
     92    osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes = nullptr;
     93 static pfn_osvrClientGetRelativeViewportForViewerEyeSurface
     94    osvr_ClientGetRelativeViewportForViewerEyeSurface = nullptr;
     95 static pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf
     96    osvr_ClientGetViewerEyeSurfaceProjectionMatrixf = nullptr;
     97 static pfn_osvrClientCheckDisplayStartup osvr_ClientCheckDisplayStartup =
     98    nullptr;
     99 static pfn_osvrClientSetRoomRotationUsingHead
    100    osvr_ClientSetRoomRotationUsingHead = nullptr;
    101 
    102 bool LoadOSVRRuntime() {
    103  static PRLibrary* osvrUtilLib = nullptr;
    104  static PRLibrary* osvrCommonLib = nullptr;
    105  static PRLibrary* osvrClientLib = nullptr;
    106  static PRLibrary* osvrClientKitLib = nullptr;
    107  // this looks up the path in the about:config setting, from greprefs.js or
    108  // modules\libpref\init\all.js we need all the libs to be valid
    109 #ifdef XP_WIN
    110  constexpr static auto* pfnGetPathStringPref = mozilla::Preferences::GetString;
    111  nsAutoString osvrUtilPath, osvrCommonPath, osvrClientPath, osvrClientKitPath;
    112 #else
    113  constexpr static auto* pfnGetPathStringPref =
    114      mozilla::Preferences::GetCString;
    115  nsAutoCString osvrUtilPath, osvrCommonPath, osvrClientPath, osvrClientKitPath;
    116 #endif
    117  if (NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.utilLibPath", osvrUtilPath,
    118                                     PrefValueKind::User)) ||
    119      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.commonLibPath",
    120                                     osvrCommonPath, PrefValueKind::User)) ||
    121      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.clientLibPath",
    122                                     osvrClientPath, PrefValueKind::User)) ||
    123      NS_FAILED(pfnGetPathStringPref("gfx.vr.osvr.clientKitLibPath",
    124                                     osvrClientKitPath, PrefValueKind::User))) {
    125    return false;
    126  }
    127 
    128  osvrUtilLib = LoadLibraryWithFlags(osvrUtilPath.get());
    129  osvrCommonLib = LoadLibraryWithFlags(osvrCommonPath.get());
    130  osvrClientLib = LoadLibraryWithFlags(osvrClientPath.get());
    131  osvrClientKitLib = LoadLibraryWithFlags(osvrClientKitPath.get());
    132 
    133  if (!osvrUtilLib) {
    134    printf_stderr("[OSVR] Failed to load OSVR Util library!\n");
    135    return false;
    136  }
    137  if (!osvrCommonLib) {
    138    printf_stderr("[OSVR] Failed to load OSVR Common library!\n");
    139    return false;
    140  }
    141  if (!osvrClientLib) {
    142    printf_stderr("[OSVR] Failed to load OSVR Client library!\n");
    143    return false;
    144  }
    145  if (!osvrClientKitLib) {
    146    printf_stderr("[OSVR] Failed to load OSVR ClientKit library!\n");
    147    return false;
    148  }
    149 
    150 // make sure all functions that we'll be using are available
    151 #define REQUIRE_FUNCTION(_x)                                                  \
    152  do {                                                                        \
    153    *(void**)&osvr_##_x = (void*)PR_FindSymbol(osvrClientKitLib, "osvr" #_x); \
    154    if (!osvr_##_x) {                                                         \
    155      printf_stderr("osvr" #_x " symbol missing\n");                          \
    156      goto fail;                                                              \
    157    }                                                                         \
    158  } while (0)
    159 
    160  REQUIRE_FUNCTION(ClientInit);
    161  REQUIRE_FUNCTION(ClientShutdown);
    162  REQUIRE_FUNCTION(ClientUpdate);
    163  REQUIRE_FUNCTION(ClientCheckStatus);
    164  REQUIRE_FUNCTION(ClientGetInterface);
    165  REQUIRE_FUNCTION(ClientFreeInterface);
    166  REQUIRE_FUNCTION(GetOrientationState);
    167  REQUIRE_FUNCTION(GetPositionState);
    168  REQUIRE_FUNCTION(ClientGetDisplay);
    169  REQUIRE_FUNCTION(ClientFreeDisplay);
    170  REQUIRE_FUNCTION(ClientGetNumEyesForViewer);
    171  REQUIRE_FUNCTION(ClientGetViewerEyePose);
    172  REQUIRE_FUNCTION(ClientGetDisplayDimensions);
    173  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionClippingPlanes);
    174  REQUIRE_FUNCTION(ClientGetRelativeViewportForViewerEyeSurface);
    175  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionMatrixf);
    176  REQUIRE_FUNCTION(ClientCheckDisplayStartup);
    177  REQUIRE_FUNCTION(ClientSetRoomRotationUsingHead);
    178 
    179 #undef REQUIRE_FUNCTION
    180 
    181  return true;
    182 
    183 fail:
    184  return false;
    185 }
    186 
    187 }  // namespace
    188 
    189 mozilla::gfx::VRFieldOfView SetFromTanRadians(double left, double right,
    190                                              double bottom, double top) {
    191  mozilla::gfx::VRFieldOfView fovInfo;
    192  fovInfo.leftDegrees = atan(left) * 180.0 / M_PI;
    193  fovInfo.rightDegrees = atan(right) * 180.0 / M_PI;
    194  fovInfo.upDegrees = atan(top) * 180.0 / M_PI;
    195  fovInfo.downDegrees = atan(bottom) * 180.0 / M_PI;
    196  return fovInfo;
    197 }
    198 
    199 OSVRSession::OSVRSession()
    200    : mRuntimeLoaded(false),
    201      mOSVRInitialized(false),
    202      mClientContextInitialized(false),
    203      mDisplayConfigInitialized(false),
    204      mInterfaceInitialized(false),
    205      m_ctx(nullptr),
    206      m_iface(nullptr),
    207      m_display(nullptr) {}
    208 OSVRSession::~OSVRSession() { Shutdown(); }
    209 
    210 bool OSVRSession::Initialize(mozilla::gfx::VRSystemState& aSystemState,
    211                             bool aDetectRuntimesOnly) {
    212  if (StaticPrefs::dom_vr_puppet_enabled()) {
    213    // Ensure that tests using the VR Puppet do not find real hardware
    214    return false;
    215  }
    216  if (!StaticPrefs::dom_vr_enabled() || !StaticPrefs::dom_vr_osvr_enabled()) {
    217    return false;
    218  }
    219  if (mOSVRInitialized) {
    220    return true;
    221  }
    222  if (!LoadOSVRRuntime()) {
    223    return false;
    224  }
    225  mRuntimeLoaded = true;
    226 
    227  if (aDetectRuntimesOnly) {
    228    aSystemState.displayState.capabilityFlags |=
    229        VRDisplayCapabilityFlags::Cap_ImmersiveVR;
    230    return false;
    231  }
    232 
    233  // initialize client context
    234  InitializeClientContext();
    235  // try to initialize interface
    236  InitializeInterface();
    237  // try to initialize display object
    238  InitializeDisplay();
    239  // verify all components are initialized
    240  CheckOSVRStatus();
    241 
    242  if (!mOSVRInitialized) {
    243    return false;
    244  }
    245 
    246  if (!InitState(aSystemState)) {
    247    return false;
    248  }
    249 
    250  return true;
    251 }
    252 
    253 void OSVRSession::CheckOSVRStatus() {
    254  if (mOSVRInitialized) {
    255    return;
    256  }
    257 
    258  // client context must be initialized first
    259  InitializeClientContext();
    260 
    261  // update client context
    262  osvr_ClientUpdate(m_ctx);
    263 
    264  // initialize interface and display if they are not initialized yet
    265  InitializeInterface();
    266  InitializeDisplay();
    267 
    268  // OSVR is fully initialized now
    269  if (mClientContextInitialized && mDisplayConfigInitialized &&
    270      mInterfaceInitialized) {
    271    mOSVRInitialized = true;
    272  }
    273 }
    274 
    275 void OSVRSession::InitializeClientContext() {
    276  // already initialized
    277  if (mClientContextInitialized) {
    278    return;
    279  }
    280 
    281  // first time creating
    282  if (!m_ctx) {
    283    // get client context
    284    m_ctx = osvr_ClientInit("com.osvr.webvr", 0);
    285    // update context
    286    osvr_ClientUpdate(m_ctx);
    287    // verify we are connected
    288    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
    289      mClientContextInitialized = true;
    290    }
    291  }
    292  // client context exists but not up and running yet
    293  else {
    294    // update context
    295    osvr_ClientUpdate(m_ctx);
    296    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
    297      mClientContextInitialized = true;
    298    }
    299  }
    300 }
    301 
    302 void OSVRSession::InitializeInterface() {
    303  // already initialized
    304  if (mInterfaceInitialized) {
    305    return;
    306  }
    307  // Client context must be initialized before getting interface
    308  if (mClientContextInitialized) {
    309    // m_iface will remain nullptr if no interface is returned
    310    if (OSVR_RETURN_SUCCESS ==
    311        osvr_ClientGetInterface(m_ctx, "/me/head", &m_iface)) {
    312      mInterfaceInitialized = true;
    313    }
    314  }
    315 }
    316 
    317 void OSVRSession::InitializeDisplay() {
    318  // display is fully configured
    319  if (mDisplayConfigInitialized) {
    320    return;
    321  }
    322 
    323  // Client context must be initialized before getting interface
    324  if (mClientContextInitialized) {
    325    // first time creating display object
    326    if (m_display == nullptr) {
    327      OSVR_ReturnCode ret = osvr_ClientGetDisplay(m_ctx, &m_display);
    328 
    329      if (ret == OSVR_RETURN_SUCCESS) {
    330        osvr_ClientUpdate(m_ctx);
    331        // display object may have been created but not fully startup
    332        if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
    333          mDisplayConfigInitialized = true;
    334        }
    335      }
    336 
    337      // Typically once we get Display object, pose data is available after
    338      // clientUpdate but sometimes it takes ~ 200 ms to get
    339      // a succesfull connection, so we might have to run a few update cycles
    340    } else {
    341      if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
    342        mDisplayConfigInitialized = true;
    343      }
    344    }
    345  }
    346 }
    347 
    348 bool OSVRSession::InitState(mozilla::gfx::VRSystemState& aSystemState) {
    349  VRDisplayState& state = aSystemState.displayState;
    350  strncpy(state.displayName.data(), "OSVR HMD", kVRDisplayNameMaxLen);
    351  state.eightCC = GFX_VR_EIGHTCC('O', 'S', 'V', 'R', ' ', ' ', ' ', ' ');
    352  state.isConnected = true;
    353  state.isMounted = false;
    354  state.capabilityFlags =
    355      (VRDisplayCapabilityFlags)((int)VRDisplayCapabilityFlags::Cap_None |
    356                                 (int)
    357                                     VRDisplayCapabilityFlags::Cap_Orientation |
    358                                 (int)VRDisplayCapabilityFlags::Cap_Position |
    359                                 (int)VRDisplayCapabilityFlags::Cap_External |
    360                                 (int)VRDisplayCapabilityFlags::Cap_Present |
    361                                 (int)
    362                                     VRDisplayCapabilityFlags::Cap_ImmersiveVR);
    363  state.blendMode = VRDisplayBlendMode::Opaque;
    364  state.reportsDroppedFrames = false;
    365 
    366  // XXX OSVR display topology allows for more than one viewer
    367  // will assume only one viewer for now (most likely stay that way)
    368 
    369  OSVR_EyeCount numEyes;
    370  osvr_ClientGetNumEyesForViewer(m_display, 0, &numEyes);
    371 
    372  for (uint8_t eye = 0; eye < numEyes; eye++) {
    373    double left, right, bottom, top;
    374    // XXX for now there is only one surface per eye
    375    osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes(
    376        m_display, 0, eye, 0, &left, &right, &bottom, &top);
    377    state.eyeFOV[eye] = SetFromTanRadians(-left, right, -bottom, top);
    378  }
    379 
    380  // XXX Assuming there is only one display input for now
    381  // however, it's possible to have more than one (dSight with 2 HDMI inputs)
    382  OSVR_DisplayDimension width, height;
    383  osvr_ClientGetDisplayDimensions(m_display, 0, &width, &height);
    384 
    385  for (uint8_t eye = 0; eye < numEyes; eye++) {
    386    OSVR_ViewportDimension l, b, w, h;
    387    osvr_ClientGetRelativeViewportForViewerEyeSurface(m_display, 0, eye, 0, &l,
    388                                                      &b, &w, &h);
    389    state.eyeResolution.width = w;
    390    state.eyeResolution.height = h;
    391    OSVR_Pose3 eyePose;
    392    // Viewer eye pose may not be immediately available, update client context
    393    // until we get it
    394    OSVR_ReturnCode ret =
    395        osvr_ClientGetViewerEyePose(m_display, 0, eye, &eyePose);
    396    while (ret != OSVR_RETURN_SUCCESS) {
    397      osvr_ClientUpdate(m_ctx);
    398      ret = osvr_ClientGetViewerEyePose(m_display, 0, eye, &eyePose);
    399    }
    400    state.eyeTranslation[eye].x = eyePose.translation.data[0];
    401    state.eyeTranslation[eye].y = eyePose.translation.data[1];
    402    state.eyeTranslation[eye].z = eyePose.translation.data[2];
    403 
    404    Matrix4x4 pose;
    405    pose.SetRotationFromQuaternion(gfx::Quaternion(
    406        osvrQuatGetX(&eyePose.rotation), osvrQuatGetY(&eyePose.rotation),
    407        osvrQuatGetZ(&eyePose.rotation), osvrQuatGetW(&eyePose.rotation)));
    408    pose.PreTranslate(eyePose.translation.data[0], eyePose.translation.data[1],
    409                      eyePose.translation.data[2]);
    410    pose.Invert();
    411    mHeadToEye[eye] = pose;
    412  }
    413 
    414  // default to an identity quaternion
    415  VRHMDSensorState& sensorState = aSystemState.sensorState;
    416  sensorState.flags =
    417      (VRDisplayCapabilityFlags)((int)
    418                                     VRDisplayCapabilityFlags::Cap_Orientation |
    419                                 (int)VRDisplayCapabilityFlags::Cap_Position);
    420  sensorState.pose.orientation[3] = 1.0f;  // Default to an identity quaternion
    421 
    422  return true;
    423 }
    424 
    425 void OSVRSession::Shutdown() {
    426  if (!mRuntimeLoaded) {
    427    return;
    428  }
    429  mOSVRInitialized = false;
    430  // client context may not have been initialized
    431  if (m_ctx) {
    432    osvr_ClientFreeDisplay(m_display);
    433  }
    434  // osvr checks that m_ctx or m_iface are not null
    435  osvr_ClientFreeInterface(m_ctx, m_iface);
    436  osvr_ClientShutdown(m_ctx);
    437 }
    438 
    439 void OSVRSession::ProcessEvents(mozilla::gfx::VRSystemState& aSystemState) {}
    440 
    441 void OSVRSession::StartFrame(mozilla::gfx::VRSystemState& aSystemState) {
    442  UpdateHeadsetPose(aSystemState);
    443 }
    444 
    445 void OSVRSession::UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState) {
    446  // Update client context before anything
    447  // this usually goes into app's mainloop
    448  osvr_ClientUpdate(m_ctx);
    449 
    450  VRHMDSensorState result{};
    451  OSVR_TimeValue timestamp;
    452 
    453  OSVR_OrientationState orientation;
    454 
    455  OSVR_ReturnCode ret =
    456      osvr_GetOrientationState(m_iface, &timestamp, &orientation);
    457 
    458  aState.sensorState.timestamp = timestamp.seconds;
    459 
    460  if (ret == OSVR_RETURN_SUCCESS) {
    461    result.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
    462    result.pose.orientation[0] = orientation.data[1];
    463    result.pose.orientation[1] = orientation.data[2];
    464    result.pose.orientation[2] = orientation.data[3];
    465    result.pose.orientation[3] = orientation.data[0];
    466  } else {
    467    // default to an identity quaternion
    468    result.pose.orientation[3] = 1.0f;
    469  }
    470 
    471  OSVR_PositionState position;
    472  ret = osvr_GetPositionState(m_iface, &timestamp, &position);
    473  if (ret == OSVR_RETURN_SUCCESS) {
    474    result.flags |= VRDisplayCapabilityFlags::Cap_Position;
    475    result.pose.position[0] = position.data[0];
    476    result.pose.position[1] = position.data[1];
    477    result.pose.position[2] = position.data[2];
    478  }
    479 
    480  result.CalcViewMatrices(mHeadToEye);
    481 }
    482 
    483 bool OSVRSession::StartPresentation() {
    484  return false;
    485  // TODO Implement
    486 }
    487 
    488 void OSVRSession::StopPresentation() {
    489  // TODO Implement
    490 }
    491 
    492 #if defined(XP_WIN)
    493 bool OSVRSession::SubmitFrame(
    494    const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
    495    ID3D11Texture2D* aTexture) {
    496  return false;
    497  // TODO Implement
    498 }
    499 #elif defined(XP_MACOSX)
    500 bool OSVRSession::SubmitFrame(
    501    const mozilla::gfx::VRLayer_Stereo_Immersive& aLayer,
    502    const VRLayerTextureHandle& aTexture) {
    503  return false;
    504  // TODO Implement
    505 }
    506 #endif
    507 
    508 void OSVRSession::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
    509                                float aIntensity, float aDuration) {}
    510 
    511 void OSVRSession::StopVibrateHaptic(uint32_t aControllerIdx) {}
    512 
    513 void OSVRSession::StopAllHaptics() {}