A Flash Developer Resource Site

Page 1 of 3 123 LastLast
Results 1 to 20 of 51

Thread: AS3 is FAST! Redux - CopyPixels vs. Sprite Pooling

  1. #1
    Senior Member webgeek's Avatar
    Join Date
    Sep 2000
    Posts
    1,352

    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!

  2. #2
    Pumpkin Carving 2008 ImprisonedPride's Avatar
    Join Date
    Apr 2006
    Location
    Grand Rapids MI
    Posts
    2,377
    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

  3. #3
    Senior Member webgeek's Avatar
    Join Date
    Sep 2000
    Posts
    1,352
    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!

  4. #4
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,223
    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?

  5. #5
    Script kiddie VENGEANCE MX's Avatar
    Join Date
    Jun 2004
    Location
    England
    Posts
    2,590
    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.
    http://www.birchlabs.co.uk/
    You know you want to.

  6. #6
    M.D. mr_malee's Avatar
    Join Date
    Dec 2002
    Location
    Shelter
    Posts
    4,139
    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.
    lather yourself up with soap - soap arcade

  7. #7
    Script kiddie VENGEANCE MX's Avatar
    Join Date
    Jun 2004
    Location
    England
    Posts
    2,590
    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.
    http://www.birchlabs.co.uk/
    You know you want to.

  8. #8
    Member
    Join Date
    Jan 2004
    Location
    Copenhagen, Denmark
    Posts
    50
    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.

  9. #9
    M.D. mr_malee's Avatar
    Join Date
    Dec 2002
    Location
    Shelter
    Posts
    4,139
    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
    lather yourself up with soap - soap arcade

  10. #10
    Member
    Join Date
    Jan 2004
    Location
    Copenhagen, Denmark
    Posts
    50
    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.

  11. #11
    Script kiddie VENGEANCE MX's Avatar
    Join Date
    Jun 2004
    Location
    England
    Posts
    2,590
    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.
    http://www.birchlabs.co.uk/
    You know you want to.

  12. #12
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,223
    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).

  13. #13
    M.D. mr_malee's Avatar
    Join Date
    Dec 2002
    Location
    Shelter
    Posts
    4,139
    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.
    lather yourself up with soap - soap arcade

  14. #14
    M.D. mr_malee's Avatar
    Join Date
    Dec 2002
    Location
    Shelter
    Posts
    4,139
    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.
    lather yourself up with soap - soap arcade

  15. #15
    Senior Member webgeek's Avatar
    Join Date
    Sep 2000
    Posts
    1,352
    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/

  16. #16
    Script kiddie VENGEANCE MX's Avatar
    Join Date
    Jun 2004
    Location
    England
    Posts
    2,590
    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?
    http://www.birchlabs.co.uk/
    You know you want to.

  17. #17
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,223
    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.

  18. #18
    Senior Member webgeek's Avatar
    Join Date
    Sep 2000
    Posts
    1,352
    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.

  19. #19
    Pumpkin Carving 2008 ImprisonedPride's Avatar
    Join Date
    Apr 2006
    Location
    Grand Rapids MI
    Posts
    2,377
    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

  20. #20
    Script kiddie VENGEANCE MX's Avatar
    Join Date
    Jun 2004
    Location
    England
    Posts
    2,590
    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.
    http://www.birchlabs.co.uk/
    You know you want to.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center