Wednesday, August 10, 2011

Hey, Chrome! Fix your texture uploads!

I've been poking and prodding at my RAGE demo as onGameStart draws nearer, trying to clean up the code and squeeze a bit more performance out of it. During this testing I've made a depressing observation:

Chrome's performance, in reference to speed of texture upload, sucks. And by "sucks", I mean as it atrociously, painfully, unforgivingly slow.

The most technically demanding aspect of the RAGE demo is the constant texture swapping that happens every few steps. We pre-allocate an array of 30-40 some 1024x1024 textures (exact number depends on the map) and as we progress along the path we identify upcoming textures that will be needed, download them, and push them into an unused texture, hopefully well before that texture is actually needed. The Webkit and Firefox nightlies can handle this fine (though we do drop a frame or two here or there) but Chrome 14 on my Mac basically breaks down and cries when asked to do this. You can see for yourself in my simple jsperf benchmark.

So, to put this in perspective: Chrome is able to squeak out a measly 22 texture uploads per second at 1024x1024. That's ~50ms per upload that your browser is blocked on that call. If you are shooting for a 60hz game (~16ms per frame) this means that uploading one texture to graphics memory just caused you to drop 3-4 frames. One texture, 3-4 frames lost. Ouch! For a medium that will be highly dependent on streaming, that hurts!

By comparison, Safari 5 gives me 62 uploads per second (ie: you may drop a frame here and there, but performance will stay pretty solid.) and Firefox 7 blasts out a whopping 188 uploads per second! That's ~8ms per upload, leaving lots of breathing room for rendering!

It's a real shame too, because in most other ways Chrome seems to be the most solid performer with WebGL. If I chop all the textures in my RAGE demo down to 512x512 I can run at a rock solid 60hz with no tearing or stuttering. (Though the texture upload is still painfully slow compared to the other browsers.)

Maybe the benchmarks look a lot better on Windows, but I don't have a machine to test that with right now. Regardless, this is something that the Chrome team really needs to smooth out. Pretty please?

(All timing is taken from my iMac)

[UPDATE: I wrote up a bug report on the issue, lets see if it goes anywhere. Similar reports have been added in the past, as seen in the comments on this post]


  1. I've written a test about this a while ago, status: unconfirmed, priority: 2, rejected as important by developers on #chromium, told me to get lost.


  2. Do you know any graphics engineers in the Chrome team? You should email them directly. Maybe they dont read your blog.

  3. I'm assuming that this refers only to the speed it takes to upload a texture from memory to the GPU. Correct?

    Sadly, I don't know of too many applications that require high texture upload performance other than Rage (how many games use virtual texturing?), so I can't see this issue being given high priority. Alas, we can hope.

    Perhaps you could poke around inside of the chromium source to find out what is going on with the call? I'm sure the team would be willing to accept a patch.

  4. Woah!

    There seems to be a surprising amount of chatter around the issue raised by Brandon.

    Good work! It seems that faster texture uploads will be coming sooner rather than later.

  5. I don't know if this makes sense or not, but have you tried using a WebGLFramebuffer instead of a texture upload for these large, ever loading textures? It may be possible to get a significant speedup compared to texture upload.

  6. I have not tried Framebuffers, no, but I have a hard time imagining that they would perform much differently, especially in light of some of the things I've recently learned about Chrome's command buffer. I think this is a "bandwidth" issue, more than a matter of the API itself.

    I suppose it's always worth a shot, I'm just not very hopeful.

  7. +1!

    This is a huge issue for video, when you only have 30-50ms at the most to get all your rendering in. It's been the single biggest bottleneck for Seriously.js in Chrome, and it's the reason why I get 30-40fps with a pretty basic scene, compared to Firefox, which exceeds the hard limit of 60fps without breaking a sweat. It's fine for now, but if I wanted a higher-res video or to composite multiple videos, forget about it.

    I'd be very interested to see an example using WebGLFramebuffer.

    And thanks for updating the jsperf test.

  8. From this weblink you will get all the info on how to handle your homework and how to do it right. Maybe you need to check it out sooner or later