Posted:

Enabling non-continuous rendering in libGDX

Motivation

Before describing how to enable non-continuous rendering in libGDX , I need to explain libGDX's default rendering mode: "continuous" rendering.

In libGDX the render thread on Android will, by default, invoke your ApplicationListener's render callback as frequently as makes sense. In practice, this means once per screen refresh, or 60 (or 30 or 50 or 80) times per second (depending on your hardware). This makes sense for games that are updating the majority of the screen the majority of the time they're running.

The major downside of this approach is battery usage. A render thread actively running 60 times a second, even when your game is relatively idle (e.g., its showing a static menu or high-score list) will be a big CPU user and a drain on the battery. If you re-draw the entire screen on each render call (which is pretty typical), the battery drain will be even worse.

Note that I'm mostly interested in the behavior on Android so the details and motivations may not apply directly to desktop, GWT, or other libGDX back ends (though all the code should work fine). Also, note that continuous rendering in no way guarantees a render rate, there are hiccups when other applications run, or when your own app takes too long in executing its render. Independent of non-continuous rendering, you should not depend on the framerate in your code.

The solution for the battery drain and high CPU usage of continuous rendering is non-continuous (or "on demand") rendering.

Enabling Non-continuous Rendering

Enabling non-continuous rendering is straight-forward. The only complexity comes from knowing when to request a render.

To enable non-continuous rendering, add this to your ApplicationListener's create method:

    Gdx.graphics.setContinuousRendering(false);
    Gdx.graphics.requestRendering();

You can enable or disable continuous rendering at any point, not just at create-time. For example, you could leave your app in continuous rendering mode during the core part of your game, and only switch to non-continuous mode when displaying a menu or other relatively static content.

Once continuous rendering is disabled, the render thread will wait before rendering a frame (technically, before invoking your app's render callback). There are currently three different ways the render thread will be awoken if non-continuous rendering is enabled:

  1. If there are input events (touch screen, keyboard, mouse, etc) to process
  2. A call to Gdx.graphics.requestRendering()
  3. A call to Gdx.app.postRunnable()

The first is case is handled internally by libGDX. So you just need to sprinkle calls to Gdx.graphics.requestRendering() where (and if) necessary in your application.

Kicking the Render Thread

As a first pass, just invoke:

    Gdx.graphics.requestRendering();

at the end of your ApplicationListener's render method. This should be exactly equivalent to the continuous rendering approach. The next step is to have logic in your render method that will occasionally skip this call to requestRendering().

In my app, I request another render in the following situations:

  • Right after enabling non-continuous rendering.
  • If any animations are active (to keep the animation smooth).
  • If any internal event is triggered, or if any internal state machines are active. This is coarse and conservative, but its safer to occasionally render an extra frame or two.
  • On resize (this shouldn't be necessary, but currently seems to be necessary on the desktop).

Consequences of Sporadic Rendering

Assuming you don't miss any places where you need to kick the renderer, there are a couple implications of non-continuous rendering.

If your render method is also the method that updates your game's state, those updates can now become more sporadic, and you may see larger gaps between updates than you would have.

The built-in FPS tracker will be knocked out of whack. I changed tack and record the time each call to render() takes (i.e., tracking seconds-per-frame) and store a histogram of the results. This gives me the same information, just in a different form.

Extras

If you're switching between continuous and non-continuous rendering, Gdx.graphics.isContinuousRendering() might be useful to figure out if you need to request a render or not. Though it probably costs exactly the same to invoke requestRendering as to check which mode is currently enabled.

Open Issues

I'm not sure if any of this applies to the GWT backend.

Non-continuous rendering was broken in the JOGL backend. The JOGL backend was executed in mid-2012 (though for other transgressions).

I'm not sure if any of the scene2d or box2d stuff is impacted by non-continuous rendering.

Comments or Questions?

Subscribe via RSS | Atom Feed