How To Write Resource Manager

Started by
4 comments, last by poigwym 7 years, 9 months ago

Hi!!!

I 'm going to write a resource manager like the manager in horde3d which call ResMan. The ResMan can hold smart pointer of few type of resource (textures,shaders...).

The question is their construct function are different, how to make a factoryFunc which can shared by these resource ?

I can only figure out a function pointer look like Resource* createFunc(string source),

and the class look like this:

class xxxRes : public Resource
{

static Resource* createFunc(string source).

};

However, the function pointer is not enough for construct some resource , such as a shader need a shader type,......

Who can explain the idea behind this design ?

Another question is who call the load and release function of resource ?

I first new and then call load rather than the resource object load itself inside it's construct function because it make the resource class cleaner,

and more data-oriented.

Advertisement
Typically "manager" is evidence of a bad design. Every class should have a single responsibility. "Manage" is not a single responsibility.

In bigger games these are typically implemented with four primary classes: xxStore, xxProxy, xxCache, xxLoader. xx is whatever thing you are working with. The Store represents all the objects. You request one and are given back a Proxy. A Proxy might contain the fully loaded object, or it might contain a different placeholder object. The Cache is a collection of objects currently loaded. The Loader finds resources that people want to use but are not loaded, and loads them up, then updates the proxy to switch out to the real loaded module. You'll probably reach the point where you need to load more things but can't, so you swap them out of the proxy to unload it and replace it with the placeholder, then dump the unused item from the cache.

You might be misunderstanding what Data-orientation actually is. Data orientation is designing frequently used code to be more efficient for it's access patterns. For concerns of resources that will be used in games, it does not need to be overly complicated or overly developed. It's job is to literally hold data, load data, and push data forward. Anymore than that and you're over engineering.

Anyways... to help explain a bit more on what's going on with Frob's explination.

The store is your database/archive. It's going to be the primary access point for your code. It's main data is the index of all of your files. When you request data from it, it'll give you a proxy. The proxy will check if the data is live in the cache. If not, it dispatches a load order, and uses a temporary file to protect against errors. The loader pulls in data from a seperate thread and stores it in the cache. When it's done, it tells the Proxy to update.

At that point, the Proxy becomes fully active.

Personally... It think it's way overly complicated. Though that's not saying that I don't see the value in it. But you should be fine with a normal resource manager.

However, the function pointer is not enough for construct some resource , such as a shader need a shader type,......

That point is handled by the Asset (file) you store besides your game code. In that file normaly should be placed how the shader should be constructed and what parameters to use like Texture, initial uniform values and so on. That is the task for the loader to correctly create that shader when doing his job

I 'm going to write a resource manager like the manager in horde3d which call ResMan. The ResMan can hold smart pointer of few type of resource (textures,shaders...).


That was a system I hadn't heard about. Learning a bit about the Horde3d engine since you last posted, it looks like the engine does most of those things for you described earlier.

The question is their construct function are different, how to make a factoryFunc which can shared by these resource ?
I can only figure out a function pointer look like Resource* createFunc(string source),


Then it doesn't look like you are following theirs at all.

Their system operates on C-style rather than C++-style objects and it provides those functions of store, proxy, cache, and loader for you.

Looking over their documentation they don't have anything like the Resource* you describe. They use handles, basic integers, with a type of H3DRes or H3DNode. Those handles serve to connect users with the corresponding proxy object, which may be a loaded or unloaded resource.

However, the function pointer is not enough for construct some resource , such as a shader need a shader type,......
Who can explain the idea behind this design ?


The design used by Horde3D is very different from what you wrote in your post.

The idea behind their design is to use handles rather than pointers for most work. This allows the engine to do what it needs to do without breaking user's code. If items get relocated in memory, if graphics contexts crash or get unloaded or otherwise break the handles they gave you can still remain valid.

I called it a Proxy, their engine calls it a H3DRes handle, but it is the same for each.

The actual resource types like Shader, Mesh, or Texture are not part of what is publicly given to users.

Resource name strings are given in their data pipeline. The resource names are set by the designers, artists, modelers, or other people who use their engine and are set as data in the game being built. The names of the files are kept in the project's data files. The string names given in code need to match the values given in the data.

Once the data is already loaded users can figure out what resource the handle goes to by calling h3dGetResType(), and once they know the actual type can call appropriate calls like h3dSetShaderPreamble() or h3dSetNodeTransMat() or various other calls that work for the resource type.

Another question is who call the load and release function of resource ?


After reading a bit more of the engine this now makes more sense. The engine provides a system that someone else can use. Someone writing their game calls those functions as they need to write their game.

People who write engines are writing the code used by others. They will usually write some small demo programs, but the actual game writing is done by whoever uses the engine.

In this case the load and release calls would be made by the person writing the actual game. It would be their decision where to put it in their game code, it doesn't particularly matter to the engine.

I first new and then call load rather than the resource object load itself inside it's construct function because it make the resource class cleaner,
and more data-oriented.


As Tangletail wrote, those have nothing to do with being data oriented.


Their design is interesting. It seems they are trying to simplify today's higher-complexity graphics libraries and reduce them to something beginner friendly. They only expose a single graphics system, a single graphics context, and that context is always active.

Their system of treating everything as a handle simplifies life for the engine users, but it means that whoever is writing their code (and since you want to copy their design, YOUR code) becomes much more complex in the process. It means you've got to manage the locking and unlocking of resources, know when the data is immutable or locked or immovable, implement all the rendering instruction streams, and handle all kinds of strange situations like graphics drivers crashing and recovering, or data on the card seemingly-spontaneously invalidating itself, and all the other fun complexities of modern graphics programming.

Their resource system is not one I'd recommend following unless you've got a strong reason for it.

However, the function pointer is not enough for construct some resource , such as a shader need a shader type,......

That point is handled by the Asset (file) you store besides your game code. In that file normaly should be placed how the shader should be constructed and what parameters to use like Texture, initial uniform values and so on. That is the task for the loader to correctly create that shader when doing his job

thank you for reminding me this point.

This topic is closed to new replies.

Advertisement