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();
}
}