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