Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Reference Counting Cache refactoring #2182

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

mikhail-dcl
Copy link
Collaborator

@mikhail-dcl mikhail-dcl commented Sep 26, 2024

Fixes #2126

  • Unified cache with ref counting capabilities for all suitable streamables:
    • Removed faulty logic that does not take into account real referencing count but relies on timestamp only
    • Introduced RefCountStreamableCacheBase for:
      • Profiles
      • Asset Bundles
      • Audio Clips
      • Nft Shape
      • Textures
    • It follows FIFO principle on clean-up: the last used asset will be unloaded first
    • Restricted to the only way to dereference via StreamableRefCountData<TAsset>, it is the base class for all cached assets with ref counting
  • Introduced reference counting for Textures:
    • Before we didn't care about it so there were many places required attention:
      • Materials already were releasing properly: they required minimum adjustments
      • Introduced proper handling of:
        • Profile Pictures
        • NFT Shapes
        • Avatar Attachment Thumbnail (Emotes and Wearables)
        • UI Background
        • Map Pins

How to QA

Following this pattern:

  • Find the scene with the corresponding asset/assets
  • Press Memory.FULL in Debug Menu
  • The given asset(-s) should remain in tact
  • Press Memory.NORMAL
  • Leave the scene (till it's unloaded or changed to LOD)
  • You should observe no "Reference count of {typeof(TAsset).Name} should never be negative!" errors

All the affected assets should be verified:

  • NFT Shapes
  • UI Background
  • Map Pins
  • Textures
  • Asset Bundles
  • Audio Clips

For Avatar Attachments check that thumbnails do not disappear (backpack, passport) after setting Memory.FULL

- Textures referencing, Sprites handling, all systems are changed accordingly
  - UIBackground
  - NFT
  - Avatar Attachment Thumbnails
  - Materials
  - Map Pins
- Common Ref Counting Data
- Asset Bundle Cache, Audio Cache, Profiles Cache are unified
 - Unify Video Texture with Texture2DData
 - Fix tests
# Conflicts:
#	Explorer/Assets/DCL/PluginSystem/Global/MultiplayerMovementPlugin.cs
Copy link

github-actions bot commented Sep 26, 2024

badge

Windows and Mac build successfull in Unity Cloud! You can find a link to the downloadable artifact below.

Name Link
Commit fa62231
Logs https://github.com/decentraland/unity-explorer/actions/runs/11128924080
Download Windows https://github.com/decentraland/unity-explorer/suites/29077124661/artifacts/2001872224
Download Mac https://github.com/decentraland/unity-explorer/suites/29077124661/artifacts/2001904623
Built on 2024-10-01T16:46:53Z

Copy link

@Ludmilafantaniella Ludmilafantaniella left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 QA Approved. The assets no longer disappear after pressing the FULL button in memory settings.

This fix was verified on Windows and Mac. A smoke test was performed, covering:

  • Backpack
  • Emotes
  • Nav bar (all shortcuts)
  • Badges/Profile Customization
  • Map navigation
  • Scenes/worlds (Doll House/Seed/Casa Roustan/Metadynelabs).

Copy link
Collaborator

@dalkia dalkia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice PR! Cache is looking so much better <3

Left some cleaning suggestions, and a possible leak detection. let me know your thoughts!

using Object = UnityEngine.Object;

namespace ECS.StreamableLoading.AssetBundles
{
/// <summary>
/// A wrapper over <see cref="AssetBundle" /> to provide additional data
/// </summary>
public class AssetBundleData : IAssetData
public class AssetBundleData : StreamableRefCountData<AssetBundle>, IStreamableRefCountData
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IStreamableRefCountData is redudant here

namespace ECS.StreamableLoading.Cache
{
public abstract class RefCountStreamableCacheBase<TAssetData, TAsset, TLoadingIntention> : IEqualityComparer<TLoadingIntention>
where TAssetData: StreamableRefCountData<TAsset> where TAsset: class
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in DM, can we make this abstract class implement IStreamableCache so it appears in Rider? Right now, it doesnt.

Also, some redudancy will appear when doing so, the explicit inheritance wont be needed in the child of this class.

image

public bool TryGet(in TLoadingIntention key, out TAssetData asset) =>
cache.TryGetValue(key, out asset);

public void AddReference(in TLoadingIntention _, TAssetData asset)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can make this one internal since its only used for testing?

/// Needed for non-ECS code to properly handle reference counting
/// </summary>
/// <returns></returns>
public RefAcquisition AcquireRef() =>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isnt it a little bit YAGNI? Some examples come to mind? As far as I see, this is not beieng used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a mess with profiles where it will be needed, I wanted to address it straight-away but the scope was too big

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to leave it here even for the existing assets so e.g. if the texture is requested from UI it can be owned and later unowned

{
private int referencesCount;
public AudioClip AudioClip => Asset;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not used anywhere. Should we remove it for clarity? Seems like Asset is the way to access the Audio

}

public void Dispose()
{
// On Dispose video textures are dereferenced by material that acquired it
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have a leak here.

This texture was never added to the texture cache, since its not created through LoadSystemBase, but rather on the fly by VideoTextureUtils, gotten through the videoTexturesPool.I understand that by this point it should not hold any reference since it was dereferenced by the material that it was using it and now destroyed.

But shouldnt it be returned to the pool here, rather than nullifying it?

Whatsmore, cleaning of this pool cache for this pool is not clear.

I see that its injected in MediaPlayerPluginWrapper and then registered to the cache cleanear, as part of the avatarPools. The name is super misleading, but Im ignoring that. When this type of pool cache is cleared in ExtendedObjectPool.ClearThrottled, only objects in the pool are cleared. But I couldnt find the place where we returned the video texture to the pool.

It may be out of scopre of this PR, but as I see it, I think we have a leak here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the only place where we return the video texture to the pool and call Dispose:

        private void CleanUpVideoTexture(ref VideoTextureConsumer videoTextureConsumer)
        {
            videoTexturesPool.Release(videoTextureConsumer.Texture);
            videoTextureConsumer.Dispose();
        }

in CleanUpMediaPlayerSystem

and VideoTextureConsumer itself is not bound to the pool itself (by design), that's why it does not handle returning to the pool.

I preserved the original design

# Conflicts:
#	Explorer/Assets/DCL/AvatarRendering/Emotes/Components/IEmote.cs
#	Explorer/Assets/DCL/SDKComponents/SceneUI/Systems/UIBackground/UIBackgroundInstantiationSystem.cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Current scenes's textures are being unloaded by the cache cleaner
3 participants