|
-
Senior Member
AS3 is FAST! Redux - CopyPixels vs. Sprite Pooling
The original thread is getting off topic and this contained enough new data I figured I'd make a new thread and sum it up. Hope that's ok 
Basically, several people have suggested using the copyPixels method on BitmapData and compare it to my sprite pooling approach. So I went ahead and did just that. The results are interesting to say the least.
Copy Pixels
http://www.electrotank.com/junk/mike/flash/copyPixel/
Sprite Pooling
http://www.electrotank.com/junk/mike/flash/objectpool/
If you set the number of arrows the same on each, you will see the copyPixels is the clear winner when it comes to frame rate while time spent in the onEnterFrame is significantly less with object pooling.
Many of the frame-rate junkies here disregard anything else as important but I feel the object pooling method still seems preferable in cases where you dont have floods of sprites or movie clips and you need to shave milliseconds.
Either way, I go into a good detail on how it all works and my speculations here. Have fun!
-
Pumpkin Carving 2008
That's really good research, web. If I finally migrate to AS3, I'll be glad started collecting all theses threads in a doc file on my pc. But... frame-rate junkies? Is that all we are to you?
The 'Boose':
ASUS Sabertooth P67 TUF
Intel Core i7-2600K Quad-Core Sandy Bridge 3.4GHz Overclocked to 4.2GHz
8GB G.Skill Ripjaws 1600 DDR3
ASUS ENGTX550 TI DC/DI/1GD5 GeForce GTX 550 Ti (Fermi) 1GB 1GDDR5 (Overclocked to 1.1GHz)
New addition: OCZ Vertex 240GB SATA III SSD
WEI Score: 7.6
-
Senior Member
But... frame-rate junkies? Is that all we are to you?
There are some, yourself excluded, that ignore performance unless the frame rate is affected. I believe there is a subtle relationship between code execution time and frame rate and that it's a lot more complicated then people think. If I get a chance, I'll see if I can hunt down an Adobe engineer to explain it to me someday...
If we are going to start building the type of games I like (RTS, large RPGs, etc.) in Flash then we need to be able to squeeze every drop of performance available. That means understanding the internals as best we can. Thanks!
-
Senior Member
I was planning to do some test about it myself. Just so I understand what method you are using, let me see if the basics are correct:
1. Sprite Pooling.
*You have separate sprite object for each arrow.
*Bitmap from memory is loaded into each arrow bitmapdata object.
*Arrows are added to stage using addChild.
*Arrows are moved by updating their x and y properties.
*Scrollrect property is changed for each arrow at every step.
2. Copy Pixels
*1 general arrowsprites bitmapdata object is created.
*You have general object for each arrow (not the sprite object).
*Arrow sprites are not added to stage.
*At the stage is visible just 1 big bitmap object.
*Arrows are moved by updating their x and y variables.
*Main bitmap is cleared at each step.
*CopyPixels is used to copy image from arrowsprites object to main bitmap into position of each arrow.
Is the description correct so far?
-
Script kiddie
Something that's being overlooked in both these tests, though, is memory.
Using OS X's Activity Monitor, I watched Safari running both examples (500 frames, 50 arrows per frame). For object pooling, the real memory stayed firm at about 88 MB and the virtual memory went to about 400 MB.
But with copyPixel, the real memory went from about 160-400 MB (kept incrementing steadily then dropped down again; probably the garbage collector) and the virtual memory reached 600 MB.
There's something I'd like to point out... I think of it as the 'spike', and I think it's caused by the garbage collector clearing up. It happens in the copyPixels example, and the object pooling example when pooling is disabled. Every few seconds, the movie freezes for about half a second (and I think it's at this point that the copyPixel goes from using 400 MB back to 160 MB of RAM). You don't get this with pooling, because objects aren't being removed. The memory usage stays constant, so you don't get freezes every few seconds. If you haven't noticed this (I'll be honest, I had to pay close attention to notice it in the copyPixel test), try using 500 arrows in the object pooling test, with pooling disabled. Much more noticeable there.
Also, am I noticing that the copyPixel example doesn't seem to have an alpha channel? The arrows don't fade out, and there's no anti-aliasing. I'd trade the 3 fps speed difference I get for the graphical improvement object pooling allows. 
So, round-up...
Sprite Pooling:
Consistently low memory usage
Alpha channel
Significantly faster enterFrame execution
About 3 fps slower
No memory spike
CopyPixels:
Erratic memory usage
No alpha channel
Slow enterFrame
3 fps speed boost
Memory spike
Maybe this is just me not having the will to do another rewrite of Invasion 5, but I still prefer object pooling. The average user can't be expected to use as much as 400 MB of RAM for a Flash game (although this is in extreme cases; realistically you wouldn't use so many sprites under any circumstances - performance results across computers would be too inconsistent), and they won't appreciate the lack of an alpha channel. Plus, believe it or not, some people don't seem to notice a 3 fps speed difference. :s
And Tonypa, that all seems correct to me, but you've left out the whole point of the sprite pooling method - the pool. When objects would usually be removed, they are instead moved into an array to be re-used when the next object is created.
-
M.D.
maybe its just me but i think one of the reasons why the pooling one works better is that there's 1200 less arrows on stage.
or am i missing something here.
-
Script kiddie
Nah, that's because object pooling defaults to 25 arrows per frame and copyPixels to 50 arrows per frame... used 50 for both when I did my test.
-
Ahr, Vengeance MX, that's not entirely true. You can use the alpha channel with CopyPixels. And for memory usage - just have a BitmapData that you always draw to. I had the same spikes when I always threw away my BitmapData canvas. Just do a .fillRect with your favorite background color and use it again.
That's what I'm doing here: http://enwire.dk/flash/Flocking.html
Alright, I'm actually using the .draw method on BitmapData so I can use BlendMode.ADD, but I strongly suspect that when the input to the draw method is a BitmapData then it's just a form of copyPixels underneath.
-
M.D.
to use alpah in copyPixels set the copyAlpha property to true
myBitmap.copyPixels(copy, rect, point, null, null, true)
its false by default.
i dont see how more memory could be created unless your re-creating bitmaps and not disposing before you do. THere used to be a memory leak in F8, not sure about F9
-
It's extremely easy to spike the memory. In my first try at it I went from 0 to 500MB in seconds. All it takes is to allocate a new BitmapData of a reasonably large size (800x600) on each EnterFrame. Sure, the old ones will be deallocated - eventually. So in the best case you will see spiking before the garbage collector kicks in a frees the memory of the old BitmapData - but if you're going too fast (30FPS @ 800x600) you can easily hit virtual memory before the garbage collector gets a chance to run. And lets just say that when that happens things (and especially FPS) go down hill fast.
The solution is of course to "pool" your BitmapData by reusing them in each frame. Either completely copying them over with new data, or if it's for a canvas type thing, simply clear them with a fillRect.
------------------------
Ahr, hadn't actually seen there was a dispose method on the BitmapData. Don't know how that would work, but there shouldn't be too much difference between reallocating and doing fillRect on an existing BitmapData. Would need to speedtest it though to see if that's true ...
And just tested dispose. You're absolutely right - no memory spikes at all. Thanks
Last edited by YaiEf; 05-24-2007 at 08:02 AM.
-
Script kiddie
Not sure about alpha with copyPixels... first time I used copyPixels (in my BitmapData blitting experiment), something along the lines of this happened (Photoshopped picture, couldn't be bothered to actually reproduce it):

Transparent pixels overwrote each other instead of overlaying each other. Does the copyAlpha property change that?
And yes, I'm surprised that the memory usage in the copyPixel experiment is changing so much... thought it'd just be a few bytes to store each arrow's properties, plus a few KB for the spritesheet, and maybe a few MB for the 800 x 600 BitmapData object.
-
Senior Member
BitmapData(width:int, height:int, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF)
To create a fully transparent bitmap, set the value of the transparent parameter to true and the value of the fillColor parameter to 0x00000000 (or to 0).
-
M.D.
heres my attempt
both copyPixels onto another bitmap (blitting)
http://soap.com.au/chris/arrow.html //5000 arrows, no rect change
http://soap.com.au/chris/arrow2.html //2300 arrows, changing rect
no sprites involved, which means no scrollRect. I should do up a scrollRect version
mem usage 14mb, 50% cpu
so i dont know how the other can be 500+, thats just weird.
Last edited by mr_malee; 05-24-2007 at 09:23 AM.
-
M.D.
scrollRect version, not so good
http://soap.com.au/chris/arrow3.html //2300 arrows, scrollRect
i dont think i'm doing it the wrong way
mem usuage 30 and climbing, i think theres something going on here with cacheAsBitmap, scrollRect forces this, so maybe when the scrollRect changes (x position) its re-caching maybe adding more memory?
Last edited by mr_malee; 05-24-2007 at 09:34 AM.
-
Senior Member
Blazing fast update by tweaking how I do alpha and using the fillRect trick suggested above by YaiEf. Thanks!
http://www.electrotank.com/junk/mike/flash/copyPixel/
-
Script kiddie
God damnit.
I'm gonna have to rewrite Invasion again, aren't I? 
Webgeek, what did you change about how you handle the alpha? Just the copyAlpha property? Or something else?
-
Senior Member
Well, I did build my own speed experiments 
I used 5000 sprites and measured time spent to do 200 enterframe steps at movie fps set to 40. Spritesize was 32 pixels and stage size was 480x360 pixels. All tests ran using standalone FP 9.0.45.0 WinXP.
Test1.
Created the bitmap objects, added them all to the stage at random positions. Each bitmap had separate bitmapdata object (small one, size of single sprite). All bitmaps had cacheAsBitmap set to false and transparent set to true.
First ran the loop without changing the position or content of objects: ~5,3 seconds.
Then ran same loop and at each step changed the position of objects randomly: 20~21 seconds.
Some additional tests with many sprites:
*changing transparent to false in every sprite reduced overall time to ~19 seconds, transparent bitmaps are slightly slower.
*changing cacheAsBitmap to true in every sprite increased overall time to ~24 seconds (not sure why)
Test2.
Created 5000 simple objects and assigned random values for xpos and ypos variables. Created 1 stagesized bitmap and added it into stage. This bitmap is cleared using fillRect at each step.
First ran the loop without changing variables in the objects: ~5,1 seconds. Slightly faster then looping through bitmaps, but by very small margin.
Then ran the the loop and changed random variables in each object, used copyPixels to copy sprite image from main sheet into stage bitmap at position of each object: ~25 seconds.
Test2 was slower overall. If you want to move around images which do not change itself (only the position), use many bitmaps.
Test3.
This was same as test2, but at each step the content of each object was also changed randomly. Not surprisingly, time was exactly same.
Test4.
Tested many bitmaps which all change the position AND the content at each step. All bitmaps had cacheAsBitmap set to false and transparent set to true. Each step changed the position of objects randomly and used copyPixels to update the content with random image: 36~37 seconds.
Test5.
Tested many bitmaps changing content using scrollRect object. Each bitmapdata object same as main spritesheet and scrollRect was used to pick image to show. Test unfinished, ran out of memory. Estimated time to finish: ~couple days.
If you have objects that change the content a lot beside moving around, use single large bitmap and copyPixels method.
-
Senior Member
Webgeek, what did you change about how you handle the alpha? Just the copyAlpha property? Or something else?
Originally, I was passing in an unnecessary alpha source. I dropped that and simply did as mr malee suggested:
myBitmap.copyPixels(copy, rect, point, null, null, true);
Nice, simple, and fast.
-
Pumpkin Carving 2008
Is there some trick to the sprite sheet used for the arrows? I understand that it's built in rotating fashion, and that it simply scrolls through each "frame" of the sheet, but how do you go about determining the appropriate frame to display, and wouldn't you need an entirely new spritesheet if the gravity/velocity was changed?
The 'Boose':
ASUS Sabertooth P67 TUF
Intel Core i7-2600K Quad-Core Sandy Bridge 3.4GHz Overclocked to 4.2GHz
8GB G.Skill Ripjaws 1600 DDR3
ASUS ENGTX550 TI DC/DI/1GD5 GeForce GTX 550 Ti (Fermi) 1GB 1GDDR5 (Overclocked to 1.1GHz)
New addition: OCZ Vertex 240GB SATA III SSD
WEI Score: 7.6
-
Script kiddie
IP, that'd be my script. 
Here's the sprite sheet, rotates 5º every frame:

frame = Math.round((Math.atan2(yspeed, xspeed)*radToDeg+90)/5);
if (frame<0) frame = 71-Math.abs(frame);
The second line of code fixes a frame selection problem that occurs because Flash's rotation system goes from 0 to 180, -180 to 0.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|