[HTML5] copyPixels is very slow and floods memory

I have just upgraded from old versions of Openfl and Lime to the latest one, and as I already told in the topic here I have noticed that copyPixels is extremely slower and floods memory, leading sometimes to browser crash, while compiling with the old libraries everything was pretty smooth.

Target: HTML5, canvas (webGL is even slower).

What’s happening?

  • UPDATE - the speed of copyPixels varies A LOT using different spritesheets, creating really weird situations: sometimes smaller Spritesheets take very longer to be parsed! Who knows why? Is it because of PNG compression type? Transparent pixels amount? Any idea?!

Do you have anything you can share, so we can see it ourselves?

Uh, no, sorry, I will be back at work on monday: I will try to load the different spritesheets in a smaller project to verify if there is the same difference in parsing time and then I will update this topic.

In the meanwhile I will describe what I tried: I launched a game that uses a ~8000x2000px spritesheet, and it took about 1-2 minutes to extract the bitmaps of all frames, creating about 5 bitmaps (with copyPixels) every second. Than I swapped this spritesheet with a bigger one (8000x5000), containing more than double the frames, and it took about 2-3 seconds to parse it all.
I then tried to save the first spritesheet (8000x2000px) with different compression levels, deleting about 3/4 of the opaque pixels, but parsing time didn’t change. I will do more tests.
I have absolutely no clues about the possible cause of the problem.

I noticed a general, sometimes unpredictable decrease in parsing/loading speed: i.e. with the older libraries I was loading about 50 sound effects in about 1 second, waiting for completion of each one to start loading the next one. Now, if I adopt the same steps it takes about 20 seconds to load the same files, so I have to load them all at once avoiding to wait for completion of each file (and I don’t know what will happen on mobile, now I am loading resources locally), and load time goes down to a few seconds (2-3).

About sound effects loading I have a suspect: in the old libraries the COMPLETE event was fake, it was being launched as soon as the download started, so it eventually loaded all the sound effects at the same time. Anyway, now the load time (start-complete) for each sound effect looks too long (and identical for 2k and 2MB files).

Two changes to the loading code, it should be more accurate with progress and completion events (as I think you noticed), but we also queue loads, limiting the number of simultaneous transfers. Too many at once crashes out on some browsers

You could try increasing this value, let me know if it helps:

So it automatically queues downloads? It looks really fast if I don’t wait for COMPLETE event myself.

- UPDATE - I tried to move all the spritesheets in a new simple project that only loads and parses them, and now copyPixels is fast on all spritesheets, so what can I try to understand why on the big project the parsing speed is so unpredictable?
One could say it depends on what the code is doing while parsing: it should be the same even if I replace the spritesheet to load, but (as I explained before) different spritesheets give totally different results, one is very fast and another one is terribly slow.

Later I will try to extract a smaller project from the big one, but I don’t know if it is possible, as it is very complex.

Can I send the tiny test project by mail?
I am downloading and parsing a single spritesheet, and the difference between the old and the new Lime/Openfl (in terms of time) is noteworthy.

Thank you for the test!

I found that (on my system) the speed varies between 150-300ms, or spikes to around 2200-2600ms. The difference was whether the BitmapData had an underlying canvas or UInt8Array data store. The context.drawImage approach was much slower (in this test) than copying each individual pixel, at least with the current Lime graphics code.

I’ve changed copyPixels in the development version of Lime to always prefer the UInt8Array route, which in this test, should always be the fast approach. I also added a small optimization where using 0 as your fill color on HTML5 should avoid a fillRect call, speeding things up further.

1 Like

Good… it looks like copyPixels “chooses” the approach for each spritesheet, right? Do I need to treat spritesheet images in order to create more manageable files?

So I need to install and give the Lime dev version a try? How do I install it?

You can follow the instructions here, if you like:

Let me know if you have questions

I have modified the Image.hx class directly, and now spritesheet parsing (copyPixels) is a lot faster!

It looks a bit slower than it was in the past, but I suppose the way Lime works has changed a lot in time: an advantage of the new libraries that I noticed is that when an (heavy) animation is played for the first time the games don’t hang anymore, maybe because the image data buffering is done before.

Thank you Joshua! You’re the man!

For what concernes mobile I will test as soon as possible, and if necessary I will update this topic.

- UPDATE - I have checked the webGL build, and it is still very slow in the parsing phase :expressionless:

You may also want changes in ImageCanvasUtil.hx and ImageDataUtil.hx if you’re doing the changes manually, but that could break C++ if you don’t have the matching Lime native binary

Done! It looks a bit slower now…

Try the latest OpenFL and Lime, and see how that works?

Looks the same: I think that the longer loading/parsing time is well compensated by the reactivity of the in-game animations. The best situation would be having the old loading/parsing times and the new reactivity of animations :wink: .

I will have to optimize animations + Spritesheet library, replacing the blind rebuilding of each frame with an hash-table to avoid double BMDs for identical frames.

Are we “a bit slower” or super slow? Curious if we’re in the 300ms camp, vs the 2200ms camp, related to the test you wrote before. Thank you

A bit slower, I didn’t keep time before, but now we are around 26secs to startup a game. Before the second code fix (= Lime 5.1) I think it was around 23-24. With the older libraries it was around 10-15 seconds.
As I told before, with the old libraries (2.9.1 + 3.6.1) the game started up faster, but it hung up everytime it had to show a new animation (just the first time for each animation), so the first minute of gameplay was pretty unpleasant.

With the new libraries all these initializations/caching seem to be made before startup (hanging up the PC, while parsing spritesheets I can’t even close the browser, that becomes completely unavailable). I’d like to know if this happens to other spritesheets users too.

Are the 26 seconds after preloading all of your assets, or does that include the preloading time?

26 seconds from F5 (reload page) without cache.

How much of the time is the preloader?

About 0.5 - 1 sec, barely visible: I am loading the JS locally.

- side note -
I have implemented the spritesheet hash-table: with certain specific spritesheets the parsing time decreases to a fraction of the previous time :wink: but the more affected spritesheets are very few…