blob: 5fb1ed4d0b191027d38b3f00eb43fb4a0bd13ae1 [file]
//============ Copyright (c) Valve Corporation, All rights reserved. ============
#include <openvr_driver.h>
#include "driverlog.h"
#include <vector>
using namespace vr;
#if defined(_WIN32)
#define HMD_DLL_EXPORT extern "C" __declspec( dllexport )
#define HMD_DLL_IMPORT extern "C" __declspec( dllimport )
#elif defined(GNUC) || defined(COMPILER_GCC)
#define HMD_DLL_EXPORT extern "C" __attribute__((visibility("default")))
#define HMD_DLL_IMPORT extern "C"
#else
#error "Unsupported Platform."
#endif
inline HmdQuaternion_t HmdQuaternion_Init( double w, double x, double y, double z )
{
HmdQuaternion_t quat;
quat.w = w;
quat.x = x;
quat.y = y;
quat.z = z;
return quat;
}
inline void HmdMatrix_SetIdentity( HmdMatrix34_t *pMatrix )
{
pMatrix->m[0][0] = 1.f;
pMatrix->m[0][1] = 0.f;
pMatrix->m[0][2] = 0.f;
pMatrix->m[0][3] = 0.f;
pMatrix->m[1][0] = 0.f;
pMatrix->m[1][1] = 1.f;
pMatrix->m[1][2] = 0.f;
pMatrix->m[1][3] = 0.f;
pMatrix->m[2][0] = 0.f;
pMatrix->m[2][1] = 0.f;
pMatrix->m[2][2] = 1.f;
pMatrix->m[2][3] = 0.f;
}
// keys for use with the settings API
static const char * const k_pch_Sample_Section = "driver_sample";
static const char * const k_pch_Sample_EnableSampleDriver_Bool = "enable";
static const char * const k_pch_Sample_SerialNumber_String = "serialNumber";
static const char * const k_pch_Sample_ModelNumber_String = "modelNumber";
static const char * const k_pch_Sample_WindowX_Int32 = "windowX";
static const char * const k_pch_Sample_WindowY_Int32 = "windowY";
static const char * const k_pch_Sample_WindowWidth_Int32 = "windowWidth";
static const char * const k_pch_Sample_WindowHeight_Int32 = "windowHeight";
static const char * const k_pch_Sample_RenderWidth_Int32 = "renderWidth";
static const char * const k_pch_Sample_RenderHeight_Int32 = "renderHeight";
static const char * const k_pch_Sample_SecondsFromVsyncToPhotons_Float = "secondsFromVsyncToPhotons";
static const char * const k_pch_Sample_DisplayFrequency_Float = "displayFrequency";
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CClientDriver_Sample : public IClientTrackedDeviceProvider
{
public:
CClientDriver_Sample()
: m_bEnableNullDriver( false )
, m_bInit( false )
{
}
virtual EVRInitError Init( vr::IDriverLog *pDriverLog, vr::IClientDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir ) ;
virtual void Cleanup() ;
virtual bool BIsHmdPresent( const char *pchUserDriverConfigDir ) ;
virtual EVRInitError SetDisplayId( const char *pchDisplayId ) { return VRInitError_None; } // Null doesn't care
virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye ) ;
virtual uint32_t GetMCImage( uint32_t *pImgWidth, uint32_t *pImgHeight, uint32_t *pChannels, void *pDataBuffer, uint32_t unBufferLen ) { return 0; }
private:
vr::IClientDriverHost *m_pClientDriverHost;
bool m_bEnableNullDriver;
bool m_bInit;
};
CClientDriver_Sample g_clientDriverNull;
EVRInitError CClientDriver_Sample::Init( vr::IDriverLog *pDriverLog, vr::IClientDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir )
{
m_pClientDriverHost = pDriverHost;
InitDriverLog( pDriverLog );
if ( !m_bInit )
{
if ( m_pClientDriverHost )
{
IVRSettings *pSettings = m_pClientDriverHost->GetSettings( vr::IVRSettings_Version );
if ( !m_bEnableNullDriver && pSettings )
{
m_bEnableNullDriver = pSettings->GetBool( k_pch_Sample_Section, k_pch_Sample_EnableSampleDriver_Bool, false );
}
}
m_bInit = true;
}
return VRInitError_None;
}
void CClientDriver_Sample::Cleanup()
{
CleanupDriverLog();
}
bool CClientDriver_Sample::BIsHmdPresent( const char *pchUserDriverConfigDir )
{
// optimistically return true. We'll have a chance to say whether there's actually an HMD later.
// This should do something quick like look for a USB VID/PID combination that makes it likely
// there's an HMD attached.
return true;
}
// ------------------------------------------------------------------------------------------
// Purpose: Return a mesh that contains the hidden area for the current HMD
// ------------------------------------------------------------------------------------------
HiddenAreaMesh_t CClientDriver_Sample::GetHiddenAreaMesh( EVREye eEye )
{
// Null doesn't do visible area meshes
vr::HiddenAreaMesh_t mesh;
mesh.pVertexData = NULL;
mesh.unTriangleCount = 0;
return mesh;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSampleDeviceDriver : public vr::ITrackedDeviceServerDriver, public vr::IVRDisplayComponent
{
public:
CSampleDeviceDriver( vr::IServerDriverHost *pDriverHost )
: m_pServerDriverHost( pDriverHost )
, m_unObjectId( vr::k_unTrackedDeviceIndexInvalid )
{
IVRSettings *pSettings = m_pServerDriverHost ? m_pServerDriverHost->GetSettings( vr::IVRSettings_Version ) : NULL;
if ( pSettings )
{
DriverLog( "Using settings values\n" );
m_flIPD = pSettings->GetFloat( k_pch_SteamVR_Section, k_pch_SteamVR_IPD_Float, 0.063f );
char buf[1024];
pSettings->GetString( k_pch_Sample_Section, k_pch_Sample_SerialNumber_String, buf, sizeof(buf), "SAMPLE1234" );
m_sSerialNumber = buf;
pSettings->GetString( k_pch_Sample_Section, k_pch_Sample_ModelNumber_String, buf, sizeof(buf), "ED209" );
m_sSerialNumber = buf;
m_nWindowX = pSettings->GetInt32( k_pch_Sample_Section, k_pch_Sample_WindowX_Int32, 0 );
m_nWindowY = pSettings->GetInt32( k_pch_Sample_Section, k_pch_Sample_WindowY_Int32, 0 );
m_nWindowWidth = pSettings->GetInt32( k_pch_Sample_Section, k_pch_Sample_WindowWidth_Int32, 1920 );
m_nWindowHeight = pSettings->GetInt32( k_pch_Sample_Section, k_pch_Sample_WindowHeight_Int32, 1080 );
m_nRenderWidth = pSettings->GetInt32( k_pch_Sample_Section, k_pch_Sample_RenderWidth_Int32, 1344 );
m_nRenderHeight = pSettings->GetInt32( k_pch_Sample_Section, k_pch_Sample_RenderHeight_Int32, 1512 );
m_flSecondsFromVsyncToPhotons = pSettings->GetFloat( k_pch_Sample_Section, k_pch_Sample_SecondsFromVsyncToPhotons_Float, 0.0 );
m_flDisplayFrequency = pSettings->GetFloat( k_pch_Sample_Section, k_pch_Sample_DisplayFrequency_Float, 0.0 );
}
else
{
DriverLog( "Could not get settings API. Using default values\n" );
m_flIPD = 0.065f;
m_sSerialNumber = "SAMPLE1234";
m_sModelNumber = "ED209";
m_nWindowX = 0;
m_nWindowY = 0;
m_nWindowWidth = 1920;
m_nWindowHeight = 1080;
m_nRenderWidth = 1344;
m_nRenderHeight = 1512;
m_flSecondsFromVsyncToPhotons = 0.0;
m_flDisplayFrequency = 0.0;
}
DriverLog( "driver_null: Serial Number: %s\n", m_sSerialNumber.c_str() );
DriverLog( "driver_null: Model Number: %s\n", m_sModelNumber.c_str() );
DriverLog( "driver_null: Window: %d %d %d %d\n", m_nWindowX, m_nWindowY, m_nWindowWidth, m_nWindowHeight );
DriverLog( "driver_null: Render Target: %d %d\n", m_nRenderWidth, m_nRenderHeight );
DriverLog( "driver_null: Seconds from Vsync to Photons: %f\n", m_flSecondsFromVsyncToPhotons );
DriverLog( "driver_null: Display Frequency: %f\n", m_flDisplayFrequency );
DriverLog( "driver_null: IPD: %f\n", m_flIPD );
}
virtual ~CSampleDeviceDriver()
{
m_pServerDriverHost = NULL;
}
virtual EVRInitError Activate( uint32_t unObjectId )
{
m_unObjectId = unObjectId;
return VRInitError_None;
}
virtual void Deactivate()
{
m_unObjectId = vr::k_unTrackedDeviceIndexInvalid;
}
void *GetComponent( const char *pchComponentNameAndVersion )
{
if ( !_stricmp( pchComponentNameAndVersion, vr::IVRDisplayComponent_Version ) )
{
return (vr::IVRDisplayComponent*)this;
}
// override this to add a component to a driver
return NULL;
}
virtual void PowerOff()
{
}
/** debug request from a client */
virtual void DebugRequest( const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize )
{
if( unResponseBufferSize >= 1 )
pchResponseBuffer[0] = 0;
}
virtual void GetWindowBounds( int32_t *pnX, int32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight )
{
*pnX = m_nWindowX;
*pnY = m_nWindowY;
*pnWidth = m_nWindowWidth;
*pnHeight = m_nWindowHeight;
}
virtual bool IsDisplayOnDesktop()
{
return true;
}
virtual bool IsDisplayRealDisplay()
{
return false;
}
virtual void GetRecommendedRenderTargetSize( uint32_t *pnWidth, uint32_t *pnHeight )
{
*pnWidth = m_nRenderWidth;
*pnHeight = m_nRenderHeight;
}
virtual void GetEyeOutputViewport( EVREye eEye, uint32_t *pnX, uint32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight )
{
*pnY = 0;
*pnWidth = m_nWindowWidth / 2;
*pnHeight = m_nWindowHeight;
if ( eEye == Eye_Left )
{
*pnX = 0;
}
else
{
*pnX = m_nWindowWidth / 2;
}
}
virtual void GetProjectionRaw( EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom )
{
*pfLeft = -1.0;
*pfRight = 1.0;
*pfTop = -1.0;
*pfBottom = 1.0;
}
virtual DistortionCoordinates_t ComputeDistortion( EVREye eEye, float fU, float fV )
{
DistortionCoordinates_t coordinates;
coordinates.rfBlue[0] = fU;
coordinates.rfBlue[1] = fV;
coordinates.rfGreen[0] = fU;
coordinates.rfGreen[1] = fV;
coordinates.rfRed[0] = fU;
coordinates.rfRed[1] = fV;
return coordinates;
}
virtual DriverPose_t GetPose()
{
DriverPose_t pose = { 0 };
pose.poseIsValid = true;
pose.result = TrackingResult_Running_OK;
pose.deviceIsConnected = true;
pose.qWorldFromDriverRotation = HmdQuaternion_Init( 1, 0, 0, 0 );
pose.qDriverFromHeadRotation = HmdQuaternion_Init( 1, 0, 0, 0 );
return pose;
}
virtual bool GetBoolTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *pError )
{
*pError = vr::TrackedProp_Success;
switch ( prop )
{
case vr::Prop_IsOnDesktop_Bool:
// avoid "not fullscreen" warnings from vrmonitor
return false;
}
*pError = vr::TrackedProp_ValueNotProvidedByDevice;
return false;
}
virtual float GetFloatTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *pError )
{
vr::ETrackedPropertyError error = vr::TrackedProp_ValueNotProvidedByDevice;
float fRetVal = 0;
switch ( prop )
{
case vr::Prop_UserIpdMeters_Float:
fRetVal = m_flIPD;
error = TrackedProp_Success;
break;
case vr::Prop_UserHeadToEyeDepthMeters_Float:
error = vr::TrackedProp_Success;
fRetVal = 0.f;
break;
case vr::Prop_DisplayFrequency_Float:
error = vr::TrackedProp_Success;
fRetVal = m_flDisplayFrequency;
break;
case vr::Prop_SecondsFromVsyncToPhotons_Float:
error = vr::TrackedProp_Success;
fRetVal = m_flSecondsFromVsyncToPhotons;
break;
}
if ( pError )
{
*pError = error;
}
return fRetVal;
}
int32_t GetInt32TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *pError )
{
int32_t nRetVal = 0;
vr::ETrackedPropertyError error = vr::TrackedProp_UnknownProperty;
switch ( prop )
{
case vr::Prop_DeviceClass_Int32:
nRetVal = vr::TrackedDeviceClass_HMD;
error = vr::TrackedProp_Success;
break;
}
if ( pError )
{
*pError = error;
}
return nRetVal;
}
virtual uint64_t GetUint64TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *pError )
{
*pError = vr::TrackedProp_Success;
switch ( prop )
{
case vr::Prop_CurrentUniverseId_Uint64:
// return a constant that's not 0 (invalid) or 1 (reserved for Oculus)
return 2;
}
*pError = vr::TrackedProp_ValueNotProvidedByDevice;
return 0;
}
vr::HmdMatrix34_t GetMatrix34TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *pError )
{
*pError = vr::TrackedProp_ValueNotProvidedByDevice;
HmdMatrix34_t matIdentity;
HmdMatrix_SetIdentity( &matIdentity);
return matIdentity;
}
virtual uint32_t GetStringTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, char *pchValue, uint32_t unBufferSize, vr::ETrackedPropertyError *pError )
{
std::string sValue= GetStringTrackedDeviceProperty( prop, pError );
if ( *pError == vr::TrackedProp_Success )
{
if ( sValue.size( ) + 1 > unBufferSize )
{
*pError = vr::TrackedProp_BufferTooSmall;
}
else
{
strcpy_s( pchValue, unBufferSize, sValue.c_str() );
}
return (uint32_t)sValue.size( ) + 1;
}
return 0;
}
std::string GetStringTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *pError )
{
*pError = vr::TrackedProp_ValueNotProvidedByDevice;
std::string sRetVal;
switch ( prop )
{
case vr::Prop_ModelNumber_String:
sRetVal = m_sModelNumber;
*pError = vr::TrackedProp_Success;
break;
case vr::Prop_SerialNumber_String:
sRetVal = m_sSerialNumber;
*pError = vr::TrackedProp_Success;
break;
}
return sRetVal;
}
void RunFrame()
{
// In a real driver, this should happen from some pose tracking thread.
// The RunFrame interval is unspecified and can be very irregular if some other
// driver blocks it for some periodic task.
if ( m_unObjectId != vr::k_unTrackedDeviceIndexInvalid )
{
m_pServerDriverHost->TrackedDevicePoseUpdated( m_unObjectId, GetPose() );
}
}
private:
vr::IServerDriverHost *m_pServerDriverHost;
uint32_t m_unObjectId;
std::string m_sSerialNumber;
std::string m_sModelNumber;
int32_t m_nWindowX;
int32_t m_nWindowY;
int32_t m_nWindowWidth;
int32_t m_nWindowHeight;
int32_t m_nRenderWidth;
int32_t m_nRenderHeight;
float m_flSecondsFromVsyncToPhotons;
float m_flDisplayFrequency;
float m_flIPD;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CServerDriver_Sample: public IServerTrackedDeviceProvider
{
public:
CServerDriver_Sample()
: m_pNullHmdLatest( NULL )
, m_bEnableNullDriver( false )
{
}
virtual EVRInitError Init( IDriverLog *pDriverLog, vr::IServerDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir ) ;
virtual void Cleanup() ;
virtual const char * const *GetInterfaceVersions() { return vr::k_InterfaceVersions; }
virtual uint32_t GetTrackedDeviceCount();
virtual ITrackedDeviceServerDriver *GetTrackedDeviceDriver( uint32_t unWhich ) ;
virtual ITrackedDeviceServerDriver* FindTrackedDeviceDriver( const char *pchId ) ;
virtual void RunFrame() ;
virtual bool ShouldBlockStandbyMode() { return false; }
virtual void EnterStandby() {}
virtual void LeaveStandby() {}
private:
CSampleDeviceDriver *m_pNullHmdLatest;
bool m_bEnableNullDriver;
};
CServerDriver_Sample g_serverDriverNull;
EVRInitError CServerDriver_Sample::Init( IDriverLog *pDriverLog, vr::IServerDriverHost *pDriverHost, const char *pchUserDriverConfigDir, const char *pchDriverInstallDir )
{
InitDriverLog( pDriverLog );
IVRSettings *pSettings = pDriverHost ? pDriverHost->GetSettings( vr::IVRSettings_Version ) : NULL;
m_bEnableNullDriver = pSettings && pSettings->GetBool( k_pch_Sample_Section, k_pch_Sample_EnableSampleDriver_Bool, false );
if ( !m_bEnableNullDriver )
return VRInitError_Init_HmdNotFound;
m_pNullHmdLatest = new CSampleDeviceDriver( pDriverHost);
return VRInitError_None;
}
void CServerDriver_Sample::Cleanup()
{
CleanupDriverLog();
delete m_pNullHmdLatest;
m_pNullHmdLatest = NULL;
}
uint32_t CServerDriver_Sample::GetTrackedDeviceCount()
{
if ( m_bEnableNullDriver )
return 1;
return 0;
}
ITrackedDeviceServerDriver *CServerDriver_Sample::GetTrackedDeviceDriver( uint32_t unWhich )
{
return m_pNullHmdLatest;
}
ITrackedDeviceServerDriver* CServerDriver_Sample::FindTrackedDeviceDriver( const char *pchId )
{
return m_pNullHmdLatest;
}
void CServerDriver_Sample::RunFrame()
{
if ( m_pNullHmdLatest )
{
m_pNullHmdLatest->RunFrame();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
HMD_DLL_EXPORT void *HmdDriverFactory( const char *pInterfaceName, int *pReturnCode )
{
if( 0 == strcmp( IServerTrackedDeviceProvider_Version, pInterfaceName ) )
{
return &g_serverDriverNull;
}
if( 0 == strcmp( IClientTrackedDeviceProvider_Version, pInterfaceName ) )
{
return &g_clientDriverNull;
}
if( pReturnCode )
*pReturnCode = VRInitError_Init_InterfaceNotFound;
return NULL;
}