// Copyright HTC Corporation All Rights Reserved.
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;
namespace VIVE.OpenXR.Feature
{
///
/// 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().
///
public class CommonWrapper : ViveFeatureWrapperBase, IViveFeatureWrapper
{
OpenXRHelper.xrGetSystemPropertiesDelegate XrGetSystemProperties;
OpenXRHelper.xrCreateSwapchainDelegate XrCreateSwapchain;
OpenXRHelper.xrDestroySwapchainDelegate XrDestroySwapchain;
OpenXRHelper.xrEnumerateSwapchainFormatsDelegate XrEnumerateSwapchainFormats;
OpenXRHelper.xrEnumerateSwapchainImagesDelegate XrEnumerateSwapchainImages;
OpenXRHelper.xrWaitSwapchainImageDelegate XrWaitSwapchainImage;
OpenXRHelper.xrAcquireSwapchainImageDelegate XrAcquireSwapchainImage;
OpenXRHelper.xrReleaseSwapchainImageDelegate XrReleaseSwapchainImage;
///
/// In feature's OnInstanceCreate(), call CommonWrapper.Instance.OnInstanceCreate() for init common APIs.
///
/// Passed in feature's OnInstanceCreate.
/// Pass OpenXRFeature.xrGetInstanceProcAddr in.
///
/// If input data not valid.
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr xrGetInstanceProcAddrPtr)
{
if (IsInited) return true;
if (xrInstance == 0)
throw new Exception("CommonWrapper: xrInstance is null");
Debug.Log("CommonWrapper: OnInstanceCreate()");
SetGetInstanceProcAddrPtr(xrGetInstanceProcAddrPtr);
bool ret = true;
IntPtr funcPtr = IntPtr.Zero;
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrGetSystemProperties", out XrGetSystemProperties);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrCreateSwapchain", out XrCreateSwapchain);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrDestroySwapchain", out XrDestroySwapchain);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrEnumerateSwapchainFormats", out XrEnumerateSwapchainFormats);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrEnumerateSwapchainImages", out XrEnumerateSwapchainImages);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrWaitSwapchainImage", out XrWaitSwapchainImage);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrAcquireSwapchainImage", out XrAcquireSwapchainImage);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrReleaseSwapchainImage", out XrReleaseSwapchainImage);
if (!ret)
throw new Exception("CommonWrapper: Get function pointers failed.");
IsInited = ret;
return ret;
}
///
/// In feature's OnInstanceDestroy(), call CommonWrapper.Instance.OnInstanceDestroy() for disable common APIs.
///
///
public void OnInstanceDestroy()
{
IsInited = false;
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);
}
///
/// Helper function to get system properties. Need input your features' xrInstance and xrSystemId. Fill the system properites in next for you feature.
/// See xrGetSystemProperties
///
///
///
///
///
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(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(pdPropertiesPtr);
}
Marshal.FreeHGlobal(systemProperties.next);
return ret;
}
public XrResult CreateSwapchain(XrSession session, ref XrSwapchainCreateInfo createInfo, out XrSwapchain swapchain)
{
if (IsInited == false || XrCreateSwapchain == null)
{
swapchain = default;
return XrResult.XR_ERROR_HANDLE_INVALID;
}
return XrCreateSwapchain(session, ref createInfo, out swapchain);
}
public XrResult DestroySwapchain(XrSwapchain swapchain)
{
if (IsInited == false || XrDestroySwapchain == null)
{
return XrResult.XR_ERROR_HANDLE_INVALID;
}
return XrDestroySwapchain(swapchain);
}
public XrResult EnumerateSwapchainFormats(XrSession session, uint formatCapacityInput, ref uint formatCountOutput, ref long[] formats)
{
if (IsInited == false || XrEnumerateSwapchainFormats == null)
{
formatCountOutput = 0;
return XrResult.XR_ERROR_HANDLE_INVALID;
}
if (formatCapacityInput != 0 && (formats == null || formats.Length < formatCapacityInput))
return XrResult.XR_ERROR_SIZE_INSUFFICIENT;
if (formatCapacityInput == 0)
{
Debug.Log("CommonWrapper: EnumerateSwapchainFormats(ci=" + formatCapacityInput + ")");
return XrEnumerateSwapchainFormats(session, 0, ref formatCountOutput, IntPtr.Zero);
}
else
{
Debug.Log("CommonWrapper: EnumerateSwapchainFormats(ci=" + formatCapacityInput + ", formats=long[" + formats.Length + "])");
IntPtr formatsPtr = MemoryTools.MakeRawMemory(formats);
var ret = XrEnumerateSwapchainFormats(session, formatCapacityInput, ref formatCountOutput, formatsPtr);
if (ret == XrResult.XR_SUCCESS)
MemoryTools.CopyFromRawMemory(formats, formatsPtr, (int)formatCountOutput);
MemoryTools.ReleaseRawMemory(formatsPtr);
return ret;
}
}
public XrResult EnumerateSwapchainImages(XrSwapchain swapchain, uint imageCapacityInput, ref uint imageCountOutput, IntPtr imagesPtr)
{
if (IsInited == false || XrEnumerateSwapchainImages == null)
{
imageCountOutput = 0;
return XrResult.XR_ERROR_HANDLE_INVALID;
}
return XrEnumerateSwapchainImages(swapchain, imageCapacityInput, ref imageCountOutput, imagesPtr);
}
[DllImport("viveopenxr", EntryPoint = "CwAcquireSwapchainImage")]
public static extern XrResult CwAcquireSwapchainImage(XrSwapchain swapchain, ref XrSwapchainImageAcquireInfo acquireInfo, out uint index);
public XrResult AcquireSwapchainImage(XrSwapchain swapchain, ref XrSwapchainImageAcquireInfo acquireInfo, out uint index)
{
if (IsInited == false || XrAcquireSwapchainImage == null)
{
index = 0;
return XrResult.XR_ERROR_HANDLE_INVALID;
}
Profiler.BeginSample("ASW: xrAcqScImg");
var res = XrAcquireSwapchainImage(swapchain, ref acquireInfo, out index);
Profiler.EndSample();
return res;
}
[DllImport("viveopenxr", EntryPoint = "CwWaitSwapchainImage")]
public static extern XrResult CwWaitSwapchainImage(XrSwapchain swapchain, ref XrSwapchainImageWaitInfo waitInfo);
public XrResult WaitSwapchainImage(XrSwapchain swapchain, ref XrSwapchainImageWaitInfo waitInfo)
{
if (IsInited == false || XrWaitSwapchainImage == null)
{
return XrResult.XR_ERROR_HANDLE_INVALID;
}
Profiler.BeginSample("ASW: xrWaitScImg");
var res = XrWaitSwapchainImage(swapchain, ref waitInfo);
Profiler.EndSample();
return res;
}
[DllImport("viveopenxr", EntryPoint = "CwReleaseSwapchainImage")]
public static extern XrResult CwReleaseSwapchainImage(XrSwapchain swapchain, ref XrSwapchainImageReleaseInfo releaseInfo);
public XrResult ReleaseSwapchainImage(XrSwapchain swapchain, ref XrSwapchainImageReleaseInfo releaseInfo)
{
if (IsInited == false || XrReleaseSwapchainImage == null)
{
return XrResult.XR_ERROR_HANDLE_INVALID;
}
// Add Profiler
Profiler.BeginSample("ASW: xrRelScImg");
var res = XrReleaseSwapchainImage(swapchain, ref releaseInfo);
Profiler.EndSample();
return res;
}
}
}