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
VR_GetInitToken()47 uint32_t VR_GetInitToken()
48 {
49 return g_nVRToken;
50 }
51
52 EVRInitError VR_LoadHmdSystemInternal();
53 void CleanupInternalInterfaces();
54
55
VR_InitInternal2(EVRInitError * peError,vr::EVRApplicationType eApplicationType,const char * pStartupInfo)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
VR_InitInternal(EVRInitError * peError,vr::EVRApplicationType eApplicationType)83 uint32_t VR_InitInternal( EVRInitError *peError, vr::EVRApplicationType eApplicationType )
84 {
85 return VR_InitInternal2( peError, eApplicationType, nullptr );
86 }
87
VR_ShutdownInternal()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
VR_LoadHmdSystemInternal()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
VR_GetGenericInterface(const char * pchInterfaceVersion,EVRInitError * peError)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
VR_IsInterfaceVersionValid(const char * pchInterfaceVersion)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
VR_IsHmdPresent()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. */
VR_IsRuntimeInstalled()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. */
VR_RuntimePath()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. */
VR_GetRuntimePath(char * pchPathBuffer,uint32_t unBufferSize,uint32_t * punRequiredBufferSize)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. */
VR_GetVRInitErrorAsSymbol(EVRInitError 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. */
VR_GetVRInitErrorAsEnglishDescription(EVRInitError 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. */
VR_GetStringForHmdError(EVRInitError error)346 const char *VR_GetStringForHmdError( EVRInitError error )
347 {
348 return VR_GetVRInitErrorAsEnglishDescription( error );
349 }
350
351 }
352
353