diff --git a/.clang-format-ignore b/.clang-format-ignore index 72ca2c07fe05..b7eff41647d6 100644 --- a/.clang-format-ignore +++ b/.clang-format-ignore @@ -25,6 +25,7 @@ ^gfx/ots/.* ^gfx/qcms/.* ^gfx/skia/.* +^gfx/vr/openvr/.* ^gfx/webrender.* ^gfx/webrender_traits.* ^gfx/ycbcr/.* diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 3bc9ce721728..f66ebc3c7c8d 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -453,7 +453,6 @@ private: 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); diff --git a/gfx/vr/VRManager.cpp b/gfx/vr/VRManager.cpp index 44d5fb563647..cdb522530723 100644 --- a/gfx/vr/VRManager.cpp +++ b/gfx/vr/VRManager.cpp @@ -7,7 +7,6 @@ #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" @@ -18,6 +17,7 @@ #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" @@ -75,15 +75,14 @@ VRManager::VRManager() 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) { diff --git a/gfx/vr/gfxVROpenVR.cpp b/gfx/vr/gfxVROpenVR.cpp index a58e0e2535c4..2d60c085df2b 100644 --- a/gfx/vr/gfxVROpenVR.cpp +++ b/gfx/vr/gfxVROpenVR.cpp @@ -20,10 +20,12 @@ #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" @@ -37,60 +39,11 @@ 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) @@ -152,7 +105,7 @@ void VRDisplayOpenVR::Destroy() { StopPresentation(); - vr_ShutdownInternal(); + ::vr::VR_Shutdown(); } void @@ -344,7 +297,7 @@ VRDisplayOpenVR::SubmitFrame(TextureSourceD3D11* aSource, ::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; @@ -383,7 +336,7 @@ 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(); @@ -554,11 +507,7 @@ VRSystemManagerOpenVR::Create() return nullptr; } - if (!LoadOpenVRRuntime()) { - return nullptr; - } - - if (!vr_IsRuntimeInstalled()) { + if (!::vr::VR_IsRuntimeInstalled()) { return nullptr; } @@ -585,31 +534,31 @@ VRSystemManagerOpenVR::Shutdown() void VRSystemManagerOpenVR::GetHMDs(nsTArray>& 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; } @@ -659,7 +608,7 @@ VRSystemManagerOpenVR::HandleInput() 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, diff --git a/gfx/vr/gfxVROpenVR.h b/gfx/vr/gfxVROpenVR.h index 068886f34606..034922e44e38 100644 --- a/gfx/vr/gfxVROpenVR.h +++ b/gfx/vr/gfxVROpenVR.h @@ -14,16 +14,9 @@ #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 { diff --git a/gfx/vr/moz.build b/gfx/vr/moz.build index 8bd0f1887eb0..ae38f2afb73d 100644 --- a/gfx/vr/moz.build +++ b/gfx/vr/moz.build @@ -23,7 +23,6 @@ LOCAL_INCLUDES += [ UNIFIED_SOURCES += [ 'gfxVR.cpp', - 'gfxVROpenVR.cpp', 'gfxVROSVR.cpp', 'gfxVRPuppet.cpp', 'ipc/VRLayerChild.cpp', @@ -37,8 +36,12 @@ UNIFIED_SOURCES += [ ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + DIRS += [ + 'openvr', + ] SOURCES += [ 'gfxVROculus.cpp', + 'gfxVROpenVR.cpp', ] IPDL_SOURCES = [ diff --git a/gfx/vr/openvr/README b/gfx/vr/openvr/README deleted file mode 100644 index 5e67e5a3a947..000000000000 --- a/gfx/vr/openvr/README +++ /dev/null @@ -1,2 +0,0 @@ -See https://github.com/ValveSoftware/openvr/ - diff --git a/gfx/vr/openvr/README.md b/gfx/vr/openvr/README.md new file mode 100644 index 000000000000..5976d622f6ad --- /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 diff --git a/gfx/vr/openvr/README.mozilla b/gfx/vr/openvr/README.mozilla new file mode 100644 index 000000000000..3bd2edb59fd1 --- /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. diff --git a/gfx/vr/openvr/openvr.h b/gfx/vr/openvr/headers/openvr.h similarity index 86% rename from gfx/vr/openvr/openvr.h rename to gfx/vr/openvr/headers/openvr.h index f8931db918f9..213be6e4e53f 100644 --- a/gfx/vr/openvr/openvr.h +++ b/gfx/vr/openvr/headers/openvr.h @@ -13,7 +13,17 @@ // 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 { @@ -105,10 +115,13 @@ enum EVREye 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 @@ -120,11 +133,15 @@ enum EColorSpace 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, @@ -136,7 +153,6 @@ enum ETrackingResult 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 */ @@ -154,8 +170,6 @@ enum ETrackedDeviceClass 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, }; @@ -188,14 +202,40 @@ 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, @@ -230,6 +270,9 @@ enum ETrackedDeviceProperty 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, @@ -269,6 +312,12 @@ enum ETrackedDeviceProperty 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, @@ -289,6 +338,25 @@ enum ETrackedDeviceProperty 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, @@ -304,12 +372,14 @@ enum ETrackedPropertyError 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 @@ -334,8 +404,32 @@ enum EVRSubmitFlags // 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 @@ -359,13 +453,15 @@ enum EVREventType 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 @@ -395,89 +491,97 @@ enum EVREventType 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_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_ChaperoneDataHasChanged = 800, + VREvent_ChaperoneUniverseHasChanged = 801, + VREvent_ChaperoneTempDataHasChanged = 802, + VREvent_ChaperoneSettingsHaveChanged = 803, + VREvent_SeatedZeroPoseReset = 804, - VREvent_AudioSettingsHaveChanged = 820, + VREvent_AudioSettingsHaveChanged = 820, - VREvent_BackgroundSettingHasChanged = 850, - VREvent_CameraSettingsHaveChanged = 851, - VREvent_ReprojectionSettingHasChanged = 852, - VREvent_ModelSkinSettingsHaveChanged = 853, - VREvent_EnvironmentSettingsHaveChanged = 854, + VREvent_BackgroundSettingHasChanged = 850, + VREvent_CameraSettingsHaveChanged = 851, + VREvent_ReprojectionSettingHasChanged = 852, + VREvent_ModelSkinSettingsHaveChanged = 853, + VREvent_EnvironmentSettingsHaveChanged = 854, + VREvent_PowerSettingsHaveChanged = 855, - VREvent_StatusUpdate = 900, + VREvent_StatusUpdate = 900, - VREvent_MCImageUpdated = 1000, + VREvent_MCImageUpdated = 1000, - VREvent_FirmwareUpdateStarted = 1100, - VREvent_FirmwareUpdateFinished = 1101, + VREvent_FirmwareUpdateStarted = 1100, + VREvent_FirmwareUpdateFinished = 1101, - VREvent_KeyboardClosed = 1200, - VREvent_KeyboardCharInput = 1201, - VREvent_KeyboardDone = 1202, // Sent when DONE button clicked on keyboard + 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_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_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_TrackedCamera_EditingSurface = 1550, - VREvent_PerformanceTest_EnableCapture = 1600, - VREvent_PerformanceTest_DisableCapture = 1601, - VREvent_PerformanceTest_FidelityLevel = 1602, + 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, }; @@ -503,6 +607,8 @@ enum EVRButtonId 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, @@ -652,7 +758,24 @@ struct VREvent_ApplicationLaunch_t 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; @@ -672,6 +795,9 @@ typedef union 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 */ @@ -698,6 +824,16 @@ struct HiddenAreaMesh_t }; +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 ); */ @@ -781,26 +917,28 @@ static const VROverlayHandle_t k_ulOverlayHandleInvalid = 0; /** Errors that can occur around VR overlays */ enum EVROverlayError { - VROverlayError_None = 0, + 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_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 @@ -882,6 +1020,8 @@ enum EVRInitError 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, @@ -1000,6 +1140,12 @@ 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) @@ -1020,7 +1166,7 @@ static const uint32_t k_unScreenshotHandleInvalid = 0; #else #error "Unsupported Platform." #endif - +*/ #if defined( _WIN32 ) #define VR_CALLTYPE __cdecl @@ -1069,15 +1215,16 @@ public: 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. @@ -1098,8 +1245,8 @@ public: 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; @@ -1211,7 +1358,7 @@ public: /** 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 @@ -1239,14 +1386,15 @@ public: // 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 @@ -1254,12 +1402,12 @@ public: /** 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. */ @@ -1292,7 +1440,6 @@ public: * 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 // ------------------------------------ @@ -1304,7 +1451,6 @@ public: * 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 // ------------------------------------ @@ -1320,7 +1466,7 @@ public: }; -static const char * const IVRSystem_Version = "IVRSystem_012"; +static const char * const IVRSystem_Version = "IVRSystem_015"; } @@ -1378,6 +1524,7 @@ namespace vr VRApplicationProperty_IsDashboardOverlay_Bool = 60, VRApplicationProperty_IsTemplate_Bool = 61, VRApplicationProperty_IsInstanced_Bool = 62, + VRApplicationProperty_IsInternal_Bool = 63, VRApplicationProperty_LastLaunchTime_Uint64 = 70, }; @@ -1399,6 +1546,10 @@ namespace vr 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: @@ -1421,7 +1572,7 @@ namespace vr /** 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. */ @@ -1461,7 +1612,7 @@ namespace vr // --------------- 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; @@ -1521,6 +1672,11 @@ namespace vr * 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"; @@ -1536,6 +1692,8 @@ namespace vr 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 @@ -1549,25 +1707,27 @@ namespace vr // 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"; @@ -1581,16 +1741,13 @@ namespace vr 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"; @@ -1599,35 +1756,35 @@ namespace vr 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"; @@ -1643,6 +1800,7 @@ namespace vr // 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"; @@ -1696,6 +1854,7 @@ namespace vr 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 @@ -1707,10 +1866,29 @@ namespace vr 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_ section + static const char * const k_pch_Driver_Enable_Bool = "enable"; + } // namespace vr // ivrchaperone.h @@ -1741,7 +1919,7 @@ enum ChaperoneCalibrationState // 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 @@ -1911,10 +2089,17 @@ enum EVRCompositorError 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 @@ -1922,6 +2107,7 @@ 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; @@ -1998,7 +2184,14 @@ public: /** 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; @@ -2016,6 +2209,15 @@ public: * * 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; @@ -2034,6 +2236,10 @@ public: * 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; @@ -2046,9 +2252,15 @@ public: * 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. */ @@ -2105,17 +2317,30 @@ public: /** 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 @@ -2232,6 +2457,9 @@ namespace vr /** 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 { @@ -2288,6 +2516,20 @@ namespace vr // 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 @@ -2331,6 +2573,40 @@ namespace vr 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: @@ -2571,7 +2847,7 @@ namespace vr * 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. @@ -2627,9 +2903,25 @@ namespace vr /** 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 @@ -2874,7 +3166,7 @@ public: /** 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; @@ -2895,7 +3187,12 @@ public: /** 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 */ @@ -3045,7 +3342,6 @@ static const char * const IVRResources_Version = "IVRResources_001"; #endif // _OPENVR_API - namespace vr { /** Finds the active installation of the VR API and initializes it. The provided path must be absolute @@ -3096,7 +3392,6 @@ namespace vr // 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; diff --git a/gfx/vr/openvr/moz.build b/gfx/vr/openvr/moz.build new file mode 100644 index 000000000000..e67d076eb225 --- /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', +] + diff --git a/gfx/vr/openvr/src/README b/gfx/vr/openvr/src/README new file mode 100644 index 000000000000..953e10587081 --- /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 diff --git a/gfx/vr/openvr/src/dirtools_public.cpp b/gfx/vr/openvr/src/dirtools_public.cpp new file mode 100644 index 000000000000..e5cfc02e0c42 --- /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 +#include + +#ifdef _WIN32 +#include "windows.h" +#else +#include +#include +#include +#include +#endif + +#if defined( OSX ) +#include +#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 +} + diff --git a/gfx/vr/openvr/src/dirtools_public.h b/gfx/vr/openvr/src/dirtools_public.h new file mode 100644 index 000000000000..b048b41b7814 --- /dev/null +++ b/gfx/vr/openvr/src/dirtools_public.h @@ -0,0 +1,17 @@ +//========= Copyright Valve Corporation ============// +#pragma once + +#include +#include + + +#if !defined(_WIN32) +#include +#include +#endif + + +extern bool BCreateDirectoryRecursive( const char *pchPath ); +extern bool BCreateDirectory( const char *pchPath ); + + diff --git a/gfx/vr/openvr/src/envvartools_public.cpp b/gfx/vr/openvr/src/envvartools_public.cpp new file mode 100644 index 000000000000..bb050d68a594 --- /dev/null +++ b/gfx/vr/openvr/src/envvartools_public.cpp @@ -0,0 +1,46 @@ +//========= Copyright Valve Corporation ============// +#include "envvartools_public.h" +#include + +#if defined(_WIN32) +#include + +#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 +} diff --git a/gfx/vr/openvr/src/envvartools_public.h b/gfx/vr/openvr/src/envvartools_public.h new file mode 100644 index 000000000000..7de981ac3e39 --- /dev/null +++ b/gfx/vr/openvr/src/envvartools_public.h @@ -0,0 +1,7 @@ +//========= Copyright Valve Corporation ============// +#pragma once + +#include + +std::string GetEnvironmentVariable( const char *pchVarName ); +bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue ); diff --git a/gfx/vr/openvr/src/hmderrors_public.cpp b/gfx/vr/openvr/src/hmderrors_public.cpp new file mode 100644 index 000000000000..5d9ecbcb738d --- /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 +#include + +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; + } + } +} + diff --git a/gfx/vr/openvr/src/hmderrors_public.h b/gfx/vr/openvr/src/hmderrors_public.h new file mode 100644 index 000000000000..ccd6c8a96c13 --- /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 ); + diff --git a/gfx/vr/openvr/src/ivrclientcore.h b/gfx/vr/openvr/src/ivrclientcore.h new file mode 100644 index 000000000000..b4c6f3a364ca --- /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"; + + +} diff --git a/gfx/vr/openvr/src/openvr_api_public.cpp b/gfx/vr/openvr/src/openvr_api_public.cpp new file mode 100644 index 000000000000..3e303dde30f4 --- /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 ); +} + +} + diff --git a/gfx/vr/openvr/src/pathtools_public.cpp b/gfx/vr/openvr/src/pathtools_public.cpp new file mode 100644 index 000000000000..6413c34352ac --- /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 +#include +#include +#include +#include + +#undef GetEnvironmentVariable +#else +#include +#include +#include +#include +#endif +#if defined OSX +#include +#include +#include +#define _S_IFDIR S_IFDIR // really from tier0/platform.h which we dont have yet +#endif + +#include + +#include + +/** 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 /.. 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(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 +} + diff --git a/gfx/vr/openvr/src/pathtools_public.h b/gfx/vr/openvr/src/pathtools_public.h new file mode 100644 index 000000000000..7c34a7175c2a --- /dev/null +++ b/gfx/vr/openvr/src/pathtools_public.h @@ -0,0 +1,129 @@ +//========= Copyright Valve Corporation ============// +#pragma once + +#include +#include + +/** 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 /.. 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 diff --git a/gfx/vr/openvr/src/sharedlibtools_public.cpp b/gfx/vr/openvr/src/sharedlibtools_public.cpp new file mode 100644 index 000000000000..9c0661ef1a57 --- /dev/null +++ b/gfx/vr/openvr/src/sharedlibtools_public.cpp @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation ============// +#include "sharedlibtools_public.h" +#include + +#if defined(_WIN32) +#include +#endif + +#if defined(POSIX) +#include +#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 +} + + diff --git a/gfx/vr/openvr/src/sharedlibtools_public.h b/gfx/vr/openvr/src/sharedlibtools_public.h new file mode 100644 index 000000000000..10163dbfab2b --- /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 ); + + diff --git a/gfx/vr/openvr/src/strtools_public.cpp b/gfx/vr/openvr/src/strtools_public.cpp new file mode 100644 index 000000000000..2c0fc8b9c903 --- /dev/null +++ b/gfx/vr/openvr/src/strtools_public.cpp @@ -0,0 +1,439 @@ +//========= Copyright Valve Corporation ============// +#include "strtools_public.h" +#include +#include +#include + +//----------------------------------------------------------------------------- +// 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(codepoint)); + else if (codepoint <= 0x7ff) + { + out.append(1, static_cast(0xc0 | ((codepoint >> 6) & 0x1f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + else if (codepoint <= 0xffff) + { + out.append(1, static_cast(0xe0 | ((codepoint >> 12) & 0x0f))); + out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); + out.append(1, static_cast(0x80 | (codepoint & 0x3f))); + } + else + { + out.append(1, static_cast(0xf0 | ((codepoint >> 18) & 0x07))); + out.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3f))); + out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); + out.append(1, static_cast(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(0xd800 + (codepoint >> 10))); + out.append(1, static_cast(0xdc00 + (codepoint & 0x03ff))); + } + else + out.append(1, static_cast(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 ); + } + } +} + diff --git a/gfx/vr/openvr/src/strtools_public.h b/gfx/vr/openvr/src/strtools_public.h new file mode 100644 index 000000000000..2a60f1280e72 --- /dev/null +++ b/gfx/vr/openvr/src/strtools_public.h @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation ============// +#pragma once + +#include +#include +#include + +/** 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 +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 ); + + diff --git a/gfx/vr/openvr/src/vrpathregistry_public.cpp b/gfx/vr/openvr/src/vrpathregistry_public.cpp new file mode 100644 index 000000000000..cf61c866a026 --- /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 +#include + +#undef GetEnvironmentVariable +#elif defined OSX +#include +#include +#elif defined(LINUX) +#include +#include +#endif + +#include + +#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 *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; +} + diff --git a/gfx/vr/openvr/src/vrpathregistry_public.h b/gfx/vr/openvr/src/vrpathregistry_public.h new file mode 100644 index 000000000000..4838a107cac4 --- /dev/null +++ b/gfx/vr/openvr/src/vrpathregistry_public.h @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation ============// +#pragma once + +#include +#include +#include + +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 *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; +}; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 918725d0dae7..959b3ffc5f93 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5076,8 +5076,6 @@ pref("dom.vr.poseprediction.enabled", true); // 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", ""); diff --git a/tools/rewriting/ThirdPartyPaths.txt b/tools/rewriting/ThirdPartyPaths.txt index 0fe3c6aa3d2d..24b4e43fcc2a 100644 --- a/tools/rewriting/ThirdPartyPaths.txt +++ b/tools/rewriting/ThirdPartyPaths.txt @@ -12,6 +12,7 @@ gfx/harfbuzz/ gfx/ots/ gfx/qcms/ gfx/skia/ +gfx/vr/openvr/ gfx/webrender gfx/webrender_traits gfx/ycbcr/