openvr_api_public.cpp (8690B)
1 //========= Copyright Valve Corporation ============// 2 #define VR_API_EXPORT 1 3 #include "openvr.h" 4 #include "ivrclientcore.h" 5 #include "pathtools_public.h" 6 #include "sharedlibtools_public.h" 7 #include "envvartools_public.h" 8 #include "hmderrors_public.h" 9 #include "strtools_public.h" 10 #include "vrpathregistry_public.h" 11 #include <mutex> 12 13 using vr::EVRInitError; 14 using vr::IVRSystem; 15 using vr::IVRClientCore; 16 using vr::VRInitError_None; 17 18 // figure out how to import from the VR API dll 19 #if defined(_WIN32) 20 21 #if !defined(OPENVR_BUILD_STATIC) 22 #define VR_EXPORT_INTERFACE extern "C" __declspec( dllexport ) 23 #else 24 #define VR_EXPORT_INTERFACE extern "C" 25 #endif 26 27 #elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(__APPLE__) 28 29 #define VR_EXPORT_INTERFACE extern "C" __attribute__((visibility("default"))) 30 31 #else 32 #error "Unsupported Platform." 33 #endif 34 35 namespace vr 36 { 37 38 static void *g_pVRModule = NULL; 39 static IVRClientCore *g_pHmdSystem = NULL; 40 static std::recursive_mutex g_mutexSystem; 41 42 43 typedef void* (*VRClientCoreFactoryFn)(const char *pInterfaceName, int *pReturnCode); 44 45 static uint32_t g_nVRToken = 0; 46 47 uint32_t VR_GetInitToken() 48 { 49 return g_nVRToken; 50 } 51 52 EVRInitError VR_LoadHmdSystemInternal(); 53 void CleanupInternalInterfaces(); 54 55 56 uint32_t VR_InitInternal2( EVRInitError *peError, vr::EVRApplicationType eApplicationType, const char *pStartupInfo ) 57 { 58 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 59 60 EVRInitError err = VR_LoadHmdSystemInternal(); 61 if ( err == vr::VRInitError_None ) 62 { 63 err = g_pHmdSystem->Init( eApplicationType, pStartupInfo ); 64 } 65 66 if ( peError ) 67 *peError = err; 68 69 if ( err != VRInitError_None ) 70 { 71 SharedLib_Unload( g_pVRModule ); 72 g_pHmdSystem = NULL; 73 g_pVRModule = NULL; 74 75 return 0; 76 } 77 78 return ++g_nVRToken; 79 } 80 81 VR_INTERFACE uint32_t VR_CALLTYPE VR_InitInternal( EVRInitError *peError, EVRApplicationType eApplicationType ); 82 83 uint32_t VR_InitInternal( EVRInitError *peError, vr::EVRApplicationType eApplicationType ) 84 { 85 return VR_InitInternal2( peError, eApplicationType, nullptr ); 86 } 87 88 void VR_ShutdownInternal() 89 { 90 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 91 92 if ( g_pHmdSystem ) 93 { 94 g_pHmdSystem->Cleanup(); 95 g_pHmdSystem = NULL; 96 } 97 if ( g_pVRModule ) 98 { 99 SharedLib_Unload( g_pVRModule ); 100 g_pVRModule = NULL; 101 } 102 103 #if !defined( VR_API_PUBLIC ) 104 CleanupInternalInterfaces(); 105 #endif 106 107 ++g_nVRToken; 108 } 109 110 EVRInitError VR_LoadHmdSystemInternal() 111 { 112 std::string sRuntimePath, sConfigPath, sLogPath; 113 114 bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL ); 115 if( !bReadPathRegistry ) 116 { 117 return vr::VRInitError_Init_PathRegistryNotFound; 118 } 119 120 // figure out where we're going to look for vrclient.dll 121 // see if the specified path actually exists. 122 if( !Path_IsDirectory( sRuntimePath ) ) 123 { 124 return vr::VRInitError_Init_InstallationNotFound; 125 } 126 127 // Because we don't have a way to select debug vs. release yet we'll just 128 // use debug if it's there 129 #if defined( LINUX64 ) || defined( LINUXARM64 ) 130 std::string sTestPath = Path_Join( sRuntimePath, "bin", PLATSUBDIR ); 131 #else 132 std::string sTestPath = Path_Join( sRuntimePath, "bin" ); 133 #endif 134 if( !Path_IsDirectory( sTestPath ) ) 135 { 136 return vr::VRInitError_Init_InstallationCorrupt; 137 } 138 139 #if defined( WIN64 ) 140 std::string sDLLPath = Path_Join( sTestPath, "vrclient_x64" DYNAMIC_LIB_EXT ); 141 #else 142 std::string sDLLPath = Path_Join( sTestPath, "vrclient" DYNAMIC_LIB_EXT ); 143 #endif 144 145 // only look in the override 146 void *pMod = SharedLib_Load( sDLLPath.c_str() ); 147 // nothing more to do if we can't load the DLL 148 if( !pMod ) 149 { 150 return vr::VRInitError_Init_VRClientDLLNotFound; 151 } 152 153 VRClientCoreFactoryFn fnFactory = ( VRClientCoreFactoryFn )( SharedLib_GetFunction( pMod, "VRClientCoreFactory" ) ); 154 if( !fnFactory ) 155 { 156 SharedLib_Unload( pMod ); 157 return vr::VRInitError_Init_FactoryNotFound; 158 } 159 160 int nReturnCode = 0; 161 g_pHmdSystem = static_cast< IVRClientCore * > ( fnFactory( vr::IVRClientCore_Version, &nReturnCode ) ); 162 if( !g_pHmdSystem ) 163 { 164 SharedLib_Unload( pMod ); 165 return vr::VRInitError_Init_InterfaceNotFound; 166 } 167 168 g_pVRModule = pMod; 169 return VRInitError_None; 170 } 171 172 173 void *VR_GetGenericInterface(const char *pchInterfaceVersion, EVRInitError *peError) 174 { 175 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 176 177 if (!g_pHmdSystem) 178 { 179 if (peError) 180 *peError = vr::VRInitError_Init_NotInitialized; 181 return NULL; 182 } 183 184 return g_pHmdSystem->GetGenericInterface(pchInterfaceVersion, peError); 185 } 186 187 bool VR_IsInterfaceVersionValid(const char *pchInterfaceVersion) 188 { 189 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 190 191 if (!g_pHmdSystem) 192 { 193 return false; 194 } 195 196 return g_pHmdSystem->IsInterfaceVersionValid(pchInterfaceVersion) == VRInitError_None; 197 } 198 199 bool VR_IsHmdPresent() 200 { 201 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 202 203 if( g_pHmdSystem ) 204 { 205 // if we're already initialized, just call through 206 return g_pHmdSystem->BIsHmdPresent(); 207 } 208 else 209 { 210 // otherwise we need to do a bit more work 211 EVRInitError err = VR_LoadHmdSystemInternal(); 212 if( err != VRInitError_None ) 213 return false; 214 215 bool bHasHmd = g_pHmdSystem->BIsHmdPresent(); 216 217 g_pHmdSystem = NULL; 218 SharedLib_Unload( g_pVRModule ); 219 g_pVRModule = NULL; 220 221 return bHasHmd; 222 } 223 } 224 225 /** Returns true if the OpenVR runtime is installed. */ 226 bool VR_IsRuntimeInstalled() 227 { 228 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 229 230 if( g_pHmdSystem ) 231 { 232 // if we're already initialized, OpenVR is obviously installed 233 return true; 234 } 235 else 236 { 237 // otherwise we need to do a bit more work 238 std::string sRuntimePath, sConfigPath, sLogPath; 239 240 bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL ); 241 if( !bReadPathRegistry ) 242 { 243 return false; 244 } 245 246 // figure out where we're going to look for vrclient.dll 247 // see if the specified path actually exists. 248 if( !Path_IsDirectory( sRuntimePath ) ) 249 { 250 return false; 251 } 252 253 // the installation may be corrupt in some way, but it certainly looks installed 254 return true; 255 } 256 } 257 258 259 // ------------------------------------------------------------------------------- 260 // Purpose: This is the old Runtime Path interface that is no longer exported in the 261 // latest header. We still want to export it from the DLL, though, so updating 262 // to a new DLL doesn't break old compiled code. This version was not thread 263 // safe and could change the buffer pointer to by a previous result on a 264 // subsequent call 265 // ------------------------------------------------------------------------------- 266 VR_EXPORT_INTERFACE const char *VR_CALLTYPE VR_RuntimePath(); 267 268 /** Returns where OpenVR runtime is installed. */ 269 const char *VR_RuntimePath() 270 { 271 static char rchBuffer[1024]; 272 uint32_t unRequiredSize; 273 if ( VR_GetRuntimePath( rchBuffer, sizeof( rchBuffer ), &unRequiredSize ) && unRequiredSize < sizeof( rchBuffer ) ) 274 { 275 return rchBuffer; 276 } 277 else 278 { 279 return nullptr; 280 } 281 } 282 283 284 /** Returns where OpenVR runtime is installed. */ 285 bool VR_GetRuntimePath( char *pchPathBuffer, uint32_t unBufferSize, uint32_t *punRequiredBufferSize ) 286 { 287 // otherwise we need to do a bit more work 288 std::string sRuntimePath; 289 290 *punRequiredBufferSize = 0; 291 292 bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, nullptr, nullptr, nullptr, nullptr ); 293 if ( !bReadPathRegistry ) 294 { 295 return false; 296 } 297 298 // figure out where we're going to look for vrclient.dll 299 // see if the specified path actually exists. 300 if ( !Path_IsDirectory( sRuntimePath ) ) 301 { 302 return false; 303 } 304 305 *punRequiredBufferSize = (uint32_t)sRuntimePath.size() + 1; 306 if ( sRuntimePath.size() >= unBufferSize ) 307 { 308 *pchPathBuffer = '\0'; 309 } 310 else 311 { 312 strcpy_safe( pchPathBuffer, unBufferSize, sRuntimePath.c_str() ); 313 } 314 315 return true; 316 } 317 318 319 /** Returns the symbol version of an HMD error. */ 320 const char *VR_GetVRInitErrorAsSymbol( EVRInitError error ) 321 { 322 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 323 324 if( g_pHmdSystem ) 325 return g_pHmdSystem->GetIDForVRInitError( error ); 326 else 327 return GetIDForVRInitError( error ); 328 } 329 330 331 /** Returns the english string version of an HMD error. */ 332 const char *VR_GetVRInitErrorAsEnglishDescription( EVRInitError error ) 333 { 334 std::lock_guard<std::recursive_mutex> lock( g_mutexSystem ); 335 336 if ( g_pHmdSystem ) 337 return g_pHmdSystem->GetEnglishStringForHmdError( error ); 338 else 339 return GetEnglishStringForHmdError( error ); 340 } 341 342 343 VR_INTERFACE const char *VR_CALLTYPE VR_GetStringForHmdError( vr::EVRInitError error ); 344 345 /** Returns the english string version of an HMD error. */ 346 const char *VR_GetStringForHmdError( EVRInitError error ) 347 { 348 return VR_GetVRInitErrorAsEnglishDescription( error ); 349 } 350 351 }