Skip to content

Instantly share code, notes, and snippets.

@doriancransac
Last active April 10, 2022 13:59
Show Gist options
  • Save doriancransac/e69728fe68dfb8542d67aa688b1405d8 to your computer and use it in GitHub Desktop.
Save doriancransac/e69728fe68dfb8542d67aa688b1405d8 to your computer and use it in GitHub Desktop.
A quick client implementation loading a sprite sheet 500 times and checking the global memory usage on the host after loading and drawing the textures
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.management.ManagementFactory;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public class MemoryUsageDebuggingClient {
private static final Logger logger = LoggerFactory.getLogger(MemoryUsageDebuggingClient.class);
public static void main(String... args){
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.width = 1900;
config.height = 1280;
final int[] renderingCounter = {0};
new LwjglApplication(new Game() {
private static final int nbAnimations = 500;
private static final int nbDistinctSheets = 500;
private BitmapFont font;
private SpriteBatch batch;
private Map<AbstractMap.SimpleEntry, Animation<TextureRegion>> testAnimations;
private List<TextureRegion[][]> spriteSheets;
private double stateTime;
@Override
public void create() {
System.out.println("Starting to create!");
//Explicit full gc calls not really necessary here, but just in case
System.gc();
System.out.println("Getting ready to load textures, memory = " + (getTotalMemory() - getFreeMemory()) / 1024 / 1024 + " MB");
initSpriteSheets();
System.gc();
System.out.println("Finished loading textures, memory = " + (getTotalMemory() - getFreeMemory()) / 1024 / 1024 + " MB");
System.gc();
System.out.println("Getting ready to initialize animations, memory = " + (getTotalMemory() - getFreeMemory()) / 1024 / 1024 + " MB");
initAnimations();
System.gc();
System.out.println("Finished creating animations, memory = " + (getTotalMemory() - getFreeMemory()) / 1024 / 1024 + " MB");
this.batch = new SpriteBatch();
this.font = new BitmapFont();
this.stateTime = 0;
System.out.println("App created, now rendering.");
}
private void initSpriteSheets() {
this.spriteSheets = new ArrayList<>();
IntStream.iterate(0, n -> n+1).limit(nbDistinctSheets).forEach(n -> {
System.out.println("Loading sheet #" + n + "...");
Texture texture = new Texture(new FileHandle("./pv-client/src/test/resources/ant_running_17frames.png"));
TextureRegion[][] singleDimensionalArray = TextureRegion.split(texture, 384, 384);
this.spriteSheets.add(singleDimensionalArray);
});
}
private void initAnimations() {
this.testAnimations = new HashMap<>();
IntStream.iterate(0, n -> n+1).limit(nbAnimations).forEach(n -> {
int electedIdx = n % nbDistinctSheets;
System.out.println("Elected sheet #" + electedIdx + " creating animation #" + n + "...");
TextureRegion[][] electedSheet = spriteSheets.get(electedIdx);
Animation<TextureRegion> animation = new Animation<>(18, electedSheet[0]);
animation.setPlayMode(Animation.PlayMode.LOOP);
int spreadFactor = 1000 / nbAnimations;
int x = (int)Math.round(Math.random()*(nbAnimations/2) * spreadFactor);
int y = (int)Math.round(Math.random()*(nbAnimations/2) * spreadFactor);
testAnimations.put(new AbstractMap.SimpleEntry(x, y), animation);
System.out.println("Added sheet #" + electedIdx + " for animation #" +n + ".");
});
}
@Override
public void render() {
renderingCounter[0]++;
if(renderingCounter[0] % 100 == 0) {
System.out.println("Main render loop, memory = " + (getTotalMemory() - getFreeMemory()) / 1024 / 1024 + " MB");
}
actuallyRender();
}
private void actuallyRender() {
Gdx.gl20.glClearColor(0f / 255f, 0f / 255f, 0f / 255f, 1f);
//Gdx.gl20.glClearColor(255f / 255f, 255f / 255f, 255f / 255f, 1f);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.stateTime+=Gdx.graphics.getDeltaTime()*1024;
batch.begin();
AtomicInteger currentIdx = new AtomicInteger();
testAnimations.entrySet().forEach(e -> {
currentIdx.getAndIncrement();
float floatStateTime = (float) (stateTime + currentIdx.get() * 1024);
//System.out.println("Drawing from sheet #");
TextureRegion keyFrame = e.getValue().getKeyFrame(floatStateTime);
//System.out.println("time=" + floatStateTime + "; idx=" + testAnimation.getKeyFrameIndex(floatStateTime) + " -> u=" + keyFrame.getU() + "; v=" + keyFrame.getV() + "; u2=" + keyFrame.getU2() + "; v2=" + keyFrame.getV2() + "; ");
batch.draw(keyFrame, (Integer)e.getKey().getKey(), (Integer)e.getKey().getValue());
});
batch.end();
drawFps();
}
private void drawFps() {
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
batch.begin();
font.draw(batch, "FPS: " + Gdx.graphics.getFramesPerSecond(), 50, height - 50);
batch.end();
}
private long getFreeMemory() {
return ((com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean()).getFreePhysicalMemorySize();
}
private long getTotalMemory() {
return ((com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean()).getTotalMemorySize();
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment