javalibgdx

"Possible flush inside a loop" warning in Android Studio


I'm using Android Studio with Java and LibGDX.

Android studio warns the draw line with "Possible flush inside a loop", with this detailed description:

Inspection info: Looks for the possibility of a flush of a batch or renderer occuring inside a loop, either directly or indirectly. For performance reasons care should be taken to not cause unnecessary flushes, and to limit the number of flushes per frame as much as possible.

DelayedRemovalArray<MyEntity> myEntities = ...;

bricks.begin();
for(MyEntity myEntity : myEntities) {
    myEntity.draw(game.getBatch()); // warning: Possible flush inside a loop
}
bricks.end();

the MyEntity.draw method:

Matrix4 tempMatrix = new Matrix4();
Matrix4 originalMatrix = new Matrix4();

NinePatchDrawable ninePatchDrawable = ...;

public void draw(SpriteBatch batch) {
    originalMatrix.set(batch.getTransformMatrix());

    tempMatrix.set(originalMatrix);
    
    tempMatrix
        .translate(myEntity.width/2, myEntity.height/2, 0)
        .rotate(0, 0, myEntity.angle, 10)
        .translate(-myEntity.width/2, -myEntity.height/2, 0);
    batch.setTransformMatrix(tempMatrix);

    ninePatchDrawable.draw(batch, ...);

    batch.setTransformMatrix(originalMatrix); 
}

If I remove the two batch.setTransformMatrix calls, the warning goes away but I need to do that otherwise the ninepatch will not be draw at the right position, due to the fact that the ninepatch.draw method does not consider the body center when applying the rotation... About this issue with ninepatches I opened a dedicated SO question here

So, how to do it without receiving that warning? Is there a better way to do this?

Thanks


Solution

  • Do not position individual entities by setting the transform of the SpriteBatch per entity, position individual entities with coordinates that make sense in the projection the batch is setup in.

    Setting the transform matrix on a batch needs to flush whatever is already submitted to that batch as everything after will be drawn with another transform.

    You can see that in the source code for SpriteBatch.

    You should normally not be changing the transform of the batch for each entity drawn using it, position and rotation of each entity is passed in the draw call (otherwise the Batch cannot batch anything).

    Often what you want to do is to set the camera view on the SpriteBatch before the begin and then draw all entities that use that projection before calling end.

    In the case of a NinePatchDrawable, just use the draw method that allows you to specify the rotation, and if you want the rotation to happen around the center of the `NinePatchDrawable' adjust the origin by half the width and height:

        ninePatchDrawable.draw(batch,
                0,                      // x
                0,                      // y
                0.5f * entityWidth,     // origin-x (rotation happens around this offset)
                0.5f * entityHeight,    // origin-y (rotation happens around this offset)
                entityWidth,
                entityHeight,
                1.0f,                   // scale-x
                1.0f,                   // scale-y
                angle);