[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] Resurrecting Update Scheduling

On Thu, Apr 15, 2010 at 13:48, Gregg Tavares <gman@google.com> wrote:
Here is a revised version of that scheduler proposal:
         context.setUpdateFunction(updateFunction, targetFramerate);

Suggestion: What about
canvas.setUpdateFunction(updateFunction, targetFramerate);

To clarify what's next let me start by saying that I preferred naming of the original proposal setRenderFunction/scheduleRender as it is common for apps/games to consider differently "update" (e.g change objects positions, detect collisions) and "render" (draw objects) code.

Proposed API promotes and limits to "Constant game speed with Maximum FPS" [1] and requires for many use cases usage of an additional setInterval since not invoking updateFunction when a context is not visible is not acceptable for some kind of apps (stopping rendering as soon a context is not visible is fine for all apps, however stopping updates of real-time app objects such as in action games is not - even if browser window has not been visible for some time).

Considering the large range of devices WebGL will run on, from older slow embedded devices to newest powerful desktops, it is difficult for developers to select a 'targetFramerate' that would work correctly on most devices.
I think we should rather promote and make it easy for app developers to build framerate-independent apps that provides the smoothest experience possible on high-end devices while degrading gracefully on slower devices (see Constant game speed with Variable FPS in [1]).

It is common that updateFunction can be called with a lesser frequency than renderFunction, for instance it is rarely needed to perform collision detection at each and every frame rendered; on the other hand the renderFunction should be invoked as often as possible on the running device (ideally at screen refresh rate), this enables apps to smooth/interpolate rendered frames between two updates for better user experience (especially for fast-moving objects).

In essence this means API must not require usage of a scheduleRender function to trigger rendering of each frame.

With some inspiration from Android's GLSurfaceView API [2], I propose :

typedef unsigned long WebGLRenderMode;
const WebGLRenderMode RENDERMODE_CONTINUOUS = 0; //render function will be invoked as often as possible
const WebGLRenderMode RENDERMODE_ONDEMAND = 1; //render function will be run in the near future after scheduleRender is invoked for each frame, useful for apps that require render after specific updates/events only

[Callback][Callable=render] interface WebGLRenderer {
void render(in WebGLContext context);

void setRenderer(in WebGLRenderer renderer, in WebGLRenderMode mode);
void scheduleRender();

This enables same benefits as original proposal, but do not force developer to empirically select a "targetFramerate" and more importantly do not force one kind of "game loop" to get these benefits.

Examples :

1) Spinning cube (the faster the device the smoother the rotation, the cube rotates at a constant speed no matter the actual framerate) :

gl.setRenderer(function () { gl.uniform1f(rotationAngle, Date.now() / 1000.f); gl.draw... }, gl.RENDERMODE_CONTINUOUS);

2) Rotate cube when mouse is clicked :

canvas.addEventListener("click", function () { gl.uniform1f(rotationAngle, angle++); gl.scheduleRender();  }
gl.setRenderer(function () { gl.draw... }, gl.RENDERMODE_ONDEMAND);


[1] : http://dewitters.koonsolo.com/gameloop.html , this article describes pretty well some of the most common loop techniques that are typically used in games and other multimedia apps.
[2] : http://developer.android.com/reference/android/opengl/GLSurfaceView.html