Java Forum / General / March 2008
Frame tearing in applet
André Wagner - 24 Mar 2008 17:24 GMT Hello,
I'm writing a videogame emulator in Java, that'll run in a applet.
The process I use to draw the image in the applet is the following:
1. The emulator process its data. During this processing, the video card is drawing to the "TV set", which means the emulator is drawing in a BufferedImage.
2. When a whole frame is drawn, I call repaint() on the emulador.
3. This makes the paint() method of the applet to be called, draws the bufferedImage on the screen, like this:
public void paint(Graphics g) { g.drawImage(video.image, 0, 0, this); }
Well, the problem is: drawImage returns immediately. So while drawImage is drawing the bufferedImage on the screen, the bufferedImage is already being changed by the emulator.
So when drawImage finishes drawing the bufferedImage on the screen, the pixels in bufferedImage are already different, and this cases "frame tearing" on the screen.
I think a way to avoid this is to wait until the image finished drawing on the screen. But I don't know how to do it, I tried using a ImageObserver but it just wasn't called.
So, does anyone knows how can I do this? Or, maybe, does anyone knows a better way to implement all this?
Best regards,
André
Mark Space - 24 Mar 2008 20:43 GMT > So, does anyone knows how can I do this? Or, maybe, does anyone knows > a better way to implement all this? Look around for "double buffering" in the 2D Java API. This uses two buffers so one can be used for blitting (copying) while the other is drawn to by the app.
If you can't find any info I'll get my Learning Java book and see if I can find anything there.
André Wagner - 24 Mar 2008 20:53 GMT Hello Mark,
thank you for your answer.
> Look around for "double buffering" in the 2D Java API. This uses two > buffers so one can be used for blitting (copying) while the other is > drawn to by the app. As I understand, doublebuffering is exactly what I am doing here. My problem is that the backBuffer changes before the screen is completely updated.
So my question is: how can I detect when the screen has been completely updated, so that I can haltany changes to the backBuffer?
Regards,
André
Mark Space - 24 Mar 2008 21:31 GMT > Hello Mark, > [quoted text clipped - 10 lines] > So my question is: how can I detect when the screen has been > completely updated, so that I can haltany changes to the backBuffer? Note that the last argument in drawImage() is an ImageObserver. You can over-ride the imageUpdate method in your component, or implement your own separate observer object.
Note the ALLBITS flag in the API: <http://java.sun.com/j2se/1.5.0/docs/api/java/awt/image/ImageObserver.html>
An example: <http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter11/loading Images.html>
If there are two threads involved here (and I think there will be, the EDT and your own thread of execution) then you'll have to synchronize the two threads, using methods like wait(), notify() and the synchronized keyword. Think this through carefully for best performance!
André Wagner - 25 Mar 2008 12:53 GMT > > So my question is: how can I detect when the screen has been > > completely updated, so that I can haltany changes to the backBuffer? > > Note that the last argument in drawImage() is an ImageObserver. You can > over-ride the imageUpdate method in your component, or implement your > own separate observer object. Well, there's exactly my problem. I implemented the image observer in my applet class like this:
public boolean imageUpdate(Image im, int flags, int x, int y, int w, int h) { System.out.println("observer"); }
But it is simply not called!
I also found out this command:
getToolkit().sync();
It worked in Linux but, surprisingly, didn't worked on Windows...
Mark Space - 25 Mar 2008 22:28 GMT > Well, there's exactly my problem. I implemented the image observer in > my applet class like this:
> But it is simply not called! I think Larry probably is on the right track. The image observer may not be called because the image is already "loaded" (in memory) and the observer doesn't have anything to do with the actual blitting.
Larry A Barowski - 25 Mar 2008 17:25 GMT > Well, the problem is: drawImage returns immediately. So while > drawImage is drawing the bufferedImage on the screen, the [quoted text clipped - 3 lines] > the pixels in bufferedImage are already different, and this cases > "frame tearing" on the screen. I highly suspect that this is not the problem. The image is being fully rendered to the screen buffer. The tearing you are seeing is because the screen may be updated at any time, including in the middle of a refresh cycle. To confirm this, I wrote a quick test that cycles a buffered image between all red and all green and paints to a component each time. Immediately after each drawImage() call, all the pixels in the buffered image are changed to blue. I tried both a top-down and a bottom up change to blue. Either way, you can see the red/green image tear, but the blue never shows up, so the tearing has nothing to do with drawImage not being finished with the source, it happens later.
What you need is a way to wait for the vertical blank of the screen before painting. Currently there is no way to do this in Java. See: http://bugs.sun.com/view_bug.do?bug_id=6378181 You can do it in full screen mode or with native code, but you are doing this in an applet, so neither solution is of use. You can wait for the vertical blank using Flash, so from a browser maybe there is some way to use Flash with JavaScript as glue to implement the wait, or maybe there is some other browser trick that will do it. You could ask this guy: http://www.nescafeweb.com/
André Wagner - 26 Mar 2008 12:26 GMT > I highly suspect that this is not the problem. The image is being > fully rendered to the screen buffer. The tearing you are seeing [quoted text clipped - 8 lines] > do with drawImage not being finished with the source, it > happens later. Yes! That is the exact problem.
> What you need is a way to wait for the vertical blank of the > screen before painting. Currently there is no way to do this [quoted text clipped - 5 lines] > to implement the wait, or maybe there is some other browser > trick that will do it. You could ask this guy:http://www.nescafeweb.com/ Thank you very much for the info. I also found the following website about the problem:
http://today.java.net/pub/a/today/2006/02/23/smooth-moves-solutions.html
According to a Java developer post I found in a forum, "We do intend to fix this in upcoming release. Didn't make it into JDK 6, unfortunately." So I believe there's not another choice but wait (which is kinda sad because I have most of my emulator done)...
Regards,
André
Knute Johnson - 25 Mar 2008 23:36 GMT > Hello, > [quoted text clipped - 34 lines] > > André What about synchronizing your drawing and your calcs? Are you using a double buffered component to draw on?
 Signature Knute Johnson email s/nospam/linux/
------->>>>>>http://www.NewsDem
André Wagner - 26 Mar 2008 12:35 GMT > What about synchronizing your drawing and your calcs? I thought about that, the problems with that are:
1. I never know how long it would take. It's a Atari 2600 emulator that runs at about 3,5 Mhz, which means something about 15000 instructions executed by frame. I can time it, but it might take a little longer than a frame to execute that.
2. I never know if my emulation is starting in the middle of a frame. If this happens, then every emulator frame will happen in the middle of a host frame...
Regards, André
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|