Sign in to follow this  
BasomtiKombucha

Can we dispose of an asset?

Recommended Posts

Hi!

So here's something that has been bothering me for a while...

Can we somehow "unload" textures/texture atlases/assets?

 

I'm working on a game that has multiple levels. At the start of each level, I preload all of the assets the level requires using the AssetLoader.

 

So at the start of the first level I have something like:

loader = new PIXI.AssetLoader(["level1_assets.json"]);loader.onComplete = startLevelloader.load();

While at the start of the second level I have something like:

loader = new PIXI.AssetLoader(["level2_assets.json"]);loader.onComplete = startLevelloader.load();

The point is, once the first level is over, I will never again need the texture atlas used to store its assets (resp. "level1_assets.json"). So there's no need for it to linger in my precious GPU memory anymore! Can I somehow dispose of it?

Share this post


Link to post
Share on other sites

Thanks for the reply! You're probably pushing me on the right track, but I still don't fully understand :( Could you be more specific?

 

 

AssetLoader.load() returns void, not an instance of a Texture element - so I can't just

var myTexture = loader.load();

But I need to call the Texture.destroy() on something - probably some instance of the 'Texture' object, right?

So how do I store an asset I loaded through loader into a 'Texture' variable?

 

TLDR; my problem is that I don't know what should I call the "texture.destroy(true)" on :/

Share this post


Link to post
Share on other sites

Sure! As documentation states all loaded textures are added to textureCache

 

If you console.log(PIXI.TextureCache)

 

it will list all of your textures inside the cache.

 

In order to remove the texture from cache you have to put this simple line of code

 

THIS IS IT!!!!!!!

PIXI.TextureCache['assets/images/hud/hud_bench.png'].destroy(true);

The true argument states that you want to remove the baseTexture as well.

 

 

So if you console log in pixi js 1.6.0 dev this (line of code 13360)

PIXI.BaseTexture.prototype.destroy = function(){    if(this.imageUrl)    {           console.log(this.imageUrl);                console.log('Base texture destroy: ', PIXI.BaseTextureCache[this.imageUrl]);        console.log('Texture cache destroy: ', PIXI.TextureCache[this.imageUrl]);                delete PIXI.BaseTextureCache[this.imageUrl];        delete PIXI.TextureCache[this.imageUrl];                console.log('Base texture destroy: ', PIXI.BaseTextureCache[this.imageUrl]);        console.log('Texture cache destroy: ', PIXI.TextureCache[this.imageUrl]);                this.imageUrl = null;        this.source.src = null;    }    else if (this.source && this.source._pixiId)    {        delete PIXI.BaseTextureCache[this.source._pixiId];    }    this.source = null;    PIXI.texturesToDestroy.push(this);};

You'll get at first the reference to the texture in cache and the base texture that I am removing and the second ones will return typeof 'undefined'.

 

Additionally in the __proto__ property you'll see the before mentioned method destroy (not the one shown in the code above this is called with the true arguemnt).

 

BUT BE AWARE THAT IF YOUR CODE CALLS THE SAME TEXTURE AS WELL BUT WITHOUT THE ASSET LOADER THE TEXTURE WILL BE READDED INTO THE TextureCache AND WILL HAVE A NEW BaseTexture.

 

So in other words calling this code somewhere else after destroying your texture will add it back!

var hud_benchTexture = new PIXI.Texture.fromImage('assets/images/hud/hud_bench.png');

Under the hood pixi js uses good old delete statement like this:

delete PIXI.BaseTextureCache['assets/images/hud/hud_bench.png'];delete PIXI.TextureCache['assets/images/hud/hud_bench.png'];

DO NOT DO IT  BY YOURSELF IN THE CODE, SINCE PIXI IS ALSO CLEANING SOME OTHER THINGS, IT CAN FREEZE YOUR APP IN CASE OF webGL context (that happened to me... yup... I was lazy about the documentation! :D )

 

IF THIS IS THE ANSWER TO YOUR QUESTION PLEASE MARK IT AS 'THE ANSWER'!!! :D

 

p.s.

 

this is the bug with the base texture that i have mentioned - http://www.html5gamedevs.com/topic/2182-pixi-web-app-slows-down-after-loading-20mb-of-images-on-ipad-mini2/, (corrections made by Peg Digital were added to the official pixi code)

and this is a very good article about delete in javascript - http://perfectionkills.com/understanding-delete/

 

 

http://www.sevenative.com

Share this post


Link to post
Share on other sites

Thanks! Yep, I guess it'll to do so I'll mark it as 'the answer' very soon  :)

 

But before that, if I may ask just one more thing: what is the difference between: 

PIXI.TextureCache['image.png'].destroy(true);

and

PIXI.Texture.removeTextureFromCache('image.png');

?

 

