phaser/docs/_phaser_tilemap_GL_progress.txt
Pete Baron 1b7eaadd06 First (nearly) working batch drawing test. Instead of pushing rectangles as pairs of triangles individually, this version creates a vertex buffer object for all visible tile rectangles, with degenerate triangles separating each one from the next. The drawing is done by a single call to gl.drawArrays.
Bizarrely, this version still chokes in Firefox, implying that the previous demo's horrible performance was not down to the GPU blocking as the rectangles are sent to it.

The test is not fully working because it does not scroll the drawing position. So instead of the map moving when you hit a scroll boundary, it simply stops drawing the top or left edges as the scroll region moves away from the visible window.  It's an easy fix, but I think I'll leave it until I find out exactly why Firefox still chokes on this demo.

Progress text file updated with latest experiments and progress today.
2016-05-23 17:48:54 +12:00

80 lines
8.3 KiB
Text

Phaser/PIXI Tilemap modifications
day one:
Background/comprehension - understanding the existing system
Experiments in PIXI - adjusting the first test code
Rewriting the PIXI component - created a new shader and handling code
Tile-mapping - added a single "tile" drawer using the "mario" test images, extended it to draw the whole map full of tiles
Optimised the code to reduce unneccesary webgl initialisation
day two:
Modify TilemapLayer to create and use PIXI.TileSprite using pixiTest flag (carried through Phaser.Tilemap.createLayer)
Tests indicate that the PIXI.TileSprite drawing isn't properly embedded in the draw list.
Created a new TilemapLayerGL class which extends PIXI.Tilemap in the same way that Phaser.TileSprite extends PIXI.TilingSprite. Used pixiTest flag in createLayer to branch and create the appropriate version. Adjusted sci-fly demo to use the new TilemapLayerGL class and tested.
We've now got a running demo with the ship over the map. It's running very slowly (profiling indicates 87% of the time is spent drawing tiles, so that will have to be modified to only draw the visible area) and it doesn't scroll when the ship hits the edges.
I think the scrolling might be related to the inability to set this.fixedToCamera (which blows up because there is no this.position value when it tries to establish the fixed position). Modified PIXI.Tilemap to extend PIXI.Sprite instead, but that didn't fix either problem. Realised that the problem was with lack of Core functions, so copied code from TileSprite to create core and experimented turning off the various mixins that it included. Successful test with only 'FixedToCamera' provided that this.fixedToCamera is set after the Core.init call.
Modified Pixi.TilingSprite to use this.x and this.y when drawing tiles, which has provided a scrolling map surface.
It's still very slow - probably because it's rebuilding the entire PIXI surface (2560x704 pixels) from 16x16 pixel tiles.
TODO: modify PIXI.Tilemap to create a surface only the size of the visible screen. Render only that part of the map into the new smaller surface.
day three:
Step through full process to ensure that slow-down is not caused by multiple draw-over (e.g. if a prior layer had multiple copies of a tile layer, or was calling render too many times). It isn't, so it must simply be too much work to draw the entire map each frame.
Add TilemapLayerGL modes to optionally draw only the visible on-screen tiles each frame. This fixed the frame-rate issues entirely, it all runs smoothly in this mode.
Did first-pass clean-up on TilemapLayerGL to get rid of all the legacy code from the original canvas implementation and correct the comments accordingly.
Modified Phaser.Tilemap to temporarily default to testing (pixiText = true) so that I can test the other examples/tilemaps demos and fix incompatibilities with the GL layer code.
Quick test results:
blank tilemap - draws tiles at top and runs, but newly drawn (by hand) tiles don't appear in the layers
create from objects - draws arrow and coins but not the map background
csv map - draws a map but with many white squares in it, doesn't feel very smooth either
csv map collide - draws a character but no map
csv map with p2 - same again
features test - draws brown background and green arrow, has a very few tiles but mostly blank brown
I'll start with "blank tilemap" and then retest the others in case it's all caused by one set of problems...
Ok, turns out that the examples are mostly set to Canvas mode... having overwritten that setting we get much better results (the examples are hardwired to use the GL tile layers at the moment, so Canvas logic + GL drawing == examples fail weirdly).
I have the blank tilemap example working, but there seems to be a difference in the way tiles are represented... for "sci fly" we have to subtract one from the tile index values (I'm assuming they're '1' based tile indices accessing a '0' based tilemap with the '0' tile index representing a blank tile). In the 'blank tilemap' example the tile indices are '0' based with '-1' representing a blank tile.
Retests:
blank tilemap - works, but tile numbers are out by one (click on the second tile picture to draw the first tile, etc) and there's no alpha blending when layers are not focused
* create from objects - draws arrow, coins, and map, but doesn't draw 'objects' like the signs
csv map (all three demos) - work but tile numbers are out by one
* features test - works but doesn't draw 'objects' like the torches and signs
fill tiles - appears to work, tile numbers are out by one
map bounce - works perfectly
map collide - works perfectly
* mario - works but 'wrap' is not repeating the map data down the screen
paint tiles - works, tiles out by one
randomise tiles - works, tiles out by one
replace tiles - works, tiles out by one
* resize map - draws map but doesn't visibly resize
sci fly - works perfectly
shuffle tiles - works perfectly
swap tiles - works perfectly
* tile callbacks - draws map but not coins, blobs where coins should be don't vanish (so callbacks might not be working)
tile properties - works perfectly
* tilemap ray cast - draws map but not debug layer, impossible to tell if raycast is working without debug
tileset from bitmapdata - works perfectly
* demos that fail for other reasons than 'tiles out by one'
create from objects: looks like the actual 'createFromObjects' call is working perfectly (coins). The failure is due to the lack of ability to handle multiple tile source images per tilemap. Looking at features_test.json (the map source) it appears that there are multiple layers with different sources... I'll start by supporting multiple layers.
With some help from Rich, finally discovered the Tileset class and it's firstgid value. Also discovered the 'draw' function in there which is hard-wired to Canvas drawing. Options: spin off TilesetGl class, or create drawGl function and branch on every draw call, or duplicate the firstgid logic in my new GL drawing code. I prefer the third option. At some point that draw in Tileset should be moved because Tileset is a data-holder class and shouldn't really contain drawing logic (despite how convenient it is to put it there to access firstgid etc from Tileset). My rationale for this separation is that rendering for browsers is very similar to writing game for old-school consoles - we separated the code that touches hardware from the logic code, because then we could convert the game to a different platform easily. In this case the 'different platform' is webgl but the approach should be the same.
day four:
Read through the new PIXI 4 tilemap code to see another approach to this task. It looks very similar (beautiful code though, mine is still very rough). They're using TRIANGLE rather than TRIANGLE_STRIP which I believe will give this implementation a slight speed edge when I add proper batching. There's an anim x,y property which is passed to the shaders, I'll need to look at their shader code to see how that's being used... might be a clever way of allowing map tile animations and passing most of the work off to the GPU.
Ran a profiler on my code using FireFox which runs the sci-fly demo extremely slowly (6 fps). As expected 95% of the time is locked in the _renderTile function, I'm virtually certain that the GPU is blocking because I'm only sending pairs in my TRIANGLE_STRIP at the moment. I shall prioritise the batch processing then re-run those tests to make sure the problem is solved. It would be very interesting to find out why Chrome and Canary on my computer do not suffer from the same problem (after all, it's the same GPU!). But I suspect I won't ever be able to answer that question in light of Rich's results (it ran slowly on his Chrome browser with a more powerful GPU...)
The batch changes are in, in a very rough form. The entire visible screen is now drawn with a single gl.drawArrays call after the JS sets up a large VBO with degenerate tris to separate the individual tiles from each other. This approach was hugely successful at drawing in the "pbRenderer" (now called "Beam"), however it is still choking FireFox. Further investigation is needed including: test the old pbRenderer demos to make sure they don't choke FireFox, if it does then check the PIXI 4 tilemap renderer to see if that does too. If the old demos work properly, then compare them with this new implementation line-by-line to find out what's causing the problem now.