Skip to content

Commit d935fe1

Browse files
svc-reach-platform-supportEvergreen
authored andcommitted
[Port] [6000.4] Initialise VolumeManager BaseComponentTypes from DefaultProfile to avoid reflection and reduce startup overhead
1 parent 3c80397 commit d935fe1

18 files changed

Lines changed: 1753 additions & 1210 deletions

File tree

Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeComponentEditor.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ internal void SetVolumeProfile(VolumeProfile p)
196196

197197
static Dictionary<Type, VolumeParameterDrawer> s_ParameterDrawers;
198198
SupportedOnRenderPipelineAttribute m_SupportedOnRenderPipelineAttribute;
199-
Type[] m_LegacyPipelineTypes;
200199

201200
static VolumeComponentEditor()
202201
{
@@ -274,11 +273,6 @@ internal void Init()
274273

275274
var volumeComponentType = volumeComponent.GetType();
276275
m_SupportedOnRenderPipelineAttribute = volumeComponentType.GetCustomAttribute<SupportedOnRenderPipelineAttribute>();
277-
278-
#pragma warning disable CS0618
279-
var supportedOn = volumeComponentType.GetCustomAttribute<VolumeComponentMenuForRenderPipeline>();
280-
m_LegacyPipelineTypes = supportedOn != null ? supportedOn.pipelineTypes : Array.Empty<Type>();
281-
#pragma warning restore CS0618
282276
}
283277

284278
internal void DetermineVisibility(Type renderPipelineAssetType, Type renderPipelineType)
@@ -295,12 +289,6 @@ internal void DetermineVisibility(Type renderPipelineAssetType, Type renderPipel
295289
return;
296290
}
297291

298-
if (renderPipelineType != null && m_LegacyPipelineTypes.Length > 0)
299-
{
300-
visible = m_LegacyPipelineTypes.Contains(renderPipelineType);
301-
return;
302-
}
303-
304292
visible = true;
305293
}
306294

