Bug 1179944, [webvr] put back support for Oculus 0.5.0 runtime, for OSX and Linux; r=mstange
authorVladimir Vukicevic <vladimir@pobox.com>
Fri, 05 Jun 2015 13:14:10 -0400
changeset 288577 29726d5ce4fbbade85b48bbc835f3b637ec11f9f
parent 288576 df8a03c8c49d564e6f4e641d9fdafeaf6680327e
child 288578 fa2405094adb717e25c9cc73375609a5a38e9f81
push id934
push userraliiev@mozilla.com
push dateMon, 26 Oct 2015 12:58:05 +0000
treeherdermozilla-release@05704e35c1d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1179944
milestone42.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 1179944, [webvr] put back support for Oculus 0.5.0 runtime, for OSX and Linux; r=mstange
gfx/layers/d3d11/CompositorD3D11.cpp
gfx/layers/d3d11/CompositorD3D11ShadersVR.h
gfx/layers/d3d11/CompositorD3D11VR.hlsl
gfx/layers/d3d11/genshaders.sh
gfx/vr/gfxVR.cpp
gfx/vr/gfxVR.h
gfx/vr/gfxVRCardboard.cpp
gfx/vr/gfxVROculus050.cpp
gfx/vr/gfxVROculus050.h
gfx/vr/moz.build
gfx/vr/ovr_capi_dynamic050.h
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -326,23 +326,23 @@ CompositorD3D11::Initialize()
       { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
       { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT,       0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
       { "TEXCOORD", 2, DXGI_FORMAT_R32G32_FLOAT,       0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
       { "COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
     };
 
     hr = mDevice->CreateInputLayout(vrlayout,
                                     sizeof(vrlayout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
-                                    OculusVRDistortionVS,
-                                    sizeof(OculusVRDistortionVS),
-                                    byRef(mAttachments->mVRDistortionInputLayout[VRHMDType::Oculus]));
+                                    Oculus050VRDistortionVS,
+                                    sizeof(Oculus050VRDistortionVS),
+                                    byRef(mAttachments->mVRDistortionInputLayout[VRHMDType::Oculus050]));
 
     // XXX shared for now, rename
     mAttachments->mVRDistortionInputLayout[VRHMDType::Cardboard] =
-      mAttachments->mVRDistortionInputLayout[VRHMDType::Oculus];
+      mAttachments->mVRDistortionInputLayout[VRHMDType::Oculus050];
 
     cBufferDesc.ByteWidth = sizeof(gfx::VRDistortionConstants);
     hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, byRef(mAttachments->mVRDistortionConstants));
     if (FAILED(hr)) {
       return false;
     }
   }
 
@@ -627,16 +627,24 @@ CompositorD3D11::DrawVRDistortion(const 
   EffectVRDistortion* vrEffect =
     static_cast<EffectVRDistortion*>(aEffectChain.mPrimaryEffect.get());
 
   TextureSourceD3D11* source = vrEffect->mTexture->AsSourceD3D11();
   gfx::IntSize size = vrEffect->mRenderTarget->GetSize(); // XXX source->GetSize()
 
   VRHMDInfo* hmdInfo = vrEffect->mHMD;
   VRHMDType hmdType = hmdInfo->GetType();
+
+  if (!mAttachments->mVRDistortionVS[hmdType] ||
+      !mAttachments->mVRDistortionPS[hmdType])
+  {
+    NS_WARNING("No VS/PS for hmd type for VR distortion!");
+    return;
+  }
+
   VRDistortionConstants shaderConstants;
 
   // do we need to recreate the VR buffers, since the config has changed?
   if (hmdInfo->GetConfiguration() != mAttachments->mVRConfiguration) {
     D3D11_SUBRESOURCE_DATA sdata = { 0 };
     CD3D11_BUFFER_DESC desc(0, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE);
 
     // XXX as an optimization, we should really pack the indices and vertices for both eyes
@@ -1258,36 +1266,36 @@ CompositorD3D11::CreateShaders()
                                   byRef(mAttachments->mRGBAShader[MaskType::Mask3d]));
   if (FAILED(hr)) {
     return false;
   }
 
 
   /* VR stuff */
 
-  hr = mDevice->CreateVertexShader(OculusVRDistortionVS,
-                                   sizeof(OculusVRDistortionVS),
+  hr = mDevice->CreateVertexShader(Oculus050VRDistortionVS,
+                                   sizeof(Oculus050VRDistortionVS),
                                    nullptr,
-                                   byRef(mAttachments->mVRDistortionVS[VRHMDType::Oculus]));
+                                   byRef(mAttachments->mVRDistortionVS[VRHMDType::Oculus050]));
   if (FAILED(hr)) {
     return false;
   }
 
-  hr = mDevice->CreatePixelShader(OculusVRDistortionPS,
-                                  sizeof(OculusVRDistortionPS),
+  hr = mDevice->CreatePixelShader(Oculus050VRDistortionPS,
+                                  sizeof(Oculus050VRDistortionPS),
                                   nullptr,
-                                  byRef(mAttachments->mVRDistortionPS[VRHMDType::Oculus]));
+                                  byRef(mAttachments->mVRDistortionPS[VRHMDType::Oculus050]));
   if (FAILED(hr)) {
     return false;
   }
 
   // These are shared
-  // XXX rename Oculus shaders to something more generic
-  mAttachments->mVRDistortionVS[VRHMDType::Cardboard] = mAttachments->mVRDistortionVS[VRHMDType::Oculus];
-  mAttachments->mVRDistortionPS[VRHMDType::Cardboard] = mAttachments->mVRDistortionPS[VRHMDType::Oculus];
+  // XXX rename Oculus050 shaders to something more generic
+  mAttachments->mVRDistortionVS[VRHMDType::Cardboard] = mAttachments->mVRDistortionVS[VRHMDType::Oculus050];
+  mAttachments->mVRDistortionPS[VRHMDType::Cardboard] = mAttachments->mVRDistortionPS[VRHMDType::Oculus050];
 
   return true;
 }
 
 bool
 CompositorD3D11::UpdateConstantBuffers()
 {
   HRESULT hr;
--- a/gfx/layers/d3d11/CompositorD3D11ShadersVR.h
+++ b/gfx/layers/d3d11/CompositorD3D11ShadersVR.h
@@ -103,17 +103,17 @@ mad o2.xy, v2.xyxx, cb0[0].zwzz, cb0[0].
 mov o2.z, l(1.000000)
 mad o3.xy, v3.xyxx, cb0[0].zwzz, cb0[0].xyxx
 mov o3.z, l(1.000000)
 mov o4.xyzw, v4.xyzw
 ret 
 // Approximately 10 instruction slots used
 #endif
 
-const BYTE OculusVRDistortionVS[] =
+const BYTE Oculus050VRDistortionVS[] =
 {
      68,  88,  66,  67, 206, 154, 
     203,  64, 121,  47, 121, 169, 
     222, 206, 108, 175, 167, 227, 
     154,  37,   1,   0,   0,   0, 
     244,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     108,   1,   0,   0,  44,   3, 
@@ -442,17 +442,17 @@ sample r0.xyzw, v2.xyxx, t0.xyzw, s0
 mul o0.y, r0.y, v4.x
 sample r0.xyzw, v3.xyxx, t0.xyzw, s0
 mul o0.z, r0.z, v4.x
 mov o0.w, l(1.000000)
 ret 
 // Approximately 8 instruction slots used
 #endif
 
-const BYTE OculusVRDistortionPS[] =
+const BYTE Oculus050VRDistortionPS[] =
 {
      68,  88,  66,  67,  48, 161, 
     127, 216, 149, 107,  53,  57, 
     164,  84,  84, 154,  58, 227, 
     125,  61,   1,   0,   0,   0, 
     124,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      60,   1,   0,   0, 132,   2, 
--- a/gfx/layers/d3d11/CompositorD3D11VR.hlsl
+++ b/gfx/layers/d3d11/CompositorD3D11VR.hlsl
@@ -33,19 +33,19 @@ struct VS_VR_OUTPUT {
 SamplerState Linear
 {
   Filter = MIN_MAG_MIP_LINEAR;
   AddressU = Clamp;
   AddressV = Clamp;
 };
 
 /*
- * Oculus basic distortion, with chroma aberration correction
+ * Oculus050 basic distortion, with chroma aberration correction
  */
-VS_VR_OUTPUT OculusVRDistortionVS(const VS_VR_INPUT aVertex)
+VS_VR_OUTPUT Oculus050VRDistortionVS(const VS_VR_INPUT aVertex)
 {
   VS_VR_OUTPUT res;
 
   float2 tc0 = aVertex.vTexCoord0 * VREyeToSource.zw + VREyeToSource.xy;
   float2 tc1 = aVertex.vTexCoord1 * VREyeToSource.zw + VREyeToSource.xy;
   float2 tc2 = aVertex.vTexCoord2 * VREyeToSource.zw + VREyeToSource.xy;
 
   //res.vPosition.xy = aVertex.vPosition.xy;
@@ -56,17 +56,17 @@ VS_VR_OUTPUT OculusVRDistortionVS(const 
   res.vTexCoord1 = float3(tc1, 1);
   res.vTexCoord2 = float3(tc2, 1);
 
   res.vGenericAttribs = aVertex.vGenericAttribs;
   
   return res;
 }
 
-float4 OculusVRDistortionPS(const VS_VR_OUTPUT aVertex) : SV_Target
+float4 Oculus050VRDistortionPS(const VS_VR_OUTPUT aVertex) : SV_Target
 {
   float resR = Texture.Sample(Linear, aVertex.vTexCoord0.xy).r;
   float resG = Texture.Sample(Linear, aVertex.vTexCoord1.xy).g;
   float resB = Texture.Sample(Linear, aVertex.vTexCoord2.xy).b;
 
   return float4(resR * aVertex.vGenericAttribs.r,
                 resG * aVertex.vGenericAttribs.r,
                 resB * aVertex.vGenericAttribs.r,
--- a/gfx/layers/d3d11/genshaders.sh
+++ b/gfx/layers/d3d11/genshaders.sh
@@ -40,12 +40,12 @@ makeShaderPS RGBAShaderMask
 makeShaderPS RGBAShaderMask3D
 makeShaderPS YCbCrShaderMask
 makeShaderPS ComponentAlphaShaderMask
 
 SRC=CompositorD3D11VR.hlsl
 DEST=CompositorD3D11ShadersVR.h
 
 rm -f $DEST
-makeShaderVS OculusVRDistortionVS
-makeShaderPS OculusVRDistortionPS
+makeShaderVS Oculus050VRDistortionVS
+makeShaderPS Oculus050VRDistortionPS
 
 rm $tempfile
--- a/gfx/vr/gfxVR.cpp
+++ b/gfx/vr/gfxVR.cpp
@@ -7,22 +7,28 @@
 
 #include "prlink.h"
 #include "prmem.h"
 #include "prenv.h"
 #include "nsString.h"
 
 #include "gfxPrefs.h"
 #include "gfxVR.h"
+#if defined(XP_WIN)
 #include "gfxVROculus.h"
+#endif
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
+#include "gfxVROculus050.h"
+#endif
 #include "gfxVRCardboard.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsIScreenManager.h"
 
+#include "mozilla/unused.h"
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/TextureHost.h"
 
 #ifndef M_PI
 # define M_PI 3.14159265358979323846
 #endif
 
 using namespace mozilla;
@@ -97,19 +103,36 @@ VRHMDManager::ManagerInit()
 {
   if (sManagers)
     return;
 
   sManagers = new VRHMDManagerArray();
 
   nsRefPtr<VRHMDManager> mgr;
 
+  // we'll only load the 0.5.0 oculus runtime if
+  // the >= 0.6.0 one failed to load
+  bool useOculus050 = true;
+  unused << useOculus050;
+
+#if defined(XP_WIN)
   mgr = new VRHMDManagerOculus();
-  if (mgr->PlatformInit())
+  if (mgr->PlatformInit()) {
+    useOculus050 = false;
     sManagers->AppendElement(mgr);
+  }
+#endif
+
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
+  if (useOculus050) {
+    mgr = new VRHMDManagerOculus050();
+    if (mgr->PlatformInit())
+      sManagers->AppendElement(mgr);
+  }
+#endif
 
   mgr = new VRHMDManagerCardboard();
   if (mgr->PlatformInit())
     sManagers->AppendElement(mgr);
 }
 
 /* static */ void
 VRHMDManager::ManagerDestroy()
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -22,16 +22,17 @@ class Compositor;
 class CompositingRenderTarget;
 }
 
 namespace gfx {
 
 enum class VRHMDType : uint16_t {
   Oculus,
   Cardboard,
+  Oculus050,
   NumHMDTypes
 };
 
 struct VRFieldOfView {
   static VRFieldOfView FromCSSPerspectiveInfo(double aPerspectiveDistance,
                                               const Point& aPerspectiveOrigin,
                                               const Point& aTransformOrigin,
                                               const Rect& aContentRectangle)
--- a/gfx/vr/gfxVRCardboard.cpp
+++ b/gfx/vr/gfxVRCardboard.cpp
@@ -93,18 +93,18 @@ HMDInfoCardboard::HMDInfoCardboard()
 
   mMaximumEyeFOV[Eye_Left] = VRFieldOfView(45.0, 45.0, 45.0, 45.0);
   mMaximumEyeFOV[Eye_Right] = VRFieldOfView(45.0, 45.0, 45.0, 45.0);
 
   SetFOV(mRecommendedEyeFOV[Eye_Left], mRecommendedEyeFOV[Eye_Right], 0.01, 10000.0);
 
 #if 1
   int32_t xcoord = 0;
-  if (getenv("FAKE_CARDBOARD_SCREEN")) {
-      const char *env = getenv("FAKE_CARDBOARD_SCREEN");
+  if (PR_GetEnv("FAKE_CARDBOARD_SCREEN")) {
+      const char *env = PR_GetEnv("FAKE_CARDBOARD_SCREEN");
       nsresult err;
       xcoord = nsCString(env).ToInteger(&err);
       if (err != NS_OK) xcoord = 0;
   }
   mScreen = VRHMDManager::MakeFakeScreen(xcoord, 0, 1920, 1080);
 #endif
 
 }
@@ -269,16 +269,22 @@ HMDInfoCardboard::SetFOV(const VRFieldOf
     iv[0] = 0; iv[1] = 1; iv[2] = 2;
     iv[3] = 2; iv[4] = 3; iv[5] = 0;
   }
 
   // XXX find out the default screen size and use that
   mEyeResolution.width = 1920 / 2;
   mEyeResolution.height = 1080;
 
+  if (PR_GetEnv("FAKE_CARDBOARD_SCREEN")) {
+    // for testing, make the eye resolution 2x of the screen
+    mEyeResolution.width *= 2;
+    mEyeResolution.height *= 2;
+  }
+
   mConfiguration.hmdType = mType;
   mConfiguration.value = 0;
   mConfiguration.fov[0] = aFOVLeft;
   mConfiguration.fov[1] = aFOVRight;
 
   return true;
 }
 
@@ -286,18 +292,23 @@ void
 HMDInfoCardboard::FillDistortionConstants(uint32_t whichEye,
                                           const IntSize& textureSize, const IntRect& eyeViewport,
                                           const Size& destViewport, const Rect& destRect,
                                           VRDistortionConstants& values)
 {
   // these modify the texture coordinates; texcoord * zw + xy
   values.eyeToSourceScaleAndOffset[0] = 0.0;
   values.eyeToSourceScaleAndOffset[1] = 0.0;
-  values.eyeToSourceScaleAndOffset[2] = 1.0;
-  values.eyeToSourceScaleAndOffset[3] = 1.0;
+  if (PR_GetEnv("FAKE_CARDBOARD_SCREEN")) {
+    values.eyeToSourceScaleAndOffset[2] = 2.0;
+    values.eyeToSourceScaleAndOffset[3] = 2.0;
+  } else {
+    values.eyeToSourceScaleAndOffset[2] = 1.0;
+    values.eyeToSourceScaleAndOffset[3] = 1.0;
+  }
 
   // Our mesh positions are in the [-1..1] clip space; we give appropriate offset
   // and scaling for the right viewport.  (In the 0..2 space for sanity)
 
   // this is the destRect in clip space
   float x0 = destRect.x / destViewport.width * 2.0 - 1.0;
   float x1 = (destRect.x + destRect.width) / destViewport.width * 2.0 - 1.0;
 
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVROculus050.cpp
@@ -0,0 +1,562 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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>
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include "prlink.h"
+#include "prmem.h"
+#include "prenv.h"
+#include "gfxPrefs.h"
+#include "nsString.h"
+#include "mozilla/Preferences.h"
+
+#include "gfxVROculus050.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsIScreenManager.h"
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+using namespace ovr050;
+using namespace mozilla::gfx;
+using namespace mozilla::gfx::impl;
+
+namespace {
+
+#ifdef OVR_CAPI_050_LIMITED_MOZILLA
+static pfn_ovr_Initialize ovr_Initialize = nullptr;
+static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
+static pfn_ovrHmd_Detect ovrHmd_Detect = nullptr;
+static pfn_ovrHmd_Create ovrHmd_Create = nullptr;
+static pfn_ovrHmd_Destroy ovrHmd_Destroy = nullptr;
+static pfn_ovrHmd_CreateDebug ovrHmd_CreateDebug = nullptr;
+static pfn_ovrHmd_GetLastError ovrHmd_GetLastError = nullptr;
+static pfn_ovrHmd_AttachToWindow ovrHmd_AttachToWindow = nullptr;
+static pfn_ovrHmd_GetEnabledCaps ovrHmd_GetEnabledCaps = nullptr;
+static pfn_ovrHmd_SetEnabledCaps ovrHmd_SetEnabledCaps = nullptr;
+static pfn_ovrHmd_ConfigureTracking ovrHmd_ConfigureTracking = nullptr;
+static pfn_ovrHmd_RecenterPose ovrHmd_RecenterPose = nullptr;
+static pfn_ovrHmd_GetTrackingState ovrHmd_GetTrackingState = nullptr;
+static pfn_ovrHmd_GetFovTextureSize ovrHmd_GetFovTextureSize = nullptr;
+static pfn_ovrHmd_GetRenderDesc ovrHmd_GetRenderDesc = nullptr;
+static pfn_ovrHmd_CreateDistortionMesh ovrHmd_CreateDistortionMesh = nullptr;
+static pfn_ovrHmd_DestroyDistortionMesh ovrHmd_DestroyDistortionMesh = nullptr;
+static pfn_ovrHmd_GetRenderScaleAndOffset ovrHmd_GetRenderScaleAndOffset = nullptr;
+static pfn_ovrHmd_GetFrameTiming ovrHmd_GetFrameTiming = nullptr;
+static pfn_ovrHmd_BeginFrameTiming ovrHmd_BeginFrameTiming = nullptr;
+static pfn_ovrHmd_EndFrameTiming ovrHmd_EndFrameTiming = nullptr;
+static pfn_ovrHmd_ResetFrameTiming ovrHmd_ResetFrameTiming = nullptr;
+static pfn_ovrHmd_GetEyePoses ovrHmd_GetEyePoses = nullptr;
+static pfn_ovrHmd_GetHmdPosePerEye ovrHmd_GetHmdPosePerEye = nullptr;
+static pfn_ovrHmd_GetEyeTimewarpMatrices ovrHmd_GetEyeTimewarpMatrices = nullptr;
+static pfn_ovrMatrix4f_Projection ovrMatrix4f_Projection = nullptr;
+static pfn_ovrMatrix4f_OrthoSubProjection ovrMatrix4f_OrthoSubProjection = nullptr;
+static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
+
+#ifdef HAVE_64BIT_BUILD
+#define BUILD_BITS 64
+#else
+#define BUILD_BITS 32
+#endif
+
+#define LIBOVR_PRODUCT_VERSION 0
+#define LIBOVR_MAJOR_VERSION   5
+#define LIBOVR_MINOR_VERSION   0
+
+static bool
+InitializeOculusCAPI()
+{
+  static PRLibrary *ovrlib = nullptr;
+
+  if (!ovrlib) {
+    nsTArray<nsCString> libSearchPaths;
+    nsCString libName;
+    nsCString searchPath;
+
+#if defined(_WIN32)
+    static const char dirSep = '\\';
+#else
+    static const char dirSep = '/';
+#endif
+
+#if defined(_WIN32)
+    static const int pathLen = 260;
+    searchPath.SetCapacity(pathLen);
+    int realLen = ::GetSystemDirectoryA(searchPath.BeginWriting(), pathLen);
+    if (realLen != 0 && realLen < pathLen) {
+      searchPath.SetLength(realLen);
+      libSearchPaths.AppendElement(searchPath);
+    }
+    libName.AppendPrintf("LibOVRRT%d_%d_%d.dll", BUILD_BITS, LIBOVR_PRODUCT_VERSION, LIBOVR_MAJOR_VERSION);
+#elif defined(__APPLE__)
+    searchPath.Truncate();
+    searchPath.AppendPrintf("/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", LIBOVR_PRODUCT_VERSION, LIBOVR_MAJOR_VERSION);
+    libSearchPaths.AppendElement(searchPath);
+
+    if (PR_GetEnv("HOME")) {
+      searchPath.Truncate();
+      searchPath.AppendPrintf("%s/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", PR_GetEnv("HOME"), LIBOVR_PRODUCT_VERSION, LIBOVR_MAJOR_VERSION);
+      libSearchPaths.AppendElement(searchPath);
+    }
+    // The following will match the va_list overload of AppendPrintf if the product version is 0
+    // That's bad times.
+    //libName.AppendPrintf("LibOVRRT_%d", LIBOVR_PRODUCT_VERSION);
+    libName.Append("LibOVRRT_");
+    libName.AppendInt(LIBOVR_PRODUCT_VERSION);
+#else
+    libSearchPaths.AppendElement(nsCString("/usr/local/lib"));
+    libSearchPaths.AppendElement(nsCString("/usr/lib"));
+    libName.AppendPrintf("libOVRRT%d_%d.so.%d", BUILD_BITS, LIBOVR_PRODUCT_VERSION, LIBOVR_MAJOR_VERSION);
+#endif
+
+    // If the pref is present, we override libName
+    nsAdoptingCString prefLibPath = mozilla::Preferences::GetCString("dom.vr.ovr_lib_path");
+    if (prefLibPath && prefLibPath.get()) {
+      libSearchPaths.InsertElementsAt(0, 1, prefLibPath);
+    }
+
+    nsAdoptingCString prefLibName = mozilla::Preferences::GetCString("dom.vr.ovr_lib_name");
+    if (prefLibName && prefLibName.get()) {
+      libName.Assign(prefLibName);
+    }
+
+    // search the path/module dir
+    libSearchPaths.InsertElementsAt(0, 1, nsCString());
+
+    // If the env var is present, we override libName
+    if (PR_GetEnv("OVR_LIB_PATH")) {
+      searchPath = PR_GetEnv("OVR_LIB_PATH");
+      libSearchPaths.InsertElementsAt(0, 1, searchPath);
+    }
+
+    if (PR_GetEnv("OVR_LIB_NAME")) {
+      libName = PR_GetEnv("OVR_LIB_NAME");
+    }
+
+    for (uint32_t i = 0; i < libSearchPaths.Length(); ++i) {
+      nsCString& libPath = libSearchPaths[i];
+      nsCString fullName;
+      if (libPath.Length() == 0) {
+        fullName.Assign(libName);
+      } else {
+        fullName.AppendPrintf("%s%c%s", libPath.BeginReading(), dirSep, libName.BeginReading());
+      }
+
+      ovrlib = PR_LoadLibrary(fullName.BeginReading());
+      if (ovrlib)
+        break;
+    }
+
+    if (!ovrlib) {
+      printf_stderr("Failed to load Oculus VR library!\n");
+      return false;
+    }
+  }
+
+  // was it already initialized?
+  if (ovr_Initialize)
+    return true;
+
+#define REQUIRE_FUNCTION(_x) do { \
+    *(void **)&_x = (void *) PR_FindSymbol(ovrlib, #_x);                \
+    if (!_x) { printf_stderr(#_x " symbol missing\n"); goto fail; }       \
+  } while (0)
+
+  REQUIRE_FUNCTION(ovr_Initialize);
+  REQUIRE_FUNCTION(ovr_Shutdown);
+  REQUIRE_FUNCTION(ovrHmd_Detect);
+  REQUIRE_FUNCTION(ovrHmd_Create);
+  REQUIRE_FUNCTION(ovrHmd_Destroy);
+  REQUIRE_FUNCTION(ovrHmd_CreateDebug);
+  REQUIRE_FUNCTION(ovrHmd_GetLastError);
+  REQUIRE_FUNCTION(ovrHmd_AttachToWindow);
+  REQUIRE_FUNCTION(ovrHmd_GetEnabledCaps);
+  REQUIRE_FUNCTION(ovrHmd_SetEnabledCaps);
+  REQUIRE_FUNCTION(ovrHmd_ConfigureTracking);
+  REQUIRE_FUNCTION(ovrHmd_RecenterPose);
+  REQUIRE_FUNCTION(ovrHmd_GetTrackingState);
+
+  REQUIRE_FUNCTION(ovrHmd_GetFovTextureSize);
+  REQUIRE_FUNCTION(ovrHmd_GetRenderDesc);
+  REQUIRE_FUNCTION(ovrHmd_CreateDistortionMesh);
+  REQUIRE_FUNCTION(ovrHmd_DestroyDistortionMesh);
+  REQUIRE_FUNCTION(ovrHmd_GetRenderScaleAndOffset);
+  REQUIRE_FUNCTION(ovrHmd_GetFrameTiming);
+  REQUIRE_FUNCTION(ovrHmd_BeginFrameTiming);
+  REQUIRE_FUNCTION(ovrHmd_EndFrameTiming);
+  REQUIRE_FUNCTION(ovrHmd_ResetFrameTiming);
+  REQUIRE_FUNCTION(ovrHmd_GetEyePoses);
+  REQUIRE_FUNCTION(ovrHmd_GetHmdPosePerEye);
+  REQUIRE_FUNCTION(ovrHmd_GetEyeTimewarpMatrices);
+  REQUIRE_FUNCTION(ovrMatrix4f_Projection);
+  REQUIRE_FUNCTION(ovrMatrix4f_OrthoSubProjection);
+  REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
+
+#undef REQUIRE_FUNCTION
+
+  return true;
+
+ fail:
+  ovr_Initialize = nullptr;
+  return false;
+}
+
+#else
+// we're statically linked; it's available
+static bool InitializeOculusCAPI()
+{
+  return true;
+}
+#endif
+
+ovrFovPort
+ToFovPort(const VRFieldOfView& aFOV)
+{
+  ovrFovPort fovPort;
+  fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
+  fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
+  fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
+  fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
+  return fovPort;
+}
+
+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
+
+HMDInfoOculus050::HMDInfoOculus050(ovrHmd aHMD)
+  : VRHMDInfo(VRHMDType::Oculus050)
+  , mHMD(aHMD)
+  , mStartCount(0)
+{
+  MOZ_ASSERT(sizeof(HMDInfoOculus050::DistortionVertex) == sizeof(VRDistortionVertex),
+             "HMDInfoOculus050::DistortionVertex must match the size of VRDistortionVertex");
+
+  MOZ_COUNT_CTOR_INHERITED(HMDInfoOculus050, VRHMDInfo);
+
+  mDeviceName.AssignLiteral("Oculus VR HMD (0.5.0)");
+
+  mSupportedSensorBits = 0;
+  if (mHMD->TrackingCaps & ovrTrackingCap_Orientation)
+    mSupportedSensorBits |= State_Orientation;
+  if (mHMD->TrackingCaps & ovrTrackingCap_Position)
+    mSupportedSensorBits |= State_Position;
+
+  mRecommendedEyeFOV[Eye_Left] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Left]);
+  mRecommendedEyeFOV[Eye_Right] = FromFovPort(mHMD->DefaultEyeFov[ovrEye_Right]);
+
+  mMaximumEyeFOV[Eye_Left] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Left]);
+  mMaximumEyeFOV[Eye_Right] = FromFovPort(mHMD->MaxEyeFov[ovrEye_Right]);
+
+  SetFOV(mRecommendedEyeFOV[Eye_Left], mRecommendedEyeFOV[Eye_Right], 0.01, 10000.0);
+
+  nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
+  if (screenmgr) {
+#if 1
+    if (getenv("FAKE_OCULUS_SCREEN")) {
+      const char *env = getenv("FAKE_OCULUS_SCREEN");
+      nsresult err;
+      int32_t xcoord = nsCString(env).ToInteger(&err);
+      if (err != NS_OK) xcoord = 0;
+      mScreen = VRHMDManager::MakeFakeScreen(xcoord, 0, 1920, 1080);
+    } else
+#endif
+    {
+      screenmgr->ScreenForRect(mHMD->WindowsPos.x, mHMD->WindowsPos.y,
+                               mHMD->Resolution.w, mHMD->Resolution.h,
+                               getter_AddRefs(mScreen));
+    }
+  }
+}
+
+void
+HMDInfoOculus050::Destroy()
+{
+  if (mHMD) {
+    ovrHmd_Destroy(mHMD);
+    mHMD = nullptr;
+  }
+}
+
+bool
+HMDInfoOculus050::SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
+                      double zNear, double zFar)
+{
+  float pixelsPerDisplayPixel = 1.0;
+  ovrSizei texSize[2];
+
+  uint32_t caps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette; // XXX TODO add TimeWarp
+
+  // get eye parameters and create the mesh
+  for (uint32_t eye = 0; eye < NumEyes; eye++) {
+    mEyeFOV[eye] = eye == 0 ? aFOVLeft : aFOVRight;
+    mFOVPort[eye] = ToFovPort(mEyeFOV[eye]);
+
+    ovrEyeRenderDesc renderDesc = ovrHmd_GetRenderDesc(mHMD, (ovrEyeType) eye, mFOVPort[eye]);
+
+    // these values are negated so that content can add the adjustment to its camera position,
+    // instead of subtracting
+    mEyeTranslation[eye] = Point3D(-renderDesc.HmdToEyeViewOffset.x, -renderDesc.HmdToEyeViewOffset.y, -renderDesc.HmdToEyeViewOffset.z);
+
+    // note that we are using a right-handed coordinate system here, to match CSS
+    mEyeProjectionMatrix[eye] = mEyeFOV[eye].ConstructProjectionMatrix(zNear, zFar, true);
+
+    texSize[eye] = ovrHmd_GetFovTextureSize(mHMD, (ovrEyeType) eye, mFOVPort[eye], pixelsPerDisplayPixel);
+
+    ovrDistortionMesh mesh;
+    bool ok = ovrHmd_CreateDistortionMesh(mHMD, (ovrEyeType) eye, mFOVPort[eye], caps, &mesh);
+    if (!ok)
+      return false;
+
+    mDistortionMesh[eye].mVertices.SetLength(mesh.VertexCount);
+    mDistortionMesh[eye].mIndices.SetLength(mesh.IndexCount);
+
+    ovrDistortionVertex *srcv = mesh.pVertexData;
+    HMDInfoOculus050::DistortionVertex *destv = reinterpret_cast<HMDInfoOculus050::DistortionVertex*>(mDistortionMesh[eye].mVertices.Elements());
+    memset(destv, 0, mesh.VertexCount * sizeof(VRDistortionVertex));
+    for (uint32_t i = 0; i < mesh.VertexCount; ++i) {
+      destv[i].pos[0] = srcv[i].ScreenPosNDC.x;
+      destv[i].pos[1] = srcv[i].ScreenPosNDC.y;
+
+      destv[i].texR[0] = srcv[i].TanEyeAnglesR.x;
+      destv[i].texR[1] = srcv[i].TanEyeAnglesR.y;
+      destv[i].texG[0] = srcv[i].TanEyeAnglesG.x;
+      destv[i].texG[1] = srcv[i].TanEyeAnglesG.y;
+      destv[i].texB[0] = srcv[i].TanEyeAnglesB.x;
+      destv[i].texB[1] = srcv[i].TanEyeAnglesB.y;
+
+      destv[i].genericAttribs[0] = srcv[i].VignetteFactor;
+      destv[i].genericAttribs[1] = srcv[i].TimeWarpFactor;
+    }
+
+    memcpy(mDistortionMesh[eye].mIndices.Elements(), mesh.pIndexData, mesh.IndexCount * sizeof(uint16_t));
+    ovrHmd_DestroyDistortionMesh(&mesh);
+  }
+
+  // take the max of both for eye resolution
+  mEyeResolution.width = std::max(texSize[Eye_Left].w, texSize[Eye_Right].w);
+  mEyeResolution.height = std::max(texSize[Eye_Left].h, texSize[Eye_Right].h);
+
+  mConfiguration.hmdType = mType;
+  mConfiguration.value = 0;
+  mConfiguration.fov[0] = aFOVLeft;
+  mConfiguration.fov[1] = aFOVRight;
+
+  return true;
+}
+
+void
+HMDInfoOculus050::FillDistortionConstants(uint32_t whichEye,
+                                       const IntSize& textureSize,
+                                       const IntRect& eyeViewport,
+                                       const Size& destViewport,
+                                       const Rect& destRect,
+                                       VRDistortionConstants& values)
+{
+  ovrSizei texSize = { textureSize.width, textureSize.height };
+  ovrRecti eyePort = { { eyeViewport.x, eyeViewport.y }, { eyeViewport.width, eyeViewport.height } };
+  ovrVector2f scaleOut[2];
+
+  ovrHmd_GetRenderScaleAndOffset(mFOVPort[whichEye], texSize, eyePort, scaleOut);
+
+  values.eyeToSourceScaleAndOffset[0] = scaleOut[1].x;
+  values.eyeToSourceScaleAndOffset[1] = scaleOut[1].y;
+  values.eyeToSourceScaleAndOffset[2] = scaleOut[0].x;
+  values.eyeToSourceScaleAndOffset[3] = scaleOut[0].y;
+
+  // These values are in clip space [-1..1] range, but we're providing
+  // scaling in the 0..2 space for sanity.
+
+  // this is the destRect in clip space
+  float x0 = destRect.x / destViewport.width * 2.0 - 1.0;
+  float x1 = (destRect.x + destRect.width) / destViewport.width * 2.0 - 1.0;
+
+  float y0 = destRect.y / destViewport.height * 2.0 - 1.0;
+  float y1 = (destRect.y + destRect.height) / destViewport.height * 2.0 - 1.0;
+
+  // offset
+  values.destinationScaleAndOffset[0] = (x0+x1) / 2.0;
+  values.destinationScaleAndOffset[1] = (y0+y1) / 2.0;
+  // scale
+  values.destinationScaleAndOffset[2] = destRect.width / destViewport.width;
+  values.destinationScaleAndOffset[3] = destRect.height / destViewport.height;
+}
+
+bool
+HMDInfoOculus050::StartSensorTracking()
+{
+  if (mStartCount == 0) {
+    bool ok = ovrHmd_ConfigureTracking(mHMD, ovrTrackingCap_Orientation | ovrTrackingCap_Position, 0);
+    if (!ok)
+      return false;
+  }
+
+  mStartCount++;
+  return true;
+}
+
+void
+HMDInfoOculus050::StopSensorTracking()
+{
+  if (--mStartCount == 0) {
+    ovrHmd_ConfigureTracking(mHMD, 0, 0);
+  }
+}
+
+void
+HMDInfoOculus050::ZeroSensor()
+{
+  ovrHmd_RecenterPose(mHMD);
+}
+
+VRHMDSensorState
+HMDInfoOculus050::GetSensorState(double timeOffset)
+{
+  VRHMDSensorState result;
+  result.Clear();
+
+  // XXX this is the wrong time base for timeOffset; we need to figure out how to synchronize
+  // the Oculus time base and the browser one.
+  ovrTrackingState state = ovrHmd_GetTrackingState(mHMD, ovr_GetTimeInSeconds() + timeOffset);
+  ovrPoseStatef& pose(state.HeadPose);
+
+  result.timestamp = pose.TimeInSeconds;
+
+  if (state.StatusFlags & ovrStatus_OrientationTracked) {
+    result.flags |= State_Orientation;
+
+    result.orientation[0] = pose.ThePose.Orientation.x;
+    result.orientation[1] = pose.ThePose.Orientation.y;
+    result.orientation[2] = pose.ThePose.Orientation.z;
+    result.orientation[3] = pose.ThePose.Orientation.w;
+    
+    result.angularVelocity[0] = pose.AngularVelocity.x;
+    result.angularVelocity[1] = pose.AngularVelocity.y;
+    result.angularVelocity[2] = pose.AngularVelocity.z;
+
+    result.angularAcceleration[0] = pose.AngularAcceleration.x;
+    result.angularAcceleration[1] = pose.AngularAcceleration.y;
+    result.angularAcceleration[2] = pose.AngularAcceleration.z;
+  }
+
+  if (state.StatusFlags & ovrStatus_PositionTracked) {
+    result.flags |= State_Position;
+
+    result.position[0] = pose.ThePose.Position.x;
+    result.position[1] = pose.ThePose.Position.y;
+    result.position[2] = pose.ThePose.Position.z;
+    
+    result.linearVelocity[0] = pose.LinearVelocity.x;
+    result.linearVelocity[1] = pose.LinearVelocity.y;
+    result.linearVelocity[2] = pose.LinearVelocity.z;
+
+    result.linearAcceleration[0] = pose.LinearAcceleration.x;
+    result.linearAcceleration[1] = pose.LinearAcceleration.y;
+    result.linearAcceleration[2] = pose.LinearAcceleration.z;
+  }
+
+  return result;
+}
+
+bool
+VRHMDManagerOculus050::PlatformInit()
+{
+  if (mOculusPlatformInitialized)
+    return true;
+
+  if (!gfxPrefs::VREnabled())
+    return false;
+
+  if (!InitializeOculusCAPI())
+    return false;
+
+  ovrInitParams params;
+  params.Flags = ovrInit_RequestVersion;
+  params.RequestedMinorVersion = LIBOVR_MINOR_VERSION;
+  params.LogCallback = nullptr;
+  params.ConnectionTimeoutMS = 0;
+
+  bool ok = ovr_Initialize(&params);
+
+  if (!ok)
+    return false;
+
+  mOculusPlatformInitialized = true;
+  return true;
+}
+
+bool
+VRHMDManagerOculus050::Init()
+{
+  if (mOculusInitialized)
+    return true;
+
+  if (!PlatformInit())
+    return false;
+
+  int count = ovrHmd_Detect();
+
+  for (int i = 0; i < count; ++i) {
+    ovrHmd hmd = ovrHmd_Create(i);
+    if (hmd) {
+      nsRefPtr<HMDInfoOculus050> oc = new HMDInfoOculus050(hmd);
+      mOculusHMDs.AppendElement(oc);
+    }
+  }
+
+  // VRAddTestDevices == 1: add test device only if no real devices present
+  // VRAddTestDevices == 2: add test device always
+  if ((count == 0 && gfxPrefs::VRAddTestDevices() == 1) ||
+      (gfxPrefs::VRAddTestDevices() == 2))
+  {
+    ovrHmd hmd = ovrHmd_CreateDebug(ovrHmd_DK2);
+    if (hmd) {
+      nsRefPtr<HMDInfoOculus050> oc = new HMDInfoOculus050(hmd);
+      mOculusHMDs.AppendElement(oc);
+    }
+  }
+
+  mOculusInitialized = true;
+  return true;
+}
+
+void
+VRHMDManagerOculus050::Destroy()
+{
+  if (!mOculusInitialized)
+    return;
+
+  for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
+    mOculusHMDs[i]->Destroy();
+  }
+
+  mOculusHMDs.Clear();
+
+  ovr_Shutdown();
+  mOculusInitialized = false;
+}
+
+void
+VRHMDManagerOculus050::GetHMDs(nsTArray<nsRefPtr<VRHMDInfo>>& aHMDResult)
+{
+  Init();
+  for (size_t i = 0; i < mOculusHMDs.Length(); ++i) {
+    aHMDResult.AppendElement(mOculusHMDs[i]);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVROculus050.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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_OCULUS_050_H
+#define GFX_VR_OCULUS_050_H
+
+#include "nsTArray.h"
+#include "nsIScreen.h"
+#include "nsCOMPtr.h"
+#include "mozilla/nsRefPtr.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/EnumeratedArray.h"
+
+#include "gfxVR.h"
+#include "ovr_capi_dynamic050.h"
+
+namespace mozilla {
+namespace gfx {
+namespace impl {
+
+class HMDInfoOculus050 : public VRHMDInfo {
+public:
+  explicit HMDInfoOculus050(ovr050::ovrHmd aHMD);
+
+  bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
+              double zNear, double zFar) override;
+
+  bool StartSensorTracking() override;
+  VRHMDSensorState GetSensorState(double timeOffset) override;
+  void StopSensorTracking() override;
+  void ZeroSensor() override;
+
+  void FillDistortionConstants(uint32_t whichEye,
+                               const IntSize& textureSize, const IntRect& eyeViewport,
+                               const Size& destViewport, const Rect& destRect,
+                               VRDistortionConstants& values) override;
+
+  void Destroy();
+
+protected:
+  // must match the size of VRDistortionVertex
+  struct DistortionVertex {
+    float pos[2];
+    float texR[2];
+    float texG[2];
+    float texB[2];
+    float genericAttribs[4];
+  };
+
+  virtual ~HMDInfoOculus050() {
+      Destroy();
+      MOZ_COUNT_DTOR_INHERITED(HMDInfoOculus050, VRHMDInfo);
+  }
+
+  ovr050::ovrHmd mHMD;
+  ovr050::ovrFovPort mFOVPort[2];
+  uint32_t mStartCount;
+};
+
+} // namespace impl
+
+class VRHMDManagerOculus050 : public VRHMDManager
+{
+public:
+  VRHMDManagerOculus050()
+    : mOculusInitialized(false), mOculusPlatformInitialized(false)
+  { }
+
+  virtual bool PlatformInit() override;
+  virtual bool Init() override;
+  virtual void Destroy() override;
+  virtual void GetHMDs(nsTArray<nsRefPtr<VRHMDInfo> >& aHMDResult) override;
+protected:
+  nsTArray<nsRefPtr<impl::HMDInfoOculus050>> mOculusHMDs;
+  bool mOculusInitialized;
+  bool mOculusPlatformInitialized;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* GFX_VR_OCULUS_050_H */
--- a/gfx/vr/moz.build
+++ b/gfx/vr/moz.build
@@ -13,16 +13,20 @@ LOCAL_INCLUDES += [
 ]
 
 UNIFIED_SOURCES += [
     'gfxVR.cpp',
     'gfxVRCardboard.cpp',
     'gfxVROculus.cpp',
 ]
 
+SOURCES += [
+    'gfxVROculus050.cpp',
+]
+
 # For building with the real SDK instead of our local hack
 #SOURCES += [
 #    'OVR_CAPI_Util.cpp',
 #    'OVR_CAPIShim.c',
 #    'OVR_StereoProjection.cpp',
 #]
 #
 #CXXFLAGS += ["-Ic:/proj/ovr/OculusSDK-0.6.0-beta/LibOVR/Include"]
new file mode 100644
--- /dev/null
+++ b/gfx/vr/ovr_capi_dynamic050.h
@@ -0,0 +1,284 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* 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/. */
+
+/* This file contains just the needed struct definitions for
+ * interacting with the Oculus VR C API, without needing to #include
+ * OVR_CAPI.h directly.  Note that it uses the same type names as the
+ * CAPI, and cannot be #included at the same time as OVR_CAPI.h.  It
+ * does not include the entire C API, just want's needed.
+ */
+
+#ifndef mozilla_ovr_capi_dynamic050_h_
+#define mozilla_ovr_capi_dynamic050_h_
+
+#define OVR_CAPI_050_LIMITED_MOZILLA 1
+
+#if defined(_WIN32)
+#define OVR_PFN __cdecl
+#else
+#define OVR_PFN
+#endif
+
+#if !defined(OVR_ALIGNAS)
+#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 408) && (defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L))
+#define OVR_ALIGNAS(n) alignas(n)
+#elif defined(__clang__) && !defined(__APPLE__) && (((__clang_major__ * 100) + __clang_minor__) >= 300) && (__cplusplus >= 201103L)
+#define OVR_ALIGNAS(n) alignas(n)
+#elif defined(__clang__) && defined(__APPLE__) && (((__clang_major__ * 100) + __clang_minor__) >= 401) && (__cplusplus >= 201103L)
+#define OVR_ALIGNAS(n) alignas(n)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1900)
+#define OVR_ALIGNAS(n) alignas(n)
+#elif defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408)
+#define OVR_ALIGNAS(n) alignas(n)
+#elif defined(__GNUC__) || defined(__clang__)
+#define OVR_ALIGNAS(n) __attribute__((aligned(n)))
+#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
+#define OVR_ALIGNAS(n) __declspec(align(n))
+#else
+#error Need to define OVR_ALIGNAS
+#endif
+#endif
+
+namespace ovr050 {
+
+typedef char ovrBool;
+typedef struct { int x, y; } ovrVector2i;
+typedef struct { int w, h; } ovrSizei;
+typedef struct { ovrVector2i Pos; ovrSizei Size; } ovrRecti;
+typedef struct { float x, y, z, w; } ovrQuatf;
+typedef struct { float x, y; } ovrVector2f;
+typedef struct { float x, y, z; } ovrVector3f;
+typedef struct { float M[4][4]; } ovrMatrix4f;
+
+typedef struct {
+  ovrQuatf Orientation;
+  ovrVector3f Position;
+} ovrPosef;
+
+typedef struct OVR_ALIGNAS(8) {
+  ovrPosef ThePose;
+  ovrVector3f AngularVelocity;
+  ovrVector3f LinearVelocity;
+  ovrVector3f AngularAcceleration;
+  ovrVector3f LinearAcceleration;
+  float       Pad;
+  double      TimeInSeconds;
+} ovrPoseStatef;
+
+typedef struct {
+  float UpTan;
+  float DownTan;
+  float LeftTan;
+  float RightTan;
+} ovrFovPort;
+
+typedef enum {
+  ovrHmd_None             = 0,    
+  ovrHmd_DK1              = 3,
+  ovrHmd_DKHD             = 4,
+  ovrHmd_DK2              = 6,
+  ovrHmd_BlackStar        = 7,
+  ovrHmd_CB               = 8,
+  ovrHmd_Other            = 9,
+  ovrHmd_EnumSize         = 0x7fffffff
+} ovrHmdType;
+
+typedef enum {
+  ovrHmdCap_Present           = 0x0001,
+  ovrHmdCap_Available         = 0x0002,
+  ovrHmdCap_Captured          = 0x0004,
+  ovrHmdCap_ExtendDesktop     = 0x0008,
+  ovrHmdCap_DebugDevice       = 0x0010,
+  ovrHmdCap_DisplayOff        = 0x0040,
+  ovrHmdCap_LowPersistence    = 0x0080,
+  ovrHmdCap_DynamicPrediction = 0x0200,
+  ovrHmdCap_NoVSync           = 0x1000,
+  ovrHmdCap_NoMirrorToWindow  = 0x2000
+} ovrHmdCapBits;
+
+typedef enum
+{
+  ovrTrackingCap_Orientation      = 0x0010,
+  ovrTrackingCap_MagYawCorrection = 0x0020,
+  ovrTrackingCap_Position         = 0x0040,
+  ovrTrackingCap_Idle             = 0x0100,
+  ovrTrackingCap_EnumSize         = 0x7fffffff
+} ovrTrackingCaps;
+
+typedef enum {
+  ovrDistortionCap_Chromatic = 0x01,
+  ovrDistortionCap_TimeWarp  = 0x02,
+  ovrDistortionCap_Vignette  = 0x08,
+  ovrDistortionCap_NoRestore = 0x10,
+  ovrDistortionCap_FlipInput = 0x20,
+  ovrDistortionCap_SRGB      = 0x40,
+  ovrDistortionCap_Overdrive = 0x80,
+  ovrDistortionCap_HqDistortion = 0x100,
+  ovrDistortionCap_LinuxDevFullscreen = 0x200,
+  ovrDistortionCap_ComputeShader = 0x400,
+  ovrDistortionCap_TimewarpJitDelay = 0x1000,
+  ovrDistortionCap_ProfileNoSpinWaits = 0x10000,
+  ovrDistortionCap_EnumSize = 0x7fffffff
+} ovrDistortionCaps;
+
+typedef enum {
+  ovrEye_Left  = 0,
+  ovrEye_Right = 1,
+  ovrEye_Count = 2,
+  ovrEye_EnumSize = 0x7fffffff
+} ovrEyeType;
+
+typedef struct ovrHmdDesc_ {
+  void* Handle;
+  ovrHmdType  Type;
+  const char* ProductName;    
+  const char* Manufacturer;
+  short VendorId;
+  short ProductId;
+  char SerialNumber[24];
+  short FirmwareMajor;
+  short FirmwareMinor;
+  float CameraFrustumHFovInRadians;
+  float CameraFrustumVFovInRadians;
+  float CameraFrustumNearZInMeters;
+  float CameraFrustumFarZInMeters;
+
+  unsigned int HmdCaps;
+  unsigned int TrackingCaps;
+  unsigned int DistortionCaps;
+
+  ovrFovPort  DefaultEyeFov[ovrEye_Count];
+  ovrFovPort  MaxEyeFov[ovrEye_Count];
+  ovrEyeType  EyeRenderOrder[ovrEye_Count];
+
+  ovrSizei    Resolution;
+  ovrVector2i WindowsPos;
+
+  const char* DisplayDeviceName;
+  int         DisplayId;
+} ovrHmdDesc;
+
+typedef const ovrHmdDesc* ovrHmd;
+
+typedef enum {
+  ovrStatus_OrientationTracked    = 0x0001,
+  ovrStatus_PositionTracked       = 0x0002,
+  ovrStatus_CameraPoseTracked     = 0x0004,
+  ovrStatus_PositionConnected     = 0x0020,
+  ovrStatus_HmdConnected          = 0x0080,
+  ovrStatus_EnumSize              = 0x7fffffff
+} ovrStatusBits;
+
+typedef struct ovrSensorData_ {
+  ovrVector3f    Accelerometer;
+  ovrVector3f    Gyro;
+  ovrVector3f    Magnetometer;
+  float          Temperature;
+  float          TimeInSeconds;
+} ovrSensorData;
+
+
+typedef struct ovrTrackingState_ {
+  ovrPoseStatef HeadPose;
+  ovrPosef CameraPose;
+  ovrPosef LeveledCameraPose;
+  ovrSensorData RawSensorData;
+  unsigned int StatusFlags;
+  double LastVisionProcessingTime;
+  uint32_t LastCameraFrameCounter;
+  uint32_t Pad;
+} ovrTrackingState;
+
+typedef struct OVR_ALIGNAS(8) ovrFrameTiming_ {
+  float DeltaSeconds;
+  float Pad; 
+  double ThisFrameSeconds;
+  double TimewarpPointSeconds;
+  double NextFrameSeconds;
+  double ScanoutMidpointSeconds;
+  double EyeScanoutSeconds[2];    
+} ovrFrameTiming;
+
+typedef struct ovrEyeRenderDesc_ {
+  ovrEyeType  Eye;
+  ovrFovPort  Fov;
+  ovrRecti DistortedViewport;
+  ovrVector2f PixelsPerTanAngleAtCenter;
+  ovrVector3f HmdToEyeViewOffset;
+} ovrEyeRenderDesc;
+
+typedef struct ovrDistortionVertex_ {
+  ovrVector2f ScreenPosNDC;
+  float       TimeWarpFactor;
+  float       VignetteFactor;
+  ovrVector2f TanEyeAnglesR;
+  ovrVector2f TanEyeAnglesG;
+  ovrVector2f TanEyeAnglesB;    
+} ovrDistortionVertex;
+
+typedef struct ovrDistortionMesh_ {
+  ovrDistortionVertex* pVertexData;
+  unsigned short*      pIndexData;
+  unsigned int         VertexCount;
+  unsigned int         IndexCount;
+} ovrDistortionMesh;
+
+typedef enum {
+  ovrInit_Debug          = 0x00000001,
+  ovrInit_ServerOptional = 0x00000002,
+  ovrInit_RequestVersion = 0x00000004,
+  ovrInit_ForceNoDebug   = 0x00000008
+} ovrInitFlags;
+
+typedef enum {
+  ovrLogLevel_Debug = 0,
+  ovrLogLevel_Info  = 1,
+  ovrLogLevel_Error = 2
+} ovrLogLevel;
+
+typedef void (OVR_PFN *ovrLogCallback)(int level, const char* message);
+
+typedef struct {
+  uint32_t Flags;
+  uint32_t RequestedMinorVersion;
+  ovrLogCallback LogCallback;
+  uint32_t ConnectionTimeoutMS;
+} ovrInitParams;
+
+extern "C" {
+
+typedef ovrBool (OVR_PFN *pfn_ovr_Initialize)(ovrInitParams const* params);
+typedef void (OVR_PFN *pfn_ovr_Shutdown)();
+typedef int (OVR_PFN *pfn_ovrHmd_Detect)();
+typedef ovrHmd (OVR_PFN *pfn_ovrHmd_Create)(int index);
+typedef void (OVR_PFN *pfn_ovrHmd_Destroy)(ovrHmd hmd);
+typedef ovrHmd (OVR_PFN *pfn_ovrHmd_CreateDebug)(ovrHmdType type);
+typedef const char* (OVR_PFN *pfn_ovrHmd_GetLastError)(ovrHmd hmd);
+typedef ovrBool (OVR_PFN *pfn_ovrHmd_AttachToWindow)(ovrHmd hmd, void* window, const ovrRecti* destMirrorRect, const ovrRecti* sourceRenderTargetRect);
+typedef unsigned int (OVR_PFN *pfn_ovrHmd_GetEnabledCaps)(ovrHmd hmd);
+typedef void (OVR_PFN *pfn_ovrHmd_SetEnabledCaps)(ovrHmd hmd, unsigned int hmdCaps);
+typedef ovrBool (OVR_PFN *pfn_ovrHmd_ConfigureTracking)(ovrHmd hmd, unsigned int supportedTrackingCaps, unsigned int requiredTrackingCaps); 
+typedef void (OVR_PFN *pfn_ovrHmd_RecenterPose)(ovrHmd hmd);
+typedef ovrTrackingState (OVR_PFN *pfn_ovrHmd_GetTrackingState)(ovrHmd hmd, double absTime);
+typedef ovrSizei (OVR_PFN *pfn_ovrHmd_GetFovTextureSize)(ovrHmd hmd, ovrEyeType eye, ovrFovPort fov, float pixelsPerDisplayPixel);
+typedef ovrEyeRenderDesc (OVR_PFN *pfn_ovrHmd_GetRenderDesc)(ovrHmd hmd, ovrEyeType eyeType, ovrFovPort fov);
+typedef ovrBool (OVR_PFN *pfn_ovrHmd_CreateDistortionMesh)(ovrHmd hmd, ovrEyeType eyeType, ovrFovPort fov, unsigned int distortionCaps, ovrDistortionMesh *meshData);
+typedef void (OVR_PFN *pfn_ovrHmd_DestroyDistortionMesh)(ovrDistortionMesh* meshData);
+typedef void (OVR_PFN *pfn_ovrHmd_GetRenderScaleAndOffset)(ovrFovPort fov, ovrSizei textureSize, ovrRecti renderViewport, ovrVector2f uvScaleOffsetOut[2]);
+typedef ovrFrameTiming (OVR_PFN *pfn_ovrHmd_GetFrameTiming)(ovrHmd hmd, unsigned int frameIndex);
+typedef ovrFrameTiming (OVR_PFN *pfn_ovrHmd_BeginFrameTiming)(ovrHmd hmd, unsigned int frameIndex);
+typedef void (OVR_PFN *pfn_ovrHmd_EndFrameTiming)(ovrHmd hmd);
+typedef void (OVR_PFN *pfn_ovrHmd_ResetFrameTiming)(ovrHmd hmd, unsigned int frameIndex, bool vsync);
+typedef void (OVR_PFN *pfn_ovrHmd_GetEyePoses)(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState);
+typedef ovrPosef (OVR_PFN *pfn_ovrHmd_GetHmdPosePerEye)(ovrHmd hmd, ovrEyeType eye);
+typedef void (OVR_PFN *pfn_ovrHmd_GetEyeTimewarpMatrices)(ovrHmd hmd, ovrEyeType eye, ovrPosef renderPose, ovrMatrix4f twmOut[2]);
+typedef ovrMatrix4f (OVR_PFN *pfn_ovrMatrix4f_Projection) (ovrFovPort fov, float znear, float zfar, ovrBool rightHanded );
+typedef ovrMatrix4f (OVR_PFN *pfn_ovrMatrix4f_OrthoSubProjection) (ovrFovPort fov, ovrVector2f orthoScale, float orthoDistance, float eyeViewAdjustX);
+typedef double (OVR_PFN *pfn_ovr_GetTimeInSeconds)();
+
+} // extern "C"
+} // namespace ovr050
+
+#endif /* mozilla_ovr_capi_dynamic050_h_ */