Update: the full sources for those benchmarks are available in the minko-examples repository on github:
The new version of Minko (Minko 1 is already available on GitHub) will introduce a few major API changes. Those changes are designed to provide better performances: Stage3D will soon be available for Android and iOS and we wanted to be ready.
To test the new version, we developed The Mirage: a small and yet addictive 3D game where you have to shoot flying saucers. You can control the game with and HTML5 web application on your iPhone/Android device. The application was built in just 24h with Minko 2 and it works on the web, the iPad, iPhone and Android devices. Check it out if you haven’t already seen it!
Minko 2 will eventually bring an incredible performance boost. Indeed, the boost is so big that working with Minko 2 will be just as fast as working with the bare Stage3D API (yes, that’s a bold claim… literally!). I will not explain how we achieved this in details, but to put it simply we’ve introduced an optimized scene-to-GPU data binding API that makes it possible to have a very high level scene representation working on a very low level static list of draw calls. Those draw calls can then be fed directly to the GPU.
If you’re a Flex/WPF developer, you’re probably familiar with the view/script data binding API. Minko’s data binding API is the same but the view is a 3D scene.
In order to demonstrate how fast it is, I’ve done a little stress test application:
The interesting number here is the “size” value: it gives the total size of the scene, including both groups and meshes. If you want the actual number of meshes (~ draw calls), you have to divide that number by two since each mesh has its own group to be placed at the right position. The numbers are monitored using Monitor.
Notice how the performances drop when you rotate the camera: the new view matrix has to be pushed in every draw call. And the more draw calls, the more CPU it will take. This kind of “global” data (camera, lights, etc…) might be allocated differently in the future to allow better performances.
I used cubes because I didn’t want to hurt the GPU too much. Here is another version that will attempt to fry your GPU with teapots:
- Intel Core i7 880
- NVidia GeForce GTX 460
- Firefox + Flash 11.2 beta 64 bits “release”
I tried to run the same application within Chrome + Flash 11.1 and I get slightly lower results (about 10 to 20%). I’m guessing the draw calls are less expensive with Flash 11.2, which is a really good thing! Flash 11.2 is available on Adobe Labs.
Please share your results for both benchmarks with your CPU/GPU configuration and Flash player version in the comments or on the dedicated Aerys Answers thread. Thank you!
The data binding is quite simple. For example when an object moves, its 3D transformation matrix “sends a signal” to notify the data binding API it has to be pushed to the GPU. But only the objects that actually use that matrix will be updated. You might think that creating the actual links between the scene and the shaders could be quite heavy to write. But it’s not thanks to some automated bindings: usual things like the camera, the viewport and the local to world transformation matrices are automatically linked.
Now you might wonder how much more complicated the framework is. And that’s the trick: it’s actually much simpler now! You only have three elements:
- the rendering (ActionScript shaders)
- the scene graph
- the data binding to link the rendering and the scene
Here is the code for the stress test application:
public class Main extends Sprite
private static const MESH : Mesh = new CubeMesh(new Effect(new TestShader()));
private var _viewport : Viewport = null;
private var _scene : Scene = null;
public function Main()
_viewport = new Viewport(stage);
// setup the camera
var camera : Camera = new Camera(_viewport);
camera.position.set(0, 0, -5);
camera.lookAt.set(0, 0, 0);
_scene = new Scene(new Group(camera));
// setup camera controls
var ctrl : ArcBallController = new ArcBallController(_camera.parent);
// setup the monitor
Monitor.monitor.watch(_viewport, ["numTriangles", "renderingTime"]);
stage.frameRate = 60;
private function enterFrameHandler(event : Event) : void
// add a new cube
if (Monitor.monitor.framerate > 30)
var m : Mesh = MESH.clone();
var tg : Group = new Group(m);
(-0.5 + Math.random()) * 70,
(-0.5 + Math.random()) * 70,
(-0.5 + Math.random()) * 70
public class TestShader extends ActionScriptShader
private var _worldNormal : SValue = null;
public function TestShader()
forkTemplate.blending = Blending.ADDITIVE;
forkTemplate.enableDepthWrite = false;
override protected function getOutputPosition() : SValue
_worldNormal = multiply4x4(vertexNormal, localToWorldMatrix);
override protected function getOutputColor() : SValue
var normal : SValue = normalize(interpolate(_worldNormal));
return multiply(add(normal, float4(1, 1, 1, 1)), .5);
I’m pretty sure anyone who worked with Minko before will recognize most of the elements here. If you have questions or suggestions, please leave a comment or post on Aerys Answers.