2015-10-21 16:29:00 -07:00
|
|
|
#include "OVR_CAPI.h"
|
2015-10-21 16:29:00 -07:00
|
|
|
#include "OVR_Version.h"
|
2017-04-13 02:41:41 +02:00
|
|
|
#include "REV_Math.h"
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-09-24 13:22:26 +02:00
|
|
|
#include "Assert.h"
|
2017-04-13 03:53:35 +02:00
|
|
|
#include "Session.h"
|
2017-04-13 03:48:18 +02:00
|
|
|
#include "CompositorBase.h"
|
|
|
|
|
#include "SessionDetails.h"
|
|
|
|
|
#include "InputManager.h"
|
|
|
|
|
#include "Settings.h"
|
2017-08-18 14:58:29 +02:00
|
|
|
#include "SettingsManager.h"
|
2017-04-13 03:48:18 +02:00
|
|
|
|
2017-09-03 18:53:12 +02:00
|
|
|
#include <dxgi1_2.h>
|
2017-04-13 03:48:18 +02:00
|
|
|
#include <openvr.h>
|
2017-12-07 03:57:00 +01:00
|
|
|
#include <Windows.h>
|
2017-04-13 03:48:18 +02:00
|
|
|
#include <MinHook.h>
|
2017-10-17 21:35:53 +02:00
|
|
|
#include <list>
|
|
|
|
|
#include <algorithm>
|
2017-11-24 15:44:12 +01:00
|
|
|
#include <assert.h>
|
2017-04-13 03:48:18 +02:00
|
|
|
|
|
|
|
|
#define REV_DEFAULT_TIMEOUT 10000
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
vr::EVRInitError g_InitError = vr::VRInitError_Init_NotInitialized;
|
2016-09-12 22:34:33 +02:00
|
|
|
uint32_t g_MinorVersion = OVR_MINOR_VERSION;
|
2017-10-17 21:35:53 +02:00
|
|
|
std::list<ovrHmdStruct> g_Sessions;
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-09-01 15:27:53 +02:00
|
|
|
ovrResult rev_InitErrorToOvrError(vr::EVRInitError error)
|
|
|
|
|
{
|
|
|
|
|
switch (error)
|
|
|
|
|
{
|
|
|
|
|
case vr::VRInitError_None: return ovrSuccess;
|
|
|
|
|
case vr::VRInitError_Unknown: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_InstallationNotFound: return ovrError_LibLoad;
|
|
|
|
|
case vr::VRInitError_Init_InstallationCorrupt: return ovrError_LibLoad;
|
|
|
|
|
case vr::VRInitError_Init_VRClientDLLNotFound: return ovrError_LibLoad;
|
|
|
|
|
case vr::VRInitError_Init_FileNotFound: return ovrError_LibLoad;
|
|
|
|
|
case vr::VRInitError_Init_FactoryNotFound: return ovrError_ServiceConnection;
|
|
|
|
|
case vr::VRInitError_Init_InterfaceNotFound: return ovrError_ServiceConnection;
|
|
|
|
|
case vr::VRInitError_Init_InvalidInterface: return ovrError_MismatchedAdapters;
|
|
|
|
|
case vr::VRInitError_Init_UserConfigDirectoryInvalid: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_HmdNotFound: return ovrError_NoHmd;
|
|
|
|
|
case vr::VRInitError_Init_NotInitialized: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_PathRegistryNotFound: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_NoConfigPath: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_NoLogPath: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_PathRegistryNotWritable: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_AppInfoInitFailed: return ovrError_ServerStart;
|
2017-12-07 03:57:00 +01:00
|
|
|
//case vr::VRInitError_Init_Retry: return ovrError_Reinitialization; // Internal
|
2017-09-01 15:27:53 +02:00
|
|
|
case vr::VRInitError_Init_InitCanceledByUser: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_AnotherAppLaunching: return ovrError_ServerStart;
|
|
|
|
|
case vr::VRInitError_Init_SettingsInitFailed: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_ShuttingDown: return ovrError_ServerStart;
|
|
|
|
|
case vr::VRInitError_Init_TooManyObjects: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_NoServerForBackgroundApp: return ovrError_ServerStart;
|
|
|
|
|
case vr::VRInitError_Init_NotSupportedWithCompositor: return ovrError_Initialize;
|
|
|
|
|
case vr::VRInitError_Init_NotAvailableToUtilityApps: return ovrError_Initialize;
|
|
|
|
|
default: return ovrError_RuntimeException;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_Initialize(const ovrInitParams* params)
|
|
|
|
|
{
|
2017-01-10 18:30:40 +01:00
|
|
|
MicroProfileOnThreadCreate("Main");
|
|
|
|
|
MicroProfileSetForceEnable(true);
|
|
|
|
|
MicroProfileSetEnableAllGroups(true);
|
|
|
|
|
MicroProfileSetForceMetaCounters(true);
|
|
|
|
|
MicroProfileWebServerStart();
|
2016-08-20 02:10:39 +02:00
|
|
|
|
2016-10-09 21:14:27 +02:00
|
|
|
g_MinorVersion = params->RequestedMinorVersion;
|
2016-09-12 22:34:33 +02:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
MH_QueueDisableHook(LoadLibraryW);
|
|
|
|
|
MH_QueueDisableHook(OpenEventW);
|
|
|
|
|
MH_ApplyQueued();
|
|
|
|
|
|
2016-07-01 14:22:37 +00:00
|
|
|
vr::VR_Init(&g_InitError, vr::VRApplication_Scene);
|
2015-10-21 16:29:00 -07:00
|
|
|
|
|
|
|
|
MH_QueueEnableHook(LoadLibraryW);
|
|
|
|
|
MH_QueueEnableHook(OpenEventW);
|
|
|
|
|
MH_ApplyQueued();
|
|
|
|
|
|
2016-10-09 21:14:27 +02:00
|
|
|
uint32_t timeout = params->ConnectionTimeoutMS;
|
|
|
|
|
if (timeout == 0)
|
|
|
|
|
timeout = REV_DEFAULT_TIMEOUT;
|
2016-09-12 22:57:33 +02:00
|
|
|
|
|
|
|
|
// Wait until the compositor is ready, if SteamVR still needs to start the nominal waiting time
|
|
|
|
|
// is 1.5 seconds. Thus we don't even attempt to wait if the requested timeout is only 100ms.
|
|
|
|
|
while (timeout > 100 && vr::VRCompositor() == nullptr)
|
|
|
|
|
{
|
|
|
|
|
Sleep(100);
|
|
|
|
|
timeout -= 100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vr::VRCompositor() == nullptr)
|
|
|
|
|
return ovrError_Timeout;
|
|
|
|
|
|
2016-07-01 14:22:37 +00:00
|
|
|
return rev_InitErrorToOvrError(g_InitError);
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(void) ovr_Shutdown()
|
|
|
|
|
{
|
2017-10-17 21:35:53 +02:00
|
|
|
g_Sessions.clear();
|
2015-10-21 16:29:00 -07:00
|
|
|
vr::VR_Shutdown();
|
2017-01-10 18:30:40 +01:00
|
|
|
MicroProfileShutdown();
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(void) ovr_GetLastErrorInfo(ovrErrorInfo* errorInfo)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetLastErrorInfo);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!errorInfo)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
const char* error = VR_GetVRInitErrorAsEnglishDescription(g_InitError);
|
|
|
|
|
strncpy_s(errorInfo->ErrorString, error, sizeof(ovrErrorInfo::ErrorString));
|
2016-07-01 14:22:37 +00:00
|
|
|
errorInfo->Result = rev_InitErrorToOvrError(g_InitError);
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(const char*) ovr_GetVersionString()
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetVersionString);
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
return OVR_VERSION_STRING;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(int) ovr_TraceMessage(int level, const char* message) { return 0; /* Debugging feature */ }
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-06-26 22:09:40 +00:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_IdentifyClient(const char* identity) { return ovrSuccess; /* Debugging feature */ }
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrHmdDesc) ovr_GetHmdDesc(ovrSession session)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetHmdDesc);
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
if (!session)
|
2015-10-21 16:29:00 -07:00
|
|
|
{
|
2017-08-23 22:54:28 +02:00
|
|
|
ovrHmdDesc desc = {};
|
|
|
|
|
desc.Type = vr::VR_IsHmdPresent() ? ovrHmd_CV1 : ovrHmd_None;
|
|
|
|
|
return desc;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return *session->Details->HmdDesc;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetTrackerCount(ovrSession session)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTrackerCount);
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
2016-08-20 02:10:39 +02:00
|
|
|
|
2017-12-02 18:37:38 -08:00
|
|
|
if (session->Details->UseHack(SessionDetails::HACK_SPOOF_SENSORS))
|
|
|
|
|
return 2;
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return (unsigned int)session->Details->TrackerCount;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrTrackerDesc) ovr_GetTrackerDesc(ovrSession session, unsigned int trackerDescIndex)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTrackerDesc);
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
if (!session)
|
|
|
|
|
return ovrTrackerDesc();
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
ovrTrackerDesc* pDesc = session->Details->TrackerDesc[trackerDescIndex];
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
if (!pDesc)
|
|
|
|
|
return ovrTrackerDesc();
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return *pDesc;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_Create(ovrSession* pSession, ovrGraphicsLuid* pLuid)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_Create);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!pSession)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
2016-07-01 21:34:40 +00:00
|
|
|
*pSession = nullptr;
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
// Initialize the opaque pointer with our own OpenVR-specific struct
|
2017-10-17 21:35:53 +02:00
|
|
|
g_Sessions.emplace_back();
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-04-15 13:57:22 +02:00
|
|
|
// Get the LUID for the OpenVR adapter
|
2017-07-14 14:08:49 +02:00
|
|
|
uint64_t adapter;
|
|
|
|
|
vr::VRSystem()->GetOutputDevice(&adapter, vr::TextureType_DirectX);
|
2017-09-03 18:53:12 +02:00
|
|
|
if (adapter)
|
|
|
|
|
{
|
|
|
|
|
// Copy the LUID into the structure
|
|
|
|
|
static_assert(sizeof(adapter) == sizeof(ovrGraphicsLuid),
|
|
|
|
|
"The adapter LUID needs to fit in ovrGraphicsLuid");
|
|
|
|
|
if (pLuid)
|
|
|
|
|
memcpy(pLuid, &adapter, sizeof(ovrGraphicsLuid));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Fall-back to the default adapter
|
|
|
|
|
IDXGIFactory1* pFactory = nullptr;
|
|
|
|
|
if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory)))
|
|
|
|
|
return ovrError_RuntimeException;
|
|
|
|
|
|
|
|
|
|
IDXGIAdapter1* pAdapter = nullptr;
|
|
|
|
|
if (FAILED(pFactory->EnumAdapters1(0, &pAdapter)))
|
|
|
|
|
return ovrError_RuntimeException;
|
|
|
|
|
|
|
|
|
|
DXGI_ADAPTER_DESC1 desc;
|
|
|
|
|
if (FAILED(pAdapter->GetDesc1(&desc)))
|
|
|
|
|
return ovrError_RuntimeException;
|
|
|
|
|
|
|
|
|
|
// Copy the LUID into the structure
|
|
|
|
|
static_assert(sizeof(desc.AdapterLuid) == sizeof(ovrGraphicsLuid),
|
|
|
|
|
"The adapter LUID needs to fit in ovrGraphicsLuid");
|
|
|
|
|
if (pLuid)
|
|
|
|
|
memcpy(pLuid, &desc.AdapterLuid, sizeof(ovrGraphicsLuid));
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-10-17 21:35:53 +02:00
|
|
|
*pSession = &g_Sessions.back();
|
2015-10-21 16:29:00 -07:00
|
|
|
return ovrSuccess;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(void) ovr_Destroy(ovrSession session)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_Destroy);
|
|
|
|
|
|
2017-10-17 21:35:53 +02:00
|
|
|
// Delete the session from the list of sessions
|
|
|
|
|
g_Sessions.erase(std::find_if(g_Sessions.begin(), g_Sessions.end(), [session](ovrHmdStruct const& o) { return &o == session; }));
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetSessionStatus(ovrSession session, ovrSessionStatus* sessionStatus)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetSessionStatus);
|
|
|
|
|
|
2016-12-22 22:12:48 +01:00
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!sessionStatus)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
// Detect if the application has focus, but only return false the first time the status is requested.
|
2017-12-02 14:11:40 -08:00
|
|
|
// If this is true from the first call then Airmech will assume the Health-and-Safety warning
|
2017-08-23 22:54:28 +02:00
|
|
|
// is still being displayed.
|
|
|
|
|
static bool firstCall = true;
|
|
|
|
|
sessionStatus->IsVisible = vr::VRCompositor()->CanRenderScene() && !firstCall;
|
|
|
|
|
firstCall = false;
|
|
|
|
|
|
2017-08-24 21:09:20 +02:00
|
|
|
SessionStatusBits status = session->SessionStatus;
|
2016-05-14 16:41:27 +00:00
|
|
|
|
2016-10-26 17:39:24 +02:00
|
|
|
// Don't use the activity level while debugging, so I don't have to put on the HMD
|
2017-08-23 22:54:28 +02:00
|
|
|
sessionStatus->HmdPresent = status.HmdPresent;
|
|
|
|
|
sessionStatus->HmdMounted = status.HmdMounted;
|
2016-07-03 13:35:15 +00:00
|
|
|
|
|
|
|
|
// TODO: Detect if the display is lost, can this ever happen with OpenVR?
|
2017-08-24 21:09:20 +02:00
|
|
|
sessionStatus->DisplayLost = status.DisplayLost;
|
|
|
|
|
sessionStatus->ShouldQuit = status.ShouldQuit;
|
|
|
|
|
sessionStatus->ShouldRecenter = status.ShouldRecenter;
|
2017-12-02 14:11:40 -08:00
|
|
|
sessionStatus->HasInputFocus = status.HasInputFocus;
|
|
|
|
|
sessionStatus->OverlayPresent = status.OverlayPresent;
|
2015-10-21 16:29:00 -07:00
|
|
|
|
|
|
|
|
return ovrSuccess;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetTrackingOriginType(ovrSession session, ovrTrackingOrigin origin)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_SetTrackingOriginType);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
// Both enums match exactly, so we can just cast them
|
2017-08-20 15:38:07 +02:00
|
|
|
session->TrackingOrigin = (vr::ETrackingUniverseOrigin)origin;
|
2015-10-21 16:29:00 -07:00
|
|
|
return ovrSuccess;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrTrackingOrigin) ovr_GetTrackingOriginType(ovrSession session)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTrackingOriginType);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!session)
|
|
|
|
|
return ovrTrackingOrigin_EyeLevel;
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
// Both enums match exactly, so we can just cast them
|
2017-08-20 15:38:07 +02:00
|
|
|
return (ovrTrackingOrigin)session->TrackingOrigin;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_RecenterTrackingOrigin(ovrSession session)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_RecenterTrackingOrigin);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
2016-07-01 14:22:37 +00:00
|
|
|
vr::VRSystem()->ResetSeatedZeroPose();
|
2015-10-21 16:29:00 -07:00
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-04-11 19:28:43 +02:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SpecifyTrackingOrigin(ovrSession session, ovrPosef originPose)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Implement through ApplyTransform()
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(void) ovr_ClearShouldRecenterFlag(ovrSession session) { /* No such flag, do nothing */ }
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrTrackingState) ovr_GetTrackingState(ovrSession session, double absTime, ovrBool latencyMarker)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTrackingState);
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
ovrTrackingState state = { 0 };
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!session)
|
|
|
|
|
return state;
|
|
|
|
|
|
2017-04-12 20:08:23 +02:00
|
|
|
session->Input->GetTrackingState(session, &state, absTime);
|
2015-10-21 16:29:00 -07:00
|
|
|
return state;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-04-12 16:23:11 +02:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetDevicePoses(ovrSession session, ovrTrackedDeviceType* deviceTypes, int deviceCount, double absTime, ovrPoseStatef* outDevicePoses)
|
|
|
|
|
{
|
2017-04-12 20:08:23 +02:00
|
|
|
REV_TRACE(ovr_GetDevicePoses);
|
2017-04-12 16:23:11 +02:00
|
|
|
|
2017-04-12 20:08:23 +02:00
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
2017-04-12 16:23:11 +02:00
|
|
|
|
2017-04-12 20:08:23 +02:00
|
|
|
return session->Input->GetDevicePoses(deviceTypes, deviceCount, absTime, outDevicePoses);
|
2017-04-12 16:23:11 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-28 18:26:25 +02:00
|
|
|
struct ovrSensorData_;
|
|
|
|
|
typedef struct ovrSensorData_ ovrSensorData;
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrTrackingState) ovr_GetTrackingStateWithSensorData(ovrSession session, double absTime, ovrBool latencyMarker, ovrSensorData* sensorData)
|
|
|
|
|
{
|
|
|
|
|
REV_TRACE(ovr_GetTrackingStateWithSensorData);
|
|
|
|
|
|
|
|
|
|
// This is a private API, ignore the raw sensor data request and hope for the best.
|
2017-11-24 15:44:12 +01:00
|
|
|
assert(sensorData == nullptr);
|
2016-10-28 18:26:25 +02:00
|
|
|
|
|
|
|
|
return ovr_GetTrackingState(session, absTime, latencyMarker);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrTrackerPose) ovr_GetTrackerPose(ovrSession session, unsigned int trackerPoseIndex)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTrackerPose);
|
|
|
|
|
|
2016-09-06 22:31:39 +02:00
|
|
|
ovrTrackerPose tracker = { 0 };
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!session)
|
2016-09-06 22:31:39 +02:00
|
|
|
return tracker;
|
2016-04-27 15:44:47 +00:00
|
|
|
|
2017-12-02 18:37:38 -08:00
|
|
|
if (session->Details->UseHack(SessionDetails::HACK_SPOOF_SENSORS))
|
|
|
|
|
{
|
|
|
|
|
tracker.LeveledPose = OVR::Posef::Identity();
|
|
|
|
|
tracker.Pose = OVR::Posef::Identity();
|
|
|
|
|
tracker.TrackerFlags = ovrTracker_Connected;
|
|
|
|
|
return tracker;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
// Get the index for this tracker.
|
2016-04-23 15:56:28 +00:00
|
|
|
vr::TrackedDeviceIndex_t trackers[vr::k_unMaxTrackedDeviceCount] = { vr::k_unTrackedDeviceIndexInvalid };
|
2016-07-01 14:22:37 +00:00
|
|
|
vr::VRSystem()->GetSortedTrackedDeviceIndicesOfClass(vr::TrackedDeviceClass_TrackingReference, trackers, vr::k_unMaxTrackedDeviceCount);
|
2015-10-21 16:29:00 -07:00
|
|
|
vr::TrackedDeviceIndex_t index = trackers[trackerPoseIndex];
|
|
|
|
|
|
2016-09-06 22:31:39 +02:00
|
|
|
// Get the device poses.
|
|
|
|
|
vr::TrackedDevicePose_t pose;
|
|
|
|
|
vr::VRCompositor()->GetLastPoseForTrackedDeviceIndex(index, &pose, nullptr);
|
|
|
|
|
|
|
|
|
|
// TODO: Should the tracker pose always be in the standing universe?
|
|
|
|
|
//vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, 0.0, poses, vr::k_unMaxTrackedDeviceCount);
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
// Set the flags
|
2016-09-06 22:31:39 +02:00
|
|
|
tracker.TrackerFlags = 0;
|
2016-04-23 15:56:28 +00:00
|
|
|
if (index != vr::k_unTrackedDeviceIndexInvalid)
|
|
|
|
|
{
|
2016-09-06 22:31:39 +02:00
|
|
|
if (vr::VRSystem()->IsTrackedDeviceConnected(index))
|
|
|
|
|
tracker.TrackerFlags |= ovrTracker_Connected;
|
|
|
|
|
if (pose.bPoseIsValid)
|
|
|
|
|
tracker.TrackerFlags |= ovrTracker_PoseTracked;
|
2016-04-23 15:56:28 +00:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
|
|
|
|
// Convert the pose
|
2017-04-13 02:41:41 +02:00
|
|
|
REV::Matrix4f matrix;
|
2016-09-06 22:31:39 +02:00
|
|
|
if (index != vr::k_unTrackedDeviceIndexInvalid && pose.bPoseIsValid)
|
2017-04-13 02:41:41 +02:00
|
|
|
matrix = REV::Matrix4f(pose.mDeviceToAbsoluteTracking);
|
2016-05-14 20:53:25 +00:00
|
|
|
|
|
|
|
|
// We need to mirror the orientation along either the X or Y axis
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR::Quatf quat = OVR::Quatf(matrix);
|
2016-05-14 20:53:25 +00:00
|
|
|
OVR::Quatf mirror = OVR::Quatf(1.0f, 0.0f, 0.0f, 0.0f);
|
2016-09-06 22:31:39 +02:00
|
|
|
tracker.Pose.Orientation = quat * mirror;
|
|
|
|
|
tracker.Pose.Position = matrix.GetTranslation();
|
2015-10-21 16:29:00 -07:00
|
|
|
|
|
|
|
|
// Level the pose
|
|
|
|
|
float yaw;
|
|
|
|
|
quat.GetYawPitchRoll(&yaw, nullptr, nullptr);
|
2016-09-06 22:31:39 +02:00
|
|
|
tracker.LeveledPose.Orientation = OVR::Quatf(OVR::Axis_Y, yaw);
|
|
|
|
|
tracker.LeveledPose.Position = matrix.GetTranslation();
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-09-06 22:31:39 +02:00
|
|
|
return tracker;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-09-12 22:34:33 +02:00
|
|
|
// Pre-1.7 input state
|
|
|
|
|
typedef struct ovrInputState1_
|
|
|
|
|
{
|
|
|
|
|
double TimeInSeconds;
|
|
|
|
|
unsigned int Buttons;
|
|
|
|
|
unsigned int Touches;
|
|
|
|
|
float IndexTrigger[ovrHand_Count];
|
|
|
|
|
float HandTrigger[ovrHand_Count];
|
|
|
|
|
ovrVector2f Thumbstick[ovrHand_Count];
|
|
|
|
|
ovrControllerType ControllerType;
|
|
|
|
|
} ovrInputState1;
|
|
|
|
|
|
2017-04-11 19:28:43 +02:00
|
|
|
// Pre-1.11 input state
|
|
|
|
|
typedef struct ovrInputState2_
|
|
|
|
|
{
|
|
|
|
|
double TimeInSeconds;
|
|
|
|
|
unsigned int Buttons;
|
|
|
|
|
unsigned int Touches;
|
|
|
|
|
float IndexTrigger[ovrHand_Count];
|
|
|
|
|
float HandTrigger[ovrHand_Count];
|
|
|
|
|
ovrVector2f Thumbstick[ovrHand_Count];
|
|
|
|
|
ovrControllerType ControllerType;
|
|
|
|
|
float IndexTriggerNoDeadzone[ovrHand_Count];
|
|
|
|
|
float HandTriggerNoDeadzone[ovrHand_Count];
|
|
|
|
|
ovrVector2f ThumbstickNoDeadzone[ovrHand_Count];
|
|
|
|
|
} ovrInputState2;
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetInputState(ovrSession session, ovrControllerType controllerType, ovrInputState* inputState)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetInputState);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
|
|
|
|
if (!inputState)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
2017-04-12 18:47:51 +02:00
|
|
|
ovrInputState state = { 0 };
|
|
|
|
|
ovrResult result = session->Input->GetInputState(session, controllerType, &state);
|
2016-09-12 22:34:33 +02:00
|
|
|
|
|
|
|
|
// We need to make sure we don't write outside of the bounds of the struct
|
|
|
|
|
// when the client expects a pre-1.7 version of LibOVR.
|
2017-04-16 02:32:50 +02:00
|
|
|
if (g_MinorVersion < 7)
|
2016-09-12 22:34:33 +02:00
|
|
|
memcpy(inputState, &state, sizeof(ovrInputState1));
|
2017-04-16 02:32:50 +02:00
|
|
|
else if (g_MinorVersion < 11)
|
|
|
|
|
memcpy(inputState, &state, sizeof(ovrInputState2));
|
2016-09-12 22:34:33 +02:00
|
|
|
else
|
|
|
|
|
memcpy(inputState, &state, sizeof(ovrInputState));
|
|
|
|
|
|
|
|
|
|
return result;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetConnectedControllerTypes(ovrSession session)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetConnectedControllerTypes);
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return session->Input->ConnectedControllers;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-09-05 12:55:51 +02:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrTouchHapticsDesc) ovr_GetTouchHapticsDesc(ovrSession session, ovrControllerType controllerType)
|
|
|
|
|
{
|
|
|
|
|
REV_TRACE(ovr_GetTouchHapticsDesc);
|
2016-10-31 16:40:09 +01:00
|
|
|
|
|
|
|
|
return session->Input->GetTouchHapticsDesc(controllerType);
|
2016-09-05 12:55:51 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetControllerVibration(ovrSession session, ovrControllerType controllerType, float frequency, float amplitude)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_SetControllerVibration);
|
|
|
|
|
|
2016-09-05 23:49:14 +02:00
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return session->Input->SetControllerVibration(session, controllerType, frequency, amplitude);
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2016-09-05 12:55:51 +02:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitControllerVibration(ovrSession session, ovrControllerType controllerType, const ovrHapticsBuffer* buffer)
|
|
|
|
|
{
|
|
|
|
|
REV_TRACE(ovr_SubmitControllerVibration);
|
2016-10-31 16:40:09 +01:00
|
|
|
|
|
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return session->Input->SubmitControllerVibration(session, controllerType, buffer);
|
2016-09-05 12:55:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetControllerVibrationState(ovrSession session, ovrControllerType controllerType, ovrHapticsPlaybackState* outState)
|
|
|
|
|
{
|
|
|
|
|
REV_TRACE(ovr_GetControllerVibrationState);
|
2016-10-31 16:40:09 +01:00
|
|
|
|
|
|
|
|
if (!session)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return session->Input->GetControllerVibrationState(session, controllerType, outState);
|
2016-09-05 12:55:51 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_TestBoundary(ovrSession session, ovrTrackedDeviceType deviceBitmask,
|
|
|
|
|
ovrBoundaryType boundaryType, ovrBoundaryTestResult* outTestResult)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_TestBoundary);
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
outTestResult->ClosestDistance = INFINITY;
|
|
|
|
|
|
|
|
|
|
vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount];
|
|
|
|
|
vr::VRCompositor()->GetLastPoses(poses, vr::k_unMaxTrackedDeviceCount, nullptr, 0);
|
|
|
|
|
|
|
|
|
|
if (vr::VRChaperone()->GetCalibrationState() != vr::ChaperoneCalibrationState_OK)
|
|
|
|
|
return ovrSuccess_BoundaryInvalid;
|
|
|
|
|
|
|
|
|
|
if (deviceBitmask & ovrTrackedDevice_HMD)
|
|
|
|
|
{
|
|
|
|
|
ovrBoundaryTestResult result = { 0 };
|
2017-04-13 02:41:41 +02:00
|
|
|
REV::Matrix4f matrix = (REV::Matrix4f)poses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking;
|
2016-09-24 17:31:52 +02:00
|
|
|
ovrVector3f point = matrix.GetTranslation();
|
|
|
|
|
|
|
|
|
|
ovrResult err = ovr_TestBoundaryPoint(session, &point, boundaryType, &result);
|
|
|
|
|
if (OVR_SUCCESS(err) && result.ClosestDistance < outTestResult->ClosestDistance)
|
|
|
|
|
*outTestResult = result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vr::TrackedDeviceIndex_t hands[] = { vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand),
|
|
|
|
|
vr::VRSystem()->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand) };
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < ovrHand_Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (deviceBitmask & (ovrTrackedDevice_LTouch << i))
|
|
|
|
|
{
|
|
|
|
|
ovrBoundaryTestResult result = { 0 };
|
|
|
|
|
if (hands[i] != vr::k_unTrackedDeviceIndexInvalid)
|
|
|
|
|
{
|
2017-04-13 02:41:41 +02:00
|
|
|
REV::Matrix4f matrix = (REV::Matrix4f)poses[hands[i]].mDeviceToAbsoluteTracking;
|
2016-09-24 17:31:52 +02:00
|
|
|
ovrVector3f point = matrix.GetTranslation();
|
|
|
|
|
|
|
|
|
|
ovrResult err = ovr_TestBoundaryPoint(session, &point, boundaryType, &result);
|
|
|
|
|
if (OVR_SUCCESS(err) && result.ClosestDistance < outTestResult->ClosestDistance)
|
|
|
|
|
*outTestResult = result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_TestBoundaryPoint(ovrSession session, const ovrVector3f* point,
|
|
|
|
|
ovrBoundaryType singleBoundaryType, ovrBoundaryTestResult* outTestResult)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_TestBoundaryPoint);
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
ovrBoundaryTestResult result = { 0 };
|
|
|
|
|
|
|
|
|
|
if (vr::VRChaperone()->GetCalibrationState() != vr::ChaperoneCalibrationState_OK)
|
|
|
|
|
return ovrSuccess_BoundaryInvalid;
|
|
|
|
|
|
|
|
|
|
result.IsTriggering = vr::VRChaperone()->AreBoundsVisible();
|
|
|
|
|
|
2016-11-07 01:45:05 +01:00
|
|
|
OVR::Vector2f playArea;
|
|
|
|
|
if (!vr::VRChaperone()->GetPlayAreaSize(&playArea.x, &playArea.y))
|
2016-09-24 17:31:52 +02:00
|
|
|
return ovrSuccess_BoundaryInvalid;
|
|
|
|
|
|
2016-11-07 01:45:05 +01:00
|
|
|
// Clamp the point to the AABB
|
|
|
|
|
OVR::Vector2f p(point->x, point->z);
|
|
|
|
|
OVR::Vector2f halfExtents(playArea.x / 2.0f, playArea.y / 2.0f);
|
|
|
|
|
OVR::Vector2f clamped = OVR::Vector2f::Min(OVR::Vector2f::Max(p, -halfExtents), halfExtents);
|
2016-09-24 17:31:52 +02:00
|
|
|
|
2016-11-07 01:45:05 +01:00
|
|
|
// If the point is inside the AABB, we need to do some extra work
|
|
|
|
|
if (clamped.Compare(p))
|
|
|
|
|
{
|
|
|
|
|
if (std::abs(p.x) > std::abs(p.y))
|
|
|
|
|
clamped.x = halfExtents.x * (p.x / std::abs(p.x));
|
|
|
|
|
else
|
|
|
|
|
clamped.y = halfExtents.y * (p.y / std::abs(p.y));
|
2016-09-24 17:31:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We don't have a ceiling, use the height from the original point
|
2016-11-07 01:45:05 +01:00
|
|
|
result.ClosestPoint.x = clamped.x;
|
2016-09-24 17:31:52 +02:00
|
|
|
result.ClosestPoint.y = point->y;
|
2016-11-07 01:45:05 +01:00
|
|
|
result.ClosestPoint.z = clamped.y;
|
|
|
|
|
|
|
|
|
|
// Get the normal, closest distance is the length of this normal
|
|
|
|
|
OVR::Vector2f normal = p - clamped;
|
|
|
|
|
result.ClosestDistance = normal.Length();
|
|
|
|
|
|
|
|
|
|
// Normalize the normal
|
|
|
|
|
normal.Normalize();
|
|
|
|
|
result.ClosestPointNormal.x = normal.x;
|
|
|
|
|
result.ClosestPointNormal.y = 0.0f;
|
|
|
|
|
result.ClosestPointNormal.z = normal.y;
|
2016-09-24 17:31:52 +02:00
|
|
|
|
|
|
|
|
*outTestResult = result;
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetBoundaryLookAndFeel(ovrSession session, const ovrBoundaryLookAndFeel* lookAndFeel)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_SetBoundaryLookAndFeel);
|
|
|
|
|
|
2017-04-16 18:19:22 +02:00
|
|
|
vr::HmdColor_t color = (vr::HmdColor_t&)lookAndFeel->Color;
|
2016-09-24 17:31:52 +02:00
|
|
|
vr::VRChaperone()->SetSceneColor(color);
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_ResetBoundaryLookAndFeel(ovrSession session)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_ResetBoundaryLookAndFeel);
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
vr::HmdColor_t color = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
|
|
|
vr::VRChaperone()->SetSceneColor(color);
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetBoundaryGeometry(ovrSession session, ovrBoundaryType boundaryType, ovrVector3f* outFloorPoints, int* outFloorPointsCount)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_GetBoundaryGeometry);
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
vr::HmdQuad_t playRect;
|
|
|
|
|
bool valid = vr::VRChaperone()->GetPlayAreaRect(&playRect);
|
2016-11-05 22:25:35 +01:00
|
|
|
if (outFloorPoints)
|
2016-11-06 23:46:26 +01:00
|
|
|
memcpy(outFloorPoints, playRect.vCorners, 4 * sizeof(ovrVector3f));
|
2016-11-05 22:25:35 +01:00
|
|
|
if (outFloorPointsCount)
|
|
|
|
|
*outFloorPointsCount = valid ? 4 : 0;
|
2016-09-24 17:31:52 +02:00
|
|
|
return valid ? ovrSuccess : ovrSuccess_BoundaryInvalid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetBoundaryDimensions(ovrSession session, ovrBoundaryType boundaryType, ovrVector3f* outDimensions)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_GetBoundaryDimensions);
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
outDimensions->y = 0.0f; // TODO: Find some good default height
|
|
|
|
|
bool valid = vr::VRChaperone()->GetPlayAreaSize(&outDimensions->x, &outDimensions->z);
|
|
|
|
|
return valid ? ovrSuccess : ovrSuccess_BoundaryInvalid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetBoundaryVisible(ovrSession session, ovrBool* outIsVisible)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_GetBoundaryVisible);
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
*outIsVisible = vr::VRChaperone()->AreBoundsVisible();
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_RequestBoundaryVisible(ovrSession session, ovrBool visible)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_RequestBoundaryVisible);
|
|
|
|
|
|
2016-09-25 15:05:20 +02:00
|
|
|
vr::VRChaperone()->ForceBoundsVisible(!!visible);
|
2016-09-24 17:31:52 +02:00
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainLength(ovrSession session, ovrTextureSwapChain chain, int* out_Length)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTextureSwapChainLength);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!chain)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
2017-04-15 17:51:35 +02:00
|
|
|
MICROPROFILE_META_CPU("Identifier", chain->Identifier);
|
2016-07-01 14:22:37 +00:00
|
|
|
*out_Length = chain->Length;
|
2015-10-21 16:29:00 -07:00
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainCurrentIndex(ovrSession session, ovrTextureSwapChain chain, int* out_Index)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTextureSwapChainCurrentIndex);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!chain)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
2017-04-15 17:51:35 +02:00
|
|
|
MICROPROFILE_META_CPU("Identifier", chain->Identifier);
|
|
|
|
|
MICROPROFILE_META_CPU("Index", chain->CurrentIndex);
|
2016-07-02 11:22:50 +00:00
|
|
|
*out_Index = chain->CurrentIndex;
|
2015-10-21 16:29:00 -07:00
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainDesc(ovrSession session, ovrTextureSwapChain chain, ovrTextureSwapChainDesc* out_Desc)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTextureSwapChainDesc);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!chain)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
2017-04-15 17:51:35 +02:00
|
|
|
MICROPROFILE_META_CPU("Identifier", chain->Identifier);
|
2016-07-06 12:49:46 +00:00
|
|
|
*out_Desc = chain->Desc;
|
2015-10-21 16:29:00 -07:00
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_CommitTextureSwapChain(ovrSession session, ovrTextureSwapChain chain)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_CommitTextureSwapChain);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!chain)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
2017-04-15 17:51:35 +02:00
|
|
|
MICROPROFILE_META_CPU("Identifier", chain->Identifier);
|
2017-07-05 16:16:08 +02:00
|
|
|
MICROPROFILE_META_CPU("CurrentIndex", chain->CurrentIndex);
|
|
|
|
|
MICROPROFILE_META_CPU("SubmitIndex", chain->SubmitIndex);
|
|
|
|
|
|
|
|
|
|
if (chain->Full())
|
|
|
|
|
return ovrError_TextureSwapChainFull;
|
|
|
|
|
|
|
|
|
|
chain->Commit();
|
2017-09-03 18:50:52 +02:00
|
|
|
|
|
|
|
|
if (chain->Overlay != vr::k_ulOverlayHandleInvalid)
|
|
|
|
|
{
|
|
|
|
|
vr::VRTextureWithPose_t texture = chain->Textures[chain->SubmitIndex]->ToVRTexture();
|
|
|
|
|
vr::VROverlay()->SetOverlayTexture(chain->Overlay, &texture);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(void) ovr_DestroyTextureSwapChain(ovrSession session, ovrTextureSwapChain chain)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_DestroyTextureSwapChain);
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
if (!chain)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-04-15 17:51:35 +02:00
|
|
|
MICROPROFILE_META_CPU("Identifier", chain->Identifier);
|
2016-07-01 14:22:37 +00:00
|
|
|
vr::VROverlay()->DestroyOverlay(chain->Overlay);
|
2015-10-21 16:29:00 -07:00
|
|
|
delete chain;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(void) ovr_DestroyMirrorTexture(ovrSession session, ovrMirrorTexture mirrorTexture)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_DestroyMirrorTexture);
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
if (!mirrorTexture)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-09-23 22:35:19 +02:00
|
|
|
session->Compositor->SetMirrorTexture(nullptr);
|
2015-10-21 16:29:00 -07:00
|
|
|
delete mirrorTexture;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrSizei) ovr_GetFovTextureSize(ovrSession session, ovrEyeType eye, ovrFovPort fov, float pixelsPerDisplayPixel)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetFovTextureSize);
|
|
|
|
|
|
2017-08-28 18:16:39 +02:00
|
|
|
// Get the descriptor for this eye
|
|
|
|
|
ovrEyeRenderDesc* desc = session->Details->RenderDesc[eye];
|
|
|
|
|
ovrSizei size = desc->DistortedViewport.Size;
|
2016-09-25 22:37:17 +02:00
|
|
|
|
2016-04-13 00:28:59 +00:00
|
|
|
// Grow the recommended size to account for the overlapping fov
|
2017-08-28 18:16:39 +02:00
|
|
|
// TODO: Add a setting to ignore pixelsPerDisplayPixel
|
|
|
|
|
vr::VRTextureBounds_t bounds = CompositorBase::FovPortToTextureBounds(desc->Fov, fov);
|
2016-12-06 16:46:56 +01:00
|
|
|
size.w = int((size.w * pixelsPerDisplayPixel) / (bounds.uMax - bounds.uMin));
|
|
|
|
|
size.h = int((size.h * pixelsPerDisplayPixel) / (bounds.vMax - bounds.vMin));
|
2016-04-13 00:28:59 +00:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
return size;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-21 20:46:30 +02:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc) ovr_GetRenderDesc2(ovrSession session, ovrEyeType eyeType, ovrFovPort fov)
|
2015-10-21 16:29:00 -07:00
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetRenderDesc);
|
|
|
|
|
|
2017-08-28 18:16:39 +02:00
|
|
|
// Make a copy so we can adjust a few parameters
|
|
|
|
|
ovrEyeRenderDesc desc = *session->Details->RenderDesc[eyeType];
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-28 18:16:39 +02:00
|
|
|
// Adjust the descriptor for the supplied field-of-view
|
|
|
|
|
desc.Fov = fov;
|
2015-10-21 16:29:00 -07:00
|
|
|
float WidthTan = fov.LeftTan + fov.RightTan;
|
|
|
|
|
float HeightTan = fov.UpTan + fov.DownTan;
|
2017-08-28 18:16:39 +02:00
|
|
|
desc.PixelsPerTanAngleAtCenter = OVR::Vector2f(desc.DistortedViewport.Size.w / WidthTan, desc.DistortedViewport.Size.h / HeightTan);
|
2015-10-21 16:29:00 -07:00
|
|
|
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-21 20:46:30 +02:00
|
|
|
typedef struct OVR_ALIGNAS(4) ovrEyeRenderDesc1_ {
|
|
|
|
|
ovrEyeType Eye;
|
|
|
|
|
ovrFovPort Fov;
|
|
|
|
|
ovrRecti DistortedViewport;
|
|
|
|
|
ovrVector2f PixelsPerTanAngleAtCenter;
|
|
|
|
|
ovrVector3f HmdToEyeOffset;
|
|
|
|
|
} ovrEyeRenderDesc1;
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc1) ovr_GetRenderDesc(ovrSession session, ovrEyeType eyeType, ovrFovPort fov)
|
|
|
|
|
{
|
|
|
|
|
ovrEyeRenderDesc1 legacy = {};
|
|
|
|
|
ovrEyeRenderDesc desc = ovr_GetRenderDesc2(session, eyeType, fov);
|
|
|
|
|
memcpy(&legacy, &desc, sizeof(ovrEyeRenderDesc1));
|
|
|
|
|
legacy.HmdToEyeOffset = desc.HmdToEyePose.Position;
|
|
|
|
|
return legacy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_WaitToBeginFrame(ovrSession session, long long frameIndex)
|
|
|
|
|
{
|
2017-09-01 15:27:53 +02:00
|
|
|
REV_TRACE(ovr_WaitToBeginFrame);
|
|
|
|
|
MICROPROFILE_META_CPU("Wait Frame", (int)frameIndex);
|
|
|
|
|
|
|
|
|
|
if (!session || !session->Compositor)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
|
|
|
|
return session->Compositor->WaitToBeginFrame(session, frameIndex);
|
2017-08-21 20:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_BeginFrame(ovrSession session, long long frameIndex)
|
|
|
|
|
{
|
2017-09-01 15:27:53 +02:00
|
|
|
REV_TRACE(ovr_BeginFrame);
|
|
|
|
|
MICROPROFILE_META_CPU("Begin Frame", (int)frameIndex);
|
|
|
|
|
|
|
|
|
|
if (!session || !session->Compositor)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
|
|
|
|
return session->Compositor->BeginFrame(session, frameIndex);
|
2017-08-21 20:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_EndFrame(ovrSession session, long long frameIndex, const ovrViewScaleDesc* viewScaleDesc,
|
2015-10-21 16:29:00 -07:00
|
|
|
ovrLayerHeader const * const * layerPtrList, unsigned int layerCount)
|
|
|
|
|
{
|
2017-09-01 15:27:53 +02:00
|
|
|
REV_TRACE(ovr_EndFrame);
|
|
|
|
|
MICROPROFILE_META_CPU("End Frame", (int)frameIndex);
|
2017-08-21 20:46:30 +02:00
|
|
|
|
2017-09-01 15:27:53 +02:00
|
|
|
if (!session || !session->Compositor)
|
|
|
|
|
return ovrError_InvalidSession;
|
2017-08-21 20:46:30 +02:00
|
|
|
|
2017-09-01 15:27:53 +02:00
|
|
|
// Use our own intermediate compositor to convert the frame to OpenVR.
|
|
|
|
|
return session->Compositor->EndFrame(session, layerPtrList, layerCount);
|
2017-08-21 20:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame2(ovrSession session, long long frameIndex, const ovrViewScaleDesc* viewScaleDesc,
|
|
|
|
|
ovrLayerHeader const * const * layerPtrList, unsigned int layerCount)
|
|
|
|
|
{
|
|
|
|
|
REV_TRACE(ovr_SubmitFrame);
|
2017-09-01 14:24:17 +02:00
|
|
|
MICROPROFILE_META_CPU("Submit Frame", (int)frameIndex);
|
|
|
|
|
|
|
|
|
|
if (!session || !session->Compositor)
|
|
|
|
|
return ovrError_InvalidSession;
|
|
|
|
|
|
2017-08-25 16:29:38 +02:00
|
|
|
if (frameIndex == 0)
|
|
|
|
|
frameIndex = session->FrameIndex;
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-09-01 15:27:53 +02:00
|
|
|
// Use our own intermediate compositor to convert the frame to OpenVR.
|
|
|
|
|
ovrResult result = session->Compositor->EndFrame(session, layerPtrList, layerCount);
|
2017-01-18 01:40:14 +01:00
|
|
|
|
2017-08-25 16:29:38 +02:00
|
|
|
// Begin the next frame
|
2017-03-30 14:21:21 +02:00
|
|
|
if (!session->Details->UseHack(SessionDetails::HACK_WAIT_IN_TRACKING_STATE))
|
2017-09-01 15:27:53 +02:00
|
|
|
session->Compositor->WaitToBeginFrame(session, frameIndex + 1);
|
|
|
|
|
session->Compositor->BeginFrame(session, frameIndex + 1);
|
2017-06-24 13:09:51 +02:00
|
|
|
|
2017-08-25 16:29:38 +02:00
|
|
|
return result;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-21 20:46:30 +02:00
|
|
|
typedef struct OVR_ALIGNAS(4) ovrViewScaleDesc1_ {
|
|
|
|
|
ovrVector3f HmdToEyeOffset[ovrEye_Count]; ///< Translation of each eye.
|
|
|
|
|
float HmdSpaceToWorldScaleInMeters; ///< Ratio of viewer units to meter units.
|
|
|
|
|
} ovrViewScaleDesc1;
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame(ovrSession session, long long frameIndex, const ovrViewScaleDesc1* viewScaleDesc,
|
|
|
|
|
ovrLayerHeader const * const * layerPtrList, unsigned int layerCount)
|
|
|
|
|
{
|
2017-09-01 15:27:53 +02:00
|
|
|
// TODO: We don't ever use viewScaleDesc so no need to do any conversion.
|
2017-08-25 14:00:26 +02:00
|
|
|
return ovr_SubmitFrame2(session, frameIndex, nullptr, layerPtrList, layerCount);
|
2017-08-21 20:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-17 03:29:02 +02:00
|
|
|
typedef struct OVR_ALIGNAS(4) ovrPerfStatsPerCompositorFrame1_
|
|
|
|
|
{
|
|
|
|
|
int HmdVsyncIndex;
|
|
|
|
|
int AppFrameIndex;
|
|
|
|
|
int AppDroppedFrameCount;
|
|
|
|
|
float AppMotionToPhotonLatency;
|
|
|
|
|
float AppQueueAheadTime;
|
|
|
|
|
float AppCpuElapsedTime;
|
|
|
|
|
float AppGpuElapsedTime;
|
|
|
|
|
int CompositorFrameIndex;
|
|
|
|
|
int CompositorDroppedFrameCount;
|
|
|
|
|
float CompositorLatency;
|
|
|
|
|
float CompositorCpuElapsedTime;
|
|
|
|
|
float CompositorGpuElapsedTime;
|
|
|
|
|
float CompositorCpuStartToGpuEndElapsedTime;
|
|
|
|
|
float CompositorGpuEndToVsyncElapsedTime;
|
|
|
|
|
} ovrPerfStatsPerCompositorFrame1;
|
|
|
|
|
|
|
|
|
|
typedef struct OVR_ALIGNAS(4) ovrPerfStats1_
|
|
|
|
|
{
|
|
|
|
|
ovrPerfStatsPerCompositorFrame1 FrameStats[ovrMaxProvidedFrameStats];
|
|
|
|
|
int FrameStatsCount;
|
|
|
|
|
ovrBool AnyFrameStatsDropped;
|
|
|
|
|
float AdaptiveGpuPerformanceScale;
|
|
|
|
|
} ovrPerfStats1;
|
|
|
|
|
|
2016-09-24 17:31:52 +02:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetPerfStats(ovrSession session, ovrPerfStats* outStats)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_GetPerfStats);
|
|
|
|
|
|
2017-04-17 03:29:02 +02:00
|
|
|
ovrPerfStatsPerCompositorFrame FrameStats[ovrMaxProvidedFrameStats];
|
2016-09-25 15:05:20 +02:00
|
|
|
|
|
|
|
|
// TODO: Implement performance scale heuristics
|
2017-04-17 03:29:02 +02:00
|
|
|
float AdaptiveGpuPerformanceScale = 1.0f;
|
|
|
|
|
bool AnyFrameStatsDropped = (session->FrameIndex - session->StatsIndex) > ovrMaxProvidedFrameStats;
|
|
|
|
|
int FrameStatsCount = AnyFrameStatsDropped ? ovrMaxProvidedFrameStats : int(session->FrameIndex - session->StatsIndex);
|
2016-09-25 15:05:20 +02:00
|
|
|
session->StatsIndex = session->FrameIndex;
|
|
|
|
|
|
2017-10-25 22:15:46 +02:00
|
|
|
vr::Compositor_FrameTiming TimingStats[ovrMaxProvidedFrameStats];
|
|
|
|
|
TimingStats[0].m_nSize = sizeof(vr::Compositor_FrameTiming);
|
|
|
|
|
vr::VRCompositor()->GetFrameTimings(TimingStats, FrameStatsCount);
|
|
|
|
|
|
|
|
|
|
vr::Compositor_CumulativeStats TotalStats;
|
|
|
|
|
vr::VRCompositor()->GetCumulativeStats(&TotalStats, sizeof(vr::Compositor_CumulativeStats));
|
|
|
|
|
|
|
|
|
|
// Subtract the base stats so we get the cumulative stats since the last call to ovr_ResetPerfStats
|
|
|
|
|
TotalStats.m_nNumFramePresents -= session->BaseStats.m_nNumFramePresents;
|
|
|
|
|
TotalStats.m_nNumDroppedFrames -= session->BaseStats.m_nNumDroppedFrames;
|
|
|
|
|
TotalStats.m_nNumReprojectedFrames -= session->BaseStats.m_nNumReprojectedFrames;
|
|
|
|
|
TotalStats.m_nNumFramePresentsOnStartup -= session->BaseStats.m_nNumFramePresentsOnStartup;
|
|
|
|
|
TotalStats.m_nNumDroppedFramesOnStartup -= session->BaseStats.m_nNumDroppedFramesOnStartup;
|
|
|
|
|
TotalStats.m_nNumReprojectedFramesOnStartup -= session->BaseStats.m_nNumReprojectedFramesOnStartup;
|
|
|
|
|
TotalStats.m_nNumLoading -= session->BaseStats.m_nNumLoading;
|
|
|
|
|
TotalStats.m_nNumFramePresentsLoading -= session->BaseStats.m_nNumFramePresentsLoading;
|
|
|
|
|
TotalStats.m_nNumDroppedFramesLoading -= session->BaseStats.m_nNumDroppedFramesLoading;
|
|
|
|
|
TotalStats.m_nNumReprojectedFramesLoading -= session->BaseStats.m_nNumReprojectedFramesLoading;
|
|
|
|
|
TotalStats.m_nNumTimedOut -= session->BaseStats.m_nNumTimedOut;
|
|
|
|
|
TotalStats.m_nNumFramePresentsTimedOut -= session->BaseStats.m_nNumFramePresentsTimedOut;
|
|
|
|
|
TotalStats.m_nNumDroppedFramesTimedOut -= session->BaseStats.m_nNumDroppedFramesTimedOut;
|
|
|
|
|
TotalStats.m_nNumReprojectedFramesTimedOut -= session->BaseStats.m_nNumReprojectedFramesTimedOut;
|
|
|
|
|
|
2016-09-25 15:05:20 +02:00
|
|
|
float fVsyncToPhotons = vr::VRSystem()->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);
|
|
|
|
|
float fDisplayFrequency = vr::VRSystem()->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
|
|
|
|
|
float fFrameDuration = 1.0f / fDisplayFrequency;
|
2017-04-17 03:29:02 +02:00
|
|
|
for (int i = 0; i < FrameStatsCount; i++)
|
2016-09-25 15:05:20 +02:00
|
|
|
{
|
2017-04-17 03:29:02 +02:00
|
|
|
ovrPerfStatsPerCompositorFrame& stats = FrameStats[i];
|
|
|
|
|
|
2017-10-25 22:15:46 +02:00
|
|
|
stats.HmdVsyncIndex = TotalStats.m_nNumFramePresents;
|
|
|
|
|
stats.AppFrameIndex = (int)session->FrameIndex;
|
|
|
|
|
stats.AppDroppedFrameCount = TotalStats.m_nNumDroppedFrames;
|
2016-09-25 15:05:20 +02:00
|
|
|
// TODO: Improve latency handling with sensor timestamps and latency markers
|
2017-04-17 03:29:02 +02:00
|
|
|
stats.AppMotionToPhotonLatency = fFrameDuration + fVsyncToPhotons;
|
2017-10-25 22:15:46 +02:00
|
|
|
stats.AppQueueAheadTime = -TimingStats[i].m_flNewPosesReadyMs / 1000.0f;
|
|
|
|
|
stats.AppCpuElapsedTime = TimingStats[i].m_flClientFrameIntervalMs / 1000.0f;
|
|
|
|
|
stats.AppGpuElapsedTime = TimingStats[i].m_flPreSubmitGpuMs / 1000.0f;
|
|
|
|
|
|
|
|
|
|
stats.CompositorFrameIndex = TimingStats[i].m_nFrameIndex;
|
|
|
|
|
stats.CompositorDroppedFrameCount = (TotalStats.m_nNumDroppedFrames + TotalStats.m_nNumDroppedFramesLoading);
|
2017-04-17 03:29:02 +02:00
|
|
|
stats.CompositorLatency = fVsyncToPhotons; // OpenVR doesn't have timewarp
|
2017-10-25 22:15:46 +02:00
|
|
|
stats.CompositorCpuElapsedTime = TimingStats[i].m_flCompositorRenderCpuMs / 1000.0f;
|
|
|
|
|
stats.CompositorGpuElapsedTime = TimingStats[i].m_flCompositorRenderGpuMs / 1000.0f;
|
|
|
|
|
stats.CompositorCpuStartToGpuEndElapsedTime = (TimingStats[i].m_flCompositorUpdateEndMs - TimingStats[i].m_flCompositorRenderStartMs) / 1000.0f;
|
|
|
|
|
stats.CompositorGpuEndToVsyncElapsedTime = TimingStats[i].m_flCompositorIdleCpuMs / 1000.0f;
|
2017-04-17 03:29:02 +02:00
|
|
|
|
|
|
|
|
// TODO: Asynchronous Spacewap is not supported in OpenVR
|
|
|
|
|
stats.AswIsActive = ovrFalse;
|
|
|
|
|
stats.AswActivatedToggleCount = 0;
|
|
|
|
|
stats.AswPresentedFrameCount = 0;
|
|
|
|
|
stats.AswFailedFrameCount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to make sure we don't write outside of the bounds of the struct in older version of the runtime
|
|
|
|
|
if (g_MinorVersion < 11)
|
|
|
|
|
{
|
|
|
|
|
ovrPerfStats1* out = (ovrPerfStats1*)outStats;
|
|
|
|
|
for (int i = 0; i < FrameStatsCount; i++)
|
|
|
|
|
memcpy(out->FrameStats + i, FrameStats + i, sizeof(ovrPerfStatsPerCompositorFrame1));
|
|
|
|
|
out->AdaptiveGpuPerformanceScale = AdaptiveGpuPerformanceScale;
|
|
|
|
|
out->AnyFrameStatsDropped = AnyFrameStatsDropped;
|
|
|
|
|
out->FrameStatsCount = FrameStatsCount;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ovrPerfStats* out = outStats;
|
|
|
|
|
memcpy(out->FrameStats, FrameStats, sizeof(FrameStats));
|
|
|
|
|
out->AdaptiveGpuPerformanceScale = AdaptiveGpuPerformanceScale;
|
|
|
|
|
out->AnyFrameStatsDropped = AnyFrameStatsDropped;
|
|
|
|
|
out->FrameStatsCount = FrameStatsCount;
|
|
|
|
|
out->AswIsAvailable = ovrFalse;
|
2017-05-10 12:40:34 +02:00
|
|
|
|
|
|
|
|
if (g_MinorVersion >= 14)
|
|
|
|
|
out->VisibleProcessId = vr::VRCompositor()->GetCurrentSceneFocusProcess();
|
2016-09-25 15:05:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ovrSuccess;
|
2016-09-24 17:31:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_ResetPerfStats(ovrSession session)
|
|
|
|
|
{
|
2016-09-25 23:56:05 +02:00
|
|
|
REV_TRACE(ovr_ResetPerfStats);
|
|
|
|
|
|
2017-10-25 22:15:46 +02:00
|
|
|
vr::VRCompositor()->GetCumulativeStats(&session->BaseStats, sizeof(vr::Compositor_CumulativeStats));
|
|
|
|
|
return ovrSuccess;
|
2016-09-24 17:31:52 +02:00
|
|
|
}
|
|
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(double) ovr_GetPredictedDisplayTime(ovrSession session, long long frameIndex)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetPredictedDisplayTime);
|
|
|
|
|
|
2017-04-15 17:51:35 +02:00
|
|
|
MICROPROFILE_META_CPU("Predict Frame", (int)frameIndex);
|
2017-04-15 14:05:31 +02:00
|
|
|
|
2017-08-25 14:01:38 +02:00
|
|
|
if (session->FrameIndex == 0)
|
|
|
|
|
return ovr_GetTimeInSeconds();
|
2017-04-16 20:31:08 +02:00
|
|
|
|
2017-08-28 18:23:18 +02:00
|
|
|
double predictAhead = vr::VRCompositor()->GetFrameTimeRemaining();
|
2017-08-28 21:34:22 +02:00
|
|
|
if (session && frameIndex > 0)
|
2017-08-25 16:29:38 +02:00
|
|
|
{
|
|
|
|
|
// Some applications ask for frames ahead of the current frame
|
|
|
|
|
ovrHmdDesc* pHmd = session->Details->HmdDesc;
|
2017-08-28 18:23:18 +02:00
|
|
|
predictAhead += double(frameIndex - session->FrameIndex) / pHmd->DisplayRefreshRate;
|
2017-08-25 16:29:38 +02:00
|
|
|
}
|
2017-08-28 18:23:18 +02:00
|
|
|
return ovr_GetTimeInSeconds() + predictAhead;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(double) ovr_GetTimeInSeconds()
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetTimeInSeconds);
|
|
|
|
|
|
2017-08-25 14:01:38 +02:00
|
|
|
static double PerfFrequencyInverse = 0.0;
|
|
|
|
|
if (PerfFrequencyInverse == 0.0)
|
|
|
|
|
{
|
|
|
|
|
LARGE_INTEGER freq;
|
|
|
|
|
QueryPerformanceFrequency(&freq);
|
|
|
|
|
PerfFrequencyInverse = 1.0 / (double)freq.QuadPart;
|
|
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2017-08-25 14:01:38 +02:00
|
|
|
LARGE_INTEGER li;
|
|
|
|
|
QueryPerformanceCounter(&li);
|
|
|
|
|
return li.QuadPart * PerfFrequencyInverse;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrBool) ovr_GetBool(ovrSession session, const char* propertyName, ovrBool defaultVal)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetBool);
|
|
|
|
|
|
2017-08-23 22:54:28 +02:00
|
|
|
return defaultVal;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetBool(ovrSession session, const char* propertyName, ovrBool value)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_SetBool);
|
|
|
|
|
|
2017-10-25 19:20:09 +02:00
|
|
|
// TODO: Should we handle QueueAheadEnabled with always-on reprojection?
|
2017-08-23 16:45:42 +02:00
|
|
|
return false;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(int) ovr_GetInt(ovrSession session, const char* propertyName, int defaultVal)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetInt);
|
|
|
|
|
|
2016-08-20 02:09:38 +02:00
|
|
|
if (strcmp("TextureSwapChainDepth", propertyName) == 0)
|
2017-08-27 22:40:46 +02:00
|
|
|
return REV_SWAPCHAIN_MAX_LENGTH;
|
2016-08-20 02:09:38 +02:00
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return defaultVal;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetInt(ovrSession session, const char* propertyName, int value)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_SetInt);
|
|
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return false;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(float) ovr_GetFloat(ovrSession session, const char* propertyName, float defaultVal)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetFloat);
|
|
|
|
|
|
2016-05-14 20:53:25 +00:00
|
|
|
if (strcmp(propertyName, "IPD") == 0)
|
2016-07-01 14:22:37 +00:00
|
|
|
return vr::VRSystem()->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_UserIpdMeters_Float);
|
2016-07-02 23:21:47 +00:00
|
|
|
|
|
|
|
|
// Override defaults, we should always return a valid value for these
|
2016-05-14 20:53:25 +00:00
|
|
|
if (strcmp(propertyName, OVR_KEY_PLAYER_HEIGHT) == 0)
|
2016-07-02 23:21:47 +00:00
|
|
|
defaultVal = OVR_DEFAULT_PLAYER_HEIGHT;
|
|
|
|
|
else if (strcmp(propertyName, OVR_KEY_EYE_HEIGHT) == 0)
|
|
|
|
|
defaultVal = OVR_DEFAULT_EYE_HEIGHT;
|
2016-05-14 20:53:25 +00:00
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return defaultVal;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetFloat(ovrSession session, const char* propertyName, float value)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_SetFloat);
|
|
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return false;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2015-10-21 16:29:00 -07:00
|
|
|
|
2015-10-21 16:29:00 -07:00
|
|
|
OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetFloatArray(ovrSession session, const char* propertyName, float values[], unsigned int valuesCapacity)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetFloatArray);
|
|
|
|
|
|
2016-05-14 20:53:25 +00:00
|
|
|
if (strcmp(propertyName, OVR_KEY_NECK_TO_EYE_DISTANCE) == 0)
|
|
|
|
|
{
|
|
|
|
|
if (valuesCapacity < 2)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// We only know the horizontal depth
|
2016-07-01 14:22:37 +00:00
|
|
|
values[0] = vr::VRSystem()->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_UserHeadToEyeDepthMeters_Float);
|
2016-05-14 20:53:25 +00:00
|
|
|
values[1] = OVR_DEFAULT_NECK_TO_EYE_VERTICAL;
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return 0;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetFloatArray(ovrSession session, const char* propertyName, const float values[], unsigned int valuesSize)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_SetFloatArray);
|
|
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return false;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(const char*) ovr_GetString(ovrSession session, const char* propertyName, const char* defaultVal)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_GetString);
|
|
|
|
|
|
2016-04-27 15:44:47 +00:00
|
|
|
if (!session)
|
2016-10-24 17:25:29 +02:00
|
|
|
return defaultVal;
|
2016-04-27 15:44:47 +00:00
|
|
|
|
2016-07-02 23:21:47 +00:00
|
|
|
// Override defaults, we should always return a valid value for these
|
2016-05-14 20:53:25 +00:00
|
|
|
if (strcmp(propertyName, OVR_KEY_GENDER) == 0)
|
2016-07-02 23:21:47 +00:00
|
|
|
defaultVal = OVR_DEFAULT_GENDER;
|
2016-05-14 20:53:25 +00:00
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return defaultVal;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetString(ovrSession session, const char* propertyName, const char* value)
|
|
|
|
|
{
|
2016-08-20 02:10:39 +02:00
|
|
|
REV_TRACE(ovr_SetString);
|
|
|
|
|
|
2017-08-23 16:45:42 +02:00
|
|
|
return false;
|
2015-10-21 16:29:00 -07:00
|
|
|
}
|
2016-09-05 13:22:28 +02:00
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_Lookup(const char* name, void** data)
|
|
|
|
|
{
|
2017-07-14 21:51:27 +02:00
|
|
|
// We don't communicate with the ovrServer.
|
2016-09-09 13:28:29 +02:00
|
|
|
return ovrError_ServiceError;
|
2016-09-05 13:22:28 +02:00
|
|
|
}
|
2017-07-14 21:51:27 +02:00
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetExternalCameras(ovrSession session, ovrExternalCamera* cameras, unsigned int* inoutCameraCount)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Support externalcamera.cfg used by the SteamVR Unity plugin
|
|
|
|
|
return ovrError_NoExternalCameraInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetExternalCameraProperties(ovrSession session, const char* name, const ovrCameraIntrinsics* const intrinsics, const ovrCameraExtrinsics* const extrinsics)
|
|
|
|
|
{
|
|
|
|
|
return ovrError_NoExternalCameraInfo;
|
|
|
|
|
}
|
2017-07-14 22:09:17 +02:00
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetEnabledCaps(ovrSession session)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(void) ovr_SetEnabledCaps(ovrSession session, unsigned int hmdCaps)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetTrackingCaps(ovrSession session)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult)
|
|
|
|
|
ovr_ConfigureTracking(
|
|
|
|
|
ovrSession session,
|
|
|
|
|
unsigned int requestedTrackingCaps,
|
|
|
|
|
unsigned int requiredTrackingCaps)
|
|
|
|
|
{
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
2017-12-02 14:11:40 -08:00
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult)
|
|
|
|
|
ovr_IsExtensionSupported(
|
|
|
|
|
ovrSession session,
|
|
|
|
|
ovrExtensions extension,
|
|
|
|
|
ovrBool* outExtensionSupported)
|
|
|
|
|
{
|
|
|
|
|
if (!outExtensionSupported)
|
|
|
|
|
return ovrError_InvalidParameter;
|
|
|
|
|
|
|
|
|
|
// TODO: Extensions support
|
|
|
|
|
*outExtensionSupported = false;
|
|
|
|
|
return ovrSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OVR_PUBLIC_FUNCTION(ovrResult)
|
|
|
|
|
ovr_EnableExtension(ovrSession session, ovrExtensions extension)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Extensions support
|
|
|
|
|
return ovrError_InvalidOperation;
|
|
|
|
|
}
|