Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make better use of cache in loaders #5650

Closed
dubejf opened this issue Nov 18, 2014 · 7 comments
Closed

Make better use of cache in loaders #5650

dubejf opened this issue Nov 18, 2014 · 7 comments

Comments

@dubejf
Copy link
Contributor

dubejf commented Nov 18, 2014

ImageLoader and XHRLoader both use a Cache to store loaded assets for reuse, although not very efficiently, at least for some use case.

For instance, TextureLoader.onload() creates a new ImageLoader every time the method is called, which means that the image cache is always empty because the image loader instance is only used once. ImageUtils.loadTexture() behaves similarly.

My preferred way to solve this would be to put the cache in the LoadingManager (one cache per LoadingManager instance). Each ImageLoader and XHRLoader would share the cache of their parent manager.

Users would be responsible to manually purge the manager cache as necessary, to free resources or request updated assets. That could be a problem for an application that cycles through a lot of loaded textures/images, especially if the DefaultLoadingManager is used - users might not be aware of cache implication. Maybe the common cache could be opted-in (loadingManager.useCache = true), which would be equivalent to the status quo. A simple loadingManager.cache.maxSize could be enough, too.

Another approach would be to create an ImageLoader instance as a property of TextureLoader in its constructor. The image cache would be reused as long as the same TextureLoader is kept around.

I can work on a patch if we agree on the approach.

Related to #3601

@mrdoob
Copy link
Owner

mrdoob commented Feb 19, 2015

Maybe Cache could be global?

mrdoob added a commit that referenced this issue Feb 19, 2015
@dubejf
Copy link
Contributor Author

dubejf commented Feb 19, 2015

The initial implementation of the Cache was global but was changed the next day (a072f1f) to the current implementation. @mrdoob, do you remember what was the issue? Problem multiple renderers?

I've experimented a bit with the cache/loader, although I'm not completely sure about the approach.

To get the 'global' behavior, I've simply added the cache to the LoadingManager.

However, that is not sufficient to solve #3601. The problem here is uncoordinated concurrent retrieval of the same resource, and it needs more that a cache. My solution to get around this problem is to introduce a CacheLoader.

You can see it in action here: http://jsfiddle.net/dubejf/r9n8b0b4/4/

Basically, instead of ImageLoader answering each 'load' request directly, the modified ImageLoader puts the loaded images in the CacheLoader, and the CacheLoader answers the original 'load' callbacks. CacheLoader understands when a request is 'in progress', and can combine multiple requests for the same resource.

CacheLoader is asynchronous. It should be possible to patch it to use a WeakMap or IndexedDB if desired. The approach is also general enough that I might start to use it to de-duplicate identical instances other types of object, e.g. Geometry and Materials.

However, it adds a some complexity, and I'm not sure how big of a problem the lack of caching is in general.

@mrdoob
Copy link
Owner

mrdoob commented Feb 19, 2015

Hmmm... Stupid me... I should detail more why I do changes... I don't remember why I made it not global...

CacheLoader seems interesting. I'll study all this 😊

@bnolan
Copy link
Contributor

bnolan commented Apr 5, 2015

This would help my use case. In the chess game, the pawns are loaded 8 times, when the cached version of the .obj could be saved and reused. :)

@mrdoob
Copy link
Owner

mrdoob commented Apr 5, 2015

scenevr is interesting! I like the spheres to open portals idea 😀

We can add caching to more loaders, but it also sound like for your case you could handle that on your side too...

@antont
Copy link
Contributor

antont commented Apr 10, 2015

@dubejf - about what you say, "I'm not sure how big of a problem the lack of caching is in general."

In my understand it is a big problem. We've dealt with it in own code, outside three.js, but it might be nice to have it work properly in three already if there's a simple nice clear way.

@bnolan
Copy link
Contributor

bnolan commented May 13, 2015

I ended up solving this by creating an AssetManager. I could make this into an npm module if there was any interest. I also parse the .objs using a webworker, but I might look into .gltf to see if it's even faster.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants