Sunday, July 20, 2008

Async Resource Loader

A few months ago I had the map loading stuff done, and wanted to try some landscape paging. I thought a worker thread would save my day but, as it turned out, loading stuff from HD was still blocking the rendering. I took a look around and found out that synchronous calls (even in a different thread) wouldn't act any better than if they were in the main (rendering) thread.

Real life then set in, and I couldn't get much done. Some weeks ago I rewrote the async loader, and this time it'd include asynchronous calls. So, a worker thread + asynchronous calls (Begin... / End... methods). I soon realized a bad design mistake and I wiped the folder (lesson learned: don't code anything until you've filled at least a page of a good old paper notebook).

I'm going to write it again before implementing anything else since I want all loads to be performed without rendering hiccups (or at least, as few as possible, since the OS has the final say on everything). So, since it's to be rewritten, I'll take more time to design it carefully.

The ARL (async resource loader, blah blah blah) allows you to use custom loaders (since all it does, on its own, is to load a stream of bytes asynchronously from somewhere). Once you have added at least a loader, you start the "service" and call the Load(ResourceInfo) method wherever you like (provided it's in the main thread). Once it's ready, you get a Resource object back (from a callback, I guess). That's about it.

There are details to consider, however; load requests have to be queued, can be aborted, the object which does the final loading (that is, converting the stream of bytes into an useable resource) must be locked (both inside the custom loader and outside), and last but not least, it really has to be threadsafe and performing, otherwise it's useless.

That's all for the moment, ran out of inspiration....

2 comments:

Ashkan said...

Every cache needs a policy, but before we get to enforcing a policy, we need a way to measure the amount of memory that a resource occupies. It's rather easy to calculate the amount of memory that a server-side resource (to borrow the term from OpenGL - a server-side resource is one that is managed by the driver) occqupies. Vertex/Index buffers and textures are just buffers, the size of which we can easily calculate.

The problem is that how should one calculate the size of resources that reside in system memory. For instance, how are you going to calculate the size of a compiled shader? Or the size of a loded DLL?

Raine said...

I agree. I think some resources are not suitable for caching, and the examples you make are quite clear in this case. Not only are they hard to size precisely, but what could be the benefit of caching resources with a non-defined behaviour? And by defined I mean knowing the mean usage figure.

Some other instead can benefit from a pool since "new" (in an unmanaged environment) sometimes just doesn't cut it for a variety of reason.

I think we can consider caches when we're talking about frequently used objects we can size, such as vertex buffers, or game objects as I mentioned in a post (where a sizeof returns all we need to know). Perhaps a profiler can show where a cache can help, instead of making things just more difficult to manage
memory-wise (considering what Raymond Chen wrote in one of his blog posts).