My problem is that instead of using the standard pixi.js, I'm using its Dart port (https://github.com/FedeOmoto/pixi) and the port does not seem to have the TextureCache class anywhere I can get (actually, I can't even find it in the official pixi.js documentation (http://www.goodboydigital.com/pixijs/docs/) perhaps it's out of date?)

 

Also the difference between Texture and BaseTexture is mystery to me, why do we need them both?

Share this post


Link to post
Share on other sites

This is how pixi does it.

 

Texture.removeTextureFromCache

PIXI.Texture.removeTextureFromCache = function(id){       var texture = PIXI.TextureCache[id];    delete PIXI.TextureCache[id];    delete PIXI.BaseTextureCache[id];    return texture;};

And this is is Texture.destroy()

PIXI.Texture.prototype.destroy = function(destroyBase){    if (destroyBase) this.baseTexture.destroy();    this.valid = false;};

Practically removing the texture from cache will not influence the textures already loaded. If you'll remove baseTexture the sprites created from texture will leave a blank (black) space.

 

as fr where your texture cache is in dart port..... drum roll! :D

 

IT IS HERE

Texture._cache[frameId]; 

And this is the equivalent of dart destroy method:

void destroy([bool destroyBase = false]) {    if (destroyBase) baseTexture.destroy();    _valid = false;  } 

IF YOU WANT TO DESTROY A TEXTURE IN DART PORT YOU HAVE TO :

Texture._cache[frameId].destroy(); // remove from cacheTexture._cache[frameId].destroy(true); // remove from cache and remove the base texture

As for what is the baseTexture used for ... I think that they use it for a technique called prerendering... BUT I AM NOT SURE. I DON'T WANT TO STEER YOU INTO THE WRONG DIRECTION!

 

http://www.sevenative.com

Share this post


Link to post
Share on other sites

The baseTexture is the image that you have loaded.

A Texture is just a frame of that image.

E.g. you have a Spritesheet 100x100 pixel (baseTexture), with 4 Textures (4x 50x50 frames)

 

 

PIXI.TextureCache['image.png'].destroy(true);
 

That line destroys the baseTexture + the frame for that baseTexture (afaik not all other frames that use that baseTexture)

 

PIXI.Texture.removeTextureFromCache('image.png'); 
 

I'd assume that this one only destroys the frame, but you have to look that up.

In short: If you want to unload the image file, you have to destroy the baseTexture.

Detroying frames alone will not unload the image.

Share this post


Link to post
Share on other sites

Hubert: It's not that simple with the 

Texture._cache[frameId];

 _ underscore works somehow like a 'private' keyword in dart and there is no getter for the "_cache"

Still, you probably had to dig in the Dart Pixi source to get that piece of code for me and I appreciate that!

 

It seems that the problem is unsolvable without modifying the library source. I'll write to its author and see what he thinks about it :)

 

Sebastian: That was well explained! I understand it completely now, thanks!

Share this post


Link to post
Share on other sites

You're right,

 

the underscore means that this element is private to the class or to the library. Additionally Texture is 'part of' PIXI so you don't have access to the private elements in the class or the library.

 

You will have to dig deeper. I think that you should add additional method to the texture class that will allow you to destroy textures the way you want.

 

http://www.sevenative.com

Share this post


Link to post
Share on other sites

You should be able to access the texture with 

 

BaseTexture.fromImage(your texture url)

and

Texture.fromImage(your texture url)

 

or you grab it from a sprite ->

 

yoursprite.texture and the baseTexture with yoursprite.texture.baseTexture

 

(fromImage only loads the image if it's not in the cache already. if it's in the cache, it will just return the cache entry for you)

Share this post


Link to post
Share on other sites

Hi!

 

In the Dart port of Pixi, the TextureCache object is intentionally hidden inside the Texture._cache static property as was already correctly pointed, and I think there's no need for it to be visible outside the library.

 

If you're loading a bunch of textures using the AssetLoader, the easiest way to destroy them is something like this (Dart code follows):

Texture.removeTextureFromCache('textureId').destroy(true);

The Texture.removeTextureFromCache static method returns the Texture being removed from the cache, so you can destroy it (and its accompanying BaseTexture) as showed.

 

This works OK if you know beforehand which texture ids you've to destroy. When using the AssetLoader, you will most likely end up creating Sprites from those textures, so, if you have a list of all the Sprites you're created, it's best to do something like this (Dart code follows):

spriteList.forEach((sprite) => sprite.texture.destroy(true));

Please let me know if any of those alternatives works OK for you, and if not, perhaps you can post a little code snippet showing your problem at which I can take a look to find the best solution.

 

Regards,

Fede

Share this post


Link to post
Share on other sites

Sebastian: You are right! I didn't realize this.

Nevertheless, I still think that a static getter would be more practical, but it's good to know that there's no need to change the source.

 

Funny that the BaseTexture.destroy() method behaves differently in Dart VM that it does in JavaScript. Calling it throws an error regarding the _source.src. It seems to work ok when compiled into JavaScript tho.

Of course, the problem partly lingers because of this - it's hard to debug and application if it exits every time you change a level and compiling it into JavaScript after every change is too slow. Still, I guess there's not much we can do about it since I believe it to be an issue with the port itself. But I have faith that Fede will look into it soon :)

