Bug 1341423 - Integrate OpenVR binding library r=daoshengmu
authorKearwood Gilbert <kgilbert@mozilla.com>
Mon, 27 Feb 2017 16:59:30 -0800
changeset 386807 1a6f70f0488dd6dccf9716b771623d12ce856973
parent 386806 8d081bf9b8399146949f67da496c287c67cd3317
child 386808 021e1f76a70fe2428adce3f8758d65362d0bbea7
push id51
push userfmarier@mozilla.com
push dateFri, 05 May 2017 18:41:45 +0000
reviewersdaoshengmu
bugs1341423
milestone55.0a1
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