mjs: Simple Vector and Matrix Math for JS
8 Comments Published by vladimir February 5th, 2010 in Canvas 3D, Firefox, MozillaOne common thread running through the many different and interesting WebGL projects out there is that they all need to do vector and matrix math, do it quickly, and do it in JavaScript. To date, developers have either rolled their own, or they've used Sylvester, a fairly featureful vector and matrix JavaScript library.
One of the problems with Sylvester is that while it's fully featured (arbitrary NxN matrices and vectors can be created and manipulated), it suffers in performance because of it. Since this is such a crucial part of a successful WebGL program, I've put together a small package that I'm calling mjs.
mjs is designed around speed and simplicity. For example, it doesn't attempt to stuff vectors and matrices into JavaScript objects. Because the language offers no operator overloading, there's very little benefit in treating these types as discrete objects, and lots of performance and memory usage downsides. Instead, it provides a set of functions for performing operations on vectors and matrices, which can be any array-like object. For any function that returns a vector or matrix, an existing array can be passed in to take the result, or the function can create a new one. Array reuse ends up being important because of the potential for expensive garbage collection churn eating away at performance.
Here's a sample of the API:
var r = M4x4.rotate(Math.PI/2, V3.$(0, 1, 0), M4x4.I);
Note that V3.$ and M4x4.$ are shorthand for creating a new V3 or M4x4 (I wanted to use V3() and M4x4(), but that didn't work out too well since functions have a length property). However, because all they return are just new array-like objects, you could also write:
var r = M4x4.rotate(Math.PI/2, [0, 1, 0], M4x4.I);
If the WebGL types are available, those will be used for newly created vectors/matrices. They are a significant performance boost especially for repeated operations; but for specifying one-off vectors such as the above, literal array syntax is fine.
The rotate function internally makes a rotation matrix, and then multiplies it by the given matrix. So the above could also be written as:
var rotation = M4x4.makeRotate(Math.PI/2, [0, 1, 0]); var r = M4x4.mul(M4x4.I, rotation);
(The last line being redundant given that we're multiplying by the identity matrix.)
All methods that return a vector or matrix take an optional final argument, that of an existing object to reuse. For example:
var m0 = M4x4.$(); r = M4x4.mul(someMatrixA, someMatrixB, m0); // r == m0, so the assignment isn't necessary, but it's handy for chaining // .... do something with r ... r = M4x4.mul(someMatrixB, someMatrixC, m0); // r == m0 still // ... do something else with new results ...
Without allocating any additional temporary objects.
As mentioned before, one of the goals of mjs is performance. Matrix multiplication is one of the most common tasks, so here are some numbers comparing mjs, Sylvester, and native C code. This was run on a Core i7 desktop using a local build of Spidermonkey, which included one patch that's about to go into the tree that fixes the no-reuse tracing case. (Without it, the no-reuse tracing case is much larger because it's never actually jitted.) The test is simple: it multiplies two matrices together in a loop 1,000,000 times.
| Test | Time |
|---|---|
| mjs, JIT, matrix reuse | 140ms |
| mjs, JIT, no reuse | 533ms |
| Sylvester, JIT, no reuse | 5,280ms |
| mjs, no JIT, matrix reuse | 25,833ms |
| mjs, no JIT, no reuse | 26,681ms |
| Sylvester, no JIT, no reuse | 41,996ms |
| Native C++, SSE2, matrix reuse | 71ms |
| Native C++, SSE2, no reuse | 142ms |
(I also have numbers for MSVC without the SSE2 compile flag, but the numbers vary greatly depending on whether the values eventually go to infinity or not; if the values end up trending towards 0, the non-SSE2 code tends to win at around 52ms vs. 71ms; if the values trend to infinity, the non-SSE2 code takes around 11,000ms!)
Those numbers are pretty encouraging -- having native code be only 2x as slow for something like this is pretty nice to see. Granted, this is only a very isolated test, and I'm sure there are some tricks to optimizing the native code case (it's currently just a fully unrolled set of multiplies and adds). The "no JIT" case is less nice, but I'm sure that our Jaegermonkey folks will be all over this testcase (right, guys?). In any case, ideally most WebGL rendering loops will be fully traced in Firefox, so it would be less of an issue.
mjs is still very much a work in progress; it's missing a test suite and a whole bunch of features. You can find it hosted at Google Code, at webgl-mjs. (Side note: I couldn't just call the project mjs because a project called mjs was abandoned on Sourceforget 5 years ago, and Google Code complained.) There's also some documentation, viewable online here.
Bugs and contributions welcome!
Android Progress: More Pixels Edition
44 Comments Published by vladimir February 2nd, 2010 in Firefox, MozillaIt's been a while since I posted a progress update (or really any blog post, ahem), but porting Firefox/Fennec to Android is progressing at a good clip. After working out a few kinks (and setting the all-important "you're allowed to touch the network" permission), I just got our first page load:
Mouse events sort of work, toplevel windows sort of work, keyboard doesn't work yet but shouldn't be hard to hook up. This is running in an emulator at the moment for ease of debugging, but it's working just fine on physical hardware as well.
You'll note that this is the full Firefox interface, and not the Fennec/Firefox Mobile UI; we're testing with the full interface because it's significantly more complex than the mobile UI and stresses Gecko much more. So, if the full UI works, then Fennec should work fine as well. Given the interest in Android on netbook and tablet devices, an updated version of the full Firefox UI might find a home on some of these. Android has been pretty great to work with so far; it's a bit unusual platform for us due to its Java core, but with the NDK we're able to bridge things together without many problems.
We're still a ways to go before any kind of usable alpha release, but we're certainly one step closer. We'll also be able to accelerate our progress now that we have some of the basic scaffolding in place. I know I'm looking forward to running Fennec on my Droid, and there are tons of Android devices coming out that should be great platforms for Fennec.
WebGL Draft Goes Public
0 Comments Published by vladimir December 10th, 2009 in Canvas 3D, Firefox, Mozilla
I'm pretty excited to have the WebGL draft spec available for review and comments today. There's still plenty of time for feedback, but we're far enough along to be able to solicit meaningful feedback. There are multiple implementations, which is a much better state than the early Canvas 3D work where things only worked during a full moon after saying "OpenGL" three times backwards into your monitor!
We're actively working through remaining warts and edge cases (and they are a lot of them!). Take a look at the official Khronos WebGL landing page and Arun's blog post for more information, including where to go to sign up for the public mailing list and for a set of resources about WebGL.
Heads Up: WebGL Canvas*Array renamed to WebGL*Array
0 Comments Published by vladimir December 2nd, 2009 in Canvas 3D, Firefox, MozillaI just checked in a patch from Mark that renames WebGL's Canvas*Array objects to be WebGL*Array, to match the current state of the spec. The APIs remain the same, so it should be a matter of search-and-replace to update. Should show up in tomorrow's nightly builds of Firefox.
WebGL Goes Mobile
6 Comments Published by vladimir December 1st, 2009 in Canvas 3D, Firefox, MozillaOne of the goals of WebGL was always to enable the functionality on both desktop and mobile devices. This is one of the reasons why OpenGL ES 2.0 was chosen as a starting point for the capabilities exposed by the spec.
We've had support for WebGL in Firefox desktop nightlies for a few weeks now, but soon I hope to have it enabled on Firefox for mobile devices (code name Fennec) as well. Jay demonstrated some simple demos working on Nokia's N900 at the ARM techcon3 today a few weeks ago (took a while to get the video done!), and I've grabbed a quick video showing things in action.
This should be showing up in Firefox for mobile devices nightly builds, so we'll see some more interesting things running on phones soon!

