// 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; }
}
}