Packages/com.unity.render-pipelines.core/Editor/Volume/VolumeProfileUtils.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,19 +140,19 @@ static VolumeComponent GetVolumeComponentOfTypeOrDefault(this VolumeProfile prof
140140
static List<Type> GetTypesMissingFromDefaultProfile(VolumeProfile profile)
141141
{
142142
List<Type> missingTypes = new List<Type>();
143-
var volumeComponentTypes = VolumeManager.instance.baseComponentTypeArray;
143+
144+
var volumeComponentTypes = VolumeManager.instance.isInitialized ?
145+
VolumeManager.instance.baseComponentTypeArray : VolumeManager.instance.LoadBaseTypesByReflection(GraphicsSettings.currentRenderPipelineAssetType);
144146
foreach (var type in volumeComponentTypes)
145147
{
146148
if (profile.components.Find(c => c.GetType() == type) == null)
147149
{
148-
if (type.IsDefined(typeof(ObsoleteAttribute), false) ||
149-
type.IsDefined(typeof(HideInInspector), false))
150+
if (type.IsDefined(typeof(ObsoleteAttribute), false))
150151
continue;
151152

152153
missingTypes.Add(type);
153154
}
154155
}
155-
156156
return missingTypes;
157157
}
158158

@@ -163,13 +163,14 @@ static List<Type> GetTypesMissingFromDefaultProfile(VolumeProfile profile)
163163
/// <param name="profile">VolumeProfile to use.</param>
164164
/// <param name="defaultValueSource">An optional VolumeProfile asset containing default values to use for
165165
/// any components that are added to <see cref="profile"/>.</param>
166-
public static void EnsureAllOverridesForDefaultProfile(VolumeProfile profile, VolumeProfile defaultValueSource = null)
166+
public static void EnsureAllOverridesForDefaultProfile(VolumeProfile profile, VolumeProfile defaultValueSource = null) => TryEnsureAllOverridesForDefaultProfile(profile, defaultValueSource);
167+
internal static bool TryEnsureAllOverridesForDefaultProfile(VolumeProfile profile, VolumeProfile defaultValueSource = null)
167168
{
168169
// It's possible that the volume profile is assigned to the default asset inside the HDRP package. In
169170
// this case it cannot be modified. User is expected to use HDRP Wizard "Fix" to create a local profile.
170171
var path = AssetDatabase.GetAssetPath(profile);
171172
if (CoreEditorUtils.IsAssetInReadOnlyPackage(path))
172-
return;
173+
return false;
173174

174175
bool changed = false;
175176
int numComponentsBefore = profile.components.Count;
@@ -241,6 +242,8 @@ public static void EnsureAllOverridesForDefaultProfile(VolumeProfile profile, Vo
241242
VolumeManager.instance.OnVolumeProfileChanged(profile);
242243
EditorUtility.SetDirty(profile);
243244
}
245+
246+
return changed;
244247
}
245248

246249
/// <summary>

Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeComponent.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public VolumeComponentMenu(string menu)
4545
/// This attribute allows you to add commands to the <b>Add Override</b> popup menu on Volumes,
4646
/// while also specifying the render pipeline(s) for which the command will be supported.
4747
/// </summary>
48-
[Obsolete(@"VolumeComponentMenuForRenderPipelineAttribute is deprecated. Use VolumeComponentMenu with SupportedOnRenderPipeline instead. #from(2023.1)")]
48+
[Obsolete(@"VolumeComponentMenuForRenderPipelineAttribute is deprecated. Use VolumeComponentMenu with SupportedOnRenderPipeline instead. #from(2023.1)", true)]
4949
public class VolumeComponentMenuForRenderPipeline : VolumeComponentMenu
5050
{
5151
/// <summary>
@@ -126,7 +126,7 @@ public sealed class VolumeComponentDeprecated : Attribute
126126
/// <para>
127127
/// In the example above, the custom component `ExampleComponent` extends `VolumeComponent` and defines a parameter
128128
/// (`intensity`) that can be manipulated within the volume framework. The `ClampedFloatParameter` is a type of
129-
/// <see cref="VolumeParameter{T}"/> that ensures the value remains within a specified range.
129+
/// <see cref="VolumeParameter{T}"/> that ensures the value remains within a specified range.
130130
/// </para>
131131
/// </example>
132132
[Serializable]
@@ -164,7 +164,7 @@ public Indent(int relativeAmount = 1)
164164
/// The backing storage of <see cref="parameters"/>. Use this for performance-critical work.
165165
/// </summary>
166166
internal VolumeParameter[] parameterList;
167-
167+
168168
ReadOnlyCollection<VolumeParameter> m_ParameterReadOnlyCollection;
169169

170170
/// <summary>
@@ -355,7 +355,7 @@ public bool AnyPropertiesIsOverridden()
355355
{
356356
for (int i = 0; i < parameterList.Length; ++i)
357357
{
358-
if (parameterList[i].overrideState)
358+
if (parameterList[i].overrideState)
359359
return true;
360360
}
361361
return false;

Packages/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs

Lines changed: 74 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ namespace UnityEngine.Rendering
4141
/// <seealso cref="GraphicsSettings"/>
4242
public sealed partial class VolumeManager
4343
{
44+
static readonly ProfilerMarker k_ProfilerMarkerInitialize = new ("VolumeManager.Initialize");
45+
static readonly ProfilerMarker k_ProfilerMarkerInitializeBaseTypesArray = new ("VolumeManager.InitializeBaseTypesArray");
4446
static readonly ProfilerMarker k_ProfilerMarkerUpdate = new ("VolumeManager.Update");
4547
static readonly ProfilerMarker k_ProfilerMarkerReplaceData = new ("VolumeManager.ReplaceData");
4648
static readonly ProfilerMarker k_ProfilerMarkerEvaluateVolumeDefaultState = new ("VolumeManager.EvaluateVolumeDefaultState");
@@ -78,7 +80,7 @@ public sealed partial class VolumeManager
7880
return supportedVolumeComponents;
7981

8082
if (baseComponentTypeArray == null)
81-
LoadBaseTypes(currentPipelineAssetType);
83+
InitializeBaseTypesArray();
8284

8385
supportedVolumeComponents = BuildVolumeComponentDisplayList(baseComponentTypeArray);
8486
s_SupportedVolumeComponentsForRenderPipeline[currentPipelineAssetType] = supportedVolumeComponents;
@@ -133,18 +135,17 @@ public sealed partial class VolumeManager
133135
volumes.Add((path, t));
134136
}
135137

136-
return volumes
137-
.OrderBy(i => i.Item1)
138-
.ToList();
138+
volumes.Sort((a, b) => string.Compare(a.Item1, b.Item1));
139+
return volumes;
139140
}
140-
141+
141142
Type[] m_BaseComponentTypeArray;
142143

143144
/// <summary>
144145
/// The current list of all available types that derive from <see cref="VolumeComponent"/>.
145146
/// </summary>
146-
public Type[] baseComponentTypeArray
147-
{
147+
public Type[] baseComponentTypeArray
148+
{
148149
get
149150
{
150151
if (isInitialized)
@@ -153,7 +154,7 @@ public Type[] baseComponentTypeArray
153154
throw new InvalidOperationException($"{nameof(VolumeManager)}.{nameof(instance)}.{nameof(baseComponentTypeArray)} cannot be called before the {nameof(VolumeManager)} is initialized. (See {nameof(VolumeManager)}.{nameof(instance)}.{nameof(isInitialized)} and {nameof(RenderPipelineManager)} for creation callback).");
154155
}
155156
internal set => m_BaseComponentTypeArray = value; // internal only for tests
156-
}
157+
}
157158

158159
/// <summary>
159160
/// Global default profile that provides default values for volume components. VolumeManager applies
@@ -247,13 +248,30 @@ internal VolumeManager()
247248
/// <param name="qualityDefaultVolumeProfile">Quality default volume profile.</param>
248249
public void Initialize(VolumeProfile globalDefaultVolumeProfile = null, VolumeProfile qualityDefaultVolumeProfile = null)
249250
{
251+
using var profilerScope = k_ProfilerMarkerInitialize.Auto();
250252
Debug.Assert(!isInitialized);
251253
Debug.Assert(m_CreatedVolumeStacks.Count == 0);
252254

253-
LoadBaseTypes(GraphicsSettings.currentRenderPipelineAssetType);
255+
InitializeBaseTypesArray(globalDefaultVolumeProfile);
256+
254257
InitializeInternal(globalDefaultVolumeProfile, qualityDefaultVolumeProfile);
255258
}
256259

260+
void InitializeBaseTypesArray(VolumeProfile globalDefaultVolumeProfile = null)
261+
{
262+
using var profilerScope = k_ProfilerMarkerInitializeBaseTypesArray.Auto();
263+
#if UNITY_EDITOR
264+
LoadBaseTypesByReflection(GraphicsSettings.currentRenderPipelineAssetType);
265+
#else
266+
if (globalDefaultVolumeProfile == null)
267+
{
268+
var defaultVolumeProfileSettings = GraphicsSettings.GetRenderPipelineSettings<IDefaultVolumeProfileAsset>();
269+
globalDefaultVolumeProfile = defaultVolumeProfileSettings?.defaultVolumeProfile;
270+
}
271+
LoadBaseTypes(globalDefaultVolumeProfile);
272+
#endif
273+
}
274+
257275
//This is called by test where the basetypes are tuned for the purpose of the test.
258276
internal void InitializeInternal(VolumeProfile globalDefaultVolumeProfile = null, VolumeProfile qualityDefaultVolumeProfile = null)
259277
{
@@ -293,6 +311,7 @@ public void Deinitialize()
293311
/// <param name="profile">The VolumeProfile to use as the global default profile.</param>
294312
public void SetGlobalDefaultProfile(VolumeProfile profile)
295313
{
314+
LoadBaseTypes(profile);
296315
globalDefaultProfile = profile;
297316
EvaluateVolumeDefaultState();
298317
}
@@ -315,6 +334,10 @@ public void SetCustomDefaultProfiles(List<VolumeProfile> profiles)
315334
{
316335
var validProfiles = profiles ?? new List<VolumeProfile>();
317336
validProfiles.RemoveAll(x => x == null);
337+
338+
if (globalDefaultProfile == null && validProfiles.Count > 0)
339+
globalDefaultProfile = validProfiles[0];
340+
318341
customDefaultProfiles = new ReadOnlyCollection<VolumeProfile>(validProfiles);
319342
EvaluateVolumeDefaultState();
320343
}
@@ -396,38 +419,44 @@ public void DestroyStack(VolumeStack stack)
396419
stack.Dispose();
397420
}
398421

399-
// For now, if a user is having a VolumeComponent with the old attribute for filtering support.
400-
// We are adding it to the supported volume components, but we are showing a warning.
401-
bool IsSupportedByObsoleteVolumeComponentMenuForRenderPipeline(Type t, Type pipelineAssetType)
422+
/// <summary>
423+
/// LoadBaseTypes is responsible for loading the list of VolumeComponent types that will be used to build the default state of the VolumeStack. It uses the provided global default profile to determine which component types are relevant for the current render pipeline.
424+
/// This will be called only once at runtime on app boot
425+
/// </summary>
426+
/// <param name="globalDefaultVolumeProfile">The global default volume profile to use to build the base component type array.</param>
427+
internal void LoadBaseTypes(VolumeProfile globalDefaultVolumeProfile)
402428
{
403-
var legacySupported = false;
404-
405-
#pragma warning disable CS0618
406-
var legacyPipelineAttribute = t.GetCustomAttribute<VolumeComponentMenuForRenderPipeline>();
407-
if (legacyPipelineAttribute != null)
429+
if (globalDefaultVolumeProfile == null)
408430
{
409-
Debug.LogWarning($"{nameof(VolumeComponentMenuForRenderPipeline)} is deprecated, use {nameof(SupportedOnRenderPipelineAttribute)} and {nameof(VolumeComponentMenu)} with {t} instead. #from(2023.1)");
410-
#if UNITY_EDITOR
411-
var renderPipelineTypeFromAsset = RenderPipelineEditorUtility.GetPipelineTypeFromPipelineAssetType(pipelineAssetType);
431+
m_BaseComponentTypeArray = Array.Empty<Type>();
432+
return;
433+
}
412434

413-
for (int i = 0; i < legacyPipelineAttribute.pipelineTypes.Length; ++i)
435+
using (ListPool<Type>.Get(out var list))
436+
{
437+
var pipelineAssetType = GraphicsSettings.currentRenderPipelineAssetType;
438+
foreach (var comp in globalDefaultVolumeProfile.components)
414439
{
415-
if (legacyPipelineAttribute.pipelineTypes[i] == renderPipelineTypeFromAsset)
416-
{
417-
legacySupported = true;
418-
break;
419-
}
440+
if (comp == null) continue;
441+
442+
var componentType = comp.GetType();
443+
if (!SupportedOnRenderPipelineAttribute.IsTypeSupportedOnRenderPipeline(componentType, pipelineAssetType))
444+
continue;
445+
446+
list.Add(componentType);
420447
}
421-
#endif
422-
}
423-
#pragma warning restore CS0618
424448

425-
return legacySupported;
449+
m_BaseComponentTypeArray = list.ToArray();
450+
}
426451
}
427452

428-
// This will be called only once at runtime and on domain reload / pipeline switch in the editor
429-
// as we need to keep track of any compatible component in the project
430-
internal void LoadBaseTypes(Type pipelineAssetType)
453+
#if UNITY_EDITOR
454+
/// <summary>
455+
/// This should only be called when we need to load base types without being able to trust default profiles are up to date. This is slow and uses Reflection!
456+
/// Will be called only once at runtime and on domain reload / pipeline switch in the editor as we need to keep track of any compatible component in the project
457+
/// </summary>
458+
/// <param name="pipelineAssetType">The Pipeline Type used to check if each VolumeComponent is supported.</param>
459+
internal Type[] LoadBaseTypesByReflection(Type pipelineAssetType)
431460
{
432461
// Grab all the component types we can find that are compatible with current pipeline
433462
using (ListPool<Type>.Get(out var list))
@@ -437,23 +466,25 @@ internal void LoadBaseTypes(Type pipelineAssetType)
437466
if (t.IsAbstract)
438467
continue;
439468

440-
var isSupported = SupportedOnRenderPipelineAttribute.IsTypeSupportedOnRenderPipeline(t, pipelineAssetType) ||
441-
IsSupportedByObsoleteVolumeComponentMenuForRenderPipeline(t, pipelineAssetType);
469+
if (!SupportedOnRenderPipelineAttribute.IsTypeSupportedOnRenderPipeline(t, pipelineAssetType))
470+
continue;
442471

443-
if (isSupported)
444-
list.Add(t);
472+
list.Add(t);
445473
}
446474

447475
m_BaseComponentTypeArray = list.ToArray();
448476
}
477+
478+
return m_BaseComponentTypeArray;
449479
}
480+
#endif
450481

451482
internal void InitializeVolumeComponents()
452483
{
453484
if (m_BaseComponentTypeArray == null || m_BaseComponentTypeArray.Length == 0)
454485
return;
455486

456-
// Call custom static Init method if present
487+
// Call deprecated static Init method if present
457488
var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
458489
foreach (var type in m_BaseComponentTypeArray)
459490
{
@@ -469,7 +500,11 @@ internal void InitializeVolumeComponents()
469500
void EvaluateVolumeDefaultState()
470501
{
471502
if (m_BaseComponentTypeArray == null || m_BaseComponentTypeArray.Length == 0)
503+
{
504+
m_ComponentsDefaultState = Array.Empty<VolumeComponent>();
505+
m_ParametersDefaultState = Array.Empty<VolumeParameter>();
472506
return;
507+
}
473508

474509
using var profilerScope = k_ProfilerMarkerEvaluateVolumeDefaultState.Auto();
475510

@@ -478,7 +513,7 @@ void EvaluateVolumeDefaultState()
478513
// Initialize() and the default state can be updated a lot quicker.
479514

480515
// First, default-construct all VolumeComponents
481-
List<VolumeComponent> componentsDefaultStateList = new();
516+
using var _ = ListPool<VolumeComponent>.Get(out var componentsDefaultStateList);
482517
foreach (var type in m_BaseComponentTypeArray)
483518
{
484519
componentsDefaultStateList.Add((VolumeComponent) ScriptableObject.CreateInstance(type));

Packages/com.unity.render-pipelines.high-definition/Editor/BuildProcessors/HDRPPreprocessBuild.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,21 @@ public void OnPreprocessBuild(BuildReport report)
4141

4242
ConfigureMinimumMaxLoDValueForAllQualitySettings();
4343

44+
if (HDRenderPipelineGlobalSettings.instance.TryInitializeDefaultVolumeProfile(out var defaultVolumeProfileSettings))
45+
{
46+
Debug.Log("Default Volume Profile has been created or Diffusion Profiles have been updated to ensure all components are present. This is required to avoid missing overrides at runtime which can lead to unexpected rendering issues. Please save these changes to avoid this message in the future.");
47+
}
48+
49+
if (defaultVolumeProfileSettings == null)
50+
{
51+
throw new BuildFailedException("Failed to initialize the Default Volume Profile. A Default Volume Profile is required for HDRP to function properly.");
52+
}
53+
54+
if (VolumeProfileUtils.TryEnsureAllOverridesForDefaultProfile(defaultVolumeProfileSettings.volumeProfile))
55+
{
56+
Debug.Log("Default Volume Profile has been modified to ensure all components are present. This is required to avoid missing overrides at runtime which can lead to unexpected rendering issues. Please save these changes to avoid this message in the future.");
57+
}
58+
4459
LogIncludedAssets(m_BuildData.renderPipelineAssets);
4560

4661
GatherShaderFeatures();

0 commit comments

Comments
 (0)