Init
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System.Collections.Generic;
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_CubeLayer : PXR_CustomLayerHandler<XrCompositionLayerCubeKHR>
|
||||
{
|
||||
protected override unsafe bool CreateSwapchain(CompositionLayerManager.LayerInfo layerInfo, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
TexturesExtension texture = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texture == null || texture.enabled == false || texture.LeftTexture == null)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
swapchainCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)(texture.LeftTexture.width),
|
||||
Height = (uint)(texture.LeftTexture.height),
|
||||
FaceCount = 6,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texture.LeftTexture.mipmapCount,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override unsafe bool CreateNativeLayer(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerCubeKHR nativeLayer)
|
||||
{
|
||||
var data = layerInfo.Layer.LayerData as CubeProjectionLayerData;
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
|
||||
nativeLayer = new XrCompositionLayerCubeKHR()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_CUBE_KHR,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
Swapchain = swapchainOutput.handle,
|
||||
ImageArrayIndex = 0,
|
||||
Orientation = new XrQuaternionf(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation)
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCubeKHR nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
return false;
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
nativeLayer.Orientation = new XrQuaternionf(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCubeKHR nativeLayer)
|
||||
{
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f76b65d70a4bf240be9fa70a4d5d87e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,491 @@
|
||||
#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.Services;
|
||||
using UnityEngine;
|
||||
#if UNITY_VIDEO
|
||||
using UnityEngine.Video;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base implementation for the <see cref="PXR_LayerProvider.ILayerHandler"/> interface.
|
||||
/// You can implement the required methods of this abstract class to create a concrete layer handler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <see cref="PXR_LayerProvider.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, PXR_CustomLayerHandler{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="PXR_LayerProvider.ILayerHandler"/> interface in its entirety.
|
||||
///
|
||||
/// You must register your concrete layer handler object with
|
||||
/// <see cref="PXR_LayerProvider.RegisterLayerHandler(Type, PXR_LayerProvider.ILayerHandler)"/>.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">The native PXR_ structure of the composition layer to handle.</typeparam>
|
||||
public abstract class PXR_CustomLayerHandler<T> : PXR_LayerProvider.ILayerHandler, IDisposable where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Container for swapchain related information that may be needed during the creation of the native PXR_ 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 PXR_ 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 PXR_ 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 PXR_ composition layer struct.
|
||||
/// </summary>
|
||||
public ulong secondStereoHandle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container for grouping render information for each compostion layer.
|
||||
/// </summary>
|
||||
class LayerRenderInfo
|
||||
{
|
||||
public Texture RenderTexture;
|
||||
public Texture Texture;
|
||||
#if UNITY_VIDEO
|
||||
public VideoPlayer videoPlayer;
|
||||
#endif
|
||||
public MeshCollider meshCollider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and returns an instance of this <c>PXR_CustomLayerHandler<T></c> while also setting the singleton instance member.
|
||||
/// </summary>
|
||||
protected PXR_CustomLayerHandler() => Instance = this;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton instance of this specific handler.
|
||||
/// </summary>
|
||||
protected static PXR_CustomLayerHandler<T> Instance;
|
||||
|
||||
/// <summary>
|
||||
/// Deinitializes this instance of c>PXR_CustomLayerHandler<T></c>.
|
||||
/// </summary>
|
||||
~PXR_CustomLayerHandler() => Dispose(false);
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to create the <see cref="XrSwapchainCreateInfo"/> struct that is passed to PXR_
|
||||
/// 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="PXR_LayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>.
|
||||
/// </remarks>
|
||||
/// <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 PXR_.
|
||||
/// 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="PXR_LayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>.
|
||||
///
|
||||
/// If your struct needs any XrSpace relative info you can use <see cref="PXR_LayerUtility.GetCurrentAppSpace"/>
|
||||
/// to get the current app space.
|
||||
/// </remarks>
|
||||
/// <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="PXR_LayerUtility.GetExtensionsChain(CompositionLayerManager.LayerInfo, Unity.XR.CompositionLayers.CompositionLayerExtension.ExtensionTarget)"/>
|
||||
/// to get any potential updates from extension components.
|
||||
/// </remarks>
|
||||
/// <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 PXR_ 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="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> 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 UnityPXR_ lib.
|
||||
/// </remarks>
|
||||
public virtual void OnUpdate()
|
||||
{
|
||||
while (actionsForMainThread.Count > 0)
|
||||
{
|
||||
if (actionsForMainThread.TryDequeue(out Action action))
|
||||
action();
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
if (m_ActiveNativeLayerCount > 0)
|
||||
PXR_LayerUtility.AddActiveLayersToEndFrame(m_ActiveNativeLayers.GetUnsafePtr(), m_ActiveNativeLayerOrders.GetUnsafePtr(), m_ActiveNativeLayerCount, UnsafeUtility.SizeOf<T>());
|
||||
}
|
||||
|
||||
m_ActiveNativeLayerCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> 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="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> 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="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> 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)
|
||||
{
|
||||
PXR_LayerUtility.ReleaseSwapchain(removedLayerId);
|
||||
m_nativeLayers.Remove(removedLayerId);
|
||||
m_layerInfos.Remove(removedLayerId);
|
||||
m_renderInfos.Remove(removedLayerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements the <see cref="PXR_LayerProvider.ILayerHandler"/> method that is called by the
|
||||
/// <see cref="PXR_LayerProvider"/> 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="PXR_LayerProvider"/>
|
||||
/// 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
|
||||
/// UnityPXR_ 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)
|
||||
PXR_LayerUtility.CreateStereoSwapchain(layerInfo.Id, swapChainInfo.nativeStruct, OnCreatedStereoSwapchainCallback);
|
||||
else
|
||||
PXR_LayerUtility.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;
|
||||
}
|
||||
|
||||
UnityEngine.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 PXR_ 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))
|
||||
{
|
||||
PXR_LayerUtility.WriteToRenderTexture(layerInfo.Id, container.Texture, container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
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){
|
||||
PXR_LayerUtility.FindAndWriteToRenderTexture(layerInfo, container.Texture, out container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
}
|
||||
else if (isNewTexture){
|
||||
PXR_LayerUtility.WriteToRenderTexture(layerInfo.Id, container.Texture, container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
}
|
||||
#else
|
||||
// We only need to write continuously to the native render texture if our texture is changing.
|
||||
if (isVideo || isUI || isNewTexture)
|
||||
PXR_LayerUtility.WriteToRenderTexture(layerInfo.Id, container.Texture, container.RenderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isRenderTextureWritten = PXR_LayerUtility.FindAndWriteToRenderTexture(layerInfo, texturesExtension.LeftTexture, out Texture renderTexture, nativeLayer.GetType() == typeof(XrCompositionLayerCubeKHR));
|
||||
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(PXR_LayerUtility.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(PXR_LayerUtility.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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c975401c3bdf0db46afd0591e8ce6a27
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,314 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_CylinderLayer : PXR_CustomLayerHandler<XrCompositionLayerCylinderKHR>
|
||||
{
|
||||
float savedDelta;
|
||||
bool layerDataChanged = false;
|
||||
|
||||
struct CylinderLayerSize
|
||||
{
|
||||
public float radius;
|
||||
public float centralAngle;
|
||||
public float aspectRatio;
|
||||
|
||||
public static implicit operator CylinderLayerSize(Vector3 v) => new CylinderLayerSize
|
||||
{
|
||||
radius = v.x,
|
||||
centralAngle = v.y,
|
||||
aspectRatio = v.z
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool CreateSwapchain(CompositionLayerManager.LayerInfo layer, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
if (layer.Layer == null)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture == null)
|
||||
goto default;
|
||||
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)texturesExtension.LeftTexture.width,
|
||||
Height = (uint)texturesExtension.LeftTexture.height,
|
||||
FaceCount = 1,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texturesExtension.LeftTexture.mipmapCount,
|
||||
};
|
||||
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = 0,
|
||||
SampleCount = 0,
|
||||
Width = (uint)texturesExtension.Resolution.x,
|
||||
Height = (uint)texturesExtension.Resolution.y,
|
||||
FaceCount = 0,
|
||||
ArraySize = 0,
|
||||
MipCount = 0,
|
||||
};
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: true);
|
||||
return true;
|
||||
#else
|
||||
goto default;
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool CreateNativeLayer(CompositionLayerManager.LayerInfo layer, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerCylinderKHR nativeLayer)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var data = layer.Layer.LayerData as CylinderLayerData;
|
||||
var transform = layer.Layer.GetComponent<Transform>();
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CylinderLayerSize scaledSize = data.GetScaledSize(transform.lossyScale);
|
||||
if (texturesExtension.CropToAspect)
|
||||
{
|
||||
scaledSize = FixAspectRatio(data, scaledSize, subImageWidth, subImageHeight);
|
||||
}
|
||||
|
||||
nativeLayer = new XrCompositionLayerCylinderKHR()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
SubImage = new XrSwapchainSubImage()
|
||||
{
|
||||
Swapchain = swapchainOutput.handle,
|
||||
ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di() { X = 0, Y = 0 },
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
}
|
||||
},
|
||||
ImageArrayIndex = 0
|
||||
},
|
||||
Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation),
|
||||
Radius = data.ApplyTransformScale ? scaledSize.radius : data.Radius,
|
||||
CentralAngle = data.ApplyTransformScale ? scaledSize.centralAngle : data.CentralAngle,
|
||||
AspectRatio = data.ApplyTransformScale ? scaledSize.aspectRatio : data.AspectRatio,
|
||||
};
|
||||
layerDataChanged = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCylinderKHR nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var data = layerInfo.Layer.LayerData as CylinderLayerData;
|
||||
GetSubImageDimensions(out int subImageWidth, out int subImageHeight, texturesExtension);
|
||||
nativeLayer.SubImage.ImageRect.Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
};
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
CylinderLayerSize scaledSize = data.GetScaledSize(transform.lossyScale);
|
||||
if (texturesExtension.CropToAspect)
|
||||
{
|
||||
scaledSize = FixAspectRatio(data, scaledSize, subImageWidth, subImageHeight);
|
||||
}
|
||||
nativeLayer.Radius = data.ApplyTransformScale ? scaledSize.radius : data.Radius;
|
||||
nativeLayer.CentralAngle = data.ApplyTransformScale ? scaledSize.centralAngle : data.CentralAngle;
|
||||
nativeLayer.AspectRatio = data.ApplyTransformScale ? scaledSize.aspectRatio : data.AspectRatio;
|
||||
|
||||
unsafe
|
||||
{
|
||||
nativeLayer.Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
}
|
||||
layerDataChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerCylinderKHR nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
|
||||
// Special treatment for cylinder type based on destination rects.
|
||||
if (texturesExtension != null && texturesExtension.CustomRects)
|
||||
{
|
||||
var cylinderLayer = layerInfo.Layer.LayerData as CylinderLayerData;
|
||||
float rotationDelta = (texturesExtension.LeftEyeDestinationRect.x + (0.5f * texturesExtension.LeftEyeDestinationRect.width) - 0.5f) * cylinderLayer.CentralAngle / (float)System.Math.PI * 180.0f;
|
||||
|
||||
if (rotationDelta != savedDelta)
|
||||
{
|
||||
Quaternion savedDeltaQuaternion = Quaternion.AngleAxis(savedDelta, Vector3.up);
|
||||
Quaternion deltaQuaternion = Quaternion.AngleAxis(rotationDelta, Vector3.up);
|
||||
Quaternion difference = deltaQuaternion * Quaternion.Inverse(savedDeltaQuaternion);
|
||||
|
||||
savedDelta = rotationDelta;
|
||||
transform.rotation *= difference;
|
||||
}
|
||||
}
|
||||
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
|
||||
if (texturesExtension.CustomRects && layerDataChanged)
|
||||
{
|
||||
GetSubImageDimensions(out int subImageWidth, out int subImageHeight, texturesExtension);
|
||||
|
||||
nativeLayer.SubImage.ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di()
|
||||
{
|
||||
X = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.x),
|
||||
Y = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.y)
|
||||
},
|
||||
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.width),
|
||||
Height = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.height)
|
||||
}
|
||||
};
|
||||
|
||||
var currentPosition = PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position;
|
||||
float cylinderHeight = nativeLayer.Radius * nativeLayer.CentralAngle / nativeLayer.AspectRatio;
|
||||
float transformedY = currentPosition.y + (((texturesExtension.LeftEyeDestinationRect.y + (0.5f * texturesExtension.LeftEyeDestinationRect.height) - 0.5f)) * (-1.0f * cylinderHeight));
|
||||
nativeLayer.Pose = new XrPosef(new Vector3(currentPosition.x, transformedY, currentPosition.z), PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
|
||||
nativeLayer.CentralAngle = nativeLayer.CentralAngle * texturesExtension.LeftEyeDestinationRect.width;
|
||||
nativeLayer.AspectRatio = nativeLayer.AspectRatio * texturesExtension.LeftEyeDestinationRect.width / texturesExtension.LeftEyeDestinationRect.height;
|
||||
layerDataChanged = false;
|
||||
}
|
||||
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
static CylinderLayerSize FixAspectRatio(CylinderLayerData data, CylinderLayerSize scaledSize, int texWidth, int texHeight)
|
||||
{
|
||||
// because we're cropping and trying to maintain the same other parameters, we don't
|
||||
// need to consider data.MaintainAspectRatio here. That's mostly an editor concern, anyway.
|
||||
float texRatio = (float)texWidth / (float)texHeight;
|
||||
if (scaledSize.aspectRatio > texRatio)
|
||||
{
|
||||
// too wide
|
||||
float width = scaledSize.radius * scaledSize.centralAngle;
|
||||
float height = width / scaledSize.aspectRatio;
|
||||
scaledSize.centralAngle = height * texRatio / scaledSize.radius;
|
||||
scaledSize.aspectRatio = texRatio;
|
||||
}
|
||||
else if (scaledSize.aspectRatio < texRatio)
|
||||
{
|
||||
// too narrow
|
||||
scaledSize.aspectRatio = texRatio;
|
||||
}
|
||||
|
||||
return scaledSize;
|
||||
}
|
||||
|
||||
static void GetSubImageDimensions(out int width, out int height, TexturesExtension texturesExtension)
|
||||
{
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
width = texturesExtension.LeftTexture.width;
|
||||
height = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
width = (int)texturesExtension.Resolution.x;
|
||||
height = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47eec2213f606e6469915b08b46fe725
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_DefaultLayer : PXR_LayerProvider.ILayerHandler
|
||||
{
|
||||
unsafe void SetDefaultLayerAttributes(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
var extensions = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
PXR_LayerUtility.SetDefaultSceneLayerExtensions(extensions);
|
||||
|
||||
var flags = layerInfo.Layer.LayerData.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha;
|
||||
PXR_LayerUtility.SetDefaultLayerFlags(flags);
|
||||
}
|
||||
|
||||
public void CreateLayer(CompositionLayerManager.LayerInfo layerInfo) => SetDefaultLayerAttributes(layerInfo);
|
||||
|
||||
public void ModifyLayer(CompositionLayerManager.LayerInfo layerInfo) => SetDefaultLayerAttributes(layerInfo);
|
||||
|
||||
public void OnUpdate()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void RemoveLayer(int id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void SetActiveLayer(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0074c6f14de152e4ca8c07c4bb7601b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,120 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System;
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
internal class PXR_Equirect2Layer : PXR_CustomLayerHandler<XrCompositionLayerEquirect2KHR>
|
||||
{
|
||||
protected override unsafe bool CreateSwapchain(CompositionLayerManager.LayerInfo layerInfo, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
TexturesExtension texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
swapchainCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)(texturesExtension.LeftTexture.width),
|
||||
Height = (uint)(texturesExtension.LeftTexture.height),
|
||||
FaceCount = 1,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texturesExtension.LeftTexture.mipmapCount,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override unsafe bool CreateNativeLayer(CompositionLayerManager.LayerInfo layerInfo, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerEquirect2KHR nativeLayer)
|
||||
{
|
||||
TexturesExtension texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
{
|
||||
nativeLayer = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
var data = layerInfo.Layer.LayerData as EquirectMeshLayerData;
|
||||
Vector2 scaleCalculated = CalculateScale(data.CentralHorizontalAngle, data.UpperVerticalAngle, data.LowerVerticalAngle);
|
||||
|
||||
nativeLayer = new XrCompositionLayerEquirect2KHR()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
SubImage = new XrSwapchainSubImage()
|
||||
{
|
||||
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(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation),
|
||||
Radius = data.Radius,
|
||||
CentralHorizontalAngle = data.CentralHorizontalAngle,
|
||||
UpperVerticalAngle = data.UpperVerticalAngle,
|
||||
LowerVerticalAngle = -data.LowerVerticalAngle
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override unsafe bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerEquirect2KHR nativeLayer)
|
||||
{
|
||||
TexturesExtension texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false || texturesExtension.LeftTexture == null)
|
||||
return false;
|
||||
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
var data = layerInfo.Layer.LayerData as EquirectMeshLayerData;
|
||||
Vector2 scaleCalculated = CalculateScale(data.CentralHorizontalAngle, data.UpperVerticalAngle, data.LowerVerticalAngle);
|
||||
|
||||
nativeLayer.SubImage.ImageRect.Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = texturesExtension.LeftTexture.width,
|
||||
Height = texturesExtension.LeftTexture.height
|
||||
};
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Radius = data.Radius;
|
||||
nativeLayer.CentralHorizontalAngle = data.CentralHorizontalAngle;
|
||||
nativeLayer.UpperVerticalAngle = data.UpperVerticalAngle;
|
||||
nativeLayer.LowerVerticalAngle = -data.LowerVerticalAngle;
|
||||
|
||||
nativeLayer.Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerEquirect2KHR nativeLayer)
|
||||
{
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
Vector2 CalculateScale(float centralHorizontalAngle, float upperVerticalAngle, float lowerVerticalAngle)
|
||||
{
|
||||
return new Vector2((2.0f * (float)Math.PI) / centralHorizontalAngle, (float)Math.PI / (upperVerticalAngle - lowerVerticalAngle));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2e2d51ed59c3174c8104de10442fb25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,300 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
using Unity.Profiling;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Provider;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages communication of changes between an application and the UnityPXR_ lib for all
|
||||
/// <see cref="Unity.XR.CompositionLayers.Layers.LayerData"/> objects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// PXR_ providers or extensions that create custom composition layer types or that override how the built-in
|
||||
/// layer types are handled, must implement the <see cref="ILayerProvider"/> interface and register instances of
|
||||
/// these implementations with the <c>PXR_LayerProvider</c> via <see cref="RegisterLayerHandler(Type, PXR_LayerProvider.ILayerHandler)"/>.
|
||||
/// </remarks>
|
||||
public class PXR_LayerProvider : ILayerProvider, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface used by the <see cref="PXR_LayerProvider"/> to communicate layer data changes to
|
||||
/// registered layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <c>ILayerHandler</c> instances must register themselves via
|
||||
/// <see cref="PXR_LayerProvider.RegisterLayerHandler(Type, PXR_LayerProvider.ILayerHandler)"/>
|
||||
/// to specify the <see cref="LayerData"/> type to handle.
|
||||
/// If more than one object registers itself as a handler for a specific <see cref="LayerData"/>
|
||||
/// type, the last registered handler is used.
|
||||
///
|
||||
/// The <see cref="PXR_CustomLayerHandler{T}"/> class provides a partial, base implementation of this interface that you can
|
||||
/// use to create custom layer handlers.
|
||||
/// </remarks>
|
||||
public interface ILayerHandler
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> during the Unity Update loop.
|
||||
/// All implementations must call <see cref="PXR_LayerUtility.AddActiveLayersToEndFrame(void*,void*,int,int)"/> every frame
|
||||
/// to add their native layer structs to the <c>endFrameInfo</c> struct inside the UnityPXR_ lib.
|
||||
/// </summary>
|
||||
public void OnUpdate();
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> when a new <see cref="LayerData"/>
|
||||
/// object of the type registered to this <c>ILayerHandler</c> instance has been created.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was just created.</param>
|
||||
public void CreateLayer(CompositionLayerManager.LayerInfo layerInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> when a <see cref="LayerData"/> object
|
||||
/// of the type registered to this <c>ILayerHandler</c> instance has been destroyed or disabled.
|
||||
/// </summary>
|
||||
/// <param name="removedLayerId"> The instance id of the CompositionLayer component that was removed.</param>
|
||||
public void RemoveLayer(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="PXR_LayerProvider"/> when a <see cref="LayerData"/> object
|
||||
/// or any attached extension components have had a member modified.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// that was modified.</param>
|
||||
public void ModifyLayer(CompositionLayerManager.LayerInfo layerInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Called every frame by the <see cref="PXR_LayerProvider"/> for all currently active <see cref="LayerData"/> objects
|
||||
/// of the type registered to this <c>ILayerHandler</c> instance.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer
|
||||
/// being set to active.</param>
|
||||
public void SetActiveLayer(CompositionLayerManager.LayerInfo layerInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and returns an instance of <c>PXR_LayerProvider</c>.
|
||||
/// Initializes and registers all the default, built-in layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <c>PXR_LayerProvider</c> is created and disposed by the <see cref="Management.XRLoader"/>.
|
||||
/// You do not need to create an instance of <c>PXR_LayerProvider</c> yourself. Layer handlers
|
||||
/// should only use the static methods and properties of this class
|
||||
/// </remarks>
|
||||
public PXR_LayerProvider() => InitializeAndRegisterBuiltInHandlers();
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when the <c>PXR_LayerProvider</c> has started and registered it's built-in layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You can use this event to wait for the <c>PXR_LayerProvider</c> to finish registering its built-in layer handlers
|
||||
/// so that you can override them with your own custom layer handlers.
|
||||
/// </remarks>
|
||||
public static event Action Started;
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when the <c>PXR_LayerProvider</c> has stopped and is disposed.
|
||||
/// </summary>
|
||||
public static event Action Stopped;
|
||||
|
||||
/// <summary>
|
||||
/// Reports whether the <c>PXR_LayerProvider</c> has already been created and started.
|
||||
/// </summary>
|
||||
public static bool isStarted { get; set; }
|
||||
|
||||
static Dictionary<Type, ILayerHandler> LayerHandlers = new Dictionary<Type, ILayerHandler>();
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderCreate = new ProfilerMarker("PXR_LayerProvider.Create");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderRemove = new ProfilerMarker("PXR_LayerProvider.Remove");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderModify = new ProfilerMarker("PXR_LayerProvider.Modify");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderActive = new ProfilerMarker("PXR_LayerProvider.Active");
|
||||
static readonly ProfilerMarker s_PXR_LayerProviderUpdate = new ProfilerMarker("PXR_LayerProvider.Update");
|
||||
|
||||
/// <summary>
|
||||
/// Registers a concrete <see cref="ILayerHandler"/> object as the handler for all layers of a specific
|
||||
/// <see cref="LayerData"/> subclass.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If more than one object registers itself as a handler for a specific <see cref="LayerData"/>
|
||||
/// type, the last registered handler is used.
|
||||
///
|
||||
/// The <c>PXR_LayerProvider</c> invokes the registered layer handler's <see cref="ILayerHandler"/> methods
|
||||
/// when any object of the associated <see cref="LayerData"/> type is updated in some way.
|
||||
/// </remarks>
|
||||
/// <param name="layerDataType">The <see cref="LayerData"/> subclass to handle.</param>
|
||||
/// <param name="handler">The concrete <c>ILayerHandler</c> instance> to register.</param>
|
||||
public static void RegisterLayerHandler(Type layerDataType, ILayerHandler handler)
|
||||
{
|
||||
if (handler == null)
|
||||
{
|
||||
LayerHandlers.Remove(layerDataType);
|
||||
return;
|
||||
}
|
||||
|
||||
LayerHandlers[layerDataType] = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the layer provider state on first assignment to the <see cref="CompositionLayerManager" />.
|
||||
/// </summary>
|
||||
/// <param name="layers">The list of all currently known <see cref="CompositionLayer"/> instances, regardless of active state.</param>
|
||||
public void SetInitialState(List<CompositionLayerManager.LayerInfo> layers)
|
||||
{
|
||||
UpdateLayers(layers, null, null, null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called by the <see cref="CompositionLayerManager" /> to tell the instance of <see cref="ILayerProvider" /> about
|
||||
/// the current state of layers it is managing.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="createdLayers">The list of layers that were just created. Any layer in
|
||||
/// this list may be in the <paramref name="activeLayers" /> list if it is activated in the same frame.
|
||||
/// Any layer in this list should not be in <paramref name="modifiedLayers" /> or <paramref name="removedLayers" />.
|
||||
/// This list is ephemeral and cleared after each call.</param>
|
||||
///
|
||||
/// <param name="removedLayers">The list of layers that are no longer being managed. Any layer in
|
||||
/// this list should not be in the <paramref name="createdLayers" />, <paramref name="modifiedLayers" />, or
|
||||
/// <paramref name="activeLayers" /> lists.
|
||||
/// This list is ephemeral and cleared after each call.</param>
|
||||
///
|
||||
/// <param name="modifiedLayers">The list of layers that have been recently modified. Any layer in
|
||||
/// this list may also be in the <paramref name="activeLayers" /> list. Any layer in this list should not
|
||||
/// be in <paramref name="createdLayers" /> or <paramref name="removedLayers" />.
|
||||
/// This list is ephemeral and cleared after each call.</param>
|
||||
///
|
||||
/// <param name="activeLayers">The list of layers currently active within the scene.
|
||||
/// Layers in this list may also be in the <paramref name="createdLayers" /> or <paramref name="modifiedLayers" /> lists
|
||||
/// if they became active in the same frame.</param>
|
||||
public void UpdateLayers(List<CompositionLayerManager.LayerInfo> createdLayers, List<int> removedLayers, List<CompositionLayerManager.LayerInfo> modifiedLayers, List<CompositionLayerManager.LayerInfo> activeLayers)
|
||||
{
|
||||
if (removedLayers != null && removedLayers.Count != 0)
|
||||
{
|
||||
foreach (var handler in LayerHandlers.Values)
|
||||
{
|
||||
foreach (var removed in removedLayers)
|
||||
{
|
||||
s_PXR_LayerProviderRemove.Begin();
|
||||
handler?.RemoveLayer(removed);
|
||||
s_PXR_LayerProviderRemove.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (createdLayers != null && createdLayers.Count != 0)
|
||||
{
|
||||
foreach (var created in createdLayers)
|
||||
{
|
||||
if (created.Layer == null)
|
||||
continue;
|
||||
|
||||
var layerDataType = created.Layer.LayerData.GetType();
|
||||
if (LayerHandlers.TryGetValue(layerDataType, out ILayerHandler handler))
|
||||
{
|
||||
s_PXR_LayerProviderCreate.Begin();
|
||||
handler?.CreateLayer(created);
|
||||
s_PXR_LayerProviderCreate.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modifiedLayers != null && modifiedLayers.Count != 0)
|
||||
{
|
||||
foreach (var modified in modifiedLayers)
|
||||
{
|
||||
if (modified.Layer == null)
|
||||
continue;
|
||||
|
||||
var layerDataType = modified.Layer.LayerData.GetType();
|
||||
|
||||
if (LayerHandlers.TryGetValue(layerDataType, out ILayerHandler handler))
|
||||
{
|
||||
s_PXR_LayerProviderModify.Begin();
|
||||
handler?.ModifyLayer(modified);
|
||||
s_PXR_LayerProviderModify.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activeLayers != null && activeLayers.Count != 0)
|
||||
{
|
||||
foreach (var active in activeLayers)
|
||||
{
|
||||
if (active.Layer == null)
|
||||
continue;
|
||||
|
||||
var layerDataType = active.Layer.LayerData.GetType();
|
||||
if (LayerHandlers.TryGetValue(layerDataType, out ILayerHandler handler))
|
||||
{
|
||||
s_PXR_LayerProviderActive.Begin();
|
||||
handler?.SetActiveLayer(active);
|
||||
s_PXR_LayerProviderActive.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var handler in LayerHandlers.Values)
|
||||
{
|
||||
s_PXR_LayerProviderUpdate.Begin();
|
||||
handler?.OnUpdate();
|
||||
s_PXR_LayerProviderUpdate.End();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for cleanup and to call Dispose() on registered layer handlers.
|
||||
/// </summary>
|
||||
/// <remarks>This is called by the PXR_Loader class when StopInternal() is invoked.</remarks>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var handler in LayerHandlers.Values)
|
||||
{
|
||||
if (handler is IDisposable)
|
||||
{
|
||||
((IDisposable)handler)?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
LayerHandlers.Clear();
|
||||
isStarted = false;
|
||||
Stopped?.Invoke();
|
||||
}
|
||||
|
||||
public void CleanupState()
|
||||
{
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
}
|
||||
|
||||
void InitializeAndRegisterBuiltInHandlers()
|
||||
{
|
||||
// var defaultLayerHandler = new PXR_DefaultLayer();
|
||||
var quadLayerHandler = new PXR_QuadLayer();
|
||||
//var projectionLayerHandler = new PXR_ProjectionLayer();
|
||||
var cylinderLayerHandler = new PXR_CylinderLayer();
|
||||
var cubeLayerHandler = new PXR_CubeLayer() ;
|
||||
ILayerHandler equirectLayerHandler = new PXR_Equirect2Layer() ;
|
||||
|
||||
// RegisterLayerHandler(typeof(DefaultLayerData), defaultLayerHandler);
|
||||
RegisterLayerHandler(typeof(QuadLayerData), quadLayerHandler);
|
||||
RegisterLayerHandler(typeof(CylinderLayerData), cylinderLayerHandler);
|
||||
//RegisterLayerHandler(typeof(ProjectionLayerData), projectionLayerHandler);
|
||||
//RegisterLayerHandler(typeof(ProjectionLayerRigData), projectionLayerHandler);
|
||||
RegisterLayerHandler(typeof(CubeProjectionLayerData), cubeLayerHandler);
|
||||
RegisterLayerHandler(typeof(EquirectMeshLayerData), equirectLayerHandler);
|
||||
|
||||
isStarted = true;
|
||||
Started?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8aed7bd439ad8c4196f22bd4fa60d1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,420 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using static Unity.XR.CompositionLayers.CompositionLayersRuntimeSettings;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// A general-purpose helper class for composition layer support.
|
||||
/// </summary>
|
||||
public static class PXR_LayerUtility
|
||||
{
|
||||
internal unsafe delegate void LayerCallbackDelegate(int layerId, XrCompositionLayerBaseHeader* layer);
|
||||
|
||||
private static Material textureM;
|
||||
private static Material cubeM;
|
||||
static Dictionary<UInt32, Texture> _textureMap = new Dictionary<UInt32, Texture>();
|
||||
static Dictionary<ValueTuple<int, int>, Texture> _textureCache = new Dictionary<ValueTuple<int, int>, Texture>();
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when a swapchain is created on the graphics thread inside the UnityPXR_ lib.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="swapchainHandle">The handle to the native swapchain that was just created.</param>
|
||||
public unsafe delegate void SwapchainCallbackDelegate(int layerId, ulong swapchainHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Calls the methods in its invocation list when a stereo swapchain is created on the graphics thread inside the UnityPXR_ lib.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="swapchainHandleLeft">The handle to one of the stereo swapchains that was just created.</param>
|
||||
/// <param name="swapchainHandleRight">The handle to one of the stereo swapchains that was just created.</param>
|
||||
public unsafe delegate void StereoSwapchainCallbackDelegate(int layerId, ulong swapchainHandleLeft, ulong swapchainHandleRight);
|
||||
|
||||
/// <summary>
|
||||
/// Helper method used to gather the extension components attached to a CompositionLayer GameObject.
|
||||
/// This method chains the native extension struct pointers of those extension components to initialize an PXR_ native object's Next pointer struct chain.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer.</param>
|
||||
/// <param name="extensionTarget"> Represents what part of the composition layer to retrieve extensions for.</param>
|
||||
/// <returns>A pointer to the head of an array of native extension objects that will be associated with a composition layer.</returns>
|
||||
public static unsafe void* GetExtensionsChain(CompositionLayerManager.LayerInfo layerInfo, CompositionLayerExtension.ExtensionTarget extensionTarget)
|
||||
{
|
||||
void* extensionsChainHead = null;
|
||||
void* extensionsChain = null;
|
||||
|
||||
foreach (var extension in layerInfo.Layer.Extensions)
|
||||
{
|
||||
// Skip extension if not enabled or not the intended target.
|
||||
if (!extension.enabled || extension.Target != extensionTarget)
|
||||
continue;
|
||||
|
||||
var extensionNativeStructPtr = extension.GetNativeStructPtr();
|
||||
|
||||
// Skip extension if no native pointer is provided.
|
||||
if (extensionNativeStructPtr == null)
|
||||
continue;
|
||||
|
||||
// Initialize pointer chain if head has not been set.
|
||||
if (extensionsChainHead == null)
|
||||
{
|
||||
extensionsChainHead = extensionNativeStructPtr;
|
||||
extensionsChain = extensionsChainHead;
|
||||
}
|
||||
// Chain pointer if head has been initialized.
|
||||
else
|
||||
{
|
||||
((XrBaseInStructure*)extensionsChain)->Next = extensionNativeStructPtr;
|
||||
extensionsChain = extensionNativeStructPtr;
|
||||
}
|
||||
}
|
||||
|
||||
return extensionsChainHead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method used get the current app space for any native composition layer structs that may require an associated XrSpace.
|
||||
/// </summary>
|
||||
/// <returns>A handle to the current app space.</returns>
|
||||
/// <remarks>Normally used when creating native composition layers.</remarks>
|
||||
//public static ulong GetCurrentAppSpace() => Features.PXR_Feature.Internal_GetAppSpace(out ulong appSpaceId) ? appSpaceId : 0; // TODO
|
||||
public static ulong GetCurrentAppSpace() => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Helper method used get the XR session handle for any native composition layer structs that may require an associated XrSession.
|
||||
/// </summary>
|
||||
/// <returns>A handle to the current xr session.</returns>
|
||||
//public static ulong GetXRSession() => Features.PXR_Feature.Internal_GetXRSession(out ulong xrSessionHandle) ? xrSessionHandle : 0; // TODO
|
||||
public static ulong GetXRSession() => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Create the <see cref="XrSwapchainCreateInfo"/> struct that is passed to PXR_ SDK to create a swapchain.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="createInfo">The struct used to create the swapchain.</param>
|
||||
/// <param name="isExternalSurface"> Optional parameter that can be used when an external surface will be used, like when using the Android Surface feature.</param>
|
||||
/// <param name="callback"> Optional parameter that can be used if your composition layer needs to know the handle after swapchain creation.</param>
|
||||
public static void CreateSwapchain(int layerId, XrSwapchainCreateInfo createInfo, bool isExternalSurface = false, SwapchainCallbackDelegate callback = null)
|
||||
{
|
||||
Pxr_CompositorLayersCreateSwapchain(layerId, createInfo, isExternalSurface, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the <see cref="XrSwapchainCreateInfo"/> struct that is passed to PXR_ SDK to create a swapchain for stereo projection, like Projection layer type.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <param name="createInfo">The struct used to create the swapchain.</param>
|
||||
/// <param name="callback"> Optional parameter that can be used if your composition layer needs to know the handles after swapchain creation.</param>
|
||||
public static void CreateStereoSwapchain(int layerId, XrSwapchainCreateInfo createInfo, StereoSwapchainCallbackDelegate callback = null)
|
||||
{
|
||||
Pxr_CompositorLayersCreateStereoSwapchain(layerId, createInfo, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release swapchain according to the id provided.
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
public static void ReleaseSwapchain(int layerId)
|
||||
{
|
||||
Pxr_CompositorLayersReleaseSwapchain(layerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return swapchain supported color format.
|
||||
/// </summary>
|
||||
/// <returns>The color format the swapchains will be using.</returns>
|
||||
public static Int64 GetDefaultColorFormat()
|
||||
{
|
||||
if (GraphicsDeviceType.Vulkan == SystemInfo.graphicsDeviceType)
|
||||
{
|
||||
return (long)PXR_CompositionLayer.ColorForamt.VK_FORMAT_R8G8B8A8_SRGB;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (long)PXR_CompositionLayer.ColorForamt.GL_SRGB8_ALPHA8;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the render texture of the give texture id.
|
||||
/// </summary>
|
||||
/// <param name="texId">The id of the render texture to find.</param>
|
||||
/// <returns>The render texture with the provided id or null if no render textrue with that id was found.</returns>
|
||||
public static Texture FindRenderTexture(int id, UInt32 texId)
|
||||
{
|
||||
// texId will be 0 if swapchain has no images.
|
||||
if (texId == 0)
|
||||
return null;
|
||||
|
||||
if (!_textureMap.TryGetValue(texId, out var renderTexture))
|
||||
{
|
||||
var objs = Resources.FindObjectsOfTypeAll<RenderTexture>();
|
||||
var name = $"XR Texture [{texId}]";
|
||||
// for (int i = 0; i < objs.Length; i++)
|
||||
// {
|
||||
// Debug.Log($"FindRenderTexture 2 objs[i]={objs[i].name}");
|
||||
|
||||
// }
|
||||
bool found = false;
|
||||
foreach (var rt in objs)
|
||||
{
|
||||
if (rt.name == name)
|
||||
{
|
||||
renderTexture = rt;
|
||||
_textureMap[texId] = rt;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderTexture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the render texture of the layer id.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer.</param>
|
||||
/// <returns>The render texture with the provided id or null if no render textrue with that id was found.</returns>
|
||||
public static Texture FindRenderTexture(CompositionLayerManager.LayerInfo layerInfo)
|
||||
{
|
||||
UInt32 texId = Pxr_CompositorLayersCreateOrGetRenderTextureId(layerInfo.Id);
|
||||
return FindRenderTexture(layerInfo.Id, texId);
|
||||
}
|
||||
|
||||
public static Texture CreateExternalTexture(int id, int width, int height, bool isCube)
|
||||
{
|
||||
int imageIndex = 0;
|
||||
PXR_Plugin.Render.UPxr_GetLayerNextImageIndexByRender(id, ref imageIndex);
|
||||
|
||||
var cacheKey = ValueTuple.Create(id, imageIndex);
|
||||
if (_textureCache.TryGetValue(cacheKey, out var cachedTexture))
|
||||
{
|
||||
return cachedTexture;
|
||||
}
|
||||
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
PXR_Plugin.Render.UPxr_GetLayerImagePtr(id, (EyeType)0, imageIndex, ref ptr);
|
||||
if (IntPtr.Zero == ptr)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture id={id}, _textureMap, imageIndex={imageIndex}, IntPtr.Zero == ptr");
|
||||
return null;
|
||||
}
|
||||
|
||||
Texture nativeTexture;
|
||||
|
||||
if (isCube)
|
||||
{
|
||||
nativeTexture = Cubemap.CreateExternalTexture(width, TextureFormat.RGBA32, false, ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
nativeTexture = Texture2D.CreateExternalTexture(width, height, TextureFormat.RGBA32, false, true, ptr);
|
||||
}
|
||||
if (nativeTexture == null)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture id={id}, _textureMap, imageIndex={imageIndex}, nativeTexture == null");
|
||||
}
|
||||
if (nativeTexture != null)
|
||||
{
|
||||
nativeTexture.name = $"{id}+{imageIndex}";
|
||||
_textureCache[cacheKey] = nativeTexture;
|
||||
}
|
||||
Debug.Log($"WriteToRenderTexture id={id}, imageIndex={imageIndex}, cacheKey={cacheKey}, ptr={ptr}");
|
||||
return nativeTexture;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handles transfering texture data to a render texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The source texture that will be written into the provided render texture.</param>
|
||||
/// <param name="renderTexture">The render texture that will be written to.</param>
|
||||
public static void WriteToRenderTexture(int id, Texture sourceTextures, Texture nativeTexture, bool isCube)
|
||||
{
|
||||
if (sourceTextures == null)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture sourceTextures == null!");
|
||||
return;
|
||||
}
|
||||
|
||||
nativeTexture = CreateExternalTexture(id, sourceTextures.width, sourceTextures.height, isCube);
|
||||
if (nativeTexture == null)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture 11 id={id} nativeTexture == null");
|
||||
return;
|
||||
}
|
||||
int eyeCount = 1;
|
||||
for (int i = 0; i < eyeCount; i++)
|
||||
{
|
||||
if (isCube && null == sourceTextures as Cubemap)
|
||||
{
|
||||
Debug.LogError($"WriteToRenderTexture 11 id={id} isCube && null == sourceTextures as Cubemap");
|
||||
return;
|
||||
}
|
||||
|
||||
int faceCount = isCube ? 6:1;
|
||||
for (int f = 0; f < faceCount; f++)
|
||||
{
|
||||
if (QualitySettings.activeColorSpace == ColorSpace.Gamma && sourceTextures != null)
|
||||
{
|
||||
Graphics.CopyTexture(sourceTextures, f, 0, nativeTexture, f, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderTextureDescriptor rtDes = new RenderTextureDescriptor((int)sourceTextures.width, (int)sourceTextures.height, RenderTextureFormat.ARGB32, 0);
|
||||
rtDes.msaaSamples = 1;
|
||||
rtDes.useMipMap = true;
|
||||
rtDes.autoGenerateMips = false;
|
||||
rtDes.sRGB = true;
|
||||
|
||||
RenderTexture renderTexture = RenderTexture.GetTemporary(rtDes);
|
||||
|
||||
if (!renderTexture.IsCreated())
|
||||
{
|
||||
renderTexture.Create();
|
||||
}
|
||||
renderTexture.DiscardContents();
|
||||
|
||||
if (isCube)
|
||||
{
|
||||
if (cubeM == null)
|
||||
{
|
||||
Debug.Log($"WriteToRenderTexture id={id}, cubeM , f={f}, cubeM == null");
|
||||
cubeM = new Material(Shader.Find("PXR_SDK/PXR_CubemapBlit"));
|
||||
}
|
||||
cubeM.SetInt("_d", f);
|
||||
Graphics.Blit(sourceTextures, renderTexture, cubeM);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (textureM == null)
|
||||
{
|
||||
Debug.Log($"WriteToRenderTexture id={id}, textureM, textureM == null");
|
||||
textureM = new Material(Shader.Find("PXR_SDK/PXR_Texture2DBlit"));
|
||||
}
|
||||
textureM.mainTexture = renderTexture;
|
||||
textureM.SetPass(0);
|
||||
//textureM.SetInt("_premultiply", isPremultipliedAlpha ? 1 : 0);
|
||||
Graphics.Blit(sourceTextures, renderTexture);
|
||||
}
|
||||
Graphics.CopyTexture(renderTexture, 0, 0, nativeTexture, f, 0);
|
||||
RenderTexture.ReleaseTemporary(renderTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the correct XR Textures for rendering and blit the layer textures.
|
||||
/// </summary>
|
||||
/// <param name="layerInfo"> Container for the instance id and CompositionLayer component of the composition layer.</param>
|
||||
/// <param name="texture">The source texture that will be written into the provided render texture.</param>
|
||||
/// <param name="renderTexture">The render texture that will be searched for and written to.
|
||||
/// Will be null if no render texture can be found for the provided layerInfo object.</param>
|
||||
/// <returns>True if a render texture was found and written to, false if the provided texture is null or if no render texture was found for the provided layerInfo object.</returns>
|
||||
public static bool FindAndWriteToRenderTexture(CompositionLayerManager.LayerInfo layerInfo, Texture texture, out Texture renderTexture, bool isCube)
|
||||
{
|
||||
if (texture == null)
|
||||
{
|
||||
Debug.Log($"FindAndWriteToRenderTexture texture == null");
|
||||
renderTexture = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
renderTexture = FindRenderTexture(layerInfo);
|
||||
WriteToRenderTexture(layerInfo.Id, texture, renderTexture, isCube);
|
||||
return renderTexture != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add native layer structs to the <c>endFrameInfo</c> struct inside the UnityPXR_ lib - for custom layer type support
|
||||
/// </summary>
|
||||
/// <param name="layers">Pointer to the native array of currently active composition layers.</param>
|
||||
/// <param name="orders">Pointer to the native array of order values for the currently active composition layers.</param>
|
||||
/// <param name="count">Indicates the size of the layers and orders arrays.</param>
|
||||
/// <param name="layerByteSize">Indicates the size in bytes of a single element of the given array of composition layers.</param>
|
||||
/// <remarks>Layers sent must all be of the same type.Demonstrated in the PXR_CustomLayerHandler class.</remarks>
|
||||
public static unsafe void AddActiveLayersToEndFrame(void* layers, void* orders, int count, int layerByteSize)
|
||||
{
|
||||
IntPtr ptrLayers = new IntPtr(layers);
|
||||
IntPtr ptrOrders = new IntPtr(orders);
|
||||
Pxr_CompositorLayersAddActiveLayers(layers, orders, count, layerByteSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the Surface object for Android External Surface support (Android only).
|
||||
/// </summary>
|
||||
/// <param name="layerId">The instance id of the composition layer object.</param>
|
||||
/// <returns>Pointer to the android surface object.</returns>
|
||||
public static System.IntPtr GetLayerAndroidSurfaceObject(int layerId)
|
||||
{
|
||||
IntPtr surfaceObject = IntPtr.Zero;
|
||||
if (Pxr_CompositorLayersGetLayerAndroidSurfaceObject(layerId, ref surfaceObject))
|
||||
{
|
||||
return surfaceObject;
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an array of extensions to be attached to the native default compostion layer.
|
||||
/// </summary>
|
||||
/// <param name="extensions">Pointer to the array of extensions to attach to the default compostion layer.</param>
|
||||
/// <remarks>Currently only called by the PXR_DefautLayer class.</remarks>
|
||||
public static unsafe void SetDefaultSceneLayerExtensions(void* extensions)
|
||||
{
|
||||
// IntPtr ptr = new IntPtr(extensions);
|
||||
// ext_composition_layers_SetDefaultSceneLayerExtensions(extensions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends what flags are to be added to the native default compostion layer.
|
||||
/// </summary>
|
||||
/// <param name="flags">Flags to be added to the native default compostion layer.</param>
|
||||
/// <remarks>Currently only called by the PXR_DefautLayer class.</remarks>
|
||||
public static unsafe void SetDefaultLayerFlags(XrCompositionLayerFlags flags)
|
||||
{
|
||||
// ext_composition_layers_SetDefaultSceneLayerFlags(flags);
|
||||
}
|
||||
|
||||
const string LibraryName = "PxrPlatform";
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern UInt32 Pxr_CompositorLayersCreateOrGetRenderTextureId(int id); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static extern bool Pxr_CompositorLayersCreateOrGetStereoRenderTextureIds(int id, out UInt32 leftId, out UInt32 rightId); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void Pxr_CompositorLayersCreateSwapchain(int id, XrSwapchainCreateInfo createInfo, [MarshalAs(UnmanagedType.I1)]bool isExternalSurface = false, SwapchainCallbackDelegate callback = null); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void Pxr_CompositorLayersCreateStereoSwapchain(int id, XrSwapchainCreateInfo createInfo, StereoSwapchainCallbackDelegate callback = null); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void Pxr_CompositorLayersReleaseSwapchain(int id); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern unsafe void Pxr_CompositorLayersAddActiveLayers(void* layers, void* orders, int count, int size); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static extern bool Pxr_CompositorLayersGetLayerAndroidSurfaceObject(int layerId, ref IntPtr surfaceObject); // Down
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern unsafe void ext_composition_layers_SetDefaultSceneLayerExtensions(void* extensions);
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void ext_composition_layers_SetDefaultSceneLayerFlags(XrCompositionLayerFlags flags);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50cb351d62257144eabbecc94c61adef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,300 @@
|
||||
#if XR_COMPOSITION_LAYERS
|
||||
using Unity.XR.CompositionLayers;
|
||||
using Unity.XR.CompositionLayers.Extensions;
|
||||
using Unity.XR.CompositionLayers.Layers;
|
||||
using Unity.XR.CompositionLayers.Services;
|
||||
using Unity.XR.PXR;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
//Default PXR_ Composition Layer - Quad Layer support
|
||||
internal class PXR_QuadLayer : PXR_CustomLayerHandler<XrCompositionLayerQuad>
|
||||
{
|
||||
protected override bool CreateSwapchain(CompositionLayerManager.LayerInfo layer, out SwapchainCreateInfo swapchainCreateInfo)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
{
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture == null)
|
||||
goto default;
|
||||
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = PXR_LayerUtility.GetDefaultColorFormat(),
|
||||
SampleCount = 1,
|
||||
Width = (uint)texturesExtension.LeftTexture.width,
|
||||
Height = (uint)texturesExtension.LeftTexture.height,
|
||||
FaceCount = 1,
|
||||
ArraySize = 1,
|
||||
MipCount = (uint)texturesExtension.LeftTexture.mipmapCount,
|
||||
};
|
||||
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
var xrCreateInfo = new XrSwapchainCreateInfo()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_SWAPCHAIN_CREATE_INFO,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Swapchain),
|
||||
CreateFlags = 0,
|
||||
UsageFlags = (ulong)(XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XrSwapchainUsageFlags.XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT),
|
||||
Format = 0,
|
||||
SampleCount = 0,
|
||||
Width = (uint)texturesExtension.Resolution.x,
|
||||
Height = (uint)texturesExtension.Resolution.y,
|
||||
FaceCount = 0,
|
||||
ArraySize = 0,
|
||||
MipCount = 0,
|
||||
};
|
||||
|
||||
swapchainCreateInfo = new SwapchainCreateInfo(xrCreateInfo, isExternalSurface: true);
|
||||
return true;
|
||||
#else
|
||||
goto default;
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
swapchainCreateInfo = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool CreateNativeLayer(CompositionLayerManager.LayerInfo layer, SwapchainCreatedOutput swapchainOutput, out XrCompositionLayerQuad nativeLayer)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var texturesExtension = layer.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
{
|
||||
nativeLayer = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = layer.Layer.LayerData as QuadLayerData;
|
||||
var transform = layer.Layer.GetComponent<Transform>();
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var correctedSize = texturesExtension.CropToAspect ?
|
||||
FixAspectRatio(data, transform, subImageWidth, subImageHeight) :
|
||||
data.GetScaledSize(transform.lossyScale);
|
||||
|
||||
nativeLayer = new XrCompositionLayerQuad()
|
||||
{
|
||||
Type = (uint)XrStructureType.XR_TYPE_COMPOSITION_LAYER_QUAD,
|
||||
Next = PXR_LayerUtility.GetExtensionsChain(layer, CompositionLayerExtension.ExtensionTarget.Layer),
|
||||
LayerFlags = data.BlendType == BlendType.Premultiply ? XrCompositionLayerFlags.SourceAlpha : XrCompositionLayerFlags.SourceAlpha | XrCompositionLayerFlags.UnPremultipliedAlpha,
|
||||
Space = PXR_LayerUtility.GetCurrentAppSpace(),
|
||||
EyeVisibility = 0,
|
||||
SubImage = new XrSwapchainSubImage()
|
||||
{
|
||||
Swapchain = swapchainOutput.handle,
|
||||
ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di() { X = 0, Y = 0 },
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
}
|
||||
},
|
||||
ImageArrayIndex = 0
|
||||
},
|
||||
Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation),
|
||||
Size = new XrExtent2Df()
|
||||
{
|
||||
width = correctedSize.x,
|
||||
height = correctedSize.y
|
||||
}
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ModifyNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerQuad nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var data = layerInfo.Layer.LayerData as QuadLayerData;
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nativeLayer.SubImage.ImageRect.Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = subImageWidth,
|
||||
Height = subImageHeight
|
||||
};
|
||||
|
||||
var correctedSize = texturesExtension.CropToAspect ?
|
||||
FixAspectRatio(data, transform, subImageWidth, subImageHeight) :
|
||||
data.GetScaledSize(transform.lossyScale);
|
||||
nativeLayer.Size = new XrExtent2Df()
|
||||
{
|
||||
width = correctedSize.x,
|
||||
height = correctedSize.y
|
||||
};
|
||||
|
||||
unsafe
|
||||
{
|
||||
nativeLayer.Next = PXR_LayerUtility.GetExtensionsChain(layerInfo, CompositionLayerExtension.ExtensionTarget.Layer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ActiveNativeLayer(CompositionLayerManager.LayerInfo layerInfo, ref XrCompositionLayerQuad nativeLayer)
|
||||
{
|
||||
var texturesExtension = layerInfo.Layer.GetComponent<TexturesExtension>();
|
||||
if (texturesExtension == null || texturesExtension.enabled == false)
|
||||
return false;
|
||||
|
||||
var data = layerInfo.Layer.LayerData as QuadLayerData;
|
||||
var transform = layerInfo.Layer.GetComponent<Transform>();
|
||||
nativeLayer.Pose = new XrPosef(PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position, PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Space = PXR_LayerUtility.GetCurrentAppSpace();
|
||||
|
||||
if (texturesExtension.CustomRects)
|
||||
{
|
||||
int subImageWidth = 0;
|
||||
int subImageHeight = 0;
|
||||
switch (texturesExtension.sourceTexture)
|
||||
{
|
||||
case TexturesExtension.SourceTextureEnum.LocalTexture:
|
||||
{
|
||||
if (texturesExtension.LeftTexture != null)
|
||||
{
|
||||
subImageWidth = texturesExtension.LeftTexture.width;
|
||||
subImageHeight = texturesExtension.LeftTexture.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TexturesExtension.SourceTextureEnum.AndroidSurface:
|
||||
{
|
||||
subImageWidth = (int)texturesExtension.Resolution.x;
|
||||
subImageHeight = (int)texturesExtension.Resolution.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nativeLayer.SubImage.ImageRect = new XrRect2Di()
|
||||
{
|
||||
Offset = new XrOffset2Di()
|
||||
{
|
||||
X = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.x),
|
||||
Y = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.y)
|
||||
},
|
||||
|
||||
Extent = new XrExtent2Di()
|
||||
{
|
||||
Width = (int)(subImageWidth * texturesExtension.LeftEyeSourceRect.width),
|
||||
Height = (int)(subImageHeight * texturesExtension.LeftEyeSourceRect.height)
|
||||
}
|
||||
};
|
||||
|
||||
var currentPosition = PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).position;
|
||||
var correctedSize = texturesExtension.CropToAspect ?
|
||||
FixAspectRatio(data, transform, subImageWidth, subImageHeight) :
|
||||
data.GetScaledSize(transform.lossyScale);
|
||||
|
||||
float transformedX = currentPosition.x + (((texturesExtension.LeftEyeDestinationRect.x + (0.5f * texturesExtension.LeftEyeDestinationRect.width) - 0.5f)) * correctedSize.x);
|
||||
float transformedY = currentPosition.y + (((texturesExtension.LeftEyeDestinationRect.y + (0.5f * texturesExtension.LeftEyeDestinationRect.height) - 0.5f)) * (-1.0f * correctedSize.y));
|
||||
nativeLayer.Pose = new XrPosef(new Vector3(transformedX, transformedY, currentPosition.z), PXR_Utility.ComputePoseToWorldSpace(transform, CompositionLayerManager.mainCameraCache).rotation);
|
||||
nativeLayer.Size = new XrExtent2Df()
|
||||
{
|
||||
width = correctedSize.x * texturesExtension.LeftEyeDestinationRect.width,
|
||||
height = correctedSize.y * texturesExtension.LeftEyeDestinationRect.height
|
||||
};
|
||||
}
|
||||
|
||||
return base.ActiveNativeLayer(layerInfo, ref nativeLayer);
|
||||
}
|
||||
|
||||
static Vector2 FixAspectRatio(QuadLayerData data, Transform transform, int texWidth, int texHeight)
|
||||
{
|
||||
var requestedSize = data.GetScaledSize(transform.lossyScale);
|
||||
float reqSizeRatio = (float)requestedSize.x / (float)requestedSize.y;
|
||||
float texRatio = (float)texWidth / (float)texHeight;
|
||||
if (reqSizeRatio > texRatio)
|
||||
{
|
||||
// too wide
|
||||
requestedSize.x = requestedSize.y * texRatio;
|
||||
}
|
||||
else if (reqSizeRatio < texRatio)
|
||||
{
|
||||
// too narrow
|
||||
requestedSize.y = requestedSize.x / texRatio;
|
||||
}
|
||||
return requestedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5e1a0709a0c74345b2e0408bec5348c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
/// <summary>
|
||||
/// PXR_ Utility Class contains helper methods that any script can use.
|
||||
/// </summary>
|
||||
public static class PXR_Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the inverse of the given pose.
|
||||
/// </summary>
|
||||
private static Pose Inverse(Pose p)
|
||||
{
|
||||
Pose ret;
|
||||
ret.rotation = Quaternion.Inverse(p.rotation);
|
||||
ret.position = ret.rotation * -p.position;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculate object position and rotation from tracking-space to world-space, for use cases like teleporting.
|
||||
/// </summary>
|
||||
/// <param name="t">original transform of the object in the scene, typically obtained by gameObject.transform</param>
|
||||
/// <param name="camera">camera the calculation is based on, normally it is the main camera</param>
|
||||
/// <returns>the recalculated pose <see cref="UnityEngine.Pose"/> in world-space.</returns>
|
||||
public static Pose ComputePoseToWorldSpace(Transform t, Camera camera)
|
||||
{
|
||||
if (camera == null)
|
||||
return default;
|
||||
|
||||
Transform cameraTransform = camera.transform;
|
||||
Pose headPose = new Pose(cameraTransform.localPosition, cameraTransform.localRotation);
|
||||
Pose camPose = new Pose(cameraTransform.position, cameraTransform.rotation);
|
||||
Pose transformPose = new Pose(t.position, t.rotation);
|
||||
|
||||
Pose headSpacePose = transformPose.GetTransformedBy(Inverse(camPose));
|
||||
return headSpacePose.GetTransformedBy(headPose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the current session is in the focused state.
|
||||
/// See <a href="https://registry.khronos.org/PXR_/specs/1.0/html/xrspec.html#session-states">XR_SESSION_STATE_FOCUSED.</a> for reference.
|
||||
/// </summary>
|
||||
public static bool IsSessionFocused => Internal_IsSessionFocused();
|
||||
/// <summary>
|
||||
/// Returns the change of user presence, such as when the user has taken off or put on an XR headset.
|
||||
/// If the system does not support user presence sensing, runtime assumes that the user is always present and IsUserPresent always returns True.
|
||||
/// If the system supports the sensing of user presence, returns true when detected the presence of a user and returns false when detected the absence of a user.
|
||||
/// See <a href="https://registry.khronos.org/PXR_/specs/1.0/html/xrspec.html#XR_EXT_user_presence">XR_EXT_user_presence.</a> for reference.
|
||||
/// </summary>
|
||||
public static bool IsUserPresent => Internal_GetUserPresence();
|
||||
|
||||
private const string LibraryName = "PxrPlatform";
|
||||
|
||||
[DllImport(LibraryName, EntryPoint = "NativeConfig_IsSessionFocused")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool Internal_IsSessionFocused();
|
||||
|
||||
[DllImport(LibraryName, EntryPoint = "NativeConfig_GetUserPresence")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool Internal_GetUserPresence();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5fe75684f72312e4187498fd4db6f5ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user