using System;
using System.Runtime.InteropServices;
namespace UnityEngine.XR.OpenXR
{
///
/// OpenXR Runtime access
///
public static class OpenXRRuntime
{
///
/// Name of the current runtime.
///
public static string name =>
Internal_GetRuntimeName(out var runtimeNamePtr) ? Marshal.PtrToStringAnsi(runtimeNamePtr) : "";
///
/// Version of the current runtime.
///
public static string version =>
Internal_GetRuntimeVersion(out var major, out var minor, out var patch) ? $"{major}.{minor}.{patch}" : "";
///
/// Version of the current runtime API.
///
public static string apiVersion =>
Internal_GetAPIVersion(out var major, out var minor, out var patch) ? $"{major}.{minor}.{patch}" : "";
///
/// Version of the current runtime plug-in.
///
public static string pluginVersion =>
Internal_GetPluginVersion(out var pluginVersionPtr) ? Marshal.PtrToStringAnsi(pluginVersionPtr) : "";
///
/// Check if current runtime API version is greater than 1.1
///
internal static bool isRuntimeAPIVersionGreaterThan1_1()
{
if (Internal_GetAPIVersion(out var major, out var minor, out var patch))
{
if (major >= 1 && minor >= 1)
return true;
}
return false;
}
///
/// Describes whether the OpenXR Extension with the given name is enabled.
///
/// Name of the extension
/// True if the extension matching the given name is enabled, false otherwise
public static bool IsExtensionEnabled(string extensionName) => Internal_IsExtensionEnabled(extensionName);
///
/// Returns the version number of the given extension.
///
/// Name of the extension
/// Version number of given extension, or zero if the extension was not found
public static uint GetExtensionVersion(string extensionName) => Internal_GetExtensionVersion(extensionName);
///
/// Returns the list of names of extensions enabled within the OpenXR runtime.
///
/// Array of extension names or an empty array if no extensions are enabled.
public static string[] GetEnabledExtensions()
{
var extensions = new string[Internal_GetEnabledExtensionCount()];
for (var i = 0; i < extensions.Length; i++)
{
Internal_GetEnabledExtensionName((uint)i, out var extensionName);
extensions[i] = $"{extensionName}";
}
return extensions;
}
///
/// Returns the list of names of extensions available within the OpenXR runtime.
///
/// Array of extension names or an empty array if no extensions are available.
public static string[] GetAvailableExtensions()
{
var extensions = new string[Internal_GetAvailableExtensionCount()];
for (var i = 0; i < extensions.Length; i++)
{
Internal_GetAvailableExtensionName((uint)i, out var extensionName);
extensions[i] = $"{extensionName}";
}
return extensions;
}
///
/// This event is raised when OpenXR wants the application to quit.
///
/// Note that this event is raised before Application.wantsToQuit is raised and is generally
/// raised because the Runtime has requested the application quit.
///
/// Return true and the quit process will continue. Return false and the quit process will cancel.
///
public static event Func wantsToQuit;
///
/// This event is raised when OpenXR Runtime wants to restart the XR loader by shutting down
/// the loader and reinitializing it.
///
/// Return true and the restart process will continue. Return false and the XR loader will be
/// unloaded and the quit process will begin.
///
public static event Func wantsToRestart;
///
/// This bool controls whether or not to retry initialization if the runtime reports a
/// FORM_FACTOR_UNAVAILABLE error during initialization.
///
public static bool retryInitializationOnFormFactorErrors
{
get
{
return Internal_GetSoftRestartLoopAtInitialization();
}
set
{
Internal_SetSoftRestartLoopAtInitialization(value);
}
}
///
/// Invokes the given event function and returns true if all invocations return true
///
/// Event function
/// True if all event invocations return true
private static bool InvokeEvent(Func func)
{
if (func == null)
return true;
foreach (Func invocation in func.GetInvocationList())
{
try
{
if (!invocation())
return false;
}
catch (Exception exception)
{
Debug.LogException(exception);
}
}
return true;
}
#if UNITY_INCLUDE_TESTS
internal static void ClearEvents()
{
if (wantsToQuit != null)
foreach (Func f in wantsToQuit.GetInvocationList()) wantsToQuit -= f;
if (wantsToRestart != null)
foreach (Func f in wantsToRestart.GetInvocationList()) wantsToRestart -= f;
wantsToQuit = null;
wantsToRestart = null;
}
#endif
internal static bool ShouldQuit() => InvokeEvent(wantsToQuit);
internal static bool ShouldRestart() => InvokeEvent(wantsToRestart);
private const string LibraryName = "UnityOpenXR";
[DllImport(LibraryName, EntryPoint = "NativeConfig_GetRuntimeName")]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetRuntimeName(out IntPtr runtimeNamePtr);
[DllImport(LibraryName, EntryPoint = "NativeConfig_GetRuntimeVersion")]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetRuntimeVersion(out ushort major, out ushort minor, out uint patch);
[DllImport(LibraryName, EntryPoint = "NativeConfig_GetAPIVersion")]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetAPIVersion(out ushort major, out ushort minor, out uint patch);
[DllImport(LibraryName, EntryPoint = "NativeConfig_GetPluginVersion")]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetPluginVersion(out IntPtr pluginVersionPtr);
[DllImport(LibraryName, EntryPoint = "unity_ext_IsExtensionEnabled")]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_IsExtensionEnabled(string extensionName);
[DllImport(LibraryName, EntryPoint = "unity_ext_GetExtensionVersion")]
private static extern uint Internal_GetExtensionVersion(string extensionName);
[DllImport(LibraryName, EntryPoint = "unity_ext_GetEnabledExtensionCount")]
private static extern uint Internal_GetEnabledExtensionCount();
[DllImport(LibraryName, EntryPoint = "unity_ext_GetEnabledExtensionName", CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetEnabledExtensionNamePtr(uint index, out IntPtr outName);
[DllImport(LibraryName, EntryPoint = "session_SetSoftRestartLoopAtInitialization")]
private static extern void Internal_SetSoftRestartLoopAtInitialization([MarshalAs(UnmanagedType.I1)] bool value);
[DllImport(LibraryName, EntryPoint = "session_GetSoftRestartLoopAtInitialization")]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetSoftRestartLoopAtInitialization();
private static bool Internal_GetEnabledExtensionName(uint index, out string extensionName)
{
if (!Internal_GetEnabledExtensionNamePtr(index, out var extensionNamePtr))
{
extensionName = "";
return false;
}
extensionName = Marshal.PtrToStringAnsi(extensionNamePtr);
return true;
}
[DllImport(LibraryName, EntryPoint = "unity_ext_GetAvailableExtensionCount")]
private static extern uint Internal_GetAvailableExtensionCount();
[DllImport(LibraryName, EntryPoint = "unity_ext_GetAvailableExtensionName", CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetAvailableExtensionNamePtr(uint index, out IntPtr extensionName);
private static bool Internal_GetAvailableExtensionName(uint index, out string extensionName)
{
if (!Internal_GetAvailableExtensionNamePtr(index, out var extensionNamePtr))
{
extensionName = "";
return false;
}
extensionName = Marshal.PtrToStringAnsi(extensionNamePtr);
return true;
}
[DllImport(LibraryName, EntryPoint = "session_GetLastError", CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool Internal_GetLastError(out IntPtr error);
///
/// Returns the last error message that was issued in the native code
///
/// Last error message
/// True if there was an error message, false if not
internal static bool GetLastError(out string error)
{
if (!Internal_GetLastError(out var errorPtr))
{
error = "";
return false;
}
error = Marshal.PtrToStringAnsi(errorPtr);
return true;
}
///
/// Logs the last error message if there is one to the console
///
internal static void LogLastError()
{
if (GetLastError(out var error))
{
Debug.LogError(error);
}
}
}
}