HTML 5 Profiler #2
by Eric Preisz · 08/10/2012 (4:34 pm) · 10 comments

Previous Posts
HTML 5 Profiler #1
Last week, I started my Innovation Friday project by kicking off a blog on the start of an open source HTML 5 profiler. Today, I started doing some research to validate my approach. Already, I’ve run into some interesting challenges and findings.
As I stated last week, my idea was to write benchmark tools that isolate each stage of the graphics pipeline to see how well each browsers takes advantage of the hardware available. This week, I’m starting to think that won’t work as well as I planned.
I started today by trying to prototype a test that isolates vertex processing performance. My first realization is summarized by my twitter post this morning.
“Does anyone know if HTML 5 Canvas uses any hardware vertex processing or are the vector objects converted to raster on the CPU? #HTML5"
Of course, the answer is, “it depends, and it’s up to the browser vendor”. So I started searching for the answer using some profiler tools to answer the question on popular browsers.
The tools I used included: gDEBugger (from Graphic Remedy), GPUPerfStudio(AMD), and PIX (Microsoft).
I realized fairly quickly that it will be hard to use these tools with Chrome. When you run a profiler on Chrome, all you are profiling is the application host process and the tools I have at my disposal won’t let me grab the process with the graphics device (each tab is a process in Chrome as I'm sure you know).
I had my first breakthrough with Firefox and PIX and I was able to answer my question...at least the answer as it relates to Firefox.
I added a simple circle to the screen that looked something like this:

Firefox does indeed tessellate the circle into polygons. In Firefox, this single circle has roughly half the number of polygons of the car model below. Plus to complete the circle it actually called draw twice (not sure why it does this exactly).

3688 Polygons (Image from Turbosquid)

One Canvas 2D circle, two draw calls: 8116 polygons
So, in Firefox, it’s fairly easy to see that your game could be limited by vertex throughput if you drew 1000 small circles on the screen (a small circle used around 1000 polygons). Not to mention there are some costly calls between Draw calls that may not be necessary such as ID3D10Buffer::Map, ID3D10Buffer::Flush, and ID3D10Buffer::UpdateSubresource. I’m not sure why those functions are called.
In chrome, this same scene ran much faster. Why, I don’t know because I haven’t had any success getting the profiler to run.
So I did learn something…I learned that I shouldn’t draw circles in Firefox. Their method to convert a parameterized primitive to a tessellated shape needs some improvement.
I learned something else too…I don’t think I will be able to write tests that help me isolate parts of the GPU when using HTML5 2D Canvas (which is what I said was the plan in the previous post). Those tests may be a better test of graphics and drivers than browsers implementations anyways.
So why can't I isolate vertex processing?
Because I don’t have enough control to make my own polygons. I would need to rely too much on the browser’s implementation.
For example, I could use many small circles on a screen to generate a high vertex count. But it could be that the reason the circle test is slow on Firefox is more because of the Map, Flush, and UpdateSubresource call. I need a better tool (such as NVIDIA’s Nsight) to determine that information. I was hoping I would be able to draw polygon’s directly in Canvas, but that’s not part of the API.
So instead of the previous approach, I’m going to build tests that focus on the performance of all the API calls. So I might write a scene that tests arcs or boxes or images and compare performance from one browser to the next. I'll also build more complex tests like ones that evaluate quick pixel rejection. I still think that will be valuable information to help you make your game.
I’ll be on vacation next week so I won’t be posting a blog next Friday. Soon, I will build the test harness and post that on GIT so that others can join in the fun.
About the author
Manager, Programmer, Author, Professor, Small Business Owner, and Marketer.
#2
The Chrome implementation was many times faster.
08/10/2012 (10:21 pm)
The only thing I noticed is screen space...but as I stated, even a small circle the size of a pencil eraser was 1000 polys. A big circle was 20,000 polys. It seems like there would be better ways to tessellate including using geometry shaders. As bad as these vertex issues seem, I think the strange API calls are the bigger issue.The Chrome implementation was many times faster.
#3
Yes, I think there would be better ways to draw a circle than that. I bet it is using some libraries that were written for compatibility in mind and not taking advantage of 3D/2D hardware acceleration.
I am guessing the strange API calls are just how they deal with buffers and notifications. It is probably drawing to a hidden buffer and then either swapping or copying the finished geometry to an on screen location. Did you test out multiple objects? Does it update for each circle or for all circles?
08/11/2012 (1:28 pm)
You may be able to find out what is going on inside Chrome and Firefox by building debug versions. Maybe that is outside the scope of what you are trying to accomplish, but that might give you more details. Yes, I think there would be better ways to draw a circle than that. I bet it is using some libraries that were written for compatibility in mind and not taking advantage of 3D/2D hardware acceleration.
I am guessing the strange API calls are just how they deal with buffers and notifications. It is probably drawing to a hidden buffer and then either swapping or copying the finished geometry to an on screen location. Did you test out multiple objects? Does it update for each circle or for all circles?
#4
I know these don't really help with your current project, but if improving overall performance will be the ultimate goal, things like these will make a difference.
Also, I believe that drawImage is your best bet when outputing just about anything on the screen. Having a preloaded circle image and using that is faster than the API call to draw an image. What is even weirder though; you might want to create separate canvases for every sprite and move and rotate those (using JS or CSS3, whichever is faster / available on the given platform) - instead of creating one canvas and drawing all your shapes on it.
You might also want to look into globalCompositeOperation, the different modes (most of them are supported by all major browsers by now, though there seem to be inconsistencies) and their uses make a huge difference performance-wise.
In general, cleaning the canvas every frame takes a lot of time. So does rotated drawing (but not rotating a canvas!) and scaling. This is why I use traditional DOM elements as extensively as possible. It gives great results, even if it seems like a terrible idea. :)
Also, it just occurred to me that not all browsers default to hardware accelerated display (actually, most of them do not). Some use it for 2D out of the box, some don't. There are CSS3 tricks to trigger 3D acceleration for 2D draws, but it's been a while since I last spent time on this.
I'm really interested to see where you get to with the benchmarks. As I find it, all implementations can be really fast once you find the quirks and learn how to take advantage of them. But it requires some intimate time with each browser individually. This is the part of HTML5 game development that really hurts the programmer imho. :) A lot of wrapping needs to be done to get great mspf counts.
And then there is iOS Safari, where true evil hides..
08/13/2012 (3:48 am)
Most of the built-in drawing routines are slow, unfortunately. It's trial-and-error with every API call, really. Also, by its nature, JavaScript itself has a few quirks that dramatically affect performance. For example some drawing routines will be significantly slower if they get floating point coordinates (x, y) so you might want to floor them (x|0,y|0). Another thing I realized is that if you force the type of a variable to a string (+"") the performance of all functions using that value will be better. (Of course, it only really makes sense in busy loops.)I know these don't really help with your current project, but if improving overall performance will be the ultimate goal, things like these will make a difference.
Also, I believe that drawImage is your best bet when outputing just about anything on the screen. Having a preloaded circle image and using that is faster than the API call to draw an image. What is even weirder though; you might want to create separate canvases for every sprite and move and rotate those (using JS or CSS3, whichever is faster / available on the given platform) - instead of creating one canvas and drawing all your shapes on it.
You might also want to look into globalCompositeOperation, the different modes (most of them are supported by all major browsers by now, though there seem to be inconsistencies) and their uses make a huge difference performance-wise.
In general, cleaning the canvas every frame takes a lot of time. So does rotated drawing (but not rotating a canvas!) and scaling. This is why I use traditional DOM elements as extensively as possible. It gives great results, even if it seems like a terrible idea. :)
Also, it just occurred to me that not all browsers default to hardware accelerated display (actually, most of them do not). Some use it for 2D out of the box, some don't. There are CSS3 tricks to trigger 3D acceleration for 2D draws, but it's been a while since I last spent time on this.
I'm really interested to see where you get to with the benchmarks. As I find it, all implementations can be really fast once you find the quirks and learn how to take advantage of them. But it requires some intimate time with each browser individually. This is the part of HTML5 game development that really hurts the programmer imho. :) A lot of wrapping needs to be done to get great mspf counts.
And then there is iOS Safari, where true evil hides..
#5
Wow, this is great info! I am just beginning to provide animation for customers on their web pages. This is great info. I wonder if any of these techniques are encapsulated in jquery yet.
@Eric,
There is a thought. If any of the html5 stuff is in jquery it could be a head start. Also, using jquery as a base for working with html5 would be good as it tends to have cross browser support.
Does anyone know if there is any browsers using JIT for javascript? Or is that a no no for security reasons?
08/14/2012 (8:15 am)
@Konrad,Wow, this is great info! I am just beginning to provide animation for customers on their web pages. This is great info. I wonder if any of these techniques are encapsulated in jquery yet.
@Eric,
There is a thought. If any of the html5 stuff is in jquery it could be a head start. Also, using jquery as a base for working with html5 would be good as it tends to have cross browser support.
Does anyone know if there is any browsers using JIT for javascript? Or is that a no no for security reasons?
#6
08/14/2012 (8:23 am)
@Frank: Thank you. Encapsulated? Not that I know of. Our HTML5 game framework is created as a jQuery plugin (we plan to make it publicly available at some point and it made sense to appeal to the majority of JS devs from the start by using a familiar design, and it's nice to build off platform-independent functions that work), and I tried to keep an open eye to not have to redo anything that's already in there - but I could be wrong of course and I certainly didn't read the entire jQuery source. :) Only some of it. :)
#7
08/14/2012 (8:53 am)
v8 (Chrome) is a JIT compiler and TraceMonkey performs sport JIT compilation from what I understand. I don't know if it is the standard JavaScript engine for Firefox or if it is a developer engine, though. Tamarin is a JIT compiler as well, and I think it has been the standard for a while. I think it replaced SpiderMonkey, but I cannot remember. It's been a while since I looked. I've primarily been working with V8 on private projects.
#8
Awesome work! The more I use jquery the more I love it. Basing your extension on it is smart.
@David,
Cool beans!
08/14/2012 (8:38 pm)
@Konrad,Awesome work! The more I use jquery the more I love it. Basing your extension on it is smart.
@David,
Cool beans!
#9
08/25/2012 (6:04 am)
I work as a software engineer for 3M (who touts/delivers innovation more than most companies our size) and I think Innovation Friday is awesome! I really hope this experiment leads to having a web platform (or web plugin) for T2D. That would seal the deal for me to stay on T2D indefinitely.
#10
3M was one of my examples when pitching innovation Friday to our investors. Quick question. When doing work for 3M under the 15% time, does the employee get any rights to the tech? We decided to give employees the right to open source their innovation Friday work to give them rights to the tech if they leave the company.
08/26/2012 (8:14 pm)
@Bruno- Yea, an HTML5 exporter would be great. Of course, it would mean that we would need to integrate Javascript into Torque (or a cross-compiler that went from TS to JS).3M was one of my examples when pitching innovation Friday to our investors. Quick question. When doing work for 3M under the 15% time, does the employee get any rights to the tech? We decided to give employees the right to open source their innovation Friday work to give them rights to the tech if they leave the company.

Torque Owner Demolishun
DemolishunConsulting Rocks!