ContentManager.ReadAsset

ContentManager.ReadAsset

Rate This
  • Comments 4

ContentManager.ReadAsset is a new function coming in the next version of the XNA Framework. What is it for, and why should you care?

You almost certainly don't care. In fact you should probably stop reading this blog post right now.

ReadAsset is for crazy people who want to customize how the ContentManager resolves shared asset references, or how it manages object lifespans. The vast majority of users will be fine with the default behavior, so will never need to know about this.

ReadAsset is a protected method that loads data directly from an XNB file, bypassing the higher level policies implemented by the default Load implementation. When called from an overridden Load method, this gives you the flexibility to do pretty much anything you want.

For instance this simple customization bypasses the default shared reference tracking:

    class MyContentManager : ContentManager
{
public MyContentManager(IServiceProvider serviceProvider)
: base(serviceProvider)
{ }

public override T Load<T>(string assetName)
{
return ReadAsset<T>(assetName, null);
}
}

With this tweaked ContentManager, every time you call Load you will get back a fresh copy of the asset. If you load two models that both reference the same texture, they will each load a separate copy of that texture.

The second parameter to ReadAsset is a delegate used to keep track of disposable objects. If you pass null, the default implementation remembers everything that is disposable, and frees them all in one go when the ContentManager is unloaded. You can change this behavior by passing a custom delegate:

    class MyContentManager : ContentManager
{
public MyContentManager(IServiceProvider serviceProvider)
: base(serviceProvider)
{ }

public override T Load<T>(string assetName)
{
return ReadAsset<T>(assetName, IgnoreDisposableAsset);
}

void IgnoreDisposableAsset(IDisposable disposable)
{
}
}

Because the IgnoreDisposableAsset delegate does nothing, this ContentManager will not track asset lifespans in any way. I don't recommend that, but maybe it would be useful for someone who intends to manually dispose all their content, or who places an inordinate amount of trust in the garbage collector!

As a more realistic example, this version reproduces the behavior of the default ContentManager, merging shared assets and keeping track of disposable content:

    class MyContentManager : ContentManager
{
public MyContentManager(IServiceProvider serviceProvider)
: base(serviceProvider)
{ }


Dictionary<string, object> loadedAssets = new Dictionary<string, object>();
List<IDisposable> disposableAssets = new List<IDisposable>();


public override T Load<T>(string assetName)
{
if (loadedAssets.ContainsKey(assetName))
return (T)loadedAssets[assetName];

T asset = ReadAsset<T>(assetName, RecordDisposableAsset);

loadedAssets.Add(assetName, asset);

return asset;
}


public override void Unload()
{
foreach (IDisposable disposable in disposableAssets)
disposable.Dispose();

loadedAssets.Clear();
disposableAssets.Clear();
}


void RecordDisposableAsset(IDisposable disposable)
{
disposableAssets.Add(disposable);
}
}

To implement more sophisticated asset management policies, you can keep track of recursive calls to the Load method, building up trees recording which meshes loaded what textures, how many meshes are referencing each texture, etc. You can then use that information to provide arbitrarily complex loading and unloading functionality.

If you need to, that is. Most people won't want to bother.

  • Great article!

    But I have one question. Game class supplies us with an instance of ContentManager (Game.Content), so we should just create the second one?

    In Understanding XNA Framework Performance we can read that it is ok to have multiple instances (of ContentManager), but only one per thread. Is it ok to create a second instance on the main thread?

  • incrediably useful post, don't under estimate it!  automatically sharing resources is sometimes far far from the desirable behaviour (although I understand why, I was a bit shocked that it was the default!) - invaluable to me to now know how to disable it!

  • Thank you so much Shawn !

    As Dave mentioned, this is great post (as usual) !

  • Thanks! It helped!

Page 1 of 1 (4 items)
Leave a Comment
  • Please add 5 and 2 and type the answer here:
  • Post