Search code examples
javalibgdx

LibGdx rendering multiple custom actors performance


I've made simple custom actor in libGdx.

public class HealthBar extends Actor {
private Texture background;
private Texture bar;
private float max;
private float current;

public HealthBar(Color bgColor, Color barColor) {
    Pixmap bgPixmap = new Pixmap(1, 1, Pixmap.Format.RGB565);
    bgPixmap.setColor(bgColor);
    bgPixmap.drawPixel(0, 0);
    background = new Texture(bgPixmap);
    bgPixmap.dispose();
    Pixmap barPixmap = new Pixmap(1, 1, Pixmap.Format.RGB565);
    barPixmap.setColor(barColor);
    barPixmap.drawPixel(0, 0);
    bar = new Texture(barPixmap);
    barPixmap.dispose();
}

@Override
public void draw(Batch batch, float parentAlpha) {
    batch.draw(background, getX(), getY(), getWidth(), getHeight());
    batch.draw(bar, getX(), getY(), getBarEnd(), getHeight());
}

private float getBarEnd() {
    return current / max * getWidth();
}

public void setHealth(float current, float max) {
    this.current = current;
    this.max = max;
}

public void dispose(){
    background.dispose();
    bar.dispose();
}

}

I'am rendering around 30 of this on stage 2d in group.

Problem is that rendering this costs me around 20 frames per second. Rendering same number of simple Label has no visible performance impact. I am missing something in this code? Those Actors are added to group which is rendered using Stage.

performance when drawing

performance with draw() content commented


Solution

  • By creating separate Texture objects for your backgrounds, you are causing the SpriteBatch to have to flush twice to draw each one of your HealthBars. SpriteBatch has to flush every time it receives a command to draw a texture that does not match the last texture submitted for drawing.

    (Unrelated, but also it is very wasteful to be creating so many copies of the same texture--it would make more sense to create a single white image and have all health bars use it.)

    The correct way to do this is to put the solid white image into a TextureAtlas with the rest of your images used in your UI and use that in your actor. You can call setColor on the batch before drawing the background and then the bar to make the white texture region look like whatever color you want. This greatly reduces or eliminates batch flushes (except for the very last one when you Stage is done drawing everything).

    However, an extra 60 batch flushes wouldn't usually be enough to get such a big frame rate drop, unless you are testing on a very low end phone or on the Android emulator. The Android emulator is useless for getting an impression of actual performance on a device.