edit: w8 a sec Fede has responded while I was writting this post, give me a sec to read it and I'll get back :D

Share this post


Link to post
Share on other sites

Yep, the error still lingers.

Texture.removeTextureFromCache('textureId').destroy(true);

Would be an ideal solution, but I can't make it work.

 

To make sure I didn't screw anything (or as little as possible) by my coding, I used the example_1_basics you included in the GitHub source (https://github.com/FedeOmoto/pixi_examples/tree/master/web/1_basics) and basically just changed the _animate method like this:

int temp = 0;void animate(num value) {    window.animationFrame.then(animate);    // Just for fun, let's rotate mr rabbit a little.    bunny.rotation += 0.1;        //THIS IS WHAT I ADDED    if (temp == 180) {      Texture.removeTextureFromCache('bunny.png').destroy(true);    }    temp++;    //--------------------    // Render the stage.    renderer.render(stage);  }

This should remove the texture after about 3 seconds of runtime. But instead, after those 3 seconds, I get an error: 

 

Uncaught Error: String expected
Stack Trace: 
#0      Native_HTMLImageElement_src_Setter (dart:_blink:2709)
#1      ImageElement.src= (dart:html:16480)
#2      BaseTexture.destroy (package:pixi_dart/src/textures/base_texture.dart:157:15)
#3      Texture.destroy (package:pixi_dart/src/textures/texture.dart:148:41)
#5      _rootRunUnary (dart:async/zone.dart:730)
#6      _RootZone.runUnary (dart:async/zone.dart:864)
#7      _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:488)
#8      _Future._propagateToListeners (dart:async/future_impl.dart:571)
#9      _Future._complete (dart:async/future_impl.dart:317)
#10     _SyncCompleter.complete (dart:async/future_impl.dart:44)
#11     Window.animationFrame.<anonymous closure> (dart:html:29269)
 
 
Exception: String expected

 

 

Tho it works if I try doing it in JavaScript via the:

PIXI.TextureCache['bunny.png'].destroy(true);

Instead of the error, the spinning bunny changes into a black rectangle, which is what I would expect it to do.

Share this post


Link to post
Share on other sites

Hi again!  :)

 

From the example in your first post, it seems that you're loading a SpriteSheet. If that's the case, it's even easier to free up the texture resources!

Just take any of the resulting Sprites and call:

sprite.texture.destroy(true);

That will suffice as you'll be creating Sprites from the same BaseTexture (the Texture objects themselves will be freed up by the garbage collector when they are dereferenced).

 

Regards,

Fede

Share this post


Link to post
Share on other sites

Why are you adding the destroy() method to the remove from cache texture?

 

Try doing something like this.

Texture.removeTextureFromCache('bunny.png')

While clalling this method dart removes the object property and everything that is under it. 

 

This is what happens under the hood in dart

Texture._cache.remove(id);

Remove() is a native dart method.

 

And since dart is a garbage collector language all dereferenced elements will be deleted from memory.

 

http://www.sevenative.com

Share this post


Link to post
Share on other sites

Hi BasomtiKombucha,

 

Thank you for pointing that! My bad, sorry, there's a bug that arises only in the Dart code when trying to destroy a BaseTexture (the Dart "type checker" doesn't allow you to set an ImageElement's src proterty to null, it must be a String).

 

It's now fixed on Pub and GitHub:

 

https://github.com/FedeOmoto/pixi

https://pub.dartlang.org/packages/pixi_dart

 

Can you please give it a try?

 

Regards,

Fede

Share this post


Link to post
Share on other sites

That's right Hubert, but since BasomtiKombucha wants to additionally destroy the Texture's BaseTexture, you've to call the destroy method (Texture.removeTextureFromCache returns the Texture being removed from the cache, so calling destroy(true) on it frees up the BaseTexture also).

 

 

Why are you adding the destroy() method to the remove from cache texture?

 

Try doing something like this.

Texture.removeTextureFromCache('bunny.png')

While clalling this method dart removes the object property and everything that is under it. 

 

This is what happens under the hood in dart

Texture._cache.remove(id);

Remove() is a native dart method.

 

And since dart is a garbage collector language all dereferenced elements will be deleted from memory.

 

http://www.sevenative.com

Share this post


Link to post
Share on other sites

Dart supports both cascading and method chaining: http://news.dartlang.org/2012/02/method-cascades-in-dart-posted-by-gilad.html

:)

 

Perhaps I didn't explain myself properly, the idea is to destroy the Texture's BaseTexure after it has been removed from the cache, that's what you achieve calling:

Texture.removeTextureFromCache('textureId').destroy(true);

As I already said, that's convenient if you have a list of textureIds somewhere, but as Sebastian pointed out, I think it's easier (more elegant?) to just call:

sprite.texture.destroy(true);

Regards,

Fede

 

 

Ok!

 

Since I'm not very advanced in dart?

 

Does cascading (method chaining) work in dart even in case of remove statement? Remove returns the element that has been removed?

 

Laika? Is the new code working? SRSLY I want to know.

 

http://www.sevenative.com

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.