![](public_html/YaBBImages/1pix.gif) |
Author |
Topic: optomising animation by refreshing changed rect (Read 2639 times) |
|
ed
![Email](public_html/YaBBImages/email.gif)
|
optomising animation by refreshing changed rect
« on: Apr 7th, 2004, 12:56pm » |
|
I'm in the process of making a much more child friendly version of www.moovl.com, which runs full screen at 1024x768 (it's designed specifically for 4-6 year olds using tablet PC's). I'm finding that the loop frame rate is critically slow when a P5 applet is set to be that big (before I've even gotten round to doing any computationally expensive stuff of my own). The majority of animation will only be occurring in portion of the screen area, so... Does anyone know what the most efficient and P5 friendly way of persuading P5 only refresh a portion of the screen during its animation loop would be?
|
|
|
|
arielm
|
Re: optomising animation by refreshing changed rec
« Reply #1 on: Apr 7th, 2004, 3:50pm » |
|
i recently made a custom java graphics engine which has a kind of "dirty region based" update algorithm, and my conclusions are that for such a framework to be really effective, all the "steps" in the drawing pipeline have to be optimized: step 1 - drawing onto a pixel buffer: in the case of 2d filled polygons, i think processing is using its regular 3d routines (may be a bit overkill for plain 2d, plus it could be complicated to implement a "draw only the required parts" system) step 2 - converting pixels to a native java image: processing is using the good-old java 1.x MemoryImageSource system, and here it's definitely possible to convert only a portion of the screen. step 3 - blitting of the newly created image to the display: here again, using Graphics.setClip(), it's possible to copy only the required parts. step 4 - clearing the previous drawings: at each frame, processing is clearing the whole screen and sometimes also the zbuffer array... these parts can also be optimized by clearing only the dirty regions, but the outcome won't be very big (i.e. modern JIT compilers are making simple array-filling loops very fast these days) all in all, i think it's possible to build an effective graphics engine dedicated to a very specific task (like drawing 2d polygons) that would be x times faster than what you have now, but i'm not sure that the processing engine is the best candidate to serve as a base. (well... you made soda with pure java a few years ago, at times most of us were playing with lingo-like stuff, so i'm probably not enlighting you with all this
|
Ariel Malka | www.chronotext.org
|
|
|
fry
|
Re: optomising animation by refreshing changed rec
« Reply #2 on: Apr 7th, 2004, 6:51pm » |
|
i recently saw a demo of the java 1.4-only features for full screen blitting/animation. seems to speed things up *significantly*, to the point where you could run a 1024x768 app without trouble. i haven't had a chance to test it out with p5, but the entire time loss with large frames is inside the java vm, which takes enormous amounts of time to move the memory for the blit to screen.
|
|
|
|
justo
|
Re: optomising animation by refreshing changed rec
« Reply #3 on: Apr 7th, 2004, 9:50pm » |
|
on Apr 7th, 2004, 6:51pm, fry wrote:i recently saw a demo of the java 1.4-only features for full screen blitting/animation. seems to speed things up *significantly*, to the point where you could run a 1024x768 app without trouble. i haven't had a chance to test it out with p5, but the entire time loss with large frames is inside the java vm, which takes enormous amounts of time to move the memory for the blit to screen. |
| it really does. the reason i was questioning you the other day on the way processing blits to screen is i was writing a version that relied on 1.2 classes (BufferedImage specifically) to eliminate some of the time the jvm spent internally copying pixel data. between that and balancing the sleep time per loop i increased a somewhat physics intensive applet (fairly similar to sodaplay, actually) from around 50 fps to around 130 to 140 fps. according to JProfiler, awt's blitting dropped from around 50% to 15%...so it was a huge performance gain. i can post the code later if need be, but its pretty simple. basically it relies on a bufferedImage as the image you draw to screen. you can get direct access to the pixel buffer of the image by calling getRaster().getDataBuffer() and cast it to a DataBufferInt...then call getData() and youll get the int array. now theres no newPixels or setAnimated or anything...youre drawing directly to the image. on some platforms you even get hardware accelerated blitting to screen. i learned about the method here: http://forum.java.sun.com/thread.jsp?forum=406&thread=500995&tst art=30&trange=15 you also get a better platform supported image with GraphicsConfiguration.createCompatibleImage(int width, int height) but you arent guaranteed that its TYPE_INT_ARGB. anyway, its trivial to add a version detecting method to use a MemoryImageSource for versions of java pre-1.2; i was probably going to add it tonight...will that work correctly if a 1.1 jvm doesnt even know what a BufferedImage is but never has to load it
|
« Last Edit: Apr 7th, 2004, 9:58pm by justo » |
|
|
|
|
justo
|
Re: optomising animation by refreshing changed rec
« Reply #5 on: Apr 8th, 2004, 12:27am » |
|
yeah, which would be nice with actual pixel operations ala processing, but i dont think it allows you access to the underlying int arrays, unfortunately. its good if youre using the java graphics2D library, though.
|
|
|
|
fry
|
Re: optomising animation by refreshing changed rec
« Reply #6 on: Apr 8th, 2004, 2:41am » |
|
on Apr 7th, 2004, 9:50pm, justo wrote: i can post the code later if need be, but its pretty simple. basically it relies on a bufferedImage as the image you draw to screen. you can get direct access to the pixel buffer of the image by calling getRaster().getDataBuffer() and cast it to a DataBufferInt...then call getData() and youll get the int array. now theres no newPixels or setAnimated or anything...youre drawing directly to the image. on some platforms you even get hardware accelerated blitting to screen. ... anyway, its trivial to add a version detecting method to use a MemoryImageSource for versions of java pre-1.2; i was probably going to add it tonight...will that work correctly if a 1.1 jvm doesnt even know what a BufferedImage is but never has to load it |
| please do post the code, i just tried hacking the graphics engine to do it, but it cut the frame rate in half, instead of improving things (tried 16/32 bit monitor depth, no change) but perhaps i'm not fully 1.2+ compliant yet. anything that could give us a performance jump like this i'd quickly add to the engine. happily, the auto-sensing 1.1 vs. 1.2+ could probably be done easily, since it's just a few lines of code, and thankfully they made BufferedImage a subclass of Image, which radically simplifies things. though who knows how speedy the reflection api would be.. hmm.
|
|
|
|
justo
|
Re: optomising animation by refreshing changed rec
« Reply #7 on: Apr 8th, 2004, 4:00am » |
|
the only really relevant code is: Code: public int[] pix; public int W, H, pixlength; public BufferedImage buffi; public Graphics2D buffg; public void init() { W = bounds().width; H = bounds().height; pixlength = W*H; //let system create BufferedImage for possible hardware acceleration GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice ().getDefaultConfiguration(); //keep buffered image and graphics2D object to write to it later if needed buffi = gc.createCompatibleImage(W, H); buffg = buffi.createGraphics(); //get buffered image's pixel array //test if bi is TYPE_INT_ARGB, warn if not...dont know how to do that yet pix = ((DataBufferInt)(buffi.getRaster().getDataBuffer())).getData(); } |
| i keep the buffg graphics object around to do things like write the FPS directly to the image rather than to screen after drawing the image to stop the text from flickering. then, in repaint (i dont do this manually yet...sounds like you had some troubles with that on OSX): Code: public void update(Graphics g) { //if desired, calc and show FPS count if (displayFPS) { buffg.setColor(Color.black); buffg.drawString(calcFPS() + " frames per second", 20, 20); } g.drawImage(buffi, 0, 0, null); } |
| the only real problems with this scheme are lack of 1.1 support, which is hopefully fixable, and, in order to increase your chances of getting a hardware accelerated bufferedimage, you have to ask the system for it...and so it might not be TYPE_INT_ARGB. i dont know what kinds of crazy things will happen if its not. cound be realllly slow as the system tries to copy the color ints to the system's color configuration, or could be something like TYPE_INT_BGR and come out all crazy. if TYPE_INT_ARGB isnt the systems color scheme, you could probably detect it and just make a bufferedImage the old fashioned way. it would be slower, but still faster than a MemoryImageSource. i only have a windows box, so thats all i've tested it on so far.
|
|
|
|
fry
|
Re: optomising animation by refreshing changed rec
« Reply #8 on: Apr 8th, 2004, 4:52am » |
|
interesting.. i'm actually using a windows box for testing, it's a speedy p4 but with an old nvidia card (riva tnt 64 i believe). the thing that was making it 2x slower was using an ARGB instead of RGB image, so swapping: new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); to just RGB: new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); got things back to the same speed (or slightly slower) as MemoryImageSource, but still not any improvement, oddly. with the GraphicsConfiguration version like in your example, i have to set my bit depth to 32 bits otherwise it won't let me get pixels[] as ints (ClassCastException). but even when having done that, it's still slower than MemoryImageSource (~10 fps instead of ~12 fps for an 800x600 project). but who knows, perhaps there are still other things that can be tweaked.
|
|
|
|
justo
|
Re: optomising animation by refreshing changed rec
« Reply #9 on: Apr 8th, 2004, 5:37am » |
|
yeah, damn, i had thought about that, but hadnt even tried the simple step of turning down my bit depth. it is interesting, though, that using a MemoryImageSource to convert an int array to your computer's bit depth was faster than using this method. i wonder what type of array it was passing back when its TYPE_INT_RGB...theres no such thing as a three byte primitive, so it should have been 32 bits....weird. so, i guess that makes this a special case then: people with recent JVMs and newer graphics cards...thats a shame. hopefully there is some tweaking that can be done, i'm getting used to this kind of performance. still, good for installations.
|
|
|
|
arielm
|
Re: optomising animation by refreshing changed rec
« Reply #10 on: Apr 8th, 2004, 11:34am » |
|
in my home-made java graphics engine (ms and sun compatible), i have a PixelBuffer class that makes use of BufferedImage to do pixel-buffering when the host machine enables it. after an intensive set of benchmarks, my results show that BufferedImage pixels are only ~10-15% faster than MemoryImageSource pixels. but anyway, according to the very makers of java, hardware acceleration is not relevant here, since arrays of int's reside inside heap (aka java) memory and it's always a huge trip for the jvm to transfer all this data to vram. worse than that: due to the way java 1.4 hardware acceleration is working (guessing and doing a lot of things for you in the background), it can even make things work slower when using pixel-buffers. proofs in this series of articles: http://today.java.net/pub/au/78
|
Ariel Malka | www.chronotext.org
|
|
|
arielm
|
Re: optomising animation by refreshing changed rec
« Reply #11 on: Apr 8th, 2004, 11:41am » |
|
on Apr 7th, 2004, 9:50pm, justo wrote:anyway, its trivial to add a version detecting method to use a MemoryImageSource for versions of java pre-1.2; i was probably going to add it tonight...will that work correctly if a 1.1 jvm doesnt even know what a BufferedImage is but never has to load it |
| something like that is working in my engine: Code:PixelBuffer buffer; try { Class c = Class.forName("java.awt.image.BufferedImage"); buffer = new PixelBuffer_BI(W, H); } catch (Throwable t) { buffer = new PixelBuffer_MIS(W, H); } |
|
|
Ariel Malka | www.chronotext.org
|
|
|
justo
|
Re: optomising animation by refreshing changed rec
« Reply #12 on: Apr 8th, 2004, 6:42pm » |
|
on Apr 8th, 2004, 11:34am, arielm wrote:in my home-made java graphics engine (ms and sun compatible), i have a PixelBuffer class that makes use of BufferedImage to do pixel-buffering when the host machine enables it. after an intensive set of benchmarks, my results show that BufferedImage pixels are only ~10-15% faster than MemoryImageSource pixels. but anyway, according to the very makers of java, hardware acceleration is not relevant here, since arrays of int's reside inside heap (aka java) memory and it's always a huge trip for the jvm to transfer all this data to vram. worse than that: due to the way java 1.4 hardware acceleration is working (guessing and doing a lot of things for you in the background), it can even make things work slower when using pixel-buffers. proofs in this series of articles: http://today.java.net/pub/au/78 |
| i had read those articles on BufferedImages, but i went back and looked and couldnt find the info on the int array. while it would normally be allocated on the heap, what i'm doing is requesting a reference to the int array the BufferedImage actually uses in its raster. i think thats why fry was getting a ClassCastException...note this is different than using the get- and setRGB() methods which actually copy the array and tend to be quite slow. im only questioning this because i'm still getting a huge performance increase with only these changes. granted, it could be a my computer only thing, but even changing to the standard new BufferedImage() instead of asking the system for the best kind still results in excellent performance, just not as good. i would guess, then, that my computer is accelerating it, because its drawing to screen at an insane speed...this is how all applets should behave. so this is weird. i'll check it out later today when i get back from class...hopefully on a couple of different computers.
|
|
|
|
ed
![Email](public_html/YaBBImages/email.gif)
|
Re: optomising animation by refreshing changed rec
« Reply #13 on: Apr 8th, 2004, 6:44pm » |
|
on Apr 7th, 2004, 6:51pm, fry wrote:i recently saw a demo of the java 1.4-only features for full screen blitting/animation. seems to speed things up *significantly*, to the point where you could run a 1024x768 app without trouble. i haven't had a chance to test it out with p5, but the entire time loss with large frames is inside the java vm, which takes enormous amounts of time to move the memory for the blit to screen. |
| Mmm, I'd also been experimenting with the new (1.4+) java.awt.image.BufferStrategy and got promising results with a crude non-P5 fullscreen test rig. I wasn't sure how easy it would be for me to get it working with P5 (call me a coward but for now I'm trying to avoid opening up the innards of P5 too much; I've got enough on my plate with this project already!). Should I simply be overiding the P5 "public void update(Graphics g)" method and inserting my route to the screen from there I'm not sure but I think my initial experiments in this direction were running into problems by by-passing the various synchornizations and flags that P5 uses to keep its loop and update out of each others way As for the various newfangled buffer types and strategies; fortunately for now I can get away with using these 1.4+ features as I'm coding for specific hardware in preparation for putting Moovl in the hands of some demanding 5 year olds: It's looking like frame rate is going to be a very critical issue so any and all optomisation tips may help make me less anxious and the youngsters more happy! Thanks yawl. x
|
|
|
|
arielm
|
Re: optomising animation by refreshing changed rec
« Reply #14 on: Apr 8th, 2004, 7:58pm » |
|
on Apr 8th, 2004, 6:42pm, justo wrote:i had read those articles on BufferedImages, but i went back and looked and couldnt find the info on the int array. while it would normally be allocated on the heap, what i'm doing is requesting a reference to the int array the BufferedImage actually uses in its raster. i think thats why fry was getting a ClassCastException...note this is different than using the get- and setRGB() methods which actually copy the array and tend to be quite slow. |
| personally, here's what i do to grab the pixels of a BufferedImage: Code:BufferedImage image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); |
| on Apr 8th, 2004, 6:42pm, justo wrote:im only questioning this because i'm still getting a huge performance increase with only these changes. granted, it could be a my computer only thing, but even changing to the standard new BufferedImage() instead of asking the system for the best kind still results in excellent performance, just not as good. i would guess, then, that my computer is accelerating it, because its drawing to screen at an insane speed...this is how all applets should behave. |
| maybe you get more than the 10-15% acceleration i was mentionning because you work in "full-screen mode" (my engine is for web-use, so it can't take advantage of this mode) btw, from all the articles and forum posts i could read, "full-screen-mode" is giving insane (i.e. above 100fps) framerate results, even when using MemoryImageSource.
|
Ariel Malka | www.chronotext.org
|
|
|
|