[LibGdx] Best way to store/get textures for rendering ?

Hi,

I’m currently working on a project where I have to render the same texture a lot of times in the same render cycle and I don’t know what is the best way to do it in terms of efficiency.

I don’t know if I should keep the texture in a variable in the Object that I have to render or if I should get it from the AssetManager every render cycle for every Object ?

Here is how my system works:
Textures:
The textures are loaded in a static AssetManager where I can access them by using an “id” that is then used to get the texture’s path from a Hashmap to finally get the texture from the AssetManager.

Rendering:
Every render cycle I call a render function in a Map object which goes trough every Tile objects in a 2 dimensional Array and calls the render function each time.

I’m a bit lost here and I would love if any of you can help me on this one.

If you need to see the code, it is available on Github.

It depends on how many objects there will be in your level. If you will only have < 500 objects, I doubt that searching Hashmap would give you any kind of performance problems. The much more probably bottleneck will be OpenGL rendering.

You don’t need to extend Object, all java classes automatically extend Object without you declaring it.

As stated on several “common mistakes with OpenGL” texture handles should be exposed. They, should be, ints. The handles themselves should be placed in a private map, which doesn’t have a getter. You should include a cleanup method.

This makes it so you can store the texture and use it directly whenever you need it without looking it up. It also avoids creating objects for your textures.

This still applies in the case with libgdx.
https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/Texture.html

The link states that there are Texture objects. You should store these in a private table to be released using ‘dispose’ method.

Something like…

private static ArrayList<Texture> textures = new ArrayList<Texture>();


public Texture loadTexture() {
Texture texture;
// do some loading
textures.add(texture);
return texture;
}

public static void cleanTexture(Texture texture) {
texture.dipose();
textures.remove(texture);
}

public static void cleanTextures() {
for (final Texture tex : textures)
tex.dipose();
textures.clear();
}

No! Don’t do that.

A hashmap lookup may be reasonable fast, but it can sum up, and with your approach you’ll run into the more serious issue of unneeded texture swaps and extra draw calls.

Pack all your tile textures into a TextureAtlas. Don’t do lookups on each Tile.render(), but get the tile’s TextureRegion at load time, and store it with your Tile instance. This reduces the work inside the render() function to a simple batch.draw(region, x, y) call.

Hydroque, it is a tiresome routine to see you fail to misconceive the question entirely. Read the freaking question, don’t just trigger on the first buzzword that jumps up on you! ::slight_smile:

Storing the texture by its most basic form in the entity that uses it is a good idea. The asset manager, which holds the scene’s data, will take care of mass releasing of textures. When the texture isn’t needed it can be released dynamically.

I don’t see how I am in the wrong for adding this information.

[quote]The textures are loaded in a static AssetManager where I can access them by using an “id” that is then used to get the texture’s path from a Hashmap to finally get the texture from the AssetManager.
[/quote]
He unnecessarily gets the asset from a hashmap. The texture used should already be loaded up to the entity at this point and used by the entity. You don’t need to constantly get and when you need to change the texture to something else, by all means go and find it and get it.

I agree with you on adding TextureAtlases, but I never replied back in response to rendering. ::slight_smile:

Because you didn’t actually answer his question initially. You literally just told him how to load a texture, and then how to reference it. That’s not what the OP asked. I think it’s pretty clear he knows how to load a texture, he’s asking what to do with it after he’s loaded it. Your second post was a little more helpful because you actually said

You still didn’t provide any proof beyond that’s what you think is best though.

I’m not a user of LibGDX, but the procedure I follow might be the same, because I employ a resource loader that loads the resources asynchronously too. First of all, I define a class called [icode]Resources[/icode] and store all my references in it.


public class Resources
{
    public static class Programs
    {
        public static Program SPRITE_PROGRAM;
        public static Program FONT_PROGRAM;
    }

    public static class Textures
    {
        public static Texture BACKGROUND;
        public static Texture CLOUDS;
        public static Texture GROUND;
        public static Texture BULLET;
        public static Texture BLOCKS_SHEET;
        public static Texture AMOEBAM_SHEET;
        public static Texture ENEMY_SHEET;
        public static Texture AMOEBAM_SHOOT_SHEET;
        public static Texture LOGO;
        public static Texture EXIT;
        public static Texture AMOEBAM_ROLL;
    }

    public static class Sounds
    {
        public static ALBuffer MUSIC;
        public static ALSource EXPLOSION;
        public static ALSource SHOOT;
    }

    public static class Animations
    {
        public static Animation AMOEBAM;
        public static Animation AMOEBAM_SMALL;
        public static Animation WATER;
        public static Animation AMOEBAM_SHOOT_START;
        public static Animation AMOEBAM_SHOOT_STOP;
        public static Animation ENEMY;
    }

    public static class CollisionTags
    {
        public static final CollisionTag GROUND  = new CollisionTag();
        public static final CollisionTag AMOEBAM = new CollisionTag();
        public static final CollisionTag BULLET  = new CollisionTag();
        public static final CollisionTag ENEMY   = new CollisionTag();
        public static final CollisionTag EXIT    = new CollisionTag();
        public static final CollisionTag WATER   = new CollisionTag();
    }

    public static class Levels
    {
        public static Level LEVEL_1;
        public static Level LEVEL_2;
        public static Level LEVEL_3;
        public static Level LEVEL_4;
        public static Level LEVEL_5;
        public static Level LEVEL_6;
        public static Level LEVEL_7;
        public static Level LEVEL_8;
        public static Level LEVEL_9;
        public static Level LEVEL_10;
    }
}

My resource loader loads the defined resources too, and it gives a long handle to get them back once handled. Once they are loaded, I just copy them to these references and I can use them anytime. For example, when I want to draw the background, I can just say


renderer.draw(Resources.Textures.BACKGROUND, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

And it works just fine. The resource loader still keeps the resources in the HashMap, which will be released at the end. These are just references and this is how I do for my games. The above source is actually from my game Amoebam, my LD entry.

SHC, while that’s fine it quickly can become unmanageable for larger projects. I advise against storing your resource objects in static classes as fields.

There are two reasons you want to hold the most basic form of texture for use.

  1. No objects hidden behind objects managed by some manager. Just one manager will do and the only thing the manager should do is hold your resources to be deallocated. You should have some structure for dynamic loading, for you have the texture object. There is no need to order textures in a list for getting. This doesn’t apply when the textures are to be changed dynamically really fast, like in a tile editor, however the static ids for the tables get old and the dynamic index-deciding is tedious to make.

  2. Mass deallocation for scenes is important and you shouldn’t be looking to manage the existence of the textures outside of the AssetManager. The reason for this is it simply becomes a mess. The only time your scene cleanup is be called is either on exit/crash or on scene switch. There is no need to release the contents hidden inside the table when you can call a cleanup method. You don’t need to duplicate the data. You don’t need to iterate over the data to find a specific texture (please keep track of your textures ._. it isn’t hard).