Files
VIVE-OpenXR-Unity/com.htc.upm.vive.openxr/Runtime/CompositionLayer/Scripts/CompositionLayerManager.cs
2023-09-14 18:17:47 +08:00

348 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// "VIVE SDK
// © 2020 HTC Corporation. All Rights Reserved.
//
// Unless otherwise required by copyright law and practice,
// upon the execution of HTC SDK license agreement,
// HTC grants you access to and use of the VIVE SDK(s).
// You shall fully comply with all of HTCs SDK license agreement terms and
// conditions signed by you and all SDK and API requirements,
// specifications, and documentation provided by HTC to You."
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.OpenXR;
using VIVE.OpenXR.CompositionLayer;
namespace VIVE.OpenXR.CompositionLayer
{
public class CompositionLayerManager : MonoBehaviour
{
private uint maxLayerCount = 0;
private static CompositionLayerManager instance = null;
private List<CompositionLayer> compositionLayers = new List<CompositionLayer>();
private List<CompositionLayer> compositionLayersToBeSubscribed = new List<CompositionLayer>();
private List<CompositionLayer> compositionLayersToBeUnsubscribed = new List<CompositionLayer>();
private bool isOnBeforeRenderSubscribed = false;
private ViveCompositionLayer compositionLayerFeature = null;
private const string LOG_TAG = "VIVE_CompositionLayerManager";
static void DEBUG(string msg) { Debug.Log(LOG_TAG + " " + msg); }
static void WARNING(string msg) { Debug.LogWarning(LOG_TAG + " " + msg); }
static void ERROR(string msg) { Debug.LogError(LOG_TAG + " " + msg); }
#region public parameter access functions
public static CompositionLayerManager GetInstance()
{
if (instance == null)
{
GameObject CompositionLayerManagerGO = new GameObject("MultiLayerManager", typeof(CompositionLayerManager));
instance = CompositionLayerManagerGO.GetComponent<CompositionLayerManager>();
}
return instance;
}
public static bool CompositionLayerManagerExists()
{
return (instance != null);
}
public int MaxLayerCount()
{
return (int)maxLayerCount;
}
public int RemainingLayerCount()
{
int count = (int)maxLayerCount - compositionLayers.Count;
if (count < 0)
{
return 0;
}
return count;
}
public int CurrentLayerCount()
{
return compositionLayers.Count;
}
#endregion
#region Monobehaviour Lifecycle
void Awake()
{
if (instance == null)
{
instance = this;
}
else if (instance != this)
{
Destroy(instance);
instance = this;
}
}
private void Start()
{
UpdateMaxLayerCount();
}
public delegate void CompositionLayerManagerOnBeforeRender();
public event CompositionLayerManagerOnBeforeRender CompositionLayerManagerOnBeforeRenderDelegate = null;
private void OnBeforeRender()
{
compositionLayerFeature = OpenXRSettings.Instance.GetFeature<ViveCompositionLayer>();
if (compositionLayerFeature != null)
{
if (compositionLayerFeature.XrSessionEnding)
{
DEBUG("XrSession is ending, stop all layers");
foreach (CompositionLayer layer in compositionLayers) //All active layers
{
if (!compositionLayersToBeUnsubscribed.Contains(layer) && !compositionLayersToBeSubscribed.Contains(layer))
{
//Add currently active layers that are not scheduled for termination to the "To be subscribed" list
compositionLayersToBeSubscribed.Add(layer);
}
layer.TerminateLayer();
}
compositionLayers.Clear();
foreach (CompositionLayer layer in compositionLayersToBeUnsubscribed) //All layers to be terminated
{
layer.TerminateLayer();
}
compositionLayersToBeUnsubscribed.Clear();
return;
}
}
else
{
ERROR("compositionLayerFeature not found");
}
bool CompositionLayerStatusUpdateNeeded = false;
//Process Sub and Unsub list in bulk at once per frame
if (compositionLayersToBeUnsubscribed.Count > 0)
{
foreach (CompositionLayer layerToBeRemoved in compositionLayersToBeUnsubscribed)
{
DEBUG("CompositionLayersToBeUnsubscribed: Processing");
if (compositionLayers.Contains(layerToBeRemoved) && !compositionLayersToBeSubscribed.Contains(layerToBeRemoved))
{
layerToBeRemoved.TerminateLayer();
compositionLayers.Remove(layerToBeRemoved);
}
}
compositionLayersToBeUnsubscribed.Clear();
CompositionLayerStatusUpdateNeeded = true;
}
if (compositionLayersToBeSubscribed.Count > 0)
{
DEBUG("CompositionLayersToBeSubscribed: Processing");
foreach (CompositionLayer layerToBeAdded in compositionLayersToBeSubscribed)
{
if (!compositionLayers.Contains(layerToBeAdded))
{
compositionLayers.Add(layerToBeAdded);
DEBUG("Add new layer");
}
else if (layerToBeAdded.isRenderPriorityChanged)
{
DEBUG("Layer RenderPriority changed");
}
}
compositionLayersToBeSubscribed.Clear();
CompositionLayerStatusUpdateNeeded = true;
}
if (CompositionLayerStatusUpdateNeeded)
{
DEBUG("CompositionLayerStatusUpdateNeeded");
UpdateLayerStatus();
CompositionLayerStatusUpdateNeeded = false;
}
CompositionLayerManagerOnBeforeRenderDelegate?.Invoke();
}
private void OnEnable()
{
if (!isOnBeforeRenderSubscribed)
{
Application.onBeforeRender += OnBeforeRender;
isOnBeforeRenderSubscribed = true;
}
}
private void OnDisable()
{
if (isOnBeforeRenderSubscribed)
{
Application.onBeforeRender -= OnBeforeRender;
isOnBeforeRenderSubscribed = false;
}
}
private void OnDestroy()
{
if (isOnBeforeRenderSubscribed)
{
Application.onBeforeRender -= OnBeforeRender;
isOnBeforeRenderSubscribed = false;
}
}
#endregion
public void SubscribeToLayerManager(CompositionLayer layerToBeAdded)
{
if (compositionLayersToBeSubscribed == null)
{
DEBUG("SubscribeToLayerManager: Layer List not found. Creating a new one.");
compositionLayersToBeSubscribed = new List<CompositionLayer>();
}
if (!compositionLayersToBeSubscribed.Contains(layerToBeAdded))
{
DEBUG("SubscribeToLayerManager: Add layer");
compositionLayersToBeSubscribed.Add(layerToBeAdded);
}
}
public void UnsubscribeFromLayerManager(CompositionLayer layerToBeRemoved, bool isImmediate)
{
if (compositionLayersToBeUnsubscribed == null)
{
DEBUG("UnsubscribeFromLayerManager: Layer List not found. Creating a new one.");
compositionLayersToBeUnsubscribed = new List<CompositionLayer>();
}
if (!compositionLayersToBeUnsubscribed.Contains(layerToBeRemoved) && !isImmediate)
{
DEBUG("UnsubscribeFromLayerManager: Remove layer");
compositionLayersToBeUnsubscribed.Add(layerToBeRemoved);
}
else if (isImmediate)
{
layerToBeRemoved.TerminateLayer();
if (compositionLayersToBeUnsubscribed.Contains(layerToBeRemoved))
{
compositionLayersToBeUnsubscribed.Remove(layerToBeRemoved);
}
if (compositionLayersToBeSubscribed.Contains(layerToBeRemoved))
{
compositionLayersToBeSubscribed.Remove(layerToBeRemoved);
}
if (compositionLayers.Contains(layerToBeRemoved))
{
compositionLayers.Remove(layerToBeRemoved);
}
}
}
private void UpdateLayerStatus()
{
SortCompositionLayers();
RenderCompositionLayers();
}
private void SortCompositionLayers()
{
if (compositionLayers == null)
{
return;
}
CompositionLayerRenderPriorityComparer renderPriorityComparer = new CompositionLayerRenderPriorityComparer();
compositionLayers.Sort(renderPriorityComparer);
}
private void RenderCompositionLayers()
{
UpdateMaxLayerCount();
for (int layerIndex=0; layerIndex < compositionLayers.Count; layerIndex++)
{
if (layerIndex < maxLayerCount) //Render as normal layers
{
if (compositionLayers[layerIndex].RenderAsLayer()) //Successfully initialized
{
DEBUG("RenderCompositionLayers: Layer " + compositionLayers[layerIndex].name + " Initialized successfully, Priority: " + compositionLayers[layerIndex].GetRenderPriority() + " layerIndex: " + layerIndex);
}
else
{
DEBUG("RenderCompositionLayers: Layer Initialization failed." + " layerIndex: " + layerIndex);
}
}
else //Fallback if enabled
{
compositionLayers[layerIndex].RenderInGame();
DEBUG("RenderCompositionLayers: Layer " + compositionLayers[layerIndex].name + " Rendering in game, Priority: " + compositionLayers[layerIndex].GetRenderPriority() + " layerIndex: " + layerIndex);
}
}
}
private void UpdateMaxLayerCount()
{
XrSystemProperties xrSystemProperties = new XrSystemProperties();
XrResult result;
compositionLayerFeature = OpenXRSettings.Instance.GetFeature<ViveCompositionLayer>();
if (compositionLayerFeature != null)
{
if ((result = compositionLayerFeature.GetSystemProperties(ref xrSystemProperties)) == XrResult.XR_SUCCESS)
{
maxLayerCount = xrSystemProperties.graphicsProperties.maxLayerCount;
}
else
{
ERROR("Failed to get max layer count: " + result);
}
}
else
{
ERROR("compositionLayerFeature not found");
maxLayerCount = 0;
}
}
class CompositionLayerRenderPriorityComparer : IComparer<CompositionLayer>
{
public int Compare(CompositionLayer layerX, CompositionLayer layerY)
{
//Rule1: Higher Render Priority -> Front of the list
//Rule2: Same Render Priority -> Do not move layer
if (layerX.GetRenderPriority() > layerY.GetRenderPriority())
{
return -1;
}
else if (layerX.GetRenderPriority() < layerY.GetRenderPriority())
{
return 1;
}
else
{
return 0;
}
}
}
}
}