CesiumGS / cesium-native

Apache License 2.0
438 stars 215 forks source link

Fix asset lifetime, avoid circular reference counting. #964

Closed kring closed 1 month ago

kring commented 1 month ago

This is a PR into #926.

@azrogers quite correctly noticed that the shared asset system, after my recent changes, had circular reference counting that would guarantee assets were never destroyed. So this PR fixes that.


It's a little confusing, but here's how I think about this (some of this should move into comments in the code). An asset like ImageCesium can be in one of three states:

Independent Asset

An independent asset isn't affiliated with an asset depot at all. Its lifetime is controlled exclusively by IntrusivePointer / reference counting. When the asset's reference count goes to zero, it deletes itself. An independent asset's _pDepot is nullptr.

Active Depot Asset

This is an asset that is owned by an asset depot and that is in use, meaning it has a reference count greater than zero. The asset depot owns the asset via a std::unique_ptr, not via adding to the reference count. So when the reference count goes to zero, only the asset depot itself still has a reference to it, so it becomes an inactive depot asset.

Inactive Depot Asset

This is also an asset that is owned by the asset depot, but there are no other references to it (it has a reference count of zero). It is found in the asset depot's deletionCandidates list. When a reference to it is added, it is removed from deletionCandidates and it becomes an active depot asset.


SharedAssets now have a raw pointer to the depot instead of an IntrusivePointer. An asset depot can be destroyed at any time, even if some of the assets it manages are still in use. When this happens, all of the assets the depot held are converted to Independent Assets, by setting _pDepot=nullptr. If the reference count is zero, they'll be destroyed immediately. Either way, this avoids a dangling pointer to the now-deleted depot.

This PR also removes an unnecessary pure virtual function in SharedAsset, which was causing a compiler error for me when building cesium-unreal.