In my code, I have an object containing a series of pixel coordinates. The performance of this object is crucial because it is used in the game at 60 frames per second, where the output cannot always be cached.
After experiments and benchmarking, the 3D array turned out to be the fastest way to implement it using untyped arrays:
var PixelCollection = function() { this.pixels = []; }; PixelCollection.prototype = { add: function(x, y) { var pixels = this.pixels; if (pixels[y]) { pixels[y].push(x); } else { pixels[y] = [x]; } }, each: function(callback) { var pixels = this.pixels; for (var y = 0, m = pixels.length; y < m; y++) { var row = pixels[y]; if (row) { for (var i = 0, mm = row.length; i < mm; i++) { callback(row[i], y); } } } } };
In some situations, the object is not fast enough, so I tried implementing the Uint8Array using a 2D array:
var WIDTH = 255; var HEIGHT = 160; PixelCollection = function() { this.pixels = new Uint8Array(WIDTH * HEIGHT); }; PixelCollection.prototype = { add: function(x, y) { this.pixels[WIDTH * y + x] = 1; }, each: function(callback) { var pixels = this.pixels; for (var i = 0, m = pixels.length; i < m; i++) { if (pixels[i]) { callback(i % WIDTH, Math.floor(i / WIDTH)); } } } }
It is slower. I thought it would be faster because writing - and reading from Uint8Array is faster, but since I create a huge object for each PixelCollection object, getting pixels is slower because it takes more time to repeat all the pixels. (Note: I also tried the implementation above with an untyped array: it is much slower)
A PixelCollection usually does not have all the pixels. However, the bounding box can span the entire canvas, so I need to create an array using a large buffer.
However, there may be such a way. I can create one large shared buffer and use a byte offset for each PixelCollection. So when the PixelCollection P1 will take up to 100 bytes, then the PixelCollection P2 will start at a byte offset of 100. This uses memory more efficiently, but I will need to keep track of the range of bytes used by each PixelCollection (is that what C calls "pointers"?) .
The annoying part: when the frame P1 expands, I need to move P2 to make a space for P1 . And I will need to set a safe buffer size for the shared buffer, so I need to make a safe estimate of how much memory it needs.
The implementation of this is possible, but it will take a lot of time, trial and error.
So, before you start with this: does this seem like a good way to do this? Are there any better or simpler ways to do this? Do you know any implementation examples that I could learn?
Edit: I added jsperf if you want to try your hand at optimization.
Add jsperf to this if you have a brilliant idea for optimization.