Last active
March 7, 2024 17:38
-
-
Save mikeskydev/8e27668eade137a1085843868fbc6269 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Copyright Icosa Foundation | |
using System; | |
using System.Runtime.InteropServices; | |
using AOT; | |
using UnityEditor; | |
using UnityEngine; | |
using UnityEngine.XR.OpenXR; | |
using UnityEngine.XR.OpenXR.Features; | |
using System.Collections; | |
using Unity.Collections; | |
#if UNITY_EDITOR | |
using UnityEditor.XR.OpenXR.Features; | |
#endif | |
namespace IcosaFoundation.OpenXR.Unity.FBDisplayRefreshRate | |
{ | |
/// <summary> | |
/// Example feature showing how to intercept a single OpenXR function. | |
/// </summary> | |
#if UNITY_EDITOR | |
[OpenXRFeature(UiName = "Facebook Display Refresh Rate", | |
BuildTargetGroups = new []{BuildTargetGroup.Standalone, BuildTargetGroup.WSA, BuildTargetGroup.Android}, | |
Company = "Icosa Foundation", | |
Desc = "Implement XR_FB_display_refresh_rate without OVR SDK", | |
OpenxrExtensionStrings = "XR_FB_display_refresh_rate", | |
Version = "0.0.1", | |
FeatureId = featureId)] | |
#endif | |
public class FBDisplayRefreshRateFeature : OpenXRFeature | |
{ | |
public const string featureId = "foundation.icosa.openxr-facebook-displayrefreshrate"; | |
private static ulong XrSession = 0; | |
private static ulong XrInstance = 0; | |
protected override bool OnInstanceCreate(ulong xrInstance) | |
{ | |
XrInstance = xrInstance; | |
var success = LoadBindings(); | |
return true; | |
} | |
protected override void OnSessionCreate(ulong xrSession) | |
{ | |
XrSession = xrSession; | |
} | |
public static float[] GetDisplayRefreshRates() | |
{ | |
if(XrSession == 0) | |
{ | |
return null; | |
} | |
var success = xrEnumerateDisplayRefreshRatesFB(XrSession, 0, out int displayRefreshRateCapacity, null); | |
if(success == XrResult.Success) | |
{ | |
var displayRefreshRates = new float[displayRefreshRateCapacity]; | |
success = xrEnumerateDisplayRefreshRatesFB(XrSession, displayRefreshRateCapacity, out displayRefreshRateCapacity, displayRefreshRates); | |
if(success == XrResult.Success) | |
{ | |
return displayRefreshRates; | |
} | |
} | |
return null; | |
} | |
public static float RefreshRate | |
{ | |
get { return GetRefreshRate(); } | |
set { SetRefreshRate(value); } | |
} | |
public static float GetRefreshRate() | |
{ | |
if(XrSession == 0) | |
{ | |
return 0.0f; | |
} | |
var success = xrGetDisplayRefreshRateFB(XrSession, out var displayRefreshRate); | |
if (success == XrResult.Success) | |
{ | |
return displayRefreshRate; | |
} | |
return 0.0f; | |
} | |
public static bool SetRefreshRate(float targetRefreshRate) | |
{ | |
if(XrSession == 0) | |
{ | |
return false; | |
} | |
var success = xrRequestDisplayRefreshRateFB(XrSession, targetRefreshRate); | |
if(success == XrResult.Success) | |
{ | |
return true; | |
} | |
return false; | |
} | |
private delegate ulong GetInstanceProcAddrDelegate(ulong instance, string procName, out IntPtr procAddr); | |
private static IntPtr GetFunction(string functionName) | |
{ | |
var getInstanceProcAddr = Marshal.GetDelegateForFunctionPointer<GetInstanceProcAddrDelegate>(xrGetInstanceProcAddr); | |
ulong result = getInstanceProcAddr(XrInstance, functionName, out var returnPtr); | |
if (result < 0) | |
{ | |
Debug.LogWarning($"Failed to find {functionName}"); | |
return IntPtr.Zero; | |
} | |
return returnPtr; | |
} | |
#region OpenXR native bindings and types | |
enum XrStructureType : UInt64 | |
{ | |
XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB = 0x1000101000 | |
} | |
enum XrResult : Int64 | |
{ | |
Success = 0, | |
XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB = -0x1000101000 | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
struct XrEventDataDisplayRefreshRateChangedFB | |
{ | |
public XrStructureType type; | |
public IntPtr next; | |
public float fromDisplayRefreshRate; | |
public float toDisplayRefreshRate; | |
public XrEventDataDisplayRefreshRateChangedFB(float fromDisplayRefreshRate, float toDisplayRefreshRate) | |
{ | |
type = XrStructureType.XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB; | |
next = IntPtr.Zero; | |
this.fromDisplayRefreshRate = fromDisplayRefreshRate; | |
this.toDisplayRefreshRate = toDisplayRefreshRate; | |
} | |
} | |
delegate XrResult del_xrEnumerateDisplayRefreshRatesFB(ulong session, [In] int displayRefreshRateCapacityInput, out int displayRefreshRateCapacityOutput, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] float[] displayRefreshRates); | |
delegate XrResult del_xrGetDisplayRefreshRateFB (ulong session, out float displayRefreshRate); | |
delegate XrResult del_xrRequestDisplayRefreshRateFB (ulong session, float displayRefreshRate); | |
static del_xrEnumerateDisplayRefreshRatesFB xrEnumerateDisplayRefreshRatesFB; | |
static del_xrGetDisplayRefreshRateFB xrGetDisplayRefreshRateFB; | |
static del_xrRequestDisplayRefreshRateFB xrRequestDisplayRefreshRateFB; | |
bool LoadBindings() | |
{ | |
xrEnumerateDisplayRefreshRatesFB = Marshal.GetDelegateForFunctionPointer<del_xrEnumerateDisplayRefreshRatesFB>(GetFunction("xrEnumerateDisplayRefreshRatesFB")); | |
xrGetDisplayRefreshRateFB = Marshal.GetDelegateForFunctionPointer<del_xrGetDisplayRefreshRateFB> (GetFunction("xrGetDisplayRefreshRateFB")); | |
xrRequestDisplayRefreshRateFB = Marshal.GetDelegateForFunctionPointer<del_xrRequestDisplayRefreshRateFB> (GetFunction("xrRequestDisplayRefreshRateFB")); | |
return | |
xrEnumerateDisplayRefreshRatesFB != null && | |
xrGetDisplayRefreshRateFB != null && | |
xrRequestDisplayRefreshRateFB != null; | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment