version 2.3.0

This commit is contained in:
Sean Lu(呂祥榮)
2024-05-15 14:09:18 +08:00
parent 45b4e46f74
commit 7f2a459592
289 changed files with 116381 additions and 5440 deletions

View File

@@ -0,0 +1,140 @@
// Copyright HTC Corporation All Rights Reserved.
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace VIVE.OpenXR.Feature
{
/// <summary>
/// To use this wrapper, you need to call CommonWrapper.Instance.OnInstanceCreate() in your feature's OnInstanceCreate(),
/// and call CommonWrapper.Instance.OnInstanceDestroy() in your feature's OnInstanceDestroy().
/// </summary>
public class CommonWrapper
{
static CommonWrapper instance = null;
public static CommonWrapper Instance
{
get
{
if (instance == null)
instance = new CommonWrapper();
return instance;
}
}
bool isInited = false;
OpenXRHelper.xrGetInstanceProcAddrDelegate XrGetInstanceProcAddr;
OpenXRHelper.xrGetSystemPropertiesDelegate XrGetSystemProperties;
/// <summary>
/// In feature's OnInstanceCreate(), call CommonWrapper.Instance.OnInstanceCreate() for init common APIs.
/// </summary>
/// <param name="xrInstance">Passed in feature's OnInstanceCreate.</param>
/// <param name="xrGetInstanceProcAddr">Pass OpenXRFeature.xrGetInstanceProcAddr in.</param>
/// <returns></returns>
/// <exception cref="Exception">If input data not valid.</exception>
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddr)
{
if (isInited) return true;
if (xrInstance == 0)
throw new Exception("CommonWrapper: xrInstance is null");
Debug.Log("CommonWrapper: OnInstanceCreate()");
/// OpenXRFeature.xrGetInstanceProcAddr
if (xrGetInstanceProcAddr == null || xrGetInstanceProcAddr == IntPtr.Zero)
throw new Exception("CommonWrapper: xrGetInstanceProcAddr is null");
Debug.Log("CommonWrapper: Get function pointer of xrGetInstanceProcAddr.");
XrGetInstanceProcAddr = Marshal.GetDelegateForFunctionPointer(
xrGetInstanceProcAddr,
typeof(OpenXRHelper.xrGetInstanceProcAddrDelegate)) as OpenXRHelper.xrGetInstanceProcAddrDelegate;
bool ret = true;
IntPtr funcPtr = IntPtr.Zero;
ret &= OpenXRHelper.GetXrFunctionDelegate(XrGetInstanceProcAddr, xrInstance, "xrGetSystemProperties", out XrGetSystemProperties);
if (!ret)
throw new Exception("CommonWrapper: Get function pointers failed.");
isInited = ret;
return ret;
}
/// <summary>
/// In feature's OnInstanceDestroy(), call CommonWrapper.Instance.OnInstanceDestroy() for disable common APIs.
/// </summary>
/// <returns></returns>
public void OnInstanceDestroy()
{
isInited = false;
XrGetInstanceProcAddr = null;
XrGetSystemProperties = null;
Debug.Log("CommonWrapper: OnInstanceDestroy()");
}
public XrResult GetInstanceProcAddr(XrInstance instance, string name, out IntPtr function)
{
if (isInited == false || XrGetInstanceProcAddr == null)
{
function = IntPtr.Zero;
return XrResult.XR_ERROR_HANDLE_INVALID;
}
return XrGetInstanceProcAddr(instance, name, out function);
}
/// <summary>
/// Helper function to get system properties. Need input your features' xrInstance and xrSystemId. Fill the system properites in next for you feature.
/// See <see href="https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#xrGetSystemProperties">xrGetSystemProperties</see>
/// </summary>
/// <param name="instance"></param>
/// <param name="systemId"></param>
/// <param name="properties"></param>
/// <returns></returns>
public XrResult GetSystemProperties(XrInstance instance, XrSystemId systemId, ref XrSystemProperties properties)
{
if (isInited == false || XrGetSystemProperties == null)
{
return XrResult.XR_ERROR_HANDLE_INVALID;
}
return XrGetSystemProperties(instance, systemId, ref properties);
}
public XrResult GetProperties<T>(XrInstance instance, XrSystemId systemId, ref T featureProperty)
{
XrSystemProperties systemProperties = new XrSystemProperties();
systemProperties.type = XrStructureType.XR_TYPE_SYSTEM_PROPERTIES;
systemProperties.next = Marshal.AllocHGlobal(Marshal.SizeOf(featureProperty));
long offset = 0;
if (IntPtr.Size == 4)
offset = systemProperties.next.ToInt32();
else
offset = systemProperties.next.ToInt64();
IntPtr pdPropertiesPtr = new IntPtr(offset);
Marshal.StructureToPtr(featureProperty, pdPropertiesPtr, false);
var ret = GetSystemProperties(instance, systemId, ref systemProperties);
if (ret == XrResult.XR_SUCCESS)
{
if (IntPtr.Size == 4)
offset = systemProperties.next.ToInt32();
else
offset = systemProperties.next.ToInt64();
pdPropertiesPtr = new IntPtr(offset);
featureProperty = Marshal.PtrToStructure<T>(pdPropertiesPtr);
}
Marshal.FreeHGlobal(systemProperties.next);
return ret;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b940cd65f52cd5c44bd79869c5d521b2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,226 @@
// Copyright HTC Corporation All Rights Reserved.
// Remove FAKE_DATA if editor or windows is supported.
#if UNITY_EDITOR
#define FAKE_DATA
#endif
using System;
using UnityEngine;
namespace VIVE.OpenXR.Feature
{
/// <summary>
/// To use this wrapper, you need to call CommonWrapper.Instance.OnInstanceCreate() in your feature's OnInstanceCreate(),
/// and call CommonWrapper.Instance.OnInstanceDestroy() in your feature's OnInstanceDestroy().
/// </summary>
public class SpaceWrapper
{
static SpaceWrapper instance = null;
public static SpaceWrapper Instance
{
get
{
if (instance == null)
instance = new SpaceWrapper();
return instance;
}
}
bool isInited = false;
delegate XrResult DelegateXrLocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, ref XrSpaceLocation location);
delegate XrResult DelegateXrDestroySpace(XrSpace space);
OpenXRHelper.xrCreateReferenceSpaceDelegate XrCreateReferenceSpace;
DelegateXrLocateSpace XrLocateSpace;
DelegateXrDestroySpace XrDestroySpace;
/// <summary>
/// Features should call ViveSpaceWrapper.Instance.OnInstanceCreate() in their OnInstanceCreate().
/// </summary>
/// <param name="xrInstance"></param>
/// <param name="GetAddr"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public bool OnInstanceCreate(XrInstance xrInstance, OpenXRHelper.xrGetInstanceProcAddrDelegate GetAddr)
{
if (isInited) return true;
if (xrInstance == null)
throw new Exception("ViveSpace: xrInstance is null");
if (GetAddr == null)
throw new Exception("ViveSpace: xrGetInstanceProcAddr is null");
Debug.Log("ViveSpace: OnInstanceCreate()");
bool ret = true;
IntPtr funcPtr = IntPtr.Zero;
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, xrInstance, "xrCreateReferenceSpace", out XrCreateReferenceSpace);
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, xrInstance, "xrLocateSpace", out XrLocateSpace);
ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, xrInstance, "xrDestroySpace", out XrDestroySpace);
isInited = ret;
return ret;
}
public void OnInstanceDestroy()
{
isInited = false;
XrCreateReferenceSpace = null;
XrLocateSpace = null;
XrDestroySpace = null;
}
/// <summary>
/// Create a reference space without create info.
/// Example:
/// CreateReferenceSpace(session, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_LOCAL, XrPosef.identity, out space);
/// CreateReferenceSpace(session, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_STAGE, XrPosef.identity, out space);
/// </summary>
/// <param name="session"></param>
/// <param name="referenceSpaceType"></param>
/// <param name="pose"></param>
/// <param name="space"></param>
/// <returns></returns>
public XrResult CreateReferenceSpace(XrSession session, XrReferenceSpaceType referenceSpaceType, XrPosef pose, out XrSpace space)
{
if (!isInited)
throw new Exception("ViveSpace: not initialized");
var createInfo = new XrReferenceSpaceCreateInfo();
createInfo.type = XrStructureType.XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
createInfo.next = IntPtr.Zero;
createInfo.referenceSpaceType = referenceSpaceType;
createInfo.poseInReferenceSpace = pose;
return XrCreateReferenceSpace(session, ref createInfo, out space);
}
/// <summary>
/// Create a reference space.
/// </summary>
/// <param name="session"></param>
/// <param name="createInfo"></param>
/// <param name="space"></param>
/// <returns></returns>
public XrResult CreateReferenceSpace(XrSession session, XrReferenceSpaceCreateInfo createInfo, out XrSpace space)
{
if (!isInited)
throw new Exception("ViveSpace: not initialized");
return XrCreateReferenceSpace(session, ref createInfo, out space);
}
public XrResult LocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, ref XrSpaceLocation location)
{
if (!isInited)
throw new Exception("ViveSpace: not initialized");
Debug.Log($"LocateSpace(s={space}, bs={baseSpace}, t={time}");
return XrLocateSpace(space, baseSpace, time, ref location);
}
public XrResult DestroySpace(XrSpace space)
{
if (!isInited)
throw new Exception("ViveSpace: not initialized");
Debug.Log($"DestroySpace({space})");
return XrDestroySpace(space);
}
}
/// <summary>
/// The XrSpace's Unity wrapper. Input and output are in Unity coordinate system.
/// After use it, you should call Dispose() to release the XrSpace.
/// </summary>
public class Space : IDisposable
{
protected XrSpace space;
private bool disposed = false;
public Space(XrSpace space)
{
Debug.Log($"Space({space})");
this.space = space;
}
/// <summary>
/// Get the raw XrSpace. Only use it when class Space instance is alive.
/// You should not try to store this XrSpace, because it may be destroyed.
/// </summary>
/// <returns></returns>
public XrSpace GetXrSpace()
{
return space;
}
public bool GetRelatedPose(XrSpace baseSpace, XrTime time, out UnityEngine.Pose pose)
{
#if FAKE_DATA
if (Application.isEditor)
{
// make a random Pose
//var pos = new Vector3(UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f));
//var rot = new Quaternion(UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f));
var pos = Vector3.up;
var rot = Quaternion.identity;
rot.Normalize();
pose = new Pose(pos, rot);
return true;
}
#endif
// If the xrBaseSpace is changed, the pose will be updated.
pose = default;
XrSpaceLocation location = new XrSpaceLocation();
location.type = XrStructureType.XR_TYPE_SPACE_LOCATION;
location.next = IntPtr.Zero;
var ret = SpaceWrapper.Instance.LocateSpace(space, baseSpace, time, ref location);
if (ret != XrResult.XR_SUCCESS)
{
Debug.Log("Space: LocateSpace ret=" + ret);
return false;
}
Debug.Log("Space: baseSpace=" + baseSpace + ", space=" + space + ", time=" + time + ", ret=" + ret);
Debug.Log("Space: location.locationFlags=" + location.locationFlags);
Debug.Log("Space: location.pose.position=" + location.pose.position.x + "," + location.pose.position.y + "," + location.pose.position.z);
Debug.Log("Space: location.pose.orientation=" + location.pose.orientation.x + "," + location.pose.orientation.y + "," + location.pose.orientation.z + "," + location.pose.orientation.w);
if ((location.locationFlags & XrSpaceLocationFlags.XR_SPACE_LOCATION_POSITION_VALID_BIT) > 0 &&
(location.locationFlags & XrSpaceLocationFlags.XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) > 0)
{
pose = new Pose(location.pose.position.ToUnityVector(), location.pose.orientation.ToUnityQuaternion());
return true;
}
return false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Managered resource
}
// Non managered resource
Debug.Log($"Space: DestroySpace({space})");
SpaceWrapper.Instance.DestroySpace(space);
space = 0;
disposed = true;
}
}
~Space()
{
Dispose(false);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8fbeadd31afbe14996c061ac261041d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
// Copyright HTC Corporation All Rights Reserved.
using System.Runtime.InteropServices;
using System;
using UnityEngine;
using AOT;
namespace VIVE.OpenXR
{
/// <summary>
/// This class is made for all features that need to intercept OpenXR API calls.
/// Some APIs will be called by Unity internally, and we need to intercept them in c# to get some information.
/// Append more interceptable functions for this class by adding a new partial class.
/// The partial class can help the delegate name be nice to read and search.
/// Please create per function in one partial class.
///
/// For all features want to use this class, please call <see cref="HookGetInstanceProcAddr" /> in your feature class.
/// For example:
/// protected override IntPtr HookGetInstanceProcAddr(IntPtr func)
/// {
/// return HtcInterceptors.Instance.HookGetInstanceProcAddr(func);
/// }
/// </summary>
partial class ViveInterceptors
{
public const string TAG = "Interceptors";
public static ViveInterceptors instance = null;
public static ViveInterceptors Instance
{
get
{
if (instance == null)
instance = new ViveInterceptors();
return instance;
}
}
public ViveInterceptors()
{
Debug.Log("HtcInterceptors");
}
bool isInited = false;
public delegate XrResult DelegateXrGetInstanceProcAddr(XrInstance instance, string name, out IntPtr function);
private static readonly DelegateXrGetInstanceProcAddr hookXrGetInstanceProcAddrHandle = new DelegateXrGetInstanceProcAddr(XrGetInstanceProcAddrInterceptor);
private static readonly IntPtr hookGetInstanceProcAddrHandlePtr = Marshal.GetFunctionPointerForDelegate(hookXrGetInstanceProcAddrHandle);
static DelegateXrGetInstanceProcAddr XrGetInstanceProcAddrOriginal = null;
[MonoPInvokeCallback(typeof(DelegateXrGetInstanceProcAddr))]
private static XrResult XrGetInstanceProcAddrInterceptor(XrInstance instance, string name, out IntPtr function)
{
// Custom interceptors
if (name == "xrWaitFrame")
{
Debug.Log($"{TAG}: XrGetInstanceProcAddrInterceptor() {name} is intercepted.");
var ret = XrGetInstanceProcAddrOriginal(instance, name, out function);
if (ret == XrResult.XR_SUCCESS)
{
XrWaitFrameOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrWaitFrame>(function);
function = xrWaitFrameInterceptorPtr;
}
return ret;
}
return XrGetInstanceProcAddrOriginal(instance, name, out function);
}
public IntPtr HookGetInstanceProcAddr(IntPtr func)
{
Debug.Log($"{TAG}: registering our own xrGetInstanceProcAddr");
if (XrGetInstanceProcAddrOriginal == null)
{
XrGetInstanceProcAddrOriginal = Marshal.GetDelegateForFunctionPointer<DelegateXrGetInstanceProcAddr>(func);
isInited = true;
return hookGetInstanceProcAddrHandlePtr;
}
else
{
return func;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 118a2474c266d174d834b364821865b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
// Copyright HTC Corporation All Rights Reserved.
using System.Runtime.InteropServices;
using System;
using UnityEngine;
using AOT;
namespace VIVE.OpenXR
{
partial class ViveInterceptors
{
#region XRWaitFrame
public struct XrFrameWaitInfo
{
public XrStructureType type;
public IntPtr next;
}
public struct XrFrameState
{
public XrStructureType type;
public IntPtr next;
public XrTime predictedDisplayTime;
public XrDuration predictedDisplayPeriod;
public XrBool32 shouldRender;
}
public delegate XrResult DelegateXrWaitFrame(XrSession session, ref XrFrameWaitInfo frameWaitInfo, ref XrFrameState frameState);
private static readonly DelegateXrWaitFrame xrWaitFrameInterceptorHandle = new DelegateXrWaitFrame(XrWaitFrameInterceptor);
private static readonly IntPtr xrWaitFrameInterceptorPtr = Marshal.GetFunctionPointerForDelegate(xrWaitFrameInterceptorHandle);
static DelegateXrWaitFrame XrWaitFrameOriginal = null;
[MonoPInvokeCallback(typeof(DelegateXrWaitFrame))]
private static XrResult XrWaitFrameInterceptor(XrSession session, ref XrFrameWaitInfo frameWaitInfo, ref XrFrameState frameState)
{
var ret = XrWaitFrameOriginal(session, ref frameWaitInfo, ref frameState);
currentFrameState = frameState;
return ret;
}
static XrFrameState currentFrameState = new XrFrameState() { predictedDisplayTime = 0 };
public XrFrameState GetCurrentFrameState()
{
if (!isInited) throw new Exception("ViveInterceptors is not inited");
return currentFrameState;
}
public XrTime GetPredictTime()
{
if (!isInited) throw new Exception("ViveInterceptors is not inited");
Debug.Log($"{TAG}: XrWaitFrameInterceptor(predictedDisplayTime={currentFrameState.predictedDisplayTime}");
if (currentFrameState.predictedDisplayTime == 0)
return new XrTime((long)(1000000L * (Time.unscaledTimeAsDouble + 0.011f)));
else
return currentFrameState.predictedDisplayTime;
}
#endregion XRWaitFrame
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9bfc07f267ee39b47a4bcbb8c1c786cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: