Frame tearing in applet

A

André Wagner

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é
 
M

Mark Space

André Wagner said:
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.
 
A

André Wagner

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é
 
M

Mark Space

André Wagner said:
Hello Mark,

thank you for your answer.


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?

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/loadingImages.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!
 
A

André Wagner

So my question is: how can I detect when the screen has been
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...
 
L

Larry A Barowski

André Wagner said:
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 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/
 
M

Mark Space

André Wagner said:
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.
 
K

Knute Johnson

André Wagner said:
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é

What about synchronizing your drawing and your calcs? Are you using a
double buffered component to draw on?
 
A

André Wagner

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.

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
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/

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é
 
A

André Wagner

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é
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,830
Latest member
HeleneMull

Latest Threads

Top