2
votes

I'm working on a simple JavaFX 2D game and I encounter performance issues.

I am rendering my game into a canvas which is updated each frame. But updating the canvas at 60 FPS strongly increases my CPU usage, and of course my GPU usage.

It doesn't come from big calculations because I tried with very basics manipulations in the canvas, as shown below, and the problem was still there.

Based on research I have made, I use a TimeLine to implement my game loop. It seems to be the best way to update the canvas at the frame rate I want :

private void initGameLoop()
{
    final Duration oneFrameAmt = Duration.millis(1000/60);
    final KeyFrame oneFrame = new KeyFrame(oneFrameAmt, actionEvent ->
    {
        gameView.getRenderer().render();
    });

    gameLoop = new Timeline();
    gameLoop.setCycleCount(Animation.INDEFINITE);
    gameLoop.getKeyFrames().add(oneFrame);
}

In this configuration I'm running my game loop at 60 FPS, and the changes are running on the FX application thread.

My render function is very simple :

public void render()
{
    gc.clearRect(0, 0, 50, 50);
    gc.setFill(Color.BLACK);
    gc.fillRect(0, 0, 50, 50);
}

gc is the graphicsContext2D of my canvas.

My canvas is scaling on my application's window size, but I'm simply redrawing a 50x50 black rectangle each frames, at 60 FPS my CPU usage increases by 8-10% on default window size, but on full screen my CPU usage increases by 25% to 30% which is insane.

The hardware acceleration is running, besides my CPU usage, my GPU usage is around 30%.

I can't just stop rendering the canvas when nothing happens in the game, because I need to render my animations.

And basically redraw only partials areas of the canvas doesn't change anything because my basic test (shown above) only redraw a 50x50 pixels rectangle on the upper left corner of the canvas, and it still uses 25%+ of the CPU.

All the examples of game loop or animations made with JavaFX that I have found on the web uses the same techniques, but every one I have tried so far have a high CPU usage.

My rendering is very smooth and fluid but the CPU usage is way to high for what it makes. I can't seem to find why doing so little takes so much on my CPU and GPU and can't find a solution on how to improve my game perfomances. From what I have found on my research, canvas seems to be the best way to render a game in JavaFX.

My questions are : Is there any way to improve performance using a canvas ? Should I be using the scene graph with multiple elements ? Or is there any solution that I have not think of yet ?

Thanks for your help !

1

1 Answers

1
votes

Conceptionally JavaFX rendering always has a CPU and a GPU portion. In the CPU portion the geometry is prepared to be rendered and the GPU portion finally does the rendering. Canvas rendering is the slowest option because the API forces you to always create new objects in each frame when you want to change something which means that you always suffer from the slow CPU portion of the rendering. On the other hand scene graph rendering can be faster if the changes you apply to your scene are only translation transforms (which can be extended to rotations and scaling with the appropriate rendering hints) because then you suffer from the slow CPU portion only once but not in every frame. If you constantly have to change the geometry too, then you are lost with both approches and the only option is to go for 3D rendering (which is what I do) via a triangle mesh. The nice thing is that in JavaFX 3D rendering can be easily combined with 2D rendering to get the best of both worlds.