Bug 1341423 - Integrate OpenVR binding library r=daoshengmu
authorKearwood Gilbert <kgilbert@mozilla.com>
Mon, 27 Feb 2017 16:59:30 -0800
changeset 403004 1a6f70f0488dd6dccf9716b771623d12ce856973
parent 403003 8d081bf9b8399146949f67da496c287c67cd3317
child 403005 021e1f76a70fe2428adce3f8758d65362d0bbea7
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdaoshengmu
bugs1341423
milestone55.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 1341423 - Integrate OpenVR binding library r=daoshengmu MozReview-Commit-ID: GaUnfbXgh9L
.clang-format-ignore
gfx/thebes/gfxPrefs.h
gfx/vr/VRManager.cpp
gfx/vr/gfxVROpenVR.cpp
gfx/vr/gfxVROpenVR.h
gfx/vr/moz.build
gfx/vr/openvr/README
gfx/vr/openvr/README.md
gfx/vr/openvr/README.mozilla
gfx/vr/openvr/headers/openvr.h
gfx/vr/openvr/moz.build
gfx/vr/openvr/openvr.h
gfx/vr/openvr/src/README
gfx/vr/openvr/src/dirtools_public.cpp
gfx/vr/openvr/src/dirtools_public.h
gfx/vr/openvr/src/envvartools_public.cpp
gfx/vr/openvr/src/envvartools_public.h
gfx/vr/openvr/src/hmderrors_public.cpp
gfx/vr/openvr/src/hmderrors_public.h
gfx/vr/openvr/src/ivrclientcore.h
gfx/vr/openvr/src/openvr_api_public.cpp
gfx/vr/openvr/src/pathtools_public.cpp
gfx/vr/openvr/src/pathtools_public.h
gfx/vr/openvr/src/sharedlibtools_public.cpp
gfx/vr/openvr/src/sharedlibtools_public.h
gfx/vr/openvr/src/strtools_public.cpp
gfx/vr/openvr/src/strtools_public.h
gfx/vr/openvr/src/vrpathregistry_public.cpp
gfx/vr/openvr/src/vrpathregistry_public.h
modules/libpref/init/all.js
tools/rewriting/ThirdPartyPaths.txt
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -20,16 +20,17 @@
 ^gfx/2d/image_operations.*
 ^gfx/angle/.*
 ^gfx/cairo/.*
 ^gfx/graphite2/.*
 ^gfx/harfbuzz/.*
 ^gfx/ots/.*
 ^gfx/qcms/.*
 ^gfx/skia/.*
+^gfx/vr/openvr/.*
 ^gfx/webrender.*
 ^gfx/webrender_traits.*
 ^gfx/ycbcr/.*
 ^intl/hyphenation/hyphen/.*
 ^intl/icu/.*
 ^ipc/chromium/.*
 ^js/src/ctypes/libffi/.*
 ^js/src/dtoa.c.*
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -448,17 +448,16 @@ private:
 
   // These times should be in milliseconds
   DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold",    TouchResampleVsyncDelayThreshold, int32_t, 20);
   DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict",        TouchResampleMaxPredict, int32_t, 8);
   DECL_GFX_PREF(Once, "gfx.touch.resample.min-delta",          TouchResampleMinDelta, int32_t, 2);
   DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5);
 
-  DECL_GFX_PREF(Once, "gfx.vr.openvr-runtime",                 VROpenVRRuntime, std::string, "");
   DECL_GFX_PREF(Live, "gfx.vsync.collect-scroll-transforms",   CollectScrollTransforms, bool, false);
   DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count",  CompositorUnobserveCount, int32_t, 10);
   DECL_GFX_PREF(Live, "gfx.webrender.profiler.enable",         WebRenderProfilerEnabled, bool, false);
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
   DECL_GFX_PREF(Once, "gfx.screen-mirroring.enabled",          ScreenMirroringEnabled, bool, false);
 
   DECL_GFX_PREF(Live, "gl.ignore-dx-interop2-blacklist",       IgnoreDXInterop2Blacklist, bool, false);
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -2,27 +2,27 @@
  * 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 "VRManager.h"
 #include "VRManagerParent.h"
 #include "gfxVR.h"
-#include "gfxVROpenVR.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/VRDisplay.h"
 #include "mozilla/dom/GamepadEventTypes.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/Unused.h"
 
 #include "gfxPrefs.h"
 #include "gfxVR.h"
 #if defined(XP_WIN)
 #include "gfxVROculus.h"
+#include "gfxVROpenVR.h"
 #endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
 #include "gfxVROSVR.h"
 #endif
 #include "gfxVRPuppet.h"
 #include "ipc/VRLayerParent.h"
 
 using namespace mozilla;
@@ -70,25 +70,24 @@ VRManager::VRManager()
    */
 
 #if defined(XP_WIN)
   // The Oculus runtime is supported only on Windows
   mgr = VRSystemManagerOculus::Create();
   if (mgr) {
     mManagers.AppendElement(mgr);
   }
-#endif
-
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
-  // OpenVR is cross platform compatible
+  // OpenVR is cross platform compatible, but supported only on Windows for now
   mgr = VRSystemManagerOpenVR::Create();
   if (mgr) {
     mManagers.AppendElement(mgr);
   }
+#endif
 
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
   // OSVR is cross platform compatible
   mgr = VRSystemManagerOSVR::Create();
   if (mgr) {
       mManagers.AppendElement(mgr);
   }
 #endif
   // Enable gamepad extensions while VR is enabled.
   // Preference only can be set at the Parent process.
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -15,87 +15,40 @@
 #include "mozilla/gfx/Quaternion.h"
 
 #ifdef XP_WIN
 #include "CompositorD3D11.h"
 #include "TextureD3D11.h"
 #endif // XP_WIN
 
 #include "gfxVROpenVR.h"
+#include "VRManager.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsIScreenManager.h"
 
+#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/dom/GamepadEventTypes.h"
 #include "mozilla/dom/GamepadBinding.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;
 
-namespace {
-extern "C" {
-typedef uint32_t (VR_CALLTYPE * pfn_VR_InitInternal)(::vr::HmdError *peError, ::vr::EVRApplicationType eApplicationType);
-typedef void (VR_CALLTYPE * pfn_VR_ShutdownInternal)();
-typedef bool (VR_CALLTYPE * pfn_VR_IsHmdPresent)();
-typedef bool (VR_CALLTYPE * pfn_VR_IsRuntimeInstalled)();
-typedef const char * (VR_CALLTYPE * pfn_VR_GetStringForHmdError)(::vr::HmdError error);
-typedef void * (VR_CALLTYPE * pfn_VR_GetGenericInterface)(const char *pchInterfaceVersion, ::vr::HmdError *peError);
-} // extern "C"
-} // namespace
-
-static pfn_VR_InitInternal vr_InitInternal = nullptr;
-static pfn_VR_ShutdownInternal vr_ShutdownInternal = nullptr;
-static pfn_VR_IsHmdPresent vr_IsHmdPresent = nullptr;
-static pfn_VR_IsRuntimeInstalled vr_IsRuntimeInstalled = nullptr;
-static pfn_VR_GetStringForHmdError vr_GetStringForHmdError = nullptr;
-static pfn_VR_GetGenericInterface vr_GetGenericInterface = nullptr;
-
 #define BTN_MASK_FROM_ID(_id) \
   vr::ButtonMaskFromId(vr::EVRButtonId::_id)
 
 static const uint32_t kNumOpenVRHaptcs = 1;
 
-
-bool
-LoadOpenVRRuntime()
-{
-  static PRLibrary *openvrLib = nullptr;
-  std::string openvrPath = gfxPrefs::VROpenVRRuntime();
-
-  if (!openvrPath.c_str())
-    return false;
-
-  openvrLib = PR_LoadLibrary(openvrPath.c_str());
-  if (!openvrLib)
-    return false;
-
-#define REQUIRE_FUNCTION(_x) do {                                       \
-    *(void **)&vr_##_x = (void *) PR_FindSymbol(openvrLib, "VR_" #_x);  \
-    if (!vr_##_x) { printf_stderr("VR_" #_x " symbol missing\n"); return false; } \
-  } while (0)
-
-  REQUIRE_FUNCTION(InitInternal);
-  REQUIRE_FUNCTION(ShutdownInternal);
-  REQUIRE_FUNCTION(IsHmdPresent);
-  REQUIRE_FUNCTION(IsRuntimeInstalled);
-  REQUIRE_FUNCTION(GetStringForHmdError);
-  REQUIRE_FUNCTION(GetGenericInterface);
-
-#undef REQUIRE_FUNCTION
-
-  return true;
-}
-
 VRDisplayOpenVR::VRDisplayOpenVR(::vr::IVRSystem *aVRSystem,
                                  ::vr::IVRChaperone *aVRChaperone,
                                  ::vr::IVRCompositor *aVRCompositor)
   : VRDisplayHost(VRDeviceType::OpenVR)
   , mVRSystem(aVRSystem)
   , mVRChaperone(aVRChaperone)
   , mVRCompositor(aVRCompositor)
   , mIsPresenting(false)
