// Copyright HTC Corporation All Rights Reserved. using System; using System.Text; using UnityEngine; using UnityEngine.XR.OpenXR; using UnityEngine.XR.OpenXR.Features; #if UNITY_EDITOR using UnityEditor; using UnityEditor.XR.OpenXR.Features; #endif namespace VIVE.OpenXR.FrameSynchronization { #if UNITY_EDITOR [OpenXRFeature(UiName = "VIVE XR Frame Synchronization (Beta)", BuildTargetGroups = new[] { BuildTargetGroup.Android }, Company = "HTC", Desc = "Support the Frame Synchronization extension.", DocumentationLink = "..\\Documentation", OpenxrExtensionStrings = kOpenxrExtensionString, Version = "1.0.0", FeatureId = featureId)] #endif public class ViveFrameSynchronization : OpenXRFeature { #region Log const string LOG_TAG = "VIVE.OpenXR.FrameSynchronization.ViveFrameSynchronization"; StringBuilder m_sb = null; StringBuilder sb { get { if (m_sb == null) { m_sb = new StringBuilder(); } return m_sb; } } void DEBUG(StringBuilder msg) { Debug.LogFormat("{0} {1}", LOG_TAG, msg); } void WARNING(StringBuilder msg) { Debug.LogWarningFormat("{0} {1}", LOG_TAG, msg); } void ERROR(StringBuilder msg) { Debug.LogErrorFormat("{0} {1}", LOG_TAG, msg); } #endregion /// /// The extension name of 12.1. XR_HTC_frame_synchronization. /// public const string kOpenxrExtensionString = "XR_HTC_frame_synchronization"; /// /// The feature id string. This is used to give the feature a well known id for reference. /// public const string featureId = "vive.openxr.feature.framesynchronization"; #region OpenXR Life Cycle /// protected override IntPtr HookGetInstanceProcAddr(IntPtr func) { sb.Clear().Append("HookGetInstanceProcAddr() xrBeginSession"); DEBUG(sb); ViveInterceptors.Instance.AddRequiredFunction("xrBeginSession"); return ViveInterceptors.Instance.HookGetInstanceProcAddr(func); } #pragma warning disable private bool m_XrInstanceCreated = false; #pragma warning enable private XrInstance m_XrInstance = 0; /// /// Called when xrCreateInstance is done. /// /// The created instance. /// True for valid XrInstance protected override bool OnInstanceCreate(ulong xrInstance) { if (!OpenXRRuntime.IsExtensionEnabled(kOpenxrExtensionString)) { sb.Clear().Append("OnInstanceCreate() ").Append(kOpenxrExtensionString).Append(" is NOT enabled."); WARNING(sb); return false; } m_XrInstance = xrInstance; m_XrInstanceCreated = true; sb.Clear().Append("OnInstanceCreate() ").Append(m_XrInstance); DEBUG(sb); ActivateFrameSynchronization(true); return true; } /// /// Called when xrDestroyInstance is done. /// /// The instance to destroy. protected override void OnInstanceDestroy(ulong xrInstance) { sb.Clear().Append("OnInstanceDestroy() ").Append(xrInstance).Append(", current: ").Append(m_XrInstance); DEBUG(sb); if (m_XrInstance == xrInstance) { m_XrInstanceCreated = false; m_XrInstance = 0; } } #pragma warning disable private bool m_XrSessionCreated = false; #pragma warning enable private XrSession m_XrSession = 0; /// /// Called when xrCreateSession is done. /// /// The created session ID. protected override void OnSessionCreate(ulong xrSession) { m_XrSession = xrSession; m_XrSessionCreated = true; sb.Clear().Append("OnSessionCreate() ").Append(m_XrSession); DEBUG(sb); } protected override void OnSessionEnd(ulong xrSession) { sb.Clear().Append("OnSessionEnd() ").Append(xrSession).Append(", current: ").Append(m_XrSession); DEBUG(sb); } /// /// Called when xrDestroySession is done. /// /// The session ID to destroy. protected override void OnSessionDestroy(ulong xrSession) { sb.Clear().Append("OnSessionDestroy() ").Append(xrSession).Append(", current: ").Append(m_XrSession); DEBUG(sb); if (m_XrSession == xrSession) { m_XrSessionCreated = false; m_XrSession = 0; ActivateFrameSynchronization(false); } } private XrSystemId m_XrSystemId = 0; /// /// Called when the XrSystemId retrieved by xrGetSystem is changed. /// /// The system id. protected override void OnSystemChange(ulong xrSystem) { m_XrSystemId = xrSystem; sb.Clear().Append("OnSystemChange() " + m_XrSystemId); DEBUG(sb); } #endregion [SerializeField] internal SynchronizationModeHTC m_SynchronizationMode = SynchronizationModeHTC.Stablized; /// /// Activate or deactivate the Frame Synchronization feature. /// /// True for activate /// The used for Frame Synchronization. private void ActivateFrameSynchronization(bool active) { sb.Clear().Append("ActivateFrameSynchronization() ").Append(active ? "enable " : "disable ").Append(m_SynchronizationMode); DEBUG(sb); ViveInterceptors.Instance.ActivateFrameSynchronization(active, (XrFrameSynchronizationModeHTC)m_SynchronizationMode); } /// /// Retrieves current frame synchronization mode. /// /// The mode of . public SynchronizationModeHTC GetSynchronizationMode() { return m_SynchronizationMode; } } }