Abstracting entity caching in XNA
Posted
by
Grofit
on Game Development
See other posts from Game Development
or by Grofit
Published on 2012-01-20T14:49:11Z
Indexed on
2012/06/19
15:27 UTC
Read the original article
Hit count: 385
I am in a situation where I am writing a framework in XNA and there will be quite a lot of static (ish) content which wont render that often. Now I am trying to take the same sort of approach I would use when doing non game development, where I don't even think about caching until I have finished my application and realise there is a performance problem and then implement a layer of caching over whatever needs it, but wrap it up so nothing is aware its happening.
However in XNA the way we would usually cache would be drawing our objects to a texture and invalidating after a change occurs. So if you assume an interface like so:
public interface IGameComponent
{
void Update(TimeSpan elapsedTime);
void Render(GraphicsDevice graphicsDevice);
}
public class ContainerComponent : IGameComponent
{
public IList<IGameComponent> ChildComponents { get; private set; }
// Assume constructor
public void Update(TimeSpan elapsedTime)
{
// Update anything that needs it
}
public void Render(GraphicsDevice graphicsDevice)
{
foreach(var component in ChildComponents)
{
// draw every component
}
}
}
Then I was under the assumption that we just draw everything directly to the screen, then when performance becomes an issue we just add a new implementation of the above like so:
public class CacheableContainerComponent : IGameComponent
{
private Texture2D cachedOutput;
private bool hasChanged;
public IList<IGameComponent> ChildComponents { get; private set; }
// Assume constructor
public void Update(TimeSpan elapsedTime)
{
// Update anything that needs it
// set hasChanged to true if required
}
public void Render(GraphicsDevice graphicsDevice)
{
if(hasChanged)
{ CacheComponents(graphicsDevice); }
// Draw cached output
}
private void CacheComponents(GraphicsDevice graphicsDevice)
{
// Clean up existing cache if needed
var cachedOutput = new RenderTarget2D(...);
graphicsDevice.SetRenderTarget(renderTarget);
foreach(var component in ChildComponents)
{
// draw every component
}
graphicsDevice.SetRenderTarget(null);
}
}
Now in this example you could inherit, but your Update may become a bit tricky then without changing your base class to alert you if you had changed, but it is up to each scenario to choose if its inheritance/implementation or composition. Also the above implementation will re-cache within the rendering cycle, which may cause performance stutters but its just an example of the scenario...
Ignoring those facts as you can see that in this example you could use a cache-able component or a non cache-able one, the rest of the framework needs not know. The problem here is that if lets say this component is drawn mid way through the game rendering, other items will already be within the default drawing buffer, so me doing this would discard them, unless I set it to be persisted, which I hear is a big no no on the Xbox. So is there a way to have my cake and eat it here?
One simple solution to this is make an ICacheable interface which exposes a cache method, but then to make any use of this interface you would need the rest of the framework to be cache aware, and check if it can cache, and to then do so. Which then means you are polluting and changing your main implementations to account for and deal with this cache...
I am also employing Dependency Injection for alot of high level components so these new cache-able objects would be spat out from that, meaning no where in the actual game would they know they are caching... if that makes sense. Just incase anyone asked how I expected to keep it cache aware when I would need to new up a cachable entity.
© Game Development or respective owner