@@ -147,17 +100,17 @@ VRDisplayOpenVR::~VRDisplayOpenVR()
   Destroy();
   MOZ_COUNT_DTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost);
 }
 
 void
 VRDisplayOpenVR::Destroy()
 {
   StopPresentation();
-  vr_ShutdownInternal();
+  ::vr::VR_Shutdown();
 }
 
 void
 VRDisplayOpenVR::UpdateStageParameters()
 {
   float sizeX = 0.0f;
   float sizeZ = 0.0f;
   if (mVRChaperone->GetPlayAreaSize(&sizeX, &sizeZ)) {
@@ -339,17 +292,17 @@ VRDisplayOpenVR::SubmitFrame(TextureSour
   const gfx::Rect& aRightEyeRect)
 {
   if (!mIsPresenting) {
     return;
   }
 
   ::vr::Texture_t tex;
   tex.handle = (void *)aSource->GetD3D11Texture();
-  tex.eType = ::vr::EGraphicsAPIConvention::API_DirectX;
+  tex.eType = ::vr::ETextureType::TextureType_DirectX;
   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;
 
@@ -378,17 +331,17 @@ VRDisplayOpenVR::SubmitFrame(TextureSour
 }
 
 #endif
 
 void
 VRDisplayOpenVR::NotifyVSync()
 {
   // We update mIsConneced once per frame.
-  mDisplayInfo.mIsConnected = vr_IsHmdPresent();
+  mDisplayInfo.mIsConnected = ::vr::VR_IsHmdPresent();
 
   // Make sure we respond to OpenVR events even when not presenting
   PollEvents();
 }
 
 VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButtons,
                                        uint32_t aNumAxes, vr::ETrackedDeviceClass aDeviceType)
   : VRControllerHost(VRDeviceType::OpenVR)
@@ -549,21 +502,17 @@ VRSystemManagerOpenVR::VRSystemManagerOp
 VRSystemManagerOpenVR::Create()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
     return nullptr;
   }
 
-  if (!LoadOpenVRRuntime()) {
-    return nullptr;
-  }
-
-  if (!vr_IsRuntimeInstalled()) {
+  if (!::vr::VR_IsRuntimeInstalled()) {
     return nullptr;
   }
 
   RefPtr<VRSystemManagerOpenVR> manager = new VRSystemManagerOpenVR();
   return manager.forget();
 }
 
 void
@@ -580,41 +529,41 @@ VRSystemManagerOpenVR::Shutdown()
   }
   RemoveControllers();
   mVRSystem = nullptr;
 }
 
 void
 VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
 {
-  if (!vr_IsHmdPresent()) {
+  if (!::vr::VR_IsHmdPresent()) {
     if (mOpenVRHMD) {
       mOpenVRHMD = nullptr;
     }
   } else if (mOpenVRHMD == nullptr) {
     ::vr::HmdError err;
 
-    vr_InitInternal(&err, ::vr::EVRApplicationType::VRApplication_Scene);
+    ::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
     if (err) {
       return;
     }
 
-    ::vr::IVRSystem *system = (::vr::IVRSystem *)vr_GetGenericInterface(::vr::IVRSystem_Version, &err);
+    ::vr::IVRSystem *system = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
     if (err || !system) {
-      vr_ShutdownInternal();
+      ::vr::VR_Shutdown();
       return;
     }
-    ::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)vr_GetGenericInterface(::vr::IVRChaperone_Version, &err);
+    ::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
     if (err || !chaperone) {
-      vr_ShutdownInternal();
+      ::vr::VR_Shutdown();
       return;
     }
-    ::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)vr_GetGenericInterface(::vr::IVRCompositor_Version, &err);
+    ::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
     if (err || !compositor) {
-      vr_ShutdownInternal();
+      ::vr::VR_Shutdown();
       return;
     }
 
     mVRSystem = system;
     mOpenVRHMD = new VRDisplayOpenVR(system, chaperone, compositor);
   }
 
   if (mOpenVRHMD) {
@@ -654,17 +603,17 @@ VRSystemManagerOpenVR::HandleInput()
     controller = mOpenVRController[i];
     const uint32_t trackedIndex = controller->GetTrackedIndex();
 
     MOZ_ASSERT(mVRSystem->GetTrackedDeviceClass(trackedIndex)
                == vr::TrackedDeviceClass_Controller ||
                mVRSystem->GetTrackedDeviceClass(trackedIndex)
                == vr::TrackedDeviceClass_GenericTracker);
 
-    if (mVRSystem->GetControllerState(trackedIndex, &state)) {
+    if (mVRSystem->GetControllerState(trackedIndex, &state, sizeof(state))) {
       for (uint32_t j = 0; j < vr::k_unControllerStateAxisCount; ++j) {
         const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty(
                                    trackedIndex,
                                    static_cast<vr::TrackedDeviceProperty>(
                                    vr::Prop_Axis0Type_Int32 + j));
         switch (axisType) {
           case vr::EVRControllerAxisType::k_eControllerAxis_Joystick:
           case vr::EVRControllerAxisType::k_eControllerAxis_TrackPad:
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -9,26 +9,19 @@
 #include "nsTArray.h"
 #include "nsIScreen.h"
 #include "nsCOMPtr.h"
 #include "mozilla/RefPtr.h"
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/EnumeratedArray.h"
 
-#include "openvr/openvr.h"
+#include "openvr.h"
 #include "gfxVR.h"
-
-// OpenVR Interfaces
-namespace vr {
-class IVRChaperone;
-class IVRCompositor;
-class IVRSystem;
-struct TrackedDevicePose_t;
-}
+#include "VRDisplayHost.h"
 
 namespace mozilla {
 namespace gfx {
 namespace impl {
 
 class VRDisplayOpenVR : public VRDisplayHost
 {
 public:
--- a/gfx/vr/moz.build
+++ b/gfx/vr/moz.build
@@ -18,32 +18,35 @@ EXPORTS += [
 LOCAL_INCLUDES += [
     '/dom/base',
     '/gfx/layers/d3d11',
     '/gfx/thebes',
 ]
 
 UNIFIED_SOURCES += [
     'gfxVR.cpp',
-    'gfxVROpenVR.cpp',
     'gfxVROSVR.cpp',
     'gfxVRPuppet.cpp',
     'ipc/VRLayerChild.cpp',
     'ipc/VRLayerParent.cpp',
     'ipc/VRManagerChild.cpp',
     'ipc/VRManagerParent.cpp',
     'VRDisplayClient.cpp',
     'VRDisplayHost.cpp',
     'VRDisplayPresentation.cpp',
     'VRManager.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    DIRS += [
+        'openvr',
+    ]
     SOURCES += [
         'gfxVROculus.cpp',
+        'gfxVROpenVR.cpp',
     ]
 
 IPDL_SOURCES = [
     'ipc/PVRLayer.ipdl',
     'ipc/PVRManager.ipdl',
 ]
 
 # For building with the real SDK instead of our local hack
deleted file mode 100644
--- a/gfx/vr/openvr/README
+++ /dev/null
@@ -1,2 +0,0 @@
-See https://github.com/ValveSoftware/openvr/
-
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/README.md
@@ -0,0 +1,13 @@
+OpenVR SDK
+---
+
+OpenVR is an API and runtime that allows access to VR hardware from multiple 
+vendors without requiring that applications have specific knowledge of the 
+hardware they are targeting. This repository is an SDK that contains the API 
+and samples. The runtime is under SteamVR in Tools on Steam. 
+
+### Documentation
+
+Documentation for the API is available on the [Github Wiki](https://github.com/ValveSoftware/openvr/wiki/API-Documentation)
+
+More information on OpenVR and SteamVR can be found on http://steamvr.com
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/README.mozilla
@@ -0,0 +1,50 @@
+This directory contains files from the OpenVR SDK, version 1.0.6.
+
+This SDK contains the OpenVR API interface headers and functions to load the
+OpenVR runtime libraries which actually implement the functionality. The
+loading functions parse a .json file in a pre-defined location on the
+end-user's machine to get details used to bind the correct runtime library.
+The OpenVR implementation ensures forward and backwards compatibility as of
+the current version.
+
+Updated versions of the OpenVR SDK are available on Github:
+
+https://github.com/ValveSoftware/openvr
+
+
+We only use some files from the SDK:
+
+- We strip out files such as C# headers, plain C API versions, and files
+  needed only when implementing OpenVR drivers.
+
+- CMake related files, such as CMakeLists.txt are skipped as we use moz.build
+  files to configure the library.
+
+- The "src/jsoncpp.cpp" file and the "src/json" directory can be skipped. OpenVR
+  uses the jsoncpp library, which we have already imported elsewhere.
+
+
+Steps to update the library:
+
+- Copy "README.md" from the root of the openvr repo to the "gfx/vr/openvr" directory.
+
+- Copy "headers/openvr.h" to "gfx/vr/openvr/headers" directory. The other files
+  in this directory can be ignored.
+
+- The rest of the files in the "src" directory and the "src/vrcommon" are copied
+  to the "gfx/vr/openvr/src" directory.
+
+- Update "gfx/vr/openvr/moz.build" when files are added or removed.
+
+- Update the "strtools_public.h" and "strtools_public.cpp" files, commenting out
+  the "Uint64ToString" function. This function name conflicts with another used
+  in Gecko. Fortunately, the OpenVR SDK does not use this function either.
+
+- Replace the #define VR_INTERFACE in openvr.h to avoid extern'ing the functions.
+  Unlike the usual OpenVR API builds, we are not building a separate dll.
+
+- Update this README.mozilla file with the new OpenVR SDK version and any
+  additional steps needed for newer versions.
+
+- Ensure that any changes made within the OpenVR files have comments including
+  the string "Mozilla" and reference this file for easy identification.
rename from gfx/vr/openvr/openvr.h
rename to gfx/vr/openvr/headers/openvr.h
--- a/gfx/vr/openvr/openvr.h
+++ b/gfx/vr/openvr/headers/openvr.h
@@ -8,17 +8,27 @@
 #define _OPENVR_API
 
 #include <stdint.h>
 
 
 
 // vrtypes.h
 #ifndef _INCLUDE_VRTYPES_H
-#define _INCLUDE_VRTYPES_H 
+#define _INCLUDE_VRTYPES_H
+
+// Forward declarations to avoid requiring vulkan.h
+struct VkDevice_T;
+struct VkPhysicalDevice_T;
+struct VkInstance_T;
+struct VkQueue_T;
+
+// Forward declarations to avoid requiring d3d12.h
+struct ID3D12Resource;
+struct ID3D12CommandQueue;
 
 namespace vr
 {
 
 #if defined(__linux__) || defined(__APPLE__) 
 	// The 32-bit version of gcc has the alignment requirement for uint64 and double set to
 	// 4 meaning that even with #pragma pack(8) these types will only be four-byte aligned.
 	// The 64-bit version of gcc has the alignment requirement for these types set to
@@ -100,48 +110,54 @@ struct DistortionCoordinates_t
 };
 
 enum EVREye
 {
 	Eye_Left = 0,
 	Eye_Right = 1
 };
 
-enum EGraphicsAPIConvention
+enum ETextureType
 {
-	API_DirectX = 0, // Normalized Z goes from 0 at the viewer to 1 at the far clip plane
-	API_OpenGL = 1,  // Normalized Z goes from 1 at the viewer to -1 at the far clip plane
+	TextureType_DirectX = 0, // Handle is an ID3D11Texture
+	TextureType_OpenGL = 1,  // Handle is an OpenGL texture name or an OpenGL render buffer name, depending on submit flags
+	TextureType_Vulkan = 2, // Handle is a pointer to a VRVulkanTextureData_t structure
+	TextureType_IOSurface = 3, // Handle is a macOS cross-process-sharable IOSurface
+	TextureType_DirectX12 = 4, // Handle is a pointer to a D3D12TextureData_t structure
 };
 
 enum EColorSpace
 {
 	ColorSpace_Auto = 0,	// Assumes 'gamma' for 8-bit per component formats, otherwise 'linear'.  This mirrors the DXGI formats which have _SRGB variants.
 	ColorSpace_Gamma = 1,	// Texture data can be displayed directly on the display without any conversion (a.k.a. display native format).
 	ColorSpace_Linear = 2,	// Same as gamma but has been converted to a linear representation using DXGI's sRGB conversion algorithm.
 };
 
 struct Texture_t
 {
-	void* handle; // Native d3d texture pointer or GL texture id.
-	EGraphicsAPIConvention eType;
+	void* handle; // See ETextureType definition above
+	ETextureType eType;
 	EColorSpace eColorSpace;
 };
 
+// Handle to a shared texture (HANDLE on Windows obtained using OpenSharedResource).
+typedef uint64_t SharedTextureHandle_t;
+#define INVALID_SHARED_TEXTURE_HANDLE	((vr::SharedTextureHandle_t)0)
+
 enum ETrackingResult
 {
 	TrackingResult_Uninitialized			= 1,
 
 	TrackingResult_Calibrating_InProgress	= 100,
 	TrackingResult_Calibrating_OutOfRange	= 101,
 
 	TrackingResult_Running_OK				= 200,
 	TrackingResult_Running_OutOfRange		= 201,
 };
 
-static const uint32_t k_unTrackingStringSize = 32;
 static const uint32_t k_unMaxDriverDebugResponseSize = 32768;
 
 /** Used to pass device IDs to API calls */
 typedef uint32_t TrackedDeviceIndex_t;
 static const uint32_t k_unTrackedDeviceIndex_Hmd = 0;
 static const uint32_t k_unMaxTrackedDeviceCount = 16;
 static const uint32_t k_unTrackedDeviceIndexOther = 0xFFFFFFFE;
 static const uint32_t k_unTrackedDeviceIndexInvalid = 0xFFFFFFFF;
@@ -149,18 +165,16 @@ static const uint32_t k_unTrackedDeviceI
 /** Describes what kind of object is being tracked at a given ID */
 enum ETrackedDeviceClass
 {
 	TrackedDeviceClass_Invalid = 0,				// the ID was not valid.
 	TrackedDeviceClass_HMD = 1,					// Head-Mounted Displays
 	TrackedDeviceClass_Controller = 2,			// Tracked controllers
 	TrackedDeviceClass_GenericTracker = 3,		// Generic trackers, similar to controllers
 	TrackedDeviceClass_TrackingReference = 4,	// Camera and base stations that serve as tracking reference points
-
-	TrackedDeviceClass_Other = 1000,
 };
 
 
 /** Describes what specific role associated with a tracked device */
 enum ETrackedControllerRole
 {
 	TrackedControllerRole_Invalid = 0,					// Invalid value for controller type
 	TrackedControllerRole_LeftHand = 1,					// Tracked device associated with the left hand
@@ -183,24 +197,50 @@ struct TrackedDevicePose_t
 };
 
 /** Identifies which style of tracking origin the application wants to use
 * for the poses it is requesting */
 enum ETrackingUniverseOrigin
 {
 	TrackingUniverseSeated = 0,		// Poses are provided relative to the seated zero pose
 	TrackingUniverseStanding = 1,	// Poses are provided relative to the safe bounds configured by the user
-	TrackingUniverseRawAndUncalibrated = 2,	// Poses are provided in the coordinate system defined by the driver. You probably don't want this one.
+	TrackingUniverseRawAndUncalibrated = 2,	// Poses are provided in the coordinate system defined by the driver.  It has Y up and is unified for devices of the same driver. You usually don't want this one.
 };
 
+// Refers to a single container of properties
+typedef uint64_t PropertyContainerHandle_t;
+typedef uint32_t PropertyTypeTag_t;
+
+static const PropertyContainerHandle_t k_ulInvalidPropertyContainer = 0;
+static const PropertyTypeTag_t k_unInvalidPropertyTag = 0;
+
+// Use these tags to set/get common types as struct properties
+static const PropertyTypeTag_t k_unFloatPropertyTag = 1;
+static const PropertyTypeTag_t k_unInt32PropertyTag = 2;
+static const PropertyTypeTag_t k_unUint64PropertyTag = 3;
+static const PropertyTypeTag_t k_unBoolPropertyTag = 4;
+static const PropertyTypeTag_t k_unStringPropertyTag = 5;
+
+static const PropertyTypeTag_t k_unHmdMatrix34PropertyTag = 20;
+static const PropertyTypeTag_t k_unHmdMatrix44PropertyTag = 21;
+static const PropertyTypeTag_t k_unHmdVector3PropertyTag = 22;
+static const PropertyTypeTag_t k_unHmdVector4PropertyTag = 23;
+
+static const PropertyTypeTag_t k_unHiddenAreaPropertyTag = 30;
+
+static const PropertyTypeTag_t k_unOpenVRInternalReserved_Start = 1000;
+static const PropertyTypeTag_t k_unOpenVRInternalReserved_End = 10000;
+
 
 /** Each entry in this enum represents a property that can be retrieved about a
 * tracked device. Many fields are only valid for one ETrackedDeviceClass. */
 enum ETrackedDeviceProperty
 {
+	Prop_Invalid								= 0,
+
 	// general properties that apply to all device classes
 	Prop_TrackingSystemName_String				= 1000,
 	Prop_ModelNumber_String						= 1001,
 	Prop_SerialNumber_String					= 1002,
 	Prop_RenderModelName_String					= 1003,
 	Prop_WillDriftInYaw_Bool					= 1004,
 	Prop_ManufacturerName_String				= 1005,
 	Prop_TrackingFirmwareVersion_String			= 1006,
@@ -225,16 +265,19 @@ enum ETrackedDeviceProperty
 	Prop_ContainsProximitySensor_Bool			= 1025,
 	Prop_DeviceProvidesBatteryStatus_Bool		= 1026,
 	Prop_DeviceCanPowerOff_Bool					= 1027,
 	Prop_Firmware_ProgrammingTarget_String		= 1028,
 	Prop_DeviceClass_Int32						= 1029,
 	Prop_HasCamera_Bool							= 1030,
 	Prop_DriverVersion_String                   = 1031,
 	Prop_Firmware_ForceUpdateRequired_Bool      = 1032,
+	Prop_ViveSystemButtonFixRequired_Bool		= 1033,
+	Prop_ParentDriver_Uint64					= 1034,
+
 
 	// Properties that are unique to TrackedDeviceClass_HMD
 	Prop_ReportsTimeSinceVSync_Bool				= 2000,
 	Prop_SecondsFromVsyncToPhotons_Float		= 2001,
 	Prop_DisplayFrequency_Float					= 2002,
 	Prop_UserIpdMeters_Float					= 2003,
 	Prop_CurrentUniverseId_Uint64				= 2004, 
 	Prop_PreviousUniverseId_Uint64				= 2005, 
@@ -264,16 +307,22 @@ enum ETrackedDeviceProperty
 	Prop_DisplayFPGAVersion_Uint64				= 2029,
 	Prop_DisplayBootloaderVersion_Uint64		= 2030,
 	Prop_DisplayHardwareVersion_Uint64			= 2031,
 	Prop_AudioFirmwareVersion_Uint64			= 2032,
 	Prop_CameraCompatibilityMode_Int32			= 2033,
 	Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034,
 	Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035,
 	Prop_DisplaySuppressed_Bool					= 2036,
+	Prop_DisplayAllowNightMode_Bool				= 2037,
+	Prop_DisplayMCImageWidth_Int32				= 2038,
+	Prop_DisplayMCImageHeight_Int32				= 2039,
+	Prop_DisplayMCImageNumChannels_Int32		= 2040,
+	Prop_DisplayMCImageData_Binary				= 2041,
+	Prop_UsesDriverDirectMode_Bool				= 2042,
 
 	// Properties that are unique to TrackedDeviceClass_Controller
 	Prop_AttachedDeviceId_String				= 3000,
 	Prop_SupportedButtons_Uint64				= 3001,
 	Prop_Axis0Type_Int32						= 3002, // Return value is of type EVRControllerAxisType
 	Prop_Axis1Type_Int32						= 3003, // Return value is of type EVRControllerAxisType
 	Prop_Axis2Type_Int32						= 3004, // Return value is of type EVRControllerAxisType
 	Prop_Axis3Type_Int32						= 3005, // Return value is of type EVRControllerAxisType
@@ -284,37 +333,58 @@ enum ETrackedDeviceProperty
 	Prop_FieldOfViewLeftDegrees_Float			= 4000,
 	Prop_FieldOfViewRightDegrees_Float			= 4001,
 	Prop_FieldOfViewTopDegrees_Float			= 4002,
 	Prop_FieldOfViewBottomDegrees_Float			= 4003,
 	Prop_TrackingRangeMinimumMeters_Float		= 4004,
 	Prop_TrackingRangeMaximumMeters_Float		= 4005,
 	Prop_ModeLabel_String						= 4006,
 
+	// Properties that are used for user interface like icons names
+	Prop_IconPathName_String						= 5000, // usually a directory named "icons"
+	Prop_NamedIconPathDeviceOff_String				= 5001, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+	Prop_NamedIconPathDeviceSearching_String		= 5002, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+	Prop_NamedIconPathDeviceSearchingAlert_String	= 5003, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+	Prop_NamedIconPathDeviceReady_String			= 5004, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+	Prop_NamedIconPathDeviceReadyAlert_String		= 5005, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+	Prop_NamedIconPathDeviceNotReady_String			= 5006, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+	Prop_NamedIconPathDeviceStandby_String			= 5007, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+	Prop_NamedIconPathDeviceAlertLow_String			= 5008, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
+
+	// Properties that are used by helpers, but are opaque to applications
+	Prop_DisplayHiddenArea_Binary_Start				= 5100,
+	Prop_DisplayHiddenArea_Binary_End				= 5150,
+
+	// Properties that are unique to drivers
+	Prop_UserConfigPath_String					= 6000,
+	Prop_InstallPath_String						= 6001,
+
 	// Vendors are free to expose private debug data in this reserved region
 	Prop_VendorSpecific_Reserved_Start			= 10000,
 	Prop_VendorSpecific_Reserved_End			= 10999,
 };
 
 /** No string property will ever be longer than this length */
 static const uint32_t k_unMaxPropertyStringSize = 32 * 1024;
 
 /** Used to return errors that occur when reading properties. */
 enum ETrackedPropertyError
 {
 	TrackedProp_Success						= 0,
 	TrackedProp_WrongDataType				= 1,
 	TrackedProp_WrongDeviceClass			= 2,
 	TrackedProp_BufferTooSmall				= 3,
-	TrackedProp_UnknownProperty				= 4,
+	TrackedProp_UnknownProperty				= 4, // Driver has not set the property (and may not ever).
 	TrackedProp_InvalidDevice				= 5,
 	TrackedProp_CouldNotContactServer		= 6,
 	TrackedProp_ValueNotProvidedByDevice	= 7,
 	TrackedProp_StringExceedsMaximumLength	= 8,
 	TrackedProp_NotYetAvailable				= 9, // The property value isn't known yet, but is expected soon. Call again later.
+	TrackedProp_PermissionDenied			= 10,
+	TrackedProp_InvalidOperation			= 11,
 };
 
 /** Allows the application to control what part of the provided texture will be used in the
 * frame buffer. */
 struct VRTextureBounds_t
 {
 	float uMin, vMin;
 	float uMax, vMax;
@@ -329,18 +399,42 @@ enum EVRSubmitFlags
 
 	// App submits final left and right eye images with lens distortion already applied (lens distortion makes the images appear
 	// barrel distorted with chromatic aberration correction applied). The app would have used the data returned by
 	// vr::IVRSystem::ComputeDistortion() to apply the correct distortion to the rendered images before calling Submit().
 	Submit_LensDistortionAlreadyApplied = 0x01,
 
 	// If the texture pointer passed in is actually a renderbuffer (e.g. for MSAA in OpenGL) then set this flag.
 	Submit_GlRenderBuffer = 0x02,
+
+	// Do not use
+	Submit_Reserved = 0x04,
 };
 
+/** Data required for passing Vulkan textures to IVRCompositor::Submit.
+* Be sure to call OpenVR_Shutdown before destroying these resources. */
+struct VRVulkanTextureData_t
+{
+	uint64_t m_nImage; // VkImage
+	VkDevice_T *m_pDevice;
+	VkPhysicalDevice_T *m_pPhysicalDevice;
+	VkInstance_T *m_pInstance;
+	VkQueue_T *m_pQueue;
+	uint32_t m_nQueueFamilyIndex;
+	uint32_t m_nWidth, m_nHeight, m_nFormat, m_nSampleCount;
+};
+
+/** Data required for passing D3D12 textures to IVRCompositor::Submit.
+* Be sure to call OpenVR_Shutdown before destroying these resources. */
+struct D3D12TextureData_t
+{
+	ID3D12Resource *m_pResource;
+	ID3D12CommandQueue *m_pCommandQueue;
+	uint32_t m_nNodeMask;
+};
 
 /** Status of the overall system or tracked objects */
 enum EVRState
 {
 	VRState_Undefined = -1,
 	VRState_Off = 0,
 	VRState_Searching = 1,
 	VRState_Searching_Alert = 2,
@@ -354,23 +448,25 @@ enum EVRState
 /** The types of events that could be posted (and what the parameters mean for each event type) */
 enum EVREventType
 {
 	VREvent_None = 0,
 
 	VREvent_TrackedDeviceActivated		= 100,
 	VREvent_TrackedDeviceDeactivated	= 101,
 	VREvent_TrackedDeviceUpdated		= 102,
-	VREvent_TrackedDeviceUserInteractionStarted		= 103,
+	VREvent_TrackedDeviceUserInteractionStarted	= 103,
 	VREvent_TrackedDeviceUserInteractionEnded	= 104,
 	VREvent_IpdChanged					= 105,
 	VREvent_EnterStandbyMode			= 106,
 	VREvent_LeaveStandbyMode			= 107,
 	VREvent_TrackedDeviceRoleChanged	= 108,
 	VREvent_WatchdogWakeUpRequested		= 109,
+	VREvent_LensDistortionChanged		= 110,
+	VREvent_PropertyChanged				= 111,
 
 	VREvent_ButtonPress					= 200, // data is controller
 	VREvent_ButtonUnpress				= 201, // data is controller
 	VREvent_ButtonTouch					= 202, // data is controller
 	VREvent_ButtonUntouch				= 203, // data is controller
 
 	VREvent_MouseMove					= 300, // data is mouse
 	VREvent_MouseButtonDown				= 301, // data is mouse
@@ -390,99 +486,107 @@ enum EVREventType
 	VREvent_InputFocusChanged			= 406, // data is process
 	VREvent_SceneApplicationSecondaryRenderingStarted = 407, // data is process
 
 	VREvent_HideRenderModels			= 410, // Sent to the scene application to request hiding render models temporarily
 	VREvent_ShowRenderModels			= 411, // Sent to the scene application to request restoring render model visibility
 
 	VREvent_OverlayShown				= 500,
 	VREvent_OverlayHidden				= 501,
-	VREvent_DashboardActivated		= 502,
-	VREvent_DashboardDeactivated	= 503,
-	VREvent_DashboardThumbSelected	= 504, // Sent to the overlay manager - data is overlay
-	VREvent_DashboardRequested		= 505, // Sent to the overlay manager - data is overlay
-	VREvent_ResetDashboard			= 506, // Send to the overlay manager
-	VREvent_RenderToast				= 507, // Send to the dashboard to render a toast - data is the notification ID
-	VREvent_ImageLoaded				= 508, // Sent to overlays when a SetOverlayRaw or SetOverlayFromFile call finishes loading
-	VREvent_ShowKeyboard = 509, // Sent to keyboard renderer in the dashboard to invoke it
-	VREvent_HideKeyboard = 510, // Sent to keyboard renderer in the dashboard to hide it
-	VREvent_OverlayGamepadFocusGained		= 511, // Sent to an overlay when IVROverlay::SetFocusOverlay is called on it
-	VREvent_OverlayGamepadFocusLost = 512, // Send to an overlay when it previously had focus and IVROverlay::SetFocusOverlay is called on something else
+	VREvent_DashboardActivated			= 502,
+	VREvent_DashboardDeactivated		= 503,
+	VREvent_DashboardThumbSelected		= 504, // Sent to the overlay manager - data is overlay
+	VREvent_DashboardRequested			= 505, // Sent to the overlay manager - data is overlay
+	VREvent_ResetDashboard				= 506, // Send to the overlay manager
+	VREvent_RenderToast					= 507, // Send to the dashboard to render a toast - data is the notification ID
+	VREvent_ImageLoaded					= 508, // Sent to overlays when a SetOverlayRaw or SetOverlayFromFile call finishes loading
+	VREvent_ShowKeyboard				= 509, // Sent to keyboard renderer in the dashboard to invoke it
+	VREvent_HideKeyboard				= 510, // Sent to keyboard renderer in the dashboard to hide it
+	VREvent_OverlayGamepadFocusGained	= 511, // Sent to an overlay when IVROverlay::SetFocusOverlay is called on it
+	VREvent_OverlayGamepadFocusLost		= 512, // Send to an overlay when it previously had focus and IVROverlay::SetFocusOverlay is called on something else
 	VREvent_OverlaySharedTextureChanged = 513,
-	VREvent_DashboardGuideButtonDown = 514,
-	VREvent_DashboardGuideButtonUp = 515,
-	VREvent_ScreenshotTriggered	= 516, // Screenshot button combo was pressed, Dashboard should request a screenshot
-	VREvent_ImageFailed				= 517, // Sent to overlays when a SetOverlayRaw or SetOverlayfromFail fails to load
+	VREvent_DashboardGuideButtonDown	= 514,
+	VREvent_DashboardGuideButtonUp		= 515,
+	VREvent_ScreenshotTriggered			= 516, // Screenshot button combo was pressed, Dashboard should request a screenshot
+	VREvent_ImageFailed					= 517, // Sent to overlays when a SetOverlayRaw or SetOverlayfromFail fails to load
+	VREvent_DashboardOverlayCreated		= 518,
 
 	// Screenshot API
-	VREvent_RequestScreenshot = 520, // Sent by vrclient application to compositor to take a screenshot
-	VREvent_ScreenshotTaken = 521, // Sent by compositor to the application that the screenshot has been taken
-	VREvent_ScreenshotFailed = 522, // Sent by compositor to the application that the screenshot failed to be taken
-	VREvent_SubmitScreenshotToDashboard = 523, // Sent by compositor to the dashboard that a completed screenshot was submitted
-	VREvent_ScreenshotProgressToDashboard = 524, // Sent by compositor to the dashboard that a completed screenshot was submitted
+	VREvent_RequestScreenshot				= 520, // Sent by vrclient application to compositor to take a screenshot
+	VREvent_ScreenshotTaken					= 521, // Sent by compositor to the application that the screenshot has been taken
+	VREvent_ScreenshotFailed				= 522, // Sent by compositor to the application that the screenshot failed to be taken
+	VREvent_SubmitScreenshotToDashboard		= 523, // Sent by compositor to the dashboard that a completed screenshot was submitted
+	VREvent_ScreenshotProgressToDashboard	= 524, // Sent by compositor to the dashboard that a completed screenshot was submitted
+
+	VREvent_PrimaryDashboardDeviceChanged	= 525,
 
 	VREvent_Notification_Shown				= 600,
 	VREvent_Notification_Hidden				= 601,
 	VREvent_Notification_BeginInteraction	= 602,
 	VREvent_Notification_Destroyed			= 603,
 
-	VREvent_Quit						= 700, // data is process
-	VREvent_ProcessQuit					= 701, // data is process
-	VREvent_QuitAborted_UserPrompt		= 702, // data is process
-	VREvent_QuitAcknowledged			= 703, // data is process
-	VREvent_DriverRequestedQuit			= 704, // The driver has requested that SteamVR shut down
-
-	VREvent_ChaperoneDataHasChanged		= 800,
-	VREvent_ChaperoneUniverseHasChanged	= 801,
-	VREvent_ChaperoneTempDataHasChanged = 802,
-	VREvent_ChaperoneSettingsHaveChanged = 803,
-	VREvent_SeatedZeroPoseReset			= 804,
-
-	VREvent_AudioSettingsHaveChanged	= 820,
-
-	VREvent_BackgroundSettingHasChanged	= 850,
-	VREvent_CameraSettingsHaveChanged	= 851,
-	VREvent_ReprojectionSettingHasChanged = 852,
-	VREvent_ModelSkinSettingsHaveChanged = 853,
-	VREvent_EnvironmentSettingsHaveChanged = 854,
-
-	VREvent_StatusUpdate				= 900,
-
-	VREvent_MCImageUpdated				= 1000,
-
-	VREvent_FirmwareUpdateStarted	= 1100,
-	VREvent_FirmwareUpdateFinished	= 1101,
-
-	VREvent_KeyboardClosed				= 1200,
-	VREvent_KeyboardCharInput			= 1201,
-	VREvent_KeyboardDone				= 1202, // Sent when DONE button clicked on keyboard
-
-	VREvent_ApplicationTransitionStarted	= 1300,
-	VREvent_ApplicationTransitionAborted	= 1301,
-	VREvent_ApplicationTransitionNewAppStarted = 1302,
-	VREvent_ApplicationListUpdated			= 1303,
-	VREvent_ApplicationMimeTypeLoad			= 1304,
-
-	VREvent_Compositor_MirrorWindowShown	= 1400,
-	VREvent_Compositor_MirrorWindowHidden	= 1401,
-	VREvent_Compositor_ChaperoneBoundsShown = 1410,
-	VREvent_Compositor_ChaperoneBoundsHidden = 1411,
+	VREvent_Quit							= 700, // data is process
+	VREvent_ProcessQuit						= 701, // data is process
+	VREvent_QuitAborted_UserPrompt			= 702, // data is process
+	VREvent_QuitAcknowledged				= 703, // data is process
+	VREvent_DriverRequestedQuit				= 704, // The driver has requested that SteamVR shut down
+
+	VREvent_ChaperoneDataHasChanged			= 800,
+	VREvent_ChaperoneUniverseHasChanged		= 801,
+	VREvent_ChaperoneTempDataHasChanged		= 802,
+	VREvent_ChaperoneSettingsHaveChanged	= 803,
+	VREvent_SeatedZeroPoseReset				= 804,
+
+	VREvent_AudioSettingsHaveChanged		= 820,
+
+	VREvent_BackgroundSettingHasChanged		= 850,
+	VREvent_CameraSettingsHaveChanged		= 851,
+	VREvent_ReprojectionSettingHasChanged	= 852,
+	VREvent_ModelSkinSettingsHaveChanged	= 853,
+	VREvent_EnvironmentSettingsHaveChanged	= 854,
+	VREvent_PowerSettingsHaveChanged		= 855,
+
+	VREvent_StatusUpdate					= 900,
+
+	VREvent_MCImageUpdated					= 1000,
+
+	VREvent_FirmwareUpdateStarted			= 1100,
+	VREvent_FirmwareUpdateFinished			= 1101,
+
+	VREvent_KeyboardClosed					= 1200,
+	VREvent_KeyboardCharInput				= 1201,
+	VREvent_KeyboardDone					= 1202, // Sent when DONE button clicked on keyboard
+
+	VREvent_ApplicationTransitionStarted		= 1300,
+	VREvent_ApplicationTransitionAborted		= 1301,
+	VREvent_ApplicationTransitionNewAppStarted	= 1302,
+	VREvent_ApplicationListUpdated				= 1303,
+	VREvent_ApplicationMimeTypeLoad				= 1304,
+	VREvent_ApplicationTransitionNewAppLaunchComplete = 1305,
+
+	VREvent_Compositor_MirrorWindowShown		= 1400,
+	VREvent_Compositor_MirrorWindowHidden		= 1401,
+	VREvent_Compositor_ChaperoneBoundsShown		= 1410,
+	VREvent_Compositor_ChaperoneBoundsHidden	= 1411,
 
 	VREvent_TrackedCamera_StartVideoStream  = 1500,
 	VREvent_TrackedCamera_StopVideoStream   = 1501,
 	VREvent_TrackedCamera_PauseVideoStream  = 1502,
 	VREvent_TrackedCamera_ResumeVideoStream = 1503,
-
-	VREvent_PerformanceTest_EnableCapture = 1600,
-	VREvent_PerformanceTest_DisableCapture = 1601,
-	VREvent_PerformanceTest_FidelityLevel = 1602,
+	VREvent_TrackedCamera_EditingSurface    = 1550,
+
+	VREvent_PerformanceTest_EnableCapture	= 1600,
+	VREvent_PerformanceTest_DisableCapture	= 1601,
+	VREvent_PerformanceTest_FidelityLevel	= 1602,
+
+	VREvent_MessageOverlay_Closed			= 1650,
 	
 	// Vendors are free to expose private events in this reserved region
-	VREvent_VendorSpecific_Reserved_Start = 10000,
-	VREvent_VendorSpecific_Reserved_End = 19999,
+	VREvent_VendorSpecific_Reserved_Start	= 10000,
+	VREvent_VendorSpecific_Reserved_End		= 19999,
 };
 
 
 /** Level of Hmd activity */
 enum EDeviceActivityLevel
 {
 	k_EDeviceActivityLevel_Unknown = -1,
 	k_EDeviceActivityLevel_Idle = 0,
@@ -498,16 +602,18 @@ enum EVRButtonId
 	k_EButton_System			= 0,
 	k_EButton_ApplicationMenu	= 1,
 	k_EButton_Grip				= 2,
 	k_EButton_DPad_Left			= 3,
 	k_EButton_DPad_Up			= 4,
 	k_EButton_DPad_Right		= 5,
 	k_EButton_DPad_Down			= 6,
 	k_EButton_A					= 7,
+	
+	k_EButton_ProximitySensor   = 31,
 
 	k_EButton_Axis0				= 32,
 	k_EButton_Axis1				= 33,
 	k_EButton_Axis2				= 34,
 	k_EButton_Axis3				= 35,
 	k_EButton_Axis4				= 36,
 
 	// aliases for well known controllers
@@ -647,17 +753,34 @@ struct VREvent_ScreenshotProgress_t
 };
 
 struct VREvent_ApplicationLaunch_t
 {
 	uint32_t pid;
 	uint32_t unArgsHandle;
 };
 
-/** If you change this you must manually update openvr_interop.cs.py */
+struct VREvent_EditingCameraSurface_t
+{
+	uint64_t overlayHandle;
+	uint32_t nVisualMode;
+};
+
+struct VREvent_MessageOverlay_t
+{
+	uint32_t unVRMessageOverlayResponse; // vr::VRMessageOverlayResponse enum
+};
+
+struct VREvent_Property_t
+{
+	PropertyContainerHandle_t container;
+	ETrackedDeviceProperty prop;
+};
+
+/** NOTE!!! If you change this you MUST manually update openvr_interop.cs.py */
 typedef union
 {
 	VREvent_Reserved_t reserved;
 	VREvent_Controller_t controller;
 	VREvent_Mouse_t mouse;
 	VREvent_Scroll_t scroll;
 	VREvent_Process_t process;
 	VREvent_Notification_t notification;
@@ -667,16 +790,19 @@ typedef union
 	VREvent_Ipd_t ipd;
 	VREvent_Chaperone_t chaperone;
 	VREvent_PerformanceTest_t performanceTest;
 	VREvent_TouchPadMove_t touchPadMove;
 	VREvent_SeatedZeroPoseReset_t seatedZeroPoseReset;
 	VREvent_Screenshot_t screenshot;
 	VREvent_ScreenshotProgress_t screenshotProgress;
 	VREvent_ApplicationLaunch_t applicationLaunch;
+	VREvent_EditingCameraSurface_t cameraSurface;
+	VREvent_MessageOverlay_t messageOverlay;
+	VREvent_Property_t property;
 } VREvent_Data_t;
 
 /** An event posted by the server to all running applications */
 struct VREvent_t
 {
 	uint32_t eventType; // EVREventType enum
 	TrackedDeviceIndex_t trackedDeviceIndex;
 	float eventAgeSeconds;
@@ -693,16 +819,26 @@ struct VREvent_t
 * NULL and unTriangleCount will be 0. */
 struct HiddenAreaMesh_t
 {
 	const HmdVector2_t *pVertexData;
 	uint32_t unTriangleCount;
 };
 
 
+enum EHiddenAreaMeshType
+{
+	k_eHiddenAreaMesh_Standard = 0,
+	k_eHiddenAreaMesh_Inverse = 1,
+	k_eHiddenAreaMesh_LineLoop = 2,
+
+	k_eHiddenAreaMesh_Max = 3,
+};
+
+
 /** Identifies what kind of axis is on the controller at index n. Read this type 
 * with pVRSystem->Get( nControllerDeviceIndex, Prop_Axis0Type_Int32 + n );
 */
 enum EVRControllerAxisType
 {
 	k_eControllerAxis_None = 0,
 	k_eControllerAxis_TrackPad = 1,
 	k_eControllerAxis_Joystick = 2,
@@ -776,36 +912,38 @@ struct Compositor_OverlaySettings
 /** used to refer to a single VR overlay */
 typedef uint64_t VROverlayHandle_t;
 
 static const VROverlayHandle_t k_ulOverlayHandleInvalid = 0;
 
 /** Errors that can occur around VR overlays */
 enum EVROverlayError
 {
-	VROverlayError_None					= 0,
-
-	VROverlayError_UnknownOverlay		= 10,
-	VROverlayError_InvalidHandle		= 11,
-	VROverlayError_PermissionDenied		= 12,
-	VROverlayError_OverlayLimitExceeded = 13, // No more overlays could be created because the maximum number already exist
-	VROverlayError_WrongVisibilityType	= 14,
-	VROverlayError_KeyTooLong			= 15,
-	VROverlayError_NameTooLong			= 16,
-	VROverlayError_KeyInUse				= 17,
-	VROverlayError_WrongTransformType	= 18,
-	VROverlayError_InvalidTrackedDevice = 19,
-	VROverlayError_InvalidParameter		= 20,
-	VROverlayError_ThumbnailCantBeDestroyed = 21,
-	VROverlayError_ArrayTooSmall		= 22,
-	VROverlayError_RequestFailed		= 23,
-	VROverlayError_InvalidTexture		= 24,
-	VROverlayError_UnableToLoadFile		= 25,
-	VROVerlayError_KeyboardAlreadyInUse = 26,
-	VROverlayError_NoNeighbor			= 27,
+	VROverlayError_None						= 0,
+
+	VROverlayError_UnknownOverlay			= 10,
+	VROverlayError_InvalidHandle			= 11,
+	VROverlayError_PermissionDenied			= 12,
+	VROverlayError_OverlayLimitExceeded		= 13, // No more overlays could be created because the maximum number already exist
+	VROverlayError_WrongVisibilityType		= 14,
+	VROverlayError_KeyTooLong				= 15,
+	VROverlayError_NameTooLong				= 16,
+	VROverlayError_KeyInUse					= 17,
+	VROverlayError_WrongTransformType		= 18,
+	VROverlayError_InvalidTrackedDevice		= 19,
+	VROverlayError_InvalidParameter			= 20,
+	VROverlayError_ThumbnailCantBeDestroyed	= 21,
+	VROverlayError_ArrayTooSmall			= 22,
+	VROverlayError_RequestFailed			= 23,
+	VROverlayError_InvalidTexture			= 24,
+	VROverlayError_UnableToLoadFile			= 25,
+	VROverlayError_KeyboardAlreadyInUse		= 26,
+	VROverlayError_NoNeighbor				= 27,
+	VROverlayError_TooManyMaskPrimitives	= 29,
+	VROverlayError_BadMaskPrimitive			= 30,
 };
 
 /** enum values to pass in to VR_Init to identify whether the application will 
 * draw a 3D scene. */
 enum EVRApplicationType
 {
 	VRApplication_Other = 0,		// Some other kind of application that isn't covered by the other entries 
 	VRApplication_Scene	= 1,		// Application will submit 3D frames 
@@ -877,16 +1015,18 @@ enum EVRInitError
 	VRInitError_Init_HmdDriverIdIsNone		 	= 125,
 	VRInitError_Init_HmdNotFoundPresenceFailed 	= 126,
 	VRInitError_Init_VRMonitorNotFound			= 127,
 	VRInitError_Init_VRMonitorStartupFailed		= 128,
 	VRInitError_Init_LowPowerWatchdogNotSupported = 129, 
 	VRInitError_Init_InvalidApplicationType		= 130,
 	VRInitError_Init_NotAvailableToWatchdogApps = 131,
 	VRInitError_Init_WatchdogDisabledInSettings = 132,
+	VRInitError_Init_VRDashboardNotFound		= 133,
+	VRInitError_Init_VRDashboardStartupFailed	= 134,
 
 	VRInitError_Driver_Failed				= 200,
 	VRInitError_Driver_Unknown				= 201,
 	VRInitError_Driver_HmdUnknown			= 202,
 	VRInitError_Driver_NotLoaded			= 203,
 	VRInitError_Driver_RuntimeOutOfDate		= 204,
 	VRInitError_Driver_HmdInUse				= 205,
 	VRInitError_Driver_NotCalibrated		= 206,
@@ -995,16 +1135,22 @@ struct CameraVideoStreamFrameHeader_t
 
 // Screenshot types
 typedef uint32_t ScreenshotHandle_t;
 
 static const uint32_t k_unScreenshotHandleInvalid = 0;
 
 #pragma pack( pop )
 
+
+// Mozilla changed VR_INTERFACE.  We don't want to extern the API functions.
+// See README.mozilla
+#define VR_INTERFACE
+
+/*
 // figure out how to import from the VR API dll
 #if defined(_WIN32)
 
 #ifdef VR_API_EXPORT
 #define VR_INTERFACE extern "C" __declspec( dllexport )
 #else
 #define VR_INTERFACE extern "C" __declspec( dllimport )
 #endif
@@ -1015,17 +1161,17 @@ static const uint32_t k_unScreenshotHand
 #define VR_INTERFACE extern "C" __attribute__((visibility("default")))
 #else
 #define VR_INTERFACE extern "C" 
 #endif
 
 #else
 #error "Unsupported Platform."
 #endif
-
+*/
 
 #if defined( _WIN32 )
 #define VR_CALLTYPE __cdecl
 #else
 #define VR_CALLTYPE 
 #endif
 
 } // namespace vr
@@ -1064,25 +1210,26 @@ public:
 	// ------------------------------------
 	// Display Methods
 	// ------------------------------------
 
 	/** Suggested size for the intermediate render target that the distortion pulls from. */
 	virtual void GetRecommendedRenderTargetSize( uint32_t *pnWidth, uint32_t *pnHeight ) = 0;
 
 	/** The projection matrix for the specified eye */
-	virtual HmdMatrix44_t GetProjectionMatrix( EVREye eEye, float fNearZ, float fFarZ, EGraphicsAPIConvention eProjType ) = 0;
+	virtual HmdMatrix44_t GetProjectionMatrix( EVREye eEye, float fNearZ, float fFarZ ) = 0;
 
 	/** The components necessary to build your own projection matrix in case your
 	* application is doing something fancy like infinite Z */
 	virtual void GetProjectionRaw( EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom ) = 0;
 
-	/** Returns the result of the distortion function for the specified eye and input UVs. UVs go from 0,0 in 
-	* the upper left of that eye's viewport and 1,1 in the lower right of that eye's viewport. */
-	virtual DistortionCoordinates_t ComputeDistortion( EVREye eEye, float fU, float fV ) = 0;
+	/** Gets the result of the distortion function for the specified eye and input UVs. UVs go from 0,0 in 
+	* the upper left of that eye's viewport and 1,1 in the lower right of that eye's viewport.
+	* Returns true for success. Otherwise, returns false, and distortion coordinates are not suitable. */
+	virtual bool ComputeDistortion( EVREye eEye, float fU, float fV, DistortionCoordinates_t *pDistortionCoordinates ) = 0;
 
 	/** Returns the transform from eye space to the head space. Eye space is the per-eye flavor of head
 	* space that provides stereo disparity. Instead of Model * View * Projection the sequence is Model * View * Eye^-1 * Projection. 
 	* Normally View and Eye^-1 will be multiplied together and treated as View in your application. 
 	*/
 	virtual HmdMatrix34_t GetEyeToHeadTransform( EVREye eEye ) = 0;
 
 	/** Returns the number of elapsed seconds since the last recorded vsync event. This 
@@ -1093,18 +1240,18 @@ public:
 
 	/** [D3D9 Only]
 	* Returns the adapter index that the user should pass into CreateDevice to set up D3D9 in such
 	* a way that it can go full screen exclusive on the HMD. Returns -1 if there was an error.
 	*/
 	virtual int32_t GetD3D9AdapterIndex() = 0;
 
 	/** [D3D10/11 Only]
-	* Returns the adapter index and output index that the user should pass into EnumAdapters and EnumOutputs 
-	* to create the device and swap chain in DX10 and DX11. If an error occurs both indices will be set to -1.
+	* Returns the adapter index that the user should pass into EnumAdapters to create the device 
+	* and swap chain in DX10 and DX11. If an error occurs the index will be set to -1.
 	*/
 	virtual void GetDXGIOutputInfo( int32_t *pnAdapterIndex ) = 0;
 
 	// ------------------------------------
 	// Display Mode methods
 	// ------------------------------------
 
 	/** Use to determine if the headset display is part of the desktop (i.e. extended) or hidden (i.e. direct mode). */
@@ -1206,17 +1353,17 @@ public:
 	/** Returns a uint64 property. If the device index is not valid or the property is not a uint64 type this function will return 0. */
 	virtual uint64_t GetUint64TrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L ) = 0;
 
 	/** Returns a matrix property. If the device index is not valid or the property is not a matrix type, this function will return identity. */
 	virtual HmdMatrix34_t GetMatrix34TrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L ) = 0;
 
 	/** Returns a string property. If the device index is not valid or the property is not a string type this function will 
 	* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
-	* null. Strings will generally fit in buffers of k_unTrackingStringSize characters. */
+	* null. Strings will always fit in buffers of k_unMaxPropertyStringSize characters. */
 	virtual uint32_t GetStringTrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L ) = 0;
 
 	/** returns a string that corresponds with the specified property error. The string will be the name 
 	* of the error enum value for all valid error codes */
 	virtual const char *GetPropErrorNameFromEnum( ETrackedPropertyError error ) = 0;
 
 	// ------------------------------------
 	// Event methods
@@ -1234,37 +1381,38 @@ public:
 
 	/** returns the name of an EVREvent enum value */
 	virtual const char *GetEventTypeNameFromEnum( EVREventType eType ) = 0;
 
 	// ------------------------------------
 	// Rendering helper methods
 	// ------------------------------------
 
-	/** Returns the stencil mesh information for the current HMD. If this HMD does not have a stencil mesh the vertex data and count will be
-	* NULL and 0 respectively. This mesh is meant to be rendered into the stencil buffer (or into the depth buffer setting nearz) before rendering
-	* each eye's view. The pixels covered by this mesh will never be seen by the user after the lens distortion is applied and based on visibility to the panels.
-	* This will improve perf by letting the GPU early-reject pixels the user will never see before running the pixel shader.
+	/** Returns the hidden area mesh for the current HMD. The pixels covered by this mesh will never be seen by the user after the lens distortion is
+	* applied based on visibility to the panels. If this HMD does not have a hidden area mesh, the vertex data and count will be NULL and 0 respectively.
+	* This mesh is meant to be rendered into the stencil buffer (or into the depth buffer setting nearz) before rendering each eye's view. 
+	* This will improve performance by letting the GPU early-reject pixels the user will never see before running the pixel shader.
 	* NOTE: Render this mesh with backface culling disabled since the winding order of the vertices can be different per-HMD or per-eye.
+	* Setting the bInverse argument to true will produce the visible area mesh that is commonly used in place of full-screen quads. The visible area mesh covers all of the pixels the hidden area mesh does not cover.
+	* Setting the bLineLoop argument will return a line loop of vertices in HiddenAreaMesh_t->pVertexData with HiddenAreaMesh_t->unTriangleCount set to the number of vertices.
 	*/
-	virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye ) = 0;
-
+	virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye, EHiddenAreaMeshType type = k_eHiddenAreaMesh_Standard ) = 0;
 
 	// ------------------------------------
 	// Controller methods
 	// ------------------------------------
 
 	/** Fills the supplied struct with the current state of the controller. Returns false if the controller index
 	* is invalid. */
-	virtual bool GetControllerState( vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState ) = 0;
+	virtual bool GetControllerState( vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, uint32_t unControllerStateSize ) = 0;
 
 	/** fills the supplied struct with the current state of the controller and the provided pose with the pose of 
 	* the controller when the controller state was updated most recently. Use this form if you need a precise controller
 	* pose as input to your application when the user presses or releases a button. */
-	virtual bool GetControllerStateWithPose( ETrackingUniverseOrigin eOrigin, vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, TrackedDevicePose_t *pTrackedDevicePose ) = 0;
+	virtual bool GetControllerStateWithPose( ETrackingUniverseOrigin eOrigin, vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, uint32_t unControllerStateSize, TrackedDevicePose_t *pTrackedDevicePose ) = 0;
 
 	/** Trigger a single haptic pulse on a controller. After this call the application may not trigger another haptic pulse on this controller
 	* and axis combination for 5ms. */
 	virtual void TriggerHapticPulse( vr::TrackedDeviceIndex_t unControllerDeviceIndex, uint32_t unAxisId, unsigned short usDurationMicroSec ) = 0;
 
 	/** returns the name of an EVRButtonId enum value */
 	virtual const char *GetButtonIdNameFromEnum( EVRButtonId eButtonId ) = 0;
 
@@ -1287,45 +1435,43 @@ public:
 	// Debug Methods
 	// ------------------------------------
 
 	/** Sends a request to the driver for the specified device and returns the response. The maximum response size is 32k,
 	* but this method can be called with a smaller buffer. If the response exceeds the size of the buffer, it is truncated. 
 	* The size of the response including its terminating null is returned. */
 	virtual uint32_t DriverDebugRequest( vr::TrackedDeviceIndex_t unDeviceIndex, const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize ) = 0;
 
-
 	// ------------------------------------
 	// Firmware methods
 	// ------------------------------------
 	
 	/** Performs the actual firmware update if applicable. 
 	 * The following events will be sent, if VRFirmwareError_None was returned: VREvent_FirmwareUpdateStarted, VREvent_FirmwareUpdateFinished 
 	 * Use the properties Prop_Firmware_UpdateAvailable_Bool, Prop_Firmware_ManualUpdate_Bool, and Prop_Firmware_ManualUpdateURL_String
 	 * to figure our whether a firmware update is available, and to figure out whether its a manual update 
 	 * Prop_Firmware_ManualUpdateURL_String should point to an URL describing the manual update process */
 	virtual vr::EVRFirmwareError PerformFirmwareUpdate( vr::TrackedDeviceIndex_t unDeviceIndex ) = 0;
 
-
 	// ------------------------------------
 	// Application life cycle methods
 	// ------------------------------------
 
 	/** Call this to acknowledge to the system that VREvent_Quit has been received and that the process is exiting.
 	* This extends the timeout until the process is killed. */
 	virtual void AcknowledgeQuit_Exiting() = 0;
 
 	/** Call this to tell the system that the user is being prompted to save data. This
 	* halts the timeout and dismisses the dashboard (if it was up). Applications should be sure to actually 
 	* prompt the user to save and then exit afterward, otherwise the user will be left in a confusing state. */
 	virtual void AcknowledgeQuit_UserPrompt() = 0;
 
 };
 
-static const char * const IVRSystem_Version = "IVRSystem_012";
+static const char * const IVRSystem_Version = "IVRSystem_015";
 
 }
 
 
 // ivrapplications.h
 namespace vr
 {
 
@@ -1373,16 +1519,17 @@ namespace vr
 		VRApplicationProperty_Description_String		= 50,
 		VRApplicationProperty_NewsURL_String			= 51,
 		VRApplicationProperty_ImagePath_String			= 52,
 		VRApplicationProperty_Source_String				= 53,
 
 		VRApplicationProperty_IsDashboardOverlay_Bool	= 60,
 		VRApplicationProperty_IsTemplate_Bool			= 61,
 		VRApplicationProperty_IsInstanced_Bool			= 62,
+		VRApplicationProperty_IsInternal_Bool			= 63,
 
 		VRApplicationProperty_LastLaunchTime_Uint64		= 70,
 	};
 
 	/** These are states the scene application startup process will go through. */
 	enum EVRApplicationTransitionState
 	{
 		VRApplicationTransition_None = 0,
@@ -1394,16 +1541,20 @@ namespace vr
 	};
 
 	struct AppOverrideKeys_t
 	{
 		const char *pchKey;
 		const char *pchValue;
 	};
 
+	/** Currently recognized mime types */
+	static const char * const k_pch_MimeType_HomeApp		= "vr/home";
+	static const char * const k_pch_MimeType_GameTheater	= "vr/game_theater";
+
 	class IVRApplications
 	{
 	public:
 
 		// ---------------  Application management  --------------- //
 
 		/** Adds an application manifest to the list to load when building the list of installed applications. 
 		* Temporary manifests are not automatically loaded */
@@ -1416,17 +1567,17 @@ namespace vr
 		virtual bool IsApplicationInstalled( const char *pchAppKey ) = 0;
 
 		/** Returns the number of applications available in the list */
 		virtual uint32_t GetApplicationCount() = 0;
 
 		/** Returns the key of the specified application. The index is at least 0 and is less than the return 
 		* value of GetApplicationCount(). The buffer should be at least k_unMaxApplicationKeyLength in order to 
 		* fit the key. */
-		virtual EVRApplicationError GetApplicationKeyByIndex( uint32_t unApplicationIndex, char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0;
+		virtual EVRApplicationError GetApplicationKeyByIndex( uint32_t unApplicationIndex, VR_OUT_STRING() char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0;
 
 		/** Returns the key of the application for the specified Process Id. The buffer should be at least 
 		* k_unMaxApplicationKeyLength in order to fit the key. */
 		virtual EVRApplicationError GetApplicationKeyByProcessId( uint32_t unProcessId, char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0;
 
 		/** Launches the application. The existing scene application will exit and then the new application will start.
 		* This call is not valid for dashboard overlay applications. */
 		virtual EVRApplicationError LaunchApplication( const char *pchAppKey ) = 0;
@@ -1456,17 +1607,17 @@ namespace vr
 		virtual uint32_t GetApplicationProcessId( const char *pchAppKey ) = 0;
 
 		/** Returns a string for an applications error */
 		virtual const char *GetApplicationsErrorNameFromEnum( EVRApplicationError error ) = 0;
 
 		// ---------------  Application properties  --------------- //
 
 		/** Returns a value for an application property. The required buffer size to fit this value will be returned. */
-		virtual uint32_t GetApplicationPropertyString( const char *pchAppKey, EVRApplicationProperty eProperty, char *pchPropertyValueBuffer, uint32_t unPropertyValueBufferLen, EVRApplicationError *peError = nullptr ) = 0;
+		virtual uint32_t GetApplicationPropertyString( const char *pchAppKey, EVRApplicationProperty eProperty, VR_OUT_STRING() char *pchPropertyValueBuffer, uint32_t unPropertyValueBufferLen, EVRApplicationError *peError = nullptr ) = 0;
 
 		/** Returns a bool value for an application property. Returns false in all error cases. */
 		virtual bool GetApplicationPropertyBool( const char *pchAppKey, EVRApplicationProperty eProperty, EVRApplicationError *peError = nullptr ) = 0;
 
 		/** Returns a uint64 value for an application property. Returns 0 in all error cases. */
 		virtual uint64_t GetApplicationPropertyUint64( const char *pchAppKey, EVRApplicationProperty eProperty, EVRApplicationError *peError = nullptr ) = 0;
 
 		/** Sets the application auto-launch flag. This is only valid for applications which return true for VRApplicationProperty_IsDashboardOverlay_Bool. */
@@ -1516,138 +1667,145 @@ namespace vr
 		virtual bool IsQuitUserPromptRequested() = 0;
 
 		/** Starts a subprocess within the calling application. This
 		* suppresses all application transition UI and automatically identifies the new executable 
 		* as part of the same application. On success the calling process should exit immediately. 
 		* If working directory is NULL or "" the directory portion of the binary path will be 
 		* the working directory. */
 		virtual EVRApplicationError LaunchInternalProcess( const char *pchBinaryPath, const char *pchArguments, const char *pchWorkingDirectory ) = 0;
+
+		/** Returns the current scene process ID according to the application system. A scene process will get scene
+		* focus once it starts rendering, but it will appear here once it calls VR_Init with the Scene application
+		* type. */
+		virtual uint32_t GetCurrentSceneProcessId() = 0;
 	};
 
 	static const char * const IVRApplications_Version = "IVRApplications_006";
 
 } // namespace vr
 
 // ivrsettings.h
 namespace vr
 {
 	enum EVRSettingsError
 	{
 		VRSettingsError_None = 0,
 		VRSettingsError_IPCFailed = 1,
 		VRSettingsError_WriteFailed = 2,
 		VRSettingsError_ReadFailed = 3,
+		VRSettingsError_JsonParseFailed = 4,
+		VRSettingsError_UnsetSettingHasNoDefault = 5, // This will be returned if the setting does not appear in the appropriate default file and has not been set
 	};
 
 	// The maximum length of a settings key
 	static const uint32_t k_unMaxSettingsKeyLength = 128;
 
 	class IVRSettings
 	{
 	public:
 		virtual const char *GetSettingsErrorNameFromEnum( EVRSettingsError eError ) = 0;
 
 		// Returns true if file sync occurred (force or settings dirty)
 		virtual bool Sync( bool bForce = false, EVRSettingsError *peError = nullptr ) = 0;
 
-		virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, bool bDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
 		virtual void SetBool( const char *pchSection, const char *pchSettingsKey, bool bValue, EVRSettingsError *peError = nullptr ) = 0;
-		virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
 		virtual void SetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nValue, EVRSettingsError *peError = nullptr ) = 0;
-		virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, float flDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
 		virtual void SetFloat( const char *pchSection, const char *pchSettingsKey, float flValue, EVRSettingsError *peError = nullptr ) = 0;
-		virtual void GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, const char *pchDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
 		virtual void SetString( const char *pchSection, const char *pchSettingsKey, const char *pchValue, EVRSettingsError *peError = nullptr ) = 0;
-		
+
+		// Users of the system need to provide a proper default in default.vrsettings in the resources/settings/ directory
+		// of either the runtime or the driver_xxx directory. Otherwise the default will be false, 0, 0.0 or ""
+		virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
+		virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
+		virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
+		virtual void GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, EVRSettingsError *peError = nullptr ) = 0;
+
 		virtual void RemoveSection( const char *pchSection, EVRSettingsError *peError = nullptr ) = 0;
 		virtual void RemoveKeyInSection( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
 	};
 
 	//-----------------------------------------------------------------------------
-	static const char * const IVRSettings_Version = "IVRSettings_001";
+	static const char * const IVRSettings_Version = "IVRSettings_002";
 
 	//-----------------------------------------------------------------------------
 	// steamvr keys
-
 	static const char * const k_pch_SteamVR_Section = "steamvr";
 	static const char * const k_pch_SteamVR_RequireHmd_String = "requireHmd";
 	static const char * const k_pch_SteamVR_ForcedDriverKey_String = "forcedDriver";
 	static const char * const k_pch_SteamVR_ForcedHmdKey_String = "forcedHmd";
 	static const char * const k_pch_SteamVR_DisplayDebug_Bool = "displayDebug";
 	static const char * const k_pch_SteamVR_DebugProcessPipe_String = "debugProcessPipe";
 	static const char * const k_pch_SteamVR_EnableDistortion_Bool = "enableDistortion";
 	static const char * const k_pch_SteamVR_DisplayDebugX_Int32 = "displayDebugX";
 	static const char * const k_pch_SteamVR_DisplayDebugY_Int32 = "displayDebugY";
 	static const char * const k_pch_SteamVR_SendSystemButtonToAllApps_Bool= "sendSystemButtonToAllApps";
 	static const char * const k_pch_SteamVR_LogLevel_Int32 = "loglevel";
 	static const char * const k_pch_SteamVR_IPD_Float = "ipd";
 	static const char * const k_pch_SteamVR_Background_String = "background";
+	static const char * const k_pch_SteamVR_BackgroundUseDomeProjection_Bool = "backgroundUseDomeProjection";
 	static const char * const k_pch_SteamVR_BackgroundCameraHeight_Float = "backgroundCameraHeight";
 	static const char * const k_pch_SteamVR_BackgroundDomeRadius_Float = "backgroundDomeRadius";
-	static const char * const k_pch_SteamVR_Environment_String = "environment";
 	static const char * const k_pch_SteamVR_GridColor_String = "gridColor";
 	static const char * const k_pch_SteamVR_PlayAreaColor_String = "playAreaColor";
 	static const char * const k_pch_SteamVR_ShowStage_Bool = "showStage";
 	static const char * const k_pch_SteamVR_ActivateMultipleDrivers_Bool = "activateMultipleDrivers";
-	static const char * const k_pch_SteamVR_PowerOffOnExit_Bool = "powerOffOnExit";
-	static const char * const k_pch_SteamVR_StandbyAppRunningTimeout_Float = "standbyAppRunningTimeout";
-	static const char * const k_pch_SteamVR_StandbyNoAppTimeout_Float = "standbyNoAppTimeout";
 	static const char * const k_pch_SteamVR_DirectMode_Bool = "directMode";
 	static const char * const k_pch_SteamVR_DirectModeEdidVid_Int32 = "directModeEdidVid";
 	static const char * const k_pch_SteamVR_DirectModeEdidPid_Int32 = "directModeEdidPid";
 	static const char * const k_pch_SteamVR_UsingSpeakers_Bool = "usingSpeakers";
 	static const char * const k_pch_SteamVR_SpeakersForwardYawOffsetDegrees_Float = "speakersForwardYawOffsetDegrees";
 	static const char * const k_pch_SteamVR_BaseStationPowerManagement_Bool = "basestationPowerManagement";
 	static const char * const k_pch_SteamVR_NeverKillProcesses_Bool = "neverKillProcesses";
 	static const char * const k_pch_SteamVR_RenderTargetMultiplier_Float = "renderTargetMultiplier";
-	static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowReprojection";
+	static const char * const k_pch_SteamVR_AllowAsyncReprojection_Bool = "allowAsyncReprojection";
+	static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowInterleavedReprojection";
 	static const char * const k_pch_SteamVR_ForceReprojection_Bool = "forceReprojection";
 	static const char * const k_pch_SteamVR_ForceFadeOnBadTracking_Bool = "forceFadeOnBadTracking";
 	static const char * const k_pch_SteamVR_DefaultMirrorView_Int32 = "defaultMirrorView";
 	static const char * const k_pch_SteamVR_ShowMirrorView_Bool = "showMirrorView";
+	static const char * const k_pch_SteamVR_MirrorViewGeometry_String = "mirrorViewGeometry";
 	static const char * const k_pch_SteamVR_StartMonitorFromAppLaunch = "startMonitorFromAppLaunch";
-	static const char * const k_pch_SteamVR_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress";
-	static const char * const k_pch_SteamVR_UseGenericGraphcisDevice_Bool = "useGenericGraphicsDevice";
-
+	static const char * const k_pch_SteamVR_StartCompositorFromAppLaunch_Bool = "startCompositorFromAppLaunch";
+	static const char * const k_pch_SteamVR_StartDashboardFromAppLaunch_Bool = "startDashboardFromAppLaunch";
+	static const char * const k_pch_SteamVR_StartOverlayAppsFromDashboard_Bool = "startOverlayAppsFromDashboard";
+	static const char * const k_pch_SteamVR_EnableHomeApp = "enableHomeApp";
+	static const char * const k_pch_SteamVR_SetInitialDefaultHomeApp = "setInitialDefaultHomeApp";
+	static const char * const k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32 = "CycleBackgroundImageTimeSec";
+	static const char * const k_pch_SteamVR_RetailDemo_Bool = "retailDemo";
+	static const char * const k_pch_SteamVR_IpdOffset_Float = "ipdOffset";
 
 	//-----------------------------------------------------------------------------
 	// lighthouse keys
-
 	static const char * const k_pch_Lighthouse_Section = "driver_lighthouse";
 	static const char * const k_pch_Lighthouse_DisableIMU_Bool = "disableimu";
 	static const char * const k_pch_Lighthouse_UseDisambiguation_String = "usedisambiguation";
 	static const char * const k_pch_Lighthouse_DisambiguationDebug_Int32 = "disambiguationdebug";
-
 	static const char * const k_pch_Lighthouse_PrimaryBasestation_Int32 = "primarybasestation";
-	static const char * const k_pch_Lighthouse_LighthouseName_String = "lighthousename";
-	static const char * const k_pch_Lighthouse_MaxIncidenceAngleDegrees_Float = "maxincidenceangledegrees";
-	static const char * const k_pch_Lighthouse_UseLighthouseDirect_Bool = "uselighthousedirect";
 	static const char * const k_pch_Lighthouse_DBHistory_Bool = "dbhistory";
 
 	//-----------------------------------------------------------------------------
 	// null keys
-
 	static const char * const k_pch_Null_Section = "driver_null";
-	static const char * const k_pch_Null_EnableNullDriver_Bool = "enable";
 	static const char * const k_pch_Null_SerialNumber_String = "serialNumber";
 	static const char * const k_pch_Null_ModelNumber_String = "modelNumber";
 	static const char * const k_pch_Null_WindowX_Int32 = "windowX";
 	static const char * const k_pch_Null_WindowY_Int32 = "windowY";
 	static const char * const k_pch_Null_WindowWidth_Int32 = "windowWidth";
 	static const char * const k_pch_Null_WindowHeight_Int32 = "windowHeight";
 	static const char * const k_pch_Null_RenderWidth_Int32 = "renderWidth";
 	static const char * const k_pch_Null_RenderHeight_Int32 = "renderHeight";
 	static const char * const k_pch_Null_SecondsFromVsyncToPhotons_Float = "secondsFromVsyncToPhotons";
 	static const char * const k_pch_Null_DisplayFrequency_Float = "displayFrequency";
 
 	//-----------------------------------------------------------------------------
 	// user interface keys
 	static const char * const k_pch_UserInterface_Section = "userinterface";
 	static const char * const k_pch_UserInterface_StatusAlwaysOnTop_Bool = "StatusAlwaysOnTop";
+	static const char * const k_pch_UserInterface_MinimizeToTray_Bool = "MinimizeToTray";
 	static const char * const k_pch_UserInterface_Screenshots_Bool = "screenshots";
 	static const char * const k_pch_UserInterface_ScreenshotType_Int = "screenshotType";
 
 	//-----------------------------------------------------------------------------
 	// notification keys
 	static const char * const k_pch_Notifications_Section = "notifications";
 	static const char * const k_pch_Notifications_DoNotDisturb_Bool = "DoNotDisturb";
 
@@ -1691,31 +1849,51 @@ namespace vr
 	static const char * const k_pch_Camera_EnableCamera_Bool = "enableCamera";
 	static const char * const k_pch_Camera_EnableCameraInDashboard_Bool = "enableCameraInDashboard";
 	static const char * const k_pch_Camera_EnableCameraForCollisionBounds_Bool = "enableCameraForCollisionBounds";
 	static const char * const k_pch_Camera_EnableCameraForRoomView_Bool = "enableCameraForRoomView";
 	static const char * const k_pch_Camera_BoundsColorGammaR_Int32 = "cameraBoundsColorGammaR";
 	static const char * const k_pch_Camera_BoundsColorGammaG_Int32 = "cameraBoundsColorGammaG";
 	static const char * const k_pch_Camera_BoundsColorGammaB_Int32 = "cameraBoundsColorGammaB";
 	static const char * const k_pch_Camera_BoundsColorGammaA_Int32 = "cameraBoundsColorGammaA";
+	static const char * const k_pch_Camera_BoundsStrength_Int32 = "cameraBoundsStrength";
 
 	//-----------------------------------------------------------------------------
 	// audio keys
 	static const char * const k_pch_audio_Section = "audio";
 	static const char * const k_pch_audio_OnPlaybackDevice_String = "onPlaybackDevice";
 	static const char * const k_pch_audio_OnRecordDevice_String = "onRecordDevice";
 	static const char * const k_pch_audio_OnPlaybackMirrorDevice_String = "onPlaybackMirrorDevice";
 	static const char * const k_pch_audio_OffPlaybackDevice_String = "offPlaybackDevice";
 	static const char * const k_pch_audio_OffRecordDevice_String = "offRecordDevice";
 	static const char * const k_pch_audio_VIVEHDMIGain = "viveHDMIGain";
 
 	//-----------------------------------------------------------------------------
+	// power management keys
+	static const char * const k_pch_Power_Section = "power";
+	static const char * const k_pch_Power_PowerOffOnExit_Bool = "powerOffOnExit";
+	static const char * const k_pch_Power_TurnOffScreensTimeout_Float = "turnOffScreensTimeout";
+	static const char * const k_pch_Power_TurnOffControllersTimeout_Float = "turnOffControllersTimeout";
+	static const char * const k_pch_Power_ReturnToWatchdogTimeout_Float = "returnToWatchdogTimeout";
+	static const char * const k_pch_Power_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress";
+
+	//-----------------------------------------------------------------------------
+	// dashboard keys
+	static const char * const k_pch_Dashboard_Section = "dashboard";
+	static const char * const k_pch_Dashboard_EnableDashboard_Bool = "enableDashboard";
+	static const char * const k_pch_Dashboard_ArcadeMode_Bool = "arcadeMode";
+
+	//-----------------------------------------------------------------------------
 	// model skin keys
 	static const char * const k_pch_modelskin_Section = "modelskins";
 
+	//-----------------------------------------------------------------------------
+	// driver keys - These could be checked in any driver_<name> section
+	static const char * const k_pch_Driver_Enable_Bool = "enable";
+
 } // namespace vr
 
 // ivrchaperone.h
 namespace vr
 {
 
 #if defined(__linux__) || defined(__APPLE__) 
 	// The 32-bit version of gcc has the alignment requirement for uint64 and double set to
@@ -1736,17 +1914,17 @@ enum ChaperoneCalibrationState
 	// Warnings
 	ChaperoneCalibrationState_Warning = 100,
 	ChaperoneCalibrationState_Warning_BaseStationMayHaveMoved = 101,	// A base station thinks that it might have moved
 	ChaperoneCalibrationState_Warning_BaseStationRemoved = 102,			// There are less base stations than when calibrated
 	ChaperoneCalibrationState_Warning_SeatedBoundsInvalid = 103,		// Seated bounds haven't been calibrated for the current tracking center
 
 	// Errors
 	ChaperoneCalibrationState_Error = 200,								// The UniverseID is invalid
-	ChaperoneCalibrationState_Error_BaseStationUninitalized = 201,		// Tracking center hasn't be calibrated for at least one of the base stations
+	ChaperoneCalibrationState_Error_BaseStationUninitialized = 201,		// Tracking center hasn't be calibrated for at least one of the base stations
 	ChaperoneCalibrationState_Error_BaseStationConflict = 202,			// Tracking center is calibrated, but base stations disagree on the tracking space
 	ChaperoneCalibrationState_Error_PlayAreaInvalid = 203,				// Play Area hasn't been calibrated for the current tracking center
 	ChaperoneCalibrationState_Error_CollisionBoundsInvalid = 204,		// Collision Bounds haven't been calibrated for the current tracking center
 };
 
 
 /** HIGH LEVEL TRACKING SPACE ASSUMPTIONS:
 * 0,0,0 is the preferred standing area center.
@@ -1906,27 +2084,35 @@ enum EVRCompositorError
 	VRCompositorError_IncompatibleVersion		= 100,
 	VRCompositorError_DoNotHaveFocus			= 101,
 	VRCompositorError_InvalidTexture			= 102,
 	VRCompositorError_IsNotSceneApplication		= 103,
 	VRCompositorError_TextureIsOnWrongDevice	= 104,
 	VRCompositorError_TextureUsesUnsupportedFormat = 105,
 	VRCompositorError_SharedTexturesNotSupported = 106,
 	VRCompositorError_IndexOutOfRange			= 107,
+	VRCompositorError_AlreadySubmitted			= 108,
 };
 
 const uint32_t VRCompositor_ReprojectionReason_Cpu = 0x01;
 const uint32_t VRCompositor_ReprojectionReason_Gpu = 0x02;
+const uint32_t VRCompositor_ReprojectionAsync      = 0x04;	// This flag indicates the async reprojection mode is active,
+															// but does not indicate if reprojection actually happened or not.
+															// Use the ReprojectionReason flags above to check if reprojection
+															// was actually applied (i.e. scene texture was reused).
+															// NumFramePresents > 1 also indicates the scene texture was reused,
+															// and also the number of times that it was presented in total.
 
 /** Provides a single frame's timing information to the app */
 struct Compositor_FrameTiming
 {
 	uint32_t m_nSize; // Set to sizeof( Compositor_FrameTiming )
 	uint32_t m_nFrameIndex;
 	uint32_t m_nNumFramePresents; // number of times this frame was presented
+	uint32_t m_nNumMisPresented; // number of times this frame was presented on a vsync other than it was originally predicted to
 	uint32_t m_nNumDroppedFrames; // number of additional times previous frame was scanned out
 	uint32_t m_nReprojectionFlags;
 
 	/** Absolute time reference for comparing frames.  This aligns with the vsync that running start is relative to. */
 	double m_flSystemTimeInSeconds;
 
 	/** These times may include work from other processes due to OS scheduling.
 	* The fewer packets of work these are broken up into, the less likely this will happen.
@@ -1993,17 +2179,24 @@ class IVRCompositor
 {
 public:
 	/** Sets tracking space returned by WaitGetPoses */
 	virtual void SetTrackingSpace( ETrackingUniverseOrigin eOrigin ) = 0;
 
 	/** Gets current tracking space returned by WaitGetPoses */
 	virtual ETrackingUniverseOrigin GetTrackingSpace() = 0;
 
-	/** Returns pose(s) to use to render scene (and optionally poses predicted two frames out for gameplay). */
+	/** Scene applications should call this function to get poses to render with (and optionally poses predicted an additional frame out to use for gameplay).
+	* This function will block until "running start" milliseconds before the start of the frame, and should be called at the last moment before needing to
+	* start rendering.
+	*
+	* Return codes:
+	*	- IsNotSceneApplication (make sure to call VR_Init with VRApplicaiton_Scene)
+	*	- DoNotHaveFocus (some other app has taken focus - this will throttle the call to 10hz to reduce the impact on that app)
+	*/
 	virtual EVRCompositorError WaitGetPoses( VR_ARRAY_COUNT(unRenderPoseArrayCount) TrackedDevicePose_t* pRenderPoseArray, uint32_t unRenderPoseArrayCount,
 		VR_ARRAY_COUNT(unGamePoseArrayCount) TrackedDevicePose_t* pGamePoseArray, uint32_t unGamePoseArrayCount ) = 0;
 
 	/** Get the last set of poses returned by WaitGetPoses. */
 	virtual EVRCompositorError GetLastPoses( VR_ARRAY_COUNT( unRenderPoseArrayCount ) TrackedDevicePose_t* pRenderPoseArray, uint32_t unRenderPoseArrayCount,
 		VR_ARRAY_COUNT( unGamePoseArrayCount ) TrackedDevicePose_t* pGamePoseArray, uint32_t unGamePoseArrayCount ) = 0;
 
 	/** Interface for accessing last set of poses returned by WaitGetPoses one at a time.
@@ -2011,16 +2204,25 @@ public:
 	* It is okay to pass NULL for either pose if you only want one of the values. */
 	virtual EVRCompositorError GetLastPoseForTrackedDeviceIndex( TrackedDeviceIndex_t unDeviceIndex, TrackedDevicePose_t *pOutputPose, TrackedDevicePose_t *pOutputGamePose ) = 0;
 
 	/** Updated scene texture to display. If pBounds is NULL the entire texture will be used.  If called from an OpenGL app, consider adding a glFlush after
 	* Submitting both frames to signal the driver to start processing, otherwise it may wait until the command buffer fills up, causing the app to miss frames.
 	*
 	* OpenGL dirty state:
 	*	glBindTexture
+	*
+	* Return codes:
+	*	- IsNotSceneApplication (make sure to call VR_Init with VRApplicaiton_Scene)
+	*	- DoNotHaveFocus (some other app has taken focus)
+	*	- TextureIsOnWrongDevice (application did not use proper AdapterIndex - see IVRSystem.GetDXGIOutputInfo)
+	*	- SharedTexturesNotSupported (application needs to call CreateDXGIFactory1 or later before creating DX device)
+	*	- TextureUsesUnsupportedFormat (scene textures must be compatible with DXGI sharing rules - e.g. uncompressed, no mips, etc.)
+	*	- InvalidTexture (usually means bad arguments passed in)
+	*	- AlreadySubmitted (app has submitted two left textures or two right textures in a single frame - i.e. before calling WaitGetPoses again)
 	*/
 	virtual EVRCompositorError Submit( EVREye eEye, const Texture_t *pTexture, const VRTextureBounds_t* pBounds = 0, EVRSubmitFlags nSubmitFlags = Submit_Default ) = 0;
 
 	/** Clears the frame that was sent with the last call to Submit. This will cause the 
 	* compositor to show the grid until Submit is called again. */
 	virtual void ClearLastSubmittedFrame() = 0;
 
 	/** Call immediately after presenting your app's window (i.e. companion window) to unblock the compositor.
@@ -2029,31 +2231,41 @@ public:
 	* introduce a deadlock of some sort.  This function tells the compositor that you have finished all rendering after having Submitted buffers for both
 	* eyes, and it is free to start its rendering work.  This should only be called from the same thread you are rendering on. */
 	virtual void PostPresentHandoff() = 0;
 
 	/** Returns true if timing data is filled it.  Sets oldest timing info if nFramesAgo is larger than the stored history.
 	* Be sure to set timing.size = sizeof(Compositor_FrameTiming) on struct passed in before calling this function. */
 	virtual bool GetFrameTiming( Compositor_FrameTiming *pTiming, uint32_t unFramesAgo = 0 ) = 0;
 
+	/** Interface for copying a range of timing data.  Frames are returned in ascending order (oldest to newest) with the last being the most recent frame.
+	* Only the first entry's m_nSize needs to be set, as the rest will be inferred from that.  Returns total number of entries filled out. */
+	virtual uint32_t GetFrameTimings( Compositor_FrameTiming *pTiming, uint32_t nFrames ) = 0;
+
 	/** Returns the time in seconds left in the current (as identified by FrameTiming's frameIndex) frame.
 	* Due to "running start", this value may roll over to the next frame before ever reaching 0.0. */
 	virtual float GetFrameTimeRemaining() = 0;
 
 	/** Fills out stats accumulated for the last connected application.  Pass in sizeof( Compositor_CumulativeStats ) as second parameter. */
 	virtual void GetCumulativeStats( Compositor_CumulativeStats *pStats, uint32_t nStatsSizeInBytes ) = 0;
 
 	/** Fades the view on the HMD to the specified color. The fade will take fSeconds, and the color values are between
 	* 0.0 and 1.0. This color is faded on top of the scene based on the alpha parameter. Removing the fade color instantly 
 	* would be FadeToColor( 0.0, 0.0, 0.0, 0.0, 0.0 ).  Values are in un-premultiplied alpha space. */
 	virtual void FadeToColor( float fSeconds, float fRed, float fGreen, float fBlue, float fAlpha, bool bBackground = false ) = 0;
 
+	/** Get current fade color value. */
+	virtual HmdColor_t GetCurrentFadeColor( bool bBackground = false ) = 0;
+
 	/** Fading the Grid in or out in fSeconds */
 	virtual void FadeGrid( float fSeconds, bool bFadeIn ) = 0;
 
+	/** Get current alpha value of grid. */
+	virtual float GetCurrentGridAlpha() = 0;
+
 	/** Override the skybox used in the compositor (e.g. for during level loads when the app can't feed scene images fast enough)
 	* Order is Front, Back, Left, Right, Top, Bottom.  If only a single texture is passed, it is assumed in lat-long format.
 	* If two are passed, it is assumed a lat-long stereo pair. */
 	virtual EVRCompositorError SetSkyboxOverride( VR_ARRAY_COUNT( unTextureCount ) const Texture_t *pTextures, uint32_t unTextureCount ) = 0;
 
 	/** Resets compositor skybox back to defaults. */
 	virtual void ClearSkyboxOverride() = 0;
 
@@ -2100,27 +2312,40 @@ public:
 	virtual void ForceInterleavedReprojectionOn( bool bOverride ) = 0;
 
 	/** Force reconnecting to the compositor process. */
 	virtual void ForceReconnectProcess() = 0;
 
 	/** Temporarily suspends rendering (useful for finer control over scene transitions). */
 	virtual void SuspendRendering( bool bSuspend ) = 0;
 
-	/** Opens a shared D3D11 texture with the undistorted composited image for each eye. */
+	/** Opens a shared D3D11 texture with the undistorted composited image for each eye.  Use ReleaseMirrorTextureD3D11 when finished
+	* instead of calling Release on the resource itself. */
 	virtual vr::EVRCompositorError GetMirrorTextureD3D11( vr::EVREye eEye, void *pD3D11DeviceOrResource, void **ppD3D11ShaderResourceView ) = 0;
+	virtual void ReleaseMirrorTextureD3D11( void *pD3D11ShaderResourceView ) = 0;
 
 	/** Access to mirror textures from OpenGL. */
 	virtual vr::EVRCompositorError GetMirrorTextureGL( vr::EVREye eEye, vr::glUInt_t *pglTextureId, vr::glSharedTextureHandle_t *pglSharedTextureHandle ) = 0;
 	virtual bool ReleaseSharedGLTexture( vr::glUInt_t glTextureId, vr::glSharedTextureHandle_t glSharedTextureHandle ) = 0;
 	virtual void LockGLSharedTextureForAccess( vr::glSharedTextureHandle_t glSharedTextureHandle ) = 0;
 	virtual void UnlockGLSharedTextureForAccess( vr::glSharedTextureHandle_t glSharedTextureHandle ) = 0;
+
+	/** [Vulkan Only]
+	* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
+	* null.  The string will be a space separated list of-required instance extensions to enable in VkCreateInstance */
+	virtual uint32_t GetVulkanInstanceExtensionsRequired( VR_OUT_STRING() char *pchValue, uint32_t unBufferSize ) = 0;
+
+	/** [Vulkan only]
+	* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
+	* null.  The string will be a space separated list of required device extensions to enable in VkCreateDevice */
+	virtual uint32_t GetVulkanDeviceExtensionsRequired( VkPhysicalDevice_T *pPhysicalDevice, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize ) = 0;
+
 };
 
-static const char * const IVRCompositor_Version = "IVRCompositor_016";
+static const char * const IVRCompositor_Version = "IVRCompositor_020";
 
 } // namespace vr
 
 
 
 // ivrnotifications.h
 namespace vr
 {
@@ -2227,16 +2452,19 @@ namespace vr
 	static const uint32_t k_unVROverlayMaxKeyLength = 128;
 
 	/** The maximum length of an overlay name in bytes, counting the terminating null character. */
 	static const uint32_t k_unVROverlayMaxNameLength = 128;
 
 	/** The maximum number of overlays that can exist in the system at one time. */
 	static const uint32_t k_unMaxOverlayCount = 64;
 
+	/** The maximum number of overlay intersection mask primitives per overlay */
+	static const uint32_t k_unMaxOverlayIntersectionMaskPrimitivesCount = 32;
+
 	/** Types of input supported by VR Overlays */
 	enum VROverlayInputMethod
 	{
 		VROverlayInputMethod_None		= 0, // No input events will be generated automatically for this overlay
 		VROverlayInputMethod_Mouse		= 1, // Tracked controllers will get mouse events automatically
 	};
 
 	/** Allows the caller to figure out which overlay transform getter to call. */
@@ -2283,16 +2511,30 @@ namespace vr
 		VROverlayFlags_SideBySide_Crossed = 11, // Texture is crossed and right/left
 
 		VROverlayFlags_Panorama = 12, // Texture is a panorama
 		VROverlayFlags_StereoPanorama = 13, // Texture is a stereo panorama
 
 		// If this is set on an overlay owned by the scene application that overlay
 		// will be sorted with the "Other" overlays on top of all other scene overlays
 		VROverlayFlags_SortWithNonSceneOverlays = 14,
+
+		// If set, the overlay will be shown in the dashboard, otherwise it will be hidden.
+		VROverlayFlags_VisibleInDashboard = 15,
+	};
+
+	enum VRMessageOverlayResponse
+	{
+		VRMessageOverlayResponse_ButtonPress_0 = 0,
+		VRMessageOverlayResponse_ButtonPress_1 = 1,
+		VRMessageOverlayResponse_ButtonPress_2 = 2,
+		VRMessageOverlayResponse_ButtonPress_3 = 3,
+		VRMessageOverlayResponse_CouldntFindSystemOverlay = 4,
+		VRMessageOverlayResponse_CouldntFindOrCreateClientOverlay= 5,
+		VRMessageOverlayResponse_ApplicationQuit = 6
 	};
 
 	struct VROverlayIntersectionParams_t
 	{
 		HmdVector3_t vSource;
 		HmdVector3_t vDirection;
 		ETrackingUniverseOrigin eOrigin;
 	};
@@ -2326,16 +2568,50 @@ namespace vr
 		OverlayDirection_Up = 0,
 		OverlayDirection_Down = 1,
 		OverlayDirection_Left = 2,
 		OverlayDirection_Right = 3,
 		
 		OverlayDirection_Count = 4,
 	};
 
+	enum EVROverlayIntersectionMaskPrimitiveType
+	{
+		OverlayIntersectionPrimitiveType_Rectangle,
+		OverlayIntersectionPrimitiveType_Circle,
+	};
+
+	struct IntersectionMaskRectangle_t
+	{
+		float m_flTopLeftX;
+		float m_flTopLeftY;
+		float m_flWidth;
+		float m_flHeight;
+	};
+
+	struct IntersectionMaskCircle_t
+	{
+		float m_flCenterX;
+		float m_flCenterY;
+		float m_flRadius;
+	};
+
+	/** NOTE!!! If you change this you MUST manually update openvr_interop.cs.py and openvr_api_flat.h.py */
+	typedef union
+	{
+		IntersectionMaskRectangle_t m_Rectangle;
+		IntersectionMaskCircle_t m_Circle;
+	} VROverlayIntersectionMaskPrimitive_Data_t;
+
+	struct VROverlayIntersectionMaskPrimitive_t
+	{
+		EVROverlayIntersectionMaskPrimitiveType m_nPrimitiveType;
+		VROverlayIntersectionMaskPrimitive_Data_t m_Primitive;
+	};
+
 	class IVROverlay
 	{
 	public:
 
 		// ---------------------------------------------
 		// Overlay management methods
 		// ---------------------------------------------
 
@@ -2566,17 +2842,17 @@ namespace vr
 		*
 		* The texture will always be sized to match the backing texture you supplied in SetOverlayTexture above.
 		*
 		* You MUST call ReleaseNativeOverlayHandle() with pNativeTextureHandle once you are done with this texture.
 		*
 		* pNativeTextureHandle is an OUTPUT, it will be a pointer to a ID3D11ShaderResourceView *.
 		* pNativeTextureRef is an INPUT and should be a ID3D11Resource *. The device used by pNativeTextureRef will be used to bind pNativeTextureHandle.
 		*/
-		virtual EVROverlayError GetOverlayTexture( VROverlayHandle_t ulOverlayHandle, void **pNativeTextureHandle, void *pNativeTextureRef, uint32_t *pWidth, uint32_t *pHeight, uint32_t *pNativeFormat, EGraphicsAPIConvention *pAPI, EColorSpace *pColorSpace ) = 0;
+		virtual EVROverlayError GetOverlayTexture( VROverlayHandle_t ulOverlayHandle, void **pNativeTextureHandle, void *pNativeTextureRef, uint32_t *pWidth, uint32_t *pHeight, uint32_t *pNativeFormat, ETextureType *pAPIType, EColorSpace *pColorSpace, VRTextureBounds_t *pTextureBounds ) = 0;
 
 		/** Release the pNativeTextureHandle provided from the GetOverlayTexture call, this allows the system to free the underlying GPU resources for this object,
 		* so only do it once you stop rendering this texture.
 		*/
 		virtual EVROverlayError ReleaseNativeOverlayHandle( VROverlayHandle_t ulOverlayHandle, void *pNativeTextureHandle ) = 0;
 
 		/** Get the size of the overlay texture */
 		virtual EVROverlayError GetOverlayTextureSize( VROverlayHandle_t ulOverlayHandle, uint32_t *pWidth, uint32_t *pHeight ) = 0;
@@ -2622,19 +2898,35 @@ namespace vr
 		virtual void HideKeyboard() = 0;
 
 		/** Set the position of the keyboard in world space **/
 		virtual void SetKeyboardTransformAbsolute( ETrackingUniverseOrigin eTrackingOrigin, const HmdMatrix34_t *pmatTrackingOriginToKeyboardTransform ) = 0;
 
 		/** Set the position of the keyboard in overlay space by telling it to avoid a rectangle in the overlay. Rectangle coords have (0,0) in the bottom left **/
 		virtual void SetKeyboardPositionForOverlay( VROverlayHandle_t ulOverlayHandle, HmdRect2_t avoidRect ) = 0;
 
+		// ---------------------------------------------
+		// Overlay input methods
+		// ---------------------------------------------
+
+		/** Sets a list of primitives to be used for controller ray intersection
+		* typically the size of the underlying UI in pixels (not in world space). */
+		virtual EVROverlayError SetOverlayIntersectionMask( VROverlayHandle_t ulOverlayHandle, VROverlayIntersectionMaskPrimitive_t *pMaskPrimitives, uint32_t unNumMaskPrimitives, uint32_t unPrimitiveSize = sizeof( VROverlayIntersectionMaskPrimitive_t ) ) = 0;
+
+		virtual EVROverlayError GetOverlayFlags( VROverlayHandle_t ulOverlayHandle, uint32_t *pFlags ) = 0;
+
+		// ---------------------------------------------
+		// Message box methods
+		// ---------------------------------------------
+
+		/** Show the message overlay. This will block and return you a result. **/
+		virtual VRMessageOverlayResponse ShowMessageOverlay( const char* pchText, const char* pchCaption, const char* pchButton0Text, const char* pchButton1Text = nullptr, const char* pchButton2Text = nullptr, const char* pchButton3Text = nullptr ) = 0;
 	};
 
-	static const char * const IVROverlay_Version = "IVROverlay_013";
+	static const char * const IVROverlay_Version = "IVROverlay_014";
 
 } // namespace vr
 
 // ivrrendermodels.h
 namespace vr
 {
 
 static const char * const k_pch_Controller_Component_GDC2015 = "gdc2015";   // Canonical coordinate system of the gdc 2015 wired controller, provided for backwards compatibility
@@ -2869,17 +3161,17 @@ public:
 	virtual const char *GetCameraErrorNameFromEnum( vr::EVRTrackedCameraError eCameraError ) = 0;
 
 	/** For convenience, same as tracked property request Prop_HasCamera_Bool */
 	virtual vr::EVRTrackedCameraError HasCamera( vr::TrackedDeviceIndex_t nDeviceIndex, bool *pHasCamera ) = 0;
 
 	/** Gets size of the image frame. */
 	virtual vr::EVRTrackedCameraError GetCameraFrameSize( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, uint32_t *pnWidth, uint32_t *pnHeight, uint32_t *pnFrameBufferSize ) = 0;
 
-	virtual vr::EVRTrackedCameraError GetCameraIntrinisics( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, vr::HmdVector2_t *pFocalLength, vr::HmdVector2_t *pCenter ) = 0;
+	virtual vr::EVRTrackedCameraError GetCameraIntrinsics( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, vr::HmdVector2_t *pFocalLength, vr::HmdVector2_t *pCenter ) = 0;
 
 	virtual vr::EVRTrackedCameraError GetCameraProjection( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, float flZNear, float flZFar, vr::HmdMatrix44_t *pProjection ) = 0;
 
 	/** Acquiring streaming service permits video streaming for the caller. Releasing hints the system that video services do not need to be maintained for this client.
 	* If the camera has not already been activated, a one time spin up may incur some auto exposure as well as initial streaming frame delays.
 	* The camera should be considered a global resource accessible for shared consumption but not exclusive to any caller.
 	* The camera may go inactive due to lack of active consumers or headset idleness. */
 	virtual vr::EVRTrackedCameraError AcquireVideoStreamingService( vr::TrackedDeviceIndex_t nDeviceIndex, vr::TrackedCameraHandle_t *pHandle ) = 0;
@@ -2890,17 +3182,22 @@ public:
 	* the caller to determine if the frame as advanced per the frame header sequence. 
 	* If there is no frame available yet, due to initial camera spinup or re-activation, the error will be VRTrackedCameraError_NoFrameAvailable.
 	* Ideally a caller should be polling at ~16ms intervals */
 	virtual vr::EVRTrackedCameraError GetVideoStreamFrameBuffer( vr::TrackedCameraHandle_t hTrackedCamera, vr::EVRTrackedCameraFrameType eFrameType, void *pFrameBuffer, uint32_t nFrameBufferSize, vr::CameraVideoStreamFrameHeader_t *pFrameHeader, uint32_t nFrameHeaderSize ) = 0;
 
 	/** Gets size of the image frame. */
 	virtual vr::EVRTrackedCameraError GetVideoStreamTextureSize( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, vr::VRTextureBounds_t *pTextureBounds, uint32_t *pnWidth, uint32_t *pnHeight ) = 0; 
 
-	/** Access a shared D3D11 texture for the specified tracked camera stream */
+	/** Access a shared D3D11 texture for the specified tracked camera stream.
+	* The camera frame type VRTrackedCameraFrameType_Undistorted is not supported directly as a shared texture. It is an interior subregion of the shared texture VRTrackedCameraFrameType_MaximumUndistorted.
+	* Instead, use GetVideoStreamTextureSize() with VRTrackedCameraFrameType_Undistorted to determine the proper interior subregion bounds along with GetVideoStreamTextureD3D11() with
+	* VRTrackedCameraFrameType_MaximumUndistorted to provide the texture. The VRTrackedCameraFrameType_MaximumUndistorted will yield an image where the invalid regions are decoded
+	* by the alpha channel having a zero component. The valid regions all have a non-zero alpha component. The subregion as described by VRTrackedCameraFrameType_Undistorted 
+	* guarantees a rectangle where all pixels are valid. */
 	virtual vr::EVRTrackedCameraError GetVideoStreamTextureD3D11( vr::TrackedCameraHandle_t hTrackedCamera, vr::EVRTrackedCameraFrameType eFrameType, void *pD3D11DeviceOrResource, void **ppD3D11ShaderResourceView, vr::CameraVideoStreamFrameHeader_t *pFrameHeader, uint32_t nFrameHeaderSize ) = 0;
 
 	/** Access a shared GL texture for the specified tracked camera stream */
 	virtual vr::EVRTrackedCameraError GetVideoStreamTextureGL( vr::TrackedCameraHandle_t hTrackedCamera, vr::EVRTrackedCameraFrameType eFrameType, vr::glUInt_t *pglTextureId, vr::CameraVideoStreamFrameHeader_t *pFrameHeader, uint32_t nFrameHeaderSize ) = 0;
 	virtual vr::EVRTrackedCameraError ReleaseVideoStreamTextureGL( vr::TrackedCameraHandle_t hTrackedCamera, vr::glUInt_t glTextureId ) = 0;
 };
 
 static const char * const IVRTrackedCamera_Version = "IVRTrackedCamera_003";
@@ -3040,17 +3337,16 @@ public:
 
 static const char * const IVRResources_Version = "IVRResources_001";
 
 
 }// End
 
 #endif // _OPENVR_API
 
-
 namespace vr
 {
 	/** Finds the active installation of the VR API and initializes it. The provided path must be absolute
 	* or relative to the current working directory. These are the local install versions of the equivalent
 	* functions in steamvr.h and will work without a local Steam install.
 	*
 	* This path is to the "root" of the VR API install. That's the directory with
 	* the "drivers" directory and a platform (i.e. "win32") directory in it, not the directory with the DLL itself.
@@ -3091,17 +3387,16 @@ namespace vr
 
 	/** Returns a token that represents whether the VR interface handles need to be reloaded */
 	VR_INTERFACE uint32_t VR_CALLTYPE VR_GetInitToken();
 
 	// These typedefs allow old enum names from SDK 0.9.11 to be used in applications.
 	// They will go away in the future.
 	typedef EVRInitError HmdError;
 	typedef EVREye Hmd_Eye;
-	typedef EGraphicsAPIConvention GraphicsAPIConvention;
 	typedef EColorSpace ColorSpace;
 	typedef ETrackingResult HmdTrackingResult;
 	typedef ETrackedDeviceClass TrackedDeviceClass;
 	typedef ETrackingUniverseOrigin TrackingUniverseOrigin;
 	typedef ETrackedDeviceProperty TrackedDeviceProperty;
 	typedef ETrackedPropertyError TrackedPropertyError;
 	typedef EVRSubmitFlags VRSubmitFlags_t;
 	typedef EVRState VRState_t;
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/moz.build
@@ -0,0 +1,47 @@
+# -*- 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/.
+
+FINAL_LIBRARY = 'xul'
+
+DEFINES['VR_API_PUBLIC'] = True
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    if CONFIG['HAVE_64BIT_BUILD']:
+        DEFINES['WIN64'] = True
+    else:
+        DEFINES['WIN32'] = True
+
+# When we support platforms other than Windows, we
+# will also need to define these:
+#
+#   LINUX64
+#   LINUX
+#   OSX
+#   POSIX
+
+LOCAL_INCLUDES += [
+    '/toolkit/crashreporter/jsoncpp/include',
+]
+
+USE_LIBS += [
+    'jsoncpp',
+]
+
+EXPORTS += [
+    'headers/openvr.h',
+]
+
+SOURCES += [
+    'src/dirtools_public.cpp',
+    'src/envvartools_public.cpp',
+    'src/hmderrors_public.cpp',
+    'src/openvr_api_public.cpp',
+    'src/pathtools_public.cpp',
+    'src/sharedlibtools_public.cpp',
+    'src/strtools_public.cpp',
+    'src/vrpathregistry_public.cpp',
+]
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/README
@@ -0,0 +1,35 @@
+This is the source code for the OpenVR API client binding library which connects
+OpenVR applications to the SteamVR runtime, taking into account the version
+of the OpenVR interface they were compiled against.
+
+The client binding library - openvr_api.dll on Windows, openvr_api.so on
+Linux, and openvr_api.dylib on macOS - knows how to find and read the
+SteamVR runtime installation information which allows it to find and
+dynamically connect to the installed runtime. In combination with the
+interface version identifiers from /include/openvr.h which are baked
+into applications at the time they are built, the OpenVR API client
+binding library captures and conveys to the SteamVR runtime the version
+of the OpenVR API interface behavior that the application expects.
+
+Applications carry with them a private/local copy of the client binding
+library when they ship, and they should install it locally to their
+application.  Applications should not install the client binding library
+globally or attempt to link to a globally installed client binding library.
+Doing so negates at least part of the ability for the client binding library
+to accurately reflect the version of the OpenVR API that the application
+was built against, and so hinders compatibility support in the face of
+API changes.
+
+Most applications should simply link to and redistribute with their application
+the pre-built client binding library found in the /bin directory of this
+repository. Some small number of applications which have specific requirements
+around redistributing only binaries they build themselves should build
+the client library from this source and either statically link it into
+their application or redistribute the binary they build.
+
+This is a cmake project, to build it use the version of cmake appropriate
+for your platform. For example, to build on a POSIX system simply perform
+
+  cd src; mkdir _build; cd _build; cmake ..; make
+
+and you will end up with the static library /src/_build/libopenvr_api.a
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/dirtools_public.cpp
@@ -0,0 +1,101 @@
+//========= Copyright Valve Corporation ============//
+#include "dirtools_public.h"
+#include "strtools_public.h"
+#include "pathtools_public.h"
+
+#include <errno.h>
+#include <string.h>
+
+#ifdef _WIN32
+#include "windows.h"
+#else
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+#if defined( OSX )
+#include <sys/syslimits.h>
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: utility function to create dirs & subdirs
+//-----------------------------------------------------------------------------
+bool BCreateDirectoryRecursive( const char *pchPath )
+{
+	// Does it already exist?
+	if ( Path_IsDirectory( pchPath ) )
+		return true;
+
+	// copy the path into something we can munge
+	int len = (int)strlen( pchPath );
+	char *path = (char *)malloc( len + 1 );
+	strcpy( path, pchPath );
+
+	// Walk backwards to first non-existing dir that we find
+	char *s = path + len - 1;
+
+	const char slash = Path_GetSlash();
+	while ( s > path )
+	{
+		if ( *s == slash )
+		{
+			*s = '\0';
+			bool bExists = Path_IsDirectory( path );
+			*s = slash;
+
+			if ( bExists )
+			{
+				++s;
+				break;
+			}
+		}
+		--s;
+	}
+
+	// and then move forwards from there
+
+	while ( *s )
+	{
+		if ( *s == slash )
+		{
+			*s = '\0';
+			BCreateDirectory( path );
+			*s = slash;
+		}
+		s++;
+	}
+
+	bool bRetVal = BCreateDirectory( path );
+	free( path );
+	return bRetVal;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates the directory, returning true if it is created, or if it already existed
+//-----------------------------------------------------------------------------
+bool BCreateDirectory( const char *pchPath )
+{
+#ifdef WIN32
+	std::wstring wPath = UTF8to16( pchPath );
+	if ( ::CreateDirectoryW( wPath.c_str(), NULL ) )
+		return true;
+
+	if ( ::GetLastError() == ERROR_ALREADY_EXISTS )
+		return true;
+
+	return false;
+#else
+	int i = mkdir( pchPath, S_IRWXU | S_IRWXG | S_IRWXO );
+	if ( i == 0 )
+		return true;
+	if ( errno == EEXIST )
+		return true;
+
+	return false;
+#endif
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/dirtools_public.h
@@ -0,0 +1,17 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+#include <stdint.h>
+#include <string>
+
+
+#if !defined(_WIN32)
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+
+extern bool BCreateDirectoryRecursive( const char *pchPath );
+extern bool BCreateDirectory( const char *pchPath );
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/envvartools_public.cpp
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation ============//
+#include "envvartools_public.h"
+#include <stdlib.h>
+
+#if defined(_WIN32)
+#include <Windows.h>
+
+#undef GetEnvironmentVariable
+#undef SetEnvironmentVariable
+#endif
+
+
+std::string GetEnvironmentVariable( const char *pchVarName )
+{
+#if defined(_WIN32)
+	char rchValue[32767]; // max size for an env var on Windows
+	DWORD cChars = GetEnvironmentVariableA( pchVarName, rchValue, sizeof( rchValue ) );
+	if( cChars == 0 )
+		return "";
+	else
+		return rchValue;
+#elif defined(POSIX)
+	char *pchValue = getenv( pchVarName );
+	if( pchValue )
+		return pchValue;
+	else
+		return "";
+#else
+#error "Unsupported Platform"
+#endif
+}
+
+
+bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue )
+{
+#if defined(_WIN32)
+	return 0 != SetEnvironmentVariableA( pchVarName, pchVarValue );
+#elif defined(POSIX)
+	if( pchVarValue == NULL )
+		return 0 == unsetenv( pchVarName );
+	else
+		return 0 == setenv( pchVarName, pchVarValue, 1 );
+#else
+#error "Unsupported Platform"
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/envvartools_public.h
@@ -0,0 +1,7 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+#include <string>
+
+std::string GetEnvironmentVariable( const char *pchVarName );
+bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue );
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/hmderrors_public.cpp
@@ -0,0 +1,205 @@
+//========= Copyright Valve Corporation ============//
+#include "openvr.h"
+#include "hmderrors_public.h"
+#include <stdio.h>
+#include <algorithm>
+
+using namespace vr;
+
+#define RETURN_ENUM_AS_STRING(enumValue) case enumValue: return #enumValue;
+
+
+const char *GetEnglishStringForHmdError( vr::EVRInitError eError )
+{
+	switch( eError )
+	{
+	case VRInitError_None:						return "No Error (0)";
+
+	case VRInitError_Init_InstallationNotFound:	return "Installation Not Found (100)";
+	case VRInitError_Init_InstallationCorrupt:	return "Installation Corrupt (101)";
+	case VRInitError_Init_VRClientDLLNotFound:	return "vrclient Shared Lib Not Found (102)";
+	case VRInitError_Init_FileNotFound:			return "File Not Found (103)";
+	case VRInitError_Init_FactoryNotFound:		return "Factory Function Not Found (104)";
+	case VRInitError_Init_InterfaceNotFound:	return "Interface Not Found (105)";
+	case VRInitError_Init_InvalidInterface:		return "Invalid Interface (106)";
+	case VRInitError_Init_UserConfigDirectoryInvalid: return "User Config Directory Invalid (107)";
+	case VRInitError_Init_HmdNotFound:			return "Hmd Not Found (108)";
+	case VRInitError_Init_NotInitialized:		return "Not Initialized (109)";
+	case VRInitError_Init_PathRegistryNotFound:	return "Installation path could not be located (110)";
+	case VRInitError_Init_NoConfigPath:			return "Config path could not be located (111)";
+	case VRInitError_Init_NoLogPath:			return "Log path could not be located (112)";
+	case VRInitError_Init_PathRegistryNotWritable: return "Unable to write path registry (113)";
+	case VRInitError_Init_AppInfoInitFailed:	return "App info manager init failed (114)";
+	case VRInitError_Init_Retry:				return "Internal Retry (115)";
+	case VRInitError_Init_InitCanceledByUser:	return "User Canceled Init (116)";
+	case VRInitError_Init_AnotherAppLaunching:	return "Another app was already launching (117)";
+	case VRInitError_Init_SettingsInitFailed:	return "Settings manager init failed (118)";
+	case VRInitError_Init_ShuttingDown:			return "VR system shutting down (119)";
+	case VRInitError_Init_TooManyObjects:		return "Too many tracked objects (120)";
+	case VRInitError_Init_NoServerForBackgroundApp: return "Not starting vrserver for background app (121)";
+	case VRInitError_Init_NotSupportedWithCompositor: return "The requested interface is incompatible with the compositor and the compositor is running (122)";
+	case VRInitError_Init_NotAvailableToUtilityApps: return "This interface is not available to utility applications (123)";
+	case VRInitError_Init_Internal:				return "vrserver internal error (124)";
+	case VRInitError_Init_HmdDriverIdIsNone:	return "Hmd DriverId is invalid (125)";
+	case VRInitError_Init_HmdNotFoundPresenceFailed:	return "Hmd Not Found Presence Failed (126)";
+
+	case VRInitError_Driver_Failed:				return "Driver Failed (200)";
+	case VRInitError_Driver_Unknown:			return "Driver Not Known (201)";
+	case VRInitError_Driver_HmdUnknown:			return "HMD Not Known (202)";
+	case VRInitError_Driver_NotLoaded:			return "Driver Not Loaded (203)";
+	case VRInitError_Driver_RuntimeOutOfDate:	return "Driver runtime is out of date (204)";
+	case VRInitError_Driver_HmdInUse:			return "HMD already in use by another application (205)";
+	case VRInitError_Driver_NotCalibrated:		return "Device is not calibrated (206)";
+	case VRInitError_Driver_CalibrationInvalid: return "Device Calibration is invalid (207)";
+	case VRInitError_Driver_HmdDisplayNotFound: return "HMD detected over USB, but Monitor not found (208)";
+	case VRInitError_Driver_TrackedDeviceInterfaceUnknown: return "Driver Tracked Device Interface unknown (209)";
+	// case VRInitError_Driver_HmdDisplayNotFoundAfterFix: return "HMD detected over USB, but Monitor not found after attempt to fix (210)"; // taken out upon Ben's request: He thinks that there is no need to separate that error from 208
+	case VRInitError_Driver_HmdDriverIdOutOfBounds: return "Hmd DriverId is our of bounds (211)";
+	case VRInitError_Driver_HmdDisplayMirrored: return "HMD detected over USB, but Monitor may be mirrored instead of extended (212)";
+
+	case VRInitError_IPC_ServerInitFailed:		return "VR Server Init Failed (300)";
+	case VRInitError_IPC_ConnectFailed:			return "Connect to VR Server Failed (301)";
+	case VRInitError_IPC_SharedStateInitFailed: return "Shared IPC State Init Failed (302)";
+	case VRInitError_IPC_CompositorInitFailed:	return "Shared IPC Compositor Init Failed (303)";
+	case VRInitError_IPC_MutexInitFailed:		return "Shared IPC Mutex Init Failed (304)";
+	case VRInitError_IPC_Failed:				return "Shared IPC Failed (305)";
+	case VRInitError_IPC_CompositorConnectFailed:				return "Shared IPC Compositor Connect Failed (306)";
+	case VRInitError_IPC_CompositorInvalidConnectResponse:		return "Shared IPC Compositor Invalid Connect Response (307)";
+	case VRInitError_IPC_ConnectFailedAfterMultipleAttempts:	return "Shared IPC Connect Failed After Multiple Attempts (308)";
+
+	case VRInitError_Compositor_Failed:						return "Compositor failed to initialize (400)";
+	case VRInitError_Compositor_D3D11HardwareRequired:		return "Compositor failed to find DX11 hardware (401)";
+	case VRInitError_Compositor_FirmwareRequiresUpdate:		return "Compositor requires mandatory firmware update (402)";
+	case VRInitError_Compositor_OverlayInitFailed:			return "Compositor initialization succeeded, but overlay init failed (403)";
+
+	// Oculus
+	case VRInitError_VendorSpecific_UnableToConnectToOculusRuntime:	return "Unable to connect to Oculus Runtime (1000)";
+
+	// Lighthouse
+	case VRInitError_VendorSpecific_HmdFound_CantOpenDevice:				return "HMD found, but can not open device (1101)";
+	case VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart:	return "HMD found, but unable to request config (1102)";
+	case VRInitError_VendorSpecific_HmdFound_NoStoredConfig:				return "HMD found, but no stored config (1103)";
+	case VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck:       return "HMD found, but failed configuration check (1113)";
+	case VRInitError_VendorSpecific_HmdFound_ConfigTooBig:					return "HMD found, but config too big (1104)";
+	case VRInitError_VendorSpecific_HmdFound_ConfigTooSmall:				return "HMD found, but config too small (1105)";
+	case VRInitError_VendorSpecific_HmdFound_UnableToInitZLib:				return "HMD found, but unable to init ZLib (1106)";
+	case VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion:		return "HMD found, but problems with the data (1107)";
+	case VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart:		return "HMD found, but problems with the data (1108)";
+	case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart:		return "HMD found, but problems with the data (1109)";
+	case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext:		return "HMD found, but problems with the data (1110)";
+	case VRInitError_VendorSpecific_HmdFound_UserDataAddressRange:			return "HMD found, but problems with the data (1111)";
+	case VRInitError_VendorSpecific_HmdFound_UserDataError:					return "HMD found, but problems with the data (1112)";
+
+	case VRInitError_Steam_SteamInstallationNotFound: return "Unable to find Steam installation (2000)";
+
+	default:
+		{
+			static char buf[128];
+			sprintf( buf, "Unknown error (%d)", eError );
+			return buf;
+		}
+	}
+
+}
+
+
+const char *GetIDForVRInitError( vr::EVRInitError eError )
+{
+	switch( eError )
+	{
+		RETURN_ENUM_AS_STRING( VRInitError_None );
+		RETURN_ENUM_AS_STRING( VRInitError_Unknown );
+
+		RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationCorrupt );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRClientDLLNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_FileNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_FactoryNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_InterfaceNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidInterface );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_UserConfigDirectoryInvalid );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NotInitialized );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NoConfigPath );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NoLogPath );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotWritable );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_AppInfoInitFailed );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_Retry );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_InitCanceledByUser );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_AnotherAppLaunching );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_SettingsInitFailed );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_ShuttingDown );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_TooManyObjects );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NoServerForBackgroundApp );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NotSupportedWithCompositor );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToUtilityApps );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_Internal );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorNotFound );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorStartupFailed );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_LowPowerWatchdogNotSupported );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidApplicationType );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToWatchdogApps );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_WatchdogDisabledInSettings );
+
+		RETURN_ENUM_AS_STRING( VRInitError_Init_HmdDriverIdIsNone );
+		RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFoundPresenceFailed );
+
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_Failed );
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_Unknown );
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdUnknown);
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_NotLoaded);
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_RuntimeOutOfDate);
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdInUse);
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_NotCalibrated);
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_CalibrationInvalid);
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFound);
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_TrackedDeviceInterfaceUnknown );
+		// RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFoundAfterFix );
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDriverIdOutOfBounds );
+		RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayMirrored );
+
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_ServerInitFailed);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailed);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_SharedStateInitFailed);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInitFailed);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_MutexInitFailed);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_Failed);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorConnectFailed);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInvalidConnectResponse);
+		RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailedAfterMultipleAttempts);
+
+		RETURN_ENUM_AS_STRING( VRInitError_Compositor_Failed );
+		RETURN_ENUM_AS_STRING( VRInitError_Compositor_D3D11HardwareRequired );
+		RETURN_ENUM_AS_STRING( VRInitError_Compositor_FirmwareRequiresUpdate );
+		RETURN_ENUM_AS_STRING( VRInitError_Compositor_OverlayInitFailed );
+
+		// Oculus
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_UnableToConnectToOculusRuntime);
+
+		// Lighthouse
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantOpenDevice);
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart);
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_NoStoredConfig);
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooBig );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooSmall );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToInitZLib );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataAddressRange );
+		RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataError );
+
+		RETURN_ENUM_AS_STRING( VRInitError_Steam_SteamInstallationNotFound );
+
+	default:
+		{
+			static char buf[128];
+			sprintf( buf, "Unknown error (%d)", eError );
+			return buf;
+		}
+	}
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/hmderrors_public.h
@@ -0,0 +1,6 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+const char *GetEnglishStringForHmdError( vr::EVRInitError eError );
+const char *GetIDForVRInitError( vr::EVRInitError eError );
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/ivrclientcore.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+namespace vr
+{
+
+class IVRClientCore
+{
+public:
+	/** Initializes the system */
+	virtual EVRInitError Init( vr::EVRApplicationType eApplicationType ) = 0;
+
+	/** cleans up everything in vrclient.dll and prepares the DLL to be unloaded */
+	virtual void Cleanup() = 0;
+
+	/** checks to see if the specified interface/version is supported in this vrclient.dll */
+	virtual EVRInitError IsInterfaceVersionValid( const char *pchInterfaceVersion ) = 0;
+
+	/** Retrieves any interface from vrclient.dll */
+	virtual void *GetGenericInterface( const char *pchNameAndVersion, EVRInitError *peError ) = 0;
+
+	/** Returns true if any driver has an HMD attached. Can be called outside of Init/Cleanup */
+	virtual bool BIsHmdPresent() = 0;
+
+	/** Returns an english error string from inside vrclient.dll which might be newer than the API DLL */
+	virtual const char *GetEnglishStringForHmdError( vr::EVRInitError eError ) = 0;
+
+	/** Returns an error symbol from inside vrclient.dll which might be newer than the API DLL */
+	virtual const char *GetIDForVRInitError( vr::EVRInitError eError ) = 0;
+};
+
+static const char * const IVRClientCore_Version = "IVRClientCore_002";
+
+
+}
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/openvr_api_public.cpp
@@ -0,0 +1,284 @@
+//========= Copyright Valve Corporation ============//
+#define VR_API_EXPORT 1
+#include "openvr.h"
+#include "ivrclientcore.h"
+#include "pathtools_public.h"
+#include "sharedlibtools_public.h"
+#include "envvartools_public.h"
+#include "hmderrors_public.h"
+#include "vrpathregistry_public.h"
+
+using vr::EVRInitError;
+using vr::IVRSystem;
+using vr::IVRClientCore;
+using vr::VRInitError_None;
+
+namespace vr
+{
+
+static void *g_pVRModule = NULL;
+static IVRClientCore *g_pHmdSystem = NULL;
+
+
+typedef void* (*VRClientCoreFactoryFn)(const char *pInterfaceName, int *pReturnCode);
+
+static uint32_t g_nVRToken = 0;
+
+uint32_t VR_GetInitToken()
+{
+	return g_nVRToken;
+}
+
+EVRInitError VR_LoadHmdSystemInternal();
+void CleanupInternalInterfaces();
+
+
+uint32_t VR_InitInternal( EVRInitError *peError, vr::EVRApplicationType eApplicationType )
+{
+	EVRInitError err = VR_LoadHmdSystemInternal();
+	if (err != vr::VRInitError_None)
+	{
+		SharedLib_Unload(g_pVRModule);
+		g_pHmdSystem = NULL;
+		g_pVRModule = NULL;
+
+		if (peError)
+			*peError = err;
+
+		return 0;
+	}
+
+	err = g_pHmdSystem->Init(eApplicationType);
+	if (err != VRInitError_None)
+	{
+		SharedLib_Unload(g_pVRModule);
+		g_pHmdSystem = NULL;
+		g_pVRModule = NULL;
+
+		if (peError)
+			*peError = err;
+
+		return 0;
+	}
+
+	if (peError)
+		*peError = VRInitError_None;
+
+	return ++g_nVRToken;
+}
+
+void VR_ShutdownInternal()
+{
+	if (g_pHmdSystem)
+	{
+		g_pHmdSystem->Cleanup();
+		g_pHmdSystem = NULL;
+	}
+	if (g_pVRModule)
+	{
+		SharedLib_Unload(g_pVRModule);
+		g_pVRModule = NULL;
+	}
+
+#if !defined( VR_API_PUBLIC )
+	CleanupInternalInterfaces();
+#endif
+
+	++g_nVRToken;
+}
+
+EVRInitError VR_LoadHmdSystemInternal()
+{
+	std::string sRuntimePath, sConfigPath, sLogPath;
+
+	bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
+	if( !bReadPathRegistry )
+	{
+		return vr::VRInitError_Init_PathRegistryNotFound;
+	}
+
+	// figure out where we're going to look for vrclient.dll
+	// see if the specified path actually exists.
+	if( !Path_IsDirectory( sRuntimePath ) )
+	{
+		return vr::VRInitError_Init_InstallationNotFound;
+	}
+
+	// Because we don't have a way to select debug vs. release yet we'll just
+	// use debug if it's there
+#if defined( LINUX64 )
+	std::string sTestPath = Path_Join( sRuntimePath, "bin", PLATSUBDIR );
+#else
+	std::string sTestPath = Path_Join( sRuntimePath, "bin" );
+#endif
+	if( !Path_IsDirectory( sTestPath ) )
+	{
+		return vr::VRInitError_Init_InstallationCorrupt;
+	}
+
+#if defined( WIN64 )
+	std::string sDLLPath = Path_Join( sTestPath, "vrclient_x64" DYNAMIC_LIB_EXT );
+#else
+	std::string sDLLPath = Path_Join( sTestPath, "vrclient" DYNAMIC_LIB_EXT );
+#endif
+
+	// only look in the override
+	void *pMod = SharedLib_Load( sDLLPath.c_str() );
+	// nothing more to do if we can't load the DLL
+	if( !pMod )
+	{
+		return vr::VRInitError_Init_VRClientDLLNotFound;
+	}
+
+	VRClientCoreFactoryFn fnFactory = ( VRClientCoreFactoryFn )( SharedLib_GetFunction( pMod, "VRClientCoreFactory" ) );
+	if( !fnFactory )
+	{
+		SharedLib_Unload( pMod );
+		return vr::VRInitError_Init_FactoryNotFound;
+	}
+
+	int nReturnCode = 0;
+	g_pHmdSystem = static_cast< IVRClientCore * > ( fnFactory( vr::IVRClientCore_Version, &nReturnCode ) );
+	if( !g_pHmdSystem )
+	{
+		SharedLib_Unload( pMod );
+		return vr::VRInitError_Init_InterfaceNotFound;
+	}
+
+	g_pVRModule = pMod;
+	return VRInitError_None;
+}
+
+
+void *VR_GetGenericInterface(const char *pchInterfaceVersion, EVRInitError *peError)
+{
+	if (!g_pHmdSystem)
+	{
+		if (peError)
+			*peError = vr::VRInitError_Init_NotInitialized;
+		return NULL;
+	}
+
+	return g_pHmdSystem->GetGenericInterface(pchInterfaceVersion, peError);
+}
+
+bool VR_IsInterfaceVersionValid(const char *pchInterfaceVersion)
+{
+	if (!g_pHmdSystem)
+	{
+		return false;
+	}
+
+	return g_pHmdSystem->IsInterfaceVersionValid(pchInterfaceVersion) == VRInitError_None;
+}
+
+bool VR_IsHmdPresent()
+{
+	if( g_pHmdSystem )
+	{
+		// if we're already initialized, just call through
+		return g_pHmdSystem->BIsHmdPresent();
+	}
+	else
+	{
+		// otherwise we need to do a bit more work
+		EVRInitError err = VR_LoadHmdSystemInternal();
+		if( err != VRInitError_None )
+			return false;
+
+		bool bHasHmd = g_pHmdSystem->BIsHmdPresent();
+
+		g_pHmdSystem = NULL;
+		SharedLib_Unload( g_pVRModule );
+		g_pVRModule = NULL;
+
+		return bHasHmd;
+	}
+}
+
+/** Returns true if the OpenVR runtime is installed. */
+bool VR_IsRuntimeInstalled()
+{
+	if( g_pHmdSystem )
+	{
+		// if we're already initialized, OpenVR is obviously installed
+		return true;
+	}
+	else
+	{
+		// otherwise we need to do a bit more work
+		std::string sRuntimePath, sConfigPath, sLogPath;
+
+		bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
+		if( !bReadPathRegistry )
+		{
+			return false;
+		}
+
+		// figure out where we're going to look for vrclient.dll
+		// see if the specified path actually exists.
+		if( !Path_IsDirectory( sRuntimePath ) )
+		{
+			return false;
+		}
+
+		// the installation may be corrupt in some way, but it certainly looks installed
+		return true;
+	}
+}
+
+
+/** Returns where OpenVR runtime is installed. */
+const char *VR_RuntimePath()
+{
+	// otherwise we need to do a bit more work
+	static std::string sRuntimePath;
+	std::string sConfigPath, sLogPath;
+
+	bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
+	if ( !bReadPathRegistry )
+	{
+		return nullptr;
+	}
+
+	// figure out where we're going to look for vrclient.dll
+	// see if the specified path actually exists.
+	if ( !Path_IsDirectory( sRuntimePath ) )
+	{
+		return nullptr;
+	}
+
+	return sRuntimePath.c_str();
+}
+
+
+/** Returns the symbol version of an HMD error. */
+const char *VR_GetVRInitErrorAsSymbol( EVRInitError error )
+{
+	if( g_pHmdSystem )
+		return g_pHmdSystem->GetIDForVRInitError( error );
+	else
+		return GetIDForVRInitError( error );
+}
+
+
+/** Returns the english string version of an HMD error. */
+const char *VR_GetVRInitErrorAsEnglishDescription( EVRInitError error )
+{
+	if ( g_pHmdSystem )
+		return g_pHmdSystem->GetEnglishStringForHmdError( error );
+	else
+		return GetEnglishStringForHmdError( error );
+}
+
+
+VR_INTERFACE const char *VR_CALLTYPE VR_GetStringForHmdError( vr::EVRInitError error );
+
+/** Returns the english string version of an HMD error. */
+const char *VR_GetStringForHmdError( EVRInitError error )
+{
+	return VR_GetVRInitErrorAsEnglishDescription( error );
+}
+
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/pathtools_public.cpp
@@ -0,0 +1,818 @@
+//========= Copyright Valve Corporation ============//
+#include "strtools_public.h"
+#include "pathtools_public.h"
+
+#if defined( _WIN32)
+#include <Windows.h>
+#include <direct.h>
+#include <Shobjidl.h>
+#include <KnownFolders.h>
+#include <Shlobj.h>
+
+#undef GetEnvironmentVariable
+#else
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+#if defined OSX
+#include <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+#include <mach-o/dyld.h>
+#define _S_IFDIR S_IFDIR     // really from tier0/platform.h which we dont have yet
+#endif
+
+#include <sys/stat.h>
+
+#include <algorithm>
+
+/** Returns the path (including filename) to the current executable */
+std::string Path_GetExecutablePath()
+{
+#if defined( _WIN32 )
+	wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
+	char *pchPath = new char[MAX_UNICODE_PATH_IN_UTF8];
+	::GetModuleFileNameW( NULL, pwchPath, MAX_UNICODE_PATH );
+	WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
+	delete[] pwchPath;
+
+	std::string sPath = pchPath;
+	delete[] pchPath;
+	return sPath;
+#elif defined( OSX )
+	char rchPath[1024];
+	uint32_t nBuff = sizeof( rchPath );
+	bool bSuccess = _NSGetExecutablePath(rchPath, &nBuff) == 0;
+	rchPath[nBuff-1] = '\0';
+	if( bSuccess )
+		return rchPath;
+	else
+		return "";
+#elif defined LINUX
+	char rchPath[1024];
+	size_t nBuff = sizeof( rchPath );
+	ssize_t nRead = readlink("/proc/self/exe", rchPath, nBuff-1 );
+	if ( nRead != -1 )
+	{
+		rchPath[ nRead ] = 0;
+		return rchPath;
+	}
+	else
+	{
+		return "";
+	}
+#else
+	AssertMsg( false, "Implement Plat_GetExecutablePath" );
+	return "";
+#endif
+
+}
+
+/** Returns the path of the current working directory */
+std::string Path_GetWorkingDirectory()
+{
+	std::string sPath;
+#if defined( _WIN32 )
+	wchar_t buf[MAX_UNICODE_PATH];
+	sPath = UTF16to8( _wgetcwd( buf, MAX_UNICODE_PATH ) );
+#else
+	char buf[ 1024 ];
+	sPath = getcwd( buf, sizeof( buf ) );
+#endif
+	return sPath;
+}
+
+/** Sets the path of the current working directory. Returns true if this was successful. */
+bool Path_SetWorkingDirectory( const std::string & sPath )
+{
+	bool bSuccess;
+#if defined( _WIN32 )
+	std::wstring wsPath = UTF8to16( sPath.c_str() );
+	bSuccess = 0 == _wchdir( wsPath.c_str() );
+#else
+	bSuccess = 0 == chdir( sPath.c_str() );
+#endif
+	return bSuccess;
+}
+
+/** Returns the specified path without its filename */
+std::string Path_StripFilename( const std::string & sPath, char slash )
+{
+	if( slash == 0 )
+		slash = Path_GetSlash();
+
+	std::string::size_type n = sPath.find_last_of( slash );
+	if( n == std::string::npos )
+		return sPath;
+	else
+		return std::string( sPath.begin(), sPath.begin() + n );
+}
+
+/** returns just the filename from the provided full or relative path. */
+std::string Path_StripDirectory( const std::string & sPath, char slash )
+{
+	if( slash == 0 )
+		slash = Path_GetSlash();
+
+	std::string::size_type n = sPath.find_last_of( slash );
+	if( n == std::string::npos )
+		return sPath;
+	else
+		return std::string( sPath.begin() + n + 1, sPath.end() );
+}
+
+/** returns just the filename with no extension of the provided filename. 
+* If there is a path the path is left intact. */
+std::string Path_StripExtension( const std::string & sPath )
+{
+	for( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
+	{
+		if( *i == '.' )
+		{
+			return std::string( sPath.begin(), i.base() - 1 );
+		}
+
+		// if we find a slash there is no extension
+		if( *i == '\\' || *i == '/' )
+			break;
+	}
+
+	// we didn't find an extension
+	return sPath;
+}
+
+/** returns just extension of the provided filename (if any). */
+std::string Path_GetExtension( const std::string & sPath )
+{
+	for ( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
+	{
+		if ( *i == '.' )
+		{
+			return std::string( i.base(), sPath.end() );
+		}
+
+		// if we find a slash there is no extension
+		if ( *i == '\\' || *i == '/' )
+			break;
+	}
+
+	// we didn't find an extension
+	return "";
+}
+
+bool Path_IsAbsolute( const std::string & sPath )
+{
+	if( sPath.empty() )
+		return false;
+
+#if defined( WIN32 )
+	if ( sPath.size() < 3 ) // must be c:\x or \\x at least
+		return false;
+
+	if ( sPath[1] == ':' ) // drive letter plus slash, but must test both slash cases
+	{
+		if ( sPath[2] == '\\' || sPath[2] == '/' )
+			return true;
+	}
+	else if ( sPath[0] == '\\' && sPath[1] == '\\' ) // UNC path
+		return true;
+#else
+	if( sPath[0] == '\\' || sPath[0] == '/' ) // any leading slash
+		return true;
+#endif
+
+	return false;
+}
+
+
+/** Makes an absolute path from a relative path and a base path */
+std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath, char slash )
+{
+	if( slash == 0 )
+		slash = Path_GetSlash();
+
+	if( Path_IsAbsolute( sRelativePath ) )
+		return sRelativePath;
+	else
+	{
+		if( !Path_IsAbsolute( sBasePath ) )
+			return "";
+
+		std::string sCompacted = Path_Compact( Path_Join( sBasePath, sRelativePath, slash ), slash );
+		if( Path_IsAbsolute( sCompacted ) )
+			return sCompacted;
+		else
+			return "";
+	}
+}
+
+
+/** Fixes the directory separators for the current platform */
+std::string Path_FixSlashes( const std::string & sPath, char slash )
+{
+	if( slash == 0 )
+		slash = Path_GetSlash();
+
+	std::string sFixed = sPath;
+	for( std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++ )
+	{
+		if( *i == '/' || *i == '\\' )
+			*i = slash;
+	}
+
+	return sFixed;
+}
+
+
+char Path_GetSlash()
+{
+#if defined(_WIN32)
+	return '\\';
+#else
+	return '/';
+#endif
+}
+
+/** Jams two paths together with the right kind of slash */
+std::string Path_Join( const std::string & first, const std::string & second, char slash )
+{
+	if( slash == 0 )
+		slash = Path_GetSlash();
+
+	// only insert a slash if we don't already have one
+	std::string::size_type nLen = first.length();
+	if( !nLen )
+		return second;
+#if defined(_WIN32)
+	if( first.back() == '\\' || first.back() == '/' )
+	    nLen--;
+#else
+	char last_char = first[first.length()-1];
+	if (last_char == '\\' || last_char == '/')
+	    nLen--;
+#endif
+
+	return first.substr( 0, nLen ) + std::string( 1, slash ) + second;
+}
+
+
+std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash )
+{
+	return Path_Join( Path_Join( first, second, slash ), third, slash );
+}
+
+std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash )
+{
+	return Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash );
+}
+
+std::string Path_Join( 
+	const std::string & first, 
+	const std::string & second, 
+	const std::string & third, 
+	const std::string & fourth, 
+	const std::string & fifth, 
+	char slash )
+{
+	return Path_Join( Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash ), fifth, slash );
+}
+
+
+std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash )
+{
+	if ( slash == 0 )
+		slash = Path_GetSlash();
+
+	std::string sPath = sRawPath;
+	std::string::size_type nCurrent = sRawPath.length();
+	if ( nCurrent == 0 )
+		return sPath;
+
+	int nLastFound = -1;
+	nCurrent--;
+	while( nCurrent != 0 )
+	{
+		if ( sRawPath[ nCurrent ] == slash )
+		{
+			nLastFound = (int)nCurrent;
+			nCurrent--;
+		}
+		else
+		{
+			break;
+		}
+	}
+		
+	if ( nLastFound >= 0 )
+	{
+		sPath.erase( nLastFound, std::string::npos );
+	}
+	
+	return sPath;
+}
+
+
+/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the 
+* specified path has a broken number of directories for its number of ..s */
+std::string Path_Compact( const std::string & sRawPath, char slash )
+{
+	if( slash == 0 )
+		slash = Path_GetSlash();
+
+	std::string sPath = Path_FixSlashes( sRawPath, slash );
+	std::string sSlashString( 1, slash );
+
+	// strip out all /./
+	for( std::string::size_type i = 0; (i + 3) < sPath.length();  )
+	{
+		if( sPath[ i ] == slash && sPath[ i+1 ] == '.' && sPath[ i+2 ] == slash )
+		{
+			sPath.replace( i, 3, sSlashString );
+		}
+		else
+		{
+			++i;
+		}
+	}
+
+
+	// get rid of trailing /. but leave the path separator
+	if( sPath.length() > 2 )
+	{
+		std::string::size_type len = sPath.length();
+		if( sPath[ len-1 ] == '.'  && sPath[ len-2 ] == slash )
+		{
+		  // sPath.pop_back();
+		  sPath[len-1] = 0;  // for now, at least
+		}
+	}
+
+	// get rid of leading ./ 
+	if( sPath.length() > 2 )
+	{
+		if( sPath[ 0 ] == '.'  && sPath[ 1 ] == slash )
+		{
+			sPath.replace( 0, 2, "" );
+		}
+	}
+
+	// each time we encounter .. back up until we've found the previous directory name
+	// then get rid of both
+	std::string::size_type i = 0;
+	while( i < sPath.length() )
+	{
+		if( i > 0 && sPath.length() - i >= 2 
+			&& sPath[i] == '.'
+			&& sPath[i+1] == '.'
+			&& ( i + 2 == sPath.length() || sPath[ i+2 ] == slash )
+			&& sPath[ i-1 ] == slash )
+		{
+			// check if we've hit the start of the string and have a bogus path
+			if( i == 1 )
+				return "";
+			
+			// find the separator before i-1
+			std::string::size_type iDirStart = i-2;
+			while( iDirStart > 0 && sPath[ iDirStart - 1 ] != slash )
+				--iDirStart;
+
+			// remove everything from iDirStart to i+2
+			sPath.replace( iDirStart, (i - iDirStart) + 3, "" );
+
+			// start over
+			i = 0;
+		}
+		else
+		{
+			++i;
+		}
+	}
+
+	return sPath;
+}
+
+
+/** Returns the path to the current DLL or exe */
+std::string Path_GetThisModulePath()
+{
+	// gets the path of vrclient.dll itself
+#ifdef WIN32
+	HMODULE hmodule = NULL;
+
+	::GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCTSTR>(Path_GetThisModulePath), &hmodule );
+
+	wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
+	char *pchPath = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
+	::GetModuleFileNameW( hmodule, pwchPath, MAX_UNICODE_PATH );
+	WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
+	delete[] pwchPath;
+
+	std::string sPath = pchPath;
+	delete [] pchPath;
+	return sPath;
+
+#elif defined( OSX ) || defined( LINUX )
+	// get the addr of a function in vrclient.so and then ask the dlopen system about it
+	Dl_info info;
+	dladdr( (void *)Path_GetThisModulePath, &info );
+	return info.dli_fname;
+#endif
+
+}
+
+
+/** returns true if the specified path exists and is a directory */
+bool Path_IsDirectory( const std::string & sPath )
+{
+	std::string sFixedPath = Path_FixSlashes( sPath );
+	if( sFixedPath.empty() )
+		return false;
+	char cLast = sFixedPath[ sFixedPath.length() - 1 ];
+	if( cLast == '/' || cLast == '\\' )
+		sFixedPath.erase( sFixedPath.end() - 1, sFixedPath.end() );
+
+	// see if the specified path actually exists.
+
+#if defined(POSIX)
+	struct	stat	buf;
+	if ( stat( sFixedPath.c_str(), &buf ) == -1 )
+	{
+		return false;
+	}
+
+#if defined( LINUX ) || defined( OSX )
+	return S_ISDIR( buf.st_mode );
+#else
+	return (buf.st_mode & _S_IFDIR) != 0;
+#endif
+
+#else
+	struct	_stat	buf;
+	std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
+	if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
+	{
+		return false;
+	}
+
+	return (buf.st_mode & _S_IFDIR) != 0;
+#endif
+}
+
+/** returns true if the specified path represents an app bundle */
+bool Path_IsAppBundle( const std::string & sPath )
+{
+#if defined(OSX)
+	NSBundle *bundle = [ NSBundle bundleWithPath: [ NSString stringWithUTF8String:sPath.c_str() ] ];
+	bool bisAppBundle = ( nullptr != bundle );
+	[ bundle release ];
+	return bisAppBundle;
+#else
+	return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the the path exists
+//-----------------------------------------------------------------------------
+bool Path_Exists( const std::string & sPath )
+{
+	std::string sFixedPath = Path_FixSlashes( sPath );
+	if( sFixedPath.empty() )
+		return false;
+
+#if defined( WIN32 )
+	struct	_stat	buf;
+	std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
+	if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
+	{
+		return false;
+	}
+#else
+	struct stat buf;
+	if ( stat ( sFixedPath.c_str(), &buf ) == -1)
+	{
+		return false;
+	}
+#endif
+
+	return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: helper to find a directory upstream from a given path
+//-----------------------------------------------------------------------------
+std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
+{
+	std::string strFoundPath = "";
+	std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
+	if ( strCurrentPath.length() == 0 )
+		return "";
+
+	bool bExists = Path_Exists( strCurrentPath );
+	std::string strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
+	if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
+		return strCurrentPath;
+
+	while( bExists && strCurrentPath.length() != 0 )
+	{
+		strCurrentPath = Path_StripFilename( strCurrentPath );
+		strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
+		bExists = Path_Exists( strCurrentPath );
+		if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
+			return strCurrentPath;
+	}
+
+	return "";
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: helper to find a subdirectory upstream from a given path
+//-----------------------------------------------------------------------------
+std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
+{
+	std::string strFoundPath = "";
+	std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
+	if ( strCurrentPath.length() == 0 )
+		return "";
+
+	bool bExists = Path_Exists( strCurrentPath );
+	while( bExists && strCurrentPath.length() != 0 )
+	{
+		strCurrentPath = Path_StripFilename( strCurrentPath );
+		bExists = Path_Exists( strCurrentPath );
+
+		if( Path_Exists( Path_Join( strCurrentPath, strDirectoryName ) ) )
+		{
+			strFoundPath = Path_Join( strCurrentPath, strDirectoryName );
+			break;
+		}
+	}
+	return strFoundPath;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: reading and writing files in the vortex directory
+//-----------------------------------------------------------------------------
+unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize )
+{
+	FILE *f;
+#if defined( POSIX )
+	f = fopen( strFilename.c_str(), "rb" );
+#else
+	std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
+	// the open operation needs to be sharable, therefore use of _wfsopen instead of _wfopen_s
+	f = _wfsopen( wstrFilename.c_str(), L"rb", _SH_DENYNO );
+#endif
+	
+	unsigned char* buf = NULL;
+
+	if ( f != NULL )
+	{
+		fseek(f, 0, SEEK_END);
+		int size = ftell(f);
+		fseek(f, 0, SEEK_SET);
+
+		buf = new unsigned char[size];
+		if (buf && fread(buf, size, 1, f) == 1)
+		{
+			if (pSize)
+				*pSize = size;
+		}
+		else
+		{
+			delete[] buf;
+			buf = 0;
+		}
+
+		fclose(f);
+	}
+
+	return buf;
+}
+
+uint32_t  Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize )
+{
+	FILE *f;
+#if defined( POSIX )
+	f = fopen( strFilename.c_str(), "rb" );
+#else
+	std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
+	errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"rb" );
+	if ( err != 0 )
+	{
+		f = NULL;
+	}
+#endif
+
+	uint32_t unSizeToReturn = 0;
+
+	if ( f != NULL )
+	{
+		fseek( f, 0, SEEK_END );
+		uint32_t size = (uint32_t)ftell( f );
+		fseek( f, 0, SEEK_SET );
+
+		if ( size > unSize || !pBuffer )
+		{
+			unSizeToReturn = (uint32_t)size;
+		}
+		else
+		{
+			if ( fread( pBuffer, size, 1, f ) == 1 )
+			{
+				unSizeToReturn = (uint32_t)size;
+			}
+		}
+
+		fclose( f );
+	}
+
+	return unSizeToReturn;
+}
+
+bool Path_WriteBinaryFile(const std::string &strFilename, unsigned char *pData, unsigned nSize)
+{
+	FILE *f;
+#if defined( POSIX )
+	f = fopen(strFilename.c_str(), "wb");
+#else
+	std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
+	errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"wb" );
+	if (err != 0)
+	{
+		f = NULL;
+	}
+#endif
+
+	size_t written = 0;
+	if (f != NULL) {
+		written = fwrite(pData, sizeof(unsigned char), nSize, f);
+		fclose(f);
+	}
+
+	return written = nSize ? true : false;
+}
+
+std::string Path_ReadTextFile( const std::string &strFilename )
+{
+	// doing it this way seems backwards, but I don't
+	// see an easy way to do this with C/C++ style IO
+	// that isn't worse...
+	int size;
+	unsigned char* buf = Path_ReadBinaryFile( strFilename, &size );
+	if (!buf)
+		return "";
+
+	// convert CRLF -> LF
+	size_t outsize = 1;
+	for (int i=1; i < size; i++)
+	{
+		if (buf[i] == '\n' && buf[i-1] == '\r') // CRLF
+			buf[outsize-1] = '\n'; // ->LF
+		else
+			buf[outsize++] = buf[i]; // just copy
+	}
+
+	std::string ret((char *)buf, outsize);
+	delete[] buf;
+	return ret;
+}
+
+
+bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData )
+{
+	FILE *f;
+#if defined( POSIX )
+	f = fopen( strFilename.c_str(), "w" );
+#else
+	std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
+	errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"w" );
+	if ( err != 0 )
+	{
+		f = NULL;
+	}
+#endif
+	
+	bool ok = false;
+
+	if ( f != NULL )
+	{
+		ok = fputs( pchData, f) >= 0;
+		fclose(f);
+	}
+
+	return ok;
+}
+
+bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData )
+{
+	std::string strTmpFilename = strFilename + ".tmp";
+
+	if ( !Path_WriteStringToTextFile( strTmpFilename, pchData ) )
+		return false;
+
+	// Platform specific atomic file replacement
+#if defined( _WIN32 )
+	std::wstring wsFilename = UTF8to16( strFilename.c_str() );
+	std::wstring wsTmpFilename = UTF8to16( strTmpFilename.c_str() );
+	if ( !::ReplaceFileW( wsFilename.c_str(), wsTmpFilename.c_str(), nullptr, 0, 0, 0 ) )
+	{
+		// if we couldn't ReplaceFile, try a non-atomic write as a fallback
+		if ( !Path_WriteStringToTextFile( strFilename, pchData ) )
+			return false;
+	}
+#elif defined( POSIX )
+	if ( rename( strTmpFilename.c_str(), strFilename.c_str() ) == -1 )
+		return false;
+#else
+#error Do not know how to write atomic file
+#endif
+
+	return true;
+}
+
+
+#if defined(WIN32)
+#define FILE_URL_PREFIX "file:///"
+#else
+#define FILE_URL_PREFIX "file://"
+#endif
+
+// ----------------------------------------------------------------------------------------------------------------------------
+// Purpose: Turns a path to a file on disk into a URL (or just returns the value if it's already a URL)
+// ----------------------------------------------------------------------------------------------------------------------------
+std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath )
+{
+	if ( !strnicmp( sRelativePath.c_str(), "http://", 7 )
+		|| !strnicmp( sRelativePath.c_str(), "https://", 8 )
+		|| !strnicmp( sRelativePath.c_str(), "file://", 7 ) )
+	{
+		return sRelativePath;
+	}
+	else
+	{
+		std::string sAbsolute = Path_MakeAbsolute( sRelativePath, sBasePath );
+		if ( sAbsolute.empty() )
+			return sAbsolute;
+		return std::string( FILE_URL_PREFIX ) + sAbsolute;
+	}
+}
+
+// -----------------------------------------------------------------------------------------------------
+// Purpose: Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned
+// -----------------------------------------------------------------------------------------------------
+std::string Path_UrlToFilePath( const std::string & sFileUrl )
+{
+	if ( !strnicmp( sFileUrl.c_str(), FILE_URL_PREFIX, strlen( FILE_URL_PREFIX ) ) )
+	{
+		return sFileUrl.c_str() + strlen( FILE_URL_PREFIX );
+	}
+	else
+	{
+		return "";
+	}
+}
+
+
+// -----------------------------------------------------------------------------------------------------
+// Purpose: Returns the root of the directory the system wants us to store user documents in
+// -----------------------------------------------------------------------------------------------------
+std::string GetUserDocumentsPath()
+{
+#if defined( WIN32 )
+	WCHAR rwchPath[MAX_PATH];
+
+	if ( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
+	{
+		return "";
+	}
+
+	// Convert the path to UTF-8 and store in the output
+	std::string sUserPath = UTF16to8( rwchPath );
+
+	return sUserPath;
+#elif defined( OSX )
+	@autoreleasepool {
+		NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
+		if ( [paths count] == 0 )
+		{
+			return "";
+		}
+		
+		return [[paths objectAtIndex:0] UTF8String];
+	}
+#elif defined( LINUX )
+	// @todo: not solved/changed as part of OSX - still not real - just removed old class based steam cut and paste
+	const char *pchHome = getenv( "HOME" );
+	if ( pchHome == NULL )
+	{
+		return "";
+	}
+	return pchHome;
+#endif
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/pathtools_public.h
@@ -0,0 +1,129 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+#include <string>
+#include <stdint.h>
+
+/** Returns the path (including filename) to the current executable */
+std::string Path_GetExecutablePath();
+
+/** Returns the path of the current working directory */
+std::string Path_GetWorkingDirectory();
+
+/** Sets the path of the current working directory. Returns true if this was successful. */
+bool Path_SetWorkingDirectory( const std::string & sPath );
+
+/** returns the path (including filename) of the current shared lib or DLL */
+std::string Path_GetThisModulePath();
+
+/** Returns the specified path without its filename.
+* If slash is unspecified the native path separator of the current platform
+* will be used. */
+std::string Path_StripFilename( const std::string & sPath, char slash = 0 );
+
+/** returns just the filename from the provided full or relative path. */
+std::string Path_StripDirectory( const std::string & sPath, char slash = 0 );
+
+/** returns just the filename with no extension of the provided filename. 
+* If there is a path the path is left intact. */
+std::string Path_StripExtension( const std::string & sPath );
+
+/** returns just extension of the provided filename (if any). */
+std::string Path_GetExtension( const std::string & sPath );
+
+/** Returns true if the path is absolute */
+bool Path_IsAbsolute( const std::string & sPath );
+
+/** Makes an absolute path from a relative path and a base path */
+std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath, char slash = 0 );
+
+/** Fixes the directory separators for the current platform.
+* If slash is unspecified the native path separator of the current platform
+* will be used. */
+std::string Path_FixSlashes( const std::string & sPath, char slash = 0 );
+
+/** Returns the path separator for the current platform */
+char Path_GetSlash();
+
+/** Jams two paths together with the right kind of slash */
+std::string Path_Join( const std::string & first, const std::string & second, char slash = 0 );
+std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash = 0 );
+std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash = 0 );
+std::string Path_Join( 
+	const std::string & first, 
+	const std::string & second, 
+	const std::string & third, 
+	const std::string & fourth, 
+	const std::string & fifth, 
+	char slash = 0 );
+
+
+/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the 
+* specified path has a broken number of directories for its number of ..s.
+* If slash is unspecified the native path separator of the current platform
+* will be used. */
+std::string Path_Compact( const std::string & sRawPath, char slash = 0 );
+
+//** Removed trailing slashes */
+std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash = 0 );
+
+/** returns true if the specified path exists and is a directory */
+bool Path_IsDirectory( const std::string & sPath );
+
+/** returns true if the specified path represents an app bundle */
+bool Path_IsAppBundle( const std::string & sPath );
+
+/** returns true if the the path exists */
+bool Path_Exists( const std::string & sPath );
+
+/** Helper functions to find parent directories or subdirectories of parent directories */
+std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
+std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
+
+/** Path operations to read or write text/binary files */
+unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize );
+uint32_t  Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize );
+bool Path_WriteBinaryFile( const std::string &strFilename, unsigned char *pData, unsigned nSize );
+std::string Path_ReadTextFile( const std::string &strFilename );
+bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData );
+bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData );
+
+/** Returns a file:// url for paths, or an http or https url if that's what was provided */
+std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath );
+
+/** Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned */
+std::string Path_UrlToFilePath( const std::string & sFileUrl );
+
+/** Returns the root of the directory the system wants us to store user documents in */
+std::string GetUserDocumentsPath();
+
+#ifndef MAX_UNICODE_PATH
+	#define MAX_UNICODE_PATH 32767
+#endif
+
+#ifndef MAX_UNICODE_PATH_IN_UTF8
+	#define MAX_UNICODE_PATH_IN_UTF8 (MAX_UNICODE_PATH * 4)
+#endif
+
+//-----------------------------------------------------------------------------
+#if defined(WIN32)
+#define DYNAMIC_LIB_EXT	".dll"
+#ifdef _WIN64
+#define PLATSUBDIR	"win64"
+#else
+#define PLATSUBDIR	"win32"
+#endif
+#elif defined(OSX)
+#define DYNAMIC_LIB_EXT	".dylib"
+#define PLATSUBDIR	"osx32"
+#elif defined(LINUX)
+#define DYNAMIC_LIB_EXT	".so"
+#if defined( LINUX32 )
+#define PLATSUBDIR	"linux32"
+#else
+#define PLATSUBDIR	"linux64"
+#endif
+#else
+#warning "Unknown platform for PLATSUBDIR"
+#define PLATSUBDIR	"unknown_platform"
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/sharedlibtools_public.cpp
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation ============//
+#include "sharedlibtools_public.h"
+#include <string.h>
+
+#if defined(_WIN32)
+#include <Windows.h>
+#endif
+
+#if defined(POSIX)
+#include <dlfcn.h>
+#endif
+
+SharedLibHandle SharedLib_Load( const char *pchPath )
+{
+#if defined( _WIN32)
+	return (SharedLibHandle)LoadLibraryEx( pchPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
+#elif defined(POSIX)
+	return (SharedLibHandle)dlopen(pchPath, RTLD_LOCAL|RTLD_NOW);
+#endif
+}
+
+void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName)
+{
+#if defined( _WIN32)
+	return GetProcAddress( (HMODULE)lib, pchFunctionName );
+#elif defined(POSIX)
+	return dlsym( lib, pchFunctionName );
+#endif
+}
+
+
+void SharedLib_Unload( SharedLibHandle lib )
+{
+#if defined( _WIN32)
+	FreeLibrary( (HMODULE)lib );
+#elif defined(POSIX)
+	dlclose( lib );
+#endif
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/sharedlibtools_public.h
@@ -0,0 +1,10 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+typedef void *SharedLibHandle;
+
+SharedLibHandle SharedLib_Load( const char *pchPath );
+void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName);
+void SharedLib_Unload( SharedLibHandle lib );
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/strtools_public.cpp
@@ -0,0 +1,439 @@
+//========= Copyright Valve Corporation ============//
+#include "strtools_public.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool StringHasPrefix( const std::string & sString, const std::string & sPrefix )
+{
+	return 0 == strnicmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
+}
+
+bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix )
+{
+	return 0 == strncmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
+}
+
+
+bool StringHasSuffix( const std::string &sString, const std::string &sSuffix )
+{
+	size_t cStrLen = sString.length();
+	size_t cSuffixLen = sSuffix.length();
+
+	if ( cSuffixLen > cStrLen )
+		return false;
+
+	std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
+
+	return 0 == stricmp( sStringSuffix.c_str(), sSuffix.c_str() );
+}
+
+bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix )
+{
+	size_t cStrLen = sString.length();
+	size_t cSuffixLen = sSuffix.length();
+
+	if ( cSuffixLen > cStrLen )
+		return false;
+
+	std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
+
+	return 0 == strncmp( sStringSuffix.c_str(), sSuffix.c_str(),cSuffixLen );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+std::string UTF16to8(const wchar_t * in)
+{
+	std::string out;
+	unsigned int codepoint = 0;
+	for ( ; in && *in != 0; ++in )
+	{
+		if (*in >= 0xd800 && *in <= 0xdbff)
+			codepoint = ((*in - 0xd800) << 10) + 0x10000;
+		else
+		{
+			if (*in >= 0xdc00 && *in <= 0xdfff)
+				codepoint |= *in - 0xdc00;
+			else
+				codepoint = *in;
+
+			if (codepoint <= 0x7f)
+				out.append(1, static_cast<char>(codepoint));
+			else if (codepoint <= 0x7ff)
+			{
+				out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
+				out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
+			}
+			else if (codepoint <= 0xffff)
+			{
+				out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
+				out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
+				out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
+			}
+			else
+			{
+				out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
+				out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
+				out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
+				out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
+			}
+			codepoint = 0;
+		}
+	}
+	return out;
+}
+
+std::wstring UTF8to16(const char * in)
+{
+	std::wstring out;
+	unsigned int codepoint = 0;
+	int following = 0;
+	for ( ; in && *in != 0; ++in )
+	{
+		unsigned char ch = *in;
+		if (ch <= 0x7f)
+		{
+			codepoint = ch;
+			following = 0;
+		}
+		else if (ch <= 0xbf)
+		{
+			if (following > 0)
+			{
+				codepoint = (codepoint << 6) | (ch & 0x3f);
+				--following;
+			}
+		}
+		else if (ch <= 0xdf)
+		{
+			codepoint = ch & 0x1f;
+			following = 1;
+		}
+		else if (ch <= 0xef)
+		{
+			codepoint = ch & 0x0f;
+			following = 2;
+		}
+		else
+		{
+			codepoint = ch & 0x07;
+			following = 3;
+		}
+		if (following == 0)
+		{
+			if (codepoint > 0xffff)
+			{
+				out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
+				out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
+			}
+			else
+				out.append(1, static_cast<wchar_t>(codepoint));
+			codepoint = 0;
+		}
+	}
+	return out;
+}
+
+
+void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource )
+{
+	pchBuffer[ unBufferSizeBytes - 1 ] = '\0';
+	strncpy( pchBuffer, pchSource, unBufferSizeBytes - 1 );
+}
+
+
+// --------------------------------------------------------------------
+// Purpose: converts a string to upper case
+// --------------------------------------------------------------------
+std::string StringToUpper( const std::string & sString )
+{
+	std::string sOut;
+	sOut.reserve( sString.size() + 1 );
+	for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
+	{
+		sOut.push_back( (char)toupper( *i ) );
+	}
+
+	return sOut;
+}
+
+
+// --------------------------------------------------------------------
+// Purpose: converts a string to lower case
+// --------------------------------------------------------------------
+std::string StringToLower( const std::string & sString )
+{
+	std::string sOut;
+	sOut.reserve( sString.size() + 1 );
+	for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
+	{
+		sOut.push_back( (char)tolower( *i ) );
+	}
+
+	return sOut;
+}
+
+
+uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen )
+{
+	uint32_t unLen = (uint32_t)sValue.length() + 1;
+	if( !pchBuffer || !unBufferLen )
+		return unLen;
+
+	if( unBufferLen < unLen )
+	{
+		pchBuffer[0] = '\0';
+	}
+	else
+	{
+		memcpy( pchBuffer, sValue.c_str(), unLen );
+	}
+
+	return unLen;
+}
+
+void BufferToStdString( std::string & sDest, const char *pchBuffer, uint32_t unBufferLen )
+{
+	sDest.resize( unBufferLen + 1 );
+	memcpy( const_cast< char* >( sDest.c_str() ), pchBuffer, unBufferLen );
+	const_cast< char* >( sDest.c_str() )[ unBufferLen ] = '\0';
+}
+
+// Commented out by Mozilla, please see README.mozilla
+/** Returns a std::string from a uint64_t */
+/*
+std::string Uint64ToString( uint64_t ulValue )
+{
+	char buf[ 22 ];
+#if defined( _WIN32 )
+	sprintf_s( buf, "%llu", ulValue );
+#else
+    snprintf( buf, sizeof( buf ), "%llu", (long long unsigned int ) ulValue );
+#endif
+	return buf;
+}
+*/
+
+/** returns a uint64_t from a string */
+uint64_t StringToUint64( const std::string & sValue )
+{
+	return strtoull( sValue.c_str(), NULL, 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for converting a numeric value to a hex digit, value should be 0-15.
+//-----------------------------------------------------------------------------
+char cIntToHexDigit( int nValue )
+{
+	//Assert( nValue >= 0 && nValue <= 15 );
+	return "0123456789ABCDEF"[ nValue & 15 ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for converting a hex char value to numeric, return -1 if the char
+//          is not a valid hex digit.
+//-----------------------------------------------------------------------------
+int iHexCharToInt( char cValue )
+{
+	int32_t iValue = cValue;
+	if ( (uint32_t)( iValue - '0' ) < 10 )
+		return iValue - '0';
+
+	iValue |= 0x20;
+	if ( (uint32_t)( iValue - 'a' ) < 6 )
+		return iValue - 'a' + 10;
+
+	return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Internal implementation of encode, works in the strict RFC manner, or
+//          with spaces turned to + like HTML form encoding.
+//-----------------------------------------------------------------------------
+void V_URLEncodeInternal( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen, bool bUsePlusForSpace )
+{
+	//AssertMsg( nDestLen > 3*nSourceLen, "Target buffer for V_URLEncode should be 3x source length, plus one for terminating null\n" );
+	
+	int iDestPos = 0;
+	for ( int i=0; i < nSourceLen; ++i )
+	{
+		// worst case we need 3 additional chars
+		if( (iDestPos+3) > nDestLen  )
+		{
+			pchDest[0] = '\0';
+//			AssertMsg( false, "Target buffer too short\n" );
+			return;
+		}
+
+		// We allow only a-z, A-Z, 0-9, period, underscore, and hyphen to pass through unescaped.
+		// These are the characters allowed by both the original RFC 1738 and the latest RFC 3986.
+		// Current specs also allow '~', but that is forbidden under original RFC 1738.
+		if ( !( pchSource[i] >= 'a' && pchSource[i] <= 'z' ) && !( pchSource[i] >= 'A' && pchSource[i] <= 'Z' ) && !(pchSource[i] >= '0' && pchSource[i] <= '9' )
+			 && pchSource[i] != '-' && pchSource[i] != '_' && pchSource[i] != '.'	
+		)
+		{
+			if ( bUsePlusForSpace && pchSource[i] == ' ' )
+			{
+				pchDest[iDestPos++] = '+';
+			}
+			else
+			{
+				pchDest[iDestPos++] = '%';
+				uint8_t iValue = pchSource[i];
+				if ( iValue == 0 )
+				{
+					pchDest[iDestPos++] = '0';
+					pchDest[iDestPos++] = '0';
+				}
+				else
+				{
+					char cHexDigit1 = cIntToHexDigit( iValue % 16 );
+					iValue /= 16;
+					char cHexDigit2 = cIntToHexDigit( iValue );
+					pchDest[iDestPos++] = cHexDigit2;
+					pchDest[iDestPos++] = cHexDigit1;
+				}
+			}
+		}
+		else
+		{
+			pchDest[iDestPos++] = pchSource[i];
+		}
+	}
+
+	if( (iDestPos+1) > nDestLen )
+	{
+		pchDest[0] = '\0';
+		//AssertMsg( false, "Target buffer too short to terminate\n" );
+		return;
+	}
+
+	// Null terminate
+	pchDest[iDestPos++] = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Internal implementation of decode, works in the strict RFC manner, or
+//          with spaces turned to + like HTML form encoding.
+//
+//			Returns the amount of space used in the output buffer.
+//-----------------------------------------------------------------------------
+size_t V_URLDecodeInternal( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen, bool bUsePlusForSpace )
+{
+	if ( nDecodeDestLen < nEncodedSourceLen )
+	{
+		//AssertMsg( false, "V_URLDecode needs a dest buffer at least as large as the source" );
+		return 0;
+	}
+
+	int iDestPos = 0;
+	for( int i=0; i < nEncodedSourceLen; ++i )
+	{
+		if ( bUsePlusForSpace && pchEncodedSource[i] == '+' )
+		{
+			pchDecodeDest[ iDestPos++ ] = ' ';
+		}
+		else if ( pchEncodedSource[i] == '%' )
+		{
+			// Percent signifies an encoded value, look ahead for the hex code, convert to numeric, and use that
+
+			// First make sure we have 2 more chars
+			if ( i < nEncodedSourceLen - 2 )
+			{
+				char cHexDigit1 = pchEncodedSource[i+1];
+				char cHexDigit2 = pchEncodedSource[i+2];
+
+				// Turn the chars into a hex value, if they are not valid, then we'll
+				// just place the % and the following two chars direct into the string,
+				// even though this really shouldn't happen, who knows what bad clients
+				// may do with encoding.
+				bool bValid = false;
+				int iValue = iHexCharToInt( cHexDigit1 );
+				if ( iValue != -1 )
+				{
+					iValue *= 16;
+					int iValue2 = iHexCharToInt( cHexDigit2 );
+					if ( iValue2 != -1 )
+					{
+						iValue += iValue2;
+						pchDecodeDest[ iDestPos++ ] = (char)iValue;
+						bValid = true;
+					}
+				}
+
+				if ( !bValid )
+				{
+					pchDecodeDest[ iDestPos++ ] = '%';
+					pchDecodeDest[ iDestPos++ ] = cHexDigit1;
+					pchDecodeDest[ iDestPos++ ] = cHexDigit2;
+				}
+			}
+
+			// Skip ahead
+			i += 2;
+		}
+		else
+		{
+			pchDecodeDest[ iDestPos++ ] = pchEncodedSource[i];
+		}
+	}
+
+	// We may not have extra room to NULL terminate, since this can be used on raw data, but if we do
+	// go ahead and do it as this can avoid bugs.
+	if ( iDestPos < nDecodeDestLen )
+	{
+		pchDecodeDest[iDestPos] = 0;
+	}
+
+	return (size_t)iDestPos;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.  
+//          This version of the call isn't a strict RFC implementation, but uses + for space as is
+//          the standard in HTML form encoding, despite it not being part of the RFC.
+//
+//          Dest buffer should be at least as large as source buffer to guarantee room for decode.
+//-----------------------------------------------------------------------------
+void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
+{
+	return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.  
+//          This version of the call isn't a strict RFC implementation, but uses + for space as is
+//          the standard in HTML form encoding, despite it not being part of the RFC.
+//
+//          Dest buffer should be at least as large as source buffer to guarantee room for decode.
+//			Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
+//-----------------------------------------------------------------------------
+size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen )
+{
+	return V_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, true );
+}
+
+//-----------------------------------------------------------------------------
+void V_StripExtension( std::string &in )
+{
+	// Find the last dot. If it's followed by a dot or a slash, then it's part of a 
+	// directory specifier like ../../somedir/./blah.
+	std::string::size_type test = in.rfind( '.' );
+	if ( test != std::string::npos )
+	{
+		// This handles things like ".\blah" or "c:\my@email.com\abc\def\geh"
+		// Which would otherwise wind up with "" and "c:\my@email", respectively.
+		if ( in.rfind( '\\' ) < test && in.rfind( '/' ) < test )
+		{
+			in.resize( test );
+		}
+	}
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/strtools_public.h
@@ -0,0 +1,127 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+#include <string>
+#include <stdint.h>
+#include <sys/types.h>
+
+/** returns true if the string has the prefix */
+bool StringHasPrefix( const std::string & sString, const std::string & sPrefix );
+bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix );
+
+/** returns if the string has the suffix */
+bool StringHasSuffix( const std::string &sString, const std::string &sSuffix );
+bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix );
+
+/** converts a UTF-16 string to a UTF-8 string */
+std::string UTF16to8(const wchar_t * in);
+
+/** converts a UTF-8 string to a UTF-16 string */
+std::wstring UTF8to16(const char * in);
+#define Utf16FromUtf8 UTF8to16
+
+/** safely copy a string into a buffer */
+void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource );
+template< size_t bufferSize >
+void strcpy_safe( char (& buffer) [ bufferSize ], const char *pchSource ) 
+{
+	strcpy_safe( buffer, bufferSize, pchSource );
+}
+
+
+/** converts a string to upper case */
+std::string StringToUpper( const std::string & sString );
+
+/** converts a string to lower case */
+std::string StringToLower( const std::string & sString );
+
+// we stricmp (from WIN) but it isn't POSIX - OSX/LINUX have strcasecmp so just inline bridge to it
+#if defined( OSX ) || defined( LINUX )
+#include <strings.h>
+inline int stricmp(const char *pStr1, const char *pStr2) { return strcasecmp(pStr1,pStr2); }
+#define _stricmp stricmp
+inline int strnicmp( const char *pStr1, const char *pStr2, size_t unBufferLen ) { return strncasecmp( pStr1,pStr2, unBufferLen ); }
+#define _strnicmp strnicmp
+
+#define _vsnprintf_s vsnprintf
+
+#define _TRUNCATE ((size_t)-1)
+
+#endif
+
+#if defined( OSX )
+// behaviors ensure NULL-termination at least as well as _TRUNCATE does, but
+// wcsncpy_s/strncpy_s can non-NULL-terminate, wcslcpy/strlcpy can not.
+inline errno_t wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
+{
+	return wcslcpy(strDest, strSource, numberOfElements);
+}
+
+inline errno_t strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
+{
+	return strlcpy(strDest, strSource, numberOfElements);
+}
+
+#endif
+
+#if defined( LINUX )
+// this implementation does not return whether or not the destination was 
+// truncated, but that is straightforward to fix if anybody actually needs the
+// return code. 
+#include "string.h"
+inline void wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
+{
+	wcsncpy(strDest, strSource, numberOfElements);
+	strDest[numberOfElements-1] = '\0';
+}
+
+inline void strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
+{
+	strncpy(strDest, strSource, numberOfElements);
+	strDest[numberOfElements-1] = '\0';
+}
+
+#endif
+
+#if defined( _WIN32 ) && _MSC_VER < 1800
+inline uint64_t strtoull(const char *str, char **endptr, int base) { return _strtoui64( str, endptr, base ); }
+#endif
+
+/* Handles copying a std::string into a buffer as would be provided in an API */
+uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen );
+
+/* Handles copying a buffer into an std::string and auto adds null terminator */
+void BufferToStdString( std::string & sDest, const char *pchBuffer, uint32_t unBufferLen );
+
+/** Returns a std::string from a uint64_t */
+// std::string Uint64ToString( uint64_t ulValue );
+// Commented out by Mozilla, please see README.mozilla
+
+/** returns a uint64_t from a string */
+uint64_t StringToUint64( const std::string & sValue );
+
+//-----------------------------------------------------------------------------
+// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.  
+//          This version of the call isn't a strict RFC implementation, but uses + for space as is
+//          the standard in HTML form encoding, despite it not being part of the RFC.
+//
+//          Dest buffer should be at least as large as source buffer to guarantee room for decode.
+//-----------------------------------------------------------------------------
+void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
+
+//-----------------------------------------------------------------------------
+// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.  
+//          This version of the call isn't a strict RFC implementation, but uses + for space as is
+//          the standard in HTML form encoding, despite it not being part of the RFC.
+//
+//          Dest buffer should be at least as large as source buffer to guarantee room for decode.
+//			Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
+//-----------------------------------------------------------------------------
+size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
+
+//-----------------------------------------------------------------------------
+// Purpose: strip extension from a path
+//-----------------------------------------------------------------------------
+void V_StripExtension( std::string &in );
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/vrpathregistry_public.cpp
@@ -0,0 +1,409 @@
+//========= Copyright Valve Corporation ============//
+
+#include "vrpathregistry_public.h"
+#include "json/json.h"
+#include "pathtools_public.h"
+#include "envvartools_public.h"
+#include "strtools_public.h"
+#include "dirtools_public.h"
+
+#if defined( WIN32 )
+#include <windows.h>
+#include <Shlobj.h>
+
+#undef GetEnvironmentVariable
+#elif defined OSX
+#include <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+#elif defined(LINUX)
+#include <dlfcn.h>
+#include <stdio.h>
+#endif
+
+#include <algorithm>
+
+#ifndef VRLog
+	#if defined( WIN32 )
+		#define VRLog(fmt, ...)		fprintf(stderr, fmt, __VA_ARGS__)
+	#else
+		#define VRLog(args...)		fprintf(stderr, args)
+	#endif
+#endif
+
+/** Returns the root of the directory the system wants us to store user config data in */
+static std::string GetAppSettingsPath()
+{
+#if defined( WIN32 )
+	WCHAR rwchPath[MAX_PATH];
+
+	if( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
+	{
+		return "";
+	}
+
+	// Convert the path to UTF-8 and store in the output
+	std::string sUserPath = UTF16to8( rwchPath );
+
+	return sUserPath;
+#elif defined( OSX )
+	std::string sSettingsDir;
+	@autoreleasepool {
+		// Search for the path
+		NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES );
+		if ( [paths count] == 0 )
+		{
+			return "";
+		}
+		
+		NSString *resolvedPath = [paths objectAtIndex:0];
+		resolvedPath = [resolvedPath stringByAppendingPathComponent: @"OpenVR"];
+		
+		if ( ![[NSFileManager new] createDirectoryAtPath: resolvedPath withIntermediateDirectories:YES attributes:nil error:nil] )
+		{
+			return "";
+		}
+		
+		sSettingsDir.assign( [resolvedPath UTF8String] );
+	}
+	return sSettingsDir;
+#elif defined( LINUX )
+
+	// As defined by XDG Base Directory Specification 
+	// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+
+	const char *pchHome = getenv("XDG_CONFIG_HOME");
+	if ( ( pchHome != NULL) && ( pchHome[0] != '\0' ) )
+	{
+		return pchHome;
+	}
+
+	//
+	// XDG_CONFIG_HOME is not defined, use ~/.config instead
+	// 
+	pchHome = getenv( "HOME" );
+	if ( pchHome == NULL )
+	{
+		return "";
+	}
+
+	std::string sUserPath( pchHome );
+	sUserPath = Path_Join( sUserPath, ".config" );
+	return sUserPath;
+#else
+	#warning "Unsupported platform"
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Constructor
+// ---------------------------------------------------------------------------
+CVRPathRegistry_Public::CVRPathRegistry_Public()
+{
+
+}
+
+// ---------------------------------------------------------------------------
+// Purpose: Computes the registry filename
+// ---------------------------------------------------------------------------
+std::string CVRPathRegistry_Public::GetOpenVRConfigPath()
+{
+	std::string sConfigPath = GetAppSettingsPath();
+	if( sConfigPath.empty() )
+		return "";
+
+#if defined( _WIN32 ) || defined( LINUX )
+	sConfigPath = Path_Join( sConfigPath, "openvr" );
+#elif defined ( OSX ) 
+	sConfigPath = Path_Join( sConfigPath, ".openvr" );
+#else
+	#warning "Unsupported platform"
+#endif
+	sConfigPath = Path_FixSlashes( sConfigPath );
+	return sConfigPath;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+std::string CVRPathRegistry_Public::GetVRPathRegistryFilename()
+{
+	std::string sPath = GetOpenVRConfigPath();
+	if ( sPath.empty() )
+		return "";
+
+#if defined( _WIN32 )
+	sPath = Path_Join( sPath, "openvrpaths.vrpath" );
+#elif defined ( POSIX ) 
+	sPath = Path_Join( sPath, "openvrpaths.vrpath" );
+#else
+	#error "Unsupported platform"
+#endif
+	sPath = Path_FixSlashes( sPath );
+	return sPath;
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Converts JSON to a history array
+// ---------------------------------------------------------------------------
+static void ParseStringListFromJson( std::vector< std::string > *pvecHistory, const Json::Value & root, const char *pchArrayName )
+{
+	if( !root.isMember( pchArrayName ) )
+		return;
+
+	const Json::Value & arrayNode = root[ pchArrayName ];
+	if( !arrayNode )
+	{
+		VRLog( "VR Path Registry node %s is not an array\n", pchArrayName );
+		return;
+	}
+
+	pvecHistory->clear();
+	pvecHistory->reserve( arrayNode.size() );
+	for( uint32_t unIndex = 0; unIndex < arrayNode.size(); unIndex++ )
+	{
+		std::string sPath( arrayNode[ unIndex ].asString() );
+		pvecHistory->push_back( sPath );
+	}
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Converts a history array to JSON
+// ---------------------------------------------------------------------------
+static void StringListToJson( const std::vector< std::string > & vecHistory, Json::Value & root, const char *pchArrayName )
+{
+	Json::Value & arrayNode = root[ pchArrayName ];
+	for( auto i = vecHistory.begin(); i != vecHistory.end(); i++ )
+	{
+		arrayNode.append( *i );
+	}
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CVRPathRegistry_Public::ToJsonString( std::string &sJsonString )
+{
+	std::string sRegPath = GetVRPathRegistryFilename();
+	if( sRegPath.empty() )
+		return false;
+	
+	std::string sRegistryContents = Path_ReadTextFile( sRegPath );
+	if( sRegistryContents.empty() )
+		return false;
+
+	sJsonString = sRegistryContents;
+
+	return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Loads the config file from its well known location
+// ---------------------------------------------------------------------------
+bool CVRPathRegistry_Public::BLoadFromFile()
+{
+	std::string sRegPath = GetVRPathRegistryFilename();
+	if( sRegPath.empty() )
+	{
+		VRLog( "Unable to determine VR Path Registry filename\n" );
+		return false;
+	}
+
+	std::string sRegistryContents = Path_ReadTextFile( sRegPath );
+	if( sRegistryContents.empty() )
+	{
+		VRLog( "Unable to read VR Path Registry from %s\n", sRegPath.c_str() );
+		return false;
+	}
+
+	Json::Value root;
+	Json::Reader reader;
+
+	if( !reader.parse( sRegistryContents, root ) )
+	{
+		VRLog( "Unable to parse %s: %s\n", sRegPath.c_str(), reader.getFormattedErrorMessages().c_str() );
+		return false;
+	}
+
+	ParseStringListFromJson( &m_vecRuntimePath, root, "runtime" );
+	ParseStringListFromJson( &m_vecConfigPath, root, "config" );
+	ParseStringListFromJson( &m_vecLogPath, root, "log" );
+	if (root.isMember( "external_drivers" ) && root[ "external_drivers" ].isArray() )
+	{
+		ParseStringListFromJson( &m_vecExternalDrivers, root, "external_drivers" );
+	}
+
+	return true;
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Saves the config file to its well known location
+// ---------------------------------------------------------------------------
+bool CVRPathRegistry_Public::BSaveToFile() const
+{
+#if defined( DASHBOARD_BUILD_MODE )
+	return false;
+#else
+	std::string sRegPath = GetVRPathRegistryFilename();
+	if( sRegPath.empty() )
+		return false;
+	
+	Json::Value root;
+	
+	root[ "version" ] = 1;
+	root[ "jsonid" ] = "vrpathreg";
+
+	StringListToJson( m_vecRuntimePath, root, "runtime" );
+	StringListToJson( m_vecConfigPath, root, "config" );
+	StringListToJson( m_vecLogPath, root, "log" );
+	StringListToJson( m_vecExternalDrivers, root, "external_drivers" );
+
+	Json::StyledWriter writer;
+	std::string sRegistryContents = writer.write( root );
+
+	// make sure the directory we're writing into actually exists
+	std::string sRegDirectory = Path_StripFilename( sRegPath );
+	if( !BCreateDirectoryRecursive( sRegDirectory.c_str() ) )
+	{
+		VRLog( "Unable to create path registry directory %s\n", sRegDirectory.c_str() );
+		return false;
+	}
+
+	if( !Path_WriteStringToTextFile( sRegPath, sRegistryContents.c_str() ) )
+	{
+		VRLog( "Unable to write VR path registry to %s\n", sRegPath.c_str() );
+		return false;
+	}
+
+	return true;
+#endif
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Returns the current runtime path or NULL if no path is configured.
+// ---------------------------------------------------------------------------
+std::string CVRPathRegistry_Public::GetRuntimePath() const
+{
+	if( m_vecRuntimePath.empty() )
+		return "";
+	else
+		return m_vecRuntimePath.front().c_str();
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Returns the current config path or NULL if no path is configured.
+// ---------------------------------------------------------------------------
+std::string CVRPathRegistry_Public::GetConfigPath() const
+{
+	if( m_vecConfigPath.empty() )
+		return "";
+	else
+		return m_vecConfigPath.front().c_str();
+}
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Returns the current log path or NULL if no path is configured.
+// ---------------------------------------------------------------------------
+std::string CVRPathRegistry_Public::GetLogPath() const
+{
+	if( m_vecLogPath.empty() )
+		return "";
+	else
+		return m_vecLogPath.front().c_str();
+}
+
+
+
+// ---------------------------------------------------------------------------
+// Purpose: Returns paths using the path registry and the provided override 
+//			values. Pass NULL for any paths you don't care about.
+// ---------------------------------------------------------------------------
+bool CVRPathRegistry_Public::GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers )
+{
+	CVRPathRegistry_Public pathReg;
+	bool bLoadedRegistry = pathReg.BLoadFromFile();
+	int nCountEnvironmentVariables = 0;
+
+	if( psRuntimePath )
+	{
+		if ( GetEnvironmentVariable( k_pchRuntimeOverrideVar ).length() != 0 )
+		{
+			*psRuntimePath = GetEnvironmentVariable( k_pchRuntimeOverrideVar );
+			nCountEnvironmentVariables++;
+		}
+		else if( !pathReg.GetRuntimePath().empty() )
+		{
+			*psRuntimePath = pathReg.GetRuntimePath();
+		}
+		else
+		{
+			*psRuntimePath = "";
+		}
+	}
+
+	if( psConfigPath )
+	{
+		if ( GetEnvironmentVariable( k_pchConfigOverrideVar ).length() != 0 )
+		{
+			*psConfigPath = GetEnvironmentVariable( k_pchConfigOverrideVar );
+			nCountEnvironmentVariables++;
+		}
+		else if( pchConfigPathOverride )
+		{
+			*psConfigPath = pchConfigPathOverride;
+		}
+		else if( !pathReg.GetConfigPath().empty() )
+		{
+			*psConfigPath = pathReg.GetConfigPath();
+		}
+		else
+		{
+			*psConfigPath = "";
+		}
+	}
+
+	if( psLogPath )
+	{
+		if ( GetEnvironmentVariable( k_pchLogOverrideVar ).length() != 0 )
+		{
+			*psLogPath = GetEnvironmentVariable( k_pchLogOverrideVar );
+			nCountEnvironmentVariables++;
+		}
+		else if( pchLogPathOverride )
+		{
+			*psLogPath = pchLogPathOverride;
+		}
+		else if( !pathReg.GetLogPath().empty() )
+		{
+			*psLogPath = pathReg.GetLogPath();
+		}
+		else
+		{
+			*psLogPath = "";
+		}
+	}
+
+	if ( pvecExternalDrivers )
+	{
+		*pvecExternalDrivers = pathReg.m_vecExternalDrivers;
+	}
+
+	if ( nCountEnvironmentVariables == 3 )
+	{
+		// all three environment variables where set, so we don't need the physical file
+		return true;
+	}
+
+	return bLoadedRegistry;
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/openvr/src/vrpathregistry_public.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation ============//
+#pragma once
+
+#include <string>
+#include <vector>
+#include <stdint.h>
+
+static const char *k_pchRuntimeOverrideVar = "VR_OVERRIDE";
+static const char *k_pchConfigOverrideVar = "VR_CONFIG_PATH";
+static const char *k_pchLogOverrideVar = "VR_LOG_PATH";
+
+class CVRPathRegistry_Public
+{
+public:
+	static std::string GetVRPathRegistryFilename();
+	static std::string GetOpenVRConfigPath();
+
+public:
+	CVRPathRegistry_Public();
+
+	/** Returns paths using the path registry and the provided override values. Pass NULL for any paths you don't care about. 
+	* Returns false if the path registry could not be read. Valid paths might still be returned based on environment variables. */
+	static bool GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers = NULL );
+
+	bool BLoadFromFile();
+	bool BSaveToFile() const;
+
+	bool ToJsonString( std::string &sJsonString );
+
+	// methods to get the current values
+	std::string GetRuntimePath() const;
+	std::string GetConfigPath() const;
+	std::string GetLogPath() const;
+
+protected:
+	typedef std::vector< std::string > StringVector_t;
+
+	// index 0 is the current setting
+	StringVector_t m_vecRuntimePath;
+	StringVector_t m_vecLogPath;
+	StringVector_t m_vecConfigPath;
+
+	// full list of external drivers
+	StringVector_t m_vecExternalDrivers;
+};
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5071,18 +5071,16 @@ pref("dom.vr.openvr.enabled", false);
 // poses to callers of the WebVR API.  This currently only has an effect for
 // Oculus Rift on SDK 0.8 or greater.
 pref("dom.vr.poseprediction.enabled", true);
 // Starting VR presentation is only allowed within a user gesture or event such
 // as VRDisplayActivate triggered by the system.  dom.vr.require-gesture allows
 // this requirement to be disabled for special cases such as during automated
 // tests or in a headless kiosk system.
 pref("dom.vr.require-gesture", true);
-// path to openvr DLL
-pref("gfx.vr.openvr-runtime", "");
 // path to OSVR DLLs
 pref("gfx.vr.osvr.utilLibPath", "");
 pref("gfx.vr.osvr.commonLibPath", "");
 pref("gfx.vr.osvr.clientLibPath", "");
 pref("gfx.vr.osvr.clientKitLibPath", "");
 // Puppet device, used for simulating VR hardware within tests and dev tools
 pref("dom.vr.puppet.enabled", false);
 pref("dom.vr.test.enabled", false);
--- a/tools/rewriting/ThirdPartyPaths.txt
+++ b/tools/rewriting/ThirdPartyPaths.txt
@@ -7,16 +7,17 @@ gfx/2d/convolver
 gfx/2d/image_operations
 gfx/angle/
 gfx/cairo/
 gfx/graphite2/
 gfx/harfbuzz/
 gfx/ots/
 gfx/qcms/
 gfx/skia/
+gfx/vr/openvr/
 gfx/webrender
 gfx/webrender_traits
 gfx/ycbcr/
 intl/hyphenation/hyphen/
 intl/icu/
 ipc/chromium/
 js/src/ctypes/libffi/
 js/src/dtoa.c