using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
///
/// Class to handle the Material Upgraders and fetching of them
///
internal class MaterialUpgraderRegistry
{
private static Lazy m_Instance = new(() => new MaterialUpgraderRegistry());
///
/// Singleton instance of the registry.
///
public static MaterialUpgraderRegistry instance => m_Instance.Value;
Dictionary> m_UpgradersSupportedByPipeline = new();
///
/// Returns a list of with a given asset type
///
/// A valid RP asset type
/// Returns a list of
public List GetMaterialUpgradersForPipeline(Type renderPipelineAssetType)
{
List materialUpgraders = GetOrCreateMaterialUpgradersForPipeline(renderPipelineAssetType);
materialUpgraders.AddRange(GetOrCreateMaterialUpgradersForPipeline(typeof(RenderPipelineAsset)));
materialUpgraders.Sort(CompareUpgradersByOldShaderAndPriority);
return materialUpgraders;
}
private int CompareUpgradersByOldShaderAndPriority(MaterialUpgrader a, MaterialUpgrader b)
{
string nameA = a?.OldShaderPath ?? string.Empty;
string nameB = b?.OldShaderPath ?? string.Empty;
int nameComparison = string.Compare(nameA, nameB, StringComparison.Ordinal);
if (nameComparison != 0)
return nameComparison;
// If names are the same, compare by priority
return b.priority.CompareTo(a.priority);
}
MaterialUpgraderRegistry()
{
var providerTypes = TypeCache.GetTypesDerivedFrom();
foreach (var providerType in providerTypes)
{
if (providerType.IsAbstract)
continue;
var provider = Activator.CreateInstance(providerType) as IMaterialUpgradersProvider;
var upgraders = provider.GetUpgraders();
if (upgraders == null)
continue;
var pipelineTypes = GetSupportedPipelines(providerType);
if (pipelineTypes.Length == 0)
pipelineTypes = new Type[] { typeof(RenderPipelineAsset) }; // Default to all pipelines if none specified
foreach (var pipelineType in pipelineTypes)
{
var upgradersForPipeline = GetOrCreateMaterialUpgradersForPipeline(pipelineType);
foreach(var upgrader in upgraders)
{
upgradersForPipeline.Add(upgrader);
}
}
}
}
private static Type[] GetSupportedPipelines(Type upgraderType)
{
var attr = upgraderType.GetCustomAttribute();
if (attr == null)
throw new InvalidOperationException($"Missing {nameof(SupportedOnRenderPipelineAttribute)} on {upgraderType}");
return attr.renderPipelineTypes;
}
private List GetOrCreateMaterialUpgradersForPipeline(Type renderPipelineAssetType)
{
if (!typeof(RenderPipelineAsset).IsAssignableFrom(renderPipelineAssetType))
throw new ArgumentException($"Type '{renderPipelineAssetType.FullName}' must inherit from RenderPipelineAsset.", nameof(renderPipelineAssetType));
if (!m_UpgradersSupportedByPipeline.TryGetValue(renderPipelineAssetType, out var upgradersForPipeline))
{
upgradersForPipeline = new List();
m_UpgradersSupportedByPipeline[renderPipelineAssetType] = upgradersForPipeline;
}
return upgradersForPipeline;
}
}
}