First off: Demos!

Title cards are for wimps!

Quake 3

Posted: August 2010

Source Engine - Team Fortress 2

Posted: September 2011

Have you noticed a trend?

Textures are a big bottleneck

Quake 3 Demo:

TF2 Demo:

Optimizing Texture Performance

WebGL Camp 4, 2011 - Brandon Jones


The rest of this presentation will make artists cry!

Optimizing Downloads

Even though games can look like this...

Lots of people are happy to play this...

Or this!

Keep your texture sizes reasonable

Choose the right file type

TF2 Heavy texture map. 1024x512, no alpha channel

Group texture data intelligently

Diffuse + Specular: 930 KB PNG
Normal: 553 KB PNG
Total: 1.4 MB

Group texture data intelligently

Diffuse: 115 KB JPEG
Normal + Specular: 844 KB PNG
Total: 959 KB

Finally, always always always GZIP!

HTTP compression is the ultimate no-brainer.
Jeff Atwood, Coding Horror - 2004

Optimizing Uploads


Posted: May 2011

Pool Texture Handles

Reuse textures for images of the same size

Don't lie to WebGL about your format

Match the format to the actual input.

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, ...);

(Note: OpenGL ES 2.0 requires that these values match)


If your textures are opaque or contain premultiplied alpha

gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);

See Chromium bug 92388

Throttling Realtime Texture Uploads

We all love the following code

var img = new Image();
img.onload = function() {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, ..., img);
img.src = textureUrl;

But doing that while rendering can cause unpredictable performance hitches

Throttling Realtime Texture Uploads

For more predictable behavior, only allow a fixed number of uploads every few frames

var img = new Image();
img.onload = function() {
    readyTextures.push({img: img, tex: texture});
img.src = textureUrl;

function requestAnimationFrameCallback() {
    if(readyTextures.length && frameCount % 2) {
        var ready = readyTextures.shift();
        gl.bindTexture(gl.TEXTURE_2D, ready.tex);
        gl.texImage2D(gl.TEXTURE_2D, ..., ready.img);
    // Draw

Measuring performance



Calls must be paired, cannot be nested


Impressive Demo

Posted: December 2011

Holy crap!

Compressed Textures!

Available now in nightly Webkit/Chrome.

Sample Code

var ct = gl.getExtension("WEBKIT_WEBGL_compressed_textures");
var texture = gl.createTexture();

gl.bindTexture(gl.TEXTURE_2D, texture);
    0, // Mip level
    ct.COMPRESSED_RGBA_S3TC_DXT5_EXT, // Internal Format
    width, height, // Texture Dimensions
    0,  // Border? 0/1
    buffer // Typed Array w/ compressed texture data
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
// and so on...

Won't help download speeds much

iOS Rage 1024x1024 texture download size

Benefit is that it can stay compressed in memory

In memory texture size


Thank you!