// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Collections.Generic; using Unity.Collections; using UnityEngine; using UnityEngine.Scripting; using UnityEngine.XR.ARSubsystems; namespace Microsoft.MixedReality.OpenXR { [Preserve] internal class SessionSubsystem : XRSessionSubsystem { public const string Id = "OpenXR Session"; private class OpenXRProvider : Provider { private readonly Guid m_sessionGuid; private readonly Feature m_allSupportedFeatures = Feature.AnyTrackingMode | Feature.PlaneTracking | Feature.Raycast | Feature.Meshing; // The requested features, excluding the requested tracking mode private readonly Feature m_requestedBaseFeatures = Feature.PlaneTracking | Feature.Raycast | Feature.Meshing; private Feature m_requestedTrackingMode = Feature.PositionAndRotation; private NativeSpaceLocationFlags m_trackingStateFlags; public OpenXRProvider() { m_sessionGuid = Guid.NewGuid(); } public override void Start() { } public override void Stop() { } public override void Destroy() { } public override Feature currentTrackingMode { get { if (!m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.OrientationValid) || !m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.PositionValid)) return Feature.None; if (!m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.PositionTracked)) return Feature.RotationOnly; return Feature.PositionAndRotation; } } public override Feature requestedTrackingMode { get => m_requestedTrackingMode; set { if (m_requestedTrackingMode != Feature.PositionAndRotation && m_requestedTrackingMode != Feature.RotationOnly) { Debug.Log("Session supported requested tracking modes are PositionAndRotation and RotationOnly."); return; } m_requestedTrackingMode = value; } } public override TrackingState trackingState { get { if (!m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.PositionValid) || !m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.OrientationValid)) return TrackingState.None; if (m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.All)) return TrackingState.Tracking; return TrackingState.Limited; } } public override NotTrackingReason notTrackingReason { get { if (!m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.PositionValid) || !m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.OrientationValid)) return NotTrackingReason.Initializing; if (m_trackingStateFlags.HasFlag(NativeSpaceLocationFlags.All)) return NotTrackingReason.None; return NotTrackingReason.Relocalizing; } } public override bool matchFrameRateEnabled { get => false; } public override bool matchFrameRateRequested { get => false; } public override int frameRate { get => 0; } // Framerate is not supported unless matchFrameRateEnabled = true public override Feature requestedFeatures { get => m_requestedBaseFeatures | m_requestedTrackingMode; } public override IntPtr nativePtr { get => IntPtr.Zero; } public override Guid sessionId { get => m_sessionGuid; } /// /// Get the session's availability, such as whether the platform supports XR. /// SessionAvailability.None: "Default value. The availability is unknown." /// SessionAvailability.Supported: "The current device is AR capable (but might require a software update)." /// SessionAvailability.Installed: "The required AR software is installed on the device." /// public override Promise GetAvailabilityAsync() { if (OpenXRContext.Current.SystemId != 0) { return Promise.CreateResolvedPromise(SessionAvailability.Supported | SessionAvailability.Installed); } return Promise.CreateResolvedPromise(SessionAvailability.None); } public override NativeArray GetConfigurationDescriptors(Allocator allocator) { // Sessions may have multiple 'modes' of operation, each with a different set of capabilities. // Our session only has one such mode, so this array will always be one ConfigurationDescriptor long. var nativeArray = new NativeArray(1, allocator, NativeArrayOptions.UninitializedMemory); nativeArray[0] = new ConfigurationDescriptor(IntPtr.Zero, m_allSupportedFeatures, 0); return nativeArray; } public override void OnApplicationPause() { } public override void OnApplicationResume() { } // Only one configuration is supported, so the configuration settings can be inferred in the standard update. public override void Update(XRSessionUpdateParams updateParams, Configuration configuration) => Update(updateParams); public override void Update(XRSessionUpdateParams updateParams) { m_trackingStateFlags = NativeLib.GetPrimaryViewTrackingState(); } } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void RegisterDescriptor() { XRSessionSubsystemDescriptor.RegisterDescriptor(new XRSessionSubsystemDescriptor.Cinfo { id = Id, providerType = typeof(SessionSubsystem.OpenXRProvider), subsystemTypeOverride = typeof(SessionSubsystem), supportsInstall = false, supportsMatchFrameRate = false }); } }; internal class SessionSubsystemController : SubsystemController { private static List s_SessionDescriptors = new List(); public SessionSubsystemController(IOpenXRContext context) : base(context) { } public override void OnSubsystemCreate(ISubsystemPlugin plugin) { plugin.CreateSubsystem(s_SessionDescriptors, SessionSubsystem.Id); } public override void OnSubsystemDestroy(ISubsystemPlugin plugin) { plugin.DestroySubsystem(); } } }