VR4Medical/ICI/Library/PackageCache/com.unity.xr.openxr@3903c1059bcf/Runtime/CompositionLayers/OpenXRCustomLayerHandler.cs
2025-07-29 13:45:50 +03:00

590 lines
29 KiB
C#

#if XR_COMPOSITION_LAYERS
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.XR.CompositionLayers.Extensions;
using Unity.XR.CompositionLayers.Layers;
using Unity.XR.CompositionLayers.Services;
using UnityEngine.XR.OpenXR.NativeTypes;
#if UNITY_VIDEO
using UnityEngine.Video;
#endif
namespace UnityEngine.XR.OpenXR.CompositionLayers
{
/// <summary>
/// Provides a base implementation for the <see cref="OpenXRLayerProvider.ILayerHandler"/> interface.
/// You can implement the required methods of this abstract class to create a concrete layer handler.
/// </summary>
/// <remarks>
/// The <see cref="OpenXRLayerProvider.ILayerHandler"/> methods that this class implements handle adding
/// and removing composition layers from native arrays, swap chain creation dispatching and other tasks
/// required by the Unity side of the API.
///
/// The abstract methods that you must implement handle the custom aspects of your layer. These methods include:
///
/// * <see cref="CreateSwapchain(CompositionLayerManager.LayerInfo, out SwapchainCreateInfo)"/>
/// * <see cref="CreateNativeLayer(CompositionLayerManager.LayerInfo, OpenXRCustomLayerHandler{T}.SwapchainCreatedOutput, out T)"/>
/// * <see cref="ModifyNativeLayer(CompositionLayerManager.LayerInfo, ref T)"/>
///
/// You are not required to implement a custom layer handler based on this abstract class, but doing so should be
/// easier than implementing the <see cref="OpenXRLayerProvider.ILayerHandler"/> interface in its entirety.
///
/// You must register your concrete layer handler object with
/// <see cref="OpenXRLayerProvider.RegisterLayerHandler(Type, OpenXRLayerProvider.ILayerHandler)"/>.
/// </remarks>
/// <typeparam name="T">The native OpenXR structure of the composition layer to handle.</typeparam>
public abstract class OpenXRCustomLayerHandler<T> : OpenXRLayerProvider.ILayerHandler, IDisposable where T : struct
{
/// <summary>
/// Container for swapchain related information that may be needed during the creation of the native OpenXR composition layer struct.
/// </summary>
protected struct SwapchainCreateInfo
{
/// <summary>
/// Native structure for the swapchain creation info.
/// </summary>
public XrSwapchainCreateInfo nativeStruct;
/// <summary>
/// Tells if swapchain is using an external surface.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool isExternalSurface;
/// <summary>
/// Tells if swapchain should be stereo.
/// </summary>
public bool isStereo;
/// <summary>
/// Initializes and returns an instance of SwapchainCreateInfo with the provided parameters.
/// </summary>
/// <param name="xrSwapchainCreateInfo">Native structure for the swapchain creation info.</param>
/// <param name="isExternalSurface">Tells if swapchain is using an external surface.</param>
/// <param name="isStereo">Tells if swapchain should be stereo.</param>
public SwapchainCreateInfo(XrSwapchainCreateInfo xrSwapchainCreateInfo, bool isExternalSurface = false, bool isStereo = false)
{
this.nativeStruct = xrSwapchainCreateInfo;
this.isExternalSurface = isExternalSurface;
this.isStereo = isStereo;
}
/// <summary>
/// Implicit conversion with just a native XrSwapchainCreateInfo struct.
/// </summary>
/// <param name="createInfo">The native struct to convert.</param>
public static implicit operator SwapchainCreateInfo(XrSwapchainCreateInfo createInfo) => new SwapchainCreateInfo(createInfo);
}
/// <summary>
/// Container for swapchain related information that may be needed during the creation of the native OpenXR composition layer struct.
/// </summary>
protected struct SwapchainCreatedOutput
{
/// <summary>
/// The handle of the created swapchain.
/// Can be used to initialize the swapchain member of a native OpenXR composition layer struct.
/// </summary>
public ulong handle;
/// <summary>
/// The second handle of the created stereo swapchain.
/// Can be used to initialize the swapchain member of a native OpenXR composition layer struct.
/// </summary>
public ulong secondStereoHandle;
}
/// <summary>
/// Container for grouping render information for each compostion layer.
/// </summary>
class LayerRenderInfo
{
public RenderTexture RenderTexture;
public Texture Texture;
#if UNITY_VIDEO
public VideoPlayer videoPlayer;
#endif
public MeshCollider meshCollider;
}
/// <summary>
/// Initializes and returns an instance of this <c>OpenXRCustomLayerHandler&lt;T&gt;</c> while also setting the singleton instance member.
/// </summary>
protected OpenXRCustomLayerHandler() => Instance = this;
/// <summary>
/// Singleton instance of this specific handler.
/// </summary>
protected static OpenXRCustomLayerHandler<T> Instance;
/// <summary>
/// Deinitializes this instance of c>OpenXRCustomLayerHandler&lt;T&gt;</c>.
/// </summary>
~OpenXRCustomLayerHandler() => Dispose(false);
/// <summary>
/// Override this method to create the <see cref="XrSwapchainCreateInfo"/> struct that is passed to OpenXR
/// to create a swapchain.
/// </summary>
/// <remarks>
/// To add extensions when constructing the <see cref="XrSwapchainCreateInfo"/> struct, initialize
/// the <c>Next</c> pointer with
/// <see cref="OpenXRLayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>.
/// </remarks>
/// <example>
/// Constructs an XrSwapchainCreateInfo struct with some members using component data.
/// <code>
/// <![CDATA[
/// protected override bool CreateSwapchain(CompositionLayerManager.LayerInfo layerInfo, out SwapchainCreateInfo swapchainCreateInfo)
/// {
/// var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
/// unsafe
/// {
/// swapchainCreateInfo = new XrSwapchainCreateInfo()
/// {
/// Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
/// Next = OpenXRLayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Swapchain),
/// CreateFlags = 0,
/// UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
/// Format = OpenXRLayerUtility.GetDefaultColorFormat(),
/// SampleCount = 1,
/// Width = (uint)texturesExtension.LeftTexture.width,
/// Height = (uint)texturesExtension.LeftTexture.height,
/// FaceCount = 1,
/// ArraySize = 1,
/// MipCount = (uint)texturesExtension.LeftTexture.mipmapCount,
/// };
/// }
/// return true;
/// }
/// ]]>
/// </code>
/// </example>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
/// that was just created.</param>
/// <param name="swapchainCreateInfo"> An <c>XrSwapchainCreateInfo</c> object created and initialized by the concrete implementation of this method.</returns>
/// <returns> A bool indicating success or failure.</returns>
protected abstract bool CreateSwapchain(CompositionLayerManager.LayerInfo layerInfo, out SwapchainCreateInfo swapchainCreateInfo);
/// <summary>
/// Override this method to create the native composition layer struct of type T that is passed to OpenXR.
/// A swapchain info struct is provided so your layer handler has access to any needed swapchain information.
/// </summary>
/// <remarks>
/// To add extensions when constructing the <see cref="XrSwapchainCreateInfo"/> struct, initialize
/// the <c>Next</c> pointer with <see cref="OpenXRLayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>.
///
/// If your struct needs any XrSpace relative info you can use <see cref="OpenXRLayerUtility.GetCurrentAppSpace"/>
/// to get the current app space.
/// </remarks>
/// <example>
/// Constructs an XrCompositionLayerQuad struct with some members using component data.
/// <code>
/// <![CDATA[
/// protected override bool CreateNativeLayer(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerQuad nativeLayer)
/// {
/// var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
/// var transform = layerInfo.Layer.GetComponent<Transform>();
///
/// unsafe
/// {
/// var data = layerInfo.Layer.LayerData as QuadLayerData;
///
/// nativeLayer = new XrCompositionLayerQuad()
/// {
/// Type = 36,
/// Next = OpenXRLayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer),
/// LayerFlags = 0x00000002,
/// Space = OpenXRLayerUtility.GetCurrentAppSpace(),
/// EyeVisibility = 0,
/// SubImage = new SwapchainSubImage()
/// {
/// Swapchain = swapchainOutput.handle,
/// ImageRect = new XrRect2Di()
/// {
/// offset = new XrOffset2Di() { x = 0, y = 0 },
/// extent = new XrExtent2Di()
/// {
/// width = texturesExtension.LeftTexture.width,
/// height = texturesExtension.LeftTexture.height
/// }
/// },
/// ImageArrayIndex = 0
/// },
/// Pose = new XrPosef(transform.position, transform.rotation),
/// Size = new XrExtend2Df()
/// {
/// width = data.GetScaledSize(transform.lossyScale).x,
/// height = data.GetScaledSize(transform.lossyScale).y
/// }
/// };
/// }
/// return true;
/// }
/// ]]>
/// </code>
/// </example>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
/// that was just created.</param>
/// <param name="swapchainOutput"> Information regarding the swapchain that was created for this layer,
/// such as the associated swapchain handle.</param>
/// <param name="nativeLayer"> An object of type T that is created and initialized by the concrete implementation of this method.</returns>
/// <returns> A bool indicating success or failure.</returns>
protected abstract bool CreateNativeLayer(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput, out T nativeLayer);
/// <summary>
/// Override this method to modify a native composition layer struct in response to changes on the associated
/// <see cref="Unity.XR.CompositionLayers.Layers.LayerData"/> object or any extension components on the
/// <see cref="Unity.XR.CompositionLayers.CompositionLayer"/> GameObject.
/// </summary>
/// <remarks>
/// You must reinitialize the Next pointer with <see cref="OpenXRLayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>
/// to get any potential updates from extension components.
/// </remarks>
/// <example>
/// Modifies an XrCompositionLayerQuad struct with new transform and extension information.
/// <code>
/// <![CDATA[
/// protected override bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerQuad nativeLayer)
/// {
/// var data = layerInfo.Layer.LayerData as QuadLayerData;
/// var transform = layerInfo.Layer.GetComponent<Transform>();
///
/// nativeLayer.Pose = new XrPosef(transform.position, transform.rotation);
/// nativeLayer.Size = new XrExtend2Df()
/// {
/// width = data.GetScaledSize(transform.lossyScale).x,
/// height = data.GetScaledSize(transform.lossyScale).y
/// };
///
/// unsafe
/// {
/// nativeLayer.Next = OpenXRLayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
/// }
/// return true;
/// }
/// ]]>
/// </code>
/// </example>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition
/// layer that was modified.</param>
/// <param name="nativeLayer"> A reference to the native OpenXR structure of the composition layer that was modified.
/// The concrete implementation of this method should update the values of the structure as appropriate.</param>
/// <returns> A bool indicating success or failure.</returns>
protected abstract bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref T nativeLayer);
/// <summary>
/// Mapping of instance ids and native layer structs to help determine what layers are currently set to be active.
/// </summary>
protected Dictionary<int, T> m_nativeLayers = new Dictionary<int, T>();
/// <summary>
/// Thread safe queue used to dispatch callbacks that may come from other threads such as the swapchain creation
/// on the graphics thread.
/// </summary>
protected ConcurrentQueue<Action> actionsForMainThread = new ConcurrentQueue<Action>();
Dictionary<int, LayerRenderInfo> m_renderInfos = new Dictionary<int, LayerRenderInfo>();
Dictionary<int, CompositionLayerManager.LayerInfo> m_layerInfos = new Dictionary<int, CompositionLayerManager.LayerInfo>();
NativeArray<T> m_ActiveNativeLayers;
NativeArray<int> m_ActiveNativeLayerOrders;
int m_ActiveNativeLayerCount;
/// <summary>
/// Implements the <see cref="OpenXRLayerProvider.ILayerHandler"/> method that is called by the
/// <see cref="OpenXRLayerProvider"/> during the Unity update loop.
/// </summary>
/// <remarks>
/// This implementation carries out two tasks. It dequeues actions for the main thread like dispatch when
/// the swapchain has been
/// created and it adds all the active layers to the <c>endFrameInfo</c> struct in the native UnityOpenXR lib.
/// </remarks>
public virtual void OnUpdate()
{
while (actionsForMainThread.Count > 0)
{
if (actionsForMainThread.TryDequeue(out Action action))
action();
}
unsafe
{
if (m_ActiveNativeLayerCount > 0)
OpenXRLayerUtility.AddActiveLayersToEndFrame(m_ActiveNativeLayers.GetUnsafePtr(), m_ActiveNativeLayerOrders.GetUnsafePtr(), m_ActiveNativeLayerCount, UnsafeUtility.SizeOf<T>());
}
m_ActiveNativeLayerCount = 0;
}
/// <summary>
/// Implements the <see cref="OpenXRLayerProvider.ILayerHandler"/> method that is called by the
/// <see cref="OpenXRLayerProvider"/> when a new layer has been created.
/// This implementation triggers the creation of a swapchain before the actual native layer struct is created.
/// </summary>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
/// being created.</param>
public void CreateLayer(CompositionLayerManager.LayerInfo layerInfo)
{
CreateSwapchainAsync(layerInfo);
}
/// <summary>
/// Implements the <see cref="OpenXRLayerProvider.ILayerHandler"/> method that is called by the
/// <see cref="OpenXRLayerProvider"/> when a layer or attached extension has been modified.
/// This implementation asks the subclass for any changes that must be made to the layer via
/// <see cref="ModifyNativeLayer(CompositionLayerManager.LayerInfo, ref T)"/>
/// by sending a reference to the native layer struct.
/// </summary>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
/// that was modified.</param>
public virtual void ModifyLayer(CompositionLayerManager.LayerInfo layerInfo)
{
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
if (!m_nativeLayers.TryGetValue(layerInfo.Id, out var nativeLayer))
{
if (texturesExtension != null && texturesExtension.TextureAdded)
{
texturesExtension.TextureAdded = false;
CreateLayer(layerInfo);
}
return;
}
var success = ModifyNativeLayer(layerInfo, ref nativeLayer);
if (success)
m_nativeLayers[layerInfo.Id] = nativeLayer;
}
/// <summary>
/// Implements the <see cref="OpenXRLayerProvider.ILayerHandler"/> method that is called by the
/// <see cref="OpenXRLayerProvider"/> when a layer is destroyed or disabled.
/// </summary>
/// <param name="removedLayerId"> The instance id of the CompositionLayer component that was removed.</param>
public virtual void RemoveLayer(int removedLayerId)
{
OpenXRLayerUtility.ReleaseSwapchain(removedLayerId);
m_nativeLayers.Remove(removedLayerId);
m_layerInfos.Remove(removedLayerId);
m_renderInfos.Remove(removedLayerId);
}
/// <summary>
/// Implements the <see cref="OpenXRLayerProvider.ILayerHandler"/> method that is called by the
/// <see cref="OpenXRLayerProvider"/> when a layer is considered to be currently active.
/// </summary>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
/// being set to active.</param>
public virtual void SetActiveLayer(CompositionLayerManager.LayerInfo layerInfo)
{
if (!m_nativeLayers.TryGetValue(layerInfo.Id, out var nativeLayer))
return;
var success = ActiveNativeLayer(layerInfo, ref nativeLayer);
if (!success)
return;
m_nativeLayers[layerInfo.Id] = nativeLayer;
ResizeNativeArrays();
m_ActiveNativeLayers[m_ActiveNativeLayerCount] = m_nativeLayers[layerInfo.Id];
m_ActiveNativeLayerOrders[m_ActiveNativeLayerCount] = layerInfo.Layer.Order;
++m_ActiveNativeLayerCount;
}
/// <summary>
/// Implements method from <see cref="IDisposable"/> that is called by the <see cref="OpenXRLayerProvider"/>
/// when this custom layer handler instance is disposed.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Clears all maps and disposes any created native arrays.
/// </summary>
/// <param name="disposing">Determines if this method was called from the Dispose() method or the finalizer.</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
m_layerInfos.Clear();
m_nativeLayers.Clear();
m_renderInfos.Clear();
}
if (m_ActiveNativeLayers.IsCreated)
m_ActiveNativeLayers.Dispose();
if (m_ActiveNativeLayerOrders.IsCreated)
m_ActiveNativeLayerOrders.Dispose();
}
/// <summary>
/// Calls <see cref="CreateSwapchain(CompositionLayerManager.LayerInfo, out SwapchainCreateInfo)"/> to create a
/// <see cref="SwapchainCreateInfo"/> struct that is then passed to the
/// UnityOpenXR lib to actually create the swapchain on the graphics thread.
/// The static <see cref="OnCreatedSwapchainCallback(int, ulong)"/> method is passed as a callback and invoked when
/// the swapchain has been created.
/// </summary>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
/// that was just created.</param>
protected virtual void CreateSwapchainAsync(CompositionLayerManager.LayerInfo layerInfo)
{
m_layerInfos[layerInfo.Id] = layerInfo;
var success = CreateSwapchain(layerInfo, out var swapChainInfo);
if (!success)
return;
if (swapChainInfo.isStereo)
OpenXRLayerUtility.CreateStereoSwapchain(layerInfo.Id, swapChainInfo.nativeStruct, OnCreatedStereoSwapchainCallback);
else
OpenXRLayerUtility.CreateSwapchain(layerInfo.Id, swapChainInfo.nativeStruct, swapChainInfo.isExternalSurface, OnCreatedSwapchainCallback);
}
/// <summary>
/// This method is dispatched to the main thread inside <see cref="OnCreatedSwapchainCallback(int, ulong)"/>
/// and asks this subclass to create the native layer struct by invoking
/// <see cref="CreateNativeLayer(CompositionLayerManager.LayerInfo, SwapchainCreatedOutput, out T)"/>.
/// </summary>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
/// that was just created.</param>
/// <param name="swapchainOutput"> Information regarding the swapchain that was created for this layer, such as
/// the associated swapchain handle.</param>
protected virtual void OnCreatedSwapchain(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput)
{
var success = CreateNativeLayer(layerInfo, swapchainOutput, out var nativeLayer);
if (success)
m_nativeLayers[layerInfo.Id] = nativeLayer;
}
/// <summary>
/// Ensures that the native arrays are of the same size as the m_nativeLayers map.
/// </summary>
protected virtual void ResizeNativeArrays()
{
if (!m_ActiveNativeLayers.IsCreated && !m_ActiveNativeLayerOrders.IsCreated)
{
m_ActiveNativeLayers = new NativeArray<T>(m_nativeLayers.Count, Allocator.Persistent);
m_ActiveNativeLayerOrders = new NativeArray<int>(m_nativeLayers.Count, Allocator.Persistent);
return;
}
Assertions.Assert.AreEqual(m_ActiveNativeLayers.Length, m_ActiveNativeLayerOrders.Length);
if (m_ActiveNativeLayers.Length < m_nativeLayers.Count)
{
var newLayerArray = new NativeArray<T>(m_nativeLayers.Count, Allocator.Persistent);
NativeArray<T>.Copy(m_ActiveNativeLayers, newLayerArray, m_ActiveNativeLayers.Length);
m_ActiveNativeLayers.Dispose();
m_ActiveNativeLayers = newLayerArray;
var newOrderArray = new NativeArray<int>(m_nativeLayers.Count, Allocator.Persistent);
NativeArray<int>.Copy(m_ActiveNativeLayerOrders, newOrderArray, m_ActiveNativeLayerOrders.Length);
m_ActiveNativeLayerOrders.Dispose();
m_ActiveNativeLayerOrders = newOrderArray;
}
}
/// <summary>
/// Override this method to modify a native composition layer struct in response to when it is active.
/// An active compositon layer will invoke this every frame.
/// </summary>
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition
/// layer that is active.</param>
/// <param name="nativeLayer"> A reference to the native OpenXR structure of the composition layer that is active.</param>
/// <returns>Bool indicating success or failure. A failure case will result in the native composition layer struct not being added into the final XrFrameEndInfo struct.</returns>
protected virtual bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref T nativeLayer)
{
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
if (texturesExtension == null || texturesExtension.LeftTexture == null || texturesExtension.sourceTexture == TexturesExtension.SourceTextureEnum.AndroidSurface)
return true;
if (m_renderInfos.TryGetValue(layerInfo.Id, out var container))
{
bool isNewTexture = container.Texture != texturesExtension.LeftTexture;
if (isNewTexture)
{
// If we have a new texture with different dimensions then we need to release the current swapchain and create another.
// This is an async procedure that also creates a new native layer object.
if (container.Texture.width != texturesExtension.LeftTexture.width || container.Texture.height != texturesExtension.LeftTexture.height)
{
RemoveLayer(layerInfo.Id);
CreateSwapchainAsync(layerInfo);
return false;
}
else
container.Texture = texturesExtension.LeftTexture;
#if UNITY_VIDEO
container.videoPlayer = layerInfo.Layer.GetComponent<VideoPlayer>();
#endif
container.meshCollider = layerInfo.Layer.GetComponent<MeshCollider>();
}
bool isVideo = false;
#if UNITY_VIDEO
isVideo = container.videoPlayer != null && container.videoPlayer.enabled;
#endif
bool isUI = container.meshCollider != null && container.meshCollider.enabled;
#if UNITY_EDITOR
// Layers with a video or ui component in editor may have multiple native render textures associated with the layer id so we must find them.
if (isVideo || isUI)
OpenXRLayerUtility.FindAndWriteToRenderTexture(layerInfo, container.Texture, out container.RenderTexture);
else if (isNewTexture)
OpenXRLayerUtility.WriteToRenderTexture(container.Texture, container.RenderTexture);
#else
// We only need to write continuously to the native render texture if our texture is changing.
if (isVideo || isUI || isNewTexture)
OpenXRLayerUtility.WriteToRenderTexture(container.Texture, container.RenderTexture);
#endif
}
else
{
bool isRenderTextureWritten = OpenXRLayerUtility.FindAndWriteToRenderTexture(layerInfo, texturesExtension.LeftTexture, out RenderTexture renderTexture);
if (isRenderTextureWritten)
{
var layerRenderInfo = new LayerRenderInfo()
{ Texture = texturesExtension.LeftTexture, RenderTexture = renderTexture,
#if UNITY_VIDEO
videoPlayer = layerInfo.Layer.GetComponent<VideoPlayer>(),
#endif
meshCollider = layerInfo.Layer.GetComponent<MeshCollider>() };
m_renderInfos.Add(layerInfo.Id, layerRenderInfo);
};
}
return true;
}
[AOT.MonoPInvokeCallback(typeof(OpenXRLayerUtility.SwapchainCallbackDelegate))]
static void OnCreatedSwapchainCallback(int layerId, ulong swapchainHandle)
{
if (Instance == null)
return;
Instance.actionsForMainThread.Enqueue(() => { Instance.OnCreatedSwapchain(Instance.m_layerInfos[layerId], new SwapchainCreatedOutput { handle = swapchainHandle });});
}
[AOT.MonoPInvokeCallback(typeof(OpenXRLayerUtility.StereoSwapchainCallbackDelegate))]
static void OnCreatedStereoSwapchainCallback(int layerId, ulong swapchainHandleLeft, ulong swapchainHandleRight)
{
if (Instance == null)
return;
Instance.actionsForMainThread.Enqueue(() => { Instance.OnCreatedSwapchain(Instance.m_layerInfos[layerId], new SwapchainCreatedOutput { handle = swapchainHandleLeft, secondStereoHandle = swapchainHandleRight}); });
}
}
}
#endif