Skip to content

Commit bec6c82

Browse files
pema99Evergreen
authored andcommitted
[6000.0] Fix excessive memory usage in APV
1 parent c8c68f9 commit bec6c82

File tree

6 files changed

+121
-20
lines changed

6 files changed

+121
-20
lines changed

Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeGIBaking.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,12 @@ public void Dispose()
641641

642642
static bool m_IsInit = false;
643643
static BakingBatch m_BakingBatch;
644-
static ProbeVolumeBakingSet m_BakingSet = null;
644+
static ProbeVolumeBakingSetWeakReference m_BakingSetReference = new();
645+
static ProbeVolumeBakingSet m_BakingSet
646+
{
647+
get => m_BakingSetReference.Get();
648+
set => m_BakingSetReference.Set(value);
649+
}
645650
static TouchupVolumeWithBoundsList s_AdjustmentVolumes;
646651

647652
static Bounds globalBounds = new Bounds();

Packages/com.unity.render-pipelines.core/Editor/Lighting/ProbeVolume/ProbeVolumeLightingTab.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,18 @@ static ProbeVolumeBakingSet defaultSet
112112
bool m_TempBakingSet = false;
113113
bool m_Initialized = false;
114114

115-
ProbeVolumeBakingSet m_ActiveSet;
115+
ProbeVolumeBakingSetWeakReference m_ActiveSet = new();
116116
ProbeVolumeBakingSet activeSet
117117
{
118-
get => m_ActiveSet;
118+
get => m_ActiveSet.Get();
119119
set
120120
{
121-
if (ReferenceEquals(m_ActiveSet, value)) return;
122-
if (m_TempBakingSet) Object.DestroyImmediate(m_ActiveSet);
123-
m_ActiveSet = value;
121+
if (ReferenceEquals(m_ActiveSet.Get(), value)) return;
122+
if (m_TempBakingSet) Object.DestroyImmediate(m_ActiveSet.Get());
123+
m_ActiveSet.Set(value);
124124
m_TempBakingSet = false;
125-
if (m_ActiveSet == null) return;
126-
m_SingleSceneMode = m_ActiveSet.singleSceneMode;
125+
if (m_ActiveSet.Get() == null) return;
126+
m_SingleSceneMode = m_ActiveSet.Get().singleSceneMode;
127127
InitializeSceneList();
128128
}
129129
}
@@ -169,14 +169,14 @@ public override void OnEnable()
169169

170170
bool FindActiveSet()
171171
{
172-
if (m_ActiveSet == null)
172+
if (m_ActiveSet.Get() == null)
173173
{
174174
activeSet = ProbeVolumeBakingSet.GetBakingSetForScene(SceneManager.GetActiveScene());
175175
for (int i = 0; activeSet == null && i < SceneManager.sceneCount; i++)
176176
activeSet = ProbeVolumeBakingSet.GetBakingSetForScene(SceneManager.GetSceneAt(i));
177177
}
178178

179-
return m_ActiveSet != null;
179+
return m_ActiveSet.Get() != null;
180180
}
181181

182182
void Initialize()

Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeReferenceVolume.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,8 +726,19 @@ public struct ExtraDataActionInput
726726
// Information of the probe volume scenes that is being loaded (if one is pending)
727727
List<string> m_ActiveScenes = new List<string>();
728728

729-
ProbeVolumeBakingSet m_CurrentBakingSet = null;
730-
ProbeVolumeBakingSet m_LazyBakingSet = null;
729+
ProbeVolumeBakingSetWeakReference m_CurrentBakingSetReference = new();
730+
ProbeVolumeBakingSet m_CurrentBakingSet
731+
{
732+
get => m_CurrentBakingSetReference.Get();
733+
set => m_CurrentBakingSetReference.Set(value);
734+
}
735+
736+
ProbeVolumeBakingSetWeakReference m_LazyBakingSetReference = new();
737+
ProbeVolumeBakingSet m_LazyBakingSet
738+
{
739+
get => m_LazyBakingSetReference.Get();
740+
set => m_LazyBakingSetReference.Set(value);
741+
}
731742

732743
bool m_NeedLoadAsset = false;
733744
bool m_ProbeReferenceVolumeInit = false;

Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSet.Editor.cs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ internal class SceneBakeData
2222

2323
[SerializeField]
2424
SerializedDictionary<string, SceneBakeData> m_SceneBakeData = new();
25-
internal static Dictionary<string, ProbeVolumeBakingSet> sceneToBakingSet = new Dictionary<string, ProbeVolumeBakingSet>();
25+
internal static Dictionary<string, ProbeVolumeBakingSetWeakReference> sceneToBakingSet = new Dictionary<string, ProbeVolumeBakingSetWeakReference>();
2626

2727
/// <summary>
2828
/// Tries to add a scene to the baking set.
@@ -42,7 +42,7 @@ internal void AddScene(string guid, SceneBakeData bakeData = null)
4242
{
4343
m_SceneGUIDs.Add(guid);
4444
m_SceneBakeData.Add(guid, bakeData != null ? bakeData : new SceneBakeData());
45-
sceneToBakingSet[guid] = this;
45+
sceneToBakingSet[guid] = new ProbeVolumeBakingSetWeakReference(this);
4646

4747
EditorUtility.SetDirty(this);
4848
}
@@ -65,7 +65,7 @@ internal void SetScene(string guid, int index, SceneBakeData bakeData = null)
6565
var previousSceneGUID = m_SceneGUIDs[index];
6666
m_SceneGUIDs[index] = guid;
6767
sceneToBakingSet.Remove(previousSceneGUID);
68-
sceneToBakingSet[guid] = this;
68+
sceneToBakingSet[guid] = new ProbeVolumeBakingSetWeakReference(this);
6969
m_SceneBakeData.Add(guid, bakeData != null ? bakeData : new SceneBakeData());
7070

7171
EditorUtility.SetDirty(this);
@@ -291,26 +291,34 @@ public string RenameScenario(string scenario, string newName)
291291

292292
internal static void SyncBakingSets()
293293
{
294-
sceneToBakingSet = new Dictionary<string, ProbeVolumeBakingSet>();
294+
sceneToBakingSet = new Dictionary<string, ProbeVolumeBakingSetWeakReference>();
295295

296-
var setGUIDs = AssetDatabase.FindAssets("t:" + typeof(ProbeVolumeBakingSet).Name);
296+
var setGUIDs = AssetDatabase.FindAssets("t:" + nameof(ProbeVolumeBakingSet));
297297

298298
foreach (var setGUID in setGUIDs)
299299
{
300-
var set = AssetDatabase.LoadAssetAtPath<ProbeVolumeBakingSet>(AssetDatabase.GUIDToAssetPath(setGUID));
300+
string bakingSetPath = AssetDatabase.GUIDToAssetPath(setGUID);
301+
bool alreadyLoaded = AssetDatabase.IsMainAssetAtPathLoaded(bakingSetPath);
302+
303+
var set = AssetDatabase.LoadAssetAtPath<ProbeVolumeBakingSet>(bakingSetPath);
301304
if (set != null)
302305
{
303306
// We need to call Migrate here because of Version.RemoveProbeVolumeSceneData step.
304307
// This step needs the obsolete ProbeVolumeSceneData to be initialized first which can happen out of order. Here we now it's ok.
305308
set.Migrate();
306309

310+
var reference = new ProbeVolumeBakingSetWeakReference(set);
307311
foreach (var guid in set.sceneGUIDs)
308-
sceneToBakingSet[guid] = set;
312+
sceneToBakingSet[guid] = reference;
313+
314+
// If the asset wasn't already in-memory, and we just loaded it into memory, free it, so we don't waste memory.
315+
if (!alreadyLoaded)
316+
reference.Unload();
309317
}
310318
}
311319
}
312320

313-
internal static ProbeVolumeBakingSet GetBakingSetForScene(string sceneGUID) => sceneToBakingSet.GetValueOrDefault(sceneGUID, null);
321+
internal static ProbeVolumeBakingSet GetBakingSetForScene(string sceneGUID) => sceneToBakingSet.GetValueOrDefault(sceneGUID, null)?.Get();
314322
internal static ProbeVolumeBakingSet GetBakingSetForScene(Scene scene) => GetBakingSetForScene(scene.GetGUID());
315323

316324
internal void SetDefaults()
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
namespace UnityEngine.Rendering
2+
{
3+
// Q: What is this?
4+
// A: A utility class for storing a reference to a ProbeVolumeBakingSet, without forcing the object to be loaded in-memory.
5+
6+
// Q: Why do we need this?
7+
// A: APV uses a lot of global state, and we aren't always good with cleaning it up. Unity's serialization layer will automatically
8+
// load referenced assets into memory, recursively. Some of the assets referenced by ProbeVolumeBakingSet can get very large, on
9+
// the order of several gigabytes. A lingering global reference to a ProbeVolumeBakingSet can keep these assets in memory indefinitely,
10+
// preventing them from being garbage collected. By using a weak reference, we prevent this - ProbeVolumeBakingSet can be freely
11+
// garbage collected. Whenever we actually need to access it, we load it on-demand, if it isn't already in memory.
12+
13+
internal class ProbeVolumeBakingSetWeakReference
14+
{
15+
public int m_InstanceID;
16+
17+
public ProbeVolumeBakingSetWeakReference(ProbeVolumeBakingSet bakingSet)
18+
{
19+
Set(bakingSet);
20+
}
21+
22+
public ProbeVolumeBakingSetWeakReference()
23+
{
24+
m_InstanceID = 0;
25+
}
26+
27+
// Change which baking set the references points to.
28+
public void Set(ProbeVolumeBakingSet bakingSet)
29+
{
30+
if (bakingSet == null)
31+
m_InstanceID = 0;
32+
else
33+
m_InstanceID = bakingSet.GetInstanceID();
34+
}
35+
36+
// Get the referenced baking set, loading it into memory if necessary.
37+
public ProbeVolumeBakingSet Get()
38+
{
39+
return Resources.InstanceIDToObject(m_InstanceID) as ProbeVolumeBakingSet;
40+
}
41+
42+
// Is the referenced baking set in memory?
43+
public bool IsLoaded()
44+
{
45+
return Resources.InstanceIDIsValid(m_InstanceID);
46+
}
47+
48+
// Force the referenced baking set to be unloaded from memory.
49+
// Calling Get() after Unload() will re-load the baking set into memory.
50+
public void Unload()
51+
{
52+
if (!IsLoaded())
53+
return;
54+
55+
var bakingSet = Get();
56+
57+
// These assets would get garbage collected, but we clean them up immediately to free memory earlier.
58+
// Only do this in editor, where the assets are never needed, so we don't unload assets that may still be in use.
59+
#if UNITY_EDITOR
60+
Resources.UnloadAsset(bakingSet.cellBricksDataAsset?.asset);
61+
Resources.UnloadAsset(bakingSet.cellSharedDataAsset?.asset);
62+
Resources.UnloadAsset(bakingSet.cellSupportDataAsset?.asset);
63+
foreach (var scenario in bakingSet.scenarios)
64+
{
65+
Resources.UnloadAsset(scenario.Value.cellDataAsset?.asset);
66+
Resources.UnloadAsset(scenario.Value.cellOptionalDataAsset?.asset);
67+
Resources.UnloadAsset(scenario.Value.cellProbeOcclusionDataAsset?.asset);
68+
}
69+
#endif
70+
71+
// Unload the baking set itself.
72+
Resources.UnloadAsset(bakingSet);
73+
}
74+
}
75+
}

Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolumeBakingSetWeakReference.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)