Merge: gamnit: optimize the `flat` 2D api using GPU buffers
authorJean Privat <jean@pryen.org>
Tue, 28 Mar 2017 12:27:32 +0000 (08:27 -0400)
committerJean Privat <jean@pryen.org>
Tue, 28 Mar 2017 12:27:32 +0000 (08:27 -0400)
commitd2b68bda560657fe4610b079f5613b44924a626f
tree4d53e1b80c2efa922e45fb74d7778d0d34a053ab
parentb9ebe66bdfd6a6633226d068366a9cb2ceacdb11
parent08ff6f6d210c5594f61fcfb743067db6caae1c36
Merge: gamnit: optimize the `flat` 2D api using GPU buffers

`gamnit::flat` is an API to quickly and easily write 2D games, it is built around sprites added to either the world `sprites` or to the `ui_sprites` sets. However, the absolute lack of optimization led to slow performances when there was a large number of sprites.

This PR rewrites the implementation of the `flat` API using vertex buffer objects (VBO) to keep sprite data in the GPU memory. The data is updated only when an attribute of a sprite is modified.

The result is 200 times higher framerate in the new minimal program `template_flat` with 2000 sprites and random modifications, going from ~10 FPS to ~2000 FPS.

This requires managing the memory of the GPU, growing it as needed, keeping a list of freed spaces and defragmenting it to compress the data after sprite deletion. The GPU memory is simulated by the `GroupedArray` class, it keeps a bit more information than needed but it would also support objects with varying sizes like the 3D models of the `depth` API. All sprites are sorted when added to either `sprites` or `ui_sprites` allowing for bulk drawing of sprites using the same pixel data and usage type.

This PR extends the current API by adding a few new services:
* The attribute `Sprite::static`, when at `true`, gives a hint to the framework that this sprite won't change often and that it is added in bulk with other static sprites. This value can be ignored in the prototyping phase of a game and added when better performances are needed.
* The pseudo attributes `red`, `green` and `blue` modifies the tint of a sprite. They are more intuitive to use than the array `tint` and they allow for an automatic update of the related data on the GPU.

There is two downsides to this implementation:
* The attribute `Point3d::sprites` is added by refinement to all 3D points, even those not used directly by the graphics framework. Hopefully it will add only a small overhead, and (of course) only in clients of gamnit games.
* There is no easily predictable order in which the sprites are drawn anymore. Causing issues with non-opaque sprites which should normally be drawn last. This could be fixed by a new sprite category or a boolean attribute similar to `static`.

Pull-Request: #2395
Reviewed-by: Jean Privat <jean@pryen.org>
lib/core/kernel.nit