agkountis / crius

MIT License
3 stars 0 forks source link

Asset loading/storage and management system investigation. #7

Open agkountis opened 4 years ago

agkountis commented 4 years ago

Task

Investigate various designs for a asset loading/storage system for crius.

Details

Document possible design ideas in this issue as comments or start a discussion on gitter or discord

mitso23 commented 4 years ago

After a bit of a research online and having a quick look on the amethyst.

Asset definition

Defining the file format for the assets

Asset Storage/Look up

Assets life cycle

Caching

Asset loader / Change monitor

Asset dependency management

agkountis commented 4 years ago

@mitso23 First of all thank you for investigating the matter.

Now to address some of your points and present my views:

Asset Definition

An asset is a "resource" that can be loaded to be consumed by the engine. E.g:

Notice how I am not mentioning configuration files as I think these should be a separate category because their use is mostly singular and that is for initialization and no other systems usually consume them at runtime.

Defining the file format for the assets

Flatbuffers

First let's talk file format. I suggested flatbuffers from google for various reasons.

First I have experience with the format because I am currently using it at work to design a custom file format for the Unity application I am working on. Flatbuffers demonstrate significant increases at deserialization times.

Flatbuffers also allow for separation between the schema definition of the file format and the language of implementation, since it uses a custom DSL description language that is used to generate bindings for multiple languages, one of which is Rust. This makes flatbuffers ideal because there is no need to recompile the code bases for each change on the file format schema.

Flatbuffers is also easy to extend without causing breakages since it follows a deprecation model where you are not allow to completely remove an entry to the schema, but only deprecate it. Additions to the schema are allowed.

Metadata

As far as metadata go we will most likely figure out what is needed when we start experimenting loading them in the engine. But most of the ones you mentioned would make sense but we have to discuss the usefulness of each one of those.

Another point of discussion would be if these metadata should be stored in a separate file or as a header in the asset itself. Both of those have advantages and disadvantages. The problem I see with storing them in a header is that flatbuffers don't seem to have the ability to read "part" of the buffer. They load the entirety (and it is really fast).

Compression

Asset files should be compressed using LZMA for maximum compression and transmission over the network and LZ4 for local storage for fast decompression speeds.

Asset Lifetime

Keep in mind we are not developing a game, but an engine. Crius only provides tools to the developer to manage assets to be used in various engine systems. Asset loading should be managed by each scene the user application has.

  • The asset manager should own the underlying memory. When a user requests an asset the assent manager will either return immediately the resource (if this has been already fetched) or schedule a download and notify the user via a callback asynchronously.
    • The main render thread shouldn't be blocked while waiting for the resource to complete ?
    • The asset manager should return a weak pointer to the client requesting the resource if the reference count of the asset drops to 1 then the asset manager can decide to free this resource and load another one.

I agree with the above but we have to consider the following:

Mutability

Assets should most likely be immutable pieces of data. If the user needs to mutate an existing asset they will most likely have to pay the cost of a clone.

RefCounting

You mention reference counting. Reference counting in Rust is done using Rc<T> for single threaded scenarios and Arc<T> for multi-threaded scenarios. Both those types are immutable by default, meaning you cannot mutate the contained type T. If you want to mutate you have to use interior mutability using RefCell<T> so the types would look like Rc<RefCell<T>> which isn't an easy to use API.

If we restrict the lifetime of assets to a per-scene basis we can practically hand out simple immutable references to the assets.

Caching

Shouldn't that be a responsibility of the user application to manage which assets they want present in the Asset Manager at any point in their scenes?

For now I don't know if setting limits in asset loading makes sense. The user application should be sensible in their data requirements based on the systems they will be targeting.

Asset loader / Change monitor

  • Need to be able to load assets from Disk asynchronously
  • Need to be able to load assets over the Network
  • Can we start using an asset before it is fully available @agkountis
  • Reload assets if the underlying file has changed

I agree will all the above.

  • Can we start using an asset before it is fully available @agkountis

This sounds like asset streaming. The only cases I can think of are:

So yes streaming is definitely a possibility, but let's start simple.

Asset Dependency Management

Can you elaborate a bit more on having assets depending to each other? The only one I can think of right now is maybe Materials referencing Shaders?

mitso23 commented 4 years ago

@agkountis thanks for the comments. I guess we can ignore the asset dependency for the time being. We can always add it later on.

So the list of the assets to be downloaded will be part of the configuration file that is going to be YAML format ?

agkountis commented 4 years ago

@mitso23 I don't think asset downloading is in the current scope.

Even if it was, I believe download logic should be handled by the user application.

If the user wants to download assets from a remote source, the engine should provide some network abstraction at most (still out of the current scope).