@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.
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 fromdeletionCandidates
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.