Monday, December 2, 2013

failIfMajorPerformanceCaveat: With great blacklisting power comes the need for self restraint

Chrome is gaining a new WebGL context creation attribute: failIfMajorPerformanceCaveat. In the words of the spec, when you've set this useful little boolean to true:
Context creation will fail if the implementation determines that the performance of the created WebGL context would be dramatically lower than that of a native application making equivalent OpenGL calls.
Essentially, if there's any reason why the browser feels that the requested WebGL context will have significant performance overhead setting this flag allows the browser to simply not give you a context. It's a way for you as the developer to say "This context needs to perform really well, and if you can't deliver that then I'd rather not get one at all." In Chrome's case specifically, there's only one reason we will currently fail to return a context and that's if the SwiftShader software renderer is being used. (We may add more cases in the future.)

I think the kneejerk reaction many developers will have upon learning about this is: "Hey! I always want my WebGL to run fast! I'm going to set this flag on every context I ever create forever!"

If that sounds like your thought process, I give a you a stern look of disapproval: ಠ_ಠ

Look, everyone wants their content to run fast, and nobody is thrilled about the idea of your fancy WebGL app running on an ancient Windows XP laptop with little to no GPU support. I get it. But if you blindly set this flag on everything you are telling the world "If you can't run this at 60 FPS then you don't deserve to see my precious Javascript. Get off my site!" And that, my friend, makes you kind of a jerk. Even if it's going to be a slideshow, often times slow performance is better than no performance.

So why did we add the flag at all if I'm immediately going to tell you not to use it? The trick is to use it with care, considering the whole user experience. Consider these guidelines:

Use failIfMajorPerformanceCaveat when you have a fallback.

Let's say you have a 2D, sprite based game with two renderers: A WebGL one and a Canvas2D renderer. The natural assumption is that WebGL should be faster than it's Canvas2D counterpart, so you've put all sorts of cool particle effects and shader tricks in your WebGL version, but still maintain the Canvas version for all those poor WebGL-less iPad owners.

This is a perfect scenario for failIfMajorPerformanceCaveat! It may be that the fancy WebGL-based special effects mean that the Canvas2D version actually performs better when SwiftShader is in use. In that case this flag will help you fall back to the code path that provides the best user experience without unnecessarily blocking people from your content.

Use failIfMajorPerformanceCaveat when speed is an absolute must.

If you've created an awesome twitch-driven action game where a single dropped frame is the difference between success and failure then this may be the right flag for you. Also, you're very brave to be building such a game in the browser, and I absolutely want you to send me a link! I would still suggest at least trying your game with the software renderer first, though! You may be surprised, as it can sometimes outperform integrated chipsets!

If you do block users for this reason, though, please make sure they land on a page that informs them as to why they didn't get the content they were hoping for. Nobody likes a black screen and a console error.

Use failIfMajorPerformanceCaveat to work around known bugs.

Maybe you've discovered that for some reason your app simply fails to work if the software renderer is active. It's unfortunate, but it happens. In this case, please once again make sure that you tell the user what happened with a friendly landing page, and please make sure to tell us about the bug!

Don't use failIfMajorPerformanceCaveat for your latest WebGL demo.

If your WebGL app isn't an actual game and doesn't provide some sort of useful service (ie: a demo) then please don't set this flag! There's really no reason why your spinning model or shader demonstration has to run at 60 FPS. Yes, you'll get visitors that pull up your content on a phone and get a whopping 5 frames per second, but I'm willing to bet that those people's reaction is going to be more along the lines of "Holy Crap! Look what my phone can do!" and not so much "Gosh, I really wish they had blocked me from seeing this."

In essence: don't use failIfMajorPerformanceCaveat to hide content. Use it to help deliver better user experiences!