using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Android; using UnityEngine.XR.OpenXR.Features; namespace UnityEngine.XR.OpenXR { public partial class OpenXRSettings { /// /// Stereo rendering mode. /// public enum RenderMode { /// /// Submit separate draw calls for each eye. /// MultiPass, /// /// Submit one draw call for both eyes. /// SinglePassInstanced, }; /// /// Stereo rendering mode. /// [SerializeField] private RenderMode m_renderMode = RenderMode.SinglePassInstanced; /// /// Runtime Stereo rendering mode. /// public RenderMode renderMode { get { if (OpenXRLoaderBase.Instance != null) return Internal_GetRenderMode(); else return m_renderMode; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetRenderMode(value); else m_renderMode = value; } } [SerializeField] private bool m_autoColorSubmissionMode = true; /// /// Automatically select the default color submission mode. /// public bool autoColorSubmissionMode { get => m_autoColorSubmissionMode; set => m_autoColorSubmissionMode = value; } [SerializeField] private ColorSubmissionModeList m_colorSubmissionModes = new ColorSubmissionModeList(); /// /// Gets or sets the preference for what color format the OpenXR display swapchain should use. /// public ColorSubmissionModeGroup[] colorSubmissionModes { get { if (m_autoColorSubmissionMode) return new[] { OpenXRSettings.kDefaultColorMode }; if (OpenXRLoaderBase.Instance != null) { int arraySize = Internal_GetColorSubmissionModes(null, 0); int[] intModes = new int[arraySize]; Internal_GetColorSubmissionModes(intModes, arraySize); return intModes.Select(i => (ColorSubmissionModeGroup)i).ToArray(); } else return m_colorSubmissionModes.m_List; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetColorSubmissionModes( value.Select(e => (int)e).ToArray(), value.Length ); else m_colorSubmissionModes.m_List = value; } } /// /// Runtime Depth submission mode. /// public enum DepthSubmissionMode { /// /// No depth is submitted to the OpenXR compositor. /// None, /// /// 16-bit depth is submitted to the OpenXR compositor. /// Depth16Bit, /// /// 24-bit depth is submitted to the OpenXR compositor. /// Depth24Bit, } /// /// Different Internal Unity APIs to use in the backend. /// public enum BackendFovationApi : byte { /// /// Use the legacy Built-in API for Foveation. This is the only option for Built-in. /// Legacy = 0, /// /// Use the Foveation for SRP API. /// SRPFoveation = 1, } /// /// Space Warp motion vector texture format. /// public enum SpaceWarpMotionVectorTextureFormat { /// /// RGBA16f texture format /// RGBA16f, /// /// RG16f texture format /// RG16f, } #if UNITY_ANDROID private string[] m_eyeTrackingPermissionsToRequest = new string[] { "com.oculus.permission.EYE_TRACKING", "android.permission.EYE_TRACKING", "android.permission.EYE_TRACKING_FINE" }; #endif /// /// Enables XR_KHR_composition_layer_depth if possible and resolves or submits depth to OpenXR runtime. /// [SerializeField] private DepthSubmissionMode m_depthSubmissionMode = DepthSubmissionMode.None; static void PermissionGrantedCallback(string permissionName) { #if UNITY_ANDROID foreach (var permission in GetInstance(true).m_eyeTrackingPermissionsToRequest) { if (permissionName == permission) { Internal_SetHasEyeTrackingPermissions(true); } } #endif } /// /// Enables XR_KHR_composition_layer_depth if possible and resolves or submits depth to OpenXR runtime. /// public DepthSubmissionMode depthSubmissionMode { get { if (OpenXRLoaderBase.Instance != null) return Internal_GetDepthSubmissionMode(); else return m_depthSubmissionMode; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetDepthSubmissionMode(value); else m_depthSubmissionMode = value; } } /// /// Space Warp motion vector texture format (default is RGBA16f). /// [SerializeField] private SpaceWarpMotionVectorTextureFormat m_spacewarpMotionVectorTextureFormat = SpaceWarpMotionVectorTextureFormat.RGBA16f; /// /// Selects the motion vector texture format for Space Warp. /// public SpaceWarpMotionVectorTextureFormat spacewarpMotionVectorTextureFormat { get { if (OpenXRLoaderBase.Instance != null) return Internal_GetSpaceWarpMotionVectorTextureFormat(); else return m_spacewarpMotionVectorTextureFormat; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetSpaceWarpMotionVectorTextureFormat(value); else m_spacewarpMotionVectorTextureFormat = value; } } [SerializeField] private bool m_optimizeBufferDiscards = false; /// /// Optimization that allows 4x MSAA textures to be memoryless on Vulkan /// public bool optimizeBufferDiscards { get { return m_optimizeBufferDiscards; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetOptimizeBufferDiscards(value); else m_optimizeBufferDiscards = value; } } private void ApplyRenderSettings() { Internal_SetSymmetricProjection(m_symmetricProjection); #if UNITY_6000_1_OR_NEWER Internal_SetOptimizeMultiviewRenderRegions(m_optimizeMultiviewRenderRegions); #endif #if UNITY_2023_2_OR_NEWER Internal_SetUsedFoveatedRenderingApi(m_foveatedRenderingApi); #endif Internal_SetRenderMode(m_renderMode); Internal_SetColorSubmissionModes( m_colorSubmissionModes.m_List.Select(e => (int)e).ToArray(), m_colorSubmissionModes.m_List.Length ); Internal_SetDepthSubmissionMode(m_depthSubmissionMode); Internal_SetSpaceWarpMotionVectorTextureFormat(m_spacewarpMotionVectorTextureFormat); Internal_SetOptimizeBufferDiscards(m_optimizeBufferDiscards); #if UNITY_ANDROID // Only Android need specific permissions for eye tracking, for now var foveatedRenderingFreature = GetFeature(); if (m_eyeTrackingPermissionsToRequest != null && m_eyeTrackingPermissionsToRequest.Length > 0 && (Internal_HasRequestedEyeTrackingPermissions() || (foveatedRenderingFreature != null && foveatedRenderingFreature.enabled))) { var permissionCallbacks = new PermissionCallbacks(); permissionCallbacks.PermissionGranted += PermissionGrantedCallback; Permission.RequestUserPermissions(m_eyeTrackingPermissionsToRequest, permissionCallbacks); } #endif } [SerializeField] private bool m_symmetricProjection = false; #if UNITY_6000_1_OR_NEWER [SerializeField] private bool m_optimizeMultiviewRenderRegions = false; #endif #if UNITY_2023_2_OR_NEWER [SerializeField] private BackendFovationApi m_foveatedRenderingApi = BackendFovationApi.Legacy; #endif /// /// If enabled, when the application begins it will create a stereo symmetric view that has the eye buffer resolution change based on the IPD. /// Provides a performance benefit across all IPDs. /// public bool symmetricProjection { get { return m_symmetricProjection; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetSymmetricProjection(value); else m_symmetricProjection = value; } } #if UNITY_6000_1_OR_NEWER /// /// Activates Multiview Render Regions optimizations at application start. /// Requires Vulkan as the Graphics API, Render Mode set to Multi-view and Symmetric rendering enabled. /// public bool optimizeMultiviewRenderRegions { get { return m_optimizeMultiviewRenderRegions; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetOptimizeMultiviewRenderRegions(value); else m_optimizeMultiviewRenderRegions = value; } } #endif /// /// Different APIs to use in the backend. /// On Built-in Render Pipeline, only Legacy will be used. /// On Scriptable Render Pipelines, it is highly recommended to use the SRPFoveation API. More textures will use FDM with the SRPFoveation API. /// #if UNITY_2023_2_OR_NEWER public BackendFovationApi foveatedRenderingApi { get { if (OpenXRLoaderBase.Instance != null) return Internal_GetUsedFoveatedRenderingApi(); else return m_foveatedRenderingApi; } set { if (OpenXRLoaderBase.Instance != null) Internal_SetUsedFoveatedRenderingApi(value); else m_foveatedRenderingApi = value; } } #else public BackendFovationApi foveatedRenderingApi => BackendFovationApi.Legacy; #endif private const string LibraryName = "UnityOpenXR"; [DllImport(LibraryName, EntryPoint = "NativeConfig_SetRenderMode")] private static extern void Internal_SetRenderMode(RenderMode renderMode); [DllImport(LibraryName, EntryPoint = "NativeConfig_GetRenderMode")] private static extern RenderMode Internal_GetRenderMode(); [DllImport(LibraryName, EntryPoint = "NativeConfig_SetDepthSubmissionMode")] private static extern void Internal_SetDepthSubmissionMode( DepthSubmissionMode depthSubmissionMode ); [DllImport(LibraryName, EntryPoint = "NativeConfig_GetDepthSubmissionMode")] private static extern DepthSubmissionMode Internal_GetDepthSubmissionMode(); [DllImport(LibraryName, EntryPoint = "NativeConfig_SetSpaceWarpMotionVectorTextureFormat")] private static extern void Internal_SetSpaceWarpMotionVectorTextureFormat( SpaceWarpMotionVectorTextureFormat spaceWarpMotionVectorTextureFormat ); [DllImport(LibraryName, EntryPoint = "NativeConfig_GetSpaceWarpMotionVectorTextureFormat")] private static extern SpaceWarpMotionVectorTextureFormat Internal_GetSpaceWarpMotionVectorTextureFormat(); [DllImport(LibraryName, EntryPoint = "NativeConfig_SetSymmetricProjection")] private static extern void Internal_SetSymmetricProjection([MarshalAs(UnmanagedType.I1)] bool enabled); [DllImport(LibraryName, EntryPoint = "NativeConfig_SetOptimizeMultiviewRenderRegions")] private static extern void Internal_SetOptimizeMultiviewRenderRegions([MarshalAs(UnmanagedType.I1)] bool enabled); [DllImport(LibraryName, EntryPoint = "NativeConfig_SetOptimizeBufferDiscards")] private static extern void Internal_SetOptimizeBufferDiscards([MarshalAs(UnmanagedType.I1)] bool enabled); [DllImport(LibraryName, EntryPoint = "OculusFoveation_SetUsedApi")] private static extern void Internal_SetUsedFoveatedRenderingApi(BackendFovationApi api); [DllImport(LibraryName, EntryPoint = "OculusFoveation_GetUsedApi")] internal static extern BackendFovationApi Internal_GetUsedFoveatedRenderingApi(); [DllImport(LibraryName, EntryPoint = "OculusFoveation_HasRequestedEyeTrackingPermissions")] [return: MarshalAs(UnmanagedType.U1)] internal static extern bool Internal_HasRequestedEyeTrackingPermissions(); [DllImport(LibraryName, EntryPoint = "OculusFoveation_GetHasEyeTrackingPermissions")] [return: MarshalAs(UnmanagedType.U1)] internal static extern bool Internal_GetHasEyeTrackingPermissions(); [DllImport(LibraryName, EntryPoint = "OculusFoveation_SetHasEyeTrackingPermissions")] internal static extern void Internal_SetHasEyeTrackingPermissions([MarshalAs(UnmanagedType.I1)] bool value); [DllImport(LibraryName, EntryPoint = "NativeConfig_SetColorSubmissionMode")] private static extern void Internal_SetColorSubmissionMode( ColorSubmissionModeGroup[] colorSubmissionMode ); [DllImport(LibraryName, EntryPoint = "NativeConfig_SetColorSubmissionModes")] private static extern void Internal_SetColorSubmissionModes( int[] colorSubmissionMode, int arraySize ); [DllImport(LibraryName, EntryPoint = "NativeConfig_GetColorSubmissionModes")] private static extern int Internal_GetColorSubmissionModes( [Out] int[] colorSubmissionMode, int arraySize ); [DllImport("UnityOpenXR", EntryPoint = "NativeConfig_GetIsUsingLegacyXRDisplay")] [return: MarshalAs(UnmanagedType.U1)] private static extern bool Internal_GetIsUsingLegacyXRDisplay